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. /// @@ -4269,6 +4270,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 @@ -1428,6 +1428,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; @@ -2237,12 +2239,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 @@ -100,4 +100,5 @@ def OMPThreadPrivate : 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 availability 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 @@ -390,6 +390,14 @@ /// Source location for newly created implicit MSInheritanceAttrs SourceLocation ImplicitMSInheritanceAttrLoc; + /// List of declspec(uuid ...) for a specific uuid string. + SmallVector DeclSpecUuidDecls; + + /// Map from a uuid string to an expr. Each uuid string is mapped to + /// a single Expr. + std::map UuidExpMap; + std::map DeclSpecToStrUuid; + /// pragma clang section kind enum PragmaClangSectionKind { PCSK_Invalid = 0, @@ -2533,7 +2541,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 @@ -4711,3 +4711,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 @@ -814,6 +814,7 @@ case OMPThreadPrivate: 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 @@ -106,6 +106,7 @@ case Decl::OMPCapturedExpr: case Decl::OMPRequires: case Decl::Empty: + case Decl::DeclSpecUuid: // None of these decls require codegen support. return; Index: lib/Parse/ParseDecl.cpp =================================================================== --- lib/Parse/ParseDecl.cpp +++ lib/Parse/ParseDecl.cpp @@ -585,6 +585,27 @@ ParsedAttr::AS_Declspec); T.skipToEnd(); return !HasInvalidAccessor; + if (AttrName->getName() == "uuid") { + // Parse the uuid attribute and create a UuidDecl. + ConsumeParen(); + + SmallString<8> UuidBuffer; + bool Invalid = false; + StringRef UuidStr = PP.getSpelling(Tok, UuidBuffer, &Invalid); + + // Clean up the string from the "\" at begining and at end. + StringRef UuidStr1 = UuidStr.ltrim('\"'); + StringRef TrimmedUuidStr = UuidStr1.rtrim('\"'); + + // Advance to next token. Should be a r-paren. + PP.Lex(Tok); + SourceLocation RParen = Tok.getLocation(); + SourceRange attrRange = SourceRange(AttrNameLoc, RParen); + if (!ExpectAndConsume(tok::r_paren)) + Attrs.addNew(AttrName, attrRange, nullptr, AttrNameLoc, nullptr, + 0, ParsedAttr::AS_Declspec); + return true; + } } unsigned NumArgs = Index: lib/Sema/SemaDecl.cpp =================================================================== --- lib/Sema/SemaDecl.cpp +++ lib/Sema/SemaDecl.cpp @@ -2493,7 +2493,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 @@ -5365,9 +5365,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 (UA->UuidAttr::getUuidAsStr().equals_lower(Uuid->getStrUuid())) return nullptr; Diag(UA->getLocation(), diag::err_mismatched_uuid); Diag(Range.getBegin(), diag::note_previous_uuid); @@ -5386,14 +5387,27 @@ 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. if (StrRef.size() == 38 && StrRef.front() == '{' && StrRef.back() == '}') StrRef = StrRef.drop_front().drop_back(); + // GUID string shouldn't be a wide string. + if (StrRef.front() == 'L') { + S.Diag(LiteralLoc, diag::err_attribute_argument_type) + << AL.getName() << AANT_ArgumentString; + return; + } + // Validate GUID length. if (StrRef.size() != 36) { S.Diag(LiteralLoc, diag::err_attribute_uuid_malformed_guid); @@ -5421,8 +5435,15 @@ 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.DeclSpecUuidDecls.push_back(D); + S.DeclSpecToStrUuid[D] = StrRef; + 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,6 +615,43 @@ } } +/// Find the uuid of a type. +static void FindStrUuid(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()) { + const Decl *dl = SemaRef.DeclSpecUuidDecls.back(); + 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) + FindStrUuid(SemaRef, TA.getAsType(), UuidDecl); + else if (TA.getKind() == TemplateArgument::Declaration) + FindStrUuid(SemaRef, TA.getAsType(), UuidDecl); + if (dd) + UuidDecl.push_back(dcl); + } + } +} + /// Build a Microsoft __uuidof expression with a type operand. ExprResult Sema::BuildCXXUuidof(QualType TypeInfoType, SourceLocation TypeidLoc, @@ -622,17 +659,28 @@ SourceLocation RParenLoc) { StringRef UuidStr; if (!Operand->getType()->isDependentType()) { - llvm::SmallSetVector UuidAttrs; - getUuidAttrOfType(*this, Operand->getType(), UuidAttrs); - if (UuidAttrs.empty()) + QualType QT = Operand->getType(); + llvm::SmallVector UuidDecl; + FindStrUuid(*this, QT, UuidDecl); + if (UuidDecl.empty()) return ExprError(Diag(TypeidLoc, diag::err_uuidof_without_guid)); - if (UuidAttrs.size() > 1) + if (UuidDecl.size() > 1) return ExprError(Diag(TypeidLoc, diag::err_uuidof_with_multiple_guids)); - UuidStr = UuidAttrs.back()->getGuid(); + const Decl *dd1 = UuidDecl.back(); + UuidStr = DeclSpecToStrUuid[dd1]; + } + + ExprResult expr = UuidExpMap[UuidStr]; + 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; } - - return new (Context) CXXUuidofExpr(TypeInfoType.withConst(), Operand, UuidStr, - SourceRange(TypeidLoc, RParenLoc)); } /// Build a Microsoft __uuidof expression with an expression operand. @@ -651,7 +699,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 @@ -549,6 +549,16 @@ return Inst; } +Decl * +TemplateDeclInstantiator::VisitDeclSpecUuidDecl(DeclSpecUuidDecl *D) { + DeclSpecUuidDecl *Inst = DeclSpecUuidDecl::Create(SemaRef.Context, Owner, + D->getLocation(), + D->getStrUuid()); + Owner->addDecl(Inst); + return Inst; +} + + 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/Parser/ms-square-bracket-attributes.mm =================================================================== --- test/Parser/ms-square-bracket-attributes.mm +++ test/Parser/ms-square-bracket-attributes.mm @@ -19,7 +19,7 @@ // 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}} +// expected-error@+1 {{attribute requires a string}} [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 Index: test/Sema/ms-uuid-1.cpp =================================================================== --- /dev/null +++ test/Sema/ms-uuid-1.cpp @@ -0,0 +1,31 @@ +// RUN: %clang_cc1 -fms-extensions -fms-compatibility -std=c++14 -emit-obj -fdiagnostics-show-option %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: 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.