Skip to content

[Clang] Disallow explicit object parameters in more contexts #89078

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 16 commits into from
Jul 15, 2024

Conversation

Sirraide
Copy link
Member

[dcl.fct]p6 states:

[...] 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].

The intent of this pr is to disallow explicit object parameters in all other contexts early on when we handle the function declarator.

This fixes #85992.

@Sirraide Sirraide added the clang:frontend Language frontend issues, e.g. anything involving "Sema" label Apr 17, 2024
@llvmbot llvmbot added the clang Clang issues not falling into any other category label Apr 17, 2024
@llvmbot
Copy link
Member

llvmbot commented Apr 17, 2024

@llvm/pr-subscribers-clang

Author: None (Sirraide)

Changes

[[dcl.fct]p6](https://eel.is/c++draft/dcl.fct#6) states:

> [...] 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].

The intent of this pr is to disallow explicit object parameters in all other contexts early on when we handle the function declarator.

This fixes #85992.


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

4 Files Affected:

  • (modified) clang/include/clang/Basic/DiagnosticSemaKinds.td (+2)
  • (modified) clang/lib/Sema/SemaDeclCXX.cpp (+2-4)
  • (modified) clang/lib/Sema/SemaType.cpp (+30)
  • (modified) clang/test/SemaCXX/cxx2b-deducing-this.cpp (+20-2)
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 5ec0218aedfe86..680638d2e59c6a 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 7669171fea56ff..ea634df48e5deb 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 404c4e8e31b558..95257b801c8a6c 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 5f29a955e053c3..ddb770a92db0f9 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; }
+}

Copy link
Contributor

@cor3ntin cor3ntin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Generally, I like the approach.

Note this PR is related to
https://github.com/llvm/llvm-project/pull/88974/files

@sdkrystian

@Sirraide
Copy link
Member Author

Note this PR is related to
https://github.com/llvm/llvm-project/pull/88974/files

That’s pr covers a different code path from what I can tell though (unless requires expressions are also modelled as function declarators, I’m honestly not sure about that one).

It also reminds me that this still needs a release note.

@sdkrystian
Copy link
Member

I'm going to merge #88974 shortly, but I don't think this interferes with anything here

@Sirraide
Copy link
Member Author

I'm going to merge #88974 shortly, but I don't think this interferes with anything here

Yeah, it seems orthogonal to this patch from what I can tell at least.

@Sirraide
Copy link
Member Author

Alright, it took me a bit, but I’ve figured out how to continue issuing the ‘... cannot appear in a non-member function’ diagnostic where appropriate. This also handles friend declarations now because I had forgotten about that; I’ve also added a few more tests for declarations w/ nested-name-specifiers.

@Sirraide Sirraide requested a review from cor3ntin April 23, 2024 17:14
@Sirraide
Copy link
Member Author

CI failure before seems to have been due to us running out of memory compiling flang from what I can tell?

@Sirraide
Copy link
Member Author

ping

@Sirraide
Copy link
Member Author

ping

@Sirraide
Copy link
Member Author

Sirraide commented Jul 4, 2024

ping

Copy link
Collaborator

@AaronBallman AaronBallman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM -- @cor3ntin, are you happy with the changes as well?

Copy link
Contributor

@cor3ntin cor3ntin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM modulo nit
Thanks for working on this

@Sirraide Sirraide merged commit 864478c into llvm:main Jul 15, 2024
8 checks passed
@Sirraide Sirraide deleted the deducing-this-nonmember branch July 16, 2024 00:37
yuxuanchen1997 pushed a commit that referenced this pull request Jul 25, 2024
Summary:
This diagnoses explicit object parameters in more contexts
where they aren’t supposed to appear in (e.g. function pointer
types, non-function member decls, etc.) [dcl.fct]

This fixes #85992.

Test Plan: 

Reviewers: 

Subscribers: 

Tasks: 

Tags: 


Differential Revision: https://phabricator.intern.facebook.com/D60251719
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:frontend Language frontend issues, e.g. anything involving "Sema" clang Clang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[clang] Pointer to member function should reject explicit object parameter
5 participants