thakis updated this revision to Diff 70013.
thakis marked an inline comment as done.
thakis added a comment.

Sorry about the delay! Now with custom parsing code that accepts uuid() without 
quotes. I thought this would be complicated, but ended up being not so bad in 
the end. See the tests for several interesting edge cases.

I figured I'd punt the deprecation warning to a (fast) follow-up.


https://reviews.llvm.org/D23895

Files:
  include/clang/Basic/Attr.td
  include/clang/Basic/Attributes.h
  include/clang/Parse/Parser.h
  include/clang/Sema/AttributeList.h
  lib/Parse/ParseDecl.cpp
  lib/Parse/ParseDeclCXX.cpp
  lib/Parse/ParseObjc.cpp
  lib/Parse/ParseOpenMP.cpp
  lib/Parse/Parser.cpp
  test/CodeGenCXX/microsoft-uuidof.cpp
  test/Parser/MicrosoftExtensions.cpp
  test/Parser/ms-square-bracket-attributes.mm
  test/Sema/MicrosoftExtensions.c
  utils/TableGen/ClangAttrEmitter.cpp

Index: utils/TableGen/ClangAttrEmitter.cpp
===================================================================
--- utils/TableGen/ClangAttrEmitter.cpp
+++ utils/TableGen/ClangAttrEmitter.cpp
@@ -1312,6 +1312,9 @@
     } else if (Variety == "Declspec") {
       Prefix = " __declspec(";
       Suffix = ")";
+    } else if (Variety == "Microsoft") {
+      Prefix = "[";
+      Suffix = "]";
     } else if (Variety == "Keyword") {
       Prefix = " ";
       Suffix = "";
@@ -2295,7 +2298,7 @@
   // Separate all of the attributes out into four group: generic, C++11, GNU,
   // and declspecs. Then generate a big switch statement for each of them.
   std::vector<Record *> Attrs = Records.getAllDerivedDefinitions("Attr");
-  std::vector<Record *> Declspec, GNU, Pragma;
+  std::vector<Record *> Declspec, Microsoft, GNU, Pragma;
   std::map<std::string, std::vector<Record *>> CXX;
 
   // Walk over the list of all attributes, and split them out based on the
@@ -2308,6 +2311,8 @@
         GNU.push_back(R);
       else if (Variety == "Declspec")
         Declspec.push_back(R);
+      else if (Variety == "Microsoft")
+        Microsoft.push_back(R);
       else if (Variety == "CXX11")
         CXX[SI.nameSpace()].push_back(R);
       else if (Variety == "Pragma")
@@ -2323,6 +2328,9 @@
   OS << "case AttrSyntax::Declspec:\n";
   OS << "  return llvm::StringSwitch<int>(Name)\n";
   GenerateHasAttrSpellingStringSwitch(Declspec, OS, "Declspec");
+  OS << "case AttrSyntax::Microsoft:\n";
+  OS << "  return llvm::StringSwitch<int>(Name)\n";
+  GenerateHasAttrSpellingStringSwitch(Microsoft, OS, "Microsoft");
   OS << "case AttrSyntax::Pragma:\n";
   OS << "  return llvm::StringSwitch<int>(Name)\n";
   GenerateHasAttrSpellingStringSwitch(Pragma, OS, "Pragma");
@@ -2361,8 +2369,9 @@
                 .Case("GNU", 0)
                 .Case("CXX11", 1)
                 .Case("Declspec", 2)
-                .Case("Keyword", 3)
-                .Case("Pragma", 4)
+                .Case("Microsoft", 3)
+                .Case("Keyword", 4)
+                .Case("Pragma", 5)
                 .Default(0)
          << " && Scope == \"" << Spellings[I].nameSpace() << "\")\n"
          << "        return " << I << ";\n";
@@ -2982,7 +2991,8 @@
   emitSourceFileHeader("Attribute name matcher", OS);
 
   std::vector<Record *> Attrs = Records.getAllDerivedDefinitions("Attr");
-  std::vector<StringMatcher::StringPair> GNU, Declspec, CXX11, Keywords, Pragma;
+  std::vector<StringMatcher::StringPair> GNU, Declspec, Microsoft, CXX11,
+      Keywords, Pragma;
   std::set<std::string> Seen;
   for (const auto *A : Attrs) {
     const Record &Attr = *A;
@@ -3024,6 +3034,8 @@
           Matches = &GNU;
         else if (Variety == "Declspec")
           Matches = &Declspec;
+        else if (Variety == "Microsoft")
+          Matches = &Microsoft;
         else if (Variety == "Keyword")
           Matches = &Keywords;
         else if (Variety == "Pragma")
@@ -3048,6 +3060,8 @@
   StringMatcher("Name", GNU, OS).Emit();
   OS << "  } else if (AttributeList::AS_Declspec == Syntax) {\n";
   StringMatcher("Name", Declspec, OS).Emit();
+  OS << "  } else if (AttributeList::AS_Microsoft == Syntax) {\n";
+  StringMatcher("Name", Microsoft, OS).Emit();
   OS << "  } else if (AttributeList::AS_CXX11 == Syntax) {\n";
   StringMatcher("Name", CXX11, OS).Emit();
   OS << "  } else if (AttributeList::AS_Keyword == Syntax || ";
@@ -3131,8 +3145,9 @@
   GNU = 1 << 0,
   CXX11 = 1 << 1,
   Declspec = 1 << 2,
-  Keyword = 1 << 3,
-  Pragma = 1 << 4
+  Microsoft = 1 << 3,
+  Keyword = 1 << 4,
+  Pragma = 1 << 5
 };
 
 static void WriteDocumentation(const DocumentationData &Doc,
@@ -3180,6 +3195,7 @@
                             .Case("GNU", GNU)
                             .Case("CXX11", CXX11)
                             .Case("Declspec", Declspec)
+                            .Case("Microsoft", Microsoft)
                             .Case("Keyword", Keyword)
                             .Case("Pragma", Pragma);
 
Index: test/Sema/MicrosoftExtensions.c
===================================================================
--- test/Sema/MicrosoftExtensions.c
+++ test/Sema/MicrosoftExtensions.c
@@ -28,6 +28,8 @@
 
 struct __declspec(uuid("00000000-0000-0000-C000-000000000046")) IUnknown {}; /* expected-error {{'uuid' attribute is not supported in C}} */
 
+[uuid("00000000-0000-0000-C000-000000000046")] struct IUnknown2 {}; /* expected-error {{'uuid' attribute is not supported in C}} */
+
 typedef struct notnested {
   long bad1;
   long bad2;
Index: test/Parser/ms-square-bracket-attributes.mm
===================================================================
--- test/Parser/ms-square-bracket-attributes.mm
+++ test/Parser/ms-square-bracket-attributes.mm
@@ -0,0 +1,139 @@
+// RUN: %clang_cc1 -fsyntax-only -std=c++14 -verify -fms-extensions %s
+
+typedef struct _GUID {
+  unsigned long Data1;
+  unsigned short Data2;
+  unsigned short Data3;
+  unsigned char Data4[8];
+} GUID;
+constexpr bool operator==(GUID a, GUID b) {
+  return a.Data1 == b.Data1;
+}
+
+
+namespace {
+// cl.exe supports [] attributes on decls like so:
+[uuid( "000000A0-0000-0000-C000-000000000049" )] struct struct_with_uuid;
+
+// Optionally, the uuid can be surrounded by one set of braces.
+[uuid(
+  "{000000A0-0000-0000-C000-000000000049}"
+)] struct struct_with_uuid_brace;
+
+// uuids must be ascii string literals.
+// expected-error@+1 {{uuid attribute contains a malformed GUID}}
+[uuid(u8"000000A0-0000-0000-C000-000000000049")] struct struct_with_uuid_u8;
+// expected-error@+1 {{uuid attribute contains a malformed GUID}}
+[uuid(L"000000A0-0000-0000-C000-000000000049")] struct struct_with_uuid_L;
+
+// cl.exe doesn't allow raw string literals in []-style attributes, but does
+// allow it for __declspec(uuid()) (u8 literals etc are not allowed there
+// either).  Since raw string literals not being allowed seems like an
+// implementation artifact in cl and not allowing them makes the parse code
+// a bit unnatural, do allow this.
+[uuid(R"(000000A0-0000-0000-C000-000000000049)")] struct struct_with_uuid_raw;
+
+// Likewise, cl supports UCNs in declspec uuid, but not in []-style uuid.
+// clang-cl allows them in both.
+[uuid("000000A0-0000\u002D0000-C000-000000000049")] struct struct_with_uuid_ucn;
+
+// cl doesn't allow string concatenation in []-style attributes, for no good
+// reason.  clang-cl allows them.
+[uuid("000000A0-00" "00-0000-C000-000000000049")] struct struct_with_uuid_split;
+
+
+// In addition to uuids in string literals, cl also allows uuids that are not
+// in a string literal, only delimited by ().  The contents of () are almost
+// treated like a literal (spaces there aren't ignored), but macro substitution,
+// \ newline escapes, and so on are performed.
+
+[ uuid (000000A0-0000-0000-C000-000000000049) ] struct struct_with_uuid2;
+[uuid({000000A0-0000-0000-C000-000000000049})] struct struct_with_uuid2_brace;
+
+// The non-quoted form doesn't allow any whitespace inside the parens:
+// expected-error@+1 {{uuid attribute contains a malformed GUID}}
+[uuid( 000000A0-0000-0000-C000-000000000049)] struct struct_with_uuid2;
+// expected-error@+1 {{uuid attribute contains a malformed GUID}}
+[uuid(000000A0-0000 -0000-C000-000000000049)] struct struct_with_uuid2;
+// expected-error@+2 {{uuid attribute contains a malformed GUID}}
+[uuid(000000A0-0000
+-0000-C000-000000000049)] struct struct_with_uuid2;
+// expected-error@+1 {{uuid attribute contains a malformed GUID}}
+[uuid(000000A0-0000/**/-0000-C000-000000000049)] struct struct_with_uuid2;
+// expected-error@+1 {{uuid attribute contains a malformed GUID}}
+[uuid(000000A0-0000-0000-C000-000000000049 )] struct struct_with_uuid2;
+// expected-error@+2 {{uuid attribute contains a malformed GUID}}
+[uuid(000000A0-0000-0000-C000-000000000049
+)] struct struct_with_uuid2;
+
+// Line continuations and macro substitution is fine though:
+[uuid(000000A0-0000-0000-\
+C000-000000000049)] struct struct_with_uuid2_cont;
+#define UUID 000000A0-0000-0000-C000-000000000049
+#define UUID_PART 000000A0-0000
+[uuid(UUID)] struct struct_with_uuid2_macro;
+[uuid(UUID_PART-0000-C000-000000000049)] struct struct_with_uuid2_macro_part;
+
+// Both cl and clang-cl accept trigraphs here (with /Zc:trigraphs, off by
+// default)
+// expected-warning@+1 2{{trigraph converted}}
+[uuid(??<000000A0-0000-0000-C000-000000000049??>)]
+struct struct_with_uuid2_trigraph;
+
+// UCNs cannot be used in this form because they're prohibited by C99.
+// expected-error@+1 {{character '-' cannot be specified by a universal character name}}
+[uuid(000000A0-0000\u002D0000-C000-000000000049)] struct struct_with_uuid2_ucn;
+
+// Invalid digits.
+// expected-error@+1 {{uuid attribute contains a malformed GUID}}
+[uuid(0Z0000A0-0000-0000-C000-000000000049)] struct struct_with_uuid2;
+
+void use_it() {
+  (void)__uuidof(struct_with_uuid);
+  (void)__uuidof(struct_with_uuid_brace);
+  (void)__uuidof(struct_with_uuid_raw);
+  (void)__uuidof(struct_with_uuid_ucn);
+  (void)__uuidof(struct_with_uuid_split);
+
+  (void)__uuidof(struct_with_uuid2);
+  (void)__uuidof(struct_with_uuid2_brace);
+  (void)__uuidof(struct_with_uuid2_cont);
+  (void)__uuidof(struct_with_uuid2_macro);
+  (void)__uuidof(struct_with_uuid2_macro_part);
+  (void)__uuidof(struct_with_uuid2_trigraph);
+}
+}
+
+// clang supports these on toplevel decls, but not on local decls since this
+// syntax is ambiguous with lambdas and Objective-C message send expressions.
+// This file documents clang's shortcomings and lists a few constructs that
+// one has to keep in mind when trying to fix this.  System headers only seem
+// to use these attributes on toplevel decls, so supporting this is not very
+// important.
+
+void local_class() {
+  // FIXME: MSVC accepts, but we reject due to ambiguity.
+  // expected-error@+1 {{expected body of lambda expression}}
+  [uuid("a5a7bd07-3b14-49bc-9399-de066d4d72cd")] struct Local {
+    int x;
+  };
+}
+
+void useit(int);
+int lambda() {
+  int uuid = 42;
+  [uuid]() {
+    useit(uuid);
+  }();
+}
+
+@interface NSObject
+- (void)retain;
+@end
+int message_send(id uuid) {
+  [uuid retain]; 
+}
+NSObject* uuid(const char*);
+int message_send2() {
+  [uuid("a5a7bd07-3b14-49bc-9399-de066d4d72cd") retain]; 
+}
Index: test/Parser/MicrosoftExtensions.cpp
===================================================================
--- test/Parser/MicrosoftExtensions.cpp
+++ test/Parser/MicrosoftExtensions.cpp
@@ -49,6 +49,7 @@
 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}}
+[uuid("000000000000-0000-1234-000000000047")] struct uuid_attr_bad6 { };// expected-error {{uuid attribute contains a malformed GUID}}
 
 __declspec(uuid("000000A0-0000-0000-C000-000000000046")) int i; // expected-warning {{'uuid' attribute only applies to classes}}
 
@@ -59,6 +60,8 @@
 struct __declspec(uuid("000000A0-0000-0000-C000-000000000049"))
 struct_with_uuid2;
 
+[uuid("000000A0-0000-0000-C000-000000000049")] struct struct_with_uuid3;
+
 struct
 struct_with_uuid2 {} ;
 
@@ -69,6 +72,7 @@
 
    __uuidof(struct_with_uuid);
    __uuidof(struct_with_uuid2);
+   __uuidof(struct_with_uuid3);
    __uuidof(struct_without_uuid); // expected-error {{cannot call operator __uuidof on a type with no GUID}}
    __uuidof(struct_with_uuid*);
    __uuidof(struct_without_uuid*); // expected-error {{cannot call operator __uuidof on a type with no GUID}}
Index: test/CodeGenCXX/microsoft-uuidof.cpp
===================================================================
--- test/CodeGenCXX/microsoft-uuidof.cpp
+++ test/CodeGenCXX/microsoft-uuidof.cpp
@@ -1,4 +1,5 @@
 // RUN: %clang_cc1 -emit-llvm %s -o - -DDEFINE_GUID -triple=i386-pc-linux -fms-extensions | FileCheck %s --check-prefix=CHECK-DEFINE-GUID
+// RUN: %clang_cc1 -emit-llvm %s -o - -DDEFINE_GUID -DBRACKET_ATTRIB -triple=i386-pc-linux -fms-extensions | FileCheck %s --check-prefix=CHECK-DEFINE-GUID
 // RUN: %clang_cc1 -emit-llvm %s -o - -triple=i386-pc-linux -fms-extensions | FileCheck %s
 // RUN: %clang_cc1 -emit-llvm %s -o - -triple=x86_64-pc-linux -fms-extensions | FileCheck %s --check-prefix=CHECK-64
 // RUN: %clang_cc1 -emit-llvm %s -o - -DDEFINE_GUID -DWRONG_GUID -triple=i386-pc-linux -fms-extensions | FileCheck %s --check-prefix=CHECK-DEFINE-WRONG-GUID
@@ -17,10 +18,17 @@
 #endif
 typedef struct _GUID GUID;
 
+#ifdef BRACKET_ATTRIB
+[uuid(12345678-1234-1234-1234-1234567890aB)] struct S1 { } s1;
+[uuid(87654321-4321-4321-4321-ba0987654321)] struct S2 { };
+[uuid({12345678-1234-1234-1234-1234567890ac})] struct Curly;
+[uuid({12345678-1234-1234-1234-1234567890ac})] struct Curly;
+#else
 struct __declspec(uuid("12345678-1234-1234-1234-1234567890aB")) S1 { } s1;
 struct __declspec(uuid("87654321-4321-4321-4321-ba0987654321")) S2 { };
 struct __declspec(uuid("{12345678-1234-1234-1234-1234567890ac}")) Curly;
 struct __declspec(uuid("{12345678-1234-1234-1234-1234567890ac}")) Curly;
+#endif
 
 #ifdef DEFINE_GUID
 // Make sure we can properly generate code when the UUID has curly braces on it.
Index: lib/Parse/Parser.cpp
===================================================================
--- lib/Parse/Parser.cpp
+++ lib/Parse/Parser.cpp
@@ -618,7 +618,6 @@
 
   ParsedAttributesWithRange attrs(AttrFactory);
   MaybeParseCXX11Attributes(attrs);
-  MaybeParseMicrosoftAttributes(attrs);
 
   Result = ParseExternalDeclaration(attrs);
   return false;
@@ -886,11 +885,10 @@
          Tok.is(tok::kw_try);          // X() try { ... }
 }
 
