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 @@ -152,6 +152,12 @@ /// NetBSD. Ver9, + /// Attempt to be ABI-compatible with code generated by Clang 10.0.x. + /// This allows mangling substitutions to be used if they refer to function + /// or template parameters at the same depth and index, even if they refer + /// to parameters of unrelated functions. + Ver10, + /// Conform to the underlying platform's C and C++ ABIs as closely /// as we can. Latest 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 @@ -377,7 +377,11 @@ AbiTagState *AbiTags = nullptr; AbiTagState AbiTagsRoot; - llvm::DenseMap Substitutions; + struct Substitution { + unsigned SeqID; + unsigned EncodingScope; + }; + llvm::DenseMap Substitutions; llvm::DenseMap ModuleSubstitutions; ASTContext &getASTContext() const { return Context.getASTContext(); } @@ -404,13 +408,19 @@ : Context(Outer.Context), Out(Out_), NullOut(false), Structor(Outer.Structor), StructorType(Outer.StructorType), SeqID(Outer.SeqID), FunctionTypeDepth(Outer.FunctionTypeDepth), - AbiTagsRoot(AbiTags), Substitutions(Outer.Substitutions) {} + AbiTagsRoot(AbiTags), Substitutions(Outer.Substitutions), + ModuleSubstitutions(Outer.ModuleSubstitutions), + InnermostScope(Outer.InnermostScope), + EncodingScopes(Outer.EncodingScopes) {} CXXNameMangler(CXXNameMangler &Outer, llvm::raw_null_ostream &Out_) : Context(Outer.Context), Out(Out_), NullOut(true), Structor(Outer.Structor), StructorType(Outer.StructorType), SeqID(Outer.SeqID), FunctionTypeDepth(Outer.FunctionTypeDepth), - AbiTagsRoot(AbiTags), Substitutions(Outer.Substitutions) {} + AbiTagsRoot(AbiTags), Substitutions(Outer.Substitutions), + ModuleSubstitutions(Outer.ModuleSubstitutions), + InnermostScope(Outer.InnermostScope), + EncodingScopes(Outer.EncodingScopes) {} raw_ostream &getStream() { return Out; } @@ -430,6 +440,84 @@ void mangleLambdaSig(const CXXRecordDecl *Lambda); private: + /// An interesting region within the mangling process. + struct ManglingScope { + CXXNameMangler &M; + ManglingScope *Parent; + enum Kind { Substitution, Encoding } K; + + ManglingScope(CXXNameMangler &M, Kind K) + : M(M), Parent(M.InnermostScope), K(K) { + M.InnermostScope = this; + } + ManglingScope(const ManglingScope&) = delete; + void operator=(const ManglingScope&) = delete; + ~ManglingScope() { + M.InnermostScope = Parent; + } + + template T *getAs() { + return K == T::StaticKind ? static_cast(this) : nullptr; + } + }; + ManglingScope *InnermostScope = nullptr; + + /// Indicates a mangling region that might be converted into a substitution. + /// This object tracks properties of the substituted component that aren't + /// captured in its pointer value. + struct SubstitutionScope : ManglingScope { + static constexpr Kind StaticKind = Substitution; + + // The innermost encoding scope that this substitution references. + unsigned InnermostEncodingScope = 0; + + SubstitutionScope(CXXNameMangler &M) : ManglingScope(M, StaticKind) {} + }; + + /// The number of local encoding scopes mangled so far, used to assign unique + /// IDs to scopes. The ID of a scope is always less than that of any inner + /// scopes. + unsigned EncodingScopes = 0; + + /// Indicates a mangling region corresponding to a nested . + struct EncodingScope : ManglingScope { + static constexpr Kind StaticKind = Encoding; + + unsigned ScopeID; + + EncodingScope(CXXNameMangler &M) + : ManglingScope(M, StaticKind), ScopeID(++M.EncodingScopes) {} + }; + + bool inEncodingScope(unsigned I) const { + for (ManglingScope *S = InnermostScope; S; S = S->Parent) { + if (EncodingScope *ES = S->getAs()) { + if (ES->ScopeID == I) return true; + if (ES->ScopeID < I) return false; + } + } + return false; + } + + /// Note that we made reference to part of the enclosing . In + /// particular, this means that any substitutions within that + /// cannot be used from outside it. + void noteReferenceToEncoding() { + unsigned InnermostEncodingScope = 0; + for (ManglingScope *S = InnermostScope; S; S = S->Parent) { + if (EncodingScope *ES = S->getAs()) { + InnermostEncodingScope = ES->ScopeID; + break; + } + } + for (ManglingScope *S = InnermostScope; S; S = S->Parent) { + if (S->getAs()) + break; + if (SubstitutionScope *SS = S->getAs()) + SS->InnermostEncodingScope = + std::max(SS->InnermostEncodingScope, InnermostEncodingScope); + } + } bool mangleSubstitution(const NamedDecl *ND); bool mangleSubstitution(QualType T); @@ -440,16 +528,16 @@ bool mangleStandardSubstitution(const NamedDecl *ND); - void addSubstitution(const NamedDecl *ND) { + void addSubstitution(const SubstitutionScope &S, const NamedDecl *ND) { ND = cast(ND->getCanonicalDecl()); - addSubstitution(reinterpret_cast(ND)); + addSubstitution(S, reinterpret_cast(ND)); } - void addSubstitution(QualType T); - void addSubstitution(TemplateName Template); - void addSubstitution(uintptr_t Ptr); + void addSubstitution(const SubstitutionScope &S, QualType T); + void addSubstitution(const SubstitutionScope &S, TemplateName Template); + void addSubstitution(const SubstitutionScope &S, uintptr_t Ptr); // Destructive copy substitutions from other mangler. - void extendSubstitutions(CXXNameMangler* Other); + void extendSubstitutions(CXXNameMangler *Other); void mangleUnresolvedPrefix(NestedNameSpecifier *qualifier, bool recursive = false); @@ -662,6 +750,9 @@ } void CXXNameMangler::mangleFunctionEncoding(GlobalDecl GD) { + // Track that we're in this encoding scope. + EncodingScope Scope(*this); + const FunctionDecl *FD = cast(GD.getDecl()); // ::= @@ -976,6 +1067,7 @@ // ::= if (mangleSubstitution(ND)) return; + SubstitutionScope Subst(*this); // ::= if (const auto *TTP = dyn_cast(ND)) { @@ -988,7 +1080,7 @@ mangleUnscopedName(GD.getWithDecl(ND->getTemplatedDecl()), AdditionalAbiTags); } - addSubstitution(ND); + addSubstitution(Subst, ND); } void CXXNameMangler::mangleUnscopedTemplateName( @@ -1000,6 +1092,7 @@ if (mangleSubstitution(Template)) return; + SubstitutionScope Subst(*this); assert(!AdditionalAbiTags && "dependent template name cannot have abi tags"); @@ -1011,7 +1104,7 @@ else mangleOperatorName(Dependent->getOperator(), UnknownArity); - addSubstitution(Template); + addSubstitution(Subst, Template); } void CXXNameMangler::mangleFloat(const llvm::APFloat &f) { @@ -1098,17 +1191,19 @@ void CXXNameMangler::manglePrefix(QualType type) { if (const auto *TST = type->getAs()) { if (!mangleSubstitution(QualType(TST, 0))) { + SubstitutionScope Subst(*this); mangleTemplatePrefix(TST->getTemplateName()); // 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()); - addSubstitution(QualType(TST, 0)); + addSubstitution(Subst, QualType(TST, 0)); } } else if (const auto *DTST = type->getAs()) { if (!mangleSubstitution(QualType(DTST, 0))) { + SubstitutionScope Subst(*this); TemplateName Template = getASTContext().getDependentTemplateName( DTST->getQualifier(), DTST->getIdentifier()); mangleTemplatePrefix(Template); @@ -1117,7 +1212,7 @@ // the template in question is a dependent template name. Should we // emulate that badness? mangleTemplateArgs(DTST->getArgs(), DTST->getNumArgs()); - addSubstitution(QualType(DTST, 0)); + addSubstitution(Subst, QualType(DTST, 0)); } } else { // We use the QualType mangle type variant here because it handles @@ -1928,6 +2023,7 @@ const NamedDecl *ND = cast(DC); if (mangleSubstitution(ND)) return; + SubstitutionScope Subst(*this); // Check if we have a template. const TemplateArgumentList *TemplateArgs = nullptr; @@ -1939,7 +2035,7 @@ mangleUnqualifiedName(ND, nullptr); } - addSubstitution(ND); + addSubstitution(Subst, ND); } void CXXNameMangler::mangleTemplatePrefix(TemplateName Template) { @@ -1977,6 +2073,7 @@ if (mangleSubstitution(ND)) return; + SubstitutionScope Subst(*this); // ::= if (const auto *TTP = dyn_cast(ND)) { @@ -1989,7 +2086,7 @@ mangleUnqualifiedName(GD.getWithDecl(ND->getTemplatedDecl()), nullptr); } - addSubstitution(ND); + addSubstitution(Subst, ND); } /// Mangles a template name under the production . Required for @@ -2000,6 +2097,7 @@ void CXXNameMangler::mangleType(TemplateName TN) { if (mangleSubstitution(TN)) return; + SubstitutionScope Subst(*this); TemplateDecl *TD = nullptr; @@ -2055,7 +2153,7 @@ } } - addSubstitution(TN); + addSubstitution(Subst, TN); } bool CXXNameMangler::mangleUnresolvedTypeOrSimpleId(QualType Ty, @@ -2571,6 +2669,7 @@ isTypeSubstitutable(quals, ty, Context.getASTContext()); if (isSubstitutable && mangleSubstitution(T)) return; + SubstitutionScope Subst(*this); // If we're mangling a qualified array type, push the qualifiers to // the element type. @@ -2612,7 +2711,7 @@ // Add the substitution. if (isSubstitutable) - addSubstitution(T); + addSubstitution(Subst, T); } void CXXNameMangler::mangleNameOrStandardSubstitution(const NamedDecl *ND) { @@ -3450,6 +3549,7 @@ } else { if (mangleSubstitution(QualType(T, 0))) return; + SubstitutionScope Subst(*this); mangleTemplatePrefix(T->getTemplateName()); @@ -3457,7 +3557,7 @@ // the template in question is a dependent template name. Should we // emulate that badness? mangleTemplateArgs(T->getArgs(), T->getNumArgs()); - addSubstitution(QualType(T, 0)); + addSubstitution(Subst, QualType(T, 0)); } } @@ -4639,6 +4739,10 @@ Out << (parmIndex - 1); } Out << '_'; + + // A reference to a function parameter is a reference to a property of the + // . + noteReferenceToEncoding(); } void CXXNameMangler::mangleCXXCtorType(CXXCtorType T, @@ -4820,6 +4924,12 @@ if (Index != 0) Out << (Index - 1); Out << '_'; + + // Make a note that this is a reference to a parameter of the innermost + // ; substitutions referring to it can only be used within that + // same . + // See https://github.com/itanium-cxx-abi/cxx-abi/issues/106 + noteReferenceToEncoding(); } void CXXNameMangler::mangleSeqID(unsigned SeqID) { @@ -4888,11 +4998,22 @@ } bool CXXNameMangler::mangleSubstitution(uintptr_t Ptr) { - llvm::DenseMap::iterator I = Substitutions.find(Ptr); + auto I = Substitutions.find(Ptr); if (I == Substitutions.end()) return false; - unsigned SeqID = I->second; + // Check this substitution is usable from this scope. + if (unsigned Scope = I->second.EncodingScope) { + // In Clang 10 and before, we permitted substitutions to refer to unrelated + // parameters from distinct s that happened to have the same + // depth and index. + if (Context.getASTContext().getLangOpts().getClangABICompat() > + LangOptions::ClangABI::Ver10 && + !inEncodingScope(Scope)) + return false; + } + + unsigned SeqID = I->second.SeqID; Out << 'S'; mangleSeqID(SeqID); @@ -5031,37 +5152,44 @@ return false; } -void CXXNameMangler::addSubstitution(QualType T) { +void CXXNameMangler::addSubstitution(const SubstitutionScope &S, QualType T) { if (!hasMangledSubstitutionQualifiers(T)) { if (const RecordType *RT = T->getAs()) { - addSubstitution(RT->getDecl()); + addSubstitution(S, RT->getDecl()); return; } } uintptr_t TypePtr = reinterpret_cast(T.getAsOpaquePtr()); - addSubstitution(TypePtr); + addSubstitution(S, TypePtr); } -void CXXNameMangler::addSubstitution(TemplateName Template) { +void CXXNameMangler::addSubstitution(const SubstitutionScope &S, + TemplateName Template) { if (TemplateDecl *TD = Template.getAsTemplateDecl()) - return addSubstitution(TD); + return addSubstitution(S, TD); Template = Context.getASTContext().getCanonicalTemplateName(Template); - addSubstitution(reinterpret_cast(Template.getAsVoidPointer())); + addSubstitution(S, reinterpret_cast(Template.getAsVoidPointer())); } -void CXXNameMangler::addSubstitution(uintptr_t Ptr) { - assert(!Substitutions.count(Ptr) && "Substitution already exists!"); - Substitutions[Ptr] = SeqID++; +void CXXNameMangler::addSubstitution(const SubstitutionScope &S, + uintptr_t Ptr) { + assert((!Substitutions.count(Ptr) || + !inEncodingScope(Substitutions[Ptr].EncodingScope)) && + "Substitution already exists!"); + Substitutions[Ptr] = {SeqID++, S.InnermostEncodingScope}; } -void CXXNameMangler::extendSubstitutions(CXXNameMangler* Other) { +void CXXNameMangler::extendSubstitutions(CXXNameMangler *Other) { assert(Other->SeqID >= SeqID && "Must be superset of substitutions!"); if (Other->SeqID > SeqID) { Substitutions.swap(Other->Substitutions); SeqID = Other->SeqID; } + assert(Other->EncodingScopes >= EncodingScopes && + "Must be superset of encoding scopes!"); + EncodingScopes = Other->EncodingScopes; } CXXNameMangler::AbiTagList diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -3406,6 +3406,8 @@ Opts.setClangABICompat(LangOptions::ClangABI::Ver7); else if (Major <= 9) Opts.setClangABICompat(LangOptions::ClangABI::Ver9); + else if (Major <= 10) + Opts.setClangABICompat(LangOptions::ClangABI::Ver10); } else if (Ver != "latest") { Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << A->getValue(); diff --git a/clang/test/CodeGenCXX/mangle-abi-tag.cpp b/clang/test/CodeGenCXX/mangle-abi-tag.cpp --- a/clang/test/CodeGenCXX/mangle-abi-tag.cpp +++ b/clang/test/CodeGenCXX/mangle-abi-tag.cpp @@ -225,7 +225,9 @@ template void g(F); template auto h(A ...a)->decltype (g (0, g < a > (a) ...)) { } -// CHECK-DAG: define {{.*}} @_ZN7pr304401hIJEEEDTcl1gLi0Espcl1gIL_ZZNS_1hEDpT_E1aEEfp_EEES2_( +// FIXME: This mangling is wrong. We should never refer to a function parameter by . +// Should be: @_ZN7pr304401hIJEEEDTcl1gLi0Espcl1gIXfp_EEfp_EEEDpT_ +// CHECK-DAG: define {{.*}} @_ZN7pr304401hIJEEEDTcl1gLi0Espcl1gIL_ZZNS_1hEDpT_E1aEEfp_EEEDpT_( void pr30440_test () { h(); diff --git a/clang/test/CodeGenCXX/mangle-local-substitutions.cpp b/clang/test/CodeGenCXX/mangle-local-substitutions.cpp new file mode 100644 --- /dev/null +++ b/clang/test/CodeGenCXX/mangle-local-substitutions.cpp @@ -0,0 +1,27 @@ +// RUN: %clang_cc1 -std=c++20 %s -emit-llvm -o - -triple x86_64-linux-gnu | FileCheck %s --check-prefix=CHECK-NEW +// RUN: %clang_cc1 -std=c++20 %s -emit-llvm -o - -triple x86_64-linux-gnu -fclang-abi-compat=10 | FileCheck %s --check-prefix=CHECK-OLD + +namespace multiple_encodings { + template auto f(T a, decltype(a)) { struct A {}; return A(); } + template auto g(T b, decltype(b)) { struct B {}; return B(); } + using A = decltype(f(0, 0)); + using B = decltype(g(0.0, 0.0)); + template struct X {}; + // Note that we do not use backreferences for the repeated T_ and DtfL1p_E + // here; they are symbolically different because they refer to parameters of + // different function template specializiations. + // CHECK-NEW: define {{.*}}@_ZN18multiple_encodings1hENS_1XIJZNS_1fIiEEDaT_DtfL1p_EE1AZNS_1gIdEEDaT_DtfL1p_EE1BEEE( + // CHECK-OLD: define {{.*}}@_ZN18multiple_encodings1hENS_1XIJZNS_1fIiEEDaT_DtfL1p_EE1AZNS_1gIdEEDaS2_S3_E1BEEE( + void h(X) {} +} + +namespace multiple_lambdas { + template struct X { X(T f) { f(0); } template void operator()(U...); }; + template void f(T&&) { X{[](auto &&, auto...){}}(); } + // Note that we use OT_ for both lambdas here, rather than using a + // substitution for the second OT_. These are references to distinct template + // parameters, so are not substitutable. + // CHECK-NEW: call {{.*}}_ZN16multiple_lambdas1XIZNS_1fIiEEvOT_EUlOT_DpT0_E_EclIJEEEvDpT_( + // CHECK-OLD: call {{.*}}_ZN16multiple_lambdas1XIZNS_1fIiEEvOT_EUlS3_DpT0_E_EclIJEEEvDpT_( + void g() { f(0); } +}