c++: address of NTTP object as targ [PR113242]

Message ID 20240105165056.571235-1-ppalka@redhat.com
State Accepted
Headers
Series c++: address of NTTP object as targ [PR113242] |

Checks

Context Check Description
snail/gcc-patch-check success Github commit url

Commit Message

Patrick Palka Jan. 5, 2024, 4:50 p.m. UTC
  Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK
for trunk and perhaps 13?

-- >8 --

invalid_tparm_referent_p was rejecting using the address of a class NTTP
object as a template argument, but this should be fine.

	PR c++/113242

gcc/cp/ChangeLog:

	* pt.cc (invalid_tparm_referent_p) <case ADDR_EXPR>: Suppress
	DECL_ARTIFICIAL rejection test for class NTTP objects.

gcc/testsuite/ChangeLog:

	* g++.dg/cpp2a/nontype-class61.C: New test.
---
 gcc/cp/pt.cc                                 |  3 ++-
 gcc/testsuite/g++.dg/cpp2a/nontype-class61.C | 27 ++++++++++++++++++++
 2 files changed, 29 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/nontype-class61.C
  

Comments

Patrick Palka Jan. 15, 2024, 7:34 p.m. UTC | #1
On Fri, Jan 5, 2024 at 11:50 AM Patrick Palka <ppalka@redhat.com> wrote:
>
> Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK
> for trunk and perhaps 13?

Ping.

