diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -2291,6 +2291,10 @@ const ObjCImplementationDecl *ID, const ObjCIvarDecl *Ivar) const; + /// Find the 'this' offset for the member path in a pointer-to-member + /// APValue. + CharUnits getMemberPointerPathAdjustment(const APValue &MP) const; + bool isNearlyEmpty(const CXXRecordDecl *RD) const; VTableContextBase *getVTableContext(); diff --git a/clang/lib/AST/APValue.cpp b/clang/lib/AST/APValue.cpp --- a/clang/lib/AST/APValue.cpp +++ b/clang/lib/AST/APValue.cpp @@ -11,10 +11,12 @@ //===----------------------------------------------------------------------===// #include "clang/AST/APValue.h" +#include "Linkage.h" #include "clang/AST/ASTContext.h" #include "clang/AST/CharUnits.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/Expr.h" +#include "clang/AST/ExprCXX.h" #include "clang/AST/Type.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" @@ -977,3 +979,100 @@ for (unsigned I = 0; I != Path.size(); ++I) InternalPath[I] = Path[I]->getCanonicalDecl(); } + +LinkageInfo LinkageComputer::getLVForValue(const APValue &V, + LVComputationKind computation) { + LinkageInfo LV = LinkageInfo::external(); + + auto MergeLV = [&](LinkageInfo MergeLV) { + LV.merge(MergeLV); + return LV.getLinkage() == InternalLinkage; + }; + auto Merge = [&](const APValue &V) { + return MergeLV(getLVForValue(V, computation)); + }; + + switch (V.getKind()) { + case APValue::None: + case APValue::Indeterminate: + case APValue::Int: + case APValue::Float: + case APValue::FixedPoint: + case APValue::ComplexInt: + case APValue::ComplexFloat: + case APValue::Vector: + break; + + case APValue::AddrLabelDiff: + // Even for an inline function, it's not reasonable to treat a difference + // between the addresses of labels as an external value. + return LinkageInfo::internal(); + + case APValue::Struct: { + for (unsigned I = 0, N = V.getStructNumBases(); I != N; ++I) + if (Merge(V.getStructBase(I))) + break; + for (unsigned I = 0, N = V.getStructNumFields(); I != N; ++I) + if (Merge(V.getStructField(I))) + break; + break; + } + + case APValue::Union: + if (const auto *FD = V.getUnionField()) + Merge(V.getUnionValue()); + break; + + case APValue::Array: { + for (unsigned I = 0, N = V.getArrayInitializedElts(); I != N; ++I) + if (Merge(V.getArrayInitializedElt(I))) + break; + if (V.hasArrayFiller()) + Merge(V.getArrayFiller()); + break; + } + + case APValue::LValue: { + if (!V.getLValueBase()) { + // Null or absolute address: this is external. + } else if (const auto *VD = + V.getLValueBase().dyn_cast()) { + if (VD && MergeLV(getLVForDecl(VD, computation))) + break; + } else if (const auto TI = V.getLValueBase().dyn_cast()) { + // FIXME: Claim that typeinfo(T) has the same linkage as T. This isn't + // correct across all ABIs, but for now it shouldn't matter as such + // values aren't permitted within template arguments. + if (MergeLV(getLVForType(*TI.getType(), computation))) + break; + } else if (const Expr *E = V.getLValueBase().dyn_cast()) { + // Almost all expression bases are internal. The exception is + // lifetime-extended temporaries. + // FIXME: These should be modeled as having the + // LifetimeExtendedTemporaryDecl itself as the base. + auto *MTE = dyn_cast(E); + if (!MTE || MTE->getStorageDuration() == SD_FullExpression) + return LinkageInfo::internal(); + if (MergeLV(getLVForDecl(MTE->getExtendingDecl(), computation))) + break; + } else { + assert(V.getLValueBase().is() && + "unexpected LValueBase kind"); + return LinkageInfo::internal(); + } + // The lvalue path doesn't matter: pointers to all subobjects always have + // the same visibility as pointers to the complete object. + break; + } + + case APValue::MemberPointer: + if (const NamedDecl *D = V.getMemberPointerDecl()) + MergeLV(getLVForDecl(D, computation)); + // Note that we could have a base-to-derived conversion here to a member of + // a derived class with less linkage/visibility. That's covered by the + // linkage and visibility of the value's type. + break; + } + + return LV; +} diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -2475,6 +2475,25 @@ return Offset; } +CharUnits ASTContext::getMemberPointerPathAdjustment(const APValue &MP) const { + const ValueDecl *MPD = MP.getMemberPointerDecl(); + CharUnits ThisAdjustment = CharUnits::Zero(); + ArrayRef Path = MP.getMemberPointerPath(); + bool DerivedMember = MP.isMemberPointerToDerivedMember(); + const CXXRecordDecl *RD = cast(MPD->getDeclContext()); + for (unsigned I = 0, N = Path.size(); I != N; ++I) { + const CXXRecordDecl *Base = RD; + const CXXRecordDecl *Derived = Path[I]; + if (DerivedMember) + std::swap(Base, Derived); + ThisAdjustment += getASTRecordLayout(Derived).getBaseClassOffset(Base); + RD = Path[I]; + } + if (DerivedMember) + ThisAdjustment = -ThisAdjustment; + return ThisAdjustment; +} + /// DeepCollectObjCIvars - /// This routine first collects all declared, but not synthesized, ivars in /// super class and then collects all ivars, including those synthesized for diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp --- a/clang/lib/AST/Decl.cpp +++ b/clang/lib/AST/Decl.cpp @@ -1395,6 +1395,15 @@ break; } + + case Decl::TemplateParamObject: { + // The template parameter object can be referenced from anywhere its type + // and value can be referenced. + auto *TPO = cast(D); + LinkageInfo LV = getLVForType(*TPO->getType(), computation); + LV.merge(getLVForValue(TPO->getValue(), computation)); + return LV; + } } // Handle linkage for namespace-scope names. diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/lib/AST/ItaniumMangle.cpp @@ -555,6 +555,7 @@ unsigned NumTemplateArgs); void mangleTemplateArgs(const TemplateArgumentList &AL); void mangleTemplateArg(TemplateArgument A); + void mangleValueInTemplateArg(QualType T, const APValue &V); void mangleTemplateParameter(unsigned Depth, unsigned Index); @@ -649,23 +650,13 @@ Out << "_Z"; if (isa(GD.getDecl())) mangleFunctionEncoding(GD); - else if (const VarDecl *VD = dyn_cast(GD.getDecl())) - mangleName(VD); + else if (isa(GD.getDecl())) + mangleName(GD); else if (const IndirectFieldDecl *IFD = dyn_cast(GD.getDecl())) mangleName(IFD->getAnonField()); - else if (const FieldDecl *FD = dyn_cast(GD.getDecl())) - mangleName(FD); - else if (const MSGuidDecl *GuidD = dyn_cast(GD.getDecl())) - mangleName(GuidD); - else if (const BindingDecl *BD = dyn_cast(GD.getDecl())) - mangleName(BD); - else if (isa(GD.getDecl())) { - DiagnosticsEngine &Diags = Context.getDiags(); - unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, - "cannot mangle template parameter objects yet"); - Diags.Report(SourceLocation(), DiagID); - } else + else llvm_unreachable("unexpected kind of global decl"); } @@ -1310,6 +1301,15 @@ break; } + if (auto *TPO = dyn_cast(ND)) { + // Proposed in https://github.com/itanium-cxx-abi/cxx-abi/issues/63. + Out << "TAX"; + mangleValueInTemplateArg(TPO->getType().getUnqualifiedType(), + TPO->getValue()); + Out << "E"; + break; + } + if (II) { // Match GCC's naming convention for internal linkage symbols, for // symbols that are not actually visible outside of this TU. GCC @@ -4870,10 +4870,21 @@ break; case TemplateArgument::Declaration: { // ::= L E # external name + ValueDecl *D = A.getAsDecl(); + + // Template parameter objects are modeled by reproducing a source form + // produced as if by aggregate initialization. + if (auto *TPO = dyn_cast(D)) { + Out << 'X'; + mangleValueInTemplateArg(TPO->getType().getUnqualifiedType(), + TPO->getValue()); + Out << 'E'; + break; + } + // Clang produces AST's where pointer-to-member-function expressions // and pointer-to-function expressions are represented as a declaration not // an expression. We compensate for it here to produce the correct mangling. - ValueDecl *D = A.getAsDecl(); bool compensateMangling = !A.getParamTypeForDecl()->isReferenceType(); if (compensateMangling) { Out << 'X'; @@ -4908,6 +4919,404 @@ } } +/// Determine whether a given value is equivalent to zero-initialization for +/// the purpose of discarding a trailing portion of a 'tl' mangling. +static bool isZeroInitialized(QualType T, const APValue &V) { + // FIXME: mangleValueInTemplateArg has quadratic time complexity in + // pathological cases due to using this, but it's a little awkward + // to do this in linear time in general. + switch (V.getKind()) { + case APValue::None: + case APValue::Indeterminate: + case APValue::AddrLabelDiff: + return false; + + case APValue::Struct: { + const CXXRecordDecl *RD = T->getAsCXXRecordDecl(); + assert(RD && "unexpected type for record value"); + unsigned I = 0; + for (const CXXBaseSpecifier &BS : RD->bases()) { + if (!isZeroInitialized(BS.getType(), V.getStructBase(I))) + return false; + ++I; + } + I = 0; + for (const FieldDecl *FD : RD->fields()) { + if (!FD->isUnnamedBitfield() && + !isZeroInitialized(FD->getType(), V.getStructField(I))) + return false; + ++I; + } + return true; + } + + case APValue::Union: { + const CXXRecordDecl *RD = T->getAsCXXRecordDecl(); + assert(RD && "unexpected type for union value"); + // Zero-initialization zeroes the first non-unnamed-bitfield field, if any. + for (const FieldDecl *FD : RD->fields()) { + if (!FD->isUnnamedBitfield()) + return V.getUnionField() && declaresSameEntity(FD, V.getUnionField()) && + isZeroInitialized(FD->getType(), V.getUnionValue()); + } + // If there are no fields (other than unnamed bitfields), the value is + // necessarily zero-initialized. + return true; + } + + case APValue::Array: { + QualType ElemT(T->getArrayElementTypeNoTypeQual(), 0); + for (unsigned I = 0, N = V.getArrayInitializedElts(); I != N; ++I) + if (!isZeroInitialized(ElemT, V.getArrayInitializedElt(I))) + return false; + return !V.hasArrayFiller() || isZeroInitialized(ElemT, V.getArrayFiller()); + } + + case APValue::Vector: { + const VectorType *VT = T->castAs(); + for (unsigned I = 0, N = V.getVectorLength(); I != N; ++I) + if (!isZeroInitialized(VT->getElementType(), V.getVectorElt(I))) + return false; + return true; + } + + case APValue::Int: + return !V.getInt(); + + case APValue::Float: + return V.getFloat().isPosZero(); + + case APValue::FixedPoint: + return !V.getFixedPoint().getValue(); + + case APValue::ComplexFloat: + return V.getComplexFloatReal().isPosZero() && + V.getComplexFloatImag().isPosZero(); + + case APValue::ComplexInt: + return !V.getComplexIntReal() && !V.getComplexIntImag(); + + case APValue::LValue: + return V.isNullPointer(); + + case APValue::MemberPointer: + return !V.getMemberPointerDecl(); + } +} + +void CXXNameMangler::mangleValueInTemplateArg(QualType T, const APValue &V) { + // Proposed in https://github.com/itanium-cxx-abi/cxx-abi/issues/63. + switch (V.getKind()) { + case APValue::None: + case APValue::Indeterminate: + Out << 'L'; + mangleType(T); + Out << 'E'; + return; + + case APValue::AddrLabelDiff: + llvm_unreachable("unexpected value kind in template argument"); + + case APValue::Struct: { + const CXXRecordDecl *RD = T->getAsCXXRecordDecl(); + assert(RD && "unexpected type for record value"); + + // Drop trailing zero-initialized elements. + llvm::SmallVector Fields(RD->field_begin(), + RD->field_end()); + while ( + !Fields.empty() && + (Fields.back()->isUnnamedBitfield() || + isZeroInitialized(Fields.back()->getType(), + V.getStructField(Fields.back()->getFieldIndex())))) { + Fields.pop_back(); + } + llvm::ArrayRef Bases(RD->bases_begin(), RD->bases_end()); + if (Fields.empty()) { + while (!Bases.empty() && + isZeroInitialized(Bases.back().getType(), + V.getStructBase(Bases.size() - 1))) + Bases = Bases.drop_back(); + } + + // ::= tl * E + Out << "tl"; + mangleType(T); + for (unsigned I = 0, N = Bases.size(); I != N; ++I) + mangleValueInTemplateArg(Bases[I].getType(), V.getStructBase(I)); + for (unsigned I = 0, N = Fields.size(); I != N; ++I) { + if (Fields[I]->isUnnamedBitfield()) + continue; + mangleValueInTemplateArg(Fields[I]->getType(), + V.getStructField(Fields[I]->getFieldIndex())); + } + Out << 'E'; + return; + } + + case APValue::Union: { + const CXXRecordDecl *RD = T->getAsCXXRecordDecl(); + assert(RD && "unexpected type for union value"); + const FieldDecl *FD = V.getUnionField(); + + if (!FD) { + Out << 'L'; + mangleType(T); + Out << 'E'; + return; + } + + // ::= di + Out << "tl"; + mangleType(T); + if (!isZeroInitialized(T, V)) { + Out << "di"; + mangleSourceName(FD->getIdentifier()); + mangleValueInTemplateArg(FD->getType(), V.getUnionValue()); + } + Out << 'E'; + return; + } + + case APValue::Array: { + QualType ElemT(T->getArrayElementTypeNoTypeQual(), 0); + + Out << "tl"; + mangleType(T); + + // Drop trailing zero-initialized elements. + unsigned N = V.getArraySize(); + if (!V.hasArrayFiller() || isZeroInitialized(ElemT, V.getArrayFiller())) { + N = V.getArrayInitializedElts(); + while (N && isZeroInitialized(ElemT, V.getArrayInitializedElt(N - 1))) + --N; + } + + for (unsigned I = 0; I != N; ++I) { + const APValue &Elem = I < V.getArrayInitializedElts() + ? V.getArrayInitializedElt(I) + : V.getArrayFiller(); + mangleValueInTemplateArg(ElemT, Elem); + } + Out << 'E'; + return; + } + + case APValue::Vector: { + const VectorType *VT = T->castAs(); + + Out << "tl"; + mangleType(T); + unsigned N = V.getVectorLength(); + while (N && isZeroInitialized(VT->getElementType(), V.getVectorElt(N - 1))) + --N; + for (unsigned I = 0; I != N; ++I) + mangleValueInTemplateArg(VT->getElementType(), V.getVectorElt(I)); + Out << 'E'; + return; + } + + case APValue::Int: + mangleIntegerLiteral(T, V.getInt()); + return; + + case APValue::Float: + Out << 'L'; + mangleType(T); + mangleFloat(V.getFloat()); + Out << 'E'; + return; + + case APValue::FixedPoint: + llvm_unreachable("Fixed point types are disabled for c++"); + return; + + case APValue::ComplexFloat: { + const ComplexType *CT = T->castAs(); + Out << "tl"; + mangleType(T); + if (V.getComplexFloatReal().isNonZero() || + V.getComplexFloatImag().isNonZero()) { + Out << 'L'; + mangleType(CT->getElementType()); + mangleFloat(V.getComplexFloatReal()); + Out << 'E'; + } + if (V.getComplexFloatImag().isNonZero()) { + Out << 'L'; + mangleType(CT->getElementType()); + mangleFloat(V.getComplexFloatImag()); + Out << 'E'; + } + Out << 'E'; + return; + } + + case APValue::ComplexInt: { + const ComplexType *CT = T->castAs(); + Out << "tl"; + mangleType(T); + if (V.getComplexIntReal().getBoolValue() || + V.getComplexIntImag().getBoolValue()) + mangleIntegerLiteral(CT->getElementType(), V.getComplexIntReal()); + if (V.getComplexIntImag().getBoolValue()) + mangleIntegerLiteral(CT->getElementType(), V.getComplexIntImag()); + Out << 'E'; + return; + } + + case APValue::LValue: { + // Proposed in https://github.com/itanium-cxx-abi/cxx-abi/issues/47. + assert((T->isPointerType() || T->isReferenceType()) && + "unexpected type for LValue template arg"); + + if (V.isNullPointer()) { + Out << "L"; + mangleType(T); + Out << "0E"; + return; + } + + APValue::LValueBase B = V.getLValueBase(); + if (!B) { + // Non-standard mangling for integer cast to a pointer; this can only + // occur as an extension. + CharUnits Offset = V.getLValueOffset(); + if (Offset.isZero()) { + // This is reinterpret_cast(0), not a null pointer. Mangle this as + // a cast, because L 0 E means something else. + Out << "rc"; + mangleType(T); + Out << "Li0E"; + } else { + Out << "L"; + mangleType(T); + Out << Offset.getQuantity() << 'E'; + } + return; + } + + enum { Base, Offset, Path } Kind; + if (!V.hasLValuePath()) { + // Mangle as (T*)((char*)&base + N). + if (T->isReferenceType()) { + Out << "decvP"; + mangleType(T->getPointeeType()); + } else { + Out << "cv"; + mangleType(T); + } + Out << "plcvPcad"; + Kind = Offset; + } else { + if (T->isPointerType()) + Out << "ad"; + if (!V.getLValuePath().empty() || V.isLValueOnePastTheEnd()) { + Out << "so"; + mangleType(T->getPointeeType()); + Kind = Path; + } else { + Kind = Base; + } + } + + QualType TypeSoFar; + if (auto *VD = B.dyn_cast()) { + Out << 'L'; + mangle(VD); + Out << 'E'; + TypeSoFar = VD->getType(); + } else if (auto *E = B.dyn_cast()) { + mangleExpression(E); + TypeSoFar = E->getType(); + } else if (auto TI = B.dyn_cast()) { + Out << "ti"; + mangleType(QualType(TI.getType(), 0)); + TypeSoFar = B.getTypeInfoType(); + } else { + // We should never see dynamic allocations here. + llvm_unreachable("unexpected lvalue base kind in template argument"); + } + + switch (Kind) { + case Base: + break; + + case Offset: + Out << 'L'; + mangleType(Context.getASTContext().getPointerDiffType()); + mangleNumber(V.getLValueOffset().getQuantity()); + Out << 'E'; + break; + + case Path: + // ::= so [] + // * [p] E + if (!V.getLValueOffset().isZero()) + mangleNumber(V.getLValueOffset().getQuantity()); + + // We model a past-the-end array pointer as array indexing with index N, + // not with the "past the end" flag. Compensate for that. + bool OnePastTheEnd = V.isLValueOnePastTheEnd(); + + for (APValue::LValuePathEntry E : V.getLValuePath()) { + if (auto *AT = TypeSoFar->getAsArrayTypeUnsafe()) { + if (auto *CAT = dyn_cast(AT)) + OnePastTheEnd |= CAT->getSize() == E.getAsArrayIndex(); + TypeSoFar = AT->getElementType(); + } else { + const Decl *D = E.getAsBaseOrMember().getPointer(); + if (auto *FD = dyn_cast(D)) { + // ::= _ + if (FD->getParent()->isUnion()) { + Out << '_'; + if (FD->getFieldIndex()) + Out << (FD->getFieldIndex() - 1); + } + TypeSoFar = FD->getType(); + } else { + TypeSoFar = + Context.getASTContext().getRecordType(cast(D)); + } + } + } + + if (OnePastTheEnd) + Out << 'p'; + Out << 'E'; + break; + } + + return; + } + + case APValue::MemberPointer: + // Proposed in https://github.com/itanium-cxx-abi/cxx-abi/issues/47. + if (!V.getMemberPointerDecl()) { + Out << 'L'; + mangleType(T); + Out << "0E"; + return; + } + + if (!V.getMemberPointerPath().empty()) { + Out << "mc"; + mangleType(T); + } + Out << "adL"; + mangle(V.getMemberPointerDecl()); + Out << 'E'; + if (!V.getMemberPointerPath().empty()) { + CharUnits Offset = + Context.getASTContext().getMemberPointerPathAdjustment(V); + if (!Offset.isZero()) + mangleNumber(Offset.getQuantity()); + Out << 'E'; + } + return; + } +} + void CXXNameMangler::mangleTemplateParameter(unsigned Depth, unsigned Index) { // ::= T_ # first template parameter // ::= T _ @@ -5224,8 +5633,8 @@ void ItaniumMangleContextImpl::mangleCXXName(GlobalDecl GD, raw_ostream &Out) { const NamedDecl *D = cast(GD.getDecl()); - assert((isa(D) || isa(D)) && - "Invalid mangleName() call, argument is not a variable or function!"); + assert((isa(D)) && + "Invalid mangleName() call, argument is not a variable or function!"); PrettyStackTraceDecl CrashInfo(D, SourceLocation(), getASTContext().getSourceManager(), diff --git a/clang/lib/AST/Linkage.h b/clang/lib/AST/Linkage.h --- a/clang/lib/AST/Linkage.h +++ b/clang/lib/AST/Linkage.h @@ -140,6 +140,8 @@ LinkageInfo getLVForTemplateParameterList(const TemplateParameterList *Params, LVComputationKind computation); + LinkageInfo getLVForValue(const APValue &V, LVComputationKind computation); + public: LinkageInfo computeLVForDecl(const NamedDecl *D, LVComputationKind computation, diff --git a/clang/lib/CodeGen/CGCXXABI.h b/clang/lib/CodeGen/CGCXXABI.h --- a/clang/lib/CodeGen/CGCXXABI.h +++ b/clang/lib/CodeGen/CGCXXABI.h @@ -220,12 +220,6 @@ /// is required. llvm::Constant *getMemberPointerAdjustment(const CastExpr *E); - /// Computes the non-virtual adjustment needed for a member pointer - /// conversion along an inheritance path stored in an APValue. Unlike - /// getMemberPointerAdjustment(), the adjustment can be negative if the path - /// is from a derived type to a base type. - CharUnits getMemberPointerPathAdjustment(const APValue &MP); - public: virtual void emitVirtualObjectDelete(CodeGenFunction &CGF, const CXXDeleteExpr *DE, diff --git a/clang/lib/CodeGen/CGCXXABI.cpp b/clang/lib/CodeGen/CGCXXABI.cpp --- a/clang/lib/CodeGen/CGCXXABI.cpp +++ b/clang/lib/CodeGen/CGCXXABI.cpp @@ -251,28 +251,6 @@ E->path_end()); } -CharUnits CGCXXABI::getMemberPointerPathAdjustment(const APValue &MP) { - // TODO: Store base specifiers in APValue member pointer paths so we can - // easily reuse CGM.GetNonVirtualBaseClassOffset(). - const ValueDecl *MPD = MP.getMemberPointerDecl(); - CharUnits ThisAdjustment = CharUnits::Zero(); - ArrayRef Path = MP.getMemberPointerPath(); - bool DerivedMember = MP.isMemberPointerToDerivedMember(); - const CXXRecordDecl *RD = cast(MPD->getDeclContext()); - for (unsigned I = 0, N = Path.size(); I != N; ++I) { - const CXXRecordDecl *Base = RD; - const CXXRecordDecl *Derived = Path[I]; - if (DerivedMember) - std::swap(Base, Derived); - ThisAdjustment += - getContext().getASTRecordLayout(Derived).getBaseClassOffset(Base); - RD = Path[I]; - } - if (DerivedMember) - ThisAdjustment = -ThisAdjustment; - return ThisAdjustment; -} - llvm::BasicBlock * CGCXXABI::EmitCtorCompleteObjectHandler(CodeGenFunction &CGF, const CXXRecordDecl *RD) { diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -2544,8 +2544,29 @@ ConstantAddress CodeGenModule::GetAddrOfTemplateParamObject( const TemplateParamObjectDecl *TPO) { - ErrorUnsupported(TPO, "template parameter object"); - return ConstantAddress::invalid(); + StringRef Name = getMangledName(TPO); + CharUnits Alignment = getNaturalTypeAlignment(TPO->getType()); + + if (llvm::GlobalVariable *GV = getModule().getNamedGlobal(Name)) + return ConstantAddress(GV, Alignment); + + ConstantEmitter Emitter(*this); + llvm::Constant *Init = Emitter.emitForInitializer( + TPO->getValue(), TPO->getType().getAddressSpace(), TPO->getType()); + + if (!Init) { + ErrorUnsupported(TPO, "template parameter object"); + return ConstantAddress::invalid(); + } + + auto *GV = new llvm::GlobalVariable( + getModule(), Init->getType(), + /*isConstant=*/true, llvm::GlobalValue::LinkOnceODRLinkage, Init, Name); + if (supportsCOMDAT()) + GV->setComdat(TheModule.getOrInsertComdat(GV->getName())); + Emitter.finalize(GV); + + return ConstantAddress(GV, Alignment); } ConstantAddress CodeGenModule::GetWeakRefReference(const ValueDecl *VD) { diff --git a/clang/lib/CodeGen/ItaniumCXXABI.cpp b/clang/lib/CodeGen/ItaniumCXXABI.cpp --- a/clang/lib/CodeGen/ItaniumCXXABI.cpp +++ b/clang/lib/CodeGen/ItaniumCXXABI.cpp @@ -1088,7 +1088,7 @@ if (!MPD) return EmitNullMemberPointer(MPT); - CharUnits ThisAdjustment = getMemberPointerPathAdjustment(MP); + CharUnits ThisAdjustment = getContext().getMemberPointerPathAdjustment(MP); if (const CXXMethodDecl *MD = dyn_cast(MPD)) return BuildMemberPointer(MD, ThisAdjustment); diff --git a/clang/test/CodeGenCXX/mangle-class-nttp.cpp b/clang/test/CodeGenCXX/mangle-class-nttp.cpp new file mode 100644 --- /dev/null +++ b/clang/test/CodeGenCXX/mangle-class-nttp.cpp @@ -0,0 +1,165 @@ +// RUN: %clang_cc1 -std=c++20 %s -triple x86_64-linux-gnu -emit-llvm -o - | FileCheck %s + +#define fold(x) (__builtin_constant_p(x) ? (x) : (x)) + +struct A { int a, b; }; +template void f() {} + +// CHECK: define weak_odr void @_Z1fIXtl1ALi1ELi2EEEEvv( +template void f(); + +struct B { int *p; int k; }; +template void f() {} + +int n = 0; +// CHECK: define weak_odr void @_Z1fIXtl1BadL_Z1nEEEEvv( +template void f(); +// CHECK: define weak_odr void @_Z1fIXtl1BLPi0ELi1EEEEvv( +template void f(); +// CHECK: define weak_odr void @_Z1fIXtl1BEEEvv( +template void f(); +// CHECK: define weak_odr void @_Z1fIXtl1BLPi32EEEEvv( +template void f(); +// CHECK: define weak_odr void @_Z1fIXtl1BrcPiLi0EEEEvv( +template void f(0))}>(); + +// Pointers to subobjects. +struct Nested { union { int k; int arr[2]; }; } nested[2]; +struct Derived : A, Nested {} derived; +// CHECK: define weak_odr void @_Z1fIXtl1BadsoiL_Z6nestedE_EEEEvv +template void f(); +// CHECK: define weak_odr void @_Z1fIXtl1BadsoiL_Z6nestedE16_0pEEEEvv +template void f(); +// CHECK: define weak_odr void @_Z1fIXtl1BadsoiL_Z7derivedE8pEEEEvv +template void f(); +// CHECK: define weak_odr void @_Z1fIXtl1BcvPiplcvPcadL_Z7derivedELl16EEEEvv +template void f(); + +// References to subobjects. +struct BR { int &r; }; +template
void f() {} +// CHECK: define weak_odr void @_Z1fIXtl2BRsoiL_Z6nestedE_EEEEvv +template void f(); +// CHECK: define weak_odr void @_Z1fIXtl2BRsoiL_Z6nestedE12_0EEEEvv +template void f(); +// CHECK: define weak_odr void @_Z1fIXtl2BRsoiL_Z7derivedE4EEEEvv +template void f(); +// CHECK: define weak_odr void @_Z1fIXtl2BRdecvPiplcvPcadL_Z7derivedELl16EEEEvv +template void f(); + +// Qualification conversions. +struct C { const int *p; }; +template void f() {} +// CHECK: define weak_odr void @_Z1fIXtl1CadsoKiL_Z7derivedE4EEEEvv +template void f(); + +// Pointers to members. +struct D { const int Derived::*p; int k; }; +template void f() {} +// CHECK: define weak_odr void @_Z1fIXtl1DLM7DerivedKi0ELi1EEEEvv +template void f(); +// CHECK: define weak_odr void @_Z1fIXtl1DEEEvv +template void f(); +// CHECK: define weak_odr void @_Z1fIXtl1DmcM7DerivedKiadL_ZN1A1aEEEEEEvv +template void f(); +// CHECK: define weak_odr void @_Z1fIXtl1DmcM7DerivedKiadL_ZN1A1bEEEEEEvv +template void f(); +// FIXME: Is the Ut_1 mangling here correct? +// CHECK: define weak_odr void @_Z1fIXtl1DmcM7DerivedKiadL_ZN6NestedUt_1kEE8EEEEvv +template void f(); +struct MoreDerived : A, Derived { int z; }; +// CHECK: define weak_odr void @_Z1fIXtl1DmcM7DerivedKiadL_ZN11MoreDerived1zEEn8EEEEvv +template void f(); + +union E { + int n; + float f; + constexpr E() {} + constexpr E(int n) : n(n) {} + constexpr E(float f) : f(f) {} +}; +template void f() {} + +// Union members. +// CHECK: define weak_odr void @_Z1fIXL1EEEEvv( +template void f(); +// CHECK: define weak_odr void @_Z1fIXtl1EEEEvv( +template void f(); +// CHECK: define weak_odr void @_Z1fIXtl1Edi1nLi42EEEEvv( +template void f(); +// CHECK: define weak_odr void @_Z1fIXtl1Edi1fLf00000000EEEEvv( +template void f(); + +// Extensions, and dropping trailing zero-initialized elements of 'tl' +// manglings. +typedef int __attribute__((ext_vector_type(3))) VI3; +struct F { VI3 v; _Complex int ci; _Complex float cf; }; +template void f() {} +// CHECK: define weak_odr void @_Z1fIXtl1FtlDv3_iLi1ELi2ELi3EEtlCiLi4ELi5EEtlCfLf40c00000ELf40e00000EEEEEvv +template void f(); +// CHECK: define weak_odr void @_Z1fIXtl1FtlDv3_iLi1ELi2ELi3EEtlCiLi4ELi5EEtlCfLf40c00000EEEEEvv +template void f(); +// CHECK: define weak_odr void @_Z1fIXtl1FtlDv3_iLi1ELi2ELi3EEtlCiLi4ELi5EEEEEvv +template void f(); +// CHECK: define weak_odr void @_Z1fIXtl1FtlDv3_iLi1ELi2ELi3EEtlCiLi4EEEEEvv +template void f(); +// CHECK: define weak_odr void @_Z1fIXtl1FtlDv3_iLi1ELi2ELi3EEEEEvv +template void f(); +// CHECK: define weak_odr void @_Z1fIXtl1FtlDv3_iLi1ELi2EEEEEvv +template void f(); +// CHECK: define weak_odr void @_Z1fIXtl1FtlDv3_iLi1EEEEEvv +template void f(); +// CHECK: define weak_odr void @_Z1fIXtl1FEEEvv +template void f(); + +// Unnamed bit-fields. +struct G { + int : 3; + int a : 4; + int : 5; + int b : 6; + int : 7; +}; +template void f() {} +// CHECK: define weak_odr void @_Z1fIXtl1GEEEvv +template void f<(G())>(); +// CHECK: define weak_odr void @_Z1fIXtl1GLi1EEEEvv +template void f(); +// CHECK: define weak_odr void @_Z1fIXtl1GLi1ELi2EEEEvv +template void f(); + +// Empty and nearly-empty unions. +union H1 {}; +union H2 { int : 1, : 2, : 3; }; +union H3 { int : 1, a, : 2, b, : 3; }; +struct H4 { H2 h2; }; +template

