Rework how UuidAttr, CXXUuidofExpr, and GUID template arguments and constants are represented.

Summary:
Previously, we treated CXXUuidofExpr as quite a special case: it was the
only kind of expression that could be a canonical template argument, it
could be a constant lvalue base object, and so on. In addition, we
represented the UUID value as a string, whose source form we did not
preserve faithfully, and that we partially parsed in multiple different
places.

With this patch, we create an MSGuidDecl object to represent the
implicit object of type 'struct _GUID' created by a UuidAttr. Each
UuidAttr holds a pointer to its 'struct _GUID' and its original
(as-written) UUID string. A non-value-dependent CXXUuidofExpr behaves
like a DeclRefExpr denoting that MSGuidDecl object. We cache an APValue
representation of the GUID on the MSGuidDecl and use it from constant
evaluation where needed.

This allows removing a lot of the special-case logic to handle these
expressions. Unfortunately, many parts of Clang assume there are only
a couple of interesting kinds of ValueDecl, so the total amount of
special-case logic is not really reduced very much.

This fixes a few bugs and issues:
 * PR38490: we now support reading from GUID objects returned from
   __uuidof during constant evaluation.
 * Our Itanium mangling for a non-instantiation-dependent template
   argument involving __uuidof no longer depends on which CXXUuidofExpr
   template argument we happened to see first.
 * We now predeclare ::_GUID, and permit use of __uuidof without
   any header inclusion, better matching MSVC's behavior. We do not
   predefine ::__s_GUID, though; that seems like a step too far.
 * Our IR representation for GUID constants now uses the correct IR type
   wherever possible. We will still fall back to using the
      {i32, i16, i16, [8 x i8]}
   layout if a definition of struct _GUID is not available. This is not
   ideal: in principle the two layouts could have different padding.

Reviewers: rnk, jdoerfert

Subscribers: arphaman, cfe-commits, aeubanks

Tags: #clang

Differential Revision: https://reviews.llvm.org/D78171
This commit is contained in:
Richard Smith 2020-04-11 22:15:29 -07:00
parent 8dfb9627b7
commit bab6df86ae
48 changed files with 599 additions and 278 deletions

View File

@ -104,6 +104,7 @@ class MangleNumberingContext;
class MaterializeTemporaryExpr;
class MemberSpecializationInfo;
class Module;
struct MSGuidDeclParts;
class ObjCCategoryDecl;
class ObjCCategoryImplDecl;
class ObjCContainerDecl;
@ -269,6 +270,9 @@ class ASTContext : public RefCountedBase<ASTContext> {
/// 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;
@ -984,7 +988,10 @@ public:
// 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 @@ public:
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 @@ public:
/// 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;

View File

@ -3963,6 +3963,81 @@ public:
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,

View File

@ -995,20 +995,20 @@ class CXXUuidofExpr : public Expr {
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));
}
@ -1036,8 +1036,7 @@ public:
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(); }

View File

@ -111,6 +111,7 @@ public:
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,

View File

