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
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
  • [PATCH] D83647: D... Richard Smith - zygoloid via Phabricator via cfe-commits

Reply via email to