diff mbox series

c++: new-expr of array of deduced class tmpl [PR101988]

Message ID 20220126235525.571059-1-polacek@redhat.com
State New
Headers show
Series c++: new-expr of array of deduced class tmpl [PR101988] | expand

Commit Message

Marek Polacek Jan. 26, 2022, 11:55 p.m. UTC
In r12-1933 I attempted to implement DR2397 aka allowing

  int a[3];
  auto (&r)[3] = a;

by removing the type_uses_auto check in create_array_type_for_decl.
That may have gone too far, because it also allows arrays of
CLASS_PLACEHOLDER_TEMPLATE and it looks like [dcl.type.class.deduct]
prohibits that: "...the declared type of the variable shall be cv T,
where T is the placeholder."  However, in /2 it explicitly states that
"A placeholder for a deduced class type can also be used in the
type-specifier-seq in the new-type-id or type-id of a new-expression."

In this PR, it manifested by making us accept invalid

  template<class T> struct A { A(T); };
  auto p = new A[]{1};

[expr.new]/2 says that such a construct is treated as an invented
declaration of the form

  A x[]{1};

but, I think, that ought to be ill-formed as per above.  So this patch
sort of restores the create_array_type_for_decl check.  I should mention
that the difference between [] and [1] is due to cp_parser_new_type_id:

      if (*nelts == NULL_TREE)
        /* Leave [] in the declarator.  */;

and groktypename returning different types based on that.

Does this make sense?  Bootstrapped/regtested on x86_64-pc-linux-gnu.

	PR c++/101988

gcc/cp/ChangeLog:

	* decl.cc (create_array_type_for_decl): Reject forming an array of
	placeholder for a deduced class type.

gcc/testsuite/ChangeLog:

	* g++.dg/cpp1z/class-deduction-new1.C: New test.
	* g++.dg/cpp23/auto-array2.C: New test.
---
 gcc/cp/decl.cc                                   | 12 ++++++++++++
 .../g++.dg/cpp1z/class-deduction-new1.C          | 16 ++++++++++++++++
 gcc/testsuite/g++.dg/cpp23/auto-array2.C         | 11 +++++++++++
 3 files changed, 39 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/cpp1z/class-deduction-new1.C
 create mode 100644 gcc/testsuite/g++.dg/cpp23/auto-array2.C


base-commit: fd5b0488ad5e4f29b65238e06a2d65b7de120235

Comments

Jason Merrill Jan. 27, 2022, 1:02 a.m. UTC | #1
On 1/26/22 18:55, Marek Polacek wrote:
> In r12-1933 I attempted to implement DR2397 aka allowing
> 
>    int a[3];
>    auto (&r)[3] = a;
> 
> by removing the type_uses_auto check in create_array_type_for_decl.
> That may have gone too far, because it also allows arrays of
> CLASS_PLACEHOLDER_TEMPLATE and it looks like [dcl.type.class.deduct]
> prohibits that: "...the declared type of the variable shall be cv T,
> where T is the placeholder."  However, in /2 it explicitly states that
> "A placeholder for a deduced class type can also be used in the
> type-specifier-seq in the new-type-id or type-id of a new-expression."
> 
> In this PR, it manifested by making us accept invalid
> 
>    template<class T> struct A { A(T); };
>    auto p = new A[]{1};
> 
> [expr.new]/2 says that such a construct is treated as an invented
> declaration of the form
> 
>    A x[]{1};
> 
> but, I think, that ought to be ill-formed as per above.  So this patch
> sort of restores the create_array_type_for_decl check.  I should mention
> that the difference between [] and [1] is due to cp_parser_new_type_id:
> 
>        if (*nelts == NULL_TREE)
>          /* Leave [] in the declarator.  */;
> 
> and groktypename returning different types based on that.
> 
> Does this make sense?  Bootstrapped/regtested on x86_64-pc-linux-gnu.

OK.

