[clang] [libcxxabi] [clang][ItaniumMangle] Mangle friend function templates with a constr… (PR #110247)

Viktoriia Bakalova via cfe-commits cfe-commits at lists.llvm.org
Fri Sep 27 08:23:24 PDT 2024


https://github.com/VitaNuo updated https://github.com/llvm/llvm-project/pull/110247

>From f8d897f5f3a89a5664e95a45948f9725101aa36f Mon Sep 17 00:00:00 2001
From: Viktoriia Bakalova <bakalova at google.com>
Date: Fri, 27 Sep 2024 11:33:17 +0000
Subject: [PATCH 1/3] [clang][ItaniumMangle] Mangle friend function templates
 with a constraint that depends on a template parameter from an enclosing
 template as members of the enclosing class.

Such function templates should be considered member-like constrained friends per [temp.friend]p9 and https://github.com/itanium-cxx-abi/cxx-abi/issues/24#issuecomment-934977198).
---
 clang/lib/AST/ItaniumMangle.cpp          | 8 ++++++++
 clang/test/CodeGenCXX/mangle-concept.cpp | 6 +++---
 libcxxabi/test/test_demangle.pass.cpp    | 6 +++---
 3 files changed, 14 insertions(+), 6 deletions(-)

diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp
index b6e1da0c3192da..172561f73b9a74 100644
--- a/clang/lib/AST/ItaniumMangle.cpp
+++ b/clang/lib/AST/ItaniumMangle.cpp
@@ -2270,6 +2270,14 @@ void CXXNameMangler::mangleTemplatePrefix(GlobalDecl GD,
     mangleTemplateParameter(TTP->getDepth(), TTP->getIndex());
   } else {
     const DeclContext *DC = Context.getEffectiveDeclContext(ND);
+    if (const auto *FD = dyn_cast<FunctionTemplateDecl>(GD.getDecl())) {
+      // Member-like constrained friends are mangled as if they were members of
+      // the enclosing class.
+      if (FD->getTemplatedDecl()->isMemberLikeConstrainedFriend() &&
+          getASTContext().getLangOpts().getClangABICompat() >
+              LangOptions::ClangABI::Ver17)
+      DC = GD.getDecl()->getLexicalDeclContext()->getRedeclContext();
+    }
     manglePrefix(DC, NoFunction);
     if (isa<BuiltinTemplateDecl>(ND) || isa<ConceptDecl>(ND))
       mangleUnqualifiedName(GD, DC, nullptr);
diff --git a/clang/test/CodeGenCXX/mangle-concept.cpp b/clang/test/CodeGenCXX/mangle-concept.cpp
index 91dc1b0e688e0d..6053511c00a7b5 100644
--- a/clang/test/CodeGenCXX/mangle-concept.cpp
+++ b/clang/test/CodeGenCXX/mangle-concept.cpp
@@ -58,19 +58,19 @@ namespace test2 {
     // CHECK: call {{.*}}@_ZN5test21AIiEF1fEzQ4TrueIT_E(
     // CLANG17: call {{.*}}@_ZN5test21fEz(
     f(ai);
-    // CHECK: call {{.*}}@_ZN5test2F1gIvEEvzQaa4TrueIT_E4TrueITL0__E(
+    // CHECK: call {{.*}}@_ZN5test21AIiEF1gIvEEvzQaa4TrueIT_E4TrueITL0__E(
     // CLANG17: call {{.*}}@_ZN5test21gIvEEvz(
     g(ai);
     // CHECK: call {{.*}}@_ZN5test21hIvEEvzQ4TrueITL0__E(
     // CLANG17: call {{.*}}@_ZN5test21hIvEEvz(
     h(ai);
-    // CHECK: call {{.*}}@_ZN5test2F1iIvQaa4TrueIT_E4TrueITL0__EEEvz(
+    // CHECK: call {{.*}}@_ZN5test21AIiEF1iIvQaa4TrueIT_E4TrueITL0__EEEvz(
     // CLANG17: call {{.*}}@_ZN5test21iIvEEvz(
     i(ai);
     // CHECK: call {{.*}}@_ZN5test21jIvQ4TrueITL0__EEEvz(
     // CLANG17: call {{.*}}@_ZN5test21jIvEEvz(
     j(ai);
-    // CHECK: call {{.*}}@_ZN5test2F1kITk4TruevQ4TrueIT_EEEvz(
+    // CHECK: call {{.*}}@_ZN5test21AIiEF1kITk4TruevQ4TrueIT_EEEvz(
     // CLANG17: call {{.*}}@_ZN5test21kIvEEvz(
     k(ai);
     // CHECK: call {{.*}}@_ZN5test21lITk4TruevEEvz(
diff --git a/libcxxabi/test/test_demangle.pass.cpp b/libcxxabi/test/test_demangle.pass.cpp
index 17786a3a486fcd..efe482aad1b76c 100644
--- a/libcxxabi/test/test_demangle.pass.cpp
+++ b/libcxxabi/test/test_demangle.pass.cpp
@@ -30128,11 +30128,11 @@ const char* cases[][2] =
     // C++20 concepts, see https://github.com/itanium-cxx-abi/cxx-abi/issues/24.
     {"_Z2f0IiE1SIX1CIT_EEEv", "S<C<int>> f0<int>()"},
     {"_ZN5test21AIiEF1fEzQ4TrueIT_E", "test2::A<int>::friend f(...) requires True<T>"},
-    {"_ZN5test2F1gIvEEvzQaa4TrueIT_E4TrueITL0__E", "void test2::friend g<void>(...) requires True<T> && True<TL0_>"},
+    {"_ZN5test21AIiEF1gIvEEvzQaa4TrueIT_E4TrueITL0__E", "void test2::A<int>::friend g<void>(...) requires True<T> && True<TL0_>"},
     {"_ZN5test21hIvEEvzQ4TrueITL0__E", "void test2::h<void>(...) requires True<TL0_>"},
-    {"_ZN5test2F1iIvQaa4TrueIT_E4TrueITL0__EEEvz", "void test2::friend i<void>(...)"},
+    {"_ZN5test21AIiEF1iIvQaa4TrueIT_E4TrueITL0__EEEvz", "void test2::A<int>::friend i<void>(...)"},
     {"_ZN5test21jIvQ4TrueITL0__EEEvz", "void test2::j<void>(...)"},
-    {"_ZN5test2F1kITk4TruevQ4TrueIT_EEEvz", "void test2::friend k<void>(...)"},
+    {"_ZN5test21AIiEF1kITk4TruevQ4TrueIT_EEEvz", "void test2::A<int>::friend k<void>(...)"},
     {"_ZN5test21lITk4TruevEEvz", "void test2::l<void>(...)"},
     {"_ZN5test31dITnDaLi0EEEvv", "void test3::d<0>()"},
     {"_ZN5test31eITnDcLi0EEEvv", "void test3::e<0>()"},

>From 7f61556ecdef242043e24a7f514fe8f80d559200 Mon Sep 17 00:00:00 2001
From: Viktoriia Bakalova <bakalova at google.com>
Date: Fri, 27 Sep 2024 11:42:04 +0000
Subject: [PATCH 2/3] fixup! [clang][ItaniumMangle] Mangle friend function
 templates with a constraint that depends on a template parameter from an
 enclosing template as members of the enclosing class.

---
 clang/lib/AST/ItaniumMangle.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp
index 172561f73b9a74..0e5963b91f3253 100644
--- a/clang/lib/AST/ItaniumMangle.cpp
+++ b/clang/lib/AST/ItaniumMangle.cpp
@@ -2276,7 +2276,7 @@ void CXXNameMangler::mangleTemplatePrefix(GlobalDecl GD,
       if (FD->getTemplatedDecl()->isMemberLikeConstrainedFriend() &&
           getASTContext().getLangOpts().getClangABICompat() >
               LangOptions::ClangABI::Ver17)
-      DC = GD.getDecl()->getLexicalDeclContext()->getRedeclContext();
+        DC = GD.getDecl()->getLexicalDeclContext()->getRedeclContext();
     }
     manglePrefix(DC, NoFunction);
     if (isa<BuiltinTemplateDecl>(ND) || isa<ConceptDecl>(ND))

>From cfc150dab0f515141e7e8fe0a8dae6a1e1586cbb Mon Sep 17 00:00:00 2001
From: Viktoriia Bakalova <bakalova at google.com>
Date: Fri, 27 Sep 2024 15:23:10 +0000
Subject: [PATCH 3/3] fixup! fixup! [clang][ItaniumMangle] Mangle friend
 function templates with a constraint that depends on a template parameter
 from an enclosing template as members of the enclosing class.

---
 clang/docs/ReleaseNotes.rst              |  1 +
 clang/lib/AST/ItaniumMangle.cpp          | 17 +++++++++--------
 clang/test/CodeGenCXX/mangle-concept.cpp | 23 +++++++++++++++++++++++
 libcxxabi/test/test_demangle.pass.cpp    |  4 ++++
 4 files changed, 37 insertions(+), 8 deletions(-)

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 14907e7db18de3..ae7f0bf062ae4a 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -426,6 +426,7 @@ Bug Fixes to C++ Support
 - Fixed an assertion failure in debug mode, and potential crashes in release mode, when
   diagnosing a failed cast caused indirectly by a failed implicit conversion to the type of the constructor parameter.
 - Fixed an assertion failure by adjusting integral to boolean vector conversions (#GH108326)
+- Fixed mangling of friend function templates with a constraint that depends on a template parameter from an enclosing template. (#GH110247)
 
 Bug Fixes to AST Handling
 ^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp
index 0e5963b91f3253..31a766d8bb0597 100644
--- a/clang/lib/AST/ItaniumMangle.cpp
+++ b/clang/lib/AST/ItaniumMangle.cpp
@@ -704,6 +704,15 @@ ItaniumMangleContextImpl::getEffectiveDeclContext(const Decl *D) {
       return D->getLexicalDeclContext()->getRedeclContext();
   }
 
+  if (const auto *FTD = dyn_cast<FunctionTemplateDecl>(D)) {
+    // Member-like constrained friends are mangled as if they were members of
+    // the enclosing class.
+    if (FTD->getTemplatedDecl()->isMemberLikeConstrainedFriend() &&
+        getASTContext().getLangOpts().getClangABICompat() >
+            LangOptions::ClangABI::Ver17)
+      return D->getLexicalDeclContext()->getRedeclContext();
+  }
+
   return DC->getRedeclContext();
 }
 
@@ -2270,14 +2279,6 @@ void CXXNameMangler::mangleTemplatePrefix(GlobalDecl GD,
     mangleTemplateParameter(TTP->getDepth(), TTP->getIndex());
   } else {
     const DeclContext *DC = Context.getEffectiveDeclContext(ND);
-    if (const auto *FD = dyn_cast<FunctionTemplateDecl>(GD.getDecl())) {
-      // Member-like constrained friends are mangled as if they were members of
-      // the enclosing class.
-      if (FD->getTemplatedDecl()->isMemberLikeConstrainedFriend() &&
-          getASTContext().getLangOpts().getClangABICompat() >
-              LangOptions::ClangABI::Ver17)
-        DC = GD.getDecl()->getLexicalDeclContext()->getRedeclContext();
-    }
     manglePrefix(DC, NoFunction);
     if (isa<BuiltinTemplateDecl>(ND) || isa<ConceptDecl>(ND))
       mangleUnqualifiedName(GD, DC, nullptr);
diff --git a/clang/test/CodeGenCXX/mangle-concept.cpp b/clang/test/CodeGenCXX/mangle-concept.cpp
index 6053511c00a7b5..966117544bfec1 100644
--- a/clang/test/CodeGenCXX/mangle-concept.cpp
+++ b/clang/test/CodeGenCXX/mangle-concept.cpp
@@ -52,6 +52,7 @@ namespace test2 {
   };
 
   A<int> ai;
+  A<bool> aj;
 
   // CHECK-LABEL: define {{.*}}@{{.*}}test2{{.*}}use
   void use() {
@@ -76,6 +77,28 @@ namespace test2 {
     // CHECK: call {{.*}}@_ZN5test21lITk4TruevEEvz(
     // CLANG17: call {{.*}}@_ZN5test21lIvEEvz(
     l(ai);
+
+    // CHECK: call {{.*}}@_ZN5test21AIbEF1fEzQ4TrueIT_E(
+    // CLANG17: call {{.*}}@_ZN5test21fEz(
+    f(aj);
+    // CHECK: call {{.*}}@_ZN5test21AIbEF1gIvEEvzQaa4TrueIT_E4TrueITL0__E(
+    // CLANG17: call {{.*}}@_ZN5test21gIvEEvz(
+    g(aj);
+    // CHECK: call {{.*}}@_ZN5test21hIvEEvzQ4TrueITL0__E(
+    // CLANG17: call {{.*}}@_ZN5test21hIvEEvz(
+    h(aj);
+    // CHECK: call {{.*}}@_ZN5test21AIbEF1iIvQaa4TrueIT_E4TrueITL0__EEEvz(
+    // CLANG17: call {{.*}}@_ZN5test21iIvEEvz(
+    i(aj);
+    // CHECK: call {{.*}}@_ZN5test21jIvQ4TrueITL0__EEEvz(
+    // CLANG17: call {{.*}}@_ZN5test21jIvEEvz(
+    j(aj);
+    // CHECK: call {{.*}}@_ZN5test21AIbEF1kITk4TruevQ4TrueIT_EEEvz(
+    // CLANG17: call {{.*}}@_ZN5test21kIvEEvz(
+    k(aj);
+    // CHECK: call {{.*}}@_ZN5test21lITk4TruevEEvz(
+    // CLANG17: call {{.*}}@_ZN5test21lIvEEvz(
+    l(aj);
   }
 }
 
diff --git a/libcxxabi/test/test_demangle.pass.cpp b/libcxxabi/test/test_demangle.pass.cpp
index efe482aad1b76c..eb32b4679aff0c 100644
--- a/libcxxabi/test/test_demangle.pass.cpp
+++ b/libcxxabi/test/test_demangle.pass.cpp
@@ -30128,11 +30128,15 @@ const char* cases[][2] =
     // C++20 concepts, see https://github.com/itanium-cxx-abi/cxx-abi/issues/24.
     {"_Z2f0IiE1SIX1CIT_EEEv", "S<C<int>> f0<int>()"},
     {"_ZN5test21AIiEF1fEzQ4TrueIT_E", "test2::A<int>::friend f(...) requires True<T>"},
+    {"_ZN5test21AIbEF1fEzQ4TrueIT_E", "test2::A<bool>::friend f(...) requires True<T>"},
     {"_ZN5test21AIiEF1gIvEEvzQaa4TrueIT_E4TrueITL0__E", "void test2::A<int>::friend g<void>(...) requires True<T> && True<TL0_>"},
+    {"_ZN5test21AIbEF1gIvEEvzQaa4TrueIT_E4TrueITL0__E", "void test2::A<bool>::friend g<void>(...) requires True<T> && True<TL0_>"},
     {"_ZN5test21hIvEEvzQ4TrueITL0__E", "void test2::h<void>(...) requires True<TL0_>"},
     {"_ZN5test21AIiEF1iIvQaa4TrueIT_E4TrueITL0__EEEvz", "void test2::A<int>::friend i<void>(...)"},
+    {"_ZN5test21AIbEF1iIvQaa4TrueIT_E4TrueITL0__EEEvz", "void test2::A<bool>::friend i<void>(...)"},
     {"_ZN5test21jIvQ4TrueITL0__EEEvz", "void test2::j<void>(...)"},
     {"_ZN5test21AIiEF1kITk4TruevQ4TrueIT_EEEvz", "void test2::A<int>::friend k<void>(...)"},
+    {"_ZN5test21AIbEF1kITk4TruevQ4TrueIT_EEEvz", "void test2::A<bool>::friend k<void>(...)"},
     {"_ZN5test21lITk4TruevEEvz", "void test2::l<void>(...)"},
     {"_ZN5test31dITnDaLi0EEEvv", "void test3::d<0>()"},
     {"_ZN5test31eITnDcLi0EEEvv", "void test3::e<0>()"},



More information about the cfe-commits mailing list