-/// ParseDeclarationOrFunctionDefinition - Parse either a function-definition or
-/// a declaration.  We can't tell which we have until we read up to the
-/// compound-statement in function-definition. TemplateParams, if
-/// non-NULL, provides the template parameters when we're parsing a
-/// C++ template-declaration.
+/// Parse either a function-definition or a declaration.  We can't tell which
+/// we have until we read up to the compound-statement in function-definition.
+/// TemplateParams, if non-NULL, provides the template parameters when we're
+/// parsing a C++ template-declaration.
 ///
 ///       function-definition: [C99 6.9.1]
 ///         decl-specs      declarator declaration-list[opt] compound-statement
@@ -906,6 +904,7 @@
 Parser::ParseDeclOrFunctionDefInternal(ParsedAttributesWithRange &attrs,
                                        ParsingDeclSpec &DS,
                                        AccessSpecifier AS) {
+  MaybeParseMicrosoftAttributes(DS.getAttributes());
   // Parse the common declaration-specifiers piece.
   ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS, DSC_top_level);
 
@@ -985,7 +984,7 @@
     // parsing c constructs and re-enter objc container scope
     // afterwards.
     ObjCDeclContextSwitch ObjCDC(*this);
-      
+
     return ParseDeclOrFunctionDefInternal(attrs, PDS, AS);
   }
 }
