diff mbox series

c++: Inherited constructor template arguments [PR94719]

Message ID 20200422185549.2052667-1-ppalka@redhat.com
State New
Headers show
Series c++: Inherited constructor template arguments [PR94719] | expand

Commit Message

Patrick Palka April 22, 2020, 6:55 p.m. UTC
My fix for PR94549 broke constraints_satisfied_p in the case where the inherited
constructor decl points to an instantiation of a constructor template coming
from an instantiation of a class template.

This is because the DECL_TI_ARGS of the inherited constructor decl in this case
contains only the innermost level of template arguments (those for the
constructor template), but constraint satisfaction expects to have the full set
of template arguments.  This causes template argument substitution to fail in
various ways.

On the the hand, the DECL_TI_ARGS of the DECL_INHERITED_CTOR is a full set of
template arguments, but with the innermost level still in its dependent form,
which is the source of PR94549.  So if we could combine these two sets of
template arguments then we'd be golden.

This patch does just that, by effectively reverting the fix for PR94549 and
instead using add_outermost_template_args to combine the template arguments of
the inherited constructor with those of its DECL_INHERITED_CTOR.

Bootstrapped and regtested successfully on x86_64-pc-linux-gnu, and also
verified that the cmcstl2 testsuite now compiles successfully again.  Does this
look OK to commit?

(The fact that the DECL_TI_ARGS of the inherited constructor decl doesn't
contain the full set of template arguments seems to be inconsistent with the
documentation for DECL_TI_ARGS, which says it is "always the full set of
arguments required to instantiate this declaration from the most general
template specialized here." But the full set of arguments for foo<int>::bar<5>
in the testcase below should be {{int},{5}}, not just {5}, I think?)

gcc/cp/ChangeLog:

	PR c++/94719
	PR c++/94549
	* constraint.cc (satisfy_declaration_constraints): If an inherited
	constructor points to an instantiation of a constructor template,
	remember and use the attached template arguments.

gcc/testsuite/ChangeLog:

	PR c++/94719
	PR c++/94549
	* g++.dg/cpp2a/concepts-inherit-ctor9.C: New test.
---
 gcc/cp/constraint.cc                          | 17 +++++++++++-----
 .../g++.dg/cpp2a/concepts-inherit-ctor9.C     | 20 +++++++++++++++++++
 2 files changed, 32 insertions(+), 5 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-inherit-ctor9.C

Comments

Jason Merrill April 22, 2020, 7:13 p.m. UTC | #1
On 4/22/20 2:55 PM, Patrick Palka wrote:
> My fix for PR94549 broke constraints_satisfied_p in the case where the inherited
> constructor decl points to an instantiation of a constructor template coming
> from an instantiation of a class template.
> 
> This is because the DECL_TI_ARGS of the inherited constructor decl in this case
> contains only the innermost level of template arguments (those for the
> constructor template), but constraint satisfaction expects to have the full set
> of template arguments.  This causes template argument substitution to fail in
> various ways.
> 
> On the the hand, the DECL_TI_ARGS of the DECL_INHERITED_CTOR is a full set of
> template arguments, but with the innermost level still in its dependent form,
> which is the source of PR94549.  So if we could combine these two sets of
> template arguments then we'd be golden.
> 
> This patch does just that, by effectively reverting the fix for PR94549 and
> instead using add_outermost_template_args to combine the template arguments of
> the inherited constructor with those of its DECL_INHERITED_CTOR.
> 
> Bootstrapped and regtested successfully on x86_64-pc-linux-gnu, and also
> verified that the cmcstl2 testsuite now compiles successfully again.  Does this
> look OK to commit?

OK.

> (The fact that the DECL_TI_ARGS of the inherited constructor decl doesn't
> contain the full set of template arguments seems to be inconsistent with the
> documentation for DECL_TI_ARGS, which says it is "always the full set of
> arguments required to instantiate this declaration from the most general
> template specialized here." But the full set of arguments for foo<int>::bar<5>
> in the testcase below should be {{int},{5}}, not just {5}, I think?)
That is strange, yes.  The situation with template arguments and 
inherited constructors seems pretty confused.

