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,22 @@ 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 (A.getParamTypeForDecl()->isRecordType()) { + Out << 'X'; + auto *TPO = cast(D); + 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 +4920,408 @@ } } +/// 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) { + // Ignore all top-level cv-qualifiers, to match GCC. + Qualifiers Quals; + T = getASTContext().getUnqualifiedArrayType(T, Quals); + + // 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 +5638,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/AST/MicrosoftMangle.cpp b/clang/lib/AST/MicrosoftMangle.cpp --- a/clang/lib/AST/MicrosoftMangle.cpp +++ b/clang/lib/AST/MicrosoftMangle.cpp @@ -308,12 +308,17 @@ void mangleName(const NamedDecl *ND); void mangleFunctionEncoding(const FunctionDecl *FD, bool ShouldMangle); void mangleVariableEncoding(const VarDecl *VD); - void mangleMemberDataPointer(const CXXRecordDecl *RD, const ValueDecl *VD); + void mangleMemberDataPointer(const CXXRecordDecl *RD, const ValueDecl *VD, + StringRef Prefix = "$"); void mangleMemberFunctionPointer(const CXXRecordDecl *RD, - const CXXMethodDecl *MD); + const CXXMethodDecl *MD, + StringRef Prefix = "$"); void mangleVirtualMemPtrThunk(const CXXMethodDecl *MD, const MethodVFTableLocation &ML); void mangleNumber(int64_t Number); + void mangleNumber(llvm::APSInt Number); + void mangleFloat(llvm::APFloat Number); + void mangleBits(llvm::APInt Number); void mangleTagTypeKind(TagTypeKind TK); void mangleArtificialTagType(TagTypeKind TK, StringRef UnqualifiedName, ArrayRef NestedNames = None); @@ -388,6 +393,8 @@ const TemplateArgumentList &TemplateArgs); void mangleTemplateArg(const TemplateDecl *TD, const TemplateArgument &TA, const NamedDecl *Parm); + void mangleTemplateArgValue(QualType T, const APValue &V, + bool WithScalarType = true); void mangleObjCProtocol(const ObjCProtocolDecl *PD); void mangleObjCLifetime(const QualType T, Qualifiers Quals, @@ -504,10 +511,8 @@ // 'const struct __s_GUID'. Out << "3U__s_GUID@@B"; else if (isa(D)) { - DiagnosticsEngine &Diags = Context.getDiags(); - unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, - "cannot mangle template parameter objects yet"); - Diags.Report(SourceLocation(), DiagID); + // Template parameter objects don't get a ; their type is + // specified as part of their value. } else llvm_unreachable("Tried to mangle unexpected NamedDecl!"); } @@ -599,7 +604,8 @@ } void MicrosoftCXXNameMangler::mangleMemberDataPointer(const CXXRecordDecl *RD, - const ValueDecl *VD) { + const ValueDecl *VD, + StringRef Prefix) { // ::= // ::= $F // ::= $G @@ -631,7 +637,7 @@ case MSInheritanceModel::Unspecified: Code = 'G'; break; } - Out << '$' << Code; + Out << Prefix << Code; mangleNumber(FieldOffset); @@ -646,7 +652,8 @@ void MicrosoftCXXNameMangler::mangleMemberFunctionPointer(const CXXRecordDecl *RD, - const CXXMethodDecl *MD) { + const CXXMethodDecl *MD, + StringRef Prefix) { // ::= $1? // ::= $H? // ::= $I? @@ -668,7 +675,7 @@ uint64_t VBTableOffset = 0; uint64_t VBPtrOffset = 0; if (MD) { - Out << '$' << Code << '?'; + Out << Prefix << Code << '?'; if (MD->isVirtual()) { MicrosoftVTableContext *VTContext = cast(getASTContext().getVTableContext()); @@ -691,12 +698,12 @@ } else { // Null single inheritance member functions are encoded as a simple nullptr. if (IM == MSInheritanceModel::Single) { - Out << "$0A@"; + Out << Prefix << "0A@"; return; } if (IM == MSInheritanceModel::Unspecified) VBTableOffset = -1; - Out << '$' << Code; + Out << Prefix << Code; } if (inheritanceModelHasNVOffsetField(/*IsMemberFunction=*/true, IM)) @@ -735,32 +742,63 @@ } void MicrosoftCXXNameMangler::mangleNumber(int64_t Number) { + mangleNumber(llvm::APSInt(llvm::APInt(64, Number), /*IsUnsigned*/false)); +} + +void MicrosoftCXXNameMangler::mangleNumber(llvm::APSInt Number) { + // MSVC never mangles any integer wider than 64 bits. In general it appears + // to convert every integer to signed 64 bit before mangling (including + // unsigned 64 bit values). Do the same, but preserve bits beyond the bottom + // 64. + llvm::APInt Value = + Number.isSigned() ? Number.sextOrSelf(64) : Number.zextOrSelf(64); + // ::= A@ # when Number == 0 // ::= # when 1 <= Number <= 10 // ::= + @ # when Number >= 10 // // ::= [?] - uint64_t Value = static_cast(Number); - if (Number < 0) { + if (Value.isNegative()) { Value = -Value; Out << '?'; } + mangleBits(Value); +} +void MicrosoftCXXNameMangler::mangleFloat(llvm::APFloat Number) { + using llvm::APFloat; + + switch (APFloat::SemanticsToEnum(Number.getSemantics())) { + case APFloat::S_IEEEsingle: Out << 'A'; break; + case APFloat::S_IEEEdouble: Out << 'B'; break; + + // The following are all Clang extensions. We try to pick manglings that are + // unlikely to conflict with MSVC's scheme. + case APFloat::S_IEEEhalf: Out << 'V'; break; + case APFloat::S_BFloat: Out << 'W'; break; + case APFloat::S_x87DoubleExtended: Out << 'X'; break; + case APFloat::S_IEEEquad: Out << 'Y'; break; + case APFloat::S_PPCDoubleDouble: Out << 'Z'; break; + } + + mangleBits(Number.bitcastToAPInt()); +} + +void MicrosoftCXXNameMangler::mangleBits(llvm::APInt Value) { if (Value == 0) Out << "A@"; - else if (Value >= 1 && Value <= 10) + else if (Value.uge(1) && Value.ule(10)) Out << (Value - 1); else { // Numbers that are not encoded as decimal digits are represented as nibbles // in the range of ASCII characters 'A' to 'P'. // The number 0x123450 would be encoded as 'BCDEFA' - char EncodedNumberBuffer[sizeof(uint64_t) * 2]; - MutableArrayRef BufferRef(EncodedNumberBuffer); - MutableArrayRef::reverse_iterator I = BufferRef.rbegin(); - for (; Value != 0; Value >>= 4) - *I++ = 'A' + (Value & 0xf); - Out.write(I.base(), I - BufferRef.rbegin()); + llvm::SmallString<32> EncodedNumberBuffer; + for (; Value != 0; Value.lshrInPlace(4)) + EncodedNumberBuffer.push_back('A' + (Value & 0xf).getZExtValue()); + std::reverse(EncodedNumberBuffer.begin(), EncodedNumberBuffer.end()); + Out.write(EncodedNumberBuffer.data(), EncodedNumberBuffer.size()); Out << '@'; } } @@ -914,6 +952,13 @@ break; } + if (const auto *TPO = dyn_cast(ND)) { + Out << "?__N"; + mangleTemplateArgValue(TPO->getType().getUnqualifiedType(), + TPO->getValue()); + break; + } + // We must have an anonymous struct. const TagDecl *TD = cast(ND); if (const TypedefNameDecl *D = TD->getTypedefNameForAnonDecl()) { @@ -1382,10 +1427,7 @@ Out << "0"; - if (Value.isSigned()) - mangleNumber(Value.getSExtValue()); - else - mangleNumber(Value.getZExtValue()); + mangleNumber(Value); } void MicrosoftCXXNameMangler::mangleExpression( @@ -1433,6 +1475,7 @@ // ::= // ::= $E? // ::= $1? + // ::= $2 # class NTTP // ::= $0A@ // ::= @@ -1462,6 +1505,11 @@ mangleName(FD); mangleFunctionEncoding(FD, /*ShouldMangle=*/true); } + } else if (TA.getParamTypeForDecl()->isRecordType()) { + Out << "$"; + auto *TPO = cast(ND); + mangleTemplateArgValue(TPO->getType().getUnqualifiedType(), + TPO->getValue()); } else { mangle(ND, TA.getParamTypeForDecl()->isReferenceType() ? "$E?" : "$1?"); } @@ -1544,6 +1592,168 @@ } } +void MicrosoftCXXNameMangler::mangleTemplateArgValue(QualType T, + const APValue &V, + bool WithScalarType) { + switch (V.getKind()) { + case APValue::None: + case APValue::Indeterminate: + // FIXME: MSVC doesn't allow this, so we can't be sure how it should be + // mangled. + if (WithScalarType) + mangleType(T, SourceRange(), QMM_Escape); + Out << '@'; + return; + + case APValue::Int: + if (WithScalarType) + mangleType(T, SourceRange(), QMM_Escape); + Out << '0'; + mangleNumber(V.getInt()); + return; + + case APValue::Float: + if (WithScalarType) + mangleType(T, SourceRange(), QMM_Escape); + mangleFloat(V.getFloat()); + return; + + case APValue::LValue: { + if (WithScalarType) + mangleType(T, SourceRange(), QMM_Escape); + + APValue::LValueBase Base = V.getLValueBase(); + if (Base.isNull()) + Out << "0A@"; + else if (auto *VD = Base.dyn_cast()) + mangle(VD, T->isReferenceType() ? "E?" : "1?"); + else + break; + + // FIXME: MSVC doesn't support template arguments referring to subobjects + // yet (it either mangles such template arguments as null pointers or + // small integers or crashes). It's probably the intent to mangle the + // declaration followed by an offset, but that's not what actually happens. + // For now just bail. + if (!V.hasLValuePath() || !V.getLValuePath().empty() || + V.isLValueOnePastTheEnd()) + break; + + return; + } + + case APValue::MemberPointer: { + if (WithScalarType) + mangleType(T, SourceRange(), QMM_Escape); + + // FIXME: The below manglings don't include a conversion, so bail if there + // would be one. MSVC mangles the (possibly converted) value of the + // pointer-to-member object as if it were a struct, leading to collisions + // in some cases. + if (!V.getMemberPointerPath().empty()) + break; + + const CXXRecordDecl *RD = + T->castAs()->getMostRecentCXXRecordDecl(); + const ValueDecl *D = V.getMemberPointerDecl(); + if (T->isMemberDataPointerType()) + mangleMemberDataPointer(RD, D, ""); + else + mangleMemberFunctionPointer(RD, cast_or_null(D), ""); + return; + } + + case APValue::Struct: { + Out << '2'; + mangleType(T, SourceRange(), QMM_Escape); + const CXXRecordDecl *RD = T->getAsCXXRecordDecl(); + assert(RD && "unexpected type for record value"); + + unsigned BaseIndex = 0; + for (const CXXBaseSpecifier &B : RD->bases()) + mangleTemplateArgValue(B.getType(), V.getStructBase(BaseIndex++)); + for (const FieldDecl *FD : RD->fields()) + if (!FD->isUnnamedBitfield()) + mangleTemplateArgValue(FD->getType(), + V.getStructField(FD->getFieldIndex())); + Out << '@'; + return; + } + + case APValue::Union: + Out << '2'; + mangleType(T, SourceRange(), QMM_Escape); + // FIXME: MSVC doesn't mangle the active member, only the type, leading to + // collisions if more than one member has the same type. + // FIXME: MSVC doesn't yet support unions with no active member, but + // there's an obvious mangling for that, so we use it. + if (const FieldDecl *FD = V.getUnionField()) + mangleTemplateArgValue(FD->getType(), V.getUnionValue()); + Out << '@'; + return; + + case APValue::ComplexInt: + // We mangle complex types as structs, so mangle the value as a struct too. + Out << '2'; + mangleType(T, SourceRange(), QMM_Escape); + Out << '0'; + mangleNumber(V.getComplexIntReal()); + Out << '0'; + mangleNumber(V.getComplexIntImag()); + Out << '@'; + return; + + case APValue::ComplexFloat: + Out << '2'; + mangleType(T, SourceRange(), QMM_Escape); + mangleFloat(V.getComplexFloatReal()); + mangleFloat(V.getComplexFloatImag()); + Out << '@'; + return; + + case APValue::Array: { + Out << '3'; + QualType ElemT = getASTContext().getAsArrayType(T)->getElementType(); + mangleType(ElemT, SourceRange(), QMM_Escape); + for (unsigned I = 0, N = V.getArraySize(); I != N; ++I) { + const APValue &ElemV = I < V.getArrayInitializedElts() + ? V.getArrayInitializedElt(I) + : V.getArrayFiller(); + mangleTemplateArgValue(ElemT, ElemV, /*WithType*/false); + Out << '@'; + } + Out << '@'; + return; + } + + case APValue::Vector: { + // __m128 is mangled as a struct containing an array. We follow this + // approach for all vector types. + Out << '2'; + mangleType(T, SourceRange(), QMM_Escape); + Out << '3'; + QualType ElemT = T->castAs()->getElementType(); + mangleType(ElemT, SourceRange(), QMM_Escape); + for (unsigned I = 0, N = V.getVectorLength(); I != N; ++I) { + const APValue &ElemV = V.getVectorElt(I); + mangleTemplateArgValue(ElemT, ElemV, /*WithType*/false); + Out << '@'; + } + Out << "@@"; + return; + } + + case APValue::AddrLabelDiff: + case APValue::FixedPoint: + break; + } + + DiagnosticsEngine &Diags = Context.getDiags(); + unsigned DiagID = Diags.getCustomDiagID( + DiagnosticsEngine::Error, "cannot mangle this template argument yet"); + Diags.Report(DiagID); +} + void MicrosoftCXXNameMangler::mangleObjCProtocol(const ObjCProtocolDecl *PD) { llvm::SmallString<64> TemplateMangling; llvm::raw_svector_ostream Stream(TemplateMangling); 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,343 @@ +// RUN: %clang_cc1 -std=c++20 %s -triple x86_64-linux-gnu -emit-llvm -o - | FileCheck %s +// RUN: %clang_cc1 -std=c++20 %s -triple x86_64-windows -emit-llvm -o - | FileCheck %s --check-prefix=MSABI + +#define fold(x) (__builtin_constant_p(x) ? (x) : (x)) + +struct A { int a; const int b; }; +template void f() {} + +// CHECK: define weak_odr void @_Z1fIXtl1ALi1ELi2EEEEvv( +// MSABI: define {{.*}} @"??$f@$2UA@@H00$$CBH01@@@YAXXZ" +template void f(); + +struct B { const int *p; int k; }; +template void f() {} + +int n = 0; +// CHECK: define weak_odr void @_Z1fIXtl1BadL_Z1nEEEEvv( +// MSABI: define {{.*}} @"??$f@$2UB@@PEBH1?n@@3HAH0A@@@@YAXXZ" +template void f(); +// CHECK: define weak_odr void @_Z1fIXtl1BLPKi0ELi1EEEEvv( +// MSABI: define {{.*}} @"??$f@$2UB@@PEBH0A@H00@@@YAXXZ" +template void f(); +// CHECK: define weak_odr void @_Z1fIXtl1BEEEvv( +// MSABI: define {{.*}} @"??$f@$2UB@@PEBH0A@H0A@@@@YAXXZ" +template void f(); +#ifndef _WIN32 +// FIXME: MSVC crashes on the first of these and mangles the second the same as +// the nullptr version. Check the output is correct once we have a reference to +// compare against. +// CHECK: define weak_odr void @_Z1fIXtl1BLPKi32EEEEvv( +template void f(); +// CHECK: define weak_odr void @_Z1fIXtl1BrcPKiLi0EEEEvv( +template void f(0))}>(); +#endif + +// Pointers to subobjects. +struct Nested { union { int k; int arr[2]; }; } nested[2]; +struct Derived : A, Nested { int z; } extern derived; +#ifndef _WIN32 +// CHECK: define weak_odr void @_Z1fIXtl1BadsoKiL_Z6nestedE_EEEEvv +// FIXME: MSVC generates the garbage mangling ??$f@$2UB@@PEAH0A@H0A@@@@YAXXZ +// for this. +template void f(); +// FIXME: MSVC crashes on these. +// CHECK: define weak_odr void @_Z1fIXtl1BadsoKiL_Z6nestedE16_0pEEEEvv +template void f(); +// CHECK: define weak_odr void @_Z1fIXtl1BadsoKiL_Z7derivedE8pEEEEvv +template void f(); +// CHECK: define weak_odr void @_Z1fIXtl1BcvPKiplcvPcadL_Z7derivedELl16EEEEvv +template void f(); +#endif + +// References to subobjects. +struct BR { const int &r; }; +template
void f() {} +#ifndef _WIN32 +// FIXME: MSVC produces garbage manglings for these. +// CHECK: define weak_odr void @_Z1fIXtl2BRsoKiL_Z6nestedE_EEEEvv +template void f(); +// CHECK: define weak_odr void @_Z1fIXtl2BRsoKiL_Z6nestedE12_0EEEEvv +template void f(); +// CHECK: define weak_odr void @_Z1fIXtl2BRsoKiL_Z7derivedE4EEEEvv +template void f(); +// FIXME: Crashes MSVC. +// CHECK: define weak_odr void @_Z1fIXtl2BRdecvPKiplcvPcadL_Z7derivedELl16EEEEvv +template void f(); +#endif + +// Qualification conversions. +struct C { const int *p; }; +template void f() {} +#ifndef _WIN32 +// FIXME: MSVC produces a garbage mangling for this. +// CHECK: define weak_odr void @_Z1fIXtl1CadsoKiL_Z7derivedE4EEEEvv +template void f(); +#endif + +// Pointers to members. +struct D { const int Derived::*p; int k; }; +template void f() {} +// CHECK: define weak_odr void @_Z1fIXtl1DLM7DerivedKi0ELi1EEEEvv +// MSABI: define {{.*}} @"??$f@$2UD@@PERDerived@@H0?0H00@@@YAXXZ" +template void f(); +// CHECK: define weak_odr void @_Z1fIXtl1DEEEvv +// MSABI: define {{.*}} @"??$f@$2UD@@PERDerived@@H0?0H0A@@@@YAXXZ" +template void f(); +// CHECK: define weak_odr void @_Z1fIXtl1DadL_ZN7Derived1zEEEEEvv +// MSABI: define {{.*}} @"??$f@$2UD@@PERDerived@@H0BA@H0A@@@@YAXXZ" +template void f(); +#ifndef _WIN32 +// CHECK: define weak_odr void @_Z1fIXtl1DmcM7DerivedKiadL_ZN1A1aEEEEEEvv +// MSABI-FIXME: define {{.*}} @"??$f@$2UD@@PERDerived@@H0A@H0A@@@@YAXXZ" +template void f(); +// CHECK: define weak_odr void @_Z1fIXtl1DmcM7DerivedKiadL_ZN1A1bEEEEEEvv +// MSABI-FIXME: define {{.*}} @"??$f@$2UD@@PERDerived@@H03H0A@@@@YAXXZ" +template void f(); +// FIXME: Is the Ut_1 mangling here correct? +// CHECK: define weak_odr void @_Z1fIXtl1DmcM7DerivedKiadL_ZN6NestedUt_1kEE8ELi2EEEEvv +// FIXME: This mangles the same as &A::a (bug in the MS ABI). +// MSABI-FIXME: define {{.*}} @"??$f@$2UD@@PERDerived@@H0A@H01@@@YAXXZ" +template void f(); +struct MoreDerived : A, Derived { int z; }; +// CHECK: define weak_odr void @_Z1fIXtl1DmcM7DerivedKiadL_ZN11MoreDerived1zEEn8EEEEvv +// MSABI-FIXME: define {{.*}} @"??$f@$2UD@@PERDerived@@H0BI@H0A@@@@YAXXZ" +template void f(); +#endif + +// FIXME: Pointers to member functions. + +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( +// FIXME: MSVC rejects this; check this is the mangling MSVC uses when they +// start accepting. +// MSABI: define {{.*}} @"??$f@$2TE@@@@@YAXXZ" +template void f(); +// CHECK: define weak_odr void @_Z1fIXtl1EEEEvv( +// MSABI: define {{.*}} @"??$f@$2TE@@H0A@@@@YAXXZ" +template void f(); +// CHECK: define weak_odr void @_Z1fIXtl1Edi1nLi42EEEEvv( +// MSABI: define {{.*}} @"??$f@$2TE@@H0CK@@@@YAXXZ" +template void f(); +// CHECK: define weak_odr void @_Z1fIXtl1Edi1fLf00000000EEEEvv( +// MSABI: define {{.*}} @"??$f@$2TE@@MAA@@@@YAXXZ" +template void f(); + +// immintrin.h vector types. +typedef float __m128 __attribute__((__vector_size__(16))); +typedef double __m128d __attribute__((__vector_size__(16))); +typedef long long __m128i __attribute__((__vector_size__(16))); +struct M128 { __m128 a; }; +struct M128D { __m128d b; }; +struct M128I { __m128i c; }; +template void f() {} +template void f() {} +template void f() {} +// MSABI: define {{.*}} @"??$f@$2UM128@@2T__m128@@3MADPIAAAAA@@AEAAAAAAA@@AEAEAAAAA@@AEAIAAAAA@@@@@@@YAXXZ" +template void f(); +// MSABI: define {{.*}} @"??$f@$2UM128D@@2U__m128d@@3NBDPPAAAAAAAAAAAAA@@BEAAAAAAAAAAAAAAA@@@@@@@YAXXZ" +template void f(); +// FIXME: We define __m128i as a vector of long long, whereas MSVC appears to +// mangle it as if it were a vector of char. +// MSABI-FIXME: define {{.*}} @"??$f@$2UM128I@@2T__m128i@@3D00@01@0A@@0A@@0A@@0A@@0A@@0A@@0A@@0A@@0A@@0A@@0A@@0A@@0A@@0A@@@@@@@YAXXZ" +// MSABI: define {{.*}} @"??$f@$2UM128I@@2T__m128i@@3_J00@01@@@@@@YAXXZ" +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 +// MSABI: define {{.*}} @"??$f@$2UF@@2T?$__vector@H$02@__clang@@3H00@01@02@@@2U?$_Complex@H@3@0304@2U?$_Complex@M@3@AEAMAAAAA@AEAOAAAAA@@@@@YAXXZ" +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 +// MSABI: define {{.*}} @"??$f@$2UF@@2T?$__vector@H$02@__clang@@3H0A@@0A@@0A@@@@2U?$_Complex@H@3@0A@0A@@2U?$_Complex@M@3@AA@AA@@@@@YAXXZ" +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 +// MSABI: define {{.*}} @"??$f@$2UG@@H0A@H0A@@@@YAXXZ" +template void f<(G())>(); +// CHECK: define weak_odr void @_Z1fIXtl1GLi1EEEEvv +// MSABI: define {{.*}} @"??$f@$2UG@@H00H0A@@@@YAXXZ" +template void f(); +// CHECK: define weak_odr void @_Z1fIXtl1GLi1ELi2EEEEvv +// MSABI: define {{.*}} @"??$f@$2UG@@H00H01@@@YAXXZ" +template void f(); +// CHECK: define weak_odr void @_Z1fIXtl1GLin8ELin32EEEEvv +// MSABI: define {{.*}} @"??$f@$2UG@@H0?7H0?CA@@@@YAXXZ" +template void f(); + +// Empty and nearly-empty unions. +// Some of the MSVC manglings here are our invention, because MSVC rejects, but +// seem likely to be right. +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 +// MSABI: define {{.*}} @"??$f@$2TH1@@@@@YAXXZ" +template void f(); +// CHECK: define weak_odr void @_Z1fIXL2H2EEEvv +// MSABI: define {{.*}} @"??$f@$2TH2@@@@@YAXXZ" +template void f(); +// CHECK: define weak_odr void @_Z1fIXtl2H3EEEvv +// MSABI: define {{.*}} @"??$f@$2TH3@@H0A@@@@YAXXZ" +template void f(); +// CHECK: define weak_odr void @_Z1fIXtl2H3di1aLi1EEEEvv +// MSABI: define {{.*}} @"??$f@$2TH3@@H00@@@YAXXZ" +template void f(); +// FIXME: Leads to mangling collision under MS ABI; same mangling as the {.a = 0} case. +#ifndef _WIN32 +// CHECK: define weak_odr void @_Z1fIXtl2H3di1bLi0EEEEvv +template void f(); +#endif +// CHECK: define weak_odr void @_Z1fIXtl2H4EEEvv +// MSABI: define {{.*}} @"??$f@$2UH4@@2TH2@@@@@@YAXXZ" +template void f(); + +// Floating-point. +struct I { + float f; + double d; + long double ld; +}; +template void f() {} +// CHECK: define weak_odr void @_Z1fIXtl1IEEEvv +// MSABI: define {{.*}} @"??$f@$2UI@@MAA@NBA@OBA@@@@YAXXZ" +template void f(); +// CHECK: define weak_odr void @_Z1fIXtl1ILf80000000ELd8000000000000000ELe80000000000000000000EEEEvv +// MSABI: define {{.*}} @"??$f@$2UI@@MAIAAAAAAA@NBIAAAAAAAAAAAAAAA@OBIAAAAAAAAAAAAAAA@@@@YAXXZ" +template void f(); +// CHECK: define weak_odr void @_Z1fIXtl1ILf3f800000ELd4000000000000000ELec000c000000000000000EEEEvv +// MSABI: define {{.*}} @"??$f@$2UI@@MADPIAAAAA@NBEAAAAAAAAAAAAAAA@OBMAAIAAAAAAAAAAAA@@@@YAXXZ" +template void f(); +// CHECK: define {{.*}} @_Z1fIXtl1ILf00000000ELd0000000000000000ELe3bcd8000000000000000EEEEvv +// Note that "small integer" special-case manglings 'A@', '0', '1', ... are +// used here and represent tiny denormal values! +// MSABI: define {{.*}} @"??$f@$2UI@@MAA@NBA@OB0@@@YAXXZ" +template void f(); +// CHECK: define {{.*}} @_Z1fIXtl1ILf00000000ELd0000000000000002ELebbce8000000000000000EEEEvv +// ... but the special-case '?' mangling for bit 63 being set is not used. +// MSABI: define {{.*}} @"??$f@$2UI@@MAA@NB1OBIAAAAAAAAAAAAAAC@@@@YAXXZ" +template void f(); + +// Base classes and members of class type. +struct J1 { int a, b; }; +struct JEmpty {}; +struct J2 { int c, d; }; +struct J : J1, JEmpty, J2 { int e; }; +template void f() {} +// CHECK: define weak_odr void @_Z1fIXtl1JEEEvv +// MSABI: define {{.*}} @"??$f@$2UJ@@2UJ1@@H0A@H0A@@2UJEmpty@@@2UJ2@@H0A@H0A@@H0A@@@@YAXXZ" +template void f(); +// CHECK: define weak_odr void @_Z1fIXtl1Jtl2J1Li1ELi2EEtl6JEmptyEtl2J2Li3ELi4EELi5EEEEvv +// MSABI: define {{.*}} @"??$f@$2UJ@@2UJ1@@H00H01@2UJEmpty@@@2UJ2@@H02H03@H04@@@YAXXZ" +template void f(); + +struct J3 { J1 j1; }; +template void f() {} +// CHECK: define {{.*}} @_Z1fIXtl2J3tl2J1Li1ELi2EEEEEvv +// MSABI: define {{.*}} @"??$f@$2UJ3@@2UJ1@@H00H01@@@@YAXXZ" +template void f(); + +// Arrays. +struct K { int n[2][3]; }; +template void f() {} +// CHECK: define {{.*}} @_Z1fIXtl1KtlA2_A3_itlS1_Li1ELi2EEEEEEvv +// MSABI: define {{.*}} @"??$f@$2UK@@3$$BY02H3H00@01@0A@@@@3H0A@@0A@@0A@@@@@@@@YAXXZ" +template void f(); +// CHECK: define {{.*}} @_Z1fIXtl1KtlA2_A3_itlS1_Li1ELi2ELi3EEtlS1_Li4ELi5ELi6EEEEEEvv +// MSABI: define {{.*}} @"??$f@$2UK@@3$$BY02H3H00@01@02@@@3H03@04@05@@@@@@@YAXXZ" +template void f(); + +struct K1 { int a, b; }; +struct K2 : K1 { int c; }; +struct K3 { K2 k2[2]; }; +template void f() {} +// CHECK: define {{.*}} @_Z1fIXtl2K3tlA2_2K2tlS1_tl2K1Li1EEEEEEEvv +// MSABI: define {{.*}} @"??$f@$2UK3@@3UK2@@2U2@2UK1@@H00H0A@@H0A@@@2U2@2U3@H0A@H0A@@H0A@@@@@@@YAXXZ" +template void f(); +template void f(); + +namespace CvQualifiers { + struct A { const int a; int *const b; int c; }; + template void f() {} + // CHECK: define {{.*}} @_ZN12CvQualifiers1fIXtlNS_1AELi0ELPi0ELi1EEEEEvv + // MSABI: define {{.*}} @"??$f@$2UA@CvQualifiers@@$$CBH0A@QEAH0A@H00@@CvQualifiers@@YAXXZ" + template void f(); + + using T1 = const int; + using T2 = T1[5]; + using T3 = const T2; + struct B { T3 arr; }; + template void f() {} + // CHECK: define {{.*}} @_ZN12CvQualifiers1fIXtlNS_1BEtlA5_iLi1ELi2ELi3ELi4ELi5EEEEEEvv + // MSABI: define {{.*}} @"??$f@$2UB@CvQualifiers@@3$$CBH00@01@02@03@04@@@@CvQualifiers@@YAXXZ" + template void f(); +} + +struct L { + signed char a = -1; + unsigned char b = -1; + short c = -1; + unsigned short d = -1; + int e = -1; + unsigned int f = -1; + long g = -1; + unsigned long h = -1; + long long i = -1; + unsigned long long j = -1; +}; +template void f() {} +// CHECK: define {{.*}} @_Z1fIXtl1LLan1ELh255ELsn1ELt65535ELin1ELj4294967295ELln1ELm18446744073709551615ELxn1ELy18446744073709551615EEEEvv +// MSABI: define {{.*}} @"??$f@$2UL@@C0?0E0PP@F0?0G0PPPP@H0?0I0PPPPPPPP@J0?0K0PPPPPPPP@_J0?0_K0?0@@@YAXXZ" +template void f(); + +// Template parameter objects. +struct M { int n; }; +template constexpr const M &f() { return a; } +// CHECK: define {{.*}} @_Z1fIXtl1MLi42EEEERKS0_v +// CHECK: ret {{.*}} @_ZTAXtl1MLi42EEE +// MSABI: define {{.*}} @"??$f@$2UM@@H0CK@@@@YAAEBUM@@XZ" +// MSABI: ret {{.*}} @"??__N2UM@@H0CK@@@" +template const M &f(); + +template void g() {} +// CHECK: define {{.*}} @_Z1gIXadL_ZTAXtl1MLi10EEEEEEvv +// MSABI: define {{.*}} @"??$g@$1??__N2UM@@H09@@@@YAXXZ" +template void g<&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,19 @@ +// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++20 %s -emit-llvm -o - | FileCheck %s --check-prefixes=ITANIUM,CHECK +// RUN: %clang_cc1 -triple x86_64-windows -std=c++20 %s -emit-llvm -o - | FileCheck %s --check-prefixes=MSABI,CHECK + +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); } + +// ITANIUM: [[HELLO:@_ZTAXtl1StlA32_cLc104ELc101ELc108ELc108ELc111ELc32ELc119ELc111ELc114ELc108ELc100EEEE]] +// MSABI: [[HELLO:@"[?][?]__N2US@@3D0GI@@0GF@@0GM@@0GM@@0GP@@0CA@@0HH@@0GP@@0HC@@0GM@@0GE@@0A@@0A@@0A@@0A@@0A@@0A@@0A@@0A@@0A@@0A@@0A@@0A@@0A@@0A@@0A@@0A@@0A@@0A@@0A@@0A@@0A@@@@@"]] +// CHECK-SAME: = 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 + +// ITANIUM: @p +// MSABI: @"?p@@3PEBDEB" +// CHECK-SAME: global i8* getelementptr inbounds ({{.*}}* [[HELLO]], i32 0, i32 0, i32 0, i32 0) +const char *p = begin(); +// ITANIUM: @q +// MSABI: @"?q@@3PEBDEB" +// CHECK-SAME: global i8* getelementptr (i8, i8* getelementptr inbounds ({{.*}}* [[HELLO]], i32 0, i32 0, i32 0, i32 0), i64 11) +const char *q = end();