@@ -2021,7 +2020,6 @@
   while (Tok.isNot(tok::r_brace) && !isEofOrEom()) {
     ParsedAttributesWithRange attrs(AttrFactory);
     MaybeParseCXX11Attributes(attrs);
-    MaybeParseMicrosoftAttributes(attrs);
     DeclGroupPtrTy Result = ParseExternalDeclaration(attrs);
     if (Result && !getCurScope()->getParent())
       Actions.getASTConsumer().HandleTopLevelDecl(Result.get());
Index: lib/Parse/ParseOpenMP.cpp
===================================================================
--- lib/Parse/ParseOpenMP.cpp
+++ lib/Parse/ParseOpenMP.cpp
@@ -610,7 +610,6 @@
       if (AS == AS_none) {
         assert(TagType == DeclSpec::TST_unspecified);
         MaybeParseCXX11Attributes(Attrs);
-        MaybeParseMicrosoftAttributes(Attrs);
         ParsingDeclSpec PDS(*this);
         Ptr = ParseExternalDeclaration(Attrs, &PDS);
       } else {
@@ -672,7 +671,6 @@
            Tok.isNot(tok::eof) && Tok.isNot(tok::r_brace)) {
       ParsedAttributesWithRange attrs(AttrFactory);
       MaybeParseCXX11Attributes(attrs);
-      MaybeParseMicrosoftAttributes(attrs);
       ParseExternalDeclaration(attrs);
       if (Tok.isAnnotation() && Tok.is(tok::annot_pragma_openmp)) {
         TentativeParsingAction TPA(*this);
Index: lib/Parse/ParseObjc.cpp
===================================================================
--- lib/Parse/ParseObjc.cpp
+++ lib/Parse/ParseObjc.cpp
@@ -2238,7 +2238,6 @@
     while (!ObjCImplParsing.isFinished() && !isEofOrEom()) {
       ParsedAttributesWithRange attrs(AttrFactory);
       MaybeParseCXX11Attributes(attrs);
-      MaybeParseMicrosoftAttributes(attrs);
       if (DeclGroupPtrTy DGP = ParseExternalDeclaration(attrs)) {
         DeclGroupRef DG = DGP.get();
         DeclsInGroup.append(DG.begin(), DG.end());
Index: lib/Parse/ParseDeclCXX.cpp
===================================================================
--- lib/Parse/ParseDeclCXX.cpp
+++ lib/Parse/ParseDeclCXX.cpp
@@ -217,7 +217,6 @@
            Tok.isNot(tok::eof)) {
       ParsedAttributesWithRange attrs(AttrFactory);
       MaybeParseCXX11Attributes(attrs);
-      MaybeParseMicrosoftAttributes(attrs);
       ParseExternalDeclaration(attrs);
     }
 
@@ -310,7 +309,6 @@
 
   ParsedAttributesWithRange attrs(AttrFactory);
   MaybeParseCXX11Attributes(attrs);
-  MaybeParseMicrosoftAttributes(attrs);
 
   if (Tok.isNot(tok::l_brace)) {
     // Reset the source range in DS, as the leading "extern"
@@ -361,7 +359,6 @@
     default:
       ParsedAttributesWithRange attrs(AttrFactory);
       MaybeParseCXX11Attributes(attrs);
-      MaybeParseMicrosoftAttributes(attrs);
       ParseExternalDeclaration(attrs);
       continue;
     }
@@ -1742,7 +1739,7 @@
       TParams =
         MultiTemplateParamsArg(&(*TemplateParams)[0], TemplateParams->size());
 
-    handleDeclspecAlignBeforeClassKey(attrs, DS, TUK);
+    stripTypeAttributesOffDeclSpec(attrs, DS, TUK);
 
     // Declaration or definition of a class type
     TagOrTempResult = Actions.ActOnTag(getCurScope(), TagType, TUK, StartLoc,
@@ -3925,6 +3922,87 @@
   return EndLoc;
 }
 
+/// Parse uuid() attribute when it appears in a [] Microsoft attribute.
+void Parser::ParseMicrosoftUuidAttributeArgs(IdentifierInfo *UuidIdent,
+                                             SourceLocation UuidLoc,
+                                             ParsedAttributes &attrs) {
+  assert(Tok.is(tok::l_paren) && "Not a Microsoft attribute list");
+
+  // Ignore the left paren location for now.
+  BalancedDelimiterTracker T(*this, tok::l_paren);
+  T.consumeOpen();
+
+  ArgsVector ArgExprs;
+  if (Tok.is(tok::string_literal)) {
+    // Easy case: uuid("...") -- quoted string.
+    ExprResult StringResult = ParseStringLiteralExpression();
+    if (StringResult.isInvalid())
+      return;
+    ArgExprs.push_back(StringResult.get());
+  } else {
+    // something like uuid({000000A0-0000-0000-C000-000000000049}) -- no
+    // quotes in the parens. Just append the spelling of all tokens encountered
+    // until the closing paren.
+
+    SmallString<42> StrBuffer; // 2 "", 36 bytes UUID, 2 optional {}, 1 nul
+    StrBuffer += "\"";
+
+    // Since none of C++'s keywords match [a-f]+, accepting just tok::l_brace,
+    // tok::r_brace, tok::minus, tok::identifier (think C000) and
+    // tok::numeric_constant (0000) should be enough. But the spelling of the
+    // uuid argument is checked later anyways, so there's no harm in accepting
+    // almost anything here.
+    // cl is very strict about whitespace in this form and errors out if any
+    // is present, so check the space flags on the tokens.
+    SourceLocation StartLoc = Tok.getLocation();
+    while (Tok.isNot(tok::r_paren)) {
+      if (Tok.hasLeadingSpace() || Tok.isAtStartOfLine()) {
+        Diag(Tok, diag::err_attribute_uuid_malformed_guid);
+        SkipUntil(tok::r_paren, StopAtSemi);
+        return;
+      }
+      SmallString<16> SpellingBuffer;
+      SpellingBuffer.resize(Tok.getLength() + 1);
+      bool Invalid = false;
+      StringRef TokSpelling = PP.getSpelling(Tok, SpellingBuffer, &Invalid);
+      if (Invalid) {
+        SkipUntil(tok::r_paren, StopAtSemi);
+        return;
+      }
+      StrBuffer += TokSpelling;
+      ConsumeAnyToken();
+    }
+    StrBuffer += "\"";
+
+    if (Tok.hasLeadingSpace() || Tok.isAtStartOfLine()) {
+      ConsumeParen();
+      Diag(Tok, diag::err_attribute_uuid_malformed_guid);
+      return;
+    }
+
+    // Pretend the user wrote the appropriate string literal here.
+    // ActOnStringLiteral() copies the string data into the literal, so it's
+    // ok that the Token points to StrBuffer.
+    Token Toks[1];
+    Toks[0].startToken();
+    Toks[0].setKind(tok::string_literal);
+    Toks[0].setLocation(StartLoc);
+    Toks[0].setLiteralData(StrBuffer.data());
+    Toks[0].setLength(StrBuffer.size());
+    StringLiteral *UuidString =
+        cast<StringLiteral>(Actions.ActOnStringLiteral(Toks, nullptr).get());
+    ArgExprs.push_back(UuidString);
+  }
+
+  if (!T.consumeClose()) {
+    // FIXME: Warn that this syntax is deprecated, with a Fix-It suggesting
+    // using __declspec(uuid()) instead.
+    attrs.addNew(UuidIdent, SourceRange(UuidLoc, T.getCloseLocation()), nullptr,
+                 SourceLocation(), ArgExprs.data(), ArgExprs.size(),
+                 AttributeList::AS_Microsoft);
+  }
+}
+
 /// ParseMicrosoftAttributes - Parse Microsoft attributes [Attr]
 ///
 /// [MS] ms-attribute:
@@ -3941,7 +4019,19 @@
     // FIXME: If this is actually a C++11 attribute, parse it as one.
     BalancedDelimiterTracker T(*this, tok::l_square);
     T.consumeOpen();
-    SkipUntil(tok::r_square, StopAtSemi | StopBeforeMatch);
+
+    // Skip most ms attributes except for a whitelist.
+    while (true) {
+      SkipUntil(tok::r_square, tok::identifier, StopAtSemi | StopBeforeMatch);
+      if (Tok.isNot(tok::identifier)) // ']', but also eof
+        break;
+      IdentifierInfo *Name = Tok.getIdentifierInfo();
+      SourceLocation Loc = Tok.getLocation();
+      ConsumeToken();
+      if (Name->getName() == "uuid" && Tok.is(tok::l_paren))
+        ParseMicrosoftUuidAttributeArgs(Name, Loc, attrs);
+    }
+
     T.consumeClose();
     if (endLoc)
       *endLoc = T.getCloseLocation();
Index: lib/Parse/ParseDecl.cpp
===================================================================
--- lib/Parse/ParseDecl.cpp
+++ lib/Parse/ParseDecl.cpp
@@ -1423,11 +1423,16 @@
   }
 }
 
+// Usually, `__attribute__((attrib)) class Foo {} var` means that attribute
+// applies to var, not the type Foo.
 // As an exception to the rule, __declspec(align(...)) before the
 // class-key affects the type instead of the variable.
-void Parser::handleDeclspecAlignBeforeClassKey(ParsedAttributesWithRange &Attrs,
-                                               DeclSpec &DS,
-                                               Sema::TagUseKind TUK) {
+// Also, Microsoft-style [attributes] seem to affect the type instead of the
+// variable.
+// This function moves attributes that should apply to the type off DS to Attrs.
+void Parser::stripTypeAttributesOffDeclSpec(ParsedAttributesWithRange &Attrs,
+                                            DeclSpec &DS,
+                                            Sema::TagUseKind TUK) {
   if (TUK == Sema::TUK_Reference)
     return;
 
@@ -1437,10 +1442,9 @@
   while (AL) {
     AttributeList *Next = AL->getNext();
 
-    // We only consider attributes using the appropriate '__declspec' spelling.
-    // This behavior doesn't extend to any other spellings.
-    if (AL->getKind() == AttributeList::AT_Aligned &&
-        AL->isDeclspecAttribute()) {
+    if ((AL->getKind() == AttributeList::AT_Aligned &&
+         AL->isDeclspecAttribute()) ||
+        AL->isMicrosoftAttribute()) {
       // Stitch the attribute into the tag's attribute list.
       AL->setNext(nullptr);
       Attrs.add(AL);
@@ -4071,7 +4075,7 @@
     return;
   }
 
-  handleDeclspecAlignBeforeClassKey(attrs, DS, TUK);
+  stripTypeAttributesOffDeclSpec(attrs, DS, TUK);
 
   Sema::SkipBodyInfo SkipBody;
   if (!Name && TUK == Sema::TUK_Definition && Tok.is(tok::l_brace) &&
Index: include/clang/Sema/AttributeList.h
===================================================================
--- include/clang/Sema/AttributeList.h
+++ include/clang/Sema/AttributeList.h
@@ -101,12 +101,14 @@
     AS_CXX11,
     /// __declspec(...)
     AS_Declspec,
+    /// [uuid("...")] class Foo
+    AS_Microsoft,
     /// __ptr16, alignas(...), etc.
     AS_Keyword,
     /// Context-sensitive version of a keyword attribute.
     AS_ContextSensitiveKeyword,
     /// #pragma ...
-    AS_Pragma
+    AS_Pragma,
   };
 
 private:
@@ -369,6 +371,7 @@
   }
 
   bool isDeclspecAttribute() const { return SyntaxUsed == AS_Declspec; }
+  bool isMicrosoftAttribute() const { return SyntaxUsed == AS_Microsoft; }
   bool isCXX11Attribute() const {
     return SyntaxUsed == AS_CXX11 || isAlignasAttribute();
   }
Index: include/clang/Parse/Parser.h
===================================================================
--- include/clang/Parse/Parser.h
+++ include/clang/Parse/Parser.h
@@ -2106,8 +2106,8 @@
   void DiagnoseMisplacedCXX11Attribute(ParsedAttributesWithRange &Attrs,
                                        SourceLocation CorrectLocation);
 
-  void handleDeclspecAlignBeforeClassKey(ParsedAttributesWithRange &Attrs,
-                                         DeclSpec &DS, Sema::TagUseKind TUK);
+  void stripTypeAttributesOffDeclSpec(ParsedAttributesWithRange &Attrs,
+                                      DeclSpec &DS, Sema::TagUseKind TUK);
 
   void ProhibitAttributes(ParsedAttributesWithRange &attrs) {
     if (!attrs.Range.isValid()) return;
@@ -2212,6 +2212,9 @@
     if (getLangOpts().MicrosoftExt && Tok.is(tok::l_square))
       ParseMicrosoftAttributes(attrs, endLoc);
   }
+  void ParseMicrosoftUuidAttributeArgs(IdentifierInfo *UuidIdent,
+                                       SourceLocation UuidLoc,
+                                       ParsedAttributes &attrs);
   void ParseMicrosoftAttributes(ParsedAttributes &attrs,
                                 SourceLocation *endLoc = nullptr);
   void MaybeParseMicrosoftDeclSpecs(ParsedAttributes &Attrs,
Index: include/clang/Basic/Attributes.h
===================================================================
--- include/clang/Basic/Attributes.h
+++ include/clang/Basic/Attributes.h
@@ -22,6 +22,8 @@
   GNU,
   /// Is the identifier known as a __declspec-style attribute?
   Declspec,
+  /// Is the identifier known as a [] Microsoft-style attribute?
+  Microsoft,
   // Is the identifier known as a C++-style attribute?
   CXX,
   // Is the identifier known as a pragma attribute?
Index: include/clang/Basic/Attr.td
===================================================================
--- include/clang/Basic/Attr.td
+++ include/clang/Basic/Attr.td
@@ -198,6 +198,7 @@
 
 class GNU<string name> : Spelling<name, "GNU">;
 class Declspec<string name> : Spelling<name, "Declspec">;
+class Microsoft<string name> : Spelling<name, "Microsoft">;
 class CXX11<string namespace, string name, int version = 1>
     : Spelling<name, "CXX11"> {
   string Namespace = namespace;
@@ -1574,7 +1575,7 @@
 }
 
 def Uuid : InheritableAttr {
-  let Spellings = [Declspec<"uuid">];
+  let Spellings = [Declspec<"uuid">, Microsoft<"uuid">];
   let Args = [StringArgument<"Guid">];
 //  let Subjects = SubjectList<[CXXRecord]>;
   let LangOpts = [MicrosoftExt, Borland];
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to