diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -104,6 +104,7 @@ class MaterializeTemporaryExpr; class MemberSpecializationInfo; class Module; +struct MSGuidDeclParts; class ObjCCategoryDecl; class ObjCCategoryImplDecl; class ObjCContainerDecl; @@ -269,6 +270,9 @@ /// Mapping from __block VarDecls to BlockVarCopyInit. llvm::DenseMap BlockVarCopyInits; + /// Mapping from GUIDs to the corresponding MSGuidDecl. + mutable llvm::FoldingSet MSGuidDecls; + /// Used to cleanups APValues stored in the AST. mutable llvm::SmallVector APValueCleanups; @@ -984,7 +988,10 @@ // Decl used to help define __builtin_va_list for some targets. // The decl is built when constructing 'BuiltinVaListDecl'. - mutable Decl *VaListTagDecl; + mutable Decl *VaListTagDecl = nullptr; + + // Implicitly-declared type 'struct _GUID'. + mutable TagDecl *MSGuidTagDecl = nullptr; ASTContext(LangOptions &LOpts, SourceManager &SM, IdentifierTable &idents, SelectorTable &sels, Builtin::Context &builtins); @@ -1854,6 +1861,15 @@ return getTypeDeclType(getBuiltinMSVaListDecl()); } + /// Retrieve the implicitly-predeclared 'struct _GUID' declaration. + TagDecl *getMSGuidTagDecl() const { return MSGuidTagDecl; } + + /// Retrieve the implicitly-predeclared 'struct _GUID' type. + QualType getMSGuidType() const { + assert(MSGuidTagDecl && "asked for GUID type but MS extensions disabled"); + return getTagDeclType(MSGuidTagDecl); + } + /// Return whether a declaration to a builtin is allowed to be /// overloaded/redeclared. bool canBuiltinBeRedeclared(const FunctionDecl *) const; @@ -2756,6 +2772,10 @@ /// PredefinedExpr to cache evaluated results. StringLiteral *getPredefinedStringLiteralFromCache(StringRef Key) const; + /// Return a declaration for the global GUID object representing the given + /// GUID value. + MSGuidDecl *getMSGuidDecl(MSGuidDeclParts Parts) const; + /// Parses the target attributes passed in, and returns only the ones that are /// valid feature names. ParsedTargetAttr filterFunctionTargetAttrs(const TargetAttr *TD) const; diff --git a/clang/include/clang/AST/DeclCXX.h b/clang/include/clang/AST/DeclCXX.h --- a/clang/include/clang/AST/DeclCXX.h +++ b/clang/include/clang/AST/DeclCXX.h @@ -3963,6 +3963,81 @@ IdentifierInfo* getSetterId() const { return SetterId; } }; +/// Parts of a decomposed MSGuidDecl. Factored out to avoid unnecessary +/// dependencies on DeclCXX.h. +struct MSGuidDeclParts { + /// {01234567-... + uint32_t Part1; + /// ...-89ab-... + uint16_t Part2; + /// ...-cdef-... + uint16_t Part3; + /// ...-0123-456789abcdef} + uint8_t Part4And5[8]; + + uint64_t getPart4And5AsUint64() const { + uint64_t Val; + memcpy(&Val, &Part4And5, sizeof(Part4And5)); + return Val; + } +}; + +/// A global _GUID constant. These are implicitly created by UuidAttrs. +/// +/// struct _declspec(uuid("01234567-89ab-cdef-0123-456789abcdef")) X{}; +/// +/// X is a CXXRecordDecl that contains a UuidAttr that references the (unique) +/// MSGuidDecl for the specified UUID. +class MSGuidDecl : public ValueDecl, + public Mergeable, + public llvm::FoldingSetNode { +public: + using Parts = MSGuidDeclParts; + +private: + /// The decomposed form of the UUID. + Parts PartVal; + + /// The resolved value of the UUID as an APValue. Computed on demand and + /// cached. + mutable APValue APVal; + + void anchor() override; + + MSGuidDecl(DeclContext *DC, QualType T, Parts P); + + static MSGuidDecl *Create(const ASTContext &C, QualType T, Parts P); + static MSGuidDecl *CreateDeserialized(ASTContext &C, unsigned ID); + + // Only ASTContext::getMSGuidDecl and deserialization create these. + friend class ASTContext; + friend class ASTReader; + friend class ASTDeclReader; + +public: + /// Print this UUID in a human-readable format. + void printName(llvm::raw_ostream &OS) const override; + + /// Get the decomposed parts of this declaration. + Parts getParts() const { return PartVal; } + + /// Get the value of this MSGuidDecl as an APValue. This may fail and return + /// an absent APValue if the type of the declaration is not of the expected + /// shape. + APValue &getAsAPValue() const; + + static void Profile(llvm::FoldingSetNodeID &ID, Parts P) { + ID.AddInteger(P.Part1); + ID.AddInteger(P.Part2); + ID.AddInteger(P.Part3); + ID.AddInteger(P.getPart4And5AsUint64()); + } + void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, PartVal); } + + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { return K == Decl::MSGuid; } +}; + /// Insertion operator for diagnostics. This allows sending an AccessSpecifier /// into a diagnostic with <<. const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, diff --git a/clang/include/clang/AST/ExprCXX.h b/clang/include/clang/AST/ExprCXX.h --- a/clang/include/clang/AST/ExprCXX.h +++ b/clang/include/clang/AST/ExprCXX.h @@ -995,20 +995,20 @@ private: llvm::PointerUnion Operand; - StringRef UuidStr; + MSGuidDecl *Guid; SourceRange Range; public: - CXXUuidofExpr(QualType Ty, TypeSourceInfo *Operand, StringRef UuidStr, + CXXUuidofExpr(QualType Ty, TypeSourceInfo *Operand, MSGuidDecl *Guid, SourceRange R) : Expr(CXXUuidofExprClass, Ty, VK_LValue, OK_Ordinary), Operand(Operand), - UuidStr(UuidStr), Range(R) { + Guid(Guid), Range(R) { setDependence(computeDependence(this)); } - CXXUuidofExpr(QualType Ty, Expr *Operand, StringRef UuidStr, SourceRange R) + CXXUuidofExpr(QualType Ty, Expr *Operand, MSGuidDecl *Guid, SourceRange R) : Expr(CXXUuidofExprClass, Ty, VK_LValue, OK_Ordinary), Operand(Operand), - UuidStr(UuidStr), Range(R) { + Guid(Guid), Range(R) { setDependence(computeDependence(this)); } @@ -1036,8 +1036,7 @@ return static_cast(Operand.get()); } - void setUuidStr(StringRef US) { UuidStr = US; } - StringRef getUuidStr() const { return UuidStr; } + MSGuidDecl *getGuidDecl() const { return Guid; } SourceLocation getBeginLoc() const LLVM_READONLY { return Range.getBegin(); } SourceLocation getEndLoc() const LLVM_READONLY { return Range.getEnd(); } diff --git a/clang/include/clang/AST/Mangle.h b/clang/include/clang/AST/Mangle.h --- a/clang/include/clang/AST/Mangle.h +++ b/clang/include/clang/AST/Mangle.h @@ -111,6 +111,7 @@ virtual void mangleCXXRTTI(QualType T, raw_ostream &) = 0; virtual void mangleCXXRTTIName(QualType T, raw_ostream &) = 0; virtual void mangleStringLiteral(const StringLiteral *SL, raw_ostream &) = 0; + virtual void mangleMSGuidDecl(const MSGuidDecl *GD, raw_ostream&); void mangleGlobalBlock(const BlockDecl *BD, const NamedDecl *ID, diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h --- a/clang/include/clang/AST/RecursiveASTVisitor.h +++ b/clang/include/clang/AST/RecursiveASTVisitor.h @@ -1993,6 +1993,8 @@ DEF_TRAVERSE_DECL(MSPropertyDecl, { TRY_TO(TraverseDeclaratorHelper(D)); }) +DEF_TRAVERSE_DECL(MSGuidDecl, {}); + DEF_TRAVERSE_DECL(FieldDecl, { TRY_TO(TraverseDeclaratorHelper(D)); if (D->isBitField()) diff --git a/clang/include/clang/AST/TemplateBase.h b/clang/include/clang/AST/TemplateBase.h --- a/clang/include/clang/AST/TemplateBase.h +++ b/clang/include/clang/AST/TemplateBase.h @@ -82,8 +82,7 @@ /// The template argument is an expression, and we've not resolved it to one /// of the other forms yet, either because it's dependent or because we're /// representing a non-canonical template argument (for instance, in a - /// TemplateSpecializationType). Also used to represent a non-dependent - /// __uuidof expression (a Microsoft extension). + /// TemplateSpecializationType). Expression, /// The template argument is actually a parameter pack. Arguments are stored diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -2434,7 +2434,8 @@ def Uuid : InheritableAttr { let Spellings = [Declspec<"uuid">, Microsoft<"uuid">]; - let Args = [StringArgument<"Guid">]; + let Args = [StringArgument<"Guid">, + DeclArgument]; let Subjects = SubjectList<[Record, Enum]>; // FIXME: Allow expressing logical AND for LangOpts. Our condition should be: // CPlusPlus && (MicrosoftExt || Borland) diff --git a/clang/include/clang/Basic/DeclNodes.td b/clang/include/clang/Basic/DeclNodes.td --- a/clang/include/clang/Basic/DeclNodes.td +++ b/clang/include/clang/Basic/DeclNodes.td @@ -40,6 +40,7 @@ def Binding : DeclNode; def OMPDeclareReduction : DeclNode, DeclContext; def OMPDeclareMapper : DeclNode, DeclContext; + def MSGuid : DeclNode; def Declarator : DeclNode; def Field : DeclNode; def ObjCIvar : DeclNode; diff --git a/clang/include/clang/Basic/DiagnosticASTKinds.td b/clang/include/clang/Basic/DiagnosticASTKinds.td --- a/clang/include/clang/Basic/DiagnosticASTKinds.td +++ b/clang/include/clang/Basic/DiagnosticASTKinds.td @@ -338,6 +338,8 @@ def note_constexpr_memory_leak : Note< "allocation performed here was not deallocated" "%plural{0:|: (along with %0 other memory leak%s0)}0">; +def note_constexpr_unsupported_layout : Note< + "type %0 has unexpected layout">; def err_experimental_clang_interp_failed : Error< "the experimental clang interpreter failed to evaluate an expression">; diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -2961,7 +2961,7 @@ VisibilityAttr *mergeVisibilityAttr(Decl *D, const AttributeCommonInfo &CI, VisibilityAttr::VisibilityType Vis); UuidAttr *mergeUuidAttr(Decl *D, const AttributeCommonInfo &CI, - StringRef Uuid); + StringRef UuidAsWritten, MSGuidDecl *GuidDecl); DLLImportAttr *mergeDLLImportAttr(Decl *D, const AttributeCommonInfo &CI); DLLExportAttr *mergeDLLExportAttr(Decl *D, const AttributeCommonInfo &CI); MSInheritanceAttr *mergeMSInheritanceAttr(Decl *D, diff --git a/clang/include/clang/Serialization/ASTBitCodes.h b/clang/include/clang/Serialization/ASTBitCodes.h --- a/clang/include/clang/Serialization/ASTBitCodes.h +++ b/clang/include/clang/Serialization/ASTBitCodes.h @@ -1134,27 +1134,30 @@ /// The internal '__builtin_ms_va_list' typedef. PREDEF_DECL_BUILTIN_MS_VA_LIST_ID = 11, + /// The predeclared '_GUID' struct. + PREDEF_DECL_BUILTIN_MS_GUID_ID = 12, + /// The extern "C" context. - PREDEF_DECL_EXTERN_C_CONTEXT_ID = 12, + PREDEF_DECL_EXTERN_C_CONTEXT_ID = 13, /// The internal '__make_integer_seq' template. - PREDEF_DECL_MAKE_INTEGER_SEQ_ID = 13, + PREDEF_DECL_MAKE_INTEGER_SEQ_ID = 14, /// The internal '__NSConstantString' typedef. - PREDEF_DECL_CF_CONSTANT_STRING_ID = 14, + PREDEF_DECL_CF_CONSTANT_STRING_ID = 15, /// The internal '__NSConstantString' tag type. - PREDEF_DECL_CF_CONSTANT_STRING_TAG_ID = 15, + PREDEF_DECL_CF_CONSTANT_STRING_TAG_ID = 16, /// The internal '__type_pack_element' template. - PREDEF_DECL_TYPE_PACK_ELEMENT_ID = 16, + PREDEF_DECL_TYPE_PACK_ELEMENT_ID = 17, }; /// The number of declaration IDs that are predefined. /// /// For more information about predefined declarations, see the /// \c PredefinedDeclIDs type and the PREDEF_DECL_*_ID constants. - const unsigned int NUM_PREDEF_DECL_IDS = 17; + const unsigned int NUM_PREDEF_DECL_IDS = 18; /// Record of updates for a declaration that was modified after /// being deserialized. This can occur within DECLTYPES_BLOCK_ID. @@ -1228,6 +1231,9 @@ /// A MSPropertyDecl record. DECL_MS_PROPERTY, + /// A MSGuidDecl record. + DECL_MS_GUID, + /// A VarDecl record. DECL_VAR, diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -1451,6 +1451,12 @@ // Builtin type used to help define __builtin_va_list. VaListTagDecl = nullptr; + + // MSVC predeclares struct _GUID, and we need it to create MSGuidDecls. + if (LangOpts.MicrosoftExt || LangOpts.Borland) { + MSGuidTagDecl = buildImplicitRecord("_GUID"); + TUDecl->addDecl(MSGuidTagDecl); + } } DiagnosticsEngine &ASTContext::getDiagnostics() const { @@ -10580,6 +10586,23 @@ return Result; } +MSGuidDecl * +ASTContext::getMSGuidDecl(MSGuidDecl::Parts Parts) const { + assert(MSGuidTagDecl && "building MS GUID without MS extensions?"); + + llvm::FoldingSetNodeID ID; + MSGuidDecl::Profile(ID, Parts); + + void *InsertPos; + if (MSGuidDecl *Existing = MSGuidDecls.FindNodeOrInsertPos(ID, InsertPos)) + return Existing; + + QualType GUIDType = getMSGuidType().withConst(); + MSGuidDecl *New = MSGuidDecl::Create(*this, GUIDType, Parts); + MSGuidDecls.InsertNode(New, InsertPos); + return New; +} + bool ASTContext::AtomicUsesUnsupportedLibcall(const AtomicExpr *E) const { const llvm::Triple &T = getTargetInfo().getTriple(); if (!T.isOSDarwin()) diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp --- a/clang/lib/AST/Decl.cpp +++ b/clang/lib/AST/Decl.cpp @@ -892,6 +892,10 @@ if (!TD->getAnonDeclWithTypedefName(/*AnyRedecl*/true)) return LinkageInfo::none(); + } else if (isa(D)) { + // A GUID behaves like an inline variable with external linkage. Fall + // through. + // Everything not covered here has no linkage. } else { return LinkageInfo::none(); diff --git a/clang/lib/AST/DeclBase.cpp b/clang/lib/AST/DeclBase.cpp --- a/clang/lib/AST/DeclBase.cpp +++ b/clang/lib/AST/DeclBase.cpp @@ -797,6 +797,7 @@ case TranslationUnit: case ExternCContext: case Decomposition: + case MSGuid: case UsingDirective: case BuiltinTemplate: diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp --- a/clang/lib/AST/DeclCXX.cpp +++ b/clang/lib/AST/DeclCXX.cpp @@ -42,6 +42,7 @@ #include "llvm/ADT/iterator_range.h" #include "llvm/Support/Casting.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/Format.h" #include "llvm/Support/raw_ostream.h" #include #include @@ -3157,6 +3158,99 @@ SourceLocation(), nullptr, nullptr); } +void MSGuidDecl::anchor() {} + +MSGuidDecl::MSGuidDecl(DeclContext *DC, QualType T, Parts P) + : ValueDecl(Decl::MSGuid, DC, SourceLocation(), DeclarationName(), T), + PartVal(P), APVal() {} + +MSGuidDecl *MSGuidDecl::Create(const ASTContext &C, QualType T, Parts P) { + DeclContext *DC = C.getTranslationUnitDecl(); + return new (C, DC) MSGuidDecl(DC, T, P); +} + +MSGuidDecl *MSGuidDecl::CreateDeserialized(ASTContext &C, unsigned ID) { + return new (C, ID) MSGuidDecl(nullptr, QualType(), Parts()); +} + +void MSGuidDecl::printName(llvm::raw_ostream &OS) const { + OS << llvm::format("GUID{%08" PRIx32 "-%04" PRIx16 "-%04" PRIx16 "-", + PartVal.Part1, PartVal.Part2, PartVal.Part3); + unsigned I = 0; + for (uint8_t Byte : PartVal.Part4And5) { + OS << llvm::format("%02" PRIx8, Byte); + if (++I == 2) + OS << '-'; + } + OS << '}'; +} + +/// Determine if T is a valid 'struct _GUID' of the shape that we expect. +static bool isValidStructGUID(ASTContext &Ctx, QualType T) { + // FIXME: We only need to check this once, not once each time we compute a + // GUID APValue. + using MatcherRef = llvm::function_ref; + + auto IsInt = [&Ctx](unsigned N) { + return [&Ctx, N](QualType T) { + return T->isUnsignedIntegerOrEnumerationType() && + Ctx.getIntWidth(T) == N; + }; + }; + + auto IsArray = [&Ctx](MatcherRef Elem, unsigned N) { + return [&Ctx, Elem, N](QualType T) { + const ConstantArrayType *CAT = Ctx.getAsConstantArrayType(T); + return CAT && CAT->getSize() == N && Elem(CAT->getElementType()); + }; + }; + + auto IsStruct = [](std::initializer_list Fields) { + return [Fields](QualType T) { + const RecordDecl *RD = T->getAsRecordDecl(); + if (!RD || RD->isUnion()) + return false; + RD = RD->getDefinition(); + if (!RD) + return false; + if (auto *CXXRD = dyn_cast(RD)) + if (CXXRD->getNumBases()) + return false; + auto MatcherIt = Fields.begin(); + for (const FieldDecl *FD : RD->fields()) { + if (FD->isUnnamedBitfield()) continue; + if (FD->isBitField() || MatcherIt == Fields.end() || + !(*MatcherIt)(FD->getType())) + return false; + ++MatcherIt; + } + return MatcherIt == Fields.end(); + }; + }; + + // We expect an {i32, i16, i16, [8 x i8]}. + return IsStruct({IsInt(32), IsInt(16), IsInt(16), IsArray(IsInt(8), 8)})(T); +} + +APValue &MSGuidDecl::getAsAPValue() const { + if (APVal.isAbsent() && isValidStructGUID(getASTContext(), getType())) { + using llvm::APInt; + using llvm::APSInt; + APVal = APValue(APValue::UninitStruct(), 0, 4); + APVal.getStructField(0) = APValue(APSInt(APInt(32, PartVal.Part1), true)); + APVal.getStructField(1) = APValue(APSInt(APInt(16, PartVal.Part2), true)); + APVal.getStructField(2) = APValue(APSInt(APInt(16, PartVal.Part3), true)); + APValue &Arr = APVal.getStructField(3) = + APValue(APValue::UninitArray(), 8, 8); + for (unsigned I = 0; I != 8; ++I) { + Arr.getArrayInitializedElt(I) = + APValue(APSInt(APInt(8, PartVal.Part4And5[I]), true)); + } + } + + return APVal; +} + static const char *getAccessName(AccessSpecifier AS) { switch (AS) { case AS_none: diff --git a/clang/lib/AST/ExprClassification.cpp b/clang/lib/AST/ExprClassification.cpp --- a/clang/lib/AST/ExprClassification.cpp +++ b/clang/lib/AST/ExprClassification.cpp @@ -124,6 +124,7 @@ case Expr::ObjCPropertyRefExprClass: // C++ [expr.typeid]p1: The result of a typeid expression is an lvalue of... case Expr::CXXTypeidExprClass: + case Expr::CXXUuidofExprClass: // Unresolved lookups and uncorrected typos get classified as lvalues. // FIXME: Is this wise? Should they get their own kind? case Expr::UnresolvedLookupExprClass: @@ -405,9 +406,6 @@ return Cl::CL_PRValue; } - case Expr::CXXUuidofExprClass: - return Cl::CL_LValue; - case Expr::PackExpansionExprClass: return ClassifyInternal(Ctx, cast(E)->getPattern()); @@ -455,6 +453,7 @@ islvalue = isa(D) || isa(D) || isa(D) || isa(D) || + isa(D) || (Ctx.getLangOpts().CPlusPlus && (isa(D) || isa(D) || isa(D))); diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -1895,7 +1895,8 @@ if (const VarDecl *VD = dyn_cast(D)) return VD->hasGlobalStorage(); // ... the address of a function, - return isa(D); + // ... the address of a GUID [MS extension], + return isa(D) || isa(D); } if (B.is() || B.is()) @@ -1918,7 +1919,6 @@ case Expr::PredefinedExprClass: case Expr::ObjCStringLiteralClass: case Expr::ObjCEncodeExprClass: - case Expr::CXXUuidofExprClass: return true; case Expr::ObjCBoxedExprClass: return cast(E)->isExpressibleAsConstantInitializer(); @@ -3615,6 +3615,22 @@ (void)CE; BaseVal = Info.EvaluatingDeclValue; } else if (const ValueDecl *D = LVal.Base.dyn_cast()) { + // Allow reading from a GUID declaration. + if (auto *GD = dyn_cast(D)) { + if (isModification(AK)) { + // All the remaining cases do not permit modification of the object. + Info.FFDiag(E, diag::note_constexpr_modify_global); + return CompleteObject(); + } + APValue &V = GD->getAsAPValue(); + if (V.isAbsent()) { + Info.FFDiag(E, diag::note_constexpr_unsupported_layout) + << GD->getType(); + return CompleteObject(); + } + return CompleteObject(LVal.Base, &V, GD->getType()); + } + // In C++98, const, non-volatile integers initialized with ICEs are ICEs. // In C++11, constexpr, non-volatile variables initialized with constant // expressions are constant expressions too. Inside constexpr functions, @@ -7540,6 +7556,8 @@ return VisitVarDecl(E, VD); if (const BindingDecl *BD = dyn_cast(E->getDecl())) return Visit(BD->getBinding()); + if (const MSGuidDecl *GD = dyn_cast(E->getDecl())) + return Success(GD); return Error(E); } @@ -7718,7 +7736,7 @@ } bool LValueExprEvaluator::VisitCXXUuidofExpr(const CXXUuidofExpr *E) { - return Success(E); + return Success(E->getGuidDecl()); } bool LValueExprEvaluator::VisitMemberExpr(const MemberExpr *E) { diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/lib/AST/ItaniumMangle.cpp @@ -652,8 +652,12 @@ else if (const IndirectFieldDecl *IFD = dyn_cast(GD.getDecl())) mangleName(IFD->getAnonField()); + else if (const FieldDecl *FD = dyn_cast(GD.getDecl())) + mangleName(FD); + else if (const MSGuidDecl *GuidD = dyn_cast(GD.getDecl())) + mangleName(GuidD); else - mangleName(cast(GD.getDecl())); + llvm_unreachable("unexpected kind of global decl"); } void CXXNameMangler::mangleFunctionEncoding(GlobalDecl GD) { @@ -1287,6 +1291,16 @@ break; } + if (auto *GD = dyn_cast(ND)) { + // We follow MSVC in mangling GUID declarations as if they were variables + // with a particular reserved name. Continue the pretense here. + SmallString GUID; + llvm::raw_svector_ostream GUIDOS(GUID); + Context.mangleMSGuidDecl(GD, GUIDOS); + Out << GUID.size() << GUID; + break; + } + if (II) { // Match GCC's naming convention for internal linkage symbols, for // symbols that are not actually visible outside of this TU. GCC diff --git a/clang/lib/AST/Mangle.cpp b/clang/lib/AST/Mangle.cpp --- a/clang/lib/AST/Mangle.cpp +++ b/clang/lib/AST/Mangle.cpp @@ -57,7 +57,9 @@ static bool isExternC(const NamedDecl *ND) { if (const FunctionDecl *FD = dyn_cast(ND)) return FD->isExternC(); - return cast(ND)->isExternC(); + if (const VarDecl *VD = dyn_cast(ND)) + return VD->isExternC(); + return false; } static CCMangling getCallingConvMangling(const ASTContext &Context, @@ -122,6 +124,10 @@ if (D->hasAttr()) return true; + // Declarations that don't have identifier names always need to be mangled. + if (isa(D)) + return true; + return shouldMangleCXXName(D); } @@ -153,6 +159,9 @@ return; } + if (auto *GD = dyn_cast(D)) + return mangleMSGuidDecl(GD, Out); + const ASTContext &ASTContext = getASTContext(); CCMangling CC = getCallingConvMangling(ASTContext, D); @@ -209,6 +218,20 @@ Out << ((TI.getPointerWidth(0) / 8) * ArgWords); } +void MangleContext::mangleMSGuidDecl(const MSGuidDecl *GD, raw_ostream &Out) { + // For now, follow the MSVC naming convention for GUID objects on all + // targets. + MSGuidDecl::Parts P = GD->getParts(); + Out << llvm::format("_GUID_%08" PRIx32 "_%04" PRIx32 "_%04" PRIx32 "_", + P.Part1, P.Part2, P.Part3); + unsigned I = 0; + for (uint8_t C : P.Part4And5) { + Out << llvm::format("%02" PRIx8, C); + if (++I == 2) + Out << "_"; + } +} + void MangleContext::mangleGlobalBlock(const BlockDecl *BD, const NamedDecl *ID, raw_ostream &Out) { diff --git a/clang/lib/AST/MicrosoftMangle.cpp b/clang/lib/AST/MicrosoftMangle.cpp --- a/clang/lib/AST/MicrosoftMangle.cpp +++ b/clang/lib/AST/MicrosoftMangle.cpp @@ -462,7 +462,7 @@ if (VD->isExternC()) return false; - // Variables at global scope with non-internal linkage are not mangled. + // Variables at global scope with internal linkage are not mangled. const DeclContext *DC = getEffectiveDeclContext(D); // Check for extern variable declared locally. if (DC->isFunctionOrMethod() && D->hasLinkage()) @@ -497,6 +497,10 @@ mangleFunctionEncoding(FD, Context.shouldMangleDeclName(FD)); else if (const VarDecl *VD = dyn_cast(D)) mangleVariableEncoding(VD); + else if (isa(D)) + // MSVC appears to mangle GUIDs as if they were variables of type + // 'const struct __s_GUID'. + Out << "3U__s_GUID@@B"; else llvm_unreachable("Tried to mangle unexpected NamedDecl!"); } @@ -893,6 +897,16 @@ break; } + if (const MSGuidDecl *GD = dyn_cast(ND)) { + // Mangle a GUID object as if it were a variable with the corresponding + // mangled name. + SmallString GUID; + llvm::raw_svector_ostream GUIDOS(GUID); + Context.mangleMSGuidDecl(GD, GUIDOS); + mangleSourceName(GUID); + break; + } + // We must have an anonymous struct. const TagDecl *TD = cast(ND); if (const TypedefNameDecl *D = TD->getTypedefNameForAnonDecl()) { @@ -1364,45 +1378,6 @@ return; } - // Look through no-op casts like template parameter substitutions. - E = E->IgnoreParenNoopCasts(Context.getASTContext()); - - const CXXUuidofExpr *UE = nullptr; - if (const UnaryOperator *UO = dyn_cast(E)) { - if (UO->getOpcode() == UO_AddrOf) - UE = dyn_cast(UO->getSubExpr()); - } else - UE = dyn_cast(E); - - if (UE) { - // If we had to peek through an address-of operator, treat this like we are - // dealing with a pointer type. Otherwise, treat it like a const reference. - // - // N.B. This matches up with the handling of TemplateArgument::Declaration - // in mangleTemplateArg - if (UE == E) - Out << "$E?"; - else - Out << "$1?"; - - // This CXXUuidofExpr is mangled as-if it were actually a VarDecl from - // const __s_GUID _GUID_{lower case UUID with underscores} - StringRef Uuid = UE->getUuidStr(); - std::string Name = "_GUID_" + Uuid.lower(); - std::replace(Name.begin(), Name.end(), '-', '_'); - - mangleSourceName(Name); - // Terminate the whole name with an '@'. - Out << '@'; - // It's a global variable. - Out << '3'; - // It's a struct called __s_GUID. - mangleArtificialTagType(TTK_Struct, "__s_GUID"); - // It's const. - Out << 'B'; - return; - } - // As bad as this diagnostic is, it's better than crashing. DiagnosticsEngine &Diags = Context.getDiags(); unsigned DiagID = Diags.getCustomDiagID( diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp --- a/clang/lib/CodeGen/CGDebugInfo.cpp +++ b/clang/lib/CodeGen/CGDebugInfo.cpp @@ -1868,6 +1868,8 @@ CharUnits chars = CGM.getContext().toCharUnitsFromBits((int64_t)fieldOffset); V = CGM.getCXXABI().EmitMemberDataPointer(MPT, chars); + } else if (const auto *GD = dyn_cast(D)) { + V = CGM.GetAddrOfMSGuidDecl(GD).getPointer(); } assert(V && "Failed to find template parameter pointer"); V = V->stripPointerCasts(); diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp --- a/clang/lib/CodeGen/CGDecl.cpp +++ b/clang/lib/CodeGen/CGDecl.cpp @@ -108,6 +108,7 @@ case Decl::StaticAssert: // static_assert(X, ""); [C++0x] case Decl::Label: // __label__ x; case Decl::Import: + case Decl::MSGuid: // __declspec(uuid("...")) case Decl::OMPThreadPrivate: case Decl::OMPAllocate: case Decl::OMPCapturedExpr: diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -2706,6 +2706,12 @@ if (const auto *BD = dyn_cast(ND)) return EmitLValue(BD->getBinding()); + // We can form DeclRefExprs naming GUID declarations when reconstituting + // non-type template parameters into expressions. + if (const auto *GD = dyn_cast(ND)) + return MakeAddrLValue(CGM.GetAddrOfMSGuidDecl(GD), T, + AlignmentSource::Decl); + llvm_unreachable("Unhandled DeclRefExpr"); } @@ -4812,7 +4818,7 @@ } Address CodeGenFunction::EmitCXXUuidofExpr(const CXXUuidofExpr *E) { - return Builder.CreateElementBitCast(CGM.GetAddrOfUuidDescriptor(E), + return Builder.CreateElementBitCast(CGM.GetAddrOfMSGuidDecl(E->getGuidDecl()), ConvertType(E->getType())); } diff --git a/clang/lib/CodeGen/CGExprConstant.cpp b/clang/lib/CodeGen/CGExprConstant.cpp --- a/clang/lib/CodeGen/CGExprConstant.cpp +++ b/clang/lib/CodeGen/CGExprConstant.cpp @@ -1766,7 +1766,6 @@ ConstantLValue VisitCallExpr(const CallExpr *E); ConstantLValue VisitBlockExpr(const BlockExpr *E); ConstantLValue VisitCXXTypeidExpr(const CXXTypeidExpr *E); - ConstantLValue VisitCXXUuidofExpr(const CXXUuidofExpr *E); ConstantLValue VisitMaterializeTemporaryExpr( const MaterializeTemporaryExpr *E); @@ -1881,6 +1880,9 @@ } } + if (auto *GD = dyn_cast(D)) + return CGM.GetAddrOfMSGuidDecl(GD); + return nullptr; } @@ -1991,11 +1993,6 @@ } ConstantLValue -ConstantLValueEmitter::VisitCXXUuidofExpr(const CXXUuidofExpr *E) { - return CGM.GetAddrOfUuidDescriptor(E); -} - -ConstantLValue ConstantLValueEmitter::VisitMaterializeTemporaryExpr( const MaterializeTemporaryExpr *E) { assert(E->getStorageDuration() == SD_Static); diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h --- a/clang/lib/CodeGen/CodeGenModule.h +++ b/clang/lib/CodeGen/CodeGenModule.h @@ -856,8 +856,8 @@ /// Get the address of the RTTI descriptor for the given type. llvm::Constant *GetAddrOfRTTIDescriptor(QualType Ty, bool ForEH = false); - /// Get the address of a uuid descriptor . - ConstantAddress GetAddrOfUuidDescriptor(const CXXUuidofExpr* E); + /// Get the address of a GUID. + ConstantAddress GetAddrOfMSGuidDecl(const MSGuidDecl *GD); /// Get the address of the thunk for the given global decl. llvm::Constant *GetAddrOfThunk(StringRef Name, llvm::Type *FnTy, @@ -1518,9 +1518,6 @@ /// .gcda files in a way that persists in .bc files. void EmitCoverageFile(); - /// Emits the initializer for a uuidof string. - llvm::Constant *EmitUuidofInitializer(StringRef uuidstr); - /// Determine whether the definition must be emitted; if this returns \c /// false, the definition can be emitted lazily if it's used. bool MustBeEmitted(const ValueDecl *D); diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -2435,13 +2435,8 @@ return true; } -ConstantAddress CodeGenModule::GetAddrOfUuidDescriptor( - const CXXUuidofExpr* E) { - // Sema has verified that IIDSource has a __declspec(uuid()), and that its - // well-formed. - StringRef Uuid = E->getUuidStr(); - std::string Name = "_GUID_" + Uuid.lower(); - std::replace(Name.begin(), Name.end(), '-', '_'); +ConstantAddress CodeGenModule::GetAddrOfMSGuidDecl(const MSGuidDecl *GD) { + StringRef Name = getMangledName(GD); // The UUID descriptor should be pointer aligned. CharUnits Alignment = CharUnits::fromQuantity(PointerAlignInBytes); @@ -2450,8 +2445,30 @@ if (llvm::GlobalVariable *GV = getModule().getNamedGlobal(Name)) return ConstantAddress(GV, Alignment); - llvm::Constant *Init = EmitUuidofInitializer(Uuid); - assert(Init && "failed to initialize as constant"); + ConstantEmitter Emitter(*this); + llvm::Constant *Init; + + APValue &V = GD->getAsAPValue(); + if (!V.isAbsent()) { + // If possible, emit the APValue version of the initializer. In particular, + // this gets the type of the constant right. + Init = Emitter.emitForInitializer( + GD->getAsAPValue(), GD->getType().getAddressSpace(), GD->getType()); + } else { + // As a fallback, directly construct the constant. + // FIXME: This may get padding wrong under esoteric struct layout rules. + // MSVC appears to create a complete type 'struct __s_GUID' that it + // presumably uses to represent these constants. + MSGuidDecl::Parts Parts = GD->getParts(); + llvm::Constant *Fields[4] = { + llvm::ConstantInt::get(Int32Ty, Parts.Part1), + llvm::ConstantInt::get(Int16Ty, Parts.Part2), + llvm::ConstantInt::get(Int16Ty, Parts.Part3), + llvm::ConstantDataArray::getRaw( + StringRef(reinterpret_cast(Parts.Part4And5), 8), 8, + Int8Ty)}; + Init = llvm::ConstantStruct::getAnon(Fields); + } auto *GV = new llvm::GlobalVariable( getModule(), Init->getType(), @@ -2459,7 +2476,16 @@ if (supportsCOMDAT()) GV->setComdat(TheModule.getOrInsertComdat(GV->getName())); setDSOLocal(GV); - return ConstantAddress(GV, Alignment); + + llvm::Constant *Addr = GV; + if (!V.isAbsent()) { + Emitter.finalize(GV); + } else { + llvm::Type *Ty = getTypes().ConvertTypeForMem(GD->getType()); + Addr = llvm::ConstantExpr::getBitCast( + GV, Ty->getPointerTo(GV->getAddressSpace())); + } + return ConstantAddress(Addr, Alignment); } ConstantAddress CodeGenModule::GetWeakRefReference(const ValueDecl *VD) { @@ -5775,33 +5801,6 @@ } } -llvm::Constant *CodeGenModule::EmitUuidofInitializer(StringRef Uuid) { - // Sema has checked that all uuid strings are of the form - // "12345678-1234-1234-1234-1234567890ab". - assert(Uuid.size() == 36); - for (unsigned i = 0; i < 36; ++i) { - if (i == 8 || i == 13 || i == 18 || i == 23) assert(Uuid[i] == '-'); - else assert(isHexDigit(Uuid[i])); - } - - // The starts of all bytes of Field3 in Uuid. Field 3 is "1234-1234567890ab". - const unsigned Field3ValueOffsets[8] = { 19, 21, 24, 26, 28, 30, 32, 34 }; - - llvm::Constant *Field3[8]; - for (unsigned Idx = 0; Idx < 8; ++Idx) - Field3[Idx] = llvm::ConstantInt::get( - Int8Ty, Uuid.substr(Field3ValueOffsets[Idx], 2), 16); - - llvm::Constant *Fields[4] = { - llvm::ConstantInt::get(Int32Ty, Uuid.substr(0, 8), 16), - llvm::ConstantInt::get(Int16Ty, Uuid.substr(9, 4), 16), - llvm::ConstantInt::get(Int16Ty, Uuid.substr(14, 4), 16), - llvm::ConstantArray::get(llvm::ArrayType::get(Int8Ty, 8), Field3) - }; - - return llvm::ConstantStruct::getAnon(Fields); -} - llvm::Constant *CodeGenModule::GetAddrOfRTTIDescriptor(QualType Ty, bool ForEH) { // Return a bogus pointer if RTTI is disabled, unless it's for EH. diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -2592,7 +2592,7 @@ AMK == Sema::AMK_ProtocolImplementation)) NewAttr = nullptr; else if (const auto *UA = dyn_cast(Attr)) - NewAttr = S.mergeUuidAttr(D, *UA, UA->getGuid()); + NewAttr = S.mergeUuidAttr(D, *UA, UA->getGuid(), UA->getGuidDecl()); else if (const auto *SLHA = dyn_cast(Attr)) NewAttr = S.mergeSpeculativeLoadHardeningAttr(D, *SLHA); else if (const auto *SLHA = dyn_cast(Attr)) diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -5471,9 +5471,9 @@ //===----------------------------------------------------------------------===// UuidAttr *Sema::mergeUuidAttr(Decl *D, const AttributeCommonInfo &CI, - StringRef Uuid) { + StringRef UuidAsWritten, MSGuidDecl *GuidDecl) { if (const auto *UA = D->getAttr()) { - if (UA->getGuid().equals_lower(Uuid)) + if (declaresSameEntity(UA->getGuidDecl(), GuidDecl)) return nullptr; if (!UA->getGuid().empty()) { Diag(UA->getLocation(), diag::err_mismatched_uuid); @@ -5482,7 +5482,7 @@ } } - return ::new (Context) UuidAttr(Context, CI, Uuid); + return ::new (Context) UuidAttr(Context, CI, UuidAsWritten, GuidDecl); } static void handleUuidAttr(Sema &S, Decl *D, const ParsedAttr &AL) { @@ -5492,13 +5492,14 @@ return; } - StringRef StrRef; + StringRef OrigStrRef; SourceLocation LiteralLoc; - if (!S.checkStringLiteralArgumentAttr(AL, 0, StrRef, &LiteralLoc)) + if (!S.checkStringLiteralArgumentAttr(AL, 0, OrigStrRef, &LiteralLoc)) return; // GUID format is "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX" or // "{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}", normalize to the former. + StringRef StrRef = OrigStrRef; if (StrRef.size() == 38 && StrRef.front() == '{' && StrRef.back() == '}') StrRef = StrRef.drop_front().drop_back(); @@ -5520,6 +5521,16 @@ } } + // Convert to our parsed format and canonicalize. + MSGuidDecl::Parts Parsed; + StrRef.substr(0, 8).getAsInteger(16, Parsed.Part1); + StrRef.substr(9, 4).getAsInteger(16, Parsed.Part2); + StrRef.substr(14, 4).getAsInteger(16, Parsed.Part3); + for (unsigned i = 0; i != 8; ++i) + StrRef.substr(19 + 2 * i + (i >= 2 ? 1 : 0), 2) + .getAsInteger(16, Parsed.Part4And5[i]); + MSGuidDecl *Guid = S.Context.getMSGuidDecl(Parsed); + // 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 // __declspec(uuid(...)). But sadly, neither the SourceLocs of the commas @@ -5529,7 +5540,7 @@ if (AL.isMicrosoftAttribute()) // Check for [uuid(...)] spelling. S.Diag(AL.getLoc(), diag::warn_atl_uuid_deprecated); - UuidAttr *UA = S.mergeUuidAttr(D, AL, StrRef); + UuidAttr *UA = S.mergeUuidAttr(D, AL, OrigStrRef, Guid); if (UA) D->addAttr(UA); } diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -3274,6 +3274,9 @@ llvm_unreachable("building reference to deduction guide"); case Decl::MSProperty: + case Decl::MSGuid: + // FIXME: Should MSGuidDecl be subject to capture in OpenMP, + // or duplicated between host and device? valueKind = VK_LValue; break; @@ -12816,6 +12819,9 @@ /// - *(x + 1) -> x, if x is an array /// - &"123"[2] -> 0 /// - & __real__ x -> x +/// +/// FIXME: We don't recurse to the RHS of a comma, nor handle pointers to +/// members. static ValueDecl *getPrimaryDecl(Expr *E) { switch (E->getStmtClass()) { case Stmt::DeclRefExprClass: @@ -12856,6 +12862,8 @@ // If the result of an implicit cast is an l-value, we care about // the sub-expression; otherwise, the result here doesn't matter. return getPrimaryDecl(cast(E)->getSubExpr()); + case Stmt::CXXUuidofExprClass: + return cast(E)->getGuidDecl(); default: return nullptr; } @@ -13076,7 +13084,7 @@ } } } else if (!isa(dcl) && !isa(dcl) && - !isa(dcl)) + !isa(dcl) && !isa(dcl)) llvm_unreachable("Unknown/unexpected decl type"); } diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -704,11 +704,11 @@ } /// Build a Microsoft __uuidof expression with a type operand. -ExprResult Sema::BuildCXXUuidof(QualType TypeInfoType, +ExprResult Sema::BuildCXXUuidof(QualType Type, SourceLocation TypeidLoc, TypeSourceInfo *Operand, SourceLocation RParenLoc) { - StringRef UuidStr; + MSGuidDecl *Guid = nullptr; if (!Operand->getType()->isDependentType()) { llvm::SmallSetVector UuidAttrs; getUuidAttrOfType(*this, Operand->getType(), UuidAttrs); @@ -716,22 +716,21 @@ 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(); + Guid = UuidAttrs.back()->getGuidDecl(); } - return new (Context) CXXUuidofExpr(TypeInfoType.withConst(), Operand, UuidStr, - SourceRange(TypeidLoc, RParenLoc)); + return new (Context) + CXXUuidofExpr(Type, Operand, Guid, SourceRange(TypeidLoc, RParenLoc)); } /// Build a Microsoft __uuidof expression with an expression operand. -ExprResult Sema::BuildCXXUuidof(QualType TypeInfoType, - SourceLocation TypeidLoc, - Expr *E, - SourceLocation RParenLoc) { - StringRef UuidStr; +ExprResult Sema::BuildCXXUuidof(QualType Type, SourceLocation TypeidLoc, + Expr *E, SourceLocation RParenLoc) { + MSGuidDecl *Guid = nullptr; if (!E->getType()->isDependentType()) { if (E->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) { - UuidStr = "00000000-0000-0000-0000-000000000000"; + // A null pointer results in {00000000-0000-0000-0000-000000000000}. + Guid = Context.getMSGuidDecl(MSGuidDecl::Parts{}); } else { llvm::SmallSetVector UuidAttrs; getUuidAttrOfType(*this, E->getType(), UuidAttrs); @@ -739,29 +738,20 @@ 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(); + Guid = UuidAttrs.back()->getGuidDecl(); } } - return new (Context) CXXUuidofExpr(TypeInfoType.withConst(), E, UuidStr, - SourceRange(TypeidLoc, RParenLoc)); + return new (Context) + CXXUuidofExpr(Type, E, Guid, SourceRange(TypeidLoc, RParenLoc)); } /// ActOnCXXUuidof - Parse __uuidof( type-id ) or __uuidof (expression); ExprResult Sema::ActOnCXXUuidof(SourceLocation OpLoc, SourceLocation LParenLoc, bool isType, void *TyOrExpr, SourceLocation RParenLoc) { - // If MSVCGuidDecl has not been cached, do the lookup. - if (!MSVCGuidDecl) { - IdentifierInfo *GuidII = &PP.getIdentifierTable().get("_GUID"); - LookupResult R(*this, GuidII, SourceLocation(), LookupTagName); - LookupQualifiedName(R, Context.getTranslationUnitDecl()); - MSVCGuidDecl = R.getAsSingle(); - if (!MSVCGuidDecl) - return ExprError(Diag(OpLoc, diag::err_need_header_before_ms_uuidof)); - } - - QualType GuidType = Context.getTypeDeclType(MSVCGuidDecl); + QualType GuidType = Context.getMSGuidType(); + GuidType.addConst(); if (isType) { // The operand is a type; handle it as such. diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -6331,8 +6331,11 @@ Arg = subst->getReplacement()->IgnoreImpCasts(); } - DeclRefExpr *DRE = dyn_cast(Arg); - ValueDecl *Entity = DRE ? DRE->getDecl() : nullptr; + ValueDecl *Entity = nullptr; + if (DeclRefExpr *DRE = dyn_cast(Arg)) + Entity = DRE->getDecl(); + else if (CXXUuidofExpr *CUE = dyn_cast(Arg)) + Entity = CUE->getGuidDecl(); // If our parameter has pointer type, check for a null template value. if (ParamType->isPointerType() || ParamType->isNullPtrType()) { @@ -6359,16 +6362,7 @@ return false; } - if (isa(Arg)) { - if (CheckTemplateArgumentIsCompatibleWithParameter(S, Param, ParamType, - ArgIn, Arg, ArgType)) - return true; - - Converted = TemplateArgument(ArgIn); - return false; - } - - if (!DRE) { + if (!Entity) { S.Diag(Arg->getBeginLoc(), diag::err_template_arg_not_decl_ref) << Arg->getSourceRange(); S.Diag(Param->getLocation(), diag::note_template_param_here); @@ -6395,13 +6389,14 @@ FunctionDecl *Func = dyn_cast(Entity); VarDecl *Var = dyn_cast(Entity); + MSGuidDecl *Guid = dyn_cast(Entity); // A non-type template argument must refer to an object or function. - if (!Func && !Var) { + if (!Func && !Var && !Guid) { // We found something, but we don't know specifically what it is. S.Diag(Arg->getBeginLoc(), diag::err_template_arg_not_object_or_func) << Arg->getSourceRange(); - S.Diag(DRE->getDecl()->getLocation(), diag::note_template_arg_refers_here); + S.Diag(Entity->getLocation(), diag::note_template_arg_refers_here); return true; } @@ -6422,30 +6417,7 @@ return true; } - if (Func) { - // If the template parameter has pointer type, the function decays. - if (ParamType->isPointerType() && !AddressTaken) - ArgType = S.Context.getPointerType(Func->getType()); - else if (AddressTaken && ParamType->isReferenceType()) { - // If we originally had an address-of operator, but the - // parameter has reference type, complain and (if things look - // like they will work) drop the address-of operator. - if (!S.Context.hasSameUnqualifiedType(Func->getType(), - ParamType.getNonReferenceType())) { - S.Diag(AddrOpLoc, diag::err_template_arg_address_of_non_pointer) - << ParamType; - S.Diag(Param->getLocation(), diag::note_template_param_here); - return true; - } - - S.Diag(AddrOpLoc, diag::err_template_arg_address_of_non_pointer) - << ParamType - << FixItHint::CreateRemoval(AddrOpLoc); - S.Diag(Param->getLocation(), diag::note_template_param_here); - - ArgType = Func->getType(); - } - } else { + if (Var) { // A value of reference type is not an object. if (Var->getType()->isReferenceType()) { S.Diag(Arg->getBeginLoc(), diag::err_template_arg_reference_var) @@ -6461,50 +6433,53 @@ S.Diag(Var->getLocation(), diag::note_template_arg_refers_here); return true; } + } - // If the template parameter has pointer type, we must have taken - // the address of this object. - if (ParamType->isReferenceType()) { - if (AddressTaken) { - // If we originally had an address-of operator, but the - // parameter has reference type, complain and (if things look - // like they will work) drop the address-of operator. - if (!S.Context.hasSameUnqualifiedType(Var->getType(), - ParamType.getNonReferenceType())) { - S.Diag(AddrOpLoc, diag::err_template_arg_address_of_non_pointer) - << ParamType; - S.Diag(Param->getLocation(), diag::note_template_param_here); - return true; - } + if (AddressTaken && ParamType->isReferenceType()) { + // If we originally had an address-of operator, but the + // parameter has reference type, complain and (if things look + // like they will work) drop the address-of operator. + if (!S.Context.hasSameUnqualifiedType(Entity->getType(), + ParamType.getNonReferenceType())) { + S.Diag(AddrOpLoc, diag::err_template_arg_address_of_non_pointer) + << ParamType; + S.Diag(Param->getLocation(), diag::note_template_param_here); + return true; + } - S.Diag(AddrOpLoc, diag::err_template_arg_address_of_non_pointer) - << ParamType - << FixItHint::CreateRemoval(AddrOpLoc); - S.Diag(Param->getLocation(), diag::note_template_param_here); + S.Diag(AddrOpLoc, diag::err_template_arg_address_of_non_pointer) + << ParamType + << FixItHint::CreateRemoval(AddrOpLoc); + S.Diag(Param->getLocation(), diag::note_template_param_here); - ArgType = Var->getType(); - } - } else if (!AddressTaken && ParamType->isPointerType()) { - if (Var->getType()->isArrayType()) { - // Array-to-pointer decay. - ArgType = S.Context.getArrayDecayedType(Var->getType()); - } else { - // If the template parameter has pointer type but the address of - // this object was not taken, complain and (possibly) recover by - // taking the address of the entity. - ArgType = S.Context.getPointerType(Var->getType()); - if (!S.Context.hasSameUnqualifiedType(ArgType, ParamType)) { - S.Diag(Arg->getBeginLoc(), diag::err_template_arg_not_address_of) - << ParamType; - S.Diag(Param->getLocation(), diag::note_template_param_here); - return true; - } + ArgType = Entity->getType(); + } + // If the template parameter has pointer type, either we must have taken the + // address or the argument must decay to a pointer. + if (!AddressTaken && ParamType->isPointerType()) { + if (Func) { + // Function-to-pointer decay. + ArgType = S.Context.getPointerType(Func->getType()); + } else if (Entity->getType()->isArrayType()) { + // Array-to-pointer decay. + ArgType = S.Context.getArrayDecayedType(Entity->getType()); + } else { + // If the template parameter has pointer type but the address of + // this object was not taken, complain and (possibly) recover by + // taking the address of the entity. + ArgType = S.Context.getPointerType(Entity->getType()); + if (!S.Context.hasSameUnqualifiedType(ArgType, ParamType)) { S.Diag(Arg->getBeginLoc(), diag::err_template_arg_not_address_of) - << ParamType << FixItHint::CreateInsertion(Arg->getBeginLoc(), "&"); - + << ParamType; S.Diag(Param->getLocation(), diag::note_template_param_here); + return true; } + + S.Diag(Arg->getBeginLoc(), diag::err_template_arg_not_address_of) + << ParamType << FixItHint::CreateInsertion(Arg->getBeginLoc(), "&"); + + S.Diag(Param->getLocation(), diag::note_template_param_here); } } @@ -6830,11 +6805,6 @@ APValue::LValueBase Base = Value.getLValueBase(); auto *VD = const_cast(Base.dyn_cast()); if (Base && (!VD || isa(VD))) { - auto *E = Base.dyn_cast(); - if (E && isa(E)) { - Converted = TemplateArgument(ArgResult.get()->IgnoreImpCasts()); - break; - } Diag(Arg->getBeginLoc(), diag::err_template_arg_not_decl_ref) << Arg->getSourceRange(); return ExprError(); diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -698,6 +698,10 @@ llvm_unreachable("extern \"C\" context cannot be instantiated"); } +Decl *TemplateDeclInstantiator::VisitMSGuidDecl(MSGuidDecl *D) { + llvm_unreachable("GUID declaration cannot be instantiated"); +} + Decl * TemplateDeclInstantiator::VisitLabelDecl(LabelDecl *D) { LabelDecl *Inst = LabelDecl::Create(SemaRef.Context, Owner, D->getLocation(), diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -8305,14 +8305,14 @@ // If the type was a forward declaration of a class/struct/union // type, produce a note. - if (Tag && !Tag->isInvalidDecl()) + if (Tag && !Tag->isInvalidDecl() && !Tag->getLocation().isInvalid()) Diag(Tag->getLocation(), Tag->isBeingDefined() ? diag::note_type_being_defined : diag::note_forward_declaration) << Context.getTagDeclType(Tag); // If the Objective-C class was a forward declaration, produce a note. - if (IFace && !IFace->isInvalidDecl()) + if (IFace && !IFace->isInvalidDecl() && !IFace->getLocation().isInvalid()) Diag(IFace->getLocation(), diag::note_forward_class); // If we have external information that we can use to suggest a fix, diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -2832,24 +2832,19 @@ /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. - ExprResult RebuildCXXUuidofExpr(QualType TypeInfoType, - SourceLocation TypeidLoc, - TypeSourceInfo *Operand, - SourceLocation RParenLoc) { - return getSema().BuildCXXUuidof(TypeInfoType, TypeidLoc, Operand, - RParenLoc); + ExprResult RebuildCXXUuidofExpr(QualType Type, SourceLocation TypeidLoc, + TypeSourceInfo *Operand, + SourceLocation RParenLoc) { + return getSema().BuildCXXUuidof(Type, TypeidLoc, Operand, RParenLoc); } /// Build a new C++ __uuidof(expr) expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. - ExprResult RebuildCXXUuidofExpr(QualType TypeInfoType, - SourceLocation TypeidLoc, - Expr *Operand, - SourceLocation RParenLoc) { - return getSema().BuildCXXUuidof(TypeInfoType, TypeidLoc, Operand, - RParenLoc); + ExprResult RebuildCXXUuidofExpr(QualType Type, SourceLocation TypeidLoc, + Expr *Operand, SourceLocation RParenLoc) { + return getSema().BuildCXXUuidof(Type, TypeidLoc, Operand, RParenLoc); } /// Build a new C++ "this" expression. diff --git a/clang/lib/Serialization/ASTCommon.cpp b/clang/lib/Serialization/ASTCommon.cpp --- a/clang/lib/Serialization/ASTCommon.cpp +++ b/clang/lib/Serialization/ASTCommon.cpp @@ -371,6 +371,7 @@ case Decl::IndirectField: case Decl::Field: case Decl::MSProperty: + case Decl::MSGuid: case Decl::ObjCIvar: case Decl::ObjCAtDefsField: case Decl::NonTypeTemplateParm: diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -7287,6 +7287,9 @@ case PREDEF_DECL_BUILTIN_MS_VA_LIST_ID: return Context.getBuiltinMSVaListDecl(); + case PREDEF_DECL_BUILTIN_MS_GUID_ID: + return Context.getMSGuidTagDecl(); + case PREDEF_DECL_EXTERN_C_CONTEXT_ID: return Context.getExternCContextDecl(); diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp --- a/clang/lib/Serialization/ASTReaderDecl.cpp +++ b/clang/lib/Serialization/ASTReaderDecl.cpp @@ -365,6 +365,7 @@ void VisitCXXConversionDecl(CXXConversionDecl *D); void VisitFieldDecl(FieldDecl *FD); void VisitMSPropertyDecl(MSPropertyDecl *FD); + void VisitMSGuidDecl(MSGuidDecl *D); void VisitIndirectFieldDecl(IndirectFieldDecl *FD); RedeclarableResult VisitVarDeclImpl(VarDecl *D); void VisitVarDecl(VarDecl *VD) { VisitVarDeclImpl(VD); } @@ -1358,6 +1359,19 @@ PD->SetterId = Record.readIdentifier(); } +void ASTDeclReader::VisitMSGuidDecl(MSGuidDecl *D) { + VisitValueDecl(D); + D->PartVal.Part1 = Record.readInt(); + D->PartVal.Part2 = Record.readInt(); + D->PartVal.Part3 = Record.readInt(); + for (auto &C : D->PartVal.Part4And5) + C = Record.readInt(); + + // Add this GUID to the AST context's lookup structure, and merge if needed. + if (MSGuidDecl *Existing = Reader.getContext().MSGuidDecls.GetOrInsertNode(D)) + Reader.getContext().setPrimaryMergedDecl(D, Existing->getCanonicalDecl()); +} + void ASTDeclReader::VisitIndirectFieldDecl(IndirectFieldDecl *FD) { VisitValueDecl(FD); @@ -3966,6 +3980,9 @@ case DECL_MS_PROPERTY: D = MSPropertyDecl::CreateDeserialized(Context, ID); break; + case DECL_MS_GUID: + D = MSGuidDecl::CreateDeserialized(Context, ID); + break; case DECL_CAPTURED: D = CapturedDecl::CreateDeserialized(Context, ID, Record.readInt()); break; diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp --- a/clang/lib/Serialization/ASTReaderStmt.cpp +++ b/clang/lib/Serialization/ASTReaderStmt.cpp @@ -2156,8 +2156,7 @@ void ASTStmtReader::VisitCXXUuidofExpr(CXXUuidofExpr *E) { VisitExpr(E); E->setSourceRange(readSourceRange()); - std::string UuidStr = readString(); - E->setUuidStr(StringRef(UuidStr).copy(Record.getContext())); + E->Guid = readDeclAs(); if (E->isTypeOperand()) E->Operand = readTypeSourceInfo(); else diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -4372,6 +4372,8 @@ RegisterPredefDecl(Context.VaListTagDecl, PREDEF_DECL_VA_LIST_TAG); RegisterPredefDecl(Context.BuiltinMSVaListDecl, PREDEF_DECL_BUILTIN_MS_VA_LIST_ID); + RegisterPredefDecl(Context.MSGuidTagDecl, + PREDEF_DECL_BUILTIN_MS_GUID_ID); RegisterPredefDecl(Context.ExternCContext, PREDEF_DECL_EXTERN_C_CONTEXT_ID); RegisterPredefDecl(Context.MakeIntegerSeqDecl, PREDEF_DECL_MAKE_INTEGER_SEQ_ID); diff --git a/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp --- a/clang/lib/Serialization/ASTWriterDecl.cpp +++ b/clang/lib/Serialization/ASTWriterDecl.cpp @@ -95,6 +95,7 @@ void VisitCXXConversionDecl(CXXConversionDecl *D); void VisitFieldDecl(FieldDecl *D); void VisitMSPropertyDecl(MSPropertyDecl *D); + void VisitMSGuidDecl(MSGuidDecl *D); void VisitIndirectFieldDecl(IndirectFieldDecl *D); void VisitVarDecl(VarDecl *D); void VisitImplicitParamDecl(ImplicitParamDecl *D); @@ -953,6 +954,17 @@ Code = serialization::DECL_MS_PROPERTY; } +void ASTDeclWriter::VisitMSGuidDecl(MSGuidDecl *D) { + VisitValueDecl(D); + MSGuidDecl::Parts Parts = D->getParts(); + Record.push_back(Parts.Part1); + Record.push_back(Parts.Part2); + Record.push_back(Parts.Part3); + for (auto C : Parts.Part4And5) + Record.push_back(C); + Code = serialization::DECL_MS_GUID; +} + void ASTDeclWriter::VisitIndirectFieldDecl(IndirectFieldDecl *D) { VisitValueDecl(D); Record.push_back(D->getChainingSize()); diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp --- a/clang/lib/Serialization/ASTWriterStmt.cpp +++ b/clang/lib/Serialization/ASTWriterStmt.cpp @@ -2070,7 +2070,7 @@ void ASTStmtWriter::VisitCXXUuidofExpr(CXXUuidofExpr *E) { VisitExpr(E); Record.AddSourceRange(E->getSourceRange()); - Record.AddString(E->getUuidStr()); + Record.AddDeclRef(E->getGuidDecl()); if (E->isTypeOperand()) { Record.AddTypeSourceInfo(E->getTypeOperandSourceInfo()); Code = serialization::EXPR_CXX_UUIDOF_TYPE; diff --git a/clang/test/CodeGenCXX/debug-info-uuid.cpp b/clang/test/CodeGenCXX/debug-info-uuid.cpp --- a/clang/test/CodeGenCXX/debug-info-uuid.cpp +++ b/clang/test/CodeGenCXX/debug-info-uuid.cpp @@ -1,34 +1,36 @@ // RUN: %clang_cc1 -emit-llvm -fms-extensions -triple=x86_64-pc-win32 -debug-info-kind=limited %s -o - -std=c++11 | FileCheck %s // RUN: %clang_cc1 -emit-llvm -fms-extensions -triple=x86_64-unknown-unknown -debug-info-kind=limited %s -o - -std=c++11 2>&1 | FileCheck %s --check-prefix=CHECK-ITANIUM -// CHECK: !DICompositeType(tag: DW_TAG_structure_type, name: "tmpl_guid2<__uuidof(uuid)>" +// CHECK: !DICompositeType(tag: DW_TAG_structure_type, name: "tmpl_guid2" // CHECK-SAME: templateParams: [[TGI2ARGS:![0-9]*]] // CHECK: [[TGI2ARGS]] = !{[[TGI2ARG1:![0-9]*]]} // CHECK: [[TGI2ARG1]] = !DITemplateValueParameter( // CHECK-SAME: type: [[CONST_GUID_REF:![0-9]*]] -// CHECK-SAME: value: { i32, i16, i16, [8 x i8] }* @_GUID_12345678_1234_1234_1234_1234567890ab +// CHECK-SAME: value: %struct._GUID* @_GUID_12345678_1234_1234_1234_1234567890ab // CHECK: [[CONST_GUID_REF]] = !DIDerivedType(tag: DW_TAG_reference_type, // CHECK-SAME: baseType: [[CONST_GUID:![0-9]*]] // CHECK: [[CONST_GUID]] = !DIDerivedType(tag: DW_TAG_const_type // CHECK-SAME: baseType: [[GUID:![0-9]*]] // CHECK: [[GUID]] = !DICompositeType(tag: DW_TAG_structure_type, name: "_GUID" -// CHECK: !DICompositeType(tag: DW_TAG_structure_type, name: "tmpl_guid<&__uuidof(uuid)>" +// CHECK: !DICompositeType(tag: DW_TAG_structure_type, name: "tmpl_guid<&GUID{12345678-1234-1234-1234-1234567890ab}>" // CHECK-SAME: templateParams: [[TGIARGS:![0-9]*]] // CHECK: [[TGIARGS]] = !{[[TGIARG1:![0-9]*]]} // CHECK: [[TGIARG1]] = !DITemplateValueParameter( // CHECK-SAME: type: [[CONST_GUID_PTR:![0-9]*]] -// CHECK-SAME: value: { i32, i16, i16, [8 x i8] }* @_GUID_12345678_1234_1234_1234_1234567890ab +// CHECK-SAME: value: %struct._GUID* @_GUID_12345678_1234_1234_1234_1234567890ab // CHECK: [[CONST_GUID_PTR]] = !DIDerivedType(tag: DW_TAG_pointer_type // CHECK-SAME: baseType: [[CONST_GUID:![0-9]*]] // CHECK-SAME: size: 64 -// CHECK-ITANIUM: !DICompositeType(tag: DW_TAG_structure_type, name: "tmpl_guid2<__uuidof(uuid)>" -// CHECK-ITANIUM-SAME: identifier: "_ZTS10tmpl_guid2IXu8__uuidoft4uuidEE" -// CHECK-ITANIUM: !DICompositeType(tag: DW_TAG_structure_type, name: "tmpl_guid<&__uuidof(uuid)>" -// CHECK-ITANIUM-SAME: identifier: "_ZTS9tmpl_guidIXadu8__uuidoft4uuidEE" +// CHECK-ITANIUM: !DICompositeType(tag: DW_TAG_structure_type, name: "tmpl_guid2" +// CHECK-ITANIUM-SAME: identifier: "_ZTS10tmpl_guid2IL_Z42_GUID_12345678_1234_1234_1234_1234567890abEE" +// CHECK-ITANIUM: !DICompositeType(tag: DW_TAG_structure_type, name: "tmpl_guid<&GUID{12345678-1234-1234-1234-1234567890ab}>" +// CHECK-ITANIUM-SAME: identifier: "_ZTS9tmpl_guidIXadL_Z42_GUID_12345678_1234_1234_1234_1234567890abEEE" -struct _GUID; +struct _GUID { + __UINT32_TYPE__ a; __UINT16_TYPE__ b, c; __UINT8_TYPE__ d[8]; +}; template struct tmpl_guid { }; diff --git a/clang/test/CodeGenCXX/microsoft-templ-uuidof.cpp b/clang/test/CodeGenCXX/microsoft-templ-uuidof.cpp --- a/clang/test/CodeGenCXX/microsoft-templ-uuidof.cpp +++ b/clang/test/CodeGenCXX/microsoft-templ-uuidof.cpp @@ -1,6 +1,10 @@ // RUN: %clang_cc1 -emit-llvm %s -o - -DDEFINE_GUID -triple=i386-pc-win32 -fms-extensions | FileCheck %s -struct _GUID; +struct _GUID { + __UINT32_TYPE__ a; + __UINT16_TYPE__ b, c; + __UINT8_TYPE__ d[8]; +}; template struct X { diff --git a/clang/test/CodeGenCXX/microsoft-uuidof-mangling.cpp b/clang/test/CodeGenCXX/microsoft-uuidof-mangling.cpp --- a/clang/test/CodeGenCXX/microsoft-uuidof-mangling.cpp +++ b/clang/test/CodeGenCXX/microsoft-uuidof-mangling.cpp @@ -22,27 +22,36 @@ int foo; }; +struct __declspec(uuid("EAFA1952-66F8-438B-8FBA-AF1BBAE42191")) OtherStruct {}; + template void test_uuidofType(void *arg[sizeof(__uuidof(T))] = 0) {} template void test_uuidofExpr(void *arg[sizeof(__uuidof(typename T::member))] = 0) {} struct HasMember { typedef TestStruct member; }; +template struct UUIDTestTwo { UUIDTestTwo(); }; + int main(int argc, const char * argv[]) { - UUIDTest uuidof_test; + // Note that these variables have the same type, so the mangling of that + // type had better not mention TestStruct or OtherStruct! + UUIDTestTwo<__uuidof(TestStruct)> uuidof_test2; + UUIDTestTwo<__uuidof(OtherStruct)> uuidof_test3; test_uuidofType(); test_uuidofExpr(); return 0; } // CHECK: define i32 @main -// CHECK: call void @_ZN8UUIDTestI10TestStructXu8__uuidoftS0_EEC1Ev +// CHECK: call void @_ZN8UUIDTestI10TestStructL_Z42_GUID_eafa1952_66f8_438b_8fba_af1bbae42191EEC1Ev +// CHECK: call void @_ZN11UUIDTestTwoIL_Z42_GUID_eafa1952_66f8_438b_8fba_af1bbae42191EEC1Ev +// CHECK: call void @_ZN11UUIDTestTwoIL_Z42_GUID_eafa1952_66f8_438b_8fba_af1bbae42191EEC1Ev // CHECK: call void @_Z15test_uuidofTypeI10TestStructEvPPv(i8** null) // CHECK: call void @_Z15test_uuidofExprI9HasMemberEvPPv(i8** null) -// CHECK: define linkonce_odr void @_ZN8UUIDTestI10TestStructXu8__uuidoftS0_EEC1Ev +// CHECK: define linkonce_odr void @_ZN8UUIDTestI10TestStructL_Z42_GUID_eafa1952_66f8_438b_8fba_af1bbae42191EEC1Ev // CHECK: define linkonce_odr void @_Z15test_uuidofTypeI10TestStructEvPPv // CHECK: define linkonce_odr void @_Z15test_uuidofExprI9HasMemberEvPPv -// CHECK: define linkonce_odr void @_ZN8UUIDTestI10TestStructXu8__uuidoftS0_EEC2Ev +// CHECK: define linkonce_odr void @_ZN8UUIDTestI10TestStructL_Z42_GUID_eafa1952_66f8_438b_8fba_af1bbae42191EEC2Ev diff --git a/clang/test/CodeGenCXX/microsoft-uuidof.cpp b/clang/test/CodeGenCXX/microsoft-uuidof.cpp --- a/clang/test/CodeGenCXX/microsoft-uuidof.cpp +++ b/clang/test/CodeGenCXX/microsoft-uuidof.cpp @@ -30,16 +30,22 @@ struct __declspec(uuid("{12345678-1234-1234-1234-1234567890ac}")) Curly; #endif +void side_effect(); + #ifdef DEFINE_GUID // Make sure we can properly generate code when the UUID has curly braces on it. -GUID thing = __uuidof(Curly); +GUID thing = (side_effect(), __uuidof(Curly)); // CHECK-DEFINE-GUID: @thing = global %struct._GUID zeroinitializer, align 4 // CHECK-DEFINE-WRONG-GUID: @thing = global %struct._GUID zeroinitializer, align 4 // This gets initialized in a static initializer. // CHECK-DEFINE-GUID: @g = global %struct._GUID zeroinitializer, align 4 // CHECK-DEFINE-WRONG-GUID: @g = global %struct._GUID zeroinitializer, align 4 -GUID g = __uuidof(S1); +GUID g = (side_effect(), __uuidof(S1)); + +// CHECK-DEFINE-GUID: @const_init = global %struct._GUID { i32 305419896, i16 4660, i16 4660, [8 x i8] c"\124\124Vx\90\AC" } +// CHECK-DEFINE-WRONG-GUID: @const_init = global %struct._GUID zeroinitializer +GUID const_init = __uuidof(Curly); #endif // First global use of __uuidof(S1) forces the creation of the global. @@ -63,13 +69,17 @@ // CHECK: @_GUID_87654321_4321_4321_4321_ba0987654321 = linkonce_odr constant { i32, i16, i16, [8 x i8] } { i32 -2023406815, i16 17185, i16 17185, [8 x i8] c"C!\BA\09\87eC!" }, comdat // The static initializer for thing. -// CHECK-DEFINE-GUID: call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 bitcast (%struct._GUID* @thing to i8*), i8* align 4 bitcast ({ i32, i16, i16, [8 x i8] }* @_GUID_12345678_1234_1234_1234_1234567890ac to i8*), i32 16, i1 false) +// CHECK-DEFINE-GUID: call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 bitcast (%struct._GUID* @thing to i8*), i8* align 4 bitcast (%struct._GUID* @_GUID_12345678_1234_1234_1234_1234567890ac to i8*), i32 16, i1 false) // CHECK-DEFINE-WRONG-GUID: call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 bitcast (%struct._GUID* @thing to i8*), i8* align 4 bitcast ({ i32, i16, i16, [8 x i8] }* @_GUID_12345678_1234_1234_1234_1234567890ac to i8*), i32 4, i1 false) // The static initializer for g. -// CHECK-DEFINE-GUID: call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 bitcast (%struct._GUID* @g to i8*), i8* align 4 bitcast ({ i32, i16, i16, [8 x i8] }* @_GUID_12345678_1234_1234_1234_1234567890ab to i8*), i32 16, i1 false) +// CHECK-DEFINE-GUID: call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 bitcast (%struct._GUID* @g to i8*), i8* align 4 bitcast (%struct._GUID* @_GUID_12345678_1234_1234_1234_1234567890ab to i8*), i32 16, i1 false) // CHECK-DEFINE-WRONG-GUID: call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 bitcast (%struct._GUID* @g to i8*), i8* align 4 bitcast ({ i32, i16, i16, [8 x i8] }* @_GUID_12345678_1234_1234_1234_1234567890ab to i8*), i32 4, i1 false) +// We don't constant-initialize const_init if the definition of _GUID is dodgy. +// CHECK-DEFINE-GUID-NOT: @const_init +// CHECK-DEFINE-WRONG-GUID: call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 bitcast (%struct._GUID* @const_init to i8*), i8* align 4 bitcast ({ i32, i16, i16, [8 x i8] }* @_GUID_12345678_1234_1234_1234_1234567890ac to i8*), i32 4, i1 false) + #ifdef DEFINE_GUID void fun() { // CHECK-DEFINE-GUID: %s1_1 = alloca %struct._GUID, align 4 @@ -81,21 +91,21 @@ // CHECK-DEFINE-GUID: [[U1:%.+]] = bitcast %struct._GUID* %s1_1 to i8* // CHECK-DEFINE-WRONG-GUID: [[U1:%.+]] = bitcast %struct._GUID* %s1_1 to i8* - // CHECK-DEFINE-GUID: call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 [[U1]], i8* align 4 bitcast ({ i32, i16, i16, [8 x i8] }* @_GUID_12345678_1234_1234_1234_1234567890ab to i8*), i32 16, i1 false) + // CHECK-DEFINE-GUID: call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 [[U1]], i8* align 4 bitcast (%struct._GUID* @_GUID_12345678_1234_1234_1234_1234567890ab to i8*), i32 16, i1 false) // CHECK-DEFINE-WRONG-GUID: call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 [[U1]], i8* align 4 bitcast ({ i32, i16, i16, [8 x i8] }* @_GUID_12345678_1234_1234_1234_1234567890ab to i8*), i32 4, i1 false) - GUID s1_1 = __uuidof(S1); + GUID s1_1 = (side_effect(), __uuidof(S1)); // CHECK-DEFINE-GUID: [[U2:%.+]] = bitcast %struct._GUID* %s1_2 to i8* // CHECK-DEFINE-WRONG-GUID: [[U2:%.+]] = bitcast %struct._GUID* %s1_2 to i8* - // CHECK-DEFINE-GUID: call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 [[U2]], i8* align 4 bitcast ({ i32, i16, i16, [8 x i8] }* @_GUID_12345678_1234_1234_1234_1234567890ab to i8*), i32 16, i1 false) + // CHECK-DEFINE-GUID: call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 [[U2]], i8* align 4 bitcast (%struct._GUID* @_GUID_12345678_1234_1234_1234_1234567890ab to i8*), i32 16, i1 false) // CHECK-DEFINE-WRONG-GUID: call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 [[U2]], i8* align 4 bitcast ({ i32, i16, i16, [8 x i8] }* @_GUID_12345678_1234_1234_1234_1234567890ab to i8*), i32 4, i1 false) - GUID s1_2 = __uuidof(S1); + GUID s1_2 = (side_effect(), __uuidof(S1)); // CHECK-DEFINE-GUID: [[U3:%.+]] = bitcast %struct._GUID* %s1_3 to i8* // CHECK-DEFINE-WRONG-GUID: [[U3:%.+]] = bitcast %struct._GUID* %s1_3 to i8* - // CHECK-DEFINE-GUID: call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 [[U3]], i8* align 4 bitcast ({ i32, i16, i16, [8 x i8] }* @_GUID_12345678_1234_1234_1234_1234567890ab to i8*), i32 16, i1 false) + // CHECK-DEFINE-GUID: call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 [[U3]], i8* align 4 bitcast (%struct._GUID* @_GUID_12345678_1234_1234_1234_1234567890ab to i8*), i32 16, i1 false) // CHECK-DEFINE-WRONG-GUID: call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 [[U3]], i8* align 4 bitcast ({ i32, i16, i16, [8 x i8] }* @_GUID_12345678_1234_1234_1234_1234567890ab to i8*), i32 4, i1 false) - GUID s1_3 = __uuidof(s1); + GUID s1_3 = (side_effect(), __uuidof(s1)); } #endif @@ -121,3 +131,9 @@ // CHECK: store %struct._GUID* bitcast ({ i32, i16, i16, [8 x i8] }* @_GUID_00000000_0000_0000_0000_000000000000 to %struct._GUID*), %struct._GUID** %zeroiid, align 4 const GUID& zeroiid = __uuidof(0); } + +namespace DeclRefExprNamingGUID { + template const _GUID &f() { return g; } + struct __declspec(uuid("12345678-1234-1234-1234-123412341234")) S {}; + auto &r = f<__uuidof(S)>(); +} diff --git a/clang/test/Parser/MicrosoftExtensions.cpp b/clang/test/Parser/MicrosoftExtensions.cpp --- a/clang/test/Parser/MicrosoftExtensions.cpp +++ b/clang/test/Parser/MicrosoftExtensions.cpp @@ -33,7 +33,7 @@ void uuidof_test1() { - __uuidof(0); // expected-error {{you need to include before using the '__uuidof' operator}} + __uuidof(0); } typedef struct _GUID @@ -137,9 +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}} -// expected-note@-1 {{read of object '__uuidof(struct_with_uuid)' whose value is not known}} -// expected-note@-2 {{temporary created here}} +COM_CLASS_TEMPLATE bad_template_arg; // expected-error {{non-type template argument for template parameter of pointer type 'const GUID *' (aka 'const _GUID *') must have its address taken}} namespace PR16911 { struct __declspec(uuid("{12345678-1234-1234-1234-1234567890aB}")) uuid; diff --git a/clang/test/SemaCXX/ms-uuid.cpp b/clang/test/SemaCXX/ms-uuid.cpp --- a/clang/test/SemaCXX/ms-uuid.cpp +++ b/clang/test/SemaCXX/ms-uuid.cpp @@ -2,10 +2,10 @@ // RUN: %clang_cc1 -fsyntax-only -std=c++17 -verify -fms-extensions %s -Wno-deprecated-declarations typedef struct _GUID { - unsigned long Data1; - unsigned short Data2; - unsigned short Data3; - unsigned char Data4[8]; + __UINT32_TYPE__ Data1; + __UINT16_TYPE__ Data2; + __UINT16_TYPE__ Data3; + __UINT8_TYPE__ Data4[8]; } GUID; namespace { @@ -111,4 +111,24 @@ // declaration has a uuid attribute struct X{}; -struct __declspec(uuid("00000000-0000-0000-0000-000000000000")) X; \ No newline at end of file +struct __declspec(uuid("00000000-0000-0000-0000-000000000000")) X; + +namespace ConstantEvaluation { + class __declspec(uuid("1babb1ed-feed-c01d-1ced-decafc0ffee5")) Request; + constexpr GUID a = __uuidof(Request); + static_assert(a.Data1 == 0x1babb1ed, ""); + static_assert(__uuidof(Request).Data1 == 0x1babb1ed, ""); + static_assert(a.Data2 == 0xfeed, ""); + static_assert(__uuidof(Request).Data2 == 0xfeed, ""); + static_assert(a.Data3 == 0xc01d, ""); + static_assert(__uuidof(Request).Data3 == 0xc01d, ""); + static_assert(a.Data4[0] == 0x1c, ""); + static_assert(__uuidof(Request).Data4[0] == 0x1c, ""); + static_assert(a.Data4[1] == 0xed, ""); + static_assert(__uuidof(Request).Data4[1] == 0xed, ""); + static_assert(a.Data4[2] == 0xde, ""); + static_assert(__uuidof(Request).Data4[2] == 0xde, ""); + static_assert(a.Data4[7] == 0xe5, ""); + static_assert(__uuidof(Request).Data4[7] == 0xe5, ""); + constexpr int k = __uuidof(Request).Data4[8]; // expected-error {{constant expression}} expected-note {{past-the-end}} +} diff --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp --- a/clang/tools/libclang/CIndex.cpp +++ b/clang/tools/libclang/CIndex.cpp @@ -6322,6 +6322,7 @@ case Decl::Field: case Decl::Binding: case Decl::MSProperty: + case Decl::MSGuid: case Decl::IndirectField: case Decl::ObjCIvar: case Decl::ObjCAtDefsField: