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" }


Reply via email to