c++: non-dependent variable template-id [PR108848]
authorPatrick Palka <ppalka@redhat.com>
Tue, 28 Feb 2023 20:05:30 +0000 (15:05 -0500)
committerPatrick Palka <ppalka@redhat.com>
Tue, 28 Feb 2023 20:05:30 +0000 (15:05 -0500)
Here we're treating deeming 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 unreachable at template parse time.  Thus
we're led into thinking tag<int>.var<void> refers to a dependent name.

This patch fixes this by making finish_id_expression_1 instantiate a
variable template-id as long as it's not dependent according to the
dependence test in lookup_and_finish_template_variable rather than
according to type_dependent_expression_p.

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, before (and regardless of) the
type_dependent_expression_p test.

gcc/testsuite/ChangeLog:

* g++.dg/cpp1y/noexcept1.C: Don't expect a bogus "different
exception specifier" error.  Expect a separate "not usable
in a constant expression" error.
* g++.dg/cpp1y/var-templ75.C: New test.
* g++.dg/cpp1y/var-templ76.C: New test.

gcc/cp/pt.cc
gcc/cp/semantics.cc
gcc/testsuite/g++.dg/cpp1y/noexcept1.C
gcc/testsuite/g++.dg/cpp1y/var-templ75.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp1y/var-templ76.C [new file with mode: 0644]

index f636bac..03958da 100644 (file)
@@ -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 resolve the TEMPLATE_ID_EXPR 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,19 +10359,14 @@ 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))
-    {
-      /* We may be called while doing a partial substitution, but the
-        type of the variable template may be auto, in which case we
-        will call do_auto_deduction in mark_used (which clears tf_partial)
-        and the auto must be properly reduced at that time for the
-        deduction to work.  */
-      complain &= ~tf_partial;
-      var = finish_template_variable (var, complain);
-      mark_used (var);
-    }
-
+  /* We may be called while doing a partial substitution, but the
+     type of the variable template may be auto, in which case we
+     will call do_auto_deduction in mark_used (which clears tf_partial)
+     and the auto must be properly reduced at that time for the
+     deduction to work.  */
+  complain &= ~tf_partial;
+  var = finish_template_variable (var, complain);
+  mark_used (var);
   return convert_from_reference (var);
 }
 
index 79b7cc7..db982d5 100644 (file)
@@ -4208,6 +4208,16 @@ 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))
+       /* Try resolving this variable TEMPLATE_ID_EXPR (which is always
+          considered type-dependent) now, so that the dependence test that
+          follows gives us the right answer: if it represents a non-dependent
+          variable template-id then finish_template_variable will yield the
+          corresponding non-dependent VAR_DECL.  */
+       decl = finish_template_variable (decl);
+
       bool dependent_p = type_dependent_expression_p (decl);
 
       /* If the declaration was explicitly qualified indicate
@@ -4275,15 +4285,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
index 86e46c9..caa4a05 100644 (file)
@@ -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-templ75.C b/gcc/testsuite/g++.dg/cpp1y/var-templ75.C
new file mode 100644 (file)
index 0000000..d2ab807
--- /dev/null
@@ -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-templ76.C b/gcc/testsuite/g++.dg/cpp1y/var-templ76.C
new file mode 100644 (file)
index 0000000..2acb815
--- /dev/null
@@ -0,0 +1,13 @@
+// Verify we can evaluate a non-dependent variable template-id ahead of time.
+// { dg-do compile { target c++14 } }
+
+template<int N>
+constexpr int var = N;
+
+template<int N> void f(int) = delete;
+template<int N> void f(...);
+
+template<class T>
+void g() {
+  f<var<42>>(0); // { dg-error "deleted" }
+}