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 stripTypeAttribsOffDeclSpec(ParsedAttributesWithRange &Attrs, + DeclSpec &DS, Sema::TagUseKind TUK); void ProhibitAttributes(ParsedAttributesWithRange &attrs) { if (!attrs.Range.isValid()) return; @@ -2224,7 +2224,8 @@ SourceLocation *End = nullptr); bool ParseMicrosoftDeclSpecArgs(IdentifierInfo *AttrName, SourceLocation AttrNameLoc, - ParsedAttributes &Attrs); + ParsedAttributes &Attrs, + AttributeList::Syntax AS); void ParseMicrosoftTypeAttributes(ParsedAttributes &attrs); void DiagnoseAndSkipExtendedMicrosoftTypeAttributes(); SourceLocation SkipExtendedMicrosoftTypeAttributes(); 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 @@ -385,7 +385,8 @@ bool Parser::ParseMicrosoftDeclSpecArgs(IdentifierInfo *AttrName, SourceLocation AttrNameLoc, - ParsedAttributes &Attrs) { + ParsedAttributes &Attrs, + AttributeList::Syntax AS) { // If the attribute isn't known, we will not attempt to parse any // arguments. if (!hasAttribute(AttrSyntax::Declspec, nullptr, AttrName, @@ -507,14 +508,13 @@ if (!HasInvalidAccessor) Attrs.addNewPropertyAttr(AttrName, AttrNameLoc, nullptr, SourceLocation(), AccessorNames[AK_Get], AccessorNames[AK_Put], - AttributeList::AS_Declspec); + AS); T.skipToEnd(); return !HasInvalidAccessor; } - unsigned NumArgs = - ParseAttributeArgsCommon(AttrName, AttrNameLoc, Attrs, nullptr, nullptr, - SourceLocation(), AttributeList::AS_Declspec); + unsigned NumArgs = ParseAttributeArgsCommon( + AttrName, AttrNameLoc, Attrs, nullptr, nullptr, SourceLocation(), AS); // If this attribute's args were parsed, and it was expected to have // arguments but none were provided, emit a diagnostic. @@ -582,7 +582,8 @@ // Parse attribute arguments. if (Tok.is(tok::l_paren)) - AttrHandled = ParseMicrosoftDeclSpecArgs(AttrName, AttrNameLoc, Attrs); + AttrHandled = ParseMicrosoftDeclSpecArgs(AttrName, AttrNameLoc, Attrs, + AttributeList::AS_Declspec); else if (AttrName->getName() == "property") // The property attribute must have an argument list. Diag(Tok.getLocation(), diag::err_expected_lparen_after) @@ -1423,11 +1424,14 @@ } } +// Usually, `__attribute__((attrib)) class Foo {} var` means that attrib 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] affect the type instead of the variable. +// This function moves attributes that should apply to the type off DS to Attrs. +void Parser::stripTypeAttribsOffDeclSpec(ParsedAttributesWithRange &Attrs, + DeclSpec &DS, Sema::TagUseKind TUK) { if (TUK == Sema::TUK_Reference) return; @@ -1437,10 +1441,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 +4074,7 @@ return; } - handleDeclspecAlignBeforeClassKey(attrs, DS, TUK); + stripTypeAttribsOffDeclSpec(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); + stripTypeAttribsOffDeclSpec(attrs, DS, TUK); // Declaration or definition of a class type TagOrTempResult = Actions.ActOnTag(getCurScope(), TagType, TUK, StartLoc, @@ -3941,7 +3938,20 @@ // 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") + ParseMicrosoftDeclSpecArgs(Name, Loc, attrs, + AttributeList::AS_Microsoft); + } + 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/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/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);