> 	PR c++/101988
> 
> gcc/cp/ChangeLog:
> 
> 	* decl.cc (create_array_type_for_decl): Reject forming an array of
> 	placeholder for a deduced class type.
> 
> gcc/testsuite/ChangeLog:
> 
> 	* g++.dg/cpp1z/class-deduction-new1.C: New test.
> 	* g++.dg/cpp23/auto-array2.C: New test.
> ---
>   gcc/cp/decl.cc                                   | 12 ++++++++++++
>   .../g++.dg/cpp1z/class-deduction-new1.C          | 16 ++++++++++++++++
>   gcc/testsuite/g++.dg/cpp23/auto-array2.C         | 11 +++++++++++
>   3 files changed, 39 insertions(+)
>   create mode 100644 gcc/testsuite/g++.dg/cpp1z/class-deduction-new1.C
>   create mode 100644 gcc/testsuite/g++.dg/cpp23/auto-array2.C
> 
> diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
> index 6534a7fd320..10e6956117e 100644
> --- a/gcc/cp/decl.cc
> +++ b/gcc/cp/decl.cc
> @@ -11087,6 +11087,18 @@ create_array_type_for_decl (tree name, tree type, tree size, location_t loc)
>     if (type == error_mark_node || size == error_mark_node)
>       return error_mark_node;
>   
> +  /* [dcl.type.class.deduct] prohibits forming an array of placeholder
> +     for a deduced class type.  */
> +  if (is_auto (type) && CLASS_PLACEHOLDER_TEMPLATE (type))
> +    {
> +      if (name)
> +	error_at (loc, "%qD declared as array of template placeholder "
> +		  "type %qT", name, type);
> +      else
> +	error ("creating array of template placeholder type %qT", type);
> +      return error_mark_node;
> +    }
> +
>     /* If there are some types which cannot be array elements,
>        issue an error-message and return.  */
>     switch (TREE_CODE (type))
> diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction-new1.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction-new1.C
> new file mode 100644
> index 00000000000..70283353619
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction-new1.C
> @@ -0,0 +1,16 @@
> +// PR c++/101988
> +// { dg-do compile { target c++17 } }
> +
> +template<typename T>
> +struct A {
> +  A(T);
> +  A();
> +};
> +auto p1 = new A[]{1}; // { dg-error "creating array of template placeholder type" }
> +auto p2 = new A[1]{1}; // { dg-error "invalid use of placeholder" }
> +auto p3 = new A<int>[]{1};
> +auto p4 = new A<int>[1]{1};
> +auto p5 = new A[]{1, 2}; // { dg-error "creating array of template placeholder type" }
> +auto p6 = new A<int>[]{1, 2};
> +auto p7 = new A<int>[]{A(1), A(1)};
> +auto p8 = new A<int>[2]{A(1), A(1)};
> diff --git a/gcc/testsuite/g++.dg/cpp23/auto-array2.C b/gcc/testsuite/g++.dg/cpp23/auto-array2.C
> new file mode 100644
> index 00000000000..06431685b30
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp23/auto-array2.C
> @@ -0,0 +1,11 @@
> +// PR c++/101988
> +// { dg-do compile { target c++17 } }
> +
> +template<class T> struct A { A(); };
> +A<int> a[3];
> +auto (*p)[3] = &a;
> +A<int> (*p2)[3] = &a;
> +A (*p3)[3] = &a; // { dg-error "template placeholder type" }
> +auto (&r)[3] = a;
> +A<int> (&r2)[3] = a;
> +A (&r3)[3] = a; // { dg-error "template placeholder type" }
> 
> base-commit: fd5b0488ad5e4f29b65238e06a2d65b7de120235
diff mbox series

Patch

diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index 6534a7fd320..10e6956117e 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -11087,6 +11087,18 @@  create_array_type_for_decl (tree name, tree type, tree size, location_t loc)
   if (type == error_mark_node || size == error_mark_node)
     return error_mark_node;
 
+  /* [dcl.type.class.deduct] prohibits forming an array of placeholder
+     for a deduced class type.  */
+  if (is_auto (type) && CLASS_PLACEHOLDER_TEMPLATE (type))
+    {
+      if (name)
+	error_at (loc, "%qD declared as array of template placeholder "
+		  "type %qT", name, type);
+      else
+	error ("creating array of template placeholder type %qT", type);
+      return error_mark_node;
+    }
+
   /* If there are some types which cannot be array elements,
      issue an error-message and return.  */
   switch (TREE_CODE (type))
diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction-new1.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction-new1.C
new file mode 100644
index 00000000000..70283353619
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction-new1.C
@@ -0,0 +1,16 @@ 
+// PR c++/101988
+// { dg-do compile { target c++17 } }
+
+template<typename T>
+struct A {
+  A(T);
+  A();
+};
+auto p1 = new A[]{1}; // { dg-error "creating array of template placeholder type" }
+auto p2 = new A[1]{1}; // { dg-error "invalid use of placeholder" }
+auto p3 = new A<int>[]{1};
+auto p4 = new A<int>[1]{1};
+auto p5 = new A[]{1, 2}; // { dg-error "creating array of template placeholder type" }
+auto p6 = new A<int>[]{1, 2};
+auto p7 = new A<int>[]{A(1), A(1)};
+auto p8 = new A<int>[2]{A(1), A(1)};
diff --git a/gcc/testsuite/g++.dg/cpp23/auto-array2.C b/gcc/testsuite/g++.dg/cpp23/auto-array2.C
new file mode 100644
index 00000000000..06431685b30
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp23/auto-array2.C
@@ -0,0 +1,11 @@ 
+// PR c++/101988
+// { dg-do compile { target c++17 } }
+
+template<class T> struct A { A(); };
+A<int> a[3];
+auto (*p)[3] = &a;
+A<int> (*p2)[3] = &a;
+A (*p3)[3] = &a; // { dg-error "template placeholder type" }
+auto (&r)[3] = a;
+A<int> (&r2)[3] = a;
+A (&r3)[3] = a; // { dg-error "template placeholder type" }