diff mbox series

c++: Constrained inherited constructor template [PR94549]

Message ID 20200420203830.3660750-1-ppalka@redhat.com
State New
Headers show
Series c++: Constrained inherited constructor template [PR94549] | expand

Commit Message

Patrick Palka April 20, 2020, 8:38 p.m. UTC
A comment in satisfy_declaration constraints says

  /* For inherited constructors, consider the original declaration;
     it has the correct template information attached. */
  d = strip_inheriting_ctors (d);

But this comment seems to be false when the inherited constructor points to an
instantiation of a constructor template.  In this case, DECL_TEMPLATE_INFO is
correct and DECL_INHERITED_CTOR points to the constructor template of the base
class rather than to the particular instantiation of the constructor template
(and so the DECL_TI_ARGS of the DECL_INHERITED_CTOR are in their dependent
form).

So doing strip_inheriting_ctors in this case then eventually leads to
satisfy_associated_constraints returning true regardless of the constraints
themselves, due to the passed in 'args' being dependent.

Since DECL_TEMPLATE_INFO seems to be non-NULL for an inherited constructor only
when the inherited constructor points to an instantiation of a constructor
template, this patch fixes this issue by avoiding to call strip_inheriting_ctors
when DECL_TEMPLATE_INFO is already non-NULL.

There is another unguarded call to strip_inheriting_ctors in
get_normalized_constraints_from_decl, but this one seems to be safe to do
unconditionally because the rest of that function doesn't need/look at the
DECL_TI_ARGS of the decl.

Passes 'make check-c++', does this look OK to commit after bootstrap/regtesting?

gcc/cp/ChangeLog:

	PR c++/94549
	* constraint.cc (satisfy_declaration_constraints): Don't strip the
	inherited constructor if it already has template information.

gcc/testsuite/ChangeLog:

	PR c++/94549
	* g++.dg/concepts/inherit-ctor3.C: Adjust expected diagnostics.
	* g++.dg/cpp2a/concepts-inherit-ctor4.C: Adjust expected diagnostics.
	* g++.dg/cpp2a/concepts-inherit-ctor8.C: New test.
---
 gcc/cp/constraint.cc                          |  7 ++++---
 gcc/testsuite/g++.dg/concepts/inherit-ctor3.C |  4 ++--
 .../g++.dg/cpp2a/concepts-inherit-ctor4.C     |  4 ++--
 .../g++.dg/cpp2a/concepts-inherit-ctor8.C     | 20 +++++++++++++++++++
 4 files changed, 28 insertions(+), 7 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-inherit-ctor8.C

Comments

Jason Merrill April 21, 2020, 9:24 p.m. UTC | #1
On 4/20/20 4:38 PM, Patrick Palka wrote:
> A comment in satisfy_declaration constraints says
> 
>    /* For inherited constructors, consider the original declaration;
>       it has the correct template information attached. */
>    d = strip_inheriting_ctors (d);
> 
> But this comment seems to be false when the inherited constructor points to an
> instantiation of a constructor template.  In this case, DECL_TEMPLATE_INFO is
> correct and DECL_INHERITED_CTOR points to the constructor template of the base
> class rather than to the particular instantiation of the constructor template
> (and so the DECL_TI_ARGS of the DECL_INHERITED_CTOR are in their dependent
> form).
> 
> So doing strip_inheriting_ctors in this case then eventually leads to
> satisfy_associated_constraints returning true regardless of the constraints
> themselves, due to the passed in 'args' being dependent.
> 
> Since DECL_TEMPLATE_INFO seems to be non-NULL for an inherited constructor only
> when the inherited constructor points to an instantiation of a constructor
> template, this patch fixes this issue by avoiding to call strip_inheriting_ctors
> when DECL_TEMPLATE_INFO is already non-NULL.
> 
> There is another unguarded call to strip_inheriting_ctors in
> get_normalized_constraints_from_decl, but this one seems to be safe to do
> unconditionally because the rest of that function doesn't need/look at the
> DECL_TI_ARGS of the decl.
> 
> Passes 'make check-c++', does this look OK to commit after bootstrap/regtesting?

OK.

