c++: P2308, Template parameter initialization (tests) [PR113800]

Message ID 20250212185455.488233-1-polacek@redhat.com
State Committed
Commit 84f19ecb01958fa791b9213dbd80331474fca9f0
Headers
Series c++: P2308, Template parameter initialization (tests) [PR113800] |

Checks

Context Check Description
linaro-tcwg-bot/tcwg_gcc_build--master-aarch64 success Build passed
linaro-tcwg-bot/tcwg_gcc_check--master-aarch64 success Test passed
linaro-tcwg-bot/tcwg_simplebootstrap_build--master-arm-bootstrap success Build passed
linaro-tcwg-bot/tcwg_gcc_build--master-arm success Build passed
linaro-tcwg-bot/tcwg_simplebootstrap_build--master-aarch64-bootstrap success Build passed

Commit Message

Marek Polacek Feb. 12, 2025, 6:54 p.m. UTC
  Tested on x86_64-pc-linux-gnu, ok for trunk?  I'll also update cxx-status.html.

-- >8 --
This proposal was implemented a long time ago by my r9-5271,
but it took me this long to verify that it still works as per P2308.

This patch adds assorted tests, both from clang and from [temp.arg.nontype].
Fortunately I did not discover any issues in the compiler.

	PR c++/113800
	DR 2450

gcc/testsuite/ChangeLog:

	* g++.dg/cpp26/pack-indexing15.C: New test.
	* g++.dg/cpp2a/nontype-class68.C: New test.
	* g++.dg/cpp2a/nontype-class69.C: New test.
	* g++.dg/cpp2a/nontype-class70.C: New test.
	* g++.dg/cpp2a/nontype-class71.C: New test.
	* g++.dg/cpp2a/nontype-class72.C: New test.
---
 gcc/testsuite/g++.dg/cpp26/pack-indexing15.C | 20 +++++++++
 gcc/testsuite/g++.dg/cpp2a/nontype-class68.C | 24 ++++++++++
 gcc/testsuite/g++.dg/cpp2a/nontype-class69.C | 27 +++++++++++
 gcc/testsuite/g++.dg/cpp2a/nontype-class70.C | 47 ++++++++++++++++++++
 gcc/testsuite/g++.dg/cpp2a/nontype-class71.C | 19 ++++++++
 gcc/testsuite/g++.dg/cpp2a/nontype-class72.C | 41 +++++++++++++++++
 6 files changed, 178 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/cpp26/pack-indexing15.C
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/nontype-class68.C
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/nontype-class69.C
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/nontype-class70.C
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/nontype-class71.C
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/nontype-class72.C


base-commit: cfdb961588ba318a78e995d2e2cde43130acd993
  

Comments

Jason Merrill Feb. 12, 2025, 11:12 p.m. UTC | #1
On 2/12/25 7:54 PM, Marek Polacek wrote:
> Tested on x86_64-pc-linux-gnu, ok for trunk?  I'll also update cxx-status.html.

OK.

