Index: include/clang/Basic/Attr.td =================================================================== --- include/clang/Basic/Attr.td +++ include/clang/Basic/Attr.td @@ -198,6 +198,7 @@ class GNU : Spelling; class Declspec : Spelling; +class Microsoft : Spelling; class CXX11 : Spelling { 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]; 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/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,7 @@ if (getLangOpts().MicrosoftExt && Tok.is(tok::l_square)) ParseMicrosoftAttributes(attrs, endLoc); } + void ParseMicrosoftUuidAttributeArgs(ParsedAttributes &Attrs); void ParseMicrosoftAttributes(ParsedAttributes &attrs, SourceLocation *endLoc = nullptr); void MaybeParseMicrosoftDeclSpecs(ParsedAttributes &Attrs, 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: 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: 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,93 @@ return EndLoc; } +/// Parse uuid() attribute when it appears in a [] Microsoft attribute. +void Parser::ParseMicrosoftUuidAttributeArgs(ParsedAttributes &Attrs) { + assert(Tok.is(tok::identifier) && "Not a Microsoft attribute list"); + IdentifierInfo *UuidIdent = Tok.getIdentifierInfo(); + assert(UuidIdent->getName() == "uuid" && "Not a Microsoft attribute list"); + + SourceLocation UuidLoc = Tok.getLocation(); + ConsumeToken(); + + // Ignore the left paren location for now. + BalancedDelimiterTracker T(*this, tok::l_paren); + if (T.consumeOpen()) { + Diag(Tok, diag::err_expected) << tok::l_paren; + return; + } + + 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()) { + Diag(Tok, diag::err_attribute_uuid_malformed_guid); + ConsumeParen(); + 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(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 +4025,16 @@ // 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; + if (Tok.getIdentifierInfo()->getName() == "uuid") + ParseMicrosoftUuidAttributeArgs(attrs); + } + T.consumeClose(); if (endLoc) *endLoc = T.getCloseLocation(); 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/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/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: 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: 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/Parser/ms-square-bracket-attributes.mm =================================================================== --- test/Parser/ms-square-bracket-attributes.mm +++ test/Parser/ms-square-bracket-attributes.mm @@ -0,0 +1,143 @@ +// 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; + +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; + +// expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}} +[uuid("{000000A0-0000-0000-C000-000000000049}", "1")] struct S {}; +// expected-error@+1 {{expected '('}} +[uuid{"000000A0-0000-0000-C000-000000000049"}] struct T {}; + + +// 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; +// expected-error@+1 {{uuid attribute contains a malformed GUID}} +[uuid({000000A0-0000-""0000-C000-000000000049})] struct struct_with_uuid2; + +// Line continuations and macro substitution are 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/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: 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 Attrs = Records.getAllDerivedDefinitions("Attr"); - std::vector Declspec, GNU, Pragma; + std::vector Declspec, Microsoft, GNU, Pragma; std::map> 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(Name)\n"; GenerateHasAttrSpellingStringSwitch(Declspec, OS, "Declspec"); + OS << "case AttrSyntax::Microsoft:\n"; + OS << " return llvm::StringSwitch(Name)\n"; + GenerateHasAttrSpellingStringSwitch(Microsoft, OS, "Microsoft"); OS << "case AttrSyntax::Pragma:\n"; OS << " return llvm::StringSwitch(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 Attrs = Records.getAllDerivedDefinitions("Attr"); - std::vector GNU, Declspec, CXX11, Keywords, Pragma; + std::vector GNU, Declspec, Microsoft, CXX11, + Keywords, Pragma; std::set 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);