llvmbot wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang

Author: None (offsetof)

<details>
<summary>Changes</summary>

* In `Sema::BuildExpressionFromDeclTemplateArgument`, qualify names of explicit 
object member functions, and treat them as lvalues when the parameter is a 
reference.
* Mangle explicit object member functions appearing as template arguments same 
as static member functions. (This fixes an assertion failure/incorrect mangling 
for Itanium ABI and a crash when mangling for MS ABI.)

Fixes #<!-- -->106660

---
Full diff: https://github.com/llvm/llvm-project/pull/133748.diff


6 Files Affected:

- (modified) clang/docs/ReleaseNotes.rst (+1) 
- (modified) clang/lib/AST/ItaniumMangle.cpp (+3-1) 
- (modified) clang/lib/AST/MicrosoftMangle.cpp (+1-1) 
- (modified) clang/lib/Sema/SemaTemplate.cpp (+15-3) 
- (added) clang/test/CodeGenCXX/mangle-ms-deducing-this.cpp (+46) 
- (modified) clang/test/SemaCXX/cxx2b-deducing-this.cpp (+39) 


``````````diff
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index daad01919ecd4..86c8e9e64b158 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -374,6 +374,7 @@ Bug Fixes to C++ Support
 - Clang no longer crashes when establishing subsumption between some 
