diff --git a/clang/include/clang/Basic/LangOptions.h b/clang/include/clang/Basic/LangOptions.h --- a/clang/include/clang/Basic/LangOptions.h +++ b/clang/include/clang/Basic/LangOptions.h @@ -155,8 +155,10 @@ /// Attempt to be ABI-compatible with code generated by Clang 11.0.x /// (git 2e10b7a39b93). This causes clang to pass unions with a 256-bit - /// vector member on the stack instead of using registers, and to not - /// properly mangle substitutions for template names in some cases. + /// vector member on the stack instead of using registers, to not properly + /// mangle substitutions for template names in some cases, and to mangle + /// declaration template arguments without a cast to the parameter type + /// even when that can lead to mangling collisions. Ver11, /// Conform to the underlying platform's C and C++ ABIs as closely 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 @@ -551,13 +551,15 @@ void mangleCXXCtorType(CXXCtorType T, const CXXRecordDecl *InheritedFrom); void mangleCXXDtorType(CXXDtorType T); - void mangleTemplateArgs(const TemplateArgumentLoc *TemplateArgs, + void mangleTemplateArgs(TemplateName TN, + const TemplateArgumentLoc *TemplateArgs, unsigned NumTemplateArgs); - void mangleTemplateArgs(const TemplateArgument *TemplateArgs, + void mangleTemplateArgs(TemplateName TN, const TemplateArgument *TemplateArgs, unsigned NumTemplateArgs); - void mangleTemplateArgs(const TemplateArgumentList &AL); - void mangleTemplateArg(TemplateArgument A); - void mangleValueInTemplateArg(QualType T, const APValue &V); + void mangleTemplateArgs(TemplateName TN, const TemplateArgumentList &AL); + void mangleTemplateArg(TemplateArgument A, bool NeedExactType); + void mangleValueInTemplateArg(QualType T, const APValue &V, bool TopLevel, + bool NeedExactType = false); void mangleTemplateParameter(unsigned Depth, unsigned Index); @@ -823,6 +825,11 @@ return GlobalDecl(); } +static TemplateName asTemplateName(GlobalDecl GD) { + const TemplateDecl *TD = dyn_cast_or_null(GD.getDecl()); + return TemplateName(const_cast(TD)); +} + void CXXNameMangler::mangleName(GlobalDecl GD) { const NamedDecl *ND = cast(GD.getDecl()); if (const VarDecl *VD = dyn_cast(ND)) { @@ -899,7 +906,7 @@ const TemplateArgumentList *TemplateArgs = nullptr; if (GlobalDecl TD = isTemplate(GD, TemplateArgs)) { mangleUnscopedTemplateName(TD, AdditionalAbiTags); - mangleTemplateArgs(*TemplateArgs); + mangleTemplateArgs(asTemplateName(TD), *TemplateArgs); return; } @@ -952,7 +959,7 @@ if (DC->isTranslationUnit() || isStdNamespace(DC)) { mangleUnscopedTemplateName(TD, nullptr); - mangleTemplateArgs(TemplateArgs, NumTemplateArgs); + mangleTemplateArgs(asTemplateName(TD), TemplateArgs, NumTemplateArgs); } else { mangleNestedName(TD, TemplateArgs, NumTemplateArgs); } @@ -1102,7 +1109,8 @@ // FIXME: GCC does not appear to mangle the template arguments when // the template in question is a dependent template name. Should we // emulate that badness? - mangleTemplateArgs(TST->getArgs(), TST->getNumArgs()); + mangleTemplateArgs(TST->getTemplateName(), TST->getArgs(), + TST->getNumArgs()); addSubstitution(QualType(TST, 0)); } } else if (const auto *DTST = @@ -1115,7 +1123,7 @@ // FIXME: GCC does not appear to mangle the template arguments when // the template in question is a dependent template name. Should we // emulate that badness? - mangleTemplateArgs(DTST->getArgs(), DTST->getNumArgs()); + mangleTemplateArgs(Template, DTST->getArgs(), DTST->getNumArgs()); addSubstitution(QualType(DTST, 0)); } } else { @@ -1258,7 +1266,7 @@ // The and on productions end in an optional // . if (TemplateArgs) - mangleTemplateArgs(TemplateArgs, NumTemplateArgs); + mangleTemplateArgs(TemplateName(), TemplateArgs, NumTemplateArgs); } void CXXNameMangler::mangleUnqualifiedName(GlobalDecl GD, @@ -1303,10 +1311,9 @@ if (auto *TPO = dyn_cast(ND)) { // Proposed in https://github.com/itanium-cxx-abi/cxx-abi/issues/63. - Out << "TAX"; + Out << "TA"; mangleValueInTemplateArg(TPO->getType().getUnqualifiedType(), - TPO->getValue()); - Out << "E"; + TPO->getValue(), /*TopLevel=*/true); break; } @@ -1458,10 +1465,13 @@ case DeclarationName::CXXConstructorName: { const CXXRecordDecl *InheritedFrom = nullptr; + TemplateName InheritedTemplateName; const TemplateArgumentList *InheritedTemplateArgs = nullptr; if (auto Inherited = cast(ND)->getInheritedConstructor()) { InheritedFrom = Inherited.getConstructor()->getParent(); + InheritedTemplateName = + TemplateName(Inherited.getConstructor()->getPrimaryTemplate()); InheritedTemplateArgs = Inherited.getConstructor()->getTemplateSpecializationArgs(); } @@ -1478,7 +1488,7 @@ // FIXME: The template arguments are part of the enclosing prefix or // nested-name, but it's more convenient to mangle them here. if (InheritedTemplateArgs) - mangleTemplateArgs(*InheritedTemplateArgs); + mangleTemplateArgs(InheritedTemplateName, *InheritedTemplateArgs); writeAbiTags(ND, AdditionalAbiTags); break; @@ -1567,7 +1577,7 @@ const TemplateArgumentList *TemplateArgs = nullptr; if (GlobalDecl TD = isTemplate(GD, TemplateArgs)) { mangleTemplatePrefix(TD, NoFunction); - mangleTemplateArgs(*TemplateArgs); + mangleTemplateArgs(asTemplateName(TD), *TemplateArgs); } else { manglePrefix(DC, NoFunction); @@ -1584,7 +1594,7 @@ Out << 'N'; mangleTemplatePrefix(TD); - mangleTemplateArgs(TemplateArgs, NumTemplateArgs); + mangleTemplateArgs(asTemplateName(TD), TemplateArgs, NumTemplateArgs); Out << 'E'; } @@ -1811,8 +1821,8 @@ = cast(Context)->getIdentifier()) { mangleSourceName(Name); const TemplateArgumentList *TemplateArgs = nullptr; - if (isTemplate(cast(Context), TemplateArgs)) - mangleTemplateArgs(*TemplateArgs); + if (GlobalDecl TD = isTemplate(cast(Context), TemplateArgs)) + mangleTemplateArgs(asTemplateName(TD), *TemplateArgs); Out << 'M'; } } @@ -1903,7 +1913,7 @@ const TemplateArgumentList *TemplateArgs = nullptr; if (GlobalDecl TD = isTemplate(ND, TemplateArgs)) { mangleTemplatePrefix(TD); - mangleTemplateArgs(*TemplateArgs); + mangleTemplateArgs(asTemplateName(TD), *TemplateArgs); } else { manglePrefix(getEffectiveDeclContext(ND), NoFunction); mangleUnqualifiedName(ND, nullptr); @@ -2162,7 +2172,7 @@ } } - mangleTemplateArgs(TST->getArgs(), TST->getNumArgs()); + mangleTemplateArgs(TN, TST->getArgs(), TST->getNumArgs()); break; } @@ -2178,8 +2188,10 @@ case Type::DependentTemplateSpecialization: { const DependentTemplateSpecializationType *DTST = cast(Ty); + TemplateName Template = getASTContext().getDependentTemplateName( + DTST->getQualifier(), DTST->getIdentifier()); mangleSourceName(DTST->getIdentifier()); - mangleTemplateArgs(DTST->getArgs(), DTST->getNumArgs()); + mangleTemplateArgs(Template, DTST->getArgs(), DTST->getNumArgs()); break; } @@ -3507,8 +3519,8 @@ Out << "u" << VendorQualifier.size() << VendorQualifier; Out << "I"; - mangleTemplateArg(T->getRowExpr()); - mangleTemplateArg(T->getColumnExpr()); + mangleTemplateArg(T->getRowExpr(), false); + mangleTemplateArg(T->getColumnExpr(), false); mangleType(T->getElementType()); Out << "E"; } @@ -3581,7 +3593,7 @@ // FIXME: GCC does not appear to mangle the template arguments when // the template in question is a dependent template name. Should we // emulate that badness? - mangleTemplateArgs(T->getArgs(), T->getNumArgs()); + mangleTemplateArgs(T->getTemplateName(), T->getArgs(), T->getNumArgs()); addSubstitution(QualType(T, 0)); } } @@ -3633,7 +3645,7 @@ // FIXME: GCC does not appear to mangle the template arguments when // the template in question is a dependent template name. Should we // emulate that badness? - mangleTemplateArgs(T->getArgs(), T->getNumArgs()); + mangleTemplateArgs(Prefix, T->getArgs(), T->getNumArgs()); Out << 'E'; } @@ -3733,7 +3745,7 @@ llvm::APSInt BW(32, true); BW = T->getNumBits(); TemplateArgument TA(Context.getASTContext(), BW, getASTContext().IntTy); - mangleTemplateArgs(&TA, 1); + mangleTemplateArgs(TemplateName(), &TA, 1); if (T->isUnsigned()) Out << "j"; else @@ -3743,7 +3755,7 @@ void CXXNameMangler::mangleType(const DependentExtIntType *T) { Out << "U7_ExtInt"; TemplateArgument TA(T->getNumBitsExpr()); - mangleTemplateArgs(&TA, 1); + mangleTemplateArgs(TemplateName(), &TA, 1); if (T->isUnsigned()) Out << "j"; else @@ -4632,7 +4644,7 @@ if (SPE->isPartiallySubstituted()) { Out << "sP"; for (const auto &A : SPE->getPartialArguments()) - mangleTemplateArg(A); + mangleTemplateArg(A, false); Out << "E"; break; } @@ -4820,33 +4832,71 @@ } } -void CXXNameMangler::mangleTemplateArgs(const TemplateArgumentLoc *TemplateArgs, +namespace { +// Helper to provide ancillary information on a template used to mangle its +// arguments. +struct TemplateArgManglingInfo { + TemplateDecl *ResolvedTemplate = nullptr; + + TemplateArgManglingInfo(TemplateName TN) { + if (TemplateDecl *TD = TN.getAsTemplateDecl()) + ResolvedTemplate = TD; + } + + /// Do we need to mangle template arguments with exactly correct types? + bool needExactType(unsigned I) const { + // We need correct types when the template-name is unresolved or when it + // names a template that is able to be overloaded. + if (!ResolvedTemplate) + return true; + if (auto *FTD = dyn_cast(ResolvedTemplate)) { + auto *RD = dyn_cast(FTD->getDeclContext()); + if (!RD || !RD->isGenericLambda()) + return true; + } + + // Otherwise, we only need a correct type if the parameter has a deduced + // type. + auto *NTTP = dyn_cast( + ResolvedTemplate->getTemplateParameters()->getParam(I)); + return NTTP && NTTP->getType()->getContainedDeducedType(); + } +}; +} + +void CXXNameMangler::mangleTemplateArgs(TemplateName TN, + const TemplateArgumentLoc *TemplateArgs, unsigned NumTemplateArgs) { // ::= I + E Out << 'I'; + TemplateArgManglingInfo Info(TN); for (unsigned i = 0; i != NumTemplateArgs; ++i) - mangleTemplateArg(TemplateArgs[i].getArgument()); + mangleTemplateArg(TemplateArgs[i].getArgument(), Info.needExactType(i)); Out << 'E'; } -void CXXNameMangler::mangleTemplateArgs(const TemplateArgumentList &AL) { +void CXXNameMangler::mangleTemplateArgs(TemplateName TN, + const TemplateArgumentList &AL) { // ::= I + E Out << 'I'; + TemplateArgManglingInfo Info(TN); for (unsigned i = 0, e = AL.size(); i != e; ++i) - mangleTemplateArg(AL[i]); + mangleTemplateArg(AL[i], Info.needExactType(i)); Out << 'E'; } -void CXXNameMangler::mangleTemplateArgs(const TemplateArgument *TemplateArgs, +void CXXNameMangler::mangleTemplateArgs(TemplateName TN, + const TemplateArgument *TemplateArgs, unsigned NumTemplateArgs) { // ::= I + E Out << 'I'; + TemplateArgManglingInfo Info(TN); for (unsigned i = 0; i != NumTemplateArgs; ++i) - mangleTemplateArg(TemplateArgs[i]); + mangleTemplateArg(TemplateArgs[i], Info.needExactType(i)); Out << 'E'; } -void CXXNameMangler::mangleTemplateArg(TemplateArgument A) { +void CXXNameMangler::mangleTemplateArg(TemplateArgument A, bool NeedExactType) { // ::= # type or template // ::= X E # expression // ::= # simple expressions @@ -4900,28 +4950,30 @@ // 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'; + TPO->getValue(), /*TopLevel=*/true, + NeedExactType); 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. - bool compensateMangling = !A.getParamTypeForDecl()->isReferenceType(); - if (compensateMangling) { - Out << 'X'; - mangleOperatorName(OO_Amp, 1); - } - - mangleDeclRefExpr(D); - - if (compensateMangling) - Out << 'E'; - + ASTContext &Ctx = Context.getASTContext(); + APValue Value; + if (D->isCXXInstanceMember()) + Value = APValue(D, false, {}); + else if (D->getType()->isArrayType() && + Ctx.hasSimilarType(Ctx.getDecayedType(D->getType()), + A.getParamTypeForDecl()) && + Ctx.getLangOpts().getClangABICompat() > + LangOptions::ClangABI::Ver11) + // Build a value corresponding to this implicit array-to-pointer decay. + Value = APValue(APValue::LValueBase(D), CharUnits::Zero(), + {APValue::LValuePathEntry::ArrayIndex(0)}, false); + else + Value = APValue(APValue::LValueBase(D), CharUnits::Zero(), + ArrayRef(), false); + mangleValueInTemplateArg(A.getParamTypeForDecl(), Value, /*TopLevel=*/true, + NeedExactType); break; } case TemplateArgument::NullPtr: { @@ -4932,7 +4984,7 @@ // ::= J * E Out << 'J'; for (const auto &P : A.pack_elements()) - mangleTemplateArg(P); + mangleTemplateArg(P, NeedExactType); Out << 'E'; } } @@ -5028,11 +5080,36 @@ llvm_unreachable("Unhandled APValue::ValueKind enum"); } -void CXXNameMangler::mangleValueInTemplateArg(QualType T, const APValue &V) { +static QualType getLValueType(ASTContext &Ctx, const APValue &LV) { + QualType T = LV.getLValueBase().getType(); + for (APValue::LValuePathEntry E : LV.getLValuePath()) { + if (const ArrayType *AT = Ctx.getAsArrayType(T)) + T = AT->getElementType(); + else if (const FieldDecl *FD = + dyn_cast(E.getAsBaseOrMember().getPointer())) + T = FD->getType(); + else + T = Ctx.getRecordType( + cast(E.getAsBaseOrMember().getPointer())); + } + return T; +} + +void CXXNameMangler::mangleValueInTemplateArg(QualType T, const APValue &V, + bool TopLevel, + bool NeedExactType) { // Ignore all top-level cv-qualifiers, to match GCC. Qualifiers Quals; T = getASTContext().getUnqualifiedArrayType(T, Quals); + // A top-level expression that's not a primary expression is wrapped in X...E. + bool IsPrimaryExpr = true; + auto NotPrimaryExpr = [&] { + if (TopLevel && IsPrimaryExpr) + Out << 'X'; + IsPrimaryExpr = false; + }; + // Proposed in https://github.com/itanium-cxx-abi/cxx-abi/issues/63. switch (V.getKind()) { case APValue::None: @@ -5040,7 +5117,7 @@ Out << 'L'; mangleType(T); Out << 'E'; - return; + break; case APValue::AddrLabelDiff: llvm_unreachable("unexpected value kind in template argument"); @@ -5068,18 +5145,20 @@ } // ::= tl * E + NotPrimaryExpr(); Out << "tl"; mangleType(T); for (unsigned I = 0, N = Bases.size(); I != N; ++I) - mangleValueInTemplateArg(Bases[I].getType(), V.getStructBase(I)); + mangleValueInTemplateArg(Bases[I].getType(), V.getStructBase(I), false); for (unsigned I = 0, N = Fields.size(); I != N; ++I) { if (Fields[I]->isUnnamedBitfield()) continue; mangleValueInTemplateArg(Fields[I]->getType(), - V.getStructField(Fields[I]->getFieldIndex())); + V.getStructField(Fields[I]->getFieldIndex()), + false); } Out << 'E'; - return; + break; } case APValue::Union: { @@ -5090,24 +5169,26 @@ Out << 'L'; mangleType(T); Out << 'E'; - return; + break; } // ::= di + NotPrimaryExpr(); Out << "tl"; mangleType(T); if (!isZeroInitialized(T, V)) { Out << "di"; mangleSourceName(FD->getIdentifier()); - mangleValueInTemplateArg(FD->getType(), V.getUnionValue()); + mangleValueInTemplateArg(FD->getType(), V.getUnionValue(), false); } Out << 'E'; - return; + break; } case APValue::Array: { QualType ElemT(T->getArrayElementTypeNoTypeQual(), 0); + NotPrimaryExpr(); Out << "tl"; mangleType(T); @@ -5123,40 +5204,42 @@ const APValue &Elem = I < V.getArrayInitializedElts() ? V.getArrayInitializedElt(I) : V.getArrayFiller(); - mangleValueInTemplateArg(ElemT, Elem); + mangleValueInTemplateArg(ElemT, Elem, false); } Out << 'E'; - return; + break; } case APValue::Vector: { const VectorType *VT = T->castAs(); + NotPrimaryExpr(); 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)); + mangleValueInTemplateArg(VT->getElementType(), V.getVectorElt(I), false); Out << 'E'; - return; + break; } case APValue::Int: mangleIntegerLiteral(T, V.getInt()); - return; + break; case APValue::Float: mangleFloatLiteral(T, V.getFloat()); - return; + break; case APValue::FixedPoint: mangleFixedPointLiteral(); - return; + break; case APValue::ComplexFloat: { const ComplexType *CT = T->castAs(); + NotPrimaryExpr(); Out << "tl"; mangleType(T); if (!V.getComplexFloatReal().isPosZero() || @@ -5165,11 +5248,12 @@ if (!V.getComplexFloatImag().isPosZero()) mangleFloatLiteral(CT->getElementType(), V.getComplexFloatImag()); Out << 'E'; - return; + break; } case APValue::ComplexInt: { const ComplexType *CT = T->castAs(); + NotPrimaryExpr(); Out << "tl"; mangleType(T); if (V.getComplexIntReal().getBoolValue() || @@ -5178,7 +5262,7 @@ if (V.getComplexIntImag().getBoolValue()) mangleIntegerLiteral(CT->getElementType(), V.getComplexIntImag()); Out << 'E'; - return; + break; } case APValue::LValue: { @@ -5188,7 +5272,7 @@ if (V.isNullPointer()) { mangleNullPointer(T); - return; + break; } APValue::LValueBase B = V.getLValueBase(); @@ -5199,54 +5283,82 @@ if (Offset.isZero()) { // This is reinterpret_cast(0), not a null pointer. Mangle this as // a cast, because L 0 E means something else. + NotPrimaryExpr(); Out << "rc"; mangleType(T); Out << "Li0E"; + if (TopLevel) + Out << 'E'; } else { Out << "L"; mangleType(T); Out << Offset.getQuantity() << 'E'; } - return; + break; } + ASTContext &Ctx = Context.getASTContext(); + enum { Base, Offset, Path } Kind; if (!V.hasLValuePath()) { // Mangle as (T*)((char*)&base + N). if (T->isReferenceType()) { + NotPrimaryExpr(); Out << "decvP"; mangleType(T->getPointeeType()); } else { + NotPrimaryExpr(); Out << "cv"; mangleType(T); } Out << "plcvPcad"; Kind = Offset; } else { - if (T->isPointerType()) - Out << "ad"; if (!V.getLValuePath().empty() || V.isLValueOnePastTheEnd()) { + NotPrimaryExpr(); + // A final conversion to the template parameter's type is usually + // folded into the 'so' mangling, but we can't do that for 'void*' + // parameters without introducing collisions. + if (NeedExactType && T->isVoidPointerType()) { + Out << "cv"; + mangleType(T); + } + if (T->isPointerType()) + Out << "ad"; Out << "so"; - mangleType(T->getPointeeType()); + mangleType(T->isVoidPointerType() + ? getLValueType(Ctx, V).getUnqualifiedType() + : T->getPointeeType()); Kind = Path; } else { + if (NeedExactType && + !Ctx.hasSameType(T->getPointeeType(), getLValueType(Ctx, V)) && + Ctx.getLangOpts().getClangABICompat() > + LangOptions::ClangABI::Ver11) { + NotPrimaryExpr(); + Out << "cv"; + mangleType(T); + } + if (T->isPointerType()) { + NotPrimaryExpr(); + Out << "ad"; + } Kind = Base; } } - QualType TypeSoFar; + QualType TypeSoFar = B.getType(); if (auto *VD = B.dyn_cast()) { Out << 'L'; mangle(VD); Out << 'E'; - TypeSoFar = VD->getType(); } else if (auto *E = B.dyn_cast()) { + NotPrimaryExpr(); mangleExpression(E); - TypeSoFar = E->getType(); } else if (auto TI = B.dyn_cast()) { + NotPrimaryExpr(); 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"); @@ -5258,7 +5370,7 @@ case Offset: Out << 'L'; - mangleType(Context.getASTContext().getPointerDiffType()); + mangleType(Ctx.getPointerDiffType()); mangleNumber(V.getLValueOffset().getQuantity()); Out << 'E'; break; @@ -5289,8 +5401,7 @@ } TypeSoFar = FD->getType(); } else { - TypeSoFar = - Context.getASTContext().getRecordType(cast(D)); + TypeSoFar = Ctx.getRecordType(cast(D)); } } } @@ -5301,19 +5412,30 @@ break; } - return; + break; } case APValue::MemberPointer: // Proposed in https://github.com/itanium-cxx-abi/cxx-abi/issues/47. if (!V.getMemberPointerDecl()) { mangleNullPointer(T); - return; + break; } + ASTContext &Ctx = Context.getASTContext(); + + NotPrimaryExpr(); if (!V.getMemberPointerPath().empty()) { Out << "mc"; mangleType(T); + } else if (NeedExactType && + !Ctx.hasSameType( + T->castAs()->getPointeeType(), + V.getMemberPointerDecl()->getType()) && + Ctx.getLangOpts().getClangABICompat() > + LangOptions::ClangABI::Ver11) { + Out << "cv"; + mangleType(T); } Out << "adL"; mangle(V.getMemberPointerDecl()); @@ -5325,8 +5447,11 @@ mangleNumber(Offset.getQuantity()); Out << 'E'; } - return; + break; } + + if (TopLevel && !IsPrimaryExpr) + Out << 'E'; } void CXXNameMangler::mangleTemplateParameter(unsigned Depth, unsigned Index) { diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp --- a/clang/lib/AST/StmtProfile.cpp +++ b/clang/lib/AST/StmtProfile.cpp @@ -2193,6 +2193,8 @@ break; case TemplateArgument::Declaration: + VisitType(Arg.getParamTypeForDecl()); + // FIXME: Do we need to recursively decompose template parameter objects? VisitDecl(Arg.getAsDecl()); break; @@ -2201,8 +2203,8 @@ break; case TemplateArgument::Integral: - Arg.getAsIntegral().Profile(ID); VisitType(Arg.getIntegralType()); + Arg.getAsIntegral().Profile(ID); break; case TemplateArgument::Expression: diff --git a/clang/lib/AST/TemplateBase.cpp b/clang/lib/AST/TemplateBase.cpp --- a/clang/lib/AST/TemplateBase.cpp +++ b/clang/lib/AST/TemplateBase.cpp @@ -244,6 +244,7 @@ break; case Declaration: + getParamTypeForDecl().Profile(ID); ID.AddPointer(getAsDecl()? getAsDecl()->getCanonicalDecl() : nullptr); break; diff --git a/clang/test/CodeGenCXX/clang-abi-compat.cpp b/clang/test/CodeGenCXX/clang-abi-compat.cpp --- a/clang/test/CodeGenCXX/clang-abi-compat.cpp +++ b/clang/test/CodeGenCXX/clang-abi-compat.cpp @@ -1,10 +1,12 @@ -// RUN: %clang_cc1 -std=c++17 -triple x86_64-linux-gnu -fclang-abi-compat=3.0 %s -emit-llvm -o - | FileCheck --check-prefixes=PRE39,PRE5,PRE12 %s -// RUN: %clang_cc1 -std=c++17 -triple x86_64-linux-gnu -fclang-abi-compat=3.8 %s -emit-llvm -o - | FileCheck --check-prefixes=PRE39,PRE5,PRE12 %s -// RUN: %clang_cc1 -std=c++17 -triple x86_64-linux-gnu -fclang-abi-compat=3.9 %s -emit-llvm -o - | FileCheck --check-prefixes=V39,PRE5,PRE12 %s -// RUN: %clang_cc1 -std=c++17 -triple x86_64-linux-gnu -fclang-abi-compat=4.0 %s -emit-llvm -o - | FileCheck --check-prefixes=V39,PRE5,PRE12 %s -// RUN: %clang_cc1 -std=c++17 -triple x86_64-linux-gnu -fclang-abi-compat=5 %s -emit-llvm -o - | FileCheck --check-prefixes=V39,V5,PRE12 %s -// RUN: %clang_cc1 -std=c++17 -triple x86_64-linux-gnu -fclang-abi-compat=11 %s -emit-llvm -o - | FileCheck --check-prefixes=V11,V5,PRE12 %s -// RUN: %clang_cc1 -std=c++17 -triple x86_64-linux-gnu -fclang-abi-compat=latest %s -emit-llvm -o - | FileCheck --check-prefixes=V39,V5,V12 %s +// RUN: %clang_cc1 -std=c++98 -triple x86_64-linux-gnu -fclang-abi-compat=3.0 %s -emit-llvm -o - | FileCheck --check-prefixes=CHECK,PRE39,PRE5,PRE12 %s +// RUN: %clang_cc1 -std=c++17 -triple x86_64-linux-gnu -fclang-abi-compat=3.0 %s -emit-llvm -o - | FileCheck --check-prefixes=CHECK,PRE39,PRE5,PRE12 %s +// RUN: %clang_cc1 -std=c++17 -triple x86_64-linux-gnu -fclang-abi-compat=3.8 %s -emit-llvm -o - | FileCheck --check-prefixes=CHECK,PRE39,PRE5,PRE12 %s +// RUN: %clang_cc1 -std=c++17 -triple x86_64-linux-gnu -fclang-abi-compat=3.9 %s -emit-llvm -o - | FileCheck --check-prefixes=CHECK,V39,PRE5,PRE12 %s +// RUN: %clang_cc1 -std=c++17 -triple x86_64-linux-gnu -fclang-abi-compat=4.0 %s -emit-llvm -o - | FileCheck --check-prefixes=CHECK,V39,PRE5,PRE12 %s +// RUN: %clang_cc1 -std=c++17 -triple x86_64-linux-gnu -fclang-abi-compat=5 %s -emit-llvm -o - | FileCheck --check-prefixes=CHECK,V39,V5,PRE12,PRE12-CXX17 %s +// RUN: %clang_cc1 -std=c++17 -triple x86_64-linux-gnu -fclang-abi-compat=11 %s -emit-llvm -o - | FileCheck --check-prefixes=CHECK,V39,V5,PRE12,PRE12-CXX17 %s +// RUN: %clang_cc1 -std=c++98 -triple x86_64-linux-gnu -fclang-abi-compat=latest %s -emit-llvm -o - | FileCheck --check-prefixes=CHECK,V39,V5,V12 %s +// RUN: %clang_cc1 -std=c++20 -triple x86_64-linux-gnu -fclang-abi-compat=latest %s -emit-llvm -o - | FileCheck --check-prefixes=CHECK,V39,V5,V12,V12-CXX17 %s typedef __attribute__((vector_size(8))) long long v1xi64; void clang39(v1xi64) {} @@ -27,3 +29,29 @@ void g() { f(1, 2); } } +int arg; +template struct clang12_unchanged {}; +// CHECK: @_Z4test17clang12_unchangedIXadL_Z3argEEE +void test(clang12_unchanged<&arg>) {} + +#if __cplusplus >= 201703L +// PRE12-CXX17: @_Z4test15clang12_changedIXadL_Z3argEEE +// V12-CXX17: @_Z4test15clang12_changedIXcvPKiadL_Z3argEEE +template struct clang12_changed {}; +void test(clang12_changed<(const int*)&arg>) {} +#endif + +// PRE12: @_Z9clang12_aIXadL_Z3argEEEvv +// V12: @_Z9clang12_aIXcvPKiadL_Z3argEEEvv +template void clang12_a() {} +template void clang12_a<&arg>(); + +// PRE12: @_Z9clang12_bIXadL_Z3arrEEEvv +// V12: @_Z9clang12_bIXadsoKcL_Z3arrEEEEvv +extern const char arr[6] = "hello"; +template void clang12_b() {} +template void clang12_b(); + +// CHECK: @_Z9clang12_cIXadL_Z3arrEEEvv +template void clang12_c() {} +template void clang12_c<&arr>(); diff --git a/clang/test/CodeGenCXX/mangle-class-nttp.cpp b/clang/test/CodeGenCXX/mangle-class-nttp.cpp --- a/clang/test/CodeGenCXX/mangle-class-nttp.cpp +++ b/clang/test/CodeGenCXX/mangle-class-nttp.cpp @@ -124,7 +124,7 @@ template void f() {} // Union members. -// CHECK: define weak_odr void @_Z1fIXL1EEEEvv( +// CHECK: define weak_odr void @_Z1fIL1EEEvv( // MSABI: define {{.*}} @"??$f@$7TE@@@@@YAXXZ" template void f(); // CHECK: define weak_odr void @_Z1fIXtl1EEEEvv( @@ -214,10 +214,10 @@ template

