Index: clang/include/clang/AST/Decl.h =================================================================== --- clang/include/clang/AST/Decl.h +++ clang/include/clang/AST/Decl.h @@ -75,6 +75,7 @@ class TypeLoc; class UnresolvedSetImpl; class VarTemplateDecl; +class DeclSpecUuidDecl; /// A container of type source information. /// @@ -4310,6 +4311,37 @@ static bool classofKind(Kind K) { return K == Empty; } }; +class DeclSpecUuidDecl : public Decl , public Redeclarable { + StringLiteral *Uuid; + +public: + static DeclSpecUuidDecl *Create(const ASTContext &C, DeclContext *DC, + SourceLocation IdLoc, StringLiteral *uuid); + + static DeclSpecUuidDecl *CreateDeserialized(ASTContext &C, unsigned ID); + + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { return K == DeclSpecUuid; } + + DeclSpecUuidDecl(Kind DK, const ASTContext &C, DeclContext *DC, + SourceLocation IdLoc, StringLiteral *uuid) + : Decl (DK, DC, IdLoc), Uuid(uuid), redeclarable_base(C) {} + + using redeclarable_base = Redeclarable; + + DeclSpecUuidDecl *getMostRecentDecl() { + return cast_or_null( + static_cast(this)->getMostRecentDecl()); + } + + DeclSpecUuidDecl *getPreviousDecl() { + return cast_or_null( + static_cast(this)->getPreviousDecl()); + } + + StringLiteral *getUuid() { return Uuid; } + }; + /// Insertion operator for diagnostics. This allows sending NamedDecl's /// into a diagnostic with <<. inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, Index: clang/include/clang/AST/RecursiveASTVisitor.h =================================================================== --- clang/include/clang/AST/RecursiveASTVisitor.h +++ clang/include/clang/AST/RecursiveASTVisitor.h @@ -1433,6 +1433,8 @@ DEF_TRAVERSE_DECL(EmptyDecl, {}) +DEF_TRAVERSE_DECL(DeclSpecUuidDecl, {}) + DEF_TRAVERSE_DECL(FileScopeAsmDecl, { TRY_TO(TraverseStmt(D->getAsmString())); }) Index: clang/include/clang/Basic/Attr.td =================================================================== --- clang/include/clang/Basic/Attr.td +++ clang/include/clang/Basic/Attr.td @@ -181,6 +181,7 @@ class VariadicExprArgument : Argument; class VariadicStringArgument : Argument; class VariadicIdentifierArgument : Argument; +class DeclSpecUuidDeclArgument : Argument; // Like VariadicUnsignedArgument except values are ParamIdx. class VariadicParamIdxArgument : Argument; @@ -2265,7 +2266,7 @@ def Uuid : InheritableAttr { let Spellings = [Declspec<"uuid">, Microsoft<"uuid">]; - let Args = [StringArgument<"Guid">]; + let Args = [DeclSpecUuidDeclArgument<"DeclSpecUuidDecl">]; let Subjects = SubjectList<[Record, Enum]>; // FIXME: Allow expressing logical AND for LangOpts. Our condition should be: // CPlusPlus && (MicrosoftExt || Borland) Index: clang/include/clang/Basic/DeclNodes.td =================================================================== --- clang/include/clang/Basic/DeclNodes.td +++ clang/include/clang/Basic/DeclNodes.td @@ -101,4 +101,4 @@ def OMPAllocate : Decl; def OMPRequires : Decl; def Empty : Decl; - +def DeclSpecUuid : Decl; \ No newline at end of file Index: clang/include/clang/Sema/Sema.h =================================================================== --- clang/include/clang/Sema/Sema.h +++ clang/include/clang/Sema/Sema.h @@ -2604,7 +2604,7 @@ VisibilityAttr::VisibilityType Vis, unsigned AttrSpellingListIndex); UuidAttr *mergeUuidAttr(Decl *D, SourceRange Range, - unsigned AttrSpellingListIndex, StringRef Uuid); + unsigned AttrSpellingListIndex, DeclSpecUuidDecl *Uuid); DLLImportAttr *mergeDLLImportAttr(Decl *D, SourceRange Range, unsigned AttrSpellingListIndex); DLLExportAttr *mergeDLLExportAttr(Decl *D, SourceRange Range, Index: clang/lib/AST/Decl.cpp =================================================================== --- clang/lib/AST/Decl.cpp +++ clang/lib/AST/Decl.cpp @@ -1962,6 +1962,15 @@ QualType(), nullptr, SC_None); } + //===----------------------------------------------------------------------===// + // UuidDeclSpec Implementation + //===----------------------------------------------------------------------===// +DeclSpecUuidDecl *DeclSpecUuidDecl::Create(const ASTContext &C, DeclContext *DC, + SourceLocation IdLoc, + StringLiteral *uuid) { + return new (C, DC) DeclSpecUuidDecl(DeclSpecUuid, C, DC, IdLoc, uuid); +} + void VarDecl::setStorageClass(StorageClass SC) { assert(isLegalForVariable(SC)); VarDeclBits.SClass = SC; Index: clang/lib/AST/DeclBase.cpp =================================================================== --- clang/lib/AST/DeclBase.cpp +++ clang/lib/AST/DeclBase.cpp @@ -800,6 +800,7 @@ case OMPAllocate: case OMPRequires: case OMPCapturedExpr: + case DeclSpecUuid: case Empty: // Never looked up by name. return 0; Index: clang/lib/AST/DeclCXX.cpp =================================================================== --- clang/lib/AST/DeclCXX.cpp +++ clang/lib/AST/DeclCXX.cpp @@ -1805,9 +1805,11 @@ if (Uuid && isStruct() && !getDeclContext()->isExternCContext() && !isDeclContextInNamespace(getDeclContext()) && ((getName() == "IUnknown" && - Uuid->getGuid() == "00000000-0000-0000-C000-000000000046") || + Uuid->getDeclSpecUuidDecl()->getUuid()->getString() == + "00000000-0000-0000-C000-000000000046") || (getName() == "IDispatch" && - Uuid->getGuid() == "00020400-0000-0000-C000-000000000046"))) { + Uuid->getDeclSpecUuidDecl()->getUuid()->getString() == + "00020400-0000-0000-C000-000000000046"))) { if (getNumBases() > 0) return false; return true; Index: clang/lib/CodeGen/CGDecl.cpp =================================================================== --- clang/lib/CodeGen/CGDecl.cpp +++ clang/lib/CodeGen/CGDecl.cpp @@ -108,6 +108,7 @@ case Decl::OMPCapturedExpr: case Decl::OMPRequires: case Decl::Empty: + case Decl::DeclSpecUuid: // None of these decls require codegen support. return; Index: clang/lib/Sema/SemaDecl.cpp =================================================================== --- clang/lib/Sema/SemaDecl.cpp +++ clang/lib/Sema/SemaDecl.cpp @@ -2515,7 +2515,7 @@ NewAttr = nullptr; else if (const auto *UA = dyn_cast(Attr)) NewAttr = S.mergeUuidAttr(D, UA->getRange(), AttrSpellingListIndex, - UA->getGuid()); + UA->getDeclSpecUuidDecl()); else if (const auto *SLHA = dyn_cast(Attr)) NewAttr = S.mergeSpeculativeLoadHardeningAttr(D, *SLHA); else if (const auto *SLHA = dyn_cast(Attr)) Index: clang/lib/Sema/SemaDeclAttr.cpp =================================================================== --- clang/lib/Sema/SemaDeclAttr.cpp +++ clang/lib/Sema/SemaDeclAttr.cpp @@ -5399,9 +5399,10 @@ //===----------------------------------------------------------------------===// UuidAttr *Sema::mergeUuidAttr(Decl *D, SourceRange Range, - unsigned AttrSpellingListIndex, StringRef Uuid) { - if (const auto *UA = D->getAttr()) { - if (UA->getGuid().equals_lower(Uuid)) + unsigned AttrSpellingListIndex, + DeclSpecUuidDecl *Uuid) { + if (auto *UA = D->getAttr()) { + if (declaresSameEntity(UA->getDeclSpecUuidDecl(), Uuid)) return nullptr; Diag(UA->getLocation(), diag::err_mismatched_uuid); Diag(Range.getBegin(), diag::note_previous_uuid); @@ -5445,6 +5446,9 @@ return; } } + StringLiteral *Uuid = StringLiteral::Create( + S.getASTContext(), StrRef, StringLiteral::Ascii, /*Pascal*/ false, + AL.getArgAsExpr(0)->getType(), LiteralLoc); // FIXME: It'd be nice to also emit a fixit removing uuid(...) (and, if it's // the only thing in the [] list, the [] too), and add an insertion of @@ -5455,8 +5459,17 @@ if (AL.isMicrosoftAttribute()) // Check for [uuid(...)] spelling. S.Diag(AL.getLoc(), diag::warn_atl_uuid_deprecated); + DeclSpecUuidDecl *ArgDecl; + ArgDecl = DeclSpecUuidDecl::Create(S.getASTContext(), + S.getFunctionLevelDeclContext(), + SourceLocation(), Uuid); + // Chain the DeclSpecUuids that have the same Uuid. + if (auto *UA = D->getAttr()) { + ArgDecl->setPreviousDecl(UA->getDeclSpecUuidDecl()); + } + UuidAttr *UA = S.mergeUuidAttr(D, AL.getRange(), - AL.getAttributeSpellingListIndex(), StrRef); + AL.getAttributeSpellingListIndex(), ArgDecl); if (UA) D->addAttr(UA); } Index: clang/lib/Sema/SemaExprCXX.cpp =================================================================== --- clang/lib/Sema/SemaExprCXX.cpp +++ clang/lib/Sema/SemaExprCXX.cpp @@ -628,7 +628,7 @@ return ExprError(Diag(TypeidLoc, diag::err_uuidof_without_guid)); if (UuidAttrs.size() > 1) return ExprError(Diag(TypeidLoc, diag::err_uuidof_with_multiple_guids)); - UuidStr = UuidAttrs.back()->getGuid(); + UuidStr = UuidAttrs.back()->getDeclSpecUuidDecl()->getUuid()->getString(); } return new (Context) CXXUuidofExpr(TypeInfoType.withConst(), Operand, UuidStr, @@ -651,7 +651,9 @@ return ExprError(Diag(TypeidLoc, diag::err_uuidof_without_guid)); if (UuidAttrs.size() > 1) return ExprError(Diag(TypeidLoc, diag::err_uuidof_with_multiple_guids)); - UuidStr = UuidAttrs.back()->getGuid(); + UuidStr = UuidAttrs.back()->getDeclSpecUuidDecl()->getUuid()->getString(); + if (UuidStr.startswith("{") && UuidStr.endswith("}")) + UuidStr = UuidStr.drop_front().drop_back(); } } Index: clang/lib/Sema/SemaTemplateInstantiateDecl.cpp =================================================================== --- clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -641,6 +641,11 @@ return Inst; } +Decl * +TemplateDeclInstantiator::VisitDeclSpecUuidDecl(DeclSpecUuidDecl *D) { + llvm_unreachable("DeclSpecUuidDecl cannot be instantiated"); +} + Decl *TemplateDeclInstantiator::InstantiateTypedefNameDecl(TypedefNameDecl *D, bool IsTypeAlias) { bool Invalid = false; Index: clang/test/Sema/ms-uuid-1.cpp =================================================================== --- /dev/null +++ clang/test/Sema/ms-uuid-1.cpp @@ -0,0 +1,31 @@ +// RUN: %clang_cc1 -fsyntax-only -verify -fms-extensions -fms-compatibility -std=c++14 %s +// expected-no-diagnostics +typedef struct _GUID { + int i; +} IID; +template +class A {}; + +struct + __declspec(uuid("{DDB47A6A-0F23-11D5-9109-00E0296B75D3}")) + S1 {}; + +struct + __declspec(uuid("{DDB47A6A-0F23-11D5-9109-00E0296B75D3}")) + S2 {}; + +struct __declspec(dllexport) + C1 : public A<&__uuidof(S1)> {}; + +struct __declspec(dllexport) + C2 : public A<&__uuidof(S2)> {}; +int printf(const char *, ...); +int main() { + + if (&__uuidof(S1) == &__uuidof(S2)) + printf("OK\n"); + else + printf("ERROR\n"); + + return 0; +} Index: clang/test/Sema/ms-uuid-2.cpp =================================================================== --- /dev/null +++ clang/test/Sema/ms-uuid-2.cpp @@ -0,0 +1,17 @@ +// RUN: %clang_cc1 -fsyntax-only -verify -fms-extensions -fms-compatibility -std=c++14 %s + + +typedef struct _GUID +{ + unsigned long Data1; + unsigned short Data2; + unsigned short Data3; + unsigned char Data4[8]; +} GUID; + +// expected-error@+5 {{C++ requires a type specifier for all declarations}} +// expected-error@+4 {{invalid digit 'a' in decimal constant}} +// expected-error@+3 {{use of undeclared identifier 'def0'}} +// expected-error@+2 {{invalid digit 'a' in decimal constant}} +// expected-error@+1 {{expected ';' after top level declarator}} +uuid(12345678-9abc-def0-1234-56789abcdef0) struct S2; Index: clang/utils/TableGen/ClangAttrEmitter.cpp =================================================================== --- clang/utils/TableGen/ClangAttrEmitter.cpp +++ clang/utils/TableGen/ClangAttrEmitter.cpp @@ -321,12 +321,15 @@ OS << "\" << get" << getUpperName() << "().getAsString() << \""; else if (type == "ParamIdx") OS << "\" << get" << getUpperName() << "().getSourceIndex() << \""; - else + else if (type == "DeclSpecUuidDecl *") { + OS << "\" << get" << getUpperName() << "() << \""; + } else OS << "\" << get" << getUpperName() << "() << \""; } void writeDump(raw_ostream &OS) const override { - if (type == "FunctionDecl *" || type == "NamedDecl *") { + if (type == "FunctionDecl *" || type == "NamedDecl *" || + type == "DeclSpecUuidDecl *") { OS << " OS << \" \";\n"; OS << " dumpBareDeclRef(SA->get" << getUpperName() << "());\n"; } else if (type == "IdentifierInfo *") { @@ -1296,6 +1299,8 @@ Ptr = llvm::make_unique(Arg, Attr); else if (ArgName == "VersionArgument") Ptr = llvm::make_unique(Arg, Attr); + else if (ArgName == "DeclSpecUuidDeclArgument") + Ptr = llvm::make_unique(Arg, Attr, "DeclSpecUuidDecl *"); if (!Ptr) { // Search in reverse order so that the most-derived type is handled first.