void f() {} +template

void f() {} +template

void f() {} +template

void f() {} +// CHECK: define weak_odr void @_Z1fIXL2H1EEEvv +template void f(); +// CHECK: define weak_odr void @_Z1fIXL2H2EEEvv +template void f(); +// CHECK: define weak_odr void @_Z1fIXtl2H3EEEvv +template void f(); +// CHECK: define weak_odr void @_Z1fIXtl2H3di1aLi1EEEEvv +template void f(); +// CHECK: define weak_odr void @_Z1fIXtl2H3di1bLi0EEEEvv +template void f(); +// CHECK: define weak_odr void @_Z1fIXtl2H4EEEvv +template void f(); + +// Floating-point. +struct I { + float f; + double d; + long double ld; +}; +template void f() {} +// CHECK: define weak_odr void @_Z1fIXtl1IEEEvv +template void f(); +// CHECK: define weak_odr void @_Z1fIXtl1ILf80000000ELd8000000000000000ELe80000000000000000000EEEEvv +template void f(); +// CHECK: define weak_odr void @_Z1fIXtl1ILf3f800000ELd4000000000000000ELe4000c000000000000000EEEEvv +template void f(); diff --git a/clang/test/CodeGenCXX/template-param-objects.cpp b/clang/test/CodeGenCXX/template-param-objects.cpp new file mode 100644 --- /dev/null +++ b/clang/test/CodeGenCXX/template-param-objects.cpp @@ -0,0 +1,12 @@ +// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++20 %s -emit-llvm -o - | FileCheck %s + +struct S { char buf[32]; }; +template constexpr const char *begin() { return s.buf; } +template constexpr const char *end() { return s.buf + __builtin_strlen(s.buf); } + +// CHECK: [[HELLO:@_ZTAXtl1StlA32_cLc104ELc101ELc108ELc108ELc111ELc32ELc119ELc111ELc114ELc108ELc100EEEE]] = linkonce_odr constant { <{ [11 x i8], [21 x i8] }> } { <{ [11 x i8], [21 x i8] }> <{ [11 x i8] c"hello world", [21 x i8] zeroinitializer }> }, comdat + +// CHECK: @p = global i8* getelementptr inbounds ({{.*}}* [[HELLO]], i32 0, i32 0, i32 0, i32 0) +const char *p = begin(); +// CHECK: @q = global i8* getelementptr (i8, i8* getelementptr inbounds ({{.*}}* [[HELLO]], i32 0, i32 0, i32 0, i32 0), i64 11) +const char *q = end();