diff mbox series

c++: Fix two issues with auto function parameter [PR99806]

Message ID 20210408201141.353897-1-polacek@redhat.com
State New
Headers show
Series c++: Fix two issues with auto function parameter [PR99806] | expand

Commit Message

Marek Polacek April 8, 2021, 8:11 p.m. UTC
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?

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


base-commit: 123b3e03c911a43054c1f88f5d3110e1d084dd4e

Comments

Patrick Palka April 8, 2021, 8:37 p.m. UTC | #1
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?
> 
> 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.

>  		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).

>  
> -  for (probe = TYPE_ARG_TYPES (TREE_TYPE (decl));
> +  for (tree probe = TYPE_ARG_TYPES (TREE_TYPE (decl));
>         probe;
>         probe = TREE_CHAIN (probe))
>      if (TREE_PURPOSE (probe))
> 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
> -- 
> 2.30.2
> 
>
Marek Polacek April 8, 2021, 8:50 p.m. UTC | #2
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?
> > 
> > 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
Jason Merrill April 9, 2021, 2:25 p.m. UTC | #3
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
>
diff mbox series

Patch

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))
 		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);
 
-  for (probe = TYPE_ARG_TYPES (TREE_TYPE (decl));
+  for (tree probe = TYPE_ARG_TYPES (TREE_TYPE (decl));
        probe;
        probe = TREE_CHAIN (probe))
     if (TREE_PURPOSE (probe))
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>, "");