void f() {} template

void f() {} template

void f() {} -// CHECK: define weak_odr void @_Z1fIXL2H1EEEvv +// CHECK: define weak_odr void @_Z1fIL2H1EEvv // MSABI: define {{.*}} @"??$f@$7TH1@@@@@YAXXZ" template void f(); -// CHECK: define weak_odr void @_Z1fIXL2H2EEEvv +// CHECK: define weak_odr void @_Z1fIL2H2EEvv // MSABI: define {{.*}} @"??$f@$7TH2@@@@@YAXXZ" template void f(); // CHECK: define weak_odr void @_Z1fIXtl2H3EEEvv diff --git a/clang/test/CodeGenCXX/mangle-template.cpp b/clang/test/CodeGenCXX/mangle-template.cpp --- a/clang/test/CodeGenCXX/mangle-template.cpp +++ b/clang/test/CodeGenCXX/mangle-template.cpp @@ -1,4 +1,5 @@ // RUN: %clang_cc1 -verify -Wno-return-type -Wno-main -std=c++11 -emit-llvm -triple %itanium_abi_triple -o - %s | FileCheck %s +// RUN: %clang_cc1 -verify -Wno-return-type -Wno-main -std=c++20 -emit-llvm -triple x86_64-linux-gnu -o - %s | FileCheck %s --check-prefixes=CHECK,CXX20 // expected-no-diagnostics namespace test1 { @@ -221,3 +222,38 @@ void g() { f(1, 2); } } +#if __cplusplus >= 202002L +namespace cxx20 { + template struct A {}; + template struct B {}; + + int x; + // CXX20: define {{.*}} @_ZN5cxx201fENS_1AIXadL_ZNS_1xEEEEE( + void f(A<&x>) {} + // CXX20: define {{.*}} @_ZN5cxx201fENS_1BIPiXadL_ZNS_1xEEEEE( + void f(B) {} + // CXX20: define {{.*}} @_ZN5cxx201fENS_1AIXcvPKiadL_ZNS_1xEEEEE( + void f(A<(const int*)&x>) {} + // CXX20: define {{.*}} @_ZN5cxx201fENS_1BIPKiXadL_ZNS_1xEEEEE( + void f(B) {} + // CXX20: define {{.*}} @_ZN5cxx201fENS_1AIXcvPvadL_ZNS_1xEEEEE( + void f(A<(void*)&x>) {} + // CXX20: define {{.*}} @_ZN5cxx201fENS_1BIPvXadL_ZNS_1xEEEEE( + void f(B) {} + // CXX20: define {{.*}} @_ZN5cxx201fENS_1AIXcvPKvadL_ZNS_1xEEEEE( + void f(A<(const void*)&x>) {} + // CXX20: define {{.*}} @_ZN5cxx201fENS_1BIPKvXadL_ZNS_1xEEEEE( + void f(B) {} + + struct Q { int x; }; + + // CXX20: define {{.*}} @_ZN5cxx201fENS_1AIXadL_ZNS_1Q1xEEEEE( + void f(A<&Q::x>) {} + // CXX20: define {{.*}} @_ZN5cxx201fENS_1BIMNS_1QEiXadL_ZNS1_1xEEEEE + void f(B) {} + // CXX20: define {{.*}} @_ZN5cxx201fENS_1AIXcvMNS_1QEKiadL_ZNS1_1xEEEEE( + void f(A<(const int Q::*)&Q::x>) {} + // CXX20: define {{.*}} @_ZN5cxx201fENS_1BIMNS_1QEKiXadL_ZNS1_1xEEEEE( + void f(B) {} +} +#endif diff --git a/clang/test/SemaTemplate/temp_arg_nontype_cxx1z.cpp b/clang/test/SemaTemplate/temp_arg_nontype_cxx1z.cpp --- a/clang/test/SemaTemplate/temp_arg_nontype_cxx1z.cpp +++ b/clang/test/SemaTemplate/temp_arg_nontype_cxx1z.cpp @@ -187,6 +187,11 @@ int &r = f(B<&a>()); float &s = f(B<&b>()); + void type_affects_identity(B<&a>) {} + void type_affects_identity(B<(const int*)&a>) {} + void type_affects_identity(B<(void*)&a>) {} + void type_affects_identity(B<(const void*)&a>) {} + // pointers to members template struct B

{}; template struct B

{}; @@ -198,6 +203,12 @@ char &u = f(B<&X::p>()); short &v = f(B<&X::pp>()); + struct Y : X {}; + void type_affects_identity(B<&X::n>) {} + void type_affects_identity(B<(int Y::*)&X::n>) {} // FIXME: expected-error {{sorry}} + void type_affects_identity(B<(const int X::*)&X::n>) {} + void type_affects_identity(B<(const int Y::*)&X::n>) {} // FIXME: expected-error {{sorry}} + // A case where we need to do auto-deduction, and check whether the // resulting dependent types match during partial ordering. These // templates are not ordered due to the mismatching function parameter.