constraint expressions. (#GH122581)
 - Clang now issues an error when placement new is used to modify a 
const-qualified variable
   in a ``constexpr`` function. (#GH131432)
+- Fixed some issues related to the use of (pointers to) explicit object member 
functions as template arguments. (#GH106660)
 
 Bug Fixes to AST Handling
 ^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp
index 49a04861ae25d..3371dd9d65185 100644
--- a/clang/lib/AST/ItaniumMangle.cpp
+++ b/clang/lib/AST/ItaniumMangle.cpp
@@ -6279,7 +6279,9 @@ void CXXNameMangler::mangleTemplateArg(TemplateArgument 
A, bool NeedExactType) {
 
     ASTContext &Ctx = Context.getASTContext();
     APValue Value;
-    if (D->isCXXInstanceMember())
+    if (auto *Method = dyn_cast<CXXMethodDecl>(D);
+        Method ? Method->isImplicitObjectMemberFunction()
+               : D->isCXXInstanceMember())
       // Simple pointer-to-member with no conversion.
       Value = APValue(D, /*IsDerivedMember=*/false, /*Path=*/{});
     else if (D->getType()->isArrayType() &&
diff --git a/clang/lib/AST/MicrosoftMangle.cpp 
b/clang/lib/AST/MicrosoftMangle.cpp
index 7e964124a9fec..28aea62905fe4 100644
--- a/clang/lib/AST/MicrosoftMangle.cpp
+++ b/clang/lib/AST/MicrosoftMangle.cpp
@@ -1805,7 +1805,7 @@ void MicrosoftCXXNameMangler::mangleTemplateArg(const 
TemplateDecl *TD,
                               TA.getParamTypeForDecl());
     } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)) {
       const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD);
-      if (MD && MD->isInstance()) {
+      if (MD && MD->isImplicitObjectMemberFunction()) {
         mangleMemberFunctionPointer(
             MD->getParent()->getMostRecentNonInjectedDecl(), MD,
             cast<NonTypeTemplateParmDecl>(Parm), TA.getParamTypeForDecl());
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index be81b6a46b2c0..2bf94d10f5f8a 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -7518,9 +7518,9 @@ ExprResult Sema::BuildExpressionFromDeclTemplateArgument(
   ValueDecl *VD = Arg.getAsDecl();
 
   CXXScopeSpec SS;
-  if (ParamType->isMemberPointerType()) {
-    // If this is a pointer to member, we need to use a qualified name to
-    // form a suitable pointer-to-member constant.
+  if (VD->isCXXInstanceMember()) {
+    // If this is a non-static member, we need to use a qualified name to
+    // form a suitable pointer or pointer-to-member expression.
     assert(VD->getDeclContext()->isRecord() &&
            (isa<CXXMethodDecl>(VD) || isa<FieldDecl>(VD) ||
             isa<IndirectFieldDecl>(VD)));
@@ -7558,6 +7558,18 @@ ExprResult Sema::BuildExpressionFromDeclTemplateArgument(
   } else {
     assert(ParamType->isReferenceType() &&
            "unexpected type for decl template argument");
+
+    if (auto *Method = dyn_cast<CXXMethodDecl>(VD);
+        Method && Method->isExplicitObjectMemberFunction()) {
+      // If the argument is an explicit object member function,
+      // RefExpr is currently a prvalue. Make it an lvalue.
+      RefExpr = ImplicitCastExpr::Create(
+          Context, RefExpr.get()->getType(), CK_NoOp, RefExpr.get(),
+          /*BasePath=*/nullptr, VK_LValue, /*FPO=*/{});
+      if (RefExpr.isInvalid())
+        return ExprError();
+    }
+
     if (NonTypeTemplateParmDecl *NTTP =
             dyn_cast_if_present<NonTypeTemplateParmDecl>(TemplateParam)) {
       QualType TemplateParamType = NTTP->getType();
diff --git a/clang/test/CodeGenCXX/mangle-ms-deducing-this.cpp 
b/clang/test/CodeGenCXX/mangle-ms-deducing-this.cpp
new file mode 100644
index 0000000000000..fb36cc914eb9b
--- /dev/null
+++ b/clang/test/CodeGenCXX/mangle-ms-deducing-this.cpp
@@ -0,0 +1,46 @@
+// RUN: %clang_cc1 %s -std=c++23 -triple=x86_64-linux -emit-llvm -o - | 
FileCheck %s
+// RUN: %clang_cc1 %s -std=c++23 -triple=x86_64-win32 -emit-llvm -o - | 
FileCheck %s --check-prefix MS
+
+namespace GH106660 {
+
+template<auto> void f1();
+template<auto&> void f2();
+template<int (*)(int)> void f3();
+template<int (&)(int)> void f4();
+
+struct X {
+    int f(this auto);
+    int f(this int);
+};
+
+void test() {
+    // CHECK: call void @_ZN8GH1066602f1ITnDaXadL_ZNHS_1X1fIiEEiT_EEEEvv
+    // MS: call void @"??$f1@$1??$f@H@X@GH106660@@SAH_VH@Z@GH106660@@YAXXZ"
+    f1<&X::f<int>>();
+    // CHECK-NEXT: call void @_ZN8GH1066602f1ITnDaXadL_ZNHS_1X1fEiEEEEvv
+    // MS-NEXT: call void @"??$f1@$1?f@X@GH106660@@SAH_VH@Z@GH106660@@YAXXZ"
+    f1<static_cast<int (*)(int)>(&X::f)>();
+
+    // CHECK-NEXT: call void @_ZN8GH1066602f2ITnRDaL_ZNHS_1X1fIiEEiT_EEEvv
+    // MS-NEXT: call void 
@"??$f2@$1??$f@H@X@GH106660@@SAH_VH@Z@GH106660@@YAXXZ"
+    f2<*&X::f<int>>();
+    // CHECK-NEXT: call void @_ZN8GH1066602f2ITnRDaL_ZNHS_1X1fEiEEEvv
+    // MS-NEXT: call void @"??$f2@$1?f@X@GH106660@@SAH_VH@Z@GH106660@@YAXXZ"
+    f2<*static_cast<int (*)(int)>(&X::f)>();
+
+    // CHECK-NEXT: call void @_ZN8GH1066602f3IXadL_ZNHS_1X1fIiEEiT_EEEEvv
+    // MS-NEXT: call void 
@"??$f3@$1??$f@H@X@GH106660@@SAH_VH@Z@GH106660@@YAXXZ"
+    f3<&X::f<int>>();
+    // CHECK-NEXT: call void @_ZN8GH1066602f3IXadL_ZNHS_1X1fEiEEEEvv
+    // MS-NEXT: call void @"??$f3@$1?f@X@GH106660@@SAH_VH@Z@GH106660@@YAXXZ"
+    f3<static_cast<int (*)(int)>(&X::f)>();
+
+    // CHECK-NEXT: call void @_ZN8GH1066602f4IL_ZNHS_1X1fIiEEiT_EEEvv
+    // MS-NEXT: call void 
@"??$f4@$1??$f@H@X@GH106660@@SAH_VH@Z@GH106660@@YAXXZ"
+    f4<*&X::f<int>>();
+    // CHECK-NEXT: call void @_ZN8GH1066602f4IL_ZNHS_1X1fEiEEEvv
+    // MS-NEXT: call void @"??$f4@$1?f@X@GH106660@@SAH_VH@Z@GH106660@@YAXXZ"
+    f4<*static_cast<int (*)(int)>(&X::f)>();
+}
+
+} // namespace GH106660
diff --git a/clang/test/SemaCXX/cxx2b-deducing-this.cpp 
b/clang/test/SemaCXX/cxx2b-deducing-this.cpp
index 6f17ce7275456..570a3e9953bf1 100644
--- a/clang/test/SemaCXX/cxx2b-deducing-this.cpp
+++ b/clang/test/SemaCXX/cxx2b-deducing-this.cpp
@@ -1118,6 +1118,45 @@ struct C4 {
 };
 }
 
+namespace GH106660 {
+
+template<auto X> constexpr int A = X(1);
+template<auto& X> constexpr int Ar = X(2);
+template<int (*X)(int)> constexpr int B = X(3);
+template<int (&X)(int)> constexpr int Br = X(4);
+template<auto X> using C = decltype(X(1));
+template<auto& X> using Cr = decltype(X(2));
+template<int (*X)(int)> using D = decltype(X(3));
+template<int (&X)(int)> using Dr = decltype(X(4));
+template<auto X> using E = decltype((X));
+template<auto& X> using Er = decltype((X));
+template<int (*X)(int)> using F = decltype((X));
+template<int (&X)(int)> using Fr = decltype((X));
+
+struct S {
+  constexpr int f(this int i) noexcept {
+    return i * 2;
+  }
+};
+
+static_assert(A<&S::f> == 2);
+static_assert(Ar<*&S::f> == 4);
+static_assert(B<&S::f> == 6);
+static_assert(Br<*&S::f> == 8);
+
+using W = C<&S::f>;
+using X = Cr<*&S::f>;
+using Y = D<&S::f>;
+using Z = Dr<*&S::f>;
+
+template<class> class R {};
+R<int (*)(int) noexcept> w = R<E<&S::f>>();
+R<int (&)(int) noexcept> x = R<Er<*&S::f>>();
+R<int (*)(int)> y = R<F<&S::f>>();
+R<int (&)(int)> z = R<Fr<*&S::f>>();
+
+
+} // namespace GH106660
 
 namespace GH112559 {
 struct Wrap  {};

``````````

</details>


https://github.com/llvm/llvm-project/pull/133748
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to