> -- >8 --
> This proposal was implemented a long time ago by my r9-5271,
> but it took me this long to verify that it still works as per P2308.
> 
> This patch adds assorted tests, both from clang and from [temp.arg.nontype].
> Fortunately I did not discover any issues in the compiler.
> 
> 	PR c++/113800
> 	DR 2450
> 
> gcc/testsuite/ChangeLog:
> 
> 	* g++.dg/cpp26/pack-indexing15.C: New test.
> 	* g++.dg/cpp2a/nontype-class68.C: New test.
> 	* g++.dg/cpp2a/nontype-class69.C: New test.
> 	* g++.dg/cpp2a/nontype-class70.C: New test.
> 	* g++.dg/cpp2a/nontype-class71.C: New test.
> 	* g++.dg/cpp2a/nontype-class72.C: New test.
> ---
>   gcc/testsuite/g++.dg/cpp26/pack-indexing15.C | 20 +++++++++
>   gcc/testsuite/g++.dg/cpp2a/nontype-class68.C | 24 ++++++++++
>   gcc/testsuite/g++.dg/cpp2a/nontype-class69.C | 27 +++++++++++
>   gcc/testsuite/g++.dg/cpp2a/nontype-class70.C | 47 ++++++++++++++++++++
>   gcc/testsuite/g++.dg/cpp2a/nontype-class71.C | 19 ++++++++
>   gcc/testsuite/g++.dg/cpp2a/nontype-class72.C | 41 +++++++++++++++++
>   6 files changed, 178 insertions(+)
>   create mode 100644 gcc/testsuite/g++.dg/cpp26/pack-indexing15.C
>   create mode 100644 gcc/testsuite/g++.dg/cpp2a/nontype-class68.C
>   create mode 100644 gcc/testsuite/g++.dg/cpp2a/nontype-class69.C
>   create mode 100644 gcc/testsuite/g++.dg/cpp2a/nontype-class70.C
>   create mode 100644 gcc/testsuite/g++.dg/cpp2a/nontype-class71.C
>   create mode 100644 gcc/testsuite/g++.dg/cpp2a/nontype-class72.C
> 
> diff --git a/gcc/testsuite/g++.dg/cpp26/pack-indexing15.C b/gcc/testsuite/g++.dg/cpp26/pack-indexing15.C
> new file mode 100644
> index 00000000000..3f8382b12cd
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp26/pack-indexing15.C
> @@ -0,0 +1,20 @@
> +// PR c++/113800
> +// { dg-do compile { target c++26 } }
> +// From LLVM's temp_arg_nontype_cxx2c.cpp.
> +
> +template<class... T>
> +concept C = sizeof(T...[1]) == 1;
> +
> +struct A {};
> +
> +template<class T, C<T> auto = A{}> struct Set {};
> +
> +template<class T>
> +void
> +foo ()
> +{
> +  Set<T> u;
> +}
> +
> +Set<bool> sb;
> +Set<float> sf; // { dg-error "placeholder constraints not satisfied" }
> diff --git a/gcc/testsuite/g++.dg/cpp2a/nontype-class68.C b/gcc/testsuite/g++.dg/cpp2a/nontype-class68.C
> new file mode 100644
> index 00000000000..ade646e391b
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp2a/nontype-class68.C
> @@ -0,0 +1,24 @@
> +// PR c++/113800
> +// { dg-do compile { target c++20 } }
> +// From [temp.arg.nontype].
> +
> +template<auto n> struct B { /* ... */ };
> +B<5> b1;                        // OK, template parameter type is int
> +B<'a'> b2;                      // OK, template parameter type is char
> +B<2.5> b3;                      // OK, template parameter type is double
> +B<void(0)> b4;                  // { dg-error ".void. is not a valid type for a template non-type parameter" }
> +
> +template<int i> struct C { /* ... */ };
> +C<{ 42 }> c1;   // OK
> +
> +struct J1 {
> +  J1 *self = this;
> +};
> +B<J1{}> j1;     // { dg-error "not a constant expression" }
> +
> +struct J2 {
> +  J2 *self = this;
> +  constexpr J2() {}
> +  constexpr J2(const J2&) {}
> +};
> +B<J2{}> j2;     // { dg-error "not a constant expression" }
> diff --git a/gcc/testsuite/g++.dg/cpp2a/nontype-class69.C b/gcc/testsuite/g++.dg/cpp2a/nontype-class69.C
> new file mode 100644
> index 00000000000..08b0a5ef73c
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp2a/nontype-class69.C
> @@ -0,0 +1,27 @@
> +// PR c++/113800
> +// { dg-do compile { target c++20 } }
> +
> +// DR 2450
> +struct S { int a; };
> +
> +template<S s>
> +void
> +f ()
> +{
> +}
> +
> +void
> +test ()
> +{
> +  f<{0}>();
> +  f<{.a= 0}>();
> +}
> +
> +// DR 2459
> +struct A {
> +  constexpr A (float) {}
> +};
> +
> +template<A>
> +struct X {};
> +X<1> x;
> diff --git a/gcc/testsuite/g++.dg/cpp2a/nontype-class70.C b/gcc/testsuite/g++.dg/cpp2a/nontype-class70.C
> new file mode 100644
> index 00000000000..0e50847e440
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp2a/nontype-class70.C
> @@ -0,0 +1,47 @@
> +// PR c++/113800
> +// P2308R1 - Template parameter initialization
> +// { dg-do compile { target c++20 } }
> +
> +struct S {
> +  int a = 0;
> +  int b = 42;
> +};
> +
> +template <S t>
> +struct A {
> +  static constexpr auto a = t.a;
> +  static constexpr auto b = t.b;
> +};
> +
> +static_assert(A<{}>::a == 0);
> +static_assert(A<{}>::b == 42);
> +static_assert(A<{.a = 3}>::a == 3);
> +static_assert(A<{.b = 4}>::b == 4);
> +
> +template<S = {}>
> +struct D1 {};
> +
> +template<S = {1, 2}>
> +struct D2 {};
> +
> +template <S = {.b = 5}>
> +struct D3 {};
> +
> +struct E {};
> +
> +struct I {
> +  constexpr I(E) {};
> +};
> +
> +template<typename T, T>
> +struct W {};
> +
> +void
> +g ()
> +{
> +  D1<> d1;
> +  D2<> d2;
> +  D3<> d3;
> +
> +  W<I, {E{}}> w;
> +}
> diff --git a/gcc/testsuite/g++.dg/cpp2a/nontype-class71.C b/gcc/testsuite/g++.dg/cpp2a/nontype-class71.C
> new file mode 100644
> index 00000000000..36ce5b16dee
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp2a/nontype-class71.C
> @@ -0,0 +1,19 @@
> +// PR c++/113800
> +// { dg-do compile { target c++20 } }
> +// From LLVM's temp_arg_nontype_cxx2c.cpp.
> +
> +template<class T, int I>
> +struct A {
> +  T x[I];
> +};
> +
> +template<class T, class... U>
> +A(T, U...) -> A<T, 1 + sizeof...(U)>;
> +
> +template<A a> void foo() { }
> +
> +void
> +bar ()
> +{
> +  foo<{1}>();
> +}
> diff --git a/gcc/testsuite/g++.dg/cpp2a/nontype-class72.C b/gcc/testsuite/g++.dg/cpp2a/nontype-class72.C
> new file mode 100644
> index 00000000000..1c48ff57add
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp2a/nontype-class72.C
> @@ -0,0 +1,41 @@
> +// PR c++/113800
> +// P2308R1 - Template parameter initialization
> +// { dg-do compile { target c++20 } }
> +// Invalid cases.
> +
> +namespace std {
> +template <typename T> class initializer_list {
> +  const T *_M_array;
> +  decltype (sizeof 0) _M_len;
> +};
> +}
> +
> +template<auto>
> +struct X {};
> +
> +struct A {
> +  int i;
> +};
> +
> +template<A>
> +struct B { };
> +
> +struct E {};
> +
> +struct I {	  // { dg-message "not literal" }
> +  I(E) {};
> +};
> +
> +template<typename T, T>
> +struct W {};
> +
> +void
> +g ()
> +{
> +  X<{0}> x;	  // { dg-error "unable to deduce" }
> +
> +  int i = 42;	  // { dg-message "not const" }
> +  B<{i}> b;	  // { dg-error "not usable" }
> +
> +  W<I, {E{}}> w;  // { dg-error "not a valid type for a template non-type parameter" }
> +}
> 
> base-commit: cfdb961588ba318a78e995d2e2cde43130acd993
  

