On 4/8/21 4:50 PM, Marek Polacek wrote:
On Thu, Apr 08, 2021 at 04:37:00PM -0400, Patrick Palka wrote:
On Thu, 8 Apr 2021, Marek Polacek via Gcc-patches wrote:

When we have a member function with auto parameter like this:

   struct S {
     void f(auto);
   };

cp_parser_member_declaration -> grokfield produces a FUNCTION_DECL
"void S::foo(auto:1)", and then finish_fully_implicit_template turns
that FUNCTION_DECL into a TEMPLATE_DECL.  The bug here is that we only
call cp_parser_save_default_args for a FUNCTION_DECL.  As a consequence,
abbrev10.C is rejected because we complain that the default argument has
not been defined, and abbrev11.C ICEs, because we don't re-parse the
delayed noexcept, so the DEFERRED_PARSE tree leaks into tsubst* where we
crash.  This patch fixes both issues.

Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk/10.4?

OK.

gcc/cp/ChangeLog:

        PR c++/99806
        * parser.c (cp_parser_member_declaration): Call
        cp_parser_save_default_args even for function templates.
        (cp_parser_save_default_args): Extract the function declaration
        from a function template.

gcc/testsuite/ChangeLog:

        PR c++/99806
        * g++.dg/concepts/abbrev10.C: New test.
        * g++.dg/concepts/abbrev11.C: New test.
---
  gcc/cp/parser.c                          |  8 +++++---
  gcc/testsuite/g++.dg/concepts/abbrev10.C | 18 ++++++++++++++++++
  gcc/testsuite/g++.dg/concepts/abbrev11.C | 10 ++++++++++
  3 files changed, 33 insertions(+), 3 deletions(-)
  create mode 100644 gcc/testsuite/g++.dg/concepts/abbrev10.C
  create mode 100644 gcc/testsuite/g++.dg/concepts/abbrev11.C

diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 59adac4492a..eef6bb3003e 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -26433,7 +26433,8 @@ cp_parser_member_declaration (cp_parser* parser)
                  || !DECL_DECLARES_FUNCTION_P (decl))
                finish_member_declaration (decl);
- if (TREE_CODE (decl) == FUNCTION_DECL)
+             if (TREE_CODE (decl) == FUNCTION_DECL
+                 || DECL_FUNCTION_TEMPLATE_P (decl))

I guess you could use DECL_DECLARES_FUNCTION_P here.

Right, thanks.

                cp_parser_save_default_args (parser, decl);
              else if (TREE_CODE (decl) == FIELD_DECL
                       && DECL_INITIAL (decl))
@@ -30959,9 +30960,10 @@ cp_parser_late_parsing_for_member (cp_parser* parser, 
tree member_function)
  static void
  cp_parser_save_default_args (cp_parser* parser, tree decl)
  {
-  tree probe;
+  if (DECL_FUNCTION_TEMPLATE_P (decl))
+    decl = DECL_TEMPLATE_RESULT (decl);

Not sure if it'd be an improvement, but could use STRIP_TEMPLATE here
instead (or perhaps on the caller side).

Might as well.  How's this?

Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk/10?

-- >8 --
When we have a member function with auto parameter like this:

   struct S {
     void f(auto);
   };

cp_parser_member_declaration -> grokfield produces a FUNCTION_DECL
"void S::foo(auto:1)", and then finish_fully_implicit_template turns
that FUNCTION_DECL into a TEMPLATE_DECL.  The bug here is that we only
call cp_parser_save_default_args for a FUNCTION_DECL.  As a consequence,
abbrev10.C is rejected because we complain that the default argument has
not been defined, and abbrev11.C ICEs, because we don't re-parse the
delayed noexcept, so the DEFERRED_PARSE tree leaks into tsubst* where we
crash.  This patch fixes both issues.

gcc/cp/ChangeLog:

        PR c++/99806
        * parser.c (cp_parser_member_declaration): Call
        cp_parser_save_default_args even for function templates.  Use
        STRIP_TEMPLATE on the declaration we're passing.

gcc/testsuite/ChangeLog:

        PR c++/99806
        * g++.dg/concepts/abbrev10.C: New test.
        * g++.dg/concepts/abbrev11.C: New test.
---
  gcc/cp/parser.c                          |  4 ++--
  gcc/testsuite/g++.dg/concepts/abbrev10.C | 18 ++++++++++++++++++
  gcc/testsuite/g++.dg/concepts/abbrev11.C | 10 ++++++++++
  3 files changed, 30 insertions(+), 2 deletions(-)
  create mode 100644 gcc/testsuite/g++.dg/concepts/abbrev10.C
  create mode 100644 gcc/testsuite/g++.dg/concepts/abbrev11.C

diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 59adac4492a..e6e6ed72a42 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -26433,8 +26433,8 @@ cp_parser_member_declaration (cp_parser* parser)
                  || !DECL_DECLARES_FUNCTION_P (decl))
                finish_member_declaration (decl);
- if (TREE_CODE (decl) == FUNCTION_DECL)
-               cp_parser_save_default_args (parser, decl);
+             if (DECL_DECLARES_FUNCTION_P (decl))
+               cp_parser_save_default_args (parser, STRIP_TEMPLATE (decl));
              else if (TREE_CODE (decl) == FIELD_DECL
                       && DECL_INITIAL (decl))
                /* Add DECL to the queue of NSDMI to be parsed later.  */
diff --git a/gcc/testsuite/g++.dg/concepts/abbrev10.C 
b/gcc/testsuite/g++.dg/concepts/abbrev10.C
new file mode 100644
index 00000000000..b611346e926
--- /dev/null
+++ b/gcc/testsuite/g++.dg/concepts/abbrev10.C
@@ -0,0 +1,18 @@
+// PR c++/99806
+// { dg-do compile { target c++14 } }
+// { dg-additional-options "-fconcepts" }
+
+struct S {
+  void f(auto, auto, int = 3);
+  void f2(auto, auto, int = 3) { }
+  template<typename T> static T g(T, auto, int = 3);
+};
+
+void
+g ()
+{
+  S::g(1, 2);
+  S s;
+  s.f(1, 2);
+  s.f2(1, 2);
+}
diff --git a/gcc/testsuite/g++.dg/concepts/abbrev11.C 
b/gcc/testsuite/g++.dg/concepts/abbrev11.C
new file mode 100644
index 00000000000..ddb479313df
--- /dev/null
+++ b/gcc/testsuite/g++.dg/concepts/abbrev11.C
@@ -0,0 +1,10 @@
+// PR c++/99806
+// { dg-do compile { target c++14 } }
+// { dg-additional-options "-fconcepts" }
+
+template <typename T> concept C = requires (T a) { a.f(0); };
+struct S {
+  void f(auto) noexcept(B);
+  static constexpr bool B = true;
+};
+static_assert(C<S>, "");

base-commit: 123b3e03c911a43054c1f88f5d3110e1d084dd4e


Reply via email to