https://github.com/Sirraide updated https://github.com/llvm/llvm-project/pull/89078
>From c611122688657287e8285edd9a2875e4975d26dd Mon Sep 17 00:00:00 2001 From: Sirraide <aeternalm...@gmail.com> Date: Wed, 17 Apr 2024 16:15:39 +0200 Subject: [PATCH 01/11] [Clang] Disallow explicit object parameters in more contexts --- .../clang/Basic/DiagnosticSemaKinds.td | 2 ++ clang/lib/Sema/SemaDeclCXX.cpp | 6 ++-- clang/lib/Sema/SemaType.cpp | 30 +++++++++++++++++++ clang/test/SemaCXX/cxx2b-deducing-this.cpp | 22 ++++++++++++-- 4 files changed, 54 insertions(+), 6 deletions(-) diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 5ec0218aedfe8..680638d2e59c6 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -7494,6 +7494,8 @@ def err_explicit_object_parameter_mutable: Error< def err_invalid_explicit_object_type_in_lambda: Error< "invalid explicit object parameter type %0 in lambda with capture; " "the type must be the same as, or derived from, the lambda">; +def err_explicit_object_parameter_invalid: Error< + "an explicit object parameter is not allowed here">; def err_ref_qualifier_overload : Error< "cannot overload a member function %select{without a ref-qualifier|with " diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 7669171fea56f..ea634df48e5de 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -11469,10 +11469,8 @@ void Sema::CheckExplicitObjectMemberFunction(Declarator &D, return; if (!DC || !DC->isRecord()) { - Diag(ExplicitObjectParam->getLocation(), - diag::err_explicit_object_parameter_nonmember) - << D.getSourceRange() << /*non-member=*/2 << IsLambda; - D.setInvalidType(); + assert(D.isInvalidType() && "Explicit object parameter in non-member " + "should have been diagnosed already"); return; } diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index 404c4e8e31b55..406065741bf2d 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -5287,6 +5287,36 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, // Check for auto functions and trailing return type and adjust the // return type accordingly. if (!D.isInvalidType()) { + // [dcl.fct]p6: + // + // An explicit-object-parameter-declaration is a parameter-declaration + // with a this specifier. An explicit-object-parameter-declaration shall + // appear only as the first parameter-declaration of a + // parameter-declaration-list of either: + // + // - a member-declarator that declares a member function [class.mem], or + // - a lambda-declarator [expr.prim.lambda]. + DeclaratorContext C = D.getContext(); + ParmVarDecl *First = + FTI.NumParams + ? dyn_cast_if_present<ParmVarDecl>(FTI.Params[0].Param) + : nullptr; + if (First && First->isExplicitObjectParameter() && + C != DeclaratorContext::LambdaExpr && + + // Either not a member or nested declarator in a member. + (C != DeclaratorContext::Member || + D.getInnermostNonParenChunk() != &DeclType) && + + // Allow out-of-line definitions if we have a scope spec. + D.getCXXScopeSpec().isEmpty()) { + S.Diag(First->getBeginLoc(), + diag::err_explicit_object_parameter_invalid) + << First->getSourceRange(); + D.setInvalidType(); + AreDeclaratorChunksValid = false; + } + // trailing-return-type is only required if we're declaring a function, // and not, for instance, a pointer to a function. if (D.getDeclSpec().hasAutoTypeSpec() && diff --git a/clang/test/SemaCXX/cxx2b-deducing-this.cpp b/clang/test/SemaCXX/cxx2b-deducing-this.cpp index 5f29a955e053c..ddb770a92db0f 100644 --- a/clang/test/SemaCXX/cxx2b-deducing-this.cpp +++ b/clang/test/SemaCXX/cxx2b-deducing-this.cpp @@ -5,7 +5,7 @@ void f(this); // expected-error{{variable has incomplete type 'void'}} \ // expected-error{{invalid use of 'this' outside of a non-static member function}} -void g(this auto); // expected-error{{an explicit object parameter cannot appear in a non-member function}} +void g(this auto); // expected-error{{an explicit object parameter is not allowed here}} auto l1 = [] (this auto) static {}; // expected-error{{an explicit object parameter cannot appear in a static lambda}} auto l2 = [] (this auto) mutable {}; // expected-error{{a lambda with an explicit object parameter cannot be mutable}} @@ -685,7 +685,7 @@ struct S { static void j(this S s); // expected-error {{an explicit object parameter cannot appear in a static function}} }; -void nonmember(this S s); // expected-error {{an explicit object parameter cannot appear in a non-member function}} +void nonmember(this S s); // expected-error {{an explicit object parameter is not allowed here}} int test() { S s; @@ -838,3 +838,21 @@ int h() { }(); } } + +namespace GH85992 { +struct S { + int (S::*x)(this int); // expected-error {{an explicit object parameter is not allowed here}} + int (*y)(this int); // expected-error {{an explicit object parameter is not allowed here}} + int (***z)(this int); // expected-error {{an explicit object parameter is not allowed here}} + + int f(this S); + int ((g))(this S); + int h(int x, int (*)(this S)); // expected-error {{an explicit object parameter is not allowed here}} +}; + +using T = int (*)(this int); // expected-error {{an explicit object parameter is not allowed here}} +using U = int (S::*)(this int); // expected-error {{an explicit object parameter is not allowed here}} +int h(this int); // expected-error {{an explicit object parameter is not allowed here}} + +int S::f(this S) { return 1; } +} >From c27a3ff93474bc890de2b66ab7f486bb59e3b6d8 Mon Sep 17 00:00:00 2001 From: Sirraide <aeternalm...@gmail.com> Date: Wed, 17 Apr 2024 16:16:47 +0200 Subject: [PATCH 02/11] [NFC] clang-format --- clang/lib/Sema/SemaType.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index 406065741bf2d..23f2b9d74931b 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -5294,7 +5294,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, // appear only as the first parameter-declaration of a // parameter-declaration-list of either: // - // - a member-declarator that declares a member function [class.mem], or + // - a member-declarator that declares a member function [class.mem], + // or // - a lambda-declarator [expr.prim.lambda]. DeclaratorContext C = D.getContext(); ParmVarDecl *First = >From 0c1239a85159aaa4958bb574a326e85f50719b1b Mon Sep 17 00:00:00 2001 From: Sirraide <aeternalm...@gmail.com> Date: Wed, 17 Apr 2024 16:23:15 +0200 Subject: [PATCH 03/11] [NFC] Reformat comment --- clang/lib/Sema/SemaType.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index 23f2b9d74931b..95257b801c8a6 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -5294,9 +5294,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, // appear only as the first parameter-declaration of a // parameter-declaration-list of either: // - // - a member-declarator that declares a member function [class.mem], - // or - // - a lambda-declarator [expr.prim.lambda]. + // - a member-declarator that declares a member function [class.mem], or + // - a lambda-declarator [expr.prim.lambda]. DeclaratorContext C = D.getContext(); ParmVarDecl *First = FTI.NumParams >From 8edd57fd41c5c62de628b8ea9cf6b0ff1e4bc535 Mon Sep 17 00:00:00 2001 From: Sirraide <aeternalm...@gmail.com> Date: Tue, 23 Apr 2024 18:25:04 +0200 Subject: [PATCH 04/11] [Clang] Check that the NNS is a class type --- clang/lib/Sema/SemaType.cpp | 9 ++++++++- clang/test/SemaCXX/cxx2b-deducing-this.cpp | 5 +++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index 95257b801c8a6..d8b74b640af40 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -5287,6 +5287,13 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, // Check for auto functions and trailing return type and adjust the // return type accordingly. if (!D.isInvalidType()) { + auto isClassType = [&](CXXScopeSpec& SS) { + // If there already was an problem with the scope; don’t issue another + // error about the explicit object parameter. + return SS.isInvalid() || + isa_and_present<CXXRecordDecl>(S.computeDeclContext(SS)); + }; + // [dcl.fct]p6: // // An explicit-object-parameter-declaration is a parameter-declaration @@ -5309,7 +5316,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, D.getInnermostNonParenChunk() != &DeclType) && // Allow out-of-line definitions if we have a scope spec. - D.getCXXScopeSpec().isEmpty()) { + !isClassType(D.getCXXScopeSpec())) { S.Diag(First->getBeginLoc(), diag::err_explicit_object_parameter_invalid) << First->getSourceRange(); diff --git a/clang/test/SemaCXX/cxx2b-deducing-this.cpp b/clang/test/SemaCXX/cxx2b-deducing-this.cpp index ddb770a92db0f..d2c47b77365cd 100644 --- a/clang/test/SemaCXX/cxx2b-deducing-this.cpp +++ b/clang/test/SemaCXX/cxx2b-deducing-this.cpp @@ -855,4 +855,9 @@ using U = int (S::*)(this int); // expected-error {{an explicit object parameter int h(this int); // expected-error {{an explicit object parameter is not allowed here}} int S::f(this S) { return 1; } + +namespace a { +void f(); +}; +void a::f(this auto) {} // expected-error {{an explicit object parameter is not allowed here}} } >From 9c0609cf787cf00685d05ecabf707a885a77cc73 Mon Sep 17 00:00:00 2001 From: Sirraide <aeternalm...@gmail.com> Date: Tue, 23 Apr 2024 19:09:45 +0200 Subject: [PATCH 05/11] [Clang] Handle friends and restore better diagnostic --- clang/lib/Sema/SemaDeclCXX.cpp | 17 +++++++++++++++++ clang/lib/Sema/SemaType.cpp | 22 +++++++++++++++++----- clang/test/SemaCXX/cxx2b-deducing-this.cpp | 15 +++++++++++---- 3 files changed, 45 insertions(+), 9 deletions(-) diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index ea634df48e5de..1333f8492b40d 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -11459,6 +11459,23 @@ void Sema::CheckExplicitObjectMemberFunction(Declarator &D, D.setInvalidType(); } + // Handle the following case: + // + // struct S { + // struct T { + // int f(this T); + // }; + // + // friend int T::f(this T); // Allow this. + // friend int f(this S); // But disallow this. + // }; + if (D.getDeclSpec().isFriendSpecified() && D.getCXXScopeSpec().isEmpty()) { + Diag(ExplicitObjectParam->getBeginLoc(), + diag::err_explicit_object_parameter_nonmember) + << D.getSourceRange() << /*non-member=*/2 << IsLambda; + D.setInvalidType(); + } + if (IsLambda && FTI.hasMutableQualifier()) { Diag(ExplicitObjectParam->getBeginLoc(), diag::err_explicit_object_parameter_mutable) diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index d8b74b640af40..2c2bdb503a34c 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -5308,18 +5308,30 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, FTI.NumParams ? dyn_cast_if_present<ParmVarDecl>(FTI.Params[0].Param) : nullptr; + + auto IsFunctionDecl = D.getInnermostNonParenChunk() == &DeclType; if (First && First->isExplicitObjectParameter() && C != DeclaratorContext::LambdaExpr && // Either not a member or nested declarator in a member. - (C != DeclaratorContext::Member || - D.getInnermostNonParenChunk() != &DeclType) && + // + // Note that e.g. 'static' or 'friend' declarations are accepted + // here; we diagnose them later when we build the member function + // because it's easier that way. + (C != DeclaratorContext::Member || !IsFunctionDecl) && // Allow out-of-line definitions if we have a scope spec. !isClassType(D.getCXXScopeSpec())) { - S.Diag(First->getBeginLoc(), - diag::err_explicit_object_parameter_invalid) - << First->getSourceRange(); + if (IsFunctionDecl) + S.Diag(First->getBeginLoc(), + diag::err_explicit_object_parameter_nonmember) + << /*non-member*/ 2 << /*function*/ 0 + << First->getSourceRange(); + else + S.Diag(First->getBeginLoc(), + diag::err_explicit_object_parameter_invalid) + << First->getSourceRange(); + D.setInvalidType(); AreDeclaratorChunksValid = false; } diff --git a/clang/test/SemaCXX/cxx2b-deducing-this.cpp b/clang/test/SemaCXX/cxx2b-deducing-this.cpp index d2c47b77365cd..48f963acc27e6 100644 --- a/clang/test/SemaCXX/cxx2b-deducing-this.cpp +++ b/clang/test/SemaCXX/cxx2b-deducing-this.cpp @@ -5,7 +5,7 @@ void f(this); // expected-error{{variable has incomplete type 'void'}} \ // expected-error{{invalid use of 'this' outside of a non-static member function}} -void g(this auto); // expected-error{{an explicit object parameter is not allowed here}} +void g(this auto); // expected-error{{an explicit object parameter cannot appear in a non-member function}} auto l1 = [] (this auto) static {}; // expected-error{{an explicit object parameter cannot appear in a static lambda}} auto l2 = [] (this auto) mutable {}; // expected-error{{a lambda with an explicit object parameter cannot be mutable}} @@ -685,7 +685,7 @@ struct S { static void j(this S s); // expected-error {{an explicit object parameter cannot appear in a static function}} }; -void nonmember(this S s); // expected-error {{an explicit object parameter is not allowed here}} +void nonmember(this S s); // expected-error{{an explicit object parameter cannot appear in a non-member function}} int test() { S s; @@ -847,17 +847,24 @@ struct S { int f(this S); int ((g))(this S); + friend int h(this S); // expected-error {{an explicit object parameter cannot appear in a non-member function}} int h(int x, int (*)(this S)); // expected-error {{an explicit object parameter is not allowed here}} + + struct T { + int f(this T); + }; + + friend int T::f(this T); }; using T = int (*)(this int); // expected-error {{an explicit object parameter is not allowed here}} using U = int (S::*)(this int); // expected-error {{an explicit object parameter is not allowed here}} -int h(this int); // expected-error {{an explicit object parameter is not allowed here}} +int h(this int); // expected-error {{an explicit object parameter cannot appear in a non-member function}} int S::f(this S) { return 1; } namespace a { void f(); }; -void a::f(this auto) {} // expected-error {{an explicit object parameter is not allowed here}} +void a::f(this auto) {} // expected-error {{an explicit object parameter cannot appear in a non-member function}} } >From 853da04fe387f56fa69a468342bb665381db2b79 Mon Sep 17 00:00:00 2001 From: Sirraide <aeternalm...@gmail.com> Date: Tue, 23 Apr 2024 19:10:11 +0200 Subject: [PATCH 06/11] [NFC] clang-format --- clang/lib/Sema/SemaType.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index 2c2bdb503a34c..6a7754dce96d7 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -5287,7 +5287,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, // Check for auto functions and trailing return type and adjust the // return type accordingly. if (!D.isInvalidType()) { - auto isClassType = [&](CXXScopeSpec& SS) { + auto isClassType = [&](CXXScopeSpec &SS) { // If there already was an problem with the scope; don’t issue another // error about the explicit object parameter. return SS.isInvalid() || >From 3d91f2fdade769e80251f831926dd8529ff0d99c Mon Sep 17 00:00:00 2001 From: Sirraide <aeternalm...@gmail.com> Date: Tue, 23 Apr 2024 19:11:28 +0200 Subject: [PATCH 07/11] [NFC] Remove spurious whitespace change --- clang/test/SemaCXX/cxx2b-deducing-this.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/test/SemaCXX/cxx2b-deducing-this.cpp b/clang/test/SemaCXX/cxx2b-deducing-this.cpp index 48f963acc27e6..7339ffeb2dab3 100644 --- a/clang/test/SemaCXX/cxx2b-deducing-this.cpp +++ b/clang/test/SemaCXX/cxx2b-deducing-this.cpp @@ -685,7 +685,7 @@ struct S { static void j(this S s); // expected-error {{an explicit object parameter cannot appear in a static function}} }; -void nonmember(this S s); // expected-error{{an explicit object parameter cannot appear in a non-member function}} +void nonmember(this S s); // expected-error {{an explicit object parameter cannot appear in a non-member function}} int test() { S s; >From e3ea2c650c749d4401613b780c912a12dd998f20 Mon Sep 17 00:00:00 2001 From: Sirraide <aeternalm...@gmail.com> Date: Tue, 23 Apr 2024 19:19:08 +0200 Subject: [PATCH 08/11] [NFC] Update comments --- clang/lib/Sema/SemaType.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index 6a7754dce96d7..ac6c93c04f925 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -5288,7 +5288,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, // return type accordingly. if (!D.isInvalidType()) { auto isClassType = [&](CXXScopeSpec &SS) { - // If there already was an problem with the scope; don’t issue another + // If there already was an problem with the scope, don’t issue another // error about the explicit object parameter. return SS.isInvalid() || isa_and_present<CXXRecordDecl>(S.computeDeclContext(SS)); @@ -5320,7 +5320,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, // because it's easier that way. (C != DeclaratorContext::Member || !IsFunctionDecl) && - // Allow out-of-line definitions if we have a scope spec. + // Allow out-of-line definitions of member functions. !isClassType(D.getCXXScopeSpec())) { if (IsFunctionDecl) S.Diag(First->getBeginLoc(), >From 985044944bd21e1a08a8c204a01974c78df18e37 Mon Sep 17 00:00:00 2001 From: Sirraide <aeternalm...@gmail.com> Date: Tue, 23 Apr 2024 19:23:28 +0200 Subject: [PATCH 09/11] [Docs] Add release note --- clang/docs/ReleaseNotes.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index ade8f4e93d5a0..4d926d7737670 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -539,6 +539,8 @@ Bug Fixes to C++ Support - Clang now correctly tracks type dependence of by-value captures in lambdas with an explicit object parameter. Fixes (#GH70604), (#GH79754), (#GH84163), (#GH84425), (#GH86054), (#GH86398), and (#GH86399). +- Clang now diagnoses explicit object parameters in member pointers and other contexts where they should not appear. + Fixes (#GH85992). Bug Fixes to AST Handling ^^^^^^^^^^^^^^^^^^^^^^^^^ >From 1d307fef1d9d6e1bee52c5d813f5c5f7805c87d6 Mon Sep 17 00:00:00 2001 From: Sirraide <aeternalm...@gmail.com> Date: Tue, 28 May 2024 20:08:57 +0200 Subject: [PATCH 10/11] Update clang/lib/Sema/SemaType.cpp Co-authored-by: Aaron Ballman <aa...@aaronballman.com> --- clang/lib/Sema/SemaType.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index f371301e89bec..27e39ec4e195d 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -4867,7 +4867,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, ? dyn_cast_if_present<ParmVarDecl>(FTI.Params[0].Param) : nullptr; - auto IsFunctionDecl = D.getInnermostNonParenChunk() == &DeclType; + bool IsFunctionDecl = D.getInnermostNonParenChunk() == &DeclType; if (First && First->isExplicitObjectParameter() && C != DeclaratorContext::LambdaExpr && >From aa4f66bd3704f8604538239aa0fe9045e3c1a6f8 Mon Sep 17 00:00:00 2001 From: Sirraide <aeternalm...@gmail.com> Date: Wed, 19 Jun 2024 15:35:09 +0200 Subject: [PATCH 11/11] Handle namespace scope specifiers correctly --- clang/lib/Sema/SemaDeclCXX.cpp | 15 +++++++++++++-- clang/lib/Sema/SemaType.cpp | 14 ++++++++++---- clang/test/SemaCXX/cxx2b-deducing-this.cpp | 11 +++++++++++ 3 files changed, 34 insertions(+), 6 deletions(-) diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 3445e705131c0..31be0944a8315 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -11401,7 +11401,12 @@ void Sema::CheckExplicitObjectMemberFunction(Declarator &D, D.setInvalidType(); } - // Handle the following case: + // Friend declarations require some care. Consider: + // + // namespace N { + // struct A{}; + // int f(A); + // } // // struct S { // struct T { @@ -11410,8 +11415,14 @@ void Sema::CheckExplicitObjectMemberFunction(Declarator &D, // // friend int T::f(this T); // Allow this. // friend int f(this S); // But disallow this. + // friend int N::f(this A); // And disallow this. // }; - if (D.getDeclSpec().isFriendSpecified() && D.getCXXScopeSpec().isEmpty()) { + // + // Here, it seems to suffice to check whether the scope + // specifier designates a class type. + if (D.getDeclSpec().isFriendSpecified() && + !isa_and_present<CXXRecordDecl>( + computeDeclContext(D.getCXXScopeSpec()))) { Diag(ExplicitObjectParam->getBeginLoc(), diag::err_explicit_object_parameter_nonmember) << D.getSourceRange() << /*non-member=*/2 << IsLambda; diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index 096c4e6f419e2..057f3e6a6e6c8 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -4845,7 +4845,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, // Check for auto functions and trailing return type and adjust the // return type accordingly. if (!D.isInvalidType()) { - auto isClassType = [&](CXXScopeSpec &SS) { + auto IsClassType = [&](CXXScopeSpec &SS) { // If there already was an problem with the scope, don’t issue another // error about the explicit object parameter. return SS.isInvalid() || @@ -4857,9 +4857,15 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, // An explicit-object-parameter-declaration is a parameter-declaration // with a this specifier. An explicit-object-parameter-declaration shall // appear only as the first parameter-declaration of a - // parameter-declaration-list of either: + // parameter-declaration-list of one of: + // + // - a declaration of a member function or member function template + // ([class.mem]), or + // + // - an explicit instantiation ([temp.explicit]) or explicit + // specialization ([temp.expl.spec]) of a templated member function, + // or // - // - a member-declarator that declares a member function [class.mem], or // - a lambda-declarator [expr.prim.lambda]. DeclaratorContext C = D.getContext(); ParmVarDecl *First = @@ -4879,7 +4885,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, (C != DeclaratorContext::Member || !IsFunctionDecl) && // Allow out-of-line definitions of member functions. - !isClassType(D.getCXXScopeSpec())) { + !IsClassType(D.getCXXScopeSpec())) { if (IsFunctionDecl) S.Diag(First->getBeginLoc(), diag::err_explicit_object_parameter_nonmember) diff --git a/clang/test/SemaCXX/cxx2b-deducing-this.cpp b/clang/test/SemaCXX/cxx2b-deducing-this.cpp index 7409c71b562c6..b6e1f33f0f79e 100644 --- a/clang/test/SemaCXX/cxx2b-deducing-this.cpp +++ b/clang/test/SemaCXX/cxx2b-deducing-this.cpp @@ -920,6 +920,14 @@ struct C { } namespace GH85992 { +namespace N { +struct A { + int f(this A); +}; + +int f(A); +} + struct S { int (S::*x)(this int); // expected-error {{an explicit object parameter is not allowed here}} int (*y)(this int); // expected-error {{an explicit object parameter is not allowed here}} @@ -935,6 +943,9 @@ struct S { }; friend int T::f(this T); + friend int N::A::f(this N::A); + friend int N::f(this N::A); // expected-error {{an explicit object parameter cannot appear in a non-member function}} + int friend func(this T); // expected-error {{an explicit object parameter cannot appear in a non-member function}} }; using T = int (*)(this int); // expected-error {{an explicit object parameter is not allowed here}} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits