public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH] c++: non-dependent variable template-id [PR108848]
@ 2023-02-23 21:52 Patrick Palka
  2023-02-27 22:36 ` Jason Merrill
  0 siblings, 1 reply; 2+ messages in thread
From: Patrick Palka @ 2023-02-23 21:52 UTC (permalink / raw)
  To: gcc-patches; +Cc: jason, Patrick Palka

Here we're incorrectly treating the non-dependent variable template-id
tag<int> as dependent ever since r226642 gave variable TEMPLATE_ID_EXPR
an empty type which causes the call to finish_template_variable from
finish_id_expression_1 to be dead code at template parse time.  Thus
we're led into treating tag<int>.var<void> as a dependent name at parse
time.

This patch fixes this by making finish_id_expression_1 instantiate a
variable template-id as long as the template and args are non-dependent
according to the dependence test in lookup_and_finish_template_variable
and not according to type_dependent_expression_p.  This patch also moves
said dependence test into finish_template_variable.

bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
trunk?

	PR c++/108848

gcc/cp/ChangeLog:

	* pt.cc (finish_template_variable): Move dependence check
	to here from ...
	(lookup_and_finish_template_variable): ... here.
	* semantics.cc (finish_id_expression_1): Call
	finish_template_variable sooner and regardless of
	type_dependent_expression_p.

gcc/testsuite/ChangeLog:

	* g++.dg/cpp1y/noexcept1.C: Don't expect bogus "different
	exception specifier" error.  Expect a separate "not usable
	in a constant expression" error.
	* g++.dg/cpp1y/var-templ70.C: New test.
	* g++.dg/cpp1y/var-templ71.C: New test.
---
 gcc/cp/pt.cc                             | 18 ++++++++++--------
 gcc/cp/semantics.cc                      | 14 +++++---------
 gcc/testsuite/g++.dg/cpp1y/noexcept1.C   |  4 ++--
 gcc/testsuite/g++.dg/cpp1y/var-templ70.C | 20 ++++++++++++++++++++
 gcc/testsuite/g++.dg/cpp1y/var-templ71.C | 10 ++++++++++
 5 files changed, 47 insertions(+), 19 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp1y/var-templ70.C
 create mode 100644 gcc/testsuite/g++.dg/cpp1y/var-templ71.C

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index b1ac7d4beb4..11c0baa0119 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -10317,7 +10317,8 @@ lookup_template_variable (tree templ, tree arglist)
   return build2 (TEMPLATE_ID_EXPR, NULL_TREE, templ, arglist);
 }
 
-/* Instantiate a variable declaration from a TEMPLATE_ID_EXPR for use. */
+/* Instantiate a variable declaration from a TEMPLATE_ID_EXPR if it's
+   not dependent.  */
 
 tree
 finish_template_variable (tree var, tsubst_flags_t complain)
@@ -10325,6 +10326,12 @@ finish_template_variable (tree var, tsubst_flags_t complain)
   tree templ = TREE_OPERAND (var, 0);
   tree arglist = TREE_OPERAND (var, 1);
 
+  /* If the template or arguments are dependent, then we
+     can't instantiate yet.  */
+  if (TMPL_PARMS_DEPTH (DECL_TEMPLATE_PARMS (templ)) != 1
+      || any_dependent_template_arguments_p (arglist))
+    return var;
+
   tree parms = DECL_TEMPLATE_PARMS (templ);
   arglist = coerce_template_parms (parms, arglist, templ, complain);
   if (arglist == error_mark_node)
@@ -10352,13 +10359,8 @@ lookup_and_finish_template_variable (tree templ, tree targs,
 				     tsubst_flags_t complain)
 {
   tree var = lookup_template_variable (templ, targs);
-  if (TMPL_PARMS_DEPTH (DECL_TEMPLATE_PARMS (templ)) == 1
-      && !any_dependent_template_arguments_p (targs))
-    {
-      var = finish_template_variable (var, complain);
-      mark_used (var);
-    }
-
+  var = finish_template_variable (var, complain);
+  mark_used (var);
   return convert_from_reference (var);
 }
 
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index c2df0b69b30..a18364dda4f 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -4208,6 +4208,11 @@ finish_id_expression_1 (tree id_expression,
     }
   else
     {
+      if (TREE_CODE (decl) == TEMPLATE_ID_EXPR
+	  && variable_template_p (TREE_OPERAND (decl, 0))
+	  && !concept_check_p (decl))
+	decl = finish_template_variable (decl);
+
       bool dependent_p = type_dependent_expression_p (decl);
 
       /* If the declaration was explicitly qualified indicate
@@ -4275,15 +4280,6 @@ finish_id_expression_1 (tree id_expression,
 	/* Replace an evaluated use of the thread_local variable with
 	   a call to its wrapper.  */
 	decl = wrap;
-      else if (TREE_CODE (decl) == TEMPLATE_ID_EXPR
-	       && !dependent_p
-	       && variable_template_p (TREE_OPERAND (decl, 0))
-	       && !concept_check_p (decl))
-	{
-	  decl = finish_template_variable (decl);
-	  mark_used (decl);
-	  decl = convert_from_reference (decl);
-	}
       else if (concept_check_p (decl))
 	{
 	  /* Nothing more to do. All of the analysis for concept checks
diff --git a/gcc/testsuite/g++.dg/cpp1y/noexcept1.C b/gcc/testsuite/g++.dg/cpp1y/noexcept1.C
index 86e46c96148..caa4a056a2e 100644
--- a/gcc/testsuite/g++.dg/cpp1y/noexcept1.C
+++ b/gcc/testsuite/g++.dg/cpp1y/noexcept1.C
@@ -5,9 +5,9 @@ template <int> bool b;
 
 template <typename> 
 struct C {
-  template <typename> friend int foo() noexcept(b<1>); // { dg-error "not usable in a constant expression|different exception specifier" }
+  template <typename> friend int foo() noexcept(b<1>); // { dg-error "not usable in a constant expression" }
 };
 
-template <typename> int foo() noexcept(b<1>);
+template <typename> int foo() noexcept(b<1>); // { dg-error "not usable in a constant expression" }
 
 auto a = C<int>();
diff --git a/gcc/testsuite/g++.dg/cpp1y/var-templ70.C b/gcc/testsuite/g++.dg/cpp1y/var-templ70.C
new file mode 100644
index 00000000000..aed2db5de88
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/var-templ70.C
@@ -0,0 +1,20 @@
+// PR c++/108848
+// { dg-do compile { target c++14 } }
+
+template<class T>
+struct tag_t {
+  template<class Sig>
+  static constexpr const Sig* var = nullptr;
+
+  template<class Sig>
+  static const Sig* fun();
+};
+
+template <class T>
+constexpr tag_t<T> tag {};
+
+template<class T>
+void f() {
+  tag<int>.var<void>;   // { dg-bogus "expected 'template' keyword" }
+  tag<int>.fun<void>(); // { dg-bogus "expected 'template' keyword" }
+};
diff --git a/gcc/testsuite/g++.dg/cpp1y/var-templ71.C b/gcc/testsuite/g++.dg/cpp1y/var-templ71.C
new file mode 100644
index 00000000000..df33c62ec3e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/var-templ71.C
@@ -0,0 +1,10 @@
+// Verify we can evaluate a non-dependent variable template-id ahead of time.
+// { dg-do compile { target c++14 } }
+
+template<class Sig>
+static constexpr int var = 0;
+
+template<class T>
+void f() {
+  static_assert(var<void>); // { dg-error "assert" }
+}
-- 
2.39.2.542.g06dd2baa8d


^ permalink raw reply	[flat|nested] 2+ messages in thread

* Re: [PATCH] c++: non-dependent variable template-id [PR108848]
  2023-02-23 21:52 [PATCH] c++: non-dependent variable template-id [PR108848] Patrick Palka
@ 2023-02-27 22:36 ` Jason Merrill
  0 siblings, 0 replies; 2+ messages in thread
From: Jason Merrill @ 2023-02-27 22:36 UTC (permalink / raw)
  To: Patrick Palka, gcc-patches

On 2/23/23 16:52, Patrick Palka wrote:
> Here we're incorrectly treating the non-dependent variable template-id
> tag<int> as dependent ever since r226642 gave variable TEMPLATE_ID_EXPR
> an empty type which causes the call to finish_template_variable from
> finish_id_expression_1 to be dead code at template parse time.  Thus
> we're led into treating tag<int>.var<void> as a dependent name at parse
> time.
> 
> This patch fixes this by making finish_id_expression_1 instantiate a
> variable template-id as long as the template and args are non-dependent
> according to the dependence test in lookup_and_finish_template_variable
> and not according to type_dependent_expression_p.  This patch also moves
> said dependence test into finish_template_variable.
> 
> bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
> trunk?
> 
> 	PR c++/108848
> 
> gcc/cp/ChangeLog:
> 
> 	* pt.cc (finish_template_variable): Move dependence check
> 	to here from ...
> 	(lookup_and_finish_template_variable): ... here.
> 	* semantics.cc (finish_id_expression_1): Call
> 	finish_template_variable sooner and regardless of
> 	type_dependent_expression_p.
> 
> gcc/testsuite/ChangeLog:
> 
> 	* g++.dg/cpp1y/noexcept1.C: Don't expect bogus "different
> 	exception specifier" error.  Expect a separate "not usable
> 	in a constant expression" error.
> 	* g++.dg/cpp1y/var-templ70.C: New test.
> 	* g++.dg/cpp1y/var-templ71.C: New test.
> ---
>   gcc/cp/pt.cc                             | 18 ++++++++++--------
>   gcc/cp/semantics.cc                      | 14 +++++---------
>   gcc/testsuite/g++.dg/cpp1y/noexcept1.C   |  4 ++--
>   gcc/testsuite/g++.dg/cpp1y/var-templ70.C | 20 ++++++++++++++++++++
>   gcc/testsuite/g++.dg/cpp1y/var-templ71.C | 10 ++++++++++
>   5 files changed, 47 insertions(+), 19 deletions(-)
>   create mode 100644 gcc/testsuite/g++.dg/cpp1y/var-templ70.C
>   create mode 100644 gcc/testsuite/g++.dg/cpp1y/var-templ71.C
> 
> diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
> index b1ac7d4beb4..11c0baa0119 100644
> --- a/gcc/cp/pt.cc
> +++ b/gcc/cp/pt.cc
> @@ -10317,7 +10317,8 @@ lookup_template_variable (tree templ, tree arglist)
>     return build2 (TEMPLATE_ID_EXPR, NULL_TREE, templ, arglist);
>   }
>   
> -/* Instantiate a variable declaration from a TEMPLATE_ID_EXPR for use. */
> +/* Instantiate a variable declaration from a TEMPLATE_ID_EXPR if it's
> +   not dependent.  */
>   
>   tree
>   finish_template_variable (tree var, tsubst_flags_t complain)
> @@ -10325,6 +10326,12 @@ finish_template_variable (tree var, tsubst_flags_t complain)
>     tree templ = TREE_OPERAND (var, 0);
>     tree arglist = TREE_OPERAND (var, 1);
>   
> +  /* If the template or arguments are dependent, then we
> +     can't instantiate yet.  */
> +  if (TMPL_PARMS_DEPTH (DECL_TEMPLATE_PARMS (templ)) != 1
> +      || any_dependent_template_arguments_p (arglist))
> +    return var;
> +
>     tree parms = DECL_TEMPLATE_PARMS (templ);
>     arglist = coerce_template_parms (parms, arglist, templ, complain);
>     if (arglist == error_mark_node)
> @@ -10352,13 +10359,8 @@ lookup_and_finish_template_variable (tree templ, tree targs,
>   				     tsubst_flags_t complain)
>   {
>     tree var = lookup_template_variable (templ, targs);
> -  if (TMPL_PARMS_DEPTH (DECL_TEMPLATE_PARMS (templ)) == 1
> -      && !any_dependent_template_arguments_p (targs))
> -    {
> -      var = finish_template_variable (var, complain);
> -      mark_used (var);
> -    }
> -
> +  var = finish_template_variable (var, complain);
> +  mark_used (var);
>     return convert_from_reference (var);
>   }
>   
> diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
> index c2df0b69b30..a18364dda4f 100644
> --- a/gcc/cp/semantics.cc
> +++ b/gcc/cp/semantics.cc
> @@ -4208,6 +4208,11 @@ finish_id_expression_1 (tree id_expression,
>       }
>     else
>       {

We could use a comment here about why this needs to come before checking 
type_dep*.  OK with that change.

> +      if (TREE_CODE (decl) == TEMPLATE_ID_EXPR
> +	  && variable_template_p (TREE_OPERAND (decl, 0))
> +	  && !concept_check_p (decl))
> +	decl = finish_template_variable (decl);
> +
>         bool dependent_p = type_dependent_expression_p (decl);
>   
>         /* If the declaration was explicitly qualified indicate
> @@ -4275,15 +4280,6 @@ finish_id_expression_1 (tree id_expression,
>   	/* Replace an evaluated use of the thread_local variable with
>   	   a call to its wrapper.  */
>   	decl = wrap;
> -      else if (TREE_CODE (decl) == TEMPLATE_ID_EXPR
> -	       && !dependent_p
> -	       && variable_template_p (TREE_OPERAND (decl, 0))
> -	       && !concept_check_p (decl))
> -	{
> -	  decl = finish_template_variable (decl);
> -	  mark_used (decl);
> -	  decl = convert_from_reference (decl);
> -	}
>         else if (concept_check_p (decl))
>   	{
>   	  /* Nothing more to do. All of the analysis for concept checks
> diff --git a/gcc/testsuite/g++.dg/cpp1y/noexcept1.C b/gcc/testsuite/g++.dg/cpp1y/noexcept1.C
> index 86e46c96148..caa4a056a2e 100644
> --- a/gcc/testsuite/g++.dg/cpp1y/noexcept1.C
> +++ b/gcc/testsuite/g++.dg/cpp1y/noexcept1.C
> @@ -5,9 +5,9 @@ template <int> bool b;
>   
>   template <typename>
>   struct C {
> -  template <typename> friend int foo() noexcept(b<1>); // { dg-error "not usable in a constant expression|different exception specifier" }
> +  template <typename> friend int foo() noexcept(b<1>); // { dg-error "not usable in a constant expression" }
>   };
>   
> -template <typename> int foo() noexcept(b<1>);
> +template <typename> int foo() noexcept(b<1>); // { dg-error "not usable in a constant expression" }
>   
>   auto a = C<int>();
> diff --git a/gcc/testsuite/g++.dg/cpp1y/var-templ70.C b/gcc/testsuite/g++.dg/cpp1y/var-templ70.C
> new file mode 100644
> index 00000000000..aed2db5de88
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp1y/var-templ70.C
> @@ -0,0 +1,20 @@
> +// PR c++/108848
> +// { dg-do compile { target c++14 } }
> +
> +template<class T>
> +struct tag_t {
> +  template<class Sig>
> +  static constexpr const Sig* var = nullptr;
> +
> +  template<class Sig>
> +  static const Sig* fun();
> +};
> +
> +template <class T>
> +constexpr tag_t<T> tag {};
> +
> +template<class T>
> +void f() {
> +  tag<int>.var<void>;   // { dg-bogus "expected 'template' keyword" }
> +  tag<int>.fun<void>(); // { dg-bogus "expected 'template' keyword" }
> +};
> diff --git a/gcc/testsuite/g++.dg/cpp1y/var-templ71.C b/gcc/testsuite/g++.dg/cpp1y/var-templ71.C
> new file mode 100644
> index 00000000000..df33c62ec3e
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp1y/var-templ71.C
> @@ -0,0 +1,10 @@
> +// Verify we can evaluate a non-dependent variable template-id ahead of time.
> +// { dg-do compile { target c++14 } }
> +
> +template<class Sig>
> +static constexpr int var = 0;
> +
> +template<class T>
> +void f() {
> +  static_assert(var<void>); // { dg-error "assert" }
> +}


^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2023-02-27 22:36 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-02-23 21:52 [PATCH] c++: non-dependent variable template-id [PR108848] Patrick Palka
2023-02-27 22:36 ` Jason Merrill

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).