Index: include/clang/AST/Decl.h =================================================================== --- include/clang/AST/Decl.h +++ include/clang/AST/Decl.h @@ -75,6 +75,7 @@ class TypeLoc; class UnresolvedSetImpl; class VarTemplateDecl; +class DeclSpecUuidDecl; /// A container of type source information. /// @@ -4276,6 +4277,22 @@ static bool classofKind(Kind K) { return K == Empty; } }; + class DeclSpecUuidDecl : public Decl { + StringRef StrUuid; + public: + static DeclSpecUuidDecl *Create(const ASTContext &C, DeclContext *DC, + SourceLocation IdLoc, + StringRef UuidVal); + + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { return K == DeclSpecUuid; } + + DeclSpecUuidDecl(Kind DK, DeclContext *DC, SourceLocation IdLoc, StringRef UuidVal) + : Decl (DK, DC, IdLoc), StrUuid(UuidVal) {} + + StringRef getStrUuid() { return StrUuid; } +}; + /// Insertion operator for diagnostics. This allows sending NamedDecl's /// into a diagnostic with <<. inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, Index: include/clang/AST/RecursiveASTVisitor.h =================================================================== --- include/clang/AST/RecursiveASTVisitor.h +++ include/clang/AST/RecursiveASTVisitor.h @@ -1427,6 +1427,8 @@ DEF_TRAVERSE_DECL(EmptyDecl, {}) +DEF_TRAVERSE_DECL(DeclSpecUuidDecl, {}) + DEF_TRAVERSE_DECL(FileScopeAsmDecl, { TRY_TO(TraverseStmt(D->getAsmString())); }) Index: include/clang/Basic/Attr.td =================================================================== --- include/clang/Basic/Attr.td +++ include/clang/Basic/Attr.td @@ -179,6 +179,8 @@ class VariadicStringArgument : Argument; class VariadicIdentifierArgument : Argument; +class DeclSpecUuidDeclArgument : Argument; + // Like VariadicUnsignedArgument except values are ParamIdx. class VariadicParamIdxArgument : Argument; @@ -2232,12 +2234,15 @@ 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) let LangOpts = [MicrosoftExt, Borland]; let Documentation = [Undocumented]; + let AdditionalMembers = [{ + StringRef getUuidAsStr() { return getDeclSpecUuidDecl()->getStrUuid(); } + }]; } def VectorSize : TypeAttr { Index: include/clang/Basic/DeclNodes.td =================================================================== --- include/clang/Basic/DeclNodes.td +++ include/clang/Basic/DeclNodes.td @@ -101,4 +101,4 @@ def OMPAllocate : Decl; def OMPRequires : Decl; def Empty : Decl; - +def DeclSpecUuid : Decl; Index: include/clang/Sema/ParsedAttr.h =================================================================== --- include/clang/Sema/ParsedAttr.h +++ include/clang/Sema/ParsedAttr.h @@ -36,6 +36,7 @@ class Expr; class IdentifierInfo; class LangOptions; +class DeclSpecUuidDecl; /// Represents information about a change in availability for /// an entity, which is part of the encoding of the 'availability' @@ -216,6 +217,8 @@ const Expr *MessageExpr; + StringRef StrUuid; + ArgsUnion *getArgsBuffer() { return getTrailingObjects(); } ArgsUnion const *getArgsBuffer() const { return getTrailingObjects(); @@ -331,6 +334,16 @@ AttrKind = getKind(getName(), getScopeName(), syntaxUsed); } + /// Constructor for __declspec(uuid) attribute. + ParsedAttr(IdentifierInfo *attrName, SourceRange attrRange, + IdentifierInfo *scopeName, SourceLocation scopeLoc, + StringRef struuid, ParsedAttr::Syntax syntaxUsed) + : AttrName(attrName), ScopeName(scopeName), AttrRange(attrRange), + ScopeLoc(scopeLoc), Invalid(false), HasParsedType(false), + SyntaxUsed(syntaxUsed), NumArgs(1), StrUuid(struuid) { + AttrKind = getKind(getName(), getScopeName(), syntaxUsed); + } + /// Type tag information is stored immediately following the arguments, if /// any, at the end of the object. They are mutually exclusive with /// availability slots. @@ -547,6 +560,11 @@ return getPropertyDataBuffer().SetterId; } + StringRef getUuidStr() const { + assert(getKind() == AT_Uuid && "Not an uuid attribute"); + return StrUuid; + } + /// Get an index into the attribute spelling list /// defined in Attr.td. This index is used by an attribute /// to pretty print itself. @@ -782,6 +800,15 @@ return add(new (memory) ParsedAttr(attrName, attrRange, scopeName, scopeLoc, getterId, setterId, syntaxUsed)); } + + ParsedAttr * + createUuidDeclSpecAttribute(IdentifierInfo *attrName, SourceRange attrRange, + IdentifierInfo *scopeName, SourceLocation scopeLoc, + StringRef struuid, ParsedAttr::Syntax syntaxUsed) { + void *memory = allocate(sizeof(ParsedAttr)); + return add(new (memory) ParsedAttr(attrName, attrRange, scopeName, + scopeLoc, struuid, syntaxUsed)); + } }; class ParsedAttributesView { @@ -974,6 +1001,16 @@ return attr; } + /// Add microsoft __delspec(uuid) attribute. + ParsedAttr * + addNew(IdentifierInfo *attrName, SourceRange attrRange, IdentifierInfo *scopeName, + SourceLocation scopeLoc, StringRef struuid, ParsedAttr::Syntax syntaxUsed) { + ParsedAttr *attr = + pool.createUuidDeclSpecAttribute(attrName, attrRange, scopeName, scopeLoc, + struuid, syntaxUsed); + addAtEnd(attr); + return attr; + } private: mutable AttributePool pool; }; Index: include/clang/Sema/Sema.h =================================================================== --- include/clang/Sema/Sema.h +++ include/clang/Sema/Sema.h @@ -405,6 +405,12 @@ /// Source location for newly created implicit MSInheritanceAttrs SourceLocation ImplicitMSInheritanceAttrLoc; + /// Map from a uuid string to an expr. Each uuid string is mapped to + /// a single Expr. + llvm::StringMap UuidExpMap; + + std::map DeclToDeclSpecUuidDecl; + /// pragma clang section kind enum PragmaClangSectionKind { PCSK_Invalid = 0, @@ -2548,7 +2554,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: lib/AST/Decl.cpp =================================================================== --- lib/AST/Decl.cpp +++ lib/AST/Decl.cpp @@ -4716,3 +4716,13 @@ ExportDecl *ExportDecl::CreateDeserialized(ASTContext &C, unsigned ID) { return new (C, ID) ExportDecl(nullptr, SourceLocation()); } + + //===----------------------------------------------------------------------===// + // UuidDeclSpec Implementation + //===----------------------------------------------------------------------===// + + DeclSpecUuidDecl *DeclSpecUuidDecl::Create(const ASTContext &C, DeclContext *DC, + SourceLocation IdLoc, + StringRef UuidVal) { + return new (C, DC) DeclSpecUuidDecl(DeclSpecUuid, DC, IdLoc, UuidVal); + } Index: lib/AST/DeclBase.cpp =================================================================== --- lib/AST/DeclBase.cpp +++ lib/AST/DeclBase.cpp @@ -815,6 +815,7 @@ case OMPAllocate: case OMPRequires: case OMPCapturedExpr: + case DeclSpecUuid: case Empty: // Never looked up by name. return 0; Index: lib/AST/DeclCXX.cpp =================================================================== --- lib/AST/DeclCXX.cpp +++ lib/AST/DeclCXX.cpp @@ -1769,16 +1769,16 @@ return false; // Check "Special" types. - const auto *Uuid = getAttr(); + auto *Uuid = getAttr(); // MS SDK declares IUnknown/IDispatch both in the root of a TU, or in an // extern C++ block directly in the TU. These are only valid if in one // of these two situations. if (Uuid && isStruct() && !getDeclContext()->isExternCContext() && !isDeclContextInNamespace(getDeclContext()) && ((getName() == "IUnknown" && - Uuid->getGuid() == "00000000-0000-0000-C000-000000000046") || + Uuid->UuidAttr::getUuidAsStr() == "00000000-0000-0000-C000-000000000046") || (getName() == "IDispatch" && - Uuid->getGuid() == "00020400-0000-0000-C000-000000000046"))) { + Uuid->UuidAttr::getUuidAsStr() == "00020400-0000-0000-C000-000000000046"))) { if (getNumBases() > 0) return false; return true; Index: lib/CodeGen/CGDecl.cpp =================================================================== --- lib/CodeGen/CGDecl.cpp +++ lib/CodeGen/CGDecl.cpp @@ -107,6 +107,7 @@ case Decl::OMPCapturedExpr: case Decl::OMPRequires: case Decl::Empty: + case Decl::DeclSpecUuid: // None of these decls require codegen support. return; Index: lib/Parse/ParseDeclCXX.cpp =================================================================== --- lib/Parse/ParseDeclCXX.cpp +++ lib/Parse/ParseDeclCXX.cpp @@ -4160,6 +4160,7 @@ 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. Index: lib/Sema/SemaDecl.cpp =================================================================== --- lib/Sema/SemaDecl.cpp +++ lib/Sema/SemaDecl.cpp @@ -2495,7 +2495,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: lib/Sema/SemaDeclAttr.cpp =================================================================== --- lib/Sema/SemaDeclAttr.cpp +++ lib/Sema/SemaDeclAttr.cpp @@ -5399,9 +5399,11 @@ //===----------------------------------------------------------------------===// 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 (UA->UuidAttr::getUuidAsStr().equals_lower(Uuid->getStrUuid()) && + declaresSameEntity(DeclToDeclSpecUuidDecl.find(D)->first, D)) return nullptr; Diag(UA->getLocation(), diag::err_mismatched_uuid); Diag(Range.getBegin(), diag::note_previous_uuid); @@ -5420,8 +5422,13 @@ StringRef StrRef; SourceLocation LiteralLoc; - if (!S.checkStringLiteralArgumentAttr(AL, 0, StrRef, &LiteralLoc)) - return; + StrRef = AL.getUuidStr(); + if (!StrRef.empty()) + LiteralLoc = AL.getLoc(); + else { + if (!S.checkStringLiteralArgumentAttr(AL, 0, StrRef, &LiteralLoc)) + return; + } // GUID format is "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX" or // "{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}", normalize to the former. @@ -5455,8 +5462,14 @@ 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(), StrRef); + + S.DeclToDeclSpecUuidDecl[D] = ArgDecl; + UuidAttr *UA = S.mergeUuidAttr(D, AL.getRange(), - AL.getAttributeSpellingListIndex(), StrRef); + AL.getAttributeSpellingListIndex(), ArgDecl); if (UA) D->addAttr(UA); } Index: lib/Sema/SemaExprCXX.cpp =================================================================== --- lib/Sema/SemaExprCXX.cpp +++ lib/Sema/SemaExprCXX.cpp @@ -615,25 +615,74 @@ } } -/// Build a Microsoft __uuidof expression with a type operand. -ExprResult Sema::BuildCXXUuidof(QualType TypeInfoType, - SourceLocation TypeidLoc, - TypeSourceInfo *Operand, - SourceLocation RParenLoc) { - StringRef UuidStr; - if (!Operand->getType()->isDependentType()) { - llvm::SmallSetVector UuidAttrs; - getUuidAttrOfType(*this, Operand->getType(), UuidAttrs); - if (UuidAttrs.empty()) - 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(); - } + /// Finds the __declSpec uuid Decl off a type. + static void FindADeclOffAType(Sema &SemaRef, + QualType QT, + llvm::SmallVector &UuidDecl) { + const Type *Ty = QT.getTypePtr(); + const Decl *dcl; + if (QT->isPointerType() || QT->isReferenceType()) + Ty = QT->getPointeeType().getTypePtr(); + else if (QT->isArrayType()) + Ty = Ty->getBaseElementTypeUnsafe(); + + const auto *TD = Ty->getAsTagDecl(); + if (!TD) { + return; + } + dcl = TD->getMostRecentDecl(); + if (TD->getMostRecentDecl()->getAttr()) { + UuidDecl.push_back(dcl); + return; + } + + if (const auto *CTSD = dyn_cast(TD)) { + const TemplateArgumentList &TAL = CTSD->getTemplateArgs(); + for (const TemplateArgument &TA : TAL.asArray()) { + const Decl *dd = nullptr; + if (TA.getKind() == TemplateArgument::Type) + FindADeclOffAType(SemaRef, TA.getAsType(), UuidDecl); + else if (TA.getKind() == TemplateArgument::Declaration) + FindADeclOffAType(SemaRef, TA.getAsType(), UuidDecl); + if (dd) + UuidDecl.push_back(dcl); + } + } + } - return new (Context) CXXUuidofExpr(TypeInfoType.withConst(), Operand, UuidStr, - SourceRange(TypeidLoc, RParenLoc)); -} + +/// Build a Microsoft __uuidof expression with a type operand. + ExprResult Sema::BuildCXXUuidof(QualType TypeInfoType, + SourceLocation TypeidLoc, + TypeSourceInfo *Operand, + SourceLocation RParenLoc) { + StringRef UuidStr; + if (!Operand->getType()->isDependentType()) { + QualType QT = Operand->getType(); + llvm::SmallVector UuidDecl; + FindADeclOffAType(*this, QT, UuidDecl); + if (UuidDecl.empty()) + return ExprError(Diag(TypeidLoc, diag::err_uuidof_without_guid)); + if (UuidDecl.size() > 1) + return ExprError(Diag(TypeidLoc, diag::err_uuidof_with_multiple_guids)); + const Decl *dd1 = UuidDecl.back(); + auto *A = dd1->getAttr(); + UuidStr = A->getUuidAsStr(); + } + + ExprResult expr = UuidExpMap[UuidStr].get(); + ExprResult uuid_expr; + if (expr.isUnset()) { + uuid_expr = + new (Context) CXXUuidofExpr(TypeInfoType.withConst(), Operand, UuidStr, + SourceRange(TypeidLoc, RParenLoc)); + UuidExpMap[UuidStr] = uuid_expr; + return uuid_expr; + } + else { + return expr; + } + } /// Build a Microsoft __uuidof expression with an expression operand. ExprResult Sema::BuildCXXUuidof(QualType TypeInfoType, @@ -651,7 +700,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()->getStrUuid(); } } Index: lib/Sema/SemaTemplateInstantiateDecl.cpp =================================================================== --- lib/Sema/SemaTemplateInstantiateDecl.cpp +++ lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -606,6 +606,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: lib/Serialization/ASTCommon.cpp =================================================================== --- lib/Serialization/ASTCommon.cpp +++ lib/Serialization/ASTCommon.cpp @@ -348,6 +348,7 @@ case Decl::ObjCProtocol: case Decl::ObjCInterface: case Decl::Empty: + case Decl::DeclSpecUuid: return true; // Never redeclarable. Index: test/Parser/MicrosoftExtensions.cpp =================================================================== --- test/Parser/MicrosoftExtensions.cpp +++ test/Parser/MicrosoftExtensions.cpp @@ -76,7 +76,7 @@ struct_with_uuid var_with_uuid[1]; struct_without_uuid var_without_uuid[1]; - __uuidof(struct_with_uuid); + __uuidof(struct_with_uuid); // expected-error {{non-type template argument of type 'const _GUID' is not a constant expression}} __uuidof(struct_with_uuid2); __uuidof(struct_with_uuid3); __uuidof(struct_without_uuid); // expected-error {{cannot call operator __uuidof on a type with no GUID}} @@ -137,7 +137,7 @@ COM_CLASS_TEMPLATE_REF good_template_arg; -COM_CLASS_TEMPLATE bad_template_arg; // expected-error {{non-type template argument of type 'const _GUID' is not a constant expression}} +COM_CLASS_TEMPLATE bad_template_arg; namespace PR16911 { struct __declspec(uuid("{12345678-1234-1234-1234-1234567890aB}")) uuid; Index: test/Sema/ms-uuid-1.cpp =================================================================== --- /dev/null +++ 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: test/Sema/ms-uuid-2.cpp =================================================================== --- /dev/null +++ test/Sema/ms-uuid-2.cpp @@ -0,0 +1,18 @@ +// 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: utils/TableGen/ClangAttrEmitter.cpp =================================================================== --- utils/TableGen/ClangAttrEmitter.cpp +++ 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.