Patch

diff --git a/gcc/testsuite/g++.dg/cpp26/pack-indexing15.C b/gcc/testsuite/g++.dg/cpp26/pack-indexing15.C
new file mode 100644
index 00000000000..3f8382b12cd
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp26/pack-indexing15.C
@@ -0,0 +1,20 @@ 
+// PR c++/113800
+// { dg-do compile { target c++26 } }
+// From LLVM's temp_arg_nontype_cxx2c.cpp.
+
+template<class... T>
+concept C = sizeof(T...[1]) == 1;
+
+struct A {};
+
+template<class T, C<T> auto = A{}> struct Set {};
+
+template<class T>
+void
+foo ()
+{
+  Set<T> u;
+}
+
+Set<bool> sb;
+Set<float> sf; // { dg-error "placeholder constraints not satisfied" }
diff --git a/gcc/testsuite/g++.dg/cpp2a/nontype-class68.C b/gcc/testsuite/g++.dg/cpp2a/nontype-class68.C
new file mode 100644
index 00000000000..ade646e391b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/nontype-class68.C
@@ -0,0 +1,24 @@ 
+// PR c++/113800
+// { dg-do compile { target c++20 } }
+// From [temp.arg.nontype].
+
+template<auto n> struct B { /* ... */ };
+B<5> b1;                        // OK, template parameter type is int
+B<'a'> b2;                      // OK, template parameter type is char
+B<2.5> b3;                      // OK, template parameter type is double
+B<void(0)> b4;                  // { dg-error ".void. is not a valid type for a template non-type parameter" }
+
+template<int i> struct C { /* ... */ };
+C<{ 42 }> c1;   // OK
+
+struct J1 {
+  J1 *self = this;
+};
+B<J1{}> j1;     // { dg-error "not a constant expression" }
+
+struct J2 {
+  J2 *self = this;
+  constexpr J2() {}
+  constexpr J2(const J2&) {}
+};
+B<J2{}> j2;     // { dg-error "not a constant expression" }
diff --git a/gcc/testsuite/g++.dg/cpp2a/nontype-class69.C b/gcc/testsuite/g++.dg/cpp2a/nontype-class69.C
new file mode 100644
index 00000000000..08b0a5ef73c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/nontype-class69.C
@@ -0,0 +1,27 @@ 
+// PR c++/113800
+// { dg-do compile { target c++20 } }
+
+// DR 2450
+struct S { int a; };
+
+template<S s>
+void
+f ()
+{
+}
+
+void
+test ()
+{
+  f<{0}>();
+  f<{.a= 0}>();
+}
+
+// DR 2459
+struct A {
+  constexpr A (float) {}
+};
+
+template<A>
+struct X {};
+X<1> x;
diff --git a/gcc/testsuite/g++.dg/cpp2a/nontype-class70.C b/gcc/testsuite/g++.dg/cpp2a/nontype-class70.C
new file mode 100644
index 00000000000..0e50847e440
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/nontype-class70.C
@@ -0,0 +1,47 @@ 
+// PR c++/113800
+// P2308R1 - Template parameter initialization
+// { dg-do compile { target c++20 } }
+
+struct S {
+  int a = 0;
+  int b = 42;
+};
+
+template <S t>
+struct A {
+  static constexpr auto a = t.a;
+  static constexpr auto b = t.b;
+};
+
+static_assert(A<{}>::a == 0);
+static_assert(A<{}>::b == 42);
+static_assert(A<{.a = 3}>::a == 3);
+static_assert(A<{.b = 4}>::b == 4);
+
+template<S = {}>
+struct D1 {};
+
+template<S = {1, 2}>
+struct D2 {};
+
+template <S = {.b = 5}>
+struct D3 {};
+
+struct E {};
+
+struct I {
+  constexpr I(E) {};
+};
+
+template<typename T, T>
+struct W {};
+
+void
+g ()
+{
+  D1<> d1;
+  D2<> d2;
+  D3<> d3;
+
+  W<I, {E{}}> w;
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/nontype-class71.C b/gcc/testsuite/g++.dg/cpp2a/nontype-class71.C
new file mode 100644
index 00000000000..36ce5b16dee
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/nontype-class71.C
@@ -0,0 +1,19 @@ 
+// PR c++/113800
+// { dg-do compile { target c++20 } }
+// From LLVM's temp_arg_nontype_cxx2c.cpp.
+
+template<class T, int I>
+struct A {
+  T x[I];
+};
+
+template<class T, class... U>
+A(T, U...) -> A<T, 1 + sizeof...(U)>;
+
+template<A a> void foo() { }
+
+void
+bar ()
+{
+  foo<{1}>();
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/nontype-class72.C b/gcc/testsuite/g++.dg/cpp2a/nontype-class72.C
new file mode 100644
index 00000000000..1c48ff57add
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/nontype-class72.C
@@ -0,0 +1,41 @@ 
+// PR c++/113800
+// P2308R1 - Template parameter initialization
+// { dg-do compile { target c++20 } }
+// Invalid cases.
+
+namespace std {
+template <typename T> class initializer_list {
+  const T *_M_array;
+  decltype (sizeof 0) _M_len;
+};
+}
+
+template<auto>
+struct X {};
+
+struct A {
+  int i;
+};
+
+template<A>
+struct B { };
+
+struct E {};
+
+struct I {	  // { dg-message "not literal" }
+  I(E) {};
+};
+
+template<typename T, T>
+struct W {};
+
+void
+g ()
+{
+  X<{0}> x;	  // { dg-error "unable to deduce" }
+
+  int i = 42;	  // { dg-message "not const" }
+  B<{i}> b;	  // { dg-error "not usable" }
+
+  W<I, {E{}}> w;  // { dg-error "not a valid type for a template non-type parameter" }
+}