[clang] [clang] Fix handling of explicit-`this` functions as template arguments (PR #133748)
via cfe-commits
cfe-commits at lists.llvm.org
Mon Mar 31 09:44:48 PDT 2025
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 at H@X at GH106660@@SAH_VH at Z@GH106660@@YAXXZ"
+ f1<&X::f<int>>();
+ // CHECK-NEXT: call void @_ZN8GH1066602f1ITnDaXadL_ZNHS_1X1fEiEEEEvv
+ // MS-NEXT: call void @"??$f1@$1?f at X@GH106660@@SAH_VH at 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 at H@X at GH106660@@SAH_VH at Z@GH106660@@YAXXZ"
+ f2<*&X::f<int>>();
+ // CHECK-NEXT: call void @_ZN8GH1066602f2ITnRDaL_ZNHS_1X1fEiEEEvv
+ // MS-NEXT: call void @"??$f2@$1?f at X@GH106660@@SAH_VH at 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 at H@X at GH106660@@SAH_VH at Z@GH106660@@YAXXZ"
+ f3<&X::f<int>>();
+ // CHECK-NEXT: call void @_ZN8GH1066602f3IXadL_ZNHS_1X1fEiEEEEvv
+ // MS-NEXT: call void @"??$f3@$1?f at X@GH106660@@SAH_VH at 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 at H@X at GH106660@@SAH_VH at Z@GH106660@@YAXXZ"
+ f4<*&X::f<int>>();
+ // CHECK-NEXT: call void @_ZN8GH1066602f4IL_ZNHS_1X1fEiEEEvv
+ // MS-NEXT: call void @"??$f4@$1?f at X@GH106660@@SAH_VH at 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
More information about the cfe-commits
mailing list