@ -1993,6 +1993,8 @@ DEF_TRAVERSE_DECL(BindingDecl, {
DEF_TRAVERSE_DECL(MSPropertyDecl, { TRY_TO(TraverseDeclaratorHelper(D)); })
DEF_TRAVERSE_DECL(MSGuidDecl, {});
DEF_TRAVERSE_DECL(FieldDecl, {
TRY_TO(TraverseDeclaratorHelper(D));
if (D->isBitField())

View File

@ -82,8 +82,7 @@ public:
/// 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

View File

@ -2434,7 +2434,8 @@ def Used : InheritableAttr {
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)

View File

@ -40,6 +40,7 @@ def Named : DeclNode<Decl, "named declarations", 1>;
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>;

View File

@ -338,6 +338,8 @@ def note_constexpr_delete_base_nonvirt_dtor : Note<
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">;

View File

@ -2961,7 +2961,7 @@ public:
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,

View File

@ -1134,27 +1134,30 @@ namespace serialization {
/// 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 @@ namespace serialization {
/// A MSPropertyDecl record.
DECL_MS_PROPERTY,
/// A MSGuidDecl record.
DECL_MS_GUID,
/// A VarDecl record.
DECL_VAR,

View File

@ -1451,6 +1451,12 @@ void ASTContext::InitBuiltinTypes(const TargetInfo &Target,
// 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 @@ ASTContext::getPredefinedStringLiteralFromCache(StringRef Key) 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())

View File

@ -892,6 +892,10 @@ LinkageComputer::getLVForNamespaceScopeDecl(const NamedDecl *D,
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();

View File

@ -797,6 +797,7 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) {
case TranslationUnit:
case ExternCContext:
case Decomposition:
case MSGuid:
case UsingDirective:
case BuiltinTemplate:

View File

@ -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 <algorithm>
#include <cassert>
@ -3157,6 +3158,99 @@ MSPropertyDecl *MSPropertyDecl::CreateDeserialized(ASTContext &C,
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:

View File

@ -124,6 +124,7 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
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 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
return Cl::CL_PRValue;
}
case Expr::CXXUuidofExprClass:
return Cl::CL_LValue;
case Expr::PackExpansionExprClass:
return ClassifyInternal(Ctx, cast<PackExpansionExpr>(E)->getPattern());
@ -455,6 +453,7 @@ static Cl::Kinds ClassifyDecl(ASTContext &Ctx, const Decl *D) {
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)));

View File

@ -1895,7 +1895,8 @@ static bool IsGlobalLValue(APValue::LValueBase B) {
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>())
@ -1918,7 +1919,6 @@ static bool IsGlobalLValue(APValue::LValueBase B) {
case Expr::PredefinedExprClass:
case Expr::ObjCStringLiteralClass:
case Expr::ObjCEncodeExprClass:
case Expr::CXXUuidofExprClass:
return true;
case Expr::ObjCBoxedExprClass:
return cast<ObjCBoxedExpr>(E)->isExpressibleAsConstantInitializer();
@ -3615,6 +3615,22 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E,
(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,
@ -7540,6 +7556,8 @@ bool LValueExprEvaluator::VisitDeclRefExpr(const DeclRefExpr *E) {
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);
}
@ -7718,7 +7736,7 @@ bool LValueExprEvaluator::VisitCXXTypeidExpr(const CXXTypeidExpr *E) {
}
bool LValueExprEvaluator::VisitCXXUuidofExpr(const CXXUuidofExpr *E) {
return Success(E);
return Success(E->getGuidDecl());
}
bool LValueExprEvaluator::VisitMemberExpr(const MemberExpr *E) {

View File

@ -652,8 +652,12 @@ void CXXNameMangler::mangle(GlobalDecl GD) {
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) {
@ -1287,6 +1291,16 @@ void CXXNameMangler::mangleUnqualifiedName(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

View File

@ -57,7 +57,9 @@ enum CCMangling {
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,
@ -122,6 +124,10 @@ bool MangleContext::shouldMangleDeclName(const NamedDecl *D) {
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);
}
@ -153,6 +159,9 @@ void MangleContext::mangleName(GlobalDecl GD, raw_ostream &Out) {
return;
}
if (auto *GD = dyn_cast<MSGuidDecl>(D))
return mangleMSGuidDecl(GD, Out);
const ASTContext &ASTContext = getASTContext();
CCMangling CC = getCallingConvMangling(ASTContext, D);
@ -209,6 +218,20 @@ void MangleContext::mangleName(GlobalDecl GD, raw_ostream &Out) {
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) {

View File

@ -462,7 +462,7 @@ bool MicrosoftMangleContextImpl::shouldMangleCXXName(const NamedDecl *D) {
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 @@ void MicrosoftCXXNameMangler::mangle(const NamedDecl *D, StringRef Prefix) {
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!");
}
@ -893,6 +897,16 @@ void MicrosoftCXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND,
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()) {
@ -1364,45 +1378,6 @@ void MicrosoftCXXNameMangler::mangleExpression(const Expr *E) {
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(

View File

@ -1868,6 +1868,8 @@ CGDebugInfo::CollectTemplateParams(const TemplateParameterList *TPList,
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();

View File

@ -108,6 +108,7 @@ void CodeGenFunction::EmitDecl(const Decl &D) {
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:

View File

@ -2706,6 +2706,12 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) {
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");
}
@ -4812,7 +4818,7 @@ CodeGenFunction::EmitCXXTypeidLValue(const CXXTypeidExpr *E) {
}
Address CodeGenFunction::EmitCXXUuidofExpr(const CXXUuidofExpr *E) {
return Builder.CreateElementBitCast(CGM.GetAddrOfUuidDescriptor(E),
return Builder.CreateElementBitCast(CGM.GetAddrOfMSGuidDecl(E->getGuidDecl()),
ConvertType(E->getType()));
}

View File

@ -1766,7 +1766,6 @@ private:
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 @@ ConstantLValueEmitter::tryEmitBase(const APValue::LValueBase &base) {
}
}
if (auto *GD = dyn_cast<MSGuidDecl>(D))
return CGM.GetAddrOfMSGuidDecl(GD);
return nullptr;
}
@ -1990,11 +1992,6 @@ ConstantLValueEmitter::VisitCXXTypeidExpr(const CXXTypeidExpr *E) {
return CGM.GetAddrOfRTTIDescriptor(T);
}
ConstantLValue
ConstantLValueEmitter::VisitCXXUuidofExpr(const CXXUuidofExpr *E) {
return CGM.GetAddrOfUuidDescriptor(E);
}
ConstantLValue
ConstantLValueEmitter::VisitMaterializeTemporaryExpr(
const MaterializeTemporaryExpr *E) {

View File

@ -2435,13 +2435,8 @@ bool CodeGenModule::MayBeEmittedEagerly(const ValueDecl *Global) {
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 @@ ConstantAddress CodeGenModule::GetAddrOfUuidDescriptor(
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(),
@ -2459,7 +2476,16 @@ ConstantAddress CodeGenModule::GetAddrOfUuidDescriptor(
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 @@ void CodeGenModule::EmitCoverageFile() {
}
}
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.

View File

@ -856,8 +856,8 @@ public:
/// 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 @@ private:
/// .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);

View File

@ -2592,7 +2592,7 @@ static bool mergeDeclAttribute(Sema &S, NamedDecl *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))

View File

@ -5471,9 +5471,9 @@ static void handleObjCPreciseLifetimeAttr(Sema &S, Decl *D,
//===----------------------------------------------------------------------===//
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);
@ -5482,7 +5482,7 @@ UuidAttr *Sema::mergeUuidAttr(Decl *D, const AttributeCommonInfo &CI,
}
}
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 @@ 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();
@ -5520,6 +5521,16 @@ static void handleUuidAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
}
}
// 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 @@ static void handleUuidAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
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);
}

View File

@ -3274,6 +3274,9 @@ ExprResult Sema::BuildDeclarationNameExpr(
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 @@ static QualType CheckIncrementDecrementOperand(Sema &S, Expr *Op,
/// - *(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 @@ static ValueDecl *getPrimaryDecl(Expr *E) {
// 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;
}
@ -13076,7 +13084,7 @@ QualType Sema::CheckAddressOfOperand(ExprResult &OrigOp, SourceLocation OpLoc) {
}
}
} else if (!isa<FunctionDecl>(dcl) && !isa<NonTypeTemplateParmDecl>(dcl) &&
!isa<BindingDecl>(dcl))
!isa<BindingDecl>(dcl) && !isa<MSGuidDecl>(dcl))
llvm_unreachable("Unknown/unexpected decl type");
}

View File

@ -704,11 +704,11 @@ getUuidAttrOfType(Sema &SemaRef, QualType QT,
}
/// 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);
@ -716,22 +716,21 @@ ExprResult Sema::BuildCXXUuidof(QualType TypeInfoType,
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);
@ -739,29 +738,20 @@ ExprResult Sema::BuildCXXUuidof(QualType TypeInfoType,
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.

View File

@ -6331,8 +6331,11 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S,
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()) {
@ -6359,16 +6362,7 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S,
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);
@ -6395,13 +6389,14 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S,
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;
}
@ -6422,30 +6417,7 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S,
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 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S,
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 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
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();

View File

@ -698,6 +698,10 @@ TemplateDeclInstantiator::VisitExternCContextDecl(ExternCContextDecl *D) {
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(),

View File

@ -8305,14 +8305,14 @@ bool Sema::RequireCompleteTypeImpl(SourceLocation Loc, QualType T,
// 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,

View File

@ -2832,24 +2832,19 @@ public:
///
/// 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.

View File

@ -371,6 +371,7 @@ bool serialization::isRedeclarableDeclKind(unsigned Kind) {
case Decl::IndirectField:
case Decl::Field:
case Decl::MSProperty:
case Decl::MSGuid:
case Decl::ObjCIvar:
case Decl::ObjCAtDefsField:
case Decl::NonTypeTemplateParm:

View File

@ -7287,6 +7287,9 @@ static Decl *getPredefinedDecl(ASTContext &Context, PredefinedDeclIDs ID) {
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();

View File

@ -365,6 +365,7 @@ namespace clang {
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 @@ void ASTDeclReader::VisitMSPropertyDecl(MSPropertyDecl *PD) {
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 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) {
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;

View File

@ -2156,8 +2156,7 @@ void ASTStmtReader::VisitMSPropertySubscriptExpr(MSPropertySubscriptExpr *E) {
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

View File

@ -4372,6 +4372,8 @@ ASTFileSignature ASTWriter::WriteASTCore(Sema &SemaRef, StringRef isysroot,
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);

View File

@ -95,6 +95,7 @@ namespace clang {
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 @@ void ASTDeclWriter::VisitMSPropertyDecl(MSPropertyDecl *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());

View File

@ -2070,7 +2070,7 @@ void ASTStmtWriter::VisitMSPropertySubscriptExpr(MSPropertySubscriptExpr *E) {
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;

View File

@ -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<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 {
};

View File

@ -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 <typename>
struct X {

View File

@ -22,27 +22,36 @@ struct __declspec(uuid("EAFA1952-66F8-438B-8FBA-AF1BBAE42191")) TestStruct
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

View File

@ -30,16 +30,22 @@ struct __declspec(uuid("{12345678-1234-1234-1234-1234567890ac}")) Curly;
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 @@ const GUID& zeroiid = __uuidof(0);
// 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 @@ void fun() {
// 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 @@ void gun() {
// 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)>();
}

View File

@ -33,7 +33,7 @@ public:
void uuidof_test1()
{
__uuidof(0); // expected-error {{you need to include <guiddef.h> before using the '__uuidof' operator}}
__uuidof(0);
}
typedef struct _GUID
@ -137,9 +137,7 @@ typedef COM_CLASS_TEMPLATE_REF<struct_with_uuid, __uuidof(struct_with_uuid)> COM
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;

View File

@ -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 @@ void F2() {
// declaration has a uuid attribute
struct X{};
struct __declspec(uuid("00000000-0000-0000-0000-000000000000")) X;
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}}
}

View File

@ -6322,6 +6322,7 @@ CXCursor clang_getCursorDefinition(CXCursor C) {
case Decl::Field:
case Decl::Binding:
case Decl::MSProperty:
case Decl::MSGuid:
case Decl::IndirectField:
case Decl::ObjCIvar:
case Decl::ObjCAtDefsField: