[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