diff options
| author | Richard Smith <richard@metafoo.co.uk> | 2020-04-11 22:15:29 -0700 |
|---|---|---|
| committer | Richard Smith <richard@metafoo.co.uk> | 2020-04-15 12:20:42 -0700 |
| commit | bab6df86aefc5ea4aa3895da7cf46be37add676d (patch) | |
| tree | 1d6479a2abb346f45aa617914c943e30ada117bd /clang/lib/CodeGen/CodeGenModule.cpp | |
| parent | 8dfb9627b7be27e7b37ab4200c60f65f5af95256 (diff) | |
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
Diffstat (limited to 'clang/lib/CodeGen/CodeGenModule.cpp')
| -rw-r--r-- | clang/lib/CodeGen/CodeGenModule.cpp | 73 |
1 files changed, 36 insertions, 37 deletions
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index 73a3212bcd47..1243ce50ec8d 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -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. |
