class MaterializeTemporaryExpr;
class MemberSpecializationInfo;
class Module;
+struct MSGuidDeclParts;
class ObjCCategoryDecl;
class ObjCCategoryImplDecl;
class ObjCContainerDecl;
/// Mapping from __block VarDecls to BlockVarCopyInit.
llvm::DenseMap<const VarDecl *, BlockVarCopyInit> BlockVarCopyInits;
+ /// Mapping from GUIDs to the corresponding MSGuidDecl.
+ mutable llvm::FoldingSet<MSGuidDecl> MSGuidDecls;
+
/// Used to cleanups APValues stored in the AST.
mutable llvm::SmallVector<APValue *, 0> APValueCleanups;
// 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);
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;
/// 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;
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<MSGuidDecl>,
+ 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,
private:
llvm::PointerUnion<Stmt *, TypeSourceInfo *> 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));
}
return static_cast<Expr*>(Operand.get<Stmt *>());
}
- 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(); }
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,
DEF_TRAVERSE_DECL(MSPropertyDecl, { TRY_TO(TraverseDeclaratorHelper(D)); })
+DEF_TRAVERSE_DECL(MSGuidDecl, {});
+
DEF_TRAVERSE_DECL(FieldDecl, {
TRY_TO(TraverseDeclaratorHelper(D));
if (D->isBitField())
/// 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
def Uuid : InheritableAttr {
let Spellings = [Declspec<"uuid">, Microsoft<"uuid">];
- let Args = [StringArgument<"Guid">];
+ let Args = [StringArgument<"Guid">,
+ DeclArgument<MSGuid, "GuidDecl", 0, /*fake=*/1>];
let Subjects = SubjectList<[Record, Enum]>;
// FIXME: Allow expressing logical AND for LangOpts. Our condition should be:
// CPlusPlus && (MicrosoftExt || Borland)
def Binding : DeclNode<Value>;
def OMPDeclareReduction : DeclNode<Value>, DeclContext;
def OMPDeclareMapper : DeclNode<Value>, DeclContext;
+ def MSGuid : DeclNode<Value>;
def Declarator : DeclNode<Value, "declarators", 1>;
def Field : DeclNode<Declarator, "non-static data members">;
def ObjCIvar : DeclNode<Field>;
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">;
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,
/// 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.
/// A MSPropertyDecl record.
DECL_MS_PROPERTY,
+ /// A MSGuidDecl record.
+ DECL_MS_GUID,
+
/// A VarDecl record.
DECL_VAR,
// 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 {
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())
if (!TD->getAnonDeclWithTypedefName(/*AnyRedecl*/true))
return LinkageInfo::none();
+ } else if (isa<MSGuidDecl>(D)) {
+ // A GUID behaves like an inline variable with external linkage. Fall
+ // through.
+
// Everything not covered here has no linkage.
} else {
return LinkageInfo::none();
case TranslationUnit:
case ExternCContext:
case Decomposition:
+ case MSGuid:
case UsingDirective:
case BuiltinTemplate:
#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 <algorithm>
#include <cassert>
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<bool(QualType)>;
+
+ 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<MatcherRef> 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<CXXRecordDecl>(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:
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:
return Cl::CL_PRValue;
}
- case Expr::CXXUuidofExprClass:
- return Cl::CL_LValue;
-
case Expr::PackExpansionExprClass:
return ClassifyInternal(Ctx, cast<PackExpansionExpr>(E)->getPattern());
islvalue = isa<VarDecl>(D) || isa<FieldDecl>(D) ||
isa<IndirectFieldDecl>(D) ||
isa<BindingDecl>(D) ||
+ isa<MSGuidDecl>(D) ||
(Ctx.getLangOpts().CPlusPlus &&
(isa<FunctionDecl>(D) || isa<MSPropertyDecl>(D) ||
isa<FunctionTemplateDecl>(D)));
if (const VarDecl *VD = dyn_cast<VarDecl>(D))
return VD->hasGlobalStorage();
// ... the address of a function,
- return isa<FunctionDecl>(D);
+ // ... the address of a GUID [MS extension],
+ return isa<FunctionDecl>(D) || isa<MSGuidDecl>(D);
}
if (B.is<TypeInfoLValue>() || B.is<DynamicAllocLValue>())
case Expr::PredefinedExprClass:
case Expr::ObjCStringLiteralClass:
case Expr::ObjCEncodeExprClass:
- case Expr::CXXUuidofExprClass:
return true;
case Expr::ObjCBoxedExprClass:
return cast<ObjCBoxedExpr>(E)->isExpressibleAsConstantInitializer();
(void)CE;
BaseVal = Info.EvaluatingDeclValue;
} else if (const ValueDecl *D = LVal.Base.dyn_cast<const ValueDecl *>()) {
+ // Allow reading from a GUID declaration.
+ if (auto *GD = dyn_cast<MSGuidDecl>(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,
return VisitVarDecl(E, VD);
if (const BindingDecl *BD = dyn_cast<BindingDecl>(E->getDecl()))
return Visit(BD->getBinding());
+ if (const MSGuidDecl *GD = dyn_cast<MSGuidDecl>(E->getDecl()))
+ return Success(GD);
return Error(E);
}
}
bool LValueExprEvaluator::VisitCXXUuidofExpr(const CXXUuidofExpr *E) {
- return Success(E);
+ return Success(E->getGuidDecl());
}
bool LValueExprEvaluator::VisitMemberExpr(const MemberExpr *E) {
else if (const IndirectFieldDecl *IFD =
dyn_cast<IndirectFieldDecl>(GD.getDecl()))
mangleName(IFD->getAnonField());
+ else if (const FieldDecl *FD = dyn_cast<FieldDecl>(GD.getDecl()))
+ mangleName(FD);
+ else if (const MSGuidDecl *GuidD = dyn_cast<MSGuidDecl>(GD.getDecl()))
+ mangleName(GuidD);
else
- mangleName(cast<FieldDecl>(GD.getDecl()));
+ llvm_unreachable("unexpected kind of global decl");
}
void CXXNameMangler::mangleFunctionEncoding(GlobalDecl GD) {
break;
}
+ if (auto *GD = dyn_cast<MSGuidDecl>(ND)) {
+ // We follow MSVC in mangling GUID declarations as if they were variables
+ // with a particular reserved name. Continue the pretense here.
+ SmallString<sizeof("_GUID_12345678_1234_1234_1234_1234567890ab")> 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
static bool isExternC(const NamedDecl *ND) {
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(ND))
return FD->isExternC();
- return cast<VarDecl>(ND)->isExternC();
+ if (const VarDecl *VD = dyn_cast<VarDecl>(ND))
+ return VD->isExternC();
+ return false;
}
static CCMangling getCallingConvMangling(const ASTContext &Context,
if (D->hasAttr<AsmLabelAttr>())
return true;
+ // Declarations that don't have identifier names always need to be mangled.
+ if (isa<MSGuidDecl>(D))
+ return true;
+
return shouldMangleCXXName(D);
}
return;
}
+ if (auto *GD = dyn_cast<MSGuidDecl>(D))
+ return mangleMSGuidDecl(GD, Out);
+
const ASTContext &ASTContext = getASTContext();
CCMangling CC = getCallingConvMangling(ASTContext, D);
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) {
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())
mangleFunctionEncoding(FD, Context.shouldMangleDeclName(FD));
else if (const VarDecl *VD = dyn_cast<VarDecl>(D))
mangleVariableEncoding(VD);
+ else if (isa<MSGuidDecl>(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!");
}
break;
}
+ if (const MSGuidDecl *GD = dyn_cast<MSGuidDecl>(ND)) {
+ // Mangle a GUID object as if it were a variable with the corresponding
+ // mangled name.
+ SmallString<sizeof("_GUID_12345678_1234_1234_1234_1234567890ab")> GUID;
+ llvm::raw_svector_ostream GUIDOS(GUID);
+ Context.mangleMSGuidDecl(GD, GUIDOS);
+ mangleSourceName(GUID);
+ break;
+ }
+
// We must have an anonymous struct.
const TagDecl *TD = cast<TagDecl>(ND);
if (const TypedefNameDecl *D = TD->getTypedefNameForAnonDecl()) {
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<UnaryOperator>(E)) {
- if (UO->getOpcode() == UO_AddrOf)
- UE = dyn_cast<CXXUuidofExpr>(UO->getSubExpr());
- } else
- UE = dyn_cast<CXXUuidofExpr>(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(
CharUnits chars =
CGM.getContext().toCharUnitsFromBits((int64_t)fieldOffset);
V = CGM.getCXXABI().EmitMemberDataPointer(MPT, chars);
+ } else if (const auto *GD = dyn_cast<MSGuidDecl>(D)) {
+ V = CGM.GetAddrOfMSGuidDecl(GD).getPointer();
}
assert(V && "Failed to find template parameter pointer");
V = V->stripPointerCasts();
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:
if (const auto *BD = dyn_cast<BindingDecl>(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<MSGuidDecl>(ND))
+ return MakeAddrLValue(CGM.GetAddrOfMSGuidDecl(GD), T,
+ AlignmentSource::Decl);
+
llvm_unreachable("Unhandled DeclRefExpr");
}
}
Address CodeGenFunction::EmitCXXUuidofExpr(const CXXUuidofExpr *E) {
- return Builder.CreateElementBitCast(CGM.GetAddrOfUuidDescriptor(E),
+ return Builder.CreateElementBitCast(CGM.GetAddrOfMSGuidDecl(E->getGuidDecl()),
ConvertType(E->getType()));
}
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);
}
}
+ if (auto *GD = dyn_cast<MSGuidDecl>(D))
+ return CGM.GetAddrOfMSGuidDecl(GD);
+
return nullptr;
}
}
ConstantLValue
-ConstantLValueEmitter::VisitCXXUuidofExpr(const CXXUuidofExpr *E) {
- return CGM.GetAddrOfUuidDescriptor(E);
-}
-
-ConstantLValue
ConstantLValueEmitter::VisitMaterializeTemporaryExpr(
const MaterializeTemporaryExpr *E) {
assert(E->getStorageDuration() == SD_Static);
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);
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<char *>(Parts.Part4And5), 8), 8,
+ Int8Ty)};
+ Init = llvm::ConstantStruct::getAnon(Fields);
+ }
auto *GV = new llvm::GlobalVariable(
getModule(), Init->getType(),
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) {
}
}
-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.
/// 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,
/// .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);
AMK == Sema::AMK_ProtocolImplementation))
NewAttr = nullptr;
else if (const auto *UA = dyn_cast<UuidAttr>(Attr))
- NewAttr = S.mergeUuidAttr(D, *UA, UA->getGuid());
+ NewAttr = S.mergeUuidAttr(D, *UA, UA->getGuid(), UA->getGuidDecl());
else if (const auto *SLHA = dyn_cast<SpeculativeLoadHardeningAttr>(Attr))
NewAttr = S.mergeSpeculativeLoadHardeningAttr(D, *SLHA);
else if (const auto *SLHA = dyn_cast<NoSpeculativeLoadHardeningAttr>(Attr))
//===----------------------------------------------------------------------===//
UuidAttr *Sema::mergeUuidAttr(Decl *D, const AttributeCommonInfo &CI,
- StringRef Uuid) {
+ StringRef UuidAsWritten, MSGuidDecl *GuidDecl) {
if (const auto *UA = D->getAttr<UuidAttr>()) {
- if (UA->getGuid().equals_lower(Uuid))
+ if (declaresSameEntity(UA->getGuidDecl(), GuidDecl))
return nullptr;
if (!UA->getGuid().empty()) {
Diag(UA->getLocation(), diag::err_mismatched_uuid);
}
}
- 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) {
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();
}
}
+ // 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
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);
}
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;
/// - *(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:
// 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<ImplicitCastExpr>(E)->getSubExpr());
+ case Stmt::CXXUuidofExprClass:
+ return cast<CXXUuidofExpr>(E)->getGuidDecl();
default:
return nullptr;
}
}
}
} else if (!isa<FunctionDecl>(dcl) && !isa<NonTypeTemplateParmDecl>(dcl) &&
- !isa<BindingDecl>(dcl))
+ !isa<BindingDecl>(dcl) && !isa<MSGuidDecl>(dcl))
llvm_unreachable("Unknown/unexpected decl type");
}
}
/// 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<const UuidAttr *, 1> UuidAttrs;
getUuidAttrOfType(*this, Operand->getType(), UuidAttrs);
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<const UuidAttr *, 1> UuidAttrs;
getUuidAttrOfType(*this, E->getType(), UuidAttrs);
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<RecordDecl>();
- 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.
Arg = subst->getReplacement()->IgnoreImpCasts();
}
- DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Arg);
- ValueDecl *Entity = DRE ? DRE->getDecl() : nullptr;
+ ValueDecl *Entity = nullptr;
+ if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Arg))
+ Entity = DRE->getDecl();
+ else if (CXXUuidofExpr *CUE = dyn_cast<CXXUuidofExpr>(Arg))
+ Entity = CUE->getGuidDecl();
// If our parameter has pointer type, check for a null template value.
if (ParamType->isPointerType() || ParamType->isNullPtrType()) {
return false;
}
- if (isa<CXXUuidofExpr>(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);
FunctionDecl *Func = dyn_cast<FunctionDecl>(Entity);
VarDecl *Var = dyn_cast<VarDecl>(Entity);
+ MSGuidDecl *Guid = dyn_cast<MSGuidDecl>(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;
}
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)
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);
}
}
APValue::LValueBase Base = Value.getLValueBase();
auto *VD = const_cast<ValueDecl *>(Base.dyn_cast<const ValueDecl *>());
if (Base && (!VD || isa<LifetimeExtendedTemporaryDecl>(VD))) {
- auto *E = Base.dyn_cast<const Expr *>();
- if (E && isa<CXXUuidofExpr>(E)) {
- Converted = TemplateArgument(ArgResult.get()->IgnoreImpCasts());
- break;
- }
Diag(Arg->getBeginLoc(), diag::err_template_arg_not_decl_ref)
<< Arg->getSourceRange();
return ExprError();
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(),
// 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,
///
/// 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.
case Decl::IndirectField:
case Decl::Field:
case Decl::MSProperty:
+ case Decl::MSGuid:
case Decl::ObjCIvar:
case Decl::ObjCAtDefsField:
case Decl::NonTypeTemplateParm:
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();
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); }
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);
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;
void ASTStmtReader::VisitCXXUuidofExpr(CXXUuidofExpr *E) {
VisitExpr(E);
E->setSourceRange(readSourceRange());
- std::string UuidStr = readString();
- E->setUuidStr(StringRef(UuidStr).copy(Record.getContext()));
+ E->Guid = readDeclAs<MSGuidDecl>();
if (E->isTypeOperand())
E->Operand = readTypeSourceInfo();
else
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);
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);
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());
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;
// 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<GUID{12345678-1234-1234-1234-1234567890ab}>"
// 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<GUID{12345678-1234-1234-1234-1234567890ab}>"
+// 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 <const _GUID *>
struct tmpl_guid {
};
// 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 <typename>
struct X {
int foo;
};
+struct __declspec(uuid("EAFA1952-66F8-438B-8FBA-AF1BBAE42191")) OtherStruct {};
+
template <class T> void test_uuidofType(void *arg[sizeof(__uuidof(T))] = 0) {}
template <class T> void test_uuidofExpr(void *arg[sizeof(__uuidof(typename T::member))] = 0) {}
struct HasMember { typedef TestStruct member; };
+template<const GUID&> struct UUIDTestTwo { UUIDTestTwo(); };
+
int main(int argc, const char * argv[])
{
-
UUIDTest<TestStruct> 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<TestStruct>();
test_uuidofExpr<HasMember>();
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
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.
// 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
// 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
// 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 &g> const _GUID &f() { return g; }
+ struct __declspec(uuid("12345678-1234-1234-1234-123412341234")) S {};
+ auto &r = f<__uuidof(S)>();
+}
void uuidof_test1()
{
- __uuidof(0); // expected-error {{you need to include <guiddef.h> before using the '__uuidof' operator}}
+ __uuidof(0);
}
typedef struct _GUID
COM_CLASS_TEMPLATE_REF<int, __uuidof(struct_with_uuid)> good_template_arg;
-COM_CLASS_TEMPLATE<int, __uuidof(struct_with_uuid)> 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<int, __uuidof(struct_with_uuid)> 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;
// 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 {
// 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}}
+}
case Decl::Field:
case Decl::Binding:
case Decl::MSProperty:
+ case Decl::MSGuid:
case Decl::IndirectField:
case Decl::ObjCIvar:
case Decl::ObjCAtDefsField: