[PATCH] c++: Suppress this injection for static member functions [PR97399]

Jason Merrill jason@redhat.com
Fri Jan 22 03:05:36 GMT 2021


On 1/21/21 11:22 AM, Patrick Palka wrote:
> Here at parse time finish_qualified_id_expr adds an implicit 'this->' to
> the expression tmp::integral<T> (because it's type-dependent, and also
> current_class_ptr is set) within the trailing return type, and later
> during substitution we can't resolve the 'this' since
> tsubst_function_type does inject_this_parm only for non-static member
> functions which tmp::func is not.
> 
> It seems the root of the problem is that we set current_class_ptr when
> parsing the signature of a static member function.  Since explicit uses
> of 'this' are already not allowed in this context, we probably shouldn't
> be doing inject_this_parm either.

Hmm, 'this' is defined in a static member function, it's just ill-formed 
to use it:

7.5.2/2: "... [this] shall not appear within the declaration of a static 
member function (although its type and value category are defined within 
a static member function as they are within a non-static member 
function). [Note: This is because declaration matching does not occur 
until the complete declarator is known. — end note]"

Perhaps maybe_dummy_object needs to be smarter about recognizing static 
context.  Or perhaps there's no way to tell the difference between the 
specified behavior above and the behavior with your patch, but:

The note suggests that we need to test the case of an out-of-class 
definition of a static member function (template); we must 
inject_this_parm when parsing such a declaration, since we don't know 
it's static until we match it to the declaration in the class.  I'm 
guessing that this would lead to the same problem.

> Bootstrapped and regtested on x64_64-pc-linux-gnu, does this look OK for
> trunk?
> 
> gcc/cp/ChangeLog:
> 
> 	PR c++/97399
> 	* parser.c (cp_parser_init_declarator): If the storage class
> 	specifier is sc_static, pass true for static_p to
> 	cp_parser_declarator.
> 	(cp_parser_direct_declarator): Don't do inject_this_parm when
> 	the member function is static.
> 
> gcc/testsuite/ChangeLog:
> 
> 	PR c++/88548
> 	PR c++/97399
> 	* g++.dg/cpp0x/this2.C: New test.
> 	* g++.dg/template/pr97399a.C: New test.
> 	* g++.dg/template/pr97399b.C: New test.
> ---
>   gcc/cp/parser.c                          |  5 +++--
>   gcc/testsuite/g++.dg/cpp0x/this2.C       |  8 ++++++++
>   gcc/testsuite/g++.dg/template/pr97399a.C | 11 +++++++++++
>   gcc/testsuite/g++.dg/template/pr97399b.C | 11 +++++++++++
>   4 files changed, 33 insertions(+), 2 deletions(-)
>   create mode 100644 gcc/testsuite/g++.dg/cpp0x/this2.C
>   create mode 100644 gcc/testsuite/g++.dg/template/pr97399a.C
>   create mode 100644 gcc/testsuite/g++.dg/template/pr97399b.C
> 
> diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
> index 48437f23175..18cf9888632 100644
> --- a/gcc/cp/parser.c
> +++ b/gcc/cp/parser.c
> @@ -21413,6 +21413,7 @@ cp_parser_init_declarator (cp_parser* parser,
>     bool is_non_constant_init;
>     int ctor_dtor_or_conv_p;
>     bool friend_p = cp_parser_friend_p (decl_specifiers);
> +  bool static_p = decl_specifiers->storage_class == sc_static;
>     tree pushed_scope = NULL_TREE;
>     bool range_for_decl_p = false;
>     bool saved_default_arg_ok_p = parser->default_arg_ok_p;
> @@ -21446,7 +21447,7 @@ cp_parser_init_declarator (cp_parser* parser,
>       = cp_parser_declarator (parser, CP_PARSER_DECLARATOR_NAMED,
>   			    flags, &ctor_dtor_or_conv_p,
>   			    /*parenthesized_p=*/NULL,
> -			    member_p, friend_p, /*static_p=*/false);
> +			    member_p, friend_p, static_p);
>     /* Gather up the deferred checks.  */
>     stop_deferring_access_checks ();
>   
> @@ -22122,7 +22123,7 @@ cp_parser_direct_declarator (cp_parser* parser,
>   
>   		  tree save_ccp = current_class_ptr;
>   		  tree save_ccr = current_class_ref;
> -		  if (memfn)
> +		  if (memfn && !static_p)
>   		    /* DR 1207: 'this' is in scope after the cv-quals.  */
>   		    inject_this_parameter (current_class_type, cv_quals);
>   
> diff --git a/gcc/testsuite/g++.dg/cpp0x/this2.C b/gcc/testsuite/g++.dg/cpp0x/this2.C
> new file mode 100644
> index 00000000000..3781bc5efec
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp0x/this2.C
> @@ -0,0 +1,8 @@
> +// PR c++/88548
> +// { dg-do compile { target c++11 } }
> +
> +struct S {
> +  int a;
> +  template <class> static auto m1 ()
> +    -> decltype(this->a) { return 0; }; // { dg-error "'this'" }
> +};
> diff --git a/gcc/testsuite/g++.dg/template/pr97399a.C b/gcc/testsuite/g++.dg/template/pr97399a.C
> new file mode 100644
> index 00000000000..3713dbde6e0
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/template/pr97399a.C
> @@ -0,0 +1,11 @@
> +// PR c++/97399
> +// { dg-do compile { target c++11 } }
> +
> +template <bool> struct enable_if_t {};
> +struct tmp {
> +  template <class T> static constexpr bool is_integral();
> +  template <class T> static auto func()
> +    -> enable_if_t<tmp::is_integral<T>()>;
> +};
> +template <class> constexpr bool tmp::is_integral() { return true; }
> +int main() { tmp::func<int>(); }
> diff --git a/gcc/testsuite/g++.dg/template/pr97399b.C b/gcc/testsuite/g++.dg/template/pr97399b.C
> new file mode 100644
> index 00000000000..9196c985834
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/template/pr97399b.C
> @@ -0,0 +1,11 @@
> +// PR c++/97399
> +// { dg-do compile { target c++11 } }
> +
> +template <bool> struct enable_if_t {};
> +struct tmp {
> +  template <class T> constexpr bool is_integral(); // non-static
> +  template <class T> static auto func()
> +    -> enable_if_t<tmp::is_integral<T>()>; // { dg-error "without object" }
> +};
> +template <class> constexpr bool tmp::is_integral() { return true; }
> +int main() { tmp::func<int>(); } // { dg-error "no match" }
> 



More information about the Gcc-patches mailing list