> gcc/cp/ChangeLog:
> 
> 	PR c++/94549
> 	* constraint.cc (satisfy_declaration_constraints): Don't strip the
> 	inherited constructor if it already has template information.
> 
> gcc/testsuite/ChangeLog:
> 
> 	PR c++/94549
> 	* g++.dg/concepts/inherit-ctor3.C: Adjust expected diagnostics.
> 	* g++.dg/cpp2a/concepts-inherit-ctor4.C: Adjust expected diagnostics.
> 	* g++.dg/cpp2a/concepts-inherit-ctor8.C: New test.
> ---
>   gcc/cp/constraint.cc                          |  7 ++++---
>   gcc/testsuite/g++.dg/concepts/inherit-ctor3.C |  4 ++--
>   .../g++.dg/cpp2a/concepts-inherit-ctor4.C     |  4 ++--
>   .../g++.dg/cpp2a/concepts-inherit-ctor8.C     | 20 +++++++++++++++++++
>   4 files changed, 28 insertions(+), 7 deletions(-)
>   create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-inherit-ctor8.C
> 
> diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
> index 320792195d6..b76402c2f85 100644
> --- a/gcc/cp/constraint.cc
> +++ b/gcc/cp/constraint.cc
> @@ -2737,9 +2737,10 @@ satisfy_declaration_constraints (tree t, subst_info info)
>   {
>     gcc_assert (DECL_P (t));
>   
> -  /* For inherited constructors, consider the original declaration;
> -     it has the correct template information attached. */
> -  if (flag_new_inheriting_ctors)
> +  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);
>   
>     /* Update the declaration for diagnostics.  */
> diff --git a/gcc/testsuite/g++.dg/concepts/inherit-ctor3.C b/gcc/testsuite/g++.dg/concepts/inherit-ctor3.C
> index abfe96e8240..6b7a7a43910 100644
> --- a/gcc/testsuite/g++.dg/concepts/inherit-ctor3.C
> +++ b/gcc/testsuite/g++.dg/concepts/inherit-ctor3.C
> @@ -12,12 +12,12 @@ template<typename T>
>   
>   template<typename T>
>     struct S2 : S1<T> { // { dg-error "no matching function" }
> -    using S1<T>::S1; // { dg-error "no matching function" }
> +    using S1<T>::S1;
>     };
>   
>   struct X { } x;
>   
>   int main() {
> -  S2<X> s1(0); // { dg-error "use of deleted function" }
> +  S2<X> s1(0); // { dg-error "no matching function" }
>     S2<X> s2; // { dg-error "use of deleted function" }
>   }
> diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-inherit-ctor4.C b/gcc/testsuite/g++.dg/cpp2a/concepts-inherit-ctor4.C
> index 75190eb3413..34eaf22c26c 100644
> --- a/gcc/testsuite/g++.dg/cpp2a/concepts-inherit-ctor4.C
> +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-inherit-ctor4.C
> @@ -10,9 +10,9 @@ template<typename T>
>   
>   template<typename T>
>     struct S2 : S1<T> {
> -    using S1<T>::S1; // { dg-error "no matching function" }
> +    using S1<T>::S1;
>     };
>   
>   int main() {
> -  S2<int> s(0); // { dg-error "use of deleted function" }
> +  S2<int> s(0); // { dg-error "no matching function" }
>   }
> diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-inherit-ctor8.C b/gcc/testsuite/g++.dg/cpp2a/concepts-inherit-ctor8.C
> new file mode 100644
> index 00000000000..5b571e32318
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-inherit-ctor8.C
> @@ -0,0 +1,20 @@
> +// PR c++/94549
> +// { dg-do compile { target concepts } }
> +
> +struct base {
> +  template <typename type>
> +    requires false
> +  base(type);
> +
> +  template <typename type>
> +    requires true
> +  base(type);
> +};
> +
> +struct derived : base {
> +  using base::base;
> +};
> +
> +void foo() {
> +  derived{'G'};
> +}
>
diff mbox series

Patch

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 320792195d6..b76402c2f85 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -2737,9 +2737,10 @@  satisfy_declaration_constraints (tree t, subst_info info)
 {
   gcc_assert (DECL_P (t));
 
-  /* For inherited constructors, consider the original declaration;
-     it has the correct template information attached. */
-  if (flag_new_inheriting_ctors)
+  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);
 
   /* Update the declaration for diagnostics.  */
diff --git a/gcc/testsuite/g++.dg/concepts/inherit-ctor3.C b/gcc/testsuite/g++.dg/concepts/inherit-ctor3.C
index abfe96e8240..6b7a7a43910 100644
--- a/gcc/testsuite/g++.dg/concepts/inherit-ctor3.C
+++ b/gcc/testsuite/g++.dg/concepts/inherit-ctor3.C
@@ -12,12 +12,12 @@  template<typename T>
 
 template<typename T>
   struct S2 : S1<T> { // { dg-error "no matching function" }
-    using S1<T>::S1; // { dg-error "no matching function" }
+    using S1<T>::S1;
   };
 
 struct X { } x;
 
 int main() {
-  S2<X> s1(0); // { dg-error "use of deleted function" }
+  S2<X> s1(0); // { dg-error "no matching function" }
   S2<X> s2; // { dg-error "use of deleted function" }
 }
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-inherit-ctor4.C b/gcc/testsuite/g++.dg/cpp2a/concepts-inherit-ctor4.C
index 75190eb3413..34eaf22c26c 100644
--- a/gcc/testsuite/g++.dg/cpp2a/concepts-inherit-ctor4.C
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-inherit-ctor4.C
@@ -10,9 +10,9 @@  template<typename T>
 
 template<typename T>
   struct S2 : S1<T> {
-    using S1<T>::S1; // { dg-error "no matching function" }
+    using S1<T>::S1;
   };
 
 int main() {
-  S2<int> s(0); // { dg-error "use of deleted function" }
+  S2<int> s(0); // { dg-error "no matching function" }
 }
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-inherit-ctor8.C b/gcc/testsuite/g++.dg/cpp2a/concepts-inherit-ctor8.C
new file mode 100644
index 00000000000..5b571e32318
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-inherit-ctor8.C
@@ -0,0 +1,20 @@ 
+// PR c++/94549
+// { dg-do compile { target concepts } }
+
+struct base {
+  template <typename type>
+    requires false
+  base(type);
+
+  template <typename type>
+    requires true
+  base(type);
+};
+
+struct derived : base {
+  using base::base;
+};
+
+void foo() {
+  derived{'G'};
+}