> gcc/cp/ChangeLog:
> 
> 	PR c++/94719
> 	PR c++/94549
> 	* constraint.cc (satisfy_declaration_constraints): If an inherited
> 	constructor points to an instantiation of a constructor template,
> 	remember and use the attached template arguments.
> 
> gcc/testsuite/ChangeLog:
> 
> 	PR c++/94719
> 	PR c++/94549
> 	* g++.dg/cpp2a/concepts-inherit-ctor9.C: New test.
> ---
>   gcc/cp/constraint.cc                          | 17 +++++++++++-----
>   .../g++.dg/cpp2a/concepts-inherit-ctor9.C     | 20 +++++++++++++++++++
>   2 files changed, 32 insertions(+), 5 deletions(-)
>   create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-inherit-ctor9.C
> 
> diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
> index c05fafe5da1..06161b8c8c4 100644
> --- a/gcc/cp/constraint.cc
> +++ b/gcc/cp/constraint.cc
> @@ -2736,12 +2736,17 @@ static tree
>   satisfy_declaration_constraints (tree t, subst_info info)
>   {
>     gcc_assert (DECL_P (t));
> +  const tree saved_t = t;
>   
> -  if (!DECL_TEMPLATE_INFO (t))
> -    /* For inherited constructors without template information, consider
> -       the original declaration; it has the correct template information
> -       attached.  */
> -    t = strip_inheriting_ctors (t);
> +  /* For inherited constructors, consider the original declaration;
> +     it has the correct template information attached. */
> +  t = strip_inheriting_ctors (t);
> +  tree inh_ctor_targs = NULL_TREE;
> +  if (t != saved_t)
> +    if (tree ti = DECL_TEMPLATE_INFO (saved_t))
> +      /* The inherited constructor points to an instantiation of a constructor
> +	 template; remember its template arguments.  */
> +      inh_ctor_targs = TI_ARGS (ti);
>   
>     /* Update the declaration for diagnostics.  */
>     info.in_decl = t;
> @@ -2761,6 +2766,8 @@ satisfy_declaration_constraints (tree t, subst_info info)
>         /* The initial parameter mapping is the complete set of
>   	 template arguments substituted into the declaration.  */
>         args = TI_ARGS (ti);
> +      if (inh_ctor_targs)
> +	args = add_outermost_template_args (args, inh_ctor_targs);
>       }
>     else
>       {
> diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-inherit-ctor9.C b/gcc/testsuite/g++.dg/cpp2a/concepts-inherit-ctor9.C
> new file mode 100644
> index 00000000000..7d3201bff9f
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-inherit-ctor9.C
> @@ -0,0 +1,20 @@
> +// PR c++/94719
> +// { dg-do compile { target concepts } }
> +
> +template<typename T>
> +struct bar
> +{
> +  template<int N = 5> requires (N == 5)
> +  bar() { }
> +};
> +
> +template<typename T>
> +struct foo : bar<T>
> +{
> +  using foo::bar::bar;
> +};
> +
> +void baz()
> +{
> +  foo<int>{};
> +}
>
diff mbox series

Patch

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index c05fafe5da1..06161b8c8c4 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -2736,12 +2736,17 @@  static tree
 satisfy_declaration_constraints (tree t, subst_info info)
 {
   gcc_assert (DECL_P (t));
+  const tree saved_t = t;
 
-  if (!DECL_TEMPLATE_INFO (t))
-    /* For inherited constructors without template information, consider
-       the original declaration; it has the correct template information
-       attached.  */
-    t = strip_inheriting_ctors (t);
+  /* For inherited constructors, consider the original declaration;
+     it has the correct template information attached. */
+  t = strip_inheriting_ctors (t);
+  tree inh_ctor_targs = NULL_TREE;
+  if (t != saved_t)
+    if (tree ti = DECL_TEMPLATE_INFO (saved_t))
+      /* The inherited constructor points to an instantiation of a constructor
+	 template; remember its template arguments.  */
+      inh_ctor_targs = TI_ARGS (ti);
 
   /* Update the declaration for diagnostics.  */
   info.in_decl = t;
@@ -2761,6 +2766,8 @@  satisfy_declaration_constraints (tree t, subst_info info)
       /* The initial parameter mapping is the complete set of
 	 template arguments substituted into the declaration.  */
       args = TI_ARGS (ti);
+      if (inh_ctor_targs)
+	args = add_outermost_template_args (args, inh_ctor_targs);
     }
   else
     {
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-inherit-ctor9.C b/gcc/testsuite/g++.dg/cpp2a/concepts-inherit-ctor9.C
new file mode 100644
index 00000000000..7d3201bff9f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-inherit-ctor9.C
@@ -0,0 +1,20 @@ 
+// PR c++/94719
+// { dg-do compile { target concepts } }
+
+template<typename T>
+struct bar
+{
+  template<int N = 5> requires (N == 5)
+  bar() { }
+};
+
+template<typename T>
+struct foo : bar<T>
+{
+  using foo::bar::bar;
+};
+
+void baz()
+{
+  foo<int>{};
+}