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(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(ND)) { const CXXMethodDecl *MD = dyn_cast(FD); - if (MD && MD->isInstance()) { + if (MD && MD->isImplicitObjectMemberFunction()) { mangleMemberFunctionPointer( MD->getParent()->getMostRecentNonInjectedDecl(), MD, cast(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(VD) || isa(VD) || isa(VD))); @@ -7558,6 +7558,18 @@ ExprResult Sema::BuildExpressionFromDeclTemplateArgument( } else { assert(ParamType->isReferenceType() && "unexpected type for decl template argument"); + + if (auto *Method = dyn_cast(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(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 void f1(); +template void f2(); +template void f3(); +template 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>(); + // CHECK-NEXT: call void @_ZN8GH1066602f1ITnDaXadL_ZNHS_1X1fEiEEEEvv + // MS-NEXT: call void @"??$f1@$1?f@X@GH106660@@SAH_VH@Z@GH106660@@YAXXZ" + f1(&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>(); + // CHECK-NEXT: call void @_ZN8GH1066602f2ITnRDaL_ZNHS_1X1fEiEEEvv + // MS-NEXT: call void @"??$f2@$1?f@X@GH106660@@SAH_VH@Z@GH106660@@YAXXZ" + f2<*static_cast(&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>(); + // CHECK-NEXT: call void @_ZN8GH1066602f3IXadL_ZNHS_1X1fEiEEEEvv + // MS-NEXT: call void @"??$f3@$1?f@X@GH106660@@SAH_VH@Z@GH106660@@YAXXZ" + f3(&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>(); + // CHECK-NEXT: call void @_ZN8GH1066602f4IL_ZNHS_1X1fEiEEEvv + // MS-NEXT: call void @"??$f4@$1?f@X@GH106660@@SAH_VH@Z@GH106660@@YAXXZ" + f4<*static_cast(&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 constexpr int A = X(1); +template constexpr int Ar = X(2); +template constexpr int B = X(3); +template constexpr int Br = X(4); +template using C = decltype(X(1)); +template using Cr = decltype(X(2)); +template using D = decltype(X(3)); +template using Dr = decltype(X(4)); +template using E = decltype((X)); +template using Er = decltype((X)); +template using F = decltype((X)); +template 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 R {}; +R w = R>(); +R x = R>(); +R y = R>(); +R z = R>(); + + +} // namespace GH106660 namespace GH112559 { struct Wrap {};