>
> -- >8 --
>
> invalid_tparm_referent_p was rejecting using the address of a class NTTP
> object as a template argument, but this should be fine.
>
>         PR c++/113242
>
> gcc/cp/ChangeLog:
>
>         * pt.cc (invalid_tparm_referent_p) <case ADDR_EXPR>: Suppress
>         DECL_ARTIFICIAL rejection test for class NTTP objects.
>
> gcc/testsuite/ChangeLog:
>
>         * g++.dg/cpp2a/nontype-class61.C: New test.
> ---
>  gcc/cp/pt.cc                                 |  3 ++-
>  gcc/testsuite/g++.dg/cpp2a/nontype-class61.C | 27 ++++++++++++++++++++
>  2 files changed, 29 insertions(+), 1 deletion(-)
>  create mode 100644 gcc/testsuite/g++.dg/cpp2a/nontype-class61.C
>
> diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
> index 154ac76cb65..8c7d178328d 100644
> --- a/gcc/cp/pt.cc
> +++ b/gcc/cp/pt.cc
> @@ -7219,7 +7219,8 @@ invalid_tparm_referent_p (tree type, tree expr, tsubst_flags_t complain)
>            * a string literal (5.13.5),
>            * the result of a typeid expression (8.2.8), or
>            * a predefined __func__ variable (11.4.1).  */
> -       else if (VAR_P (decl) && DECL_ARTIFICIAL (decl))
> +       else if (VAR_P (decl) && !DECL_NTTP_OBJECT_P (decl)
> +                && DECL_ARTIFICIAL (decl))
>           {
>             if (complain & tf_error)
>               error ("the address of %qD is not a valid template argument",
> diff --git a/gcc/testsuite/g++.dg/cpp2a/nontype-class61.C b/gcc/testsuite/g++.dg/cpp2a/nontype-class61.C
> new file mode 100644
> index 00000000000..90805a05ecf
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp2a/nontype-class61.C
> @@ -0,0 +1,27 @@
> +// PR c++/113242
> +// { dg-do compile { target c++20 } }
> +
> +struct wrapper {
> +  int n;
> +};
> +
> +template<const wrapper& X>
> +void f1() {
> +  static_assert(X.n == 42);
> +}
> +
> +template<const wrapper* X>
> +void f2() {
> +  static_assert(X->n == 42);
> +}
> +
> +template<wrapper X>
> +void g() {
> +  f1<X>();
> +  f2<&X>();
> +}
> +
> +int main() {
> +  constexpr wrapper X = {42};
> +  g<X>();
> +}
> --
> 2.43.0.254.ga26002b628
>
  
Jason Merrill Jan. 15, 2024, 9 p.m. UTC | #2
On 1/5/24 11:50, Patrick Palka wrote:
> Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK
> for trunk and perhaps 13?
> 
> -- >8 --
> 
> invalid_tparm_referent_p was rejecting using the address of a class NTTP
> object as a template argument, but this should be fine.

Hmm, I suppose so; https://eel.is/c++draft/temp#param-8 saying "No two 
template parameter objects are template-argument-equivalent" suggests 
there can be only one.  And clang/msvc allow it.

> 	PR c++/113242
> 
> gcc/cp/ChangeLog:
> 
> 	* pt.cc (invalid_tparm_referent_p) <case ADDR_EXPR>: Suppress
> 	DECL_ARTIFICIAL rejection test for class NTTP objects.
> 
> gcc/testsuite/ChangeLog:
> 
> 	* g++.dg/cpp2a/nontype-class61.C: New test.
> ---
>   gcc/cp/pt.cc                                 |  3 ++-
>   gcc/testsuite/g++.dg/cpp2a/nontype-class61.C | 27 ++++++++++++++++++++
>   2 files changed, 29 insertions(+), 1 deletion(-)
>   create mode 100644 gcc/testsuite/g++.dg/cpp2a/nontype-class61.C
> 
> diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
> index 154ac76cb65..8c7d178328d 100644
> --- a/gcc/cp/pt.cc
> +++ b/gcc/cp/pt.cc
> @@ -7219,7 +7219,8 @@ invalid_tparm_referent_p (tree type, tree expr, tsubst_flags_t complain)
>   	   * a string literal (5.13.5),
>   	   * the result of a typeid expression (8.2.8), or
>   	   * a predefined __func__ variable (11.4.1).  */
> -	else if (VAR_P (decl) && DECL_ARTIFICIAL (decl))
> +	else if (VAR_P (decl) && !DECL_NTTP_OBJECT_P (decl)
> +		 && DECL_ARTIFICIAL (decl))

If now some artificial variables are OK and others are not, perhaps we 
should enumerate them either way and abort if it's one we haven't 
specifically considered.

Jason
  
Patrick Palka Jan. 17, 2024, 3:43 p.m. UTC | #3
On Mon, 15 Jan 2024, Jason Merrill wrote:

> On 1/5/24 11:50, Patrick Palka wrote:
> > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK
> > for trunk and perhaps 13?
> > 
> > -- >8 --
> > 
> > invalid_tparm_referent_p was rejecting using the address of a class NTTP
> > object as a template argument, but this should be fine.
> 
> Hmm, I suppose so; https://eel.is/c++draft/temp#param-8 saying "No two
> template parameter objects are template-argument-equivalent" suggests there
> can be only one.  And clang/msvc allow it.
> 
> > 	PR c++/113242
> > 
> > gcc/cp/ChangeLog:
> > 
> > 	* pt.cc (invalid_tparm_referent_p) <case ADDR_EXPR>: Suppress
> > 	DECL_ARTIFICIAL rejection test for class NTTP objects.
> > 
> > gcc/testsuite/ChangeLog:
> > 
> > 	* g++.dg/cpp2a/nontype-class61.C: New test.
> > ---
> >   gcc/cp/pt.cc                                 |  3 ++-
> >   gcc/testsuite/g++.dg/cpp2a/nontype-class61.C | 27 ++++++++++++++++++++
> >   2 files changed, 29 insertions(+), 1 deletion(-)
> >   create mode 100644 gcc/testsuite/g++.dg/cpp2a/nontype-class61.C
> > 
> > diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
> > index 154ac76cb65..8c7d178328d 100644
> > --- a/gcc/cp/pt.cc
> > +++ b/gcc/cp/pt.cc
> > @@ -7219,7 +7219,8 @@ invalid_tparm_referent_p (tree type, tree expr,
> > tsubst_flags_t complain)
> >   	   * a string literal (5.13.5),
> >   	   * the result of a typeid expression (8.2.8), or
> >   	   * a predefined __func__ variable (11.4.1).  */
> > -	else if (VAR_P (decl) && DECL_ARTIFICIAL (decl))
> > +	else if (VAR_P (decl) && !DECL_NTTP_OBJECT_P (decl)
> > +		 && DECL_ARTIFICIAL (decl))
> 
> If now some artificial variables are OK and others are not, perhaps we should
> enumerate them either way and abort if it's one we haven't specifically
> considered.

Sounds good, like so?  Shall we backport this patch or the original
patch to the 13 branch?

-- >8 --

Subject: [PATCH] c++: address of class NTTP object as targ [PR113242]

invalid_tparm_referent_p was rejecting using the address of a class NTTP
object as a template argument, but this should be fine.

This patch fixes this by refining the DECL_ARTIFICIAL rejection test to
check specifically for the kinds of artificial variables we want to
exclude.

	PR c++/113242

gcc/cp/ChangeLog:

	* pt.cc (invalid_tparm_referent_p) <case ADDR_EXPR>: Refine
	DECL_ARTIFICIAL rejection test.  Assert that C++20 template
	parameter objects are the only artificial variables we accept.

gcc/testsuite/ChangeLog:

	* g++.dg/cpp2a/nontype-class61.C: New test.
---
 gcc/cp/pt.cc                                 | 13 +++++++---
 gcc/testsuite/g++.dg/cpp2a/nontype-class61.C | 27 ++++++++++++++++++++
 2 files changed, 37 insertions(+), 3 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/nontype-class61.C

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index b6117231de1..885c297450e 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -7212,12 +7212,14 @@ invalid_tparm_referent_p (tree type, tree expr, tsubst_flags_t complain)
 	/* C++17: For a non-type template-parameter of reference or pointer
 	   type, the value of the constant expression shall not refer to (or
 	   for a pointer type, shall not be the address of):
-	   * a subobject (4.5),
+	   * a subobject (4.5), (relaxed in C++20)
 	   * a temporary object (15.2),
-	   * a string literal (5.13.5),
+	   * a string literal (5.13.5), (we diagnose this early in
+	     convert_nontype_argument)
 	   * the result of a typeid expression (8.2.8), or
 	   * a predefined __func__ variable (11.4.1).  */
-	else if (VAR_P (decl) && DECL_ARTIFICIAL (decl))
+	else if (VAR_P (decl)
+		 && (DECL_TINFO_P (decl) || DECL_FNAME_P (decl)))
 	  {
 	    if (complain & tf_error)
 	      error ("the address of %qD is not a valid template argument",
@@ -7242,6 +7244,11 @@ invalid_tparm_referent_p (tree type, tree expr, tsubst_flags_t complain)
 		     decl);
 	    return true;
 	  }
+
+	/* The only artificial variables we do accept are C++20
+	   template parameter objects.   */
+	if (VAR_P (decl) && DECL_ARTIFICIAL (decl))
+	  gcc_checking_assert (DECL_NTTP_OBJECT_P (decl));
       }
       break;
 
diff --git a/gcc/testsuite/g++.dg/cpp2a/nontype-class61.C b/gcc/testsuite/g++.dg/cpp2a/nontype-class61.C
new file mode 100644
index 00000000000..90805a05ecf
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/nontype-class61.C
@@ -0,0 +1,27 @@
+// PR c++/113242
+// { dg-do compile { target c++20 } }
+
+struct wrapper {
+  int n;
+};
+
+template<const wrapper& X>
+void f1() {
+  static_assert(X.n == 42);
+}
+
+template<const wrapper* X>
+void f2() {
+  static_assert(X->n == 42);
+}
+
+template<wrapper X>
+void g() {
+  f1<X>();
+  f2<&X>();
+}
+
+int main() {
+  constexpr wrapper X = {42};
+  g<X>();
+}
  
Jason Merrill Jan. 17, 2024, 4:34 p.m. UTC | #4
On 1/17/24 10:43, Patrick Palka wrote:
> On Mon, 15 Jan 2024, Jason Merrill wrote:
>> On 1/5/24 11:50, Patrick Palka wrote:
>>>
>>> invalid_tparm_referent_p was rejecting using the address of a class NTTP
>>> object as a template argument, but this should be fine.
>>
>> Hmm, I suppose so; https://eel.is/c++draft/temp#param-8 saying "No two
>> template parameter objects are template-argument-equivalent" suggests there
>> can be only one.  And clang/msvc allow it.
>>
>>> +	else if (VAR_P (decl) && !DECL_NTTP_OBJECT_P (decl)
>>> +		 && DECL_ARTIFICIAL (decl))
>>
>> If now some artificial variables are OK and others are not, perhaps we should
>> enumerate them either way and abort if it's one we haven't specifically
>> considered.
> 
> Sounds good, like so?  Shall we backport this patch or the original
> patch to the 13 branch?

Hmm, looks like this patch changes the non-checking default behavior 
from reject to accept; maybe just add a checking_assert (tinfo || fname) 
to your original patch?  OK with that change, for trunk and 13.

> -- >8 --
> 
> Subject: [PATCH] c++: address of class NTTP object as targ [PR113242]
> 
> invalid_tparm_referent_p was rejecting using the address of a class NTTP
> object as a template argument, but this should be fine.
> 
> This patch fixes this by refining the DECL_ARTIFICIAL rejection test to
> check specifically for the kinds of artificial variables we want to
> exclude.
> 
> 	PR c++/113242
> 
> gcc/cp/ChangeLog:
> 
> 	* pt.cc (invalid_tparm_referent_p) <case ADDR_EXPR>: Refine
> 	DECL_ARTIFICIAL rejection test.  Assert that C++20 template
> 	parameter objects are the only artificial variables we accept.
> 
> gcc/testsuite/ChangeLog:
> 
> 	* g++.dg/cpp2a/nontype-class61.C: New test.
> ---
>   gcc/cp/pt.cc                                 | 13 +++++++---
>   gcc/testsuite/g++.dg/cpp2a/nontype-class61.C | 27 ++++++++++++++++++++
>   2 files changed, 37 insertions(+), 3 deletions(-)
>   create mode 100644 gcc/testsuite/g++.dg/cpp2a/nontype-class61.C
> 
> diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
> index b6117231de1..885c297450e 100644
> --- a/gcc/cp/pt.cc
> +++ b/gcc/cp/pt.cc
> @@ -7212,12 +7212,14 @@ invalid_tparm_referent_p (tree type, tree expr, tsubst_flags_t complain)
>   	/* C++17: For a non-type template-parameter of reference or pointer
>   	   type, the value of the constant expression shall not refer to (or
>   	   for a pointer type, shall not be the address of):
> -	   * a subobject (4.5),
> +	   * a subobject (4.5), (relaxed in C++20)
>   	   * a temporary object (15.2),
> -	   * a string literal (5.13.5),
> +	   * a string literal (5.13.5), (we diagnose this early in
> +	     convert_nontype_argument)
>   	   * the result of a typeid expression (8.2.8), or
>   	   * a predefined __func__ variable (11.4.1).  */
> -	else if (VAR_P (decl) && DECL_ARTIFICIAL (decl))
> +	else if (VAR_P (decl)
> +		 && (DECL_TINFO_P (decl) || DECL_FNAME_P (decl)))
>   	  {
>   	    if (complain & tf_error)
>   	      error ("the address of %qD is not a valid template argument",
> @@ -7242,6 +7244,11 @@ invalid_tparm_referent_p (tree type, tree expr, tsubst_flags_t complain)
>   		     decl);
>   	    return true;
>   	  }
> +
> +	/* The only artificial variables we do accept are C++20
> +	   template parameter objects.   */
> +	if (VAR_P (decl) && DECL_ARTIFICIAL (decl))
> +	  gcc_checking_assert (DECL_NTTP_OBJECT_P (decl));
>         }
>         break;
>   
> diff --git a/gcc/testsuite/g++.dg/cpp2a/nontype-class61.C b/gcc/testsuite/g++.dg/cpp2a/nontype-class61.C
> new file mode 100644
> index 00000000000..90805a05ecf
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp2a/nontype-class61.C
> @@ -0,0 +1,27 @@
> +// PR c++/113242
> +// { dg-do compile { target c++20 } }
> +
> +struct wrapper {
> +  int n;
> +};
> +
> +template<const wrapper& X>
> +void f1() {
> +  static_assert(X.n == 42);
> +}
> +
> +template<const wrapper* X>
> +void f2() {
> +  static_assert(X->n == 42);
> +}
> +
> +template<wrapper X>
> +void g() {
> +  f1<X>();
> +  f2<&X>();
> +}
> +
> +int main() {
> +  constexpr wrapper X = {42};
> +  g<X>();
> +}
  

Patch

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 154ac76cb65..8c7d178328d 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -7219,7 +7219,8 @@  invalid_tparm_referent_p (tree type, tree expr, tsubst_flags_t complain)
 	   * a string literal (5.13.5),
 	   * the result of a typeid expression (8.2.8), or
 	   * a predefined __func__ variable (11.4.1).  */
-	else if (VAR_P (decl) && DECL_ARTIFICIAL (decl))
+	else if (VAR_P (decl) && !DECL_NTTP_OBJECT_P (decl)
+		 && DECL_ARTIFICIAL (decl))
 	  {
 	    if (complain & tf_error)
 	      error ("the address of %qD is not a valid template argument",
diff --git a/gcc/testsuite/g++.dg/cpp2a/nontype-class61.C b/gcc/testsuite/g++.dg/cpp2a/nontype-class61.C
new file mode 100644
index 00000000000..90805a05ecf
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/nontype-class61.C
@@ -0,0 +1,27 @@ 
+// PR c++/113242
+// { dg-do compile { target c++20 } }
+
+struct wrapper {
+  int n;
+};
+
+template<const wrapper& X>
+void f1() {
+  static_assert(X.n == 42);
+}
+
+template<const wrapper* X>
+void f2() {
+  static_assert(X->n == 42);
+}
+
+template<wrapper X>
+void g() {
+  f1<X>();
+  f2<&X>();
+}
+
+int main() {
+  constexpr wrapper X = {42};
+  g<X>();
+}