rsmith created this revision.
rsmith added a reviewer: rjmccall.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.
Per the ABI rules, substitutable components are symbolic constructs, not
the associated mangling character strings, so references to function
parameters or template parameters of distinct <encoding>s should not be
considered substitutable even if they're at the same depth / index.
See https://github.com/itanium-cxx-abi/cxx-abi/issues/106.
This change can be turned off by setting -fclang-abi-compat to 10 or
earlier.
Repository:
rG LLVM Github Monorepo
https://reviews.llvm.org/D83647
Files:
clang/include/clang/Basic/LangOptions.h
clang/lib/AST/ItaniumMangle.cpp
clang/lib/Frontend/CompilerInvocation.cpp
clang/test/CodeGenCXX/mangle-abi-tag.cpp
clang/test/CodeGenCXX/mangle-local-substitutions.cpp
Index: clang/test/CodeGenCXX/mangle-local-substitutions.cpp
===================================================================
--- /dev/null
+++ 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<typename T> auto f(T a, decltype(a)) { struct A {}; return A(); }
+ template<typename T> 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<typename ...T> 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<A, B>) {}
+}
+
+namespace multiple_lambdas {
+ template<typename T> struct X { X(T f) { f(0); } template<typename ...U> void operator()(U...); };
+ template<typename T> 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); }
+}
Index: clang/test/CodeGenCXX/mangle-abi-tag.cpp
===================================================================
--- clang/test/CodeGenCXX/mangle-abi-tag.cpp
+++ clang/test/CodeGenCXX/mangle-abi-tag.cpp
@@ -225,7 +225,9 @@
template<class F> void g(F);
template<class ...A> 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 <local-name>.
+// Should be: @_ZN7pr304401hIJEEEDTcl1gLi0Espcl1gIXfp_EEfp_EEEDpT_
+// CHECK-DAG: define {{.*}} @_ZN7pr304401hIJEEEDTcl1gLi0Espcl1gIL_ZZNS_1hEDpT_E1aEEfp_EEEDpT_(
void pr30440_test () {
h();
Index: clang/lib/Frontend/CompilerInvocation.cpp
===================================================================
--- clang/lib/Frontend/CompilerInvocation.cpp
+++ 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();
Index: clang/lib/AST/ItaniumMangle.cpp
===================================================================
--- clang/lib/AST/ItaniumMangle.cpp
+++ clang/lib/AST/ItaniumMangle.cpp
@@ -377,7 +377,11 @@
AbiTagState *AbiTags = nullptr;
AbiTagState AbiTagsRoot;
- llvm::DenseMap<uintptr_t, unsigned> Substitutions;
+ struct Substitution {
+ unsigned SeqID;
+ unsigned EncodingScope;
+ };
+ llvm::DenseMap<uintptr_t, Substitution> Substitutions;
llvm::DenseMap<StringRef, unsigned> 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<typename T> T *getAs() {
+ return K == T::StaticKind ? static_cast<T*>(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 <encoding>.
+ 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<EncodingScope>()) {
+ if (ES->ScopeID == I) return true;
+ if (ES->ScopeID < I) return false;
+ }
+ }
+ return false;
+ }
+
+ /// Note that we made reference to part of the enclosing <encoding>. In
+ /// particular, this means that any substitutions within that <encoding>
+ /// cannot be used from outside it.
+ void noteReferenceToEncoding() {
+ unsigned InnermostEncodingScope = 0;
+ for (ManglingScope *S = InnermostScope; S; S = S->Parent) {
+ if (EncodingScope *ES = S->getAs<EncodingScope>()) {
+ InnermostEncodingScope = ES->ScopeID;
+ break;
+ }
+ }
+ for (ManglingScope *S = InnermostScope; S; S = S->Parent) {
+ if (S->getAs<EncodingScope>())
+ break;
+ if (SubstitutionScope *SS = S->getAs<SubstitutionScope>())
+ 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<NamedDecl>(ND->getCanonicalDecl());
- addSubstitution(reinterpret_cast<uintptr_t>(ND));
+ addSubstitution(S, reinterpret_cast<uintptr_t>(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<FunctionDecl>(GD.getDecl());
// <encoding> ::= <function name> <bare-function-type>
@@ -976,6 +1067,7 @@
// ::= <substitution>
if (mangleSubstitution(ND))
return;
+ SubstitutionScope Subst(*this);
// <template-template-param> ::= <template-param>
if (const auto *TTP = dyn_cast<TemplateTemplateParmDecl>(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<TemplateSpecializationType>()) {
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<DependentTemplateSpecializationType>()) {
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<NamedDecl>(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);
// <template-template-param> ::= <template-param>
if (const auto *TTP = dyn_cast<TemplateTemplateParmDecl>(ND)) {
@@ -1989,7 +2086,7 @@
mangleUnqualifiedName(GD.getWithDecl(ND->getTemplatedDecl()), nullptr);
}
- addSubstitution(ND);
+ addSubstitution(Subst, ND);
}
/// Mangles a template name under the production <type>. 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
+ // <encoding>.
+ 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
+ // <encoding>; substitutions referring to it can only be used within that
+ // same <encoding>.
+ // 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<uintptr_t, unsigned>::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 <encoding>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<RecordType>()) {
- addSubstitution(RT->getDecl());
+ addSubstitution(S, RT->getDecl());
return;
}
}
uintptr_t TypePtr = reinterpret_cast<uintptr_t>(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<uintptr_t>(Template.getAsVoidPointer()));
+ addSubstitution(S, reinterpret_cast<uintptr_t>(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
Index: clang/include/clang/Basic/LangOptions.h
===================================================================
--- clang/include/clang/Basic/LangOptions.h
+++ 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
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits