[clang] 98322d3 - Complete the implementation of P2361 Unevaluated string literals
Corentin Jabot via cfe-commits
cfe-commits at lists.llvm.org
Tue Aug 15 05:13:19 PDT 2023
Author: Corentin Jabot
Date: 2023-08-15T14:13:13+02:00
New Revision: 98322d3eb43168a6a64c1a15a1e754e15c04aa2f
URL: https://github.com/llvm/llvm-project/commit/98322d3eb43168a6a64c1a15a1e754e15c04aa2f
DIFF: https://github.com/llvm/llvm-project/commit/98322d3eb43168a6a64c1a15a1e754e15c04aa2f.diff
LOG: Complete the implementation of P2361 Unevaluated string literals
The attributes changes were left out of Clang 17.
Attributes that used to take a string literal now accept an unevaluated
string literal instead, which means they reject numeric escape sequences
and strings literal with an encoding prefix - but the later was already
ill-formed in most cases.
We need to know that we are going to parse an unevaluated string literal
before we do - so we can reject numeric escape sequence,
so we derive from Attrs.td which attributes parameters are expected
to be string literals.
Reviewed By: aaron.ballman
Differential Revision: https://reviews.llvm.org/D156237
Added:
Modified:
clang/docs/ReleaseNotes.rst
clang/include/clang/Basic/DiagnosticCommonKinds.td
clang/include/clang/Parse/Parser.h
clang/include/clang/Sema/ParsedAttr.h
clang/lib/Parse/ParseDecl.cpp
clang/lib/Parse/ParseExpr.cpp
clang/lib/Sema/SemaDeclAttr.cpp
clang/test/Parser/MicrosoftExtensions.cpp
clang/test/Parser/c2x-attributes.c
clang/test/Parser/cxx-attributes.cpp
clang/test/Parser/cxx0x-attributes.cpp
clang/test/Sema/MicrosoftExtensions.c
clang/test/Sema/annotate-type.c
clang/test/Sema/annotate.c
clang/test/Sema/attr-assume.c
clang/test/Sema/attr-btf_tag.c
clang/test/Sema/attr-btf_type_tag.c
clang/test/Sema/attr-capabilities.c
clang/test/Sema/attr-enforce-tcb-errors.cpp
clang/test/Sema/attr-enforce-tcb-errors.m
clang/test/Sema/attr-error.c
clang/test/Sema/attr-handles.cpp
clang/test/Sema/attr-section.c
clang/test/Sema/attr-tls_model.c
clang/test/Sema/attr-unavailable-message.c
clang/test/Sema/attr-warning.c
clang/test/Sema/diagnose_if.c
clang/test/Sema/enable_if.c
clang/test/SemaCXX/attr-deprecated-replacement-error.cpp
clang/test/SemaCXX/attr-no-sanitize.cpp
clang/test/SemaCXX/attr-section.cpp
clang/test/SemaCXX/attr-weakref.cpp
clang/test/SemaCXX/suppress.cpp
clang/test/SemaObjC/attr-swift_bridge.m
clang/test/SemaObjC/objc-asm-attribute-neg-test.m
clang/test/SemaObjC/validate-attr-swift_attr.m
clang/test/SemaTemplate/attributes.cpp
clang/utils/TableGen/ClangAttrEmitter.cpp
clang/www/cxx_status.html
Removed:
################################################################################
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index cd7beff546c932..56eef72c8a2835 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -85,6 +85,9 @@ C++2c Feature Support
int _; // Previously diagnosed under -Wunused, no longer diagnosed
}
+- Attributes now expect unevaluated strings in attributes parameters that are string literals.
+ This is applied to both C++ standard attributes, and other attributes supported by Clang.
+ This completes the implementation of `P2361R6 Unevaluated Strings <https://wg21.link/P2361R6>_`
Resolutions to C++ Defect Reports
diff --git a/clang/include/clang/Basic/DiagnosticCommonKinds.td b/clang/include/clang/Basic/DiagnosticCommonKinds.td
index 46a21d5da54026..195a61127c2a67 100644
--- a/clang/include/clang/Basic/DiagnosticCommonKinds.td
+++ b/clang/include/clang/Basic/DiagnosticCommonKinds.td
@@ -56,7 +56,9 @@ def err_expected_string_literal : Error<"expected string literal "
"%select{in %1|for diagnostic message in static_assert|"
"for optional message in 'availability' attribute|"
"for %select{language name|source container name|USR}1 in "
- "'external_source_symbol' attribute}0">;
+ "'external_source_symbol' attribute|"
+ "as argument of '%1' attribute}0">;
+
def err_invalid_string_udl : Error<
"string literal with user-defined suffix cannot be used here">;
def err_invalid_character_udl : Error<
diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h
index 6312318d0ba983..c4dff165a13041 100644
--- a/clang/include/clang/Parse/Parser.h
+++ b/clang/include/clang/Parse/Parser.h
@@ -2790,6 +2790,13 @@ class Parser : public CodeCompletionHandler {
/// clang accepts as an extension.
void DiagnoseCXX11AttributeExtension(ParsedAttributes &Attrs);
+ ExprResult ParseUnevaluatedStringInAttribute(const IdentifierInfo &AttrName);
+
+ bool
+ ParseAttributeArgumentList(const clang::IdentifierInfo &AttrName,
+ SmallVectorImpl<Expr *> &Exprs,
+ ParsedAttributeArgumentsProperties ArgsProperties);
+
/// Parses syntax-generic attribute arguments for attributes which are
/// known to the implementation, and adds them to the given ParsedAttributes
/// list with the given attribute syntax. Returns the number of arguments
diff --git a/clang/include/clang/Sema/ParsedAttr.h b/clang/include/clang/Sema/ParsedAttr.h
index 592580bccd234f..8c0edca1ebc5ee 100644
--- a/clang/include/clang/Sema/ParsedAttr.h
+++ b/clang/include/clang/Sema/ParsedAttr.h
@@ -24,6 +24,7 @@
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/Allocator.h"
#include "llvm/Support/VersionTuple.h"
+#include <bitset>
#include <cassert>
#include <cstddef>
#include <cstring>
@@ -911,6 +912,20 @@ class ParsedAttributesView {
VecTy AttrList;
};
+struct ParsedAttributeArgumentsProperties {
+ ParsedAttributeArgumentsProperties(uint32_t StringLiteralBits)
+ : StringLiterals(StringLiteralBits) {}
+ bool isStringLiteralArg(unsigned I) const {
+ // If the last bit is set, assume we have a variadic parameter
+ if (I >= StringLiterals.size())
+ return StringLiterals.test(StringLiterals.size() - 1);
+ return StringLiterals.test(I);
+ }
+
+private:
+ std::bitset<32> StringLiterals;
+};
+
/// ParsedAttributes - A collection of parsed attributes. Currently
/// we don't
diff erentiate between the various attribute syntaxes,
/// which is basically silly.
diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index 2840b48cce1eb1..b5a3ee1eaf076d 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -288,6 +288,16 @@ static bool attributeHasIdentifierArg(const IdentifierInfo &II) {
#undef CLANG_ATTR_IDENTIFIER_ARG_LIST
}
+/// Determine whether the given attribute has an identifier argument.
+static ParsedAttributeArgumentsProperties
+attributeStringLiteralListArg(const IdentifierInfo &II) {
+#define CLANG_ATTR_STRING_LITERAL_ARG_LIST
+ return llvm::StringSwitch<uint32_t>(normalizeAttrName(II.getName()))
+#include "clang/Parse/AttrParserStringSwitches.inc"
+ .Default(0);
+#undef CLANG_ATTR_STRING_LITERAL_ARG_LIST
+}
+
/// Determine whether the given attribute has a variadic identifier argument.
static bool attributeHasVariadicIdentifierArg(const IdentifierInfo &II) {
#define CLANG_ATTR_VARIADIC_IDENTIFIER_ARG_LIST
@@ -371,6 +381,81 @@ void Parser::ParseAttributeWithTypeArg(IdentifierInfo &AttrName,
ScopeName, ScopeLoc, nullptr, 0, Form);
}
+ExprResult
+Parser::ParseUnevaluatedStringInAttribute(const IdentifierInfo &AttrName) {
+ if (Tok.is(tok::l_paren)) {
+ BalancedDelimiterTracker Paren(*this, tok::l_paren);
+ Paren.consumeOpen();
+ ExprResult Res = ParseUnevaluatedStringInAttribute(AttrName);
+ Paren.consumeClose();
+ return Res;
+ }
+ if (!isTokenStringLiteral()) {
+ Diag(Tok.getLocation(), diag::err_expected_string_literal)
+ << /*in attribute...*/ 4 << AttrName.getName();
+ return ExprError();
+ }
+ return ParseUnevaluatedStringLiteralExpression();
+}
+
+bool Parser::ParseAttributeArgumentList(
+ const IdentifierInfo &AttrName, SmallVectorImpl<Expr *> &Exprs,
+ ParsedAttributeArgumentsProperties ArgsProperties) {
+ bool SawError = false;
+ unsigned Arg = 0;
+ while (true) {
+ ExprResult Expr;
+ if (ArgsProperties.isStringLiteralArg(Arg)) {
+ Expr = ParseUnevaluatedStringInAttribute(AttrName);
+ } else if (getLangOpts().CPlusPlus11 && Tok.is(tok::l_brace)) {
+ Diag(Tok, diag::warn_cxx98_compat_generalized_initializer_lists);
+ Expr = ParseBraceInitializer();
+ } else {
+ Expr = ParseAssignmentExpression();
+ }
+ Expr = Actions.CorrectDelayedTyposInExpr(Expr);
+
+ if (Tok.is(tok::ellipsis))
+ Expr = Actions.ActOnPackExpansion(Expr.get(), ConsumeToken());
+ else if (Tok.is(tok::code_completion)) {
+ // There's nothing to suggest in here as we parsed a full expression.
+ // Instead fail and propagate the error since caller might have something
+ // the suggest, e.g. signature help in function call. Note that this is
+ // performed before pushing the \p Expr, so that signature help can report
+ // current argument correctly.
+ SawError = true;
+ cutOffParsing();
+ break;
+ }
+
+ if (Expr.isInvalid()) {
+ SawError = true;
+ break;
+ }
+
+ Exprs.push_back(Expr.get());
+
+ if (Tok.isNot(tok::comma))
+ break;
+ // Move to the next argument, remember where the comma was.
+ Token Comma = Tok;
+ ConsumeToken();
+ checkPotentialAngleBracketDelimiter(Comma);
+ Arg++;
+ }
+
+ if (SawError) {
+ // Ensure typos get diagnosed when errors were encountered while parsing the
+ // expression list.
+ for (auto &E : Exprs) {
+ ExprResult Expr = Actions.CorrectDelayedTyposInExpr(E);
+ if (Expr.isUsable())
+ E = Expr.get();
+ }
+ }
+ return SawError;
+}
+
unsigned Parser::ParseAttributeArgsCommon(
IdentifierInfo *AttrName, SourceLocation AttrNameLoc,
ParsedAttributes &Attrs, SourceLocation *EndLoc, IdentifierInfo *ScopeName,
@@ -463,9 +548,9 @@ unsigned Parser::ParseAttributeArgsCommon(
: Sema::ExpressionEvaluationContext::ConstantEvaluated);
ExprVector ParsedExprs;
- if (ParseExpressionList(ParsedExprs, llvm::function_ref<void()>(),
- /*FailImmediatelyOnInvalidExpr=*/true,
- /*EarlyTypoCorrection=*/true)) {
+ ParsedAttributeArgumentsProperties ArgProperties =
+ attributeStringLiteralListArg(*AttrName);
+ if (ParseAttributeArgumentList(*AttrName, ParsedExprs, ArgProperties)) {
SkipUntil(tok::r_paren, StopAtSemi);
return 0;
}
diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp
index bd72de067cfae9..f8bf785da2896a 100644
--- a/clang/lib/Parse/ParseExpr.cpp
+++ b/clang/lib/Parse/ParseExpr.cpp
@@ -3515,7 +3515,7 @@ bool Parser::ParseExpressionList(SmallVectorImpl<Expr *> &Exprs,
Expr = Actions.ActOnPackExpansion(Expr.get(), ConsumeToken());
else if (Tok.is(tok::code_completion)) {
// There's nothing to suggest in here as we parsed a full expression.
- // Instead fail and propogate the error since caller might have something
+ // Instead fail and propagate the error since caller might have something
// the suggest, e.g. signature help in function call. Note that this is
// performed before pushing the \p Expr, so that signature help can report
// current argument correctly.
diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index 115db2b9a985e9..afc9937da0b15c 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -350,7 +350,7 @@ bool Sema::checkStringLiteralArgumentAttr(const AttributeCommonInfo &CI,
if (ArgLocation)
*ArgLocation = E->getBeginLoc();
- if (!Literal || !Literal->isOrdinary()) {
+ if (!Literal || (!Literal->isUnevaluated() && !Literal->isOrdinary())) {
Diag(E->getBeginLoc(), diag::err_attribute_argument_type)
<< CI << AANT_ArgumentString;
return false;
@@ -382,6 +382,16 @@ bool Sema::checkStringLiteralArgumentAttr(const ParsedAttr &AL, unsigned ArgNum,
// Now check for an actual string literal.
Expr *ArgExpr = AL.getArgAsExpr(ArgNum);
+ const auto *Literal = dyn_cast<StringLiteral>(ArgExpr->IgnoreParenCasts());
+ if (ArgLocation)
+ *ArgLocation = ArgExpr->getBeginLoc();
+
+ if (!Literal || (!Literal->isUnevaluated() && !Literal->isOrdinary())) {
+ Diag(ArgExpr->getBeginLoc(), diag::err_attribute_argument_type)
+ << AL << AANT_ArgumentString;
+ return false;
+ }
+ Str = Literal->getString();
return checkStringLiteralArgumentAttr(AL, ArgExpr, Str, ArgLocation);
}
diff --git a/clang/test/Parser/MicrosoftExtensions.cpp b/clang/test/Parser/MicrosoftExtensions.cpp
index 01e59aa1945a86..6bf802a29ace39 100644
--- a/clang/test/Parser/MicrosoftExtensions.cpp
+++ b/clang/test/Parser/MicrosoftExtensions.cpp
@@ -44,8 +44,8 @@ typedef struct _GUID
unsigned char Data4[8];
} GUID;
-struct __declspec(uuid(L"00000000-0000-0000-1234-000000000047")) uuid_attr_bad1 { };// expected-error {{'uuid' attribute requires a string}}
-struct __declspec(uuid(3)) uuid_attr_bad2 { };// expected-error {{'uuid' attribute requires a string}}
+struct __declspec(uuid(L"00000000-0000-0000-1234-000000000047")) uuid_attr_bad1 { };// expected-warning {{encoding prefix 'L' on an unevaluated string literal has no effect and is incompatible with c++2c}}
+struct __declspec(uuid(3)) uuid_attr_bad2 { };// expected-error {{expected string literal as argument of 'uuid' attribute}}
struct __declspec(uuid("0000000-0000-0000-1234-0000500000047")) uuid_attr_bad3 { };// expected-error {{uuid attribute contains a malformed GUID}}
struct __declspec(uuid("0000000-0000-0000-Z234-000000000047")) uuid_attr_bad4 { };// expected-error {{uuid attribute contains a malformed GUID}}
struct __declspec(uuid("000000000000-0000-1234-000000000047")) uuid_attr_bad5 { };// expected-error {{uuid attribute contains a malformed GUID}}
diff --git a/clang/test/Parser/c2x-attributes.c b/clang/test/Parser/c2x-attributes.c
index 3e9469f8fa8b5f..be039e40f98ef1 100644
--- a/clang/test/Parser/c2x-attributes.c
+++ b/clang/test/Parser/c2x-attributes.c
@@ -16,7 +16,7 @@ enum { [[]] Six }; // expected-error {{expected identifier}}
// FIXME: this diagnostic can be improved.
enum E3 [[]] { Seven }; // expected-error {{expected identifier or '('}}
-[[deprecated([""])]] int WrongArgs; // expected-error {{expected expression}}
+[[deprecated([""])]] int WrongArgs; // expected-error {{expected string literal as argument of 'deprecated' attribute}}
[[,,,,,]] int Commas1; // ok
[[,, maybe_unused]] int Commas2; // ok
[[maybe_unused,,,]] int Commas3; // ok
@@ -24,6 +24,13 @@ enum E3 [[]] { Seven }; // expected-error {{expected identifier or '('}}
[[foo bar]] int NoComma; // expected-error {{expected ','}} \
// expected-warning {{unknown attribute 'foo' ignored}}
+
+[[deprecated(L"abc")]] void unevaluated_string(void);
+// expected-warning at -1 {{encoding prefix 'L' on an unevaluated string literal has no effect}}
+
+[[nodiscard("\123")]] int unevaluated_string2(void);
+// expected-error at -1 {{invalid escape sequence '\123' in an unevaluated string literal}}
+
struct [[]] S1 {
int i [[]];
int [[]] j;
diff --git a/clang/test/Parser/cxx-attributes.cpp b/clang/test/Parser/cxx-attributes.cpp
index b46326c4d474f0..51d1f9c8228121 100644
--- a/clang/test/Parser/cxx-attributes.cpp
+++ b/clang/test/Parser/cxx-attributes.cpp
@@ -41,7 +41,7 @@ void fn() {
pi = &i[0];
}
-[[deprecated([""])]] int WrongArgs; // expected-error {{expected variable name or 'this' in lambda capture list}}
+[[deprecated([""])]] int WrongArgs; // expected-error {{expected string literal as argument of 'deprecated' attribute}}
[[,,,,,]] int Commas1; // ok
[[,, maybe_unused]] int Commas2; // ok
[[maybe_unused,,,]] int Commas3; // ok
diff --git a/clang/test/Parser/cxx0x-attributes.cpp b/clang/test/Parser/cxx0x-attributes.cpp
index 3cb4e180e5f5f1..10c5bbcac10227 100644
--- a/clang/test/Parser/cxx0x-attributes.cpp
+++ b/clang/test/Parser/cxx0x-attributes.cpp
@@ -94,7 +94,7 @@ class [[]] [[]] final_class_another
[[]] [[]] alignas(16) [[]]{}; // expected-error {{an attribute list cannot appear here}}
// The diagnostics here don't matter much, this just shouldn't crash:
-class C final [[deprecated(l]] {}); // expected-error {{use of undeclared identifier}} expected-error {{expected ']'}} expected-error {{an attribute list cannot appear here}} expected-error {{expected unqualified-id}}
+class C final [[deprecated(l]] {}); //expected-error {{expected string literal as argument of 'deprecated' attribute}} expected-error {{an attribute list cannot appear here}} expected-error {{expected unqualified-id}}
class D final alignas ([l) {}]{}); // expected-error {{expected ',' or ']' in lambda capture list}} expected-error {{an attribute list cannot appear here}}
[[]] struct with_init_declarators {} init_declarator;
@@ -266,7 +266,7 @@ template<typename...Ts> void variadic() {
template <int... Is> void variadic_nttp() {
void bar [[noreturn...]] (); // expected-error {{attribute 'noreturn' cannot be used as an attribute pack}}
- void baz [[clang::no_sanitize(Is...)]] (); // expected-error {{attribute 'no_sanitize' does not support argument pack expansion}}
+ void baz [[clang::no_sanitize(Is...)]] (); // expected-error {{expected string literal as argument of 'no_sanitize' attribute}}
void bor [[clang::annotate("A", "V" ...)]] (); // expected-error {{pack expansion does not contain any unexpanded parameter packs}}
void bir [[clang::annotate("B", {1, 2, 3, 4})]] (); // expected-error {{'annotate' attribute requires parameter 1 to be a constant expression}} expected-note {{subexpression not valid in a constant expression}}
void boo [[unknown::foo(Is...)]] (); // expected-warning {{unknown attribute 'foo' ignored}}
@@ -445,3 +445,9 @@ class Ordering {
) {
}
};
+
+namespace P2361 {
+[[deprecated(L"abc")]] void a(); // expected-warning{{encoding prefix 'L' on an unevaluated string literal has no effect and is incompatible with c++2c}} \
+ // expected-warning {{use of the 'deprecated' attribute is a C++14 extension}}
+[[nodiscard("\123")]] int b(); // expected-error{{invalid escape sequence '\123' in an unevaluated string literal}}
+}
diff --git a/clang/test/Sema/MicrosoftExtensions.c b/clang/test/Sema/MicrosoftExtensions.c
index 50077d90314886..cf7463d2e76ebc 100644
--- a/clang/test/Sema/MicrosoftExtensions.c
+++ b/clang/test/Sema/MicrosoftExtensions.c
@@ -123,7 +123,7 @@ struct __declspec(deprecated) DS1 { int i; float f; }; // expected-note {{'DS1'
#define MY_TEXT "This is also deprecated"
__declspec(deprecated(MY_TEXT)) void Dfunc1( void ) {} // expected-note {{'Dfunc1' has been explicitly marked deprecated here}}
-struct __declspec(deprecated(123)) DS2 {}; // expected-error {{'deprecated' attribute requires a string}}
+struct __declspec(deprecated(123)) DS2 {}; // expected-error {{expected string literal as argument of 'deprecated' attribute}}
void test( void ) {
e1 = one; // expected-warning {{'e1' is deprecated: This is deprecated}}
diff --git a/clang/test/Sema/annotate-type.c b/clang/test/Sema/annotate-type.c
index 9fd95f953c5d48..901cef7ffa8b3a 100644
--- a/clang/test/Sema/annotate-type.c
+++ b/clang/test/Sema/annotate-type.c
@@ -20,10 +20,10 @@ void foo(float *[[clang::annotate_type("foo")]] a) {
[[clang::annotate_type("bar")]] int *z1; // expected-error {{'annotate_type' attribute cannot be applied to a declaration}}
int *z2 [[clang::annotate_type("bar")]]; // expected-error {{'annotate_type' attribute cannot be applied to a declaration}}
[[clang::annotate_type("bar")]]; // expected-error {{'annotate_type' attribute cannot be applied to a statement}}
- int *[[clang::annotate_type(1)]] z3; // expected-error {{'annotate_type' attribute requires a string}}
+ int *[[clang::annotate_type(1)]] z3; // expected-error {{expected string literal as argument of 'annotate_type' attribute}}
int *[[clang::annotate_type()]] z4; // expected-error {{'annotate_type' attribute takes at least 1 argument}}
int *[[clang::annotate_type]] z5; // expected-error {{'annotate_type' attribute takes at least 1 argument}}
- int *[[clang::annotate_type(some_function())]] z6; // expected-error {{'annotate_type' attribute requires a string}}
+ int *[[clang::annotate_type(some_function())]] z6; // expected-error {{expected string literal as argument of 'annotate_type' attribute}}
int *[[clang::annotate_type("bar", some_function())]] z7; // expected-error {{'annotate_type' attribute requires parameter 1 to be a constant expression}} expected-note{{subexpression not valid in a constant expression}}
int *[[clang::annotate_type("bar", z7)]] z8; // expected-error {{'annotate_type' attribute requires parameter 1 to be a constant expression}} expected-note{{subexpression not valid in a constant expression}}
int *[[clang::annotate_type("bar", int)]] z9; // expected-error {{expected expression}}
diff --git a/clang/test/Sema/annotate.c b/clang/test/Sema/annotate.c
index 2e7a37936fedec..b4551a102e6174 100644
--- a/clang/test/Sema/annotate.c
+++ b/clang/test/Sema/annotate.c
@@ -3,8 +3,8 @@
void __attribute__((annotate("foo"))) foo(float *a) {
__attribute__((annotate("bar"))) int x;
[[clang::annotate("bar")]] int x2;
- __attribute__((annotate(1))) int y; // expected-error {{'annotate' attribute requires a string}}
- [[clang::annotate(1)]] int y2; // expected-error {{'annotate' attribute requires a string}}
+ __attribute__((annotate(1))) int y; // expected-error {{expected string literal as argument of 'annotate' attribute}}
+ [[clang::annotate(1)]] int y2; // expected-error {{expected string literal as argument of 'annotate' attribute}}
__attribute__((annotate("bar", 1))) int z;
[[clang::annotate("bar", 1)]] int z2;
diff --git a/clang/test/Sema/attr-assume.c b/clang/test/Sema/attr-assume.c
index cb07940d02b5b5..98deffa3a74609 100644
--- a/clang/test/Sema/attr-assume.c
+++ b/clang/test/Sema/attr-assume.c
@@ -1,8 +1,8 @@
// RUN: %clang_cc1 -triple i386-apple-darwin9 -fsyntax-only -verify %s
-void f1(void) __attribute__((assume(3))); // expected-error {{'assume' attribute requires a string}}
-void f2(void) __attribute__((assume(int))); // expected-error {{expected expression}}
-void f3(void) __attribute__((assume(for))); // expected-error {{expected expression}}
+void f1(void) __attribute__((assume(3))); // expected-error {{expected string literal as argument of 'assume' attribute}}
+void f2(void) __attribute__((assume(int))); // expected-error {{expected string literal as argument of 'assume' attribute}}
+void f3(void) __attribute__((assume(for))); // expected-error {{expected string literal as argument of 'assume' attribute}}
void f4(void) __attribute__((assume("QQQQ"))); // expected-warning {{unknown assumption string 'QQQQ'; attribute is potentially ignored}}
void f5(void) __attribute__((assume("omp_no_openmp")));
void f6(void) __attribute__((assume("omp_noopenmp"))); // expected-warning {{unknown assumption string 'omp_noopenmp' may be misspelled; attribute is potentially ignored, did you mean 'omp_no_openmp'?}}
@@ -10,5 +10,5 @@ void f7(void) __attribute__((assume("omp_no_openmp_routine"))); // expected-warn
void f8(void) __attribute__((assume("omp_no_openmp1"))); // expected-warning {{unknown assumption string 'omp_no_openmp1' may be misspelled; attribute is potentially ignored, did you mean 'omp_no_openmp'?}}
void f9(void) __attribute__((assume("omp_no_openmp", "omp_no_openmp"))); // expected-error {{'assume' attribute takes one argument}}
-int g1 __attribute__((assume(0))); // expected-warning {{'assume' attribute only applies to functions and Objective-C methods}}
+int g1 __attribute__((assume(0))); // expected-error {{expected string literal as argument of 'assume' attribute}}
int g2 __attribute__((assume("omp_no_openmp"))); // expected-warning {{'assume' attribute only applies to functions and Objective-C methods}}
diff --git a/clang/test/Sema/attr-btf_tag.c b/clang/test/Sema/attr-btf_tag.c
index d33ccdf962825f..cbb21a5a88bb68 100644
--- a/clang/test/Sema/attr-btf_tag.c
+++ b/clang/test/Sema/attr-btf_tag.c
@@ -21,7 +21,7 @@ struct __tag2 __tag3 t2 {
int g1 __tag1;
int g2 __tag_no_arg; // expected-error {{'btf_decl_tag' attribute takes one argument}}
int g3 __tag_2_arg; // expected-error {{'btf_decl_tag' attribute takes one argument}}
-int i1 __invalid; // expected-error {{'btf_decl_tag' attribute requires a string}}
+int i1 __invalid; // expected-error {{expected string literal as argument of 'btf_decl_tag' attribute}}
enum e1 {
E1
diff --git a/clang/test/Sema/attr-btf_type_tag.c b/clang/test/Sema/attr-btf_type_tag.c
index a3ef404f38238b..aa3230a3e9b7f3 100644
--- a/clang/test/Sema/attr-btf_type_tag.c
+++ b/clang/test/Sema/attr-btf_type_tag.c
@@ -8,7 +8,7 @@
#define __tag6 __attribute__((btf_type_tag("tag6")))
int __attribute__((btf_type_tag("tag1", "tag2"))) *invalid1; // expected-error {{'btf_type_tag' attribute takes one argument}}
-int __attribute__((btf_type_tag(2))) *invalid2; // expected-error {{'btf_type_tag' attribute requires a string}}
+int __attribute__((btf_type_tag(2))) *invalid2; // expected-error {{expected string literal as argument of 'btf_type_tag' attribute}}
int * __tag1 __tag2 * __tag3 __tag4 * __tag5 __tag6 *g;
diff --git a/clang/test/Sema/attr-capabilities.c b/clang/test/Sema/attr-capabilities.c
index b28c437935a130..5138803bd5eb7a 100644
--- a/clang/test/Sema/attr-capabilities.c
+++ b/clang/test/Sema/attr-capabilities.c
@@ -17,8 +17,8 @@ int Test3 __attribute__((acquire_capability("test3"))); // expected-warning {{'
int Test4 __attribute__((try_acquire_capability("test4"))); // expected-error {{'try_acquire_capability' attribute only applies to functions}}
int Test5 __attribute__((release_capability("test5"))); // expected-warning {{'release_capability' attribute only applies to functions}}
-struct __attribute__((capability(12))) Test3 {}; // expected-error {{'capability' attribute requires a string}}
-struct __attribute__((shared_capability(Test2))) Test4 {}; // expected-error {{'shared_capability' attribute requires a string}}
+struct __attribute__((capability(12))) Test3 {}; // expected-error {{expected string literal as argument of 'capability' attribute}}
+struct __attribute__((shared_capability(Test2))) Test4 {}; // expected-error {{expected string literal as argument of 'shared_capability' attribute}}
struct __attribute__((capability)) Test5 {}; // expected-error {{'capability' attribute takes one argument}}
struct __attribute__((shared_capability("test1", 12))) Test6 {}; // expected-error {{'shared_capability' attribute takes one argument}}
diff --git a/clang/test/Sema/attr-enforce-tcb-errors.cpp b/clang/test/Sema/attr-enforce-tcb-errors.cpp
index 1ce147ab32df92..b5effe2fe51809 100644
--- a/clang/test/Sema/attr-enforce-tcb-errors.cpp
+++ b/clang/test/Sema/attr-enforce-tcb-errors.cpp
@@ -6,14 +6,14 @@ void no_arguments() __attribute__((enforce_tcb)); // expected-error{{'enforce_tc
void too_many_arguments() __attribute__((enforce_tcb("test", 12))); // expected-error{{'enforce_tcb' attribute takes one argument}}
-void wrong_argument_type() __attribute__((enforce_tcb(12))); // expected-error{{'enforce_tcb' attribute requires a string}}
+void wrong_argument_type() __attribute__((enforce_tcb(12))); // expected-error{{expected string literal as argument of 'enforce_tcb' attribute}}
[[clang::enforce_tcb_leaf("oops")]] int wrong_subject_type_leaf; // expected-warning{{'enforce_tcb_leaf' attribute only applies to functions}}
void no_arguments_leaf() __attribute__((enforce_tcb_leaf)); // expected-error{{'enforce_tcb_leaf' attribute takes one argument}}
void too_many_arguments_leaf() __attribute__((enforce_tcb_leaf("test", 12))); // expected-error{{'enforce_tcb_leaf' attribute takes one argument}}
-void wrong_argument_type_leaf() __attribute__((enforce_tcb_leaf(12))); // expected-error{{'enforce_tcb_leaf' attribute requires a string}}
+void wrong_argument_type_leaf() __attribute__((enforce_tcb_leaf(12))); // expected-error{{expected string literal as argument of 'enforce_tcb_leaf' attribute}}
void foo();
diff --git a/clang/test/Sema/attr-enforce-tcb-errors.m b/clang/test/Sema/attr-enforce-tcb-errors.m
index f82d38c919d1d4..c8d0716553cc6a 100644
--- a/clang/test/Sema/attr-enforce-tcb-errors.m
+++ b/clang/test/Sema/attr-enforce-tcb-errors.m
@@ -20,13 +20,13 @@ - (void)noArguments __attribute__((enforce_tcb)); // expected-error{{'enforce_tc
- (void)tooManyArguments __attribute__((enforce_tcb("test", 12))); // expected-error{{'enforce_tcb' attribute takes one argument}}
-- (void)wrongArgumentType __attribute__((enforce_tcb(12))); // expected-error{{'enforce_tcb' attribute requires a string}}
+- (void)wrongArgumentType __attribute__((enforce_tcb(12))); // expected-error{{expected string literal as argument of 'enforce_tcb' attribute}}
- (void)noArgumentsLeaf __attribute__((enforce_tcb_leaf)); // expected-error{{'enforce_tcb_leaf' attribute takes one argument}}
- (void)tooManyArgumentsLeaf __attribute__((enforce_tcb_leaf("test", 12))); // expected-error{{'enforce_tcb_leaf' attribute takes one argument}}
-- (void)wrongArgumentTypeLeaf __attribute__((enforce_tcb_leaf(12))); // expected-error{{'enforce_tcb_leaf' attribute requires a string}}
+- (void)wrongArgumentTypeLeaf __attribute__((enforce_tcb_leaf(12))); // expected-error{{expected string literal as argument of 'enforce_tcb_leaf' attribute}}
@end
@implementation AClass
diff --git a/clang/test/Sema/attr-error.c b/clang/test/Sema/attr-error.c
index 581bfc43cbc06b..9f500a87be14c6 100644
--- a/clang/test/Sema/attr-error.c
+++ b/clang/test/Sema/attr-error.c
@@ -15,7 +15,7 @@ int bad2(void) {
__attribute__((error("bad2"))); // expected-error {{'error' attribute cannot be applied to a statement}}
}
-__attribute__((error(3))) // expected-error {{'error' attribute requires a string}}
+__attribute__((error(3))) // expected-error {{expected string literal as argument of 'error' attribute}}
int
bad3(void);
diff --git a/clang/test/Sema/attr-handles.cpp b/clang/test/Sema/attr-handles.cpp
index 135467b6c0a8c2..ff1c1f68dfec8e 100644
--- a/clang/test/Sema/attr-handles.cpp
+++ b/clang/test/Sema/attr-handles.cpp
@@ -6,7 +6,7 @@ void (*fp)(int handle [[clang::use_handle("Fuchsia")]]);
auto lambda = [](int handle [[clang::use_handle("Fuchsia")]]){};
void g(int a __attribute__((acquire_handle("Fuchsia")))); // expected-error {{attribute only applies to output parameters}}
void h(int *a __attribute__((acquire_handle))); // expected-error {{'acquire_handle' attribute takes one argument}}
-void h(int *a __attribute__((acquire_handle(1)))); // expected-error {{attribute requires a string}}
+void h(int *a __attribute__((acquire_handle(1)))); // expected-error {{expected string literal as argument of 'acquire_handle' attribute}}
void h(int *a __attribute__((acquire_handle("RandomString", "AndAnother")))); // expected-error {{'acquire_handle' attribute takes one argument}}
__attribute__((release_handle("Fuchsia"))) int i(); // expected-warning {{'release_handle' attribute only applies to parameters}}
__attribute__((use_handle("Fuchsia"))) int j(); // expected-warning {{'use_handle' attribute only applies to parameters}}
diff --git a/clang/test/Sema/attr-section.c b/clang/test/Sema/attr-section.c
index 3ea922c91947e3..1f058c24f980fd 100644
--- a/clang/test/Sema/attr-section.c
+++ b/clang/test/Sema/attr-section.c
@@ -1,7 +1,7 @@
// RUN: %clang_cc1 -verify -fsyntax-only -triple x86_64-apple-darwin9 %s
int x __attribute__((section(
- 42))); // expected-error {{'section' attribute requires a string}}
+ 42))); // expected-error {{expected string literal as argument of 'section' attribute}}
// rdar://4341926
diff --git a/clang/test/Sema/attr-tls_model.c b/clang/test/Sema/attr-tls_model.c
index 9106d39b55a3af..ec99c7aacaa3a8 100644
--- a/clang/test/Sema/attr-tls_model.c
+++ b/clang/test/Sema/attr-tls_model.c
@@ -10,5 +10,5 @@ int x __attribute((tls_model("global-dynamic"))); // expected-error {{'tls_model
static __thread int y __attribute((tls_model("global-dynamic"))); // no-warning
static __thread int y __attribute((tls_model("local", "dynamic"))); // expected-error {{'tls_model' attribute takes one argument}}
-static __thread int y __attribute((tls_model(123))); // expected-error {{'tls_model' attribute requires a string}}
+static __thread int y __attribute((tls_model(123))); // expected-error {{expected string literal as argument of 'tls_model' attribute}}
static __thread int y __attribute((tls_model("foobar"))); // expected-error {{tls_model must be "global-dynamic", "local-dynamic", "initial-exec" or "local-exec"}}
diff --git a/clang/test/Sema/attr-unavailable-message.c b/clang/test/Sema/attr-unavailable-message.c
index b4ae70e0a39cba..0caa943ad8a42f 100644
--- a/clang/test/Sema/attr-unavailable-message.c
+++ b/clang/test/Sema/attr-unavailable-message.c
@@ -8,7 +8,7 @@ double dfoo(double) __attribute__((__unavailable__("NO LONGER"))); // expected-
void bar(void) __attribute__((__unavailable__)); // expected-note {{explicitly marked unavailable}}
-int quux(void) __attribute__((__unavailable__(12))); // expected-error {{'__unavailable__' attribute requires a string}}
+int quux(void) __attribute__((__unavailable__(12))); // expected-error {{expected string literal as argument of '__unavailable__' attribute}}
#define ACCEPTABLE "Use something else"
int quux2(void) __attribute__((__unavailable__(ACCEPTABLE)));
diff --git a/clang/test/Sema/attr-warning.c b/clang/test/Sema/attr-warning.c
index 0973f3c8eb4bd7..7510e88d291b1a 100644
--- a/clang/test/Sema/attr-warning.c
+++ b/clang/test/Sema/attr-warning.c
@@ -15,7 +15,7 @@ int bad2(void) {
__attribute__((warning("bad2"))); // expected-error {{'warning' attribute cannot be applied to a statement}}
}
-__attribute__((warning(3))) // expected-error {{'warning' attribute requires a string}}
+__attribute__((warning(3))) // expected-error {{expected string literal as argument of 'warning' attribute}}
int
bad3(void);
diff --git a/clang/test/Sema/diagnose_if.c b/clang/test/Sema/diagnose_if.c
index 6297545781f90d..4df39916c031e3 100644
--- a/clang/test/Sema/diagnose_if.c
+++ b/clang/test/Sema/diagnose_if.c
@@ -6,7 +6,7 @@ void failure1(void) _diagnose_if(); // expected-error{{exactly 3 arguments}}
void failure2(void) _diagnose_if(0); // expected-error{{exactly 3 arguments}}
void failure3(void) _diagnose_if(0, ""); // expected-error{{exactly 3 arguments}}
void failure4(void) _diagnose_if(0, "", "error", 1); // expected-error{{exactly 3 arguments}}
-void failure5(void) _diagnose_if(0, 0, "error"); // expected-error{{requires a string}}
+void failure5(void) _diagnose_if(0, 0, "error"); // expected-error{{expected string literal as argument of 'diagnose_if' attribute}}
void failure6(void) _diagnose_if(0, "", "invalid"); // expected-error{{invalid diagnostic type for 'diagnose_if'; use "error" or "warning" instead}}
void failure7(void) _diagnose_if(0, "", "ERROR"); // expected-error{{invalid diagnostic type}}
void failure8(int a) _diagnose_if(a, "", ""); // expected-error{{invalid diagnostic type}}
diff --git a/clang/test/Sema/enable_if.c b/clang/test/Sema/enable_if.c
index 22eb84fa7275c0..9d46c71274d692 100644
--- a/clang/test/Sema/enable_if.c
+++ b/clang/test/Sema/enable_if.c
@@ -105,7 +105,7 @@ __attribute__((enable_if(n == 0, "chosen when 'n' is zero"))) void f1(int n); //
int n __attribute__((enable_if(1, "always chosen"))); // expected-warning{{'enable_if' attribute only applies to functions}}
-void f(int n) __attribute__((enable_if("chosen when 'n' is zero", n == 0))); // expected-error{{'enable_if' attribute requires a string}}
+void f(int n) __attribute__((enable_if("chosen when 'n' is zero", n == 0))); // expected-error{{expected string literal as argument of 'enable_if' attribute}}
void f(int n) __attribute__((enable_if())); // expected-error{{'enable_if' attribute requires exactly 2 arguments}}
diff --git a/clang/test/SemaCXX/attr-deprecated-replacement-error.cpp b/clang/test/SemaCXX/attr-deprecated-replacement-error.cpp
index 54d0f9e74f3403..8c9d9b29c55352 100644
--- a/clang/test/SemaCXX/attr-deprecated-replacement-error.cpp
+++ b/clang/test/SemaCXX/attr-deprecated-replacement-error.cpp
@@ -5,13 +5,13 @@
#endif
int a1 [[deprecated("warning", "fixit")]]; // expected-error{{'deprecated' attribute takes no more than 1 argument}}
-int a2 [[deprecated("warning", 1)]]; // expected-error{{'deprecated' attribute takes no more than 1 argument}}
+int a2 [[deprecated("warning", 1)]]; // expected-error{{expected string literal as argument of 'deprecated' attribute}}
int b1 [[gnu::deprecated("warning", "fixit")]]; // expected-error{{'deprecated' attribute takes no more than 1 argument}}
-int b2 [[gnu::deprecated("warning", 1)]]; // expected-error{{'deprecated' attribute takes no more than 1 argument}}
+int b2 [[gnu::deprecated("warning", 1)]]; // expected-error{{expected string literal as argument of 'deprecated' attribute}}
__declspec(deprecated("warning", "fixit")) int c1; // expected-error{{'deprecated' attribute takes no more than 1 argument}}
-__declspec(deprecated("warning", 1)) int c2; // expected-error{{'deprecated' attribute takes no more than 1 argument}}
+__declspec(deprecated("warning", 1)) int c2; // expected-error{{expected string literal as argument of 'deprecated' attribute}}
int d1 __attribute__((deprecated("warning", "fixit")));
-int d2 __attribute__((deprecated("warning", 1))); // expected-error{{'deprecated' attribute requires a string}}
+int d2 __attribute__((deprecated("warning", 1))); // expected-error{{expected string literal as argument of 'deprecated' attribute}}
diff --git a/clang/test/SemaCXX/attr-no-sanitize.cpp b/clang/test/SemaCXX/attr-no-sanitize.cpp
index 9e13fd3c02702e..a464947fe5a346 100644
--- a/clang/test/SemaCXX/attr-no-sanitize.cpp
+++ b/clang/test/SemaCXX/attr-no-sanitize.cpp
@@ -4,7 +4,7 @@
int f1() __attribute__((no_sanitize)); // expected-error{{'no_sanitize' attribute takes at least 1 argument}}
-int f2() __attribute__((no_sanitize(1))); // expected-error{{'no_sanitize' attribute requires a string}}
+int f2() __attribute__((no_sanitize(1))); // expected-error{{expected string literal as argument of 'no_sanitize' attribute}}
__attribute__((no_sanitize("all"))) int global; // expected-warning{{'no_sanitize' attribute argument 'all' not supported on a global variable}}
__attribute__((no_sanitize("unknown"))) int global2; // expected-warning{{unknown sanitizer 'unknown' ignored}}
diff --git a/clang/test/SemaCXX/attr-section.cpp b/clang/test/SemaCXX/attr-section.cpp
index e2418e0abcc5ff..1c07e3dd8bba2b 100644
--- a/clang/test/SemaCXX/attr-section.cpp
+++ b/clang/test/SemaCXX/attr-section.cpp
@@ -1,7 +1,7 @@
// RUN: %clang_cc1 -verify -fsyntax-only -triple x86_64-linux-gnu %s
int x __attribute__((section(
- 42))); // expected-error {{'section' attribute requires a string}}
+ 42))); // expected-error {{expected string literal as argument of 'section' attribute}}
// PR6007
diff --git a/clang/test/SemaCXX/attr-weakref.cpp b/clang/test/SemaCXX/attr-weakref.cpp
index 46ca5ab2068203..4e1834096ebede 100644
--- a/clang/test/SemaCXX/attr-weakref.cpp
+++ b/clang/test/SemaCXX/attr-weakref.cpp
@@ -33,6 +33,6 @@ int a9 __attribute__((weakref)); // expected-error {{weakref declaration of 'a9
static int a10();
int a10() __attribute__((weakref ("foo")));
-static int v __attribute__((weakref(a1), alias("foo"))); // expected-error {{'weakref' attribute requires a string}}
+static int v __attribute__((weakref(a1), alias("foo"))); // expected-error {{expected string literal as argument of 'weakref' attribute}}
__attribute__((weakref ("foo"))) auto a11 = 1; // expected-error {{weakref declaration must have internal linkage}}
diff --git a/clang/test/SemaCXX/suppress.cpp b/clang/test/SemaCXX/suppress.cpp
index d88ae0bbca00f9..29544b3c573ccc 100644
--- a/clang/test/SemaCXX/suppress.cpp
+++ b/clang/test/SemaCXX/suppress.cpp
@@ -16,7 +16,7 @@ void f_() {
[[gsl::suppress]] int x; // expected-error {{'suppress' attribute takes at least 1 argument}}
[[gsl::suppress()]] int y; // expected-error {{'suppress' attribute takes at least 1 argument}}
int [[gsl::suppress("r")]] z; // expected-error {{'suppress' attribute cannot be applied to types}}
- [[gsl::suppress(f_)]] float f; // expected-error {{'suppress' attribute requires a string}}
+ [[gsl::suppress(f_)]] float f; // expected-error {{expected string literal as argument of 'suppress' attribut}}
}
union [[gsl::suppress("type.1")]] U {
diff --git a/clang/test/SemaObjC/attr-swift_bridge.m b/clang/test/SemaObjC/attr-swift_bridge.m
index 8f53ed8154588c..0464e3f326e0ab 100644
--- a/clang/test/SemaObjC/attr-swift_bridge.m
+++ b/clang/test/SemaObjC/attr-swift_bridge.m
@@ -5,7 +5,7 @@
@interface I
@end
-// expected-error at +1 {{'__swift_bridge__' attribute requires a string}}
+// expected-error at +1 {{expected string literal as argument of '__swift_bridge__' attribute}}
__attribute__((__swift_bridge__(1)))
@interface J
@end
diff --git a/clang/test/SemaObjC/objc-asm-attribute-neg-test.m b/clang/test/SemaObjC/objc-asm-attribute-neg-test.m
index 9941189357ba1e..ac3871969fe21a 100644
--- a/clang/test/SemaObjC/objc-asm-attribute-neg-test.m
+++ b/clang/test/SemaObjC/objc-asm-attribute-neg-test.m
@@ -5,7 +5,7 @@
@interface BInterface
@end
-__attribute__((objc_runtime_name(123))) // expected-error {{'objc_runtime_name' attribute requires a string}}
+__attribute__((objc_runtime_name(123))) // expected-error {{expected string literal as argument of 'objc_runtime_name' attribute}}
@protocol BProtocol1
@end
@@ -14,7 +14,7 @@ @protocol Protocol
@end
__attribute__((objc_runtime_name("MySecretNamespace.Message")))
- at interface Message <Protocol> {
+ at interface Message <Protocol> {
__attribute__((objc_runtime_name("MySecretNamespace.Message"))) // expected-error {{'objc_runtime_name' attribute only applies to Objective-C interfaces and Objective-C protocols}}
id MyIVAR;
}
diff --git a/clang/test/SemaObjC/validate-attr-swift_attr.m b/clang/test/SemaObjC/validate-attr-swift_attr.m
index 4ff434d179725d..2c73b0a892722c 100644
--- a/clang/test/SemaObjC/validate-attr-swift_attr.m
+++ b/clang/test/SemaObjC/validate-attr-swift_attr.m
@@ -5,7 +5,7 @@
@interface I
@end
-// expected-error at +1 {{'swift_attr' attribute requires a string}}
+// expected-error at +1 {{expected string literal as argument of 'swift_attr' attribute}}
__attribute__((swift_attr(1)))
@interface J
@end
diff --git a/clang/test/SemaTemplate/attributes.cpp b/clang/test/SemaTemplate/attributes.cpp
index a7081e83470aa1..9fd448a5e9353e 100644
--- a/clang/test/SemaTemplate/attributes.cpp
+++ b/clang/test/SemaTemplate/attributes.cpp
@@ -25,7 +25,7 @@ namespace attribute_aligned {
{
__attribute__((aligned(Align))) char storage[Size];
};
-
+
template<typename T>
class C {
public:
@@ -95,11 +95,11 @@ void UseAnnotations() { HasAnnotations<int>(); }
template <int... Is> [[clang::annotate("ANNOTATE_BAZ", Is...)]] void HasPackAnnotations();
void UsePackAnnotations() { HasPackAnnotations<1, 2, 3>(); }
-template <int... Is> [[clang::annotate(Is...)]] void HasOnlyPackAnnotation() {} // expected-error {{'annotate' attribute takes at least 1 argument}} expected-error {{'annotate' attribute requires a string}}
+template <int... Is> [[clang::annotate(Is...)]] void HasOnlyPackAnnotation() {} // expected-error {{expected string literal as argument of 'annotate' attribute}}
void UseOnlyPackAnnotations() {
- HasOnlyPackAnnotation<>(); // expected-note {{in instantiation of function template specialization 'attribute_annotate::HasOnlyPackAnnotation<>' requested here}}
- HasOnlyPackAnnotation<1>(); // expected-note {{in instantiation of function template specialization 'attribute_annotate::HasOnlyPackAnnotation<1>' requested here}}
+ HasOnlyPackAnnotation<>();
+ HasOnlyPackAnnotation<1>();
}
// CHECK: ClassTemplateDecl {{.*}} AnnotatedPackTemplateStruct
@@ -276,40 +276,21 @@ void UseOnlyPackAnnotations() {
// CHECK-NEXT: value: Int 6
// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 6
// CHECK-NEXT: CXXRecordDecl {{.*}} implicit struct AnnotatedPackTemplateStruct
-// CHECK-NEXT: ClassTemplatePartialSpecializationDecl {{.*}} struct AnnotatedPackTemplateStruct definition
-// CHECK-NEXT: DefinitionData
-// CHECK-NEXT: DefaultConstructor
-// CHECK-NEXT: CopyConstructor
-// CHECK-NEXT: MoveConstructor
-// CHECK-NEXT: CopyAssignment
-// CHECK-NEXT: MoveAssignment
-// CHECK-NEXT: Destructor
-// CHECK-NEXT: TemplateArgument{{.*}} type 'char'
-// CHECK-NEXT: BuiltinType {{.*}} 'char'
-// CHECK-NEXT: TemplateArgument{{.*}} pack
-// CHECK-NEXT: TemplateArgument{{.*}} expr
-// CHECK-NEXT: PackExpansionExpr {{.*}} 'int'
-// CHECK-NEXT: DeclRefExpr {{.*}} 'int' NonTypeTemplateParm {{.*}} 'Is' 'int'
-// CHECK-NEXT: NonTypeTemplateParmDecl {{.*}} referenced 'int' depth 0 index 0 ... Is
-// CHECK-NEXT: AnnotateAttr {{.*}} ""
-// CHECK-NEXT: PackExpansionExpr {{.*}} '<dependent type>'
-// CHECK-NEXT: DeclRefExpr {{.*}} 'int' NonTypeTemplateParm {{.*}} 'Is' 'int'
-// CHECK-NEXT: CXXRecordDecl {{.*}} implicit struct AnnotatedPackTemplateStruct
template <typename T, int... Is> struct [[clang::annotate("ANNOTATE_FOZ", Is...)]] AnnotatedPackTemplateStruct{};
template <int... Is> struct [[clang::annotate("ANNOTATE_BOO", Is...)]] AnnotatedPackTemplateStruct<int, Is...>{};
template <int... Is> struct [[clang::annotate("ANNOTATE_FOZ", 4, 5, 6)]] AnnotatedPackTemplateStruct<float, Is...>{};
-template <int... Is> struct [[clang::annotate(Is...)]] AnnotatedPackTemplateStruct<char, Is...>{}; // expected-error {{'annotate' attribute requires a string}} expected-error {{'annotate' attribute takes at least 1 argument}}
+template <int... Is> struct [[clang::annotate(Is...)]] AnnotatedPackTemplateStruct<char, Is...>{}; // expected-error {{expected string literal as argument of 'annotate' attribute}}
void UseAnnotatedPackTemplateStructSpecializations() {
AnnotatedPackTemplateStruct<int, 1, 2, 3> Instance1{};
AnnotatedPackTemplateStruct<float, 3, 2, 1> Instance2{};
AnnotatedPackTemplateStruct<bool, 7, 8, 9> Instance3{};
- AnnotatedPackTemplateStruct<char, 1, 2, 3> Instance4{}; // expected-note {{in instantiation of template class 'attribute_annotate::AnnotatedPackTemplateStruct<char, 1, 2, 3>' requested here}}
- AnnotatedPackTemplateStruct<char> Instance5{}; // expected-note {{in instantiation of template class 'attribute_annotate::AnnotatedPackTemplateStruct<char>' requested here}}
+ AnnotatedPackTemplateStruct<char, 1, 2, 3> Instance4{};
+ AnnotatedPackTemplateStruct<char> Instance5{};
}
// CHECK: ClassTemplateDecl {{.*}} InvalidAnnotatedPackTemplateStruct
// CHECK-NEXT: TemplateTypeParmDecl {{.*}} typename depth 0 index 0 T
-// CHECK-NEXT: NonTypeTemplateParmDecl {{.*}} referenced 'int' depth 0 index 1 ... Is
+// CHECK-NEXT: NonTypeTemplateParmDecl {{.*}} 'int' depth 0 index 1 ... Is
// CHECK-NEXT: CXXRecordDecl {{.*}} struct InvalidAnnotatedPackTemplateStruct definition
// CHECK-NEXT: DefinitionData
// CHECK-NEXT: DefaultConstructor
@@ -318,9 +299,6 @@ void UseAnnotatedPackTemplateStructSpecializations() {
// CHECK-NEXT: CopyAssignment
// CHECK-NEXT: MoveAssignment
// CHECK-NEXT: Destructor
-// CHECK-NEXT: AnnotateAttr {{.*}} ""
-// CHECK-NEXT: PackExpansionExpr {{.*}} '<dependent type>'
-// CHECK-NEXT: DeclRefExpr {{.*}} 'int' NonTypeTemplateParm {{.*}} 'Is' 'int'
// CHECK-NEXT: CXXRecordDecl {{.*}} implicit struct InvalidAnnotatedPackTemplateStruct
// CHECK-NEXT: ClassTemplateSpecialization {{.*}} 'InvalidAnnotatedPackTemplateStruct'
// CHECK-NEXT: ClassTemplateSpecializationDecl {{.*}} struct InvalidAnnotatedPackTemplateStruct definition
@@ -446,7 +424,7 @@ void UseAnnotatedPackTemplateStructSpecializations() {
// CHECK-NEXT: TemplateArgument{{.*}} integral 6
// CHECK-NEXT: TemplateArgument{{.*}} integral 7
// CHECK-NEXT: CXXRecordDecl {{.*}} implicit struct InvalidAnnotatedPackTemplateStruct
-template <typename T, int... Is> struct [[clang::annotate(Is...)]] InvalidAnnotatedPackTemplateStruct{}; // expected-error {{'annotate' attribute requires a string}} expected-error {{'annotate' attribute takes at least 1 argument}}
+template <typename T, int... Is> struct InvalidAnnotatedPackTemplateStruct{};
template <int... Is> struct [[clang::annotate("ANNOTATE_BIR", Is...)]] InvalidAnnotatedPackTemplateStruct<int, Is...>{};
template <int... Is> struct InvalidAnnotatedPackTemplateStruct<float, Is...> {};
template <> struct InvalidAnnotatedPackTemplateStruct<char, 5, 6, 7> {};
@@ -454,8 +432,8 @@ void UseInvalidAnnotatedPackTemplateStruct() {
InvalidAnnotatedPackTemplateStruct<int, 1, 2, 3> Instance1{};
InvalidAnnotatedPackTemplateStruct<float, 3, 2, 1> Instance2{};
InvalidAnnotatedPackTemplateStruct<char, 5, 6, 7> Instance3{};
- InvalidAnnotatedPackTemplateStruct<bool, 7, 8, 9> Instance4{}; // expected-note {{in instantiation of template class 'attribute_annotate::InvalidAnnotatedPackTemplateStruct<bool, 7, 8, 9>' requested here}}
- InvalidAnnotatedPackTemplateStruct<bool> Instance5{}; // expected-note {{in instantiation of template class 'attribute_annotate::InvalidAnnotatedPackTemplateStruct<bool>' requested here}}
+ InvalidAnnotatedPackTemplateStruct<bool, 7, 8, 9> Instance4{};
+ InvalidAnnotatedPackTemplateStruct<bool> Instance5{};
}
// CHECK: FunctionTemplateDecl {{.*}} RedeclaredAnnotatedFunc
diff --git a/clang/utils/TableGen/ClangAttrEmitter.cpp b/clang/utils/TableGen/ClangAttrEmitter.cpp
index 3dda407fad84af..fe9e4cd757d398 100644
--- a/clang/utils/TableGen/ClangAttrEmitter.cpp
+++ b/clang/utils/TableGen/ClangAttrEmitter.cpp
@@ -2297,6 +2297,22 @@ static bool isVariadicExprArgument(const Record *Arg) {
.Default(false);
}
+static bool isStringLiteralArgument(const Record *Arg) {
+ return !Arg->getSuperClasses().empty() &&
+ llvm::StringSwitch<bool>(
+ Arg->getSuperClasses().back().first->getName())
+ .Case("StringArgument", true)
+ .Default(false);
+}
+
+static bool isVariadicStringLiteralArgument(const Record *Arg) {
+ return !Arg->getSuperClasses().empty() &&
+ llvm::StringSwitch<bool>(
+ Arg->getSuperClasses().back().first->getName())
+ .Case("VariadicStringArgument", true)
+ .Default(false);
+}
+
static void emitClangAttrVariadicIdentifierArgList(RecordKeeper &Records,
raw_ostream &OS) {
OS << "#if defined(CLANG_ATTR_VARIADIC_IDENTIFIER_ARG_LIST)\n";
@@ -2317,6 +2333,34 @@ static void emitClangAttrVariadicIdentifierArgList(RecordKeeper &Records,
OS << "#endif // CLANG_ATTR_VARIADIC_IDENTIFIER_ARG_LIST\n\n";
}
+// Emits the list of arguments that should be parsed as unevaluated string
+// literals for each attribute.
+static void emitClangAttrUnevaluatedStringLiteralList(RecordKeeper &Records,
+ raw_ostream &OS) {
+ OS << "#if defined(CLANG_ATTR_STRING_LITERAL_ARG_LIST)\n";
+ std::vector<Record *> Attrs = Records.getAllDerivedDefinitions("Attr");
+ for (const auto *Attr : Attrs) {
+ std::vector<Record *> Args = Attr->getValueAsListOfDefs("Args");
+ uint32_t Bits = 0;
+ assert(Args.size() <= 32 && "unsupported number of arguments in attribute");
+ for (uint32_t N = 0; N < Args.size(); ++N) {
+ Bits |= (isStringLiteralArgument(Args[N]) << N);
+ // If we have a variadic string argument, set all the remaining bits to 1
+ if (isVariadicStringLiteralArgument(Args[N])) {
+ Bits |= maskTrailingZeros<decltype(Bits)>(N);
+ break;
+ }
+ }
+ if (!Bits)
+ continue;
+ // All these spellings have at least one string literal has argument.
+ forEachUniqueSpelling(*Attr, [&](const FlattenedSpelling &S) {
+ OS << ".Case(\"" << S.name() << "\", " << Bits << ")\n";
+ });
+ }
+ OS << "#endif // CLANG_ATTR_STRING_LITERAL_ARG_LIST\n\n";
+}
+
// Emits the first-argument-is-identifier property for attributes.
static void emitClangAttrIdentifierArgList(RecordKeeper &Records, raw_ostream &OS) {
OS << "#if defined(CLANG_ATTR_IDENTIFIER_ARG_LIST)\n";
@@ -4611,6 +4655,7 @@ void EmitClangAttrParserStringSwitches(RecordKeeper &Records,
emitSourceFileHeader("Parser-related llvm::StringSwitch cases", OS);
emitClangAttrArgContextList(Records, OS);
emitClangAttrIdentifierArgList(Records, OS);
+ emitClangAttrUnevaluatedStringLiteralList(Records, OS);
emitClangAttrVariadicIdentifierArgList(Records, OS);
emitClangAttrThisIsaIdentifierArgList(Records, OS);
emitClangAttrAcceptsExprPack(Records, OS);
diff --git a/clang/www/cxx_status.html b/clang/www/cxx_status.html
index 9c40292ce605fb..da0a1c219c0ecc 100755
--- a/clang/www/cxx_status.html
+++ b/clang/www/cxx_status.html
@@ -115,12 +115,7 @@ <h2 id="cxx26">C++2c implementation status</h2>
<tr>
<td>Unevaluated strings</td>
<td><a href="https://wg21.link/P2361R6">P2361R6</a></td>
- <td class="partial" align="center">
- <details>
- <summary>Clang 17 (Partial)</summary>
- Attributes arguments don't yet parse as unevaluated string literals.
- </details>
- </td>
+ <td class="unreleased" align="center">Clang 18</td>
</tr>
<tr>
<td>Add @, $, and ` to the basic character set</td>
More information about the cfe-commits
mailing list