diff mbox

C++ PATCH for c++/66260 (various variable template specialization issues)

Message ID 55C24E22.7060403@redhat.com
State New
Headers show

Commit Message

Jason Merrill Aug. 5, 2015, 5:55 p.m. UTC
The fundamental problem here was that I was setting the type of a 
variable TEMPLATE_ID_EXPR to unknown_type_node, which is not dependent, 
so places such as finish_id_expression that check dependent_type_p to 
determine whether an expression is type-dependent were getting the wrong 
answer.

Fixing that means that variable TEMPLATE_ID_EXPRs survive until they 
become non-dependent, and so we need to handle them in 
tsubst_copy_and_build.

We were also using the wrong arguments for a partial specialization in 
instantiate_decl because we forgot to update DECL_TI_ARGS when we 
figured out the correct partial specialization in instantiate_template_1.

Tested x86_64-pc-linux-gnu, applying to trunk and 5.
diff mbox

Patch

commit 2b427166d914064eaf5d20c0c293ec5e7dcf0e89
Author: Jason Merrill <jason@redhat.com>
Date:   Wed Aug 5 12:02:11 2015 -0400

    	PR c++/66260
    	PR c++/66596
    	PR c++/66649
    	PR c++/66923
    	* pt.c (lookup_template_variable): Use NULL_TREE for type.
    	(instantiate_template_1): Also set DECL_TI_ARGS based on
    	the immediate parent.
    	(tsubst_copy_and_build) [TEMPLATE_ID_EXPR]: Handle variable templates.
    	(finish_template_variable): Add complain parm.
    	* cp-tree.h: Adjust.

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 63fd6e9..e70dcb4 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -5954,7 +5954,7 @@  extern tree perform_koenig_lookup		(tree, vec<tree, va_gc> *,
 						 tsubst_flags_t);
 extern tree finish_call_expr			(tree, vec<tree, va_gc> **, bool,
 						 bool, tsubst_flags_t);
-extern tree finish_template_variable	(tree);
+extern tree finish_template_variable		(tree, tsubst_flags_t = tf_warning_or_error);
 extern tree finish_increment_expr		(tree, enum tree_code);
 extern tree finish_this_expr			(void);
 extern tree finish_pseudo_destructor_expr       (tree, tree, tree, location_t);
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 7ad2334..f8c123c 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -8187,14 +8187,14 @@  lookup_template_class (tree d1, tree arglist, tree in_decl, tree context,
 tree
 lookup_template_variable (tree templ, tree arglist)
 {
-  tree type = unknown_type_node;
+  tree type = NULL_TREE;
   return build2 (TEMPLATE_ID_EXPR, type, templ, arglist);
 }
 
 /* Instantiate a variable declaration from a TEMPLATE_ID_EXPR for use. */
 
 tree
-finish_template_variable (tree var)
+finish_template_variable (tree var, tsubst_flags_t complain)
 {
   tree templ = TREE_OPERAND (var, 0);
 
@@ -8203,7 +8203,6 @@  finish_template_variable (tree var)
   arglist = add_outermost_template_args (tmpl_args, arglist);
 
   tree parms = DECL_TEMPLATE_PARMS (templ);
-  tsubst_flags_t complain = tf_warning_or_error;
   arglist = coerce_innermost_template_parms (parms, arglist, templ, complain,
 					     /*req_all*/true,
 					     /*use_default*/true);
@@ -14750,6 +14749,17 @@  tsubst_copy_and_build (tree t,
 	if (targs)
 	  targs = tsubst_template_args (targs, args, complain, in_decl);
 
+	if (variable_template_p (templ))
+	  {
+	    templ = lookup_template_variable (templ, targs);
+	    if (!any_dependent_template_arguments_p (targs))
+	      {
+		templ = finish_template_variable (templ, complain);
+		mark_used (templ);
+	      }
+	    RETURN (convert_from_reference (templ));
+	  }
+
 	if (TREE_CODE (templ) == COMPONENT_REF)
 	  {
 	    object = TREE_OPERAND (templ, 0);
@@ -16153,6 +16163,7 @@  instantiate_template_1 (tree tmpl, tree orig_args, tsubst_flags_t complain)
   /* The DECL_TI_TEMPLATE should always be the immediate parent
      template, not the most general template.  */
   DECL_TI_TEMPLATE (fndecl) = tmpl;
+  DECL_TI_ARGS (fndecl) = targ_ptr;
 
   /* Now we know the specialization, compute access previously
      deferred.  */
diff --git a/gcc/testsuite/g++.dg/cpp1y/var-templ32.C b/gcc/testsuite/g++.dg/cpp1y/var-templ32.C
index d9d2fff..80077a1 100644
--- a/gcc/testsuite/g++.dg/cpp1y/var-templ32.C
+++ b/gcc/testsuite/g++.dg/cpp1y/var-templ32.C
@@ -4,4 +4,4 @@  template<typename T>
 bool V1 = true;
 
 template<typename T>
-bool V1<int> = false; // { dg-error "primary template" }
+bool V1<int> = false; // { dg-error "primary template|not deducible" }
diff --git a/gcc/testsuite/g++.dg/cpp1y/var-templ35.C b/gcc/testsuite/g++.dg/cpp1y/var-templ35.C
index c2c58ac..5ed0abc 100644
--- a/gcc/testsuite/g++.dg/cpp1y/var-templ35.C
+++ b/gcc/testsuite/g++.dg/cpp1y/var-templ35.C
@@ -2,4 +2,4 @@ 
 // { dg-do compile { target c++14 } }
 
 template<typename T> int typeID{42};
-template<typename T> double typeID<double>{10.10}; // { dg-error "primary template|redeclaration" }
+template<typename T> double typeID<double>{10.10}; // { dg-error "primary template|redeclaration|not deducible" }
diff --git a/gcc/testsuite/g++.dg/cpp1y/var-templ36.C b/gcc/testsuite/g++.dg/cpp1y/var-templ36.C
new file mode 100644
index 0000000..760e36f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/var-templ36.C
@@ -0,0 +1,15 @@ 
+// { dg-do compile { target c++14 } }
+
+template <class T>
+constexpr T v = T();
+
+template <class T>
+constexpr T v<T*> = T();
+
+template <class T>
+struct A {
+  static constexpr decltype (v<T>) v = ::v<T>;
+};
+
+double d1 = v<double*>;
+double d2 = A<double*>::v;
diff --git a/gcc/testsuite/g++.dg/cpp1y/var-templ38.C b/gcc/testsuite/g++.dg/cpp1y/var-templ38.C
new file mode 100644
index 0000000..1fd76d3
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/var-templ38.C
@@ -0,0 +1,9 @@ 
+// PR c++/66596
+// { dg-do compile { target c++14 } }
+
+struct U { void f() {} };
+struct V { void f() {} };
+template<class T> U t;
+template<> V t<int>;
+template<class T> void g() { t<T>.f(); }
+int main() { g<int>(); }
diff --git a/gcc/testsuite/g++.dg/cpp1y/var-templ39.C b/gcc/testsuite/g++.dg/cpp1y/var-templ39.C
new file mode 100644
index 0000000..e06519d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/var-templ39.C
@@ -0,0 +1,16 @@ 
+// PR c++/66260
+// { dg-do compile { target c++14 } }
+
+template <class>
+constexpr bool foo = false;
+template <>
+constexpr bool foo<int> = true;
+template <class T, int N>
+constexpr bool foo<T[N]> = foo<T>;
+
+static_assert(foo<int>, "");
+static_assert(!foo<double>, "");
+static_assert(foo<int[3]>, "");
+static_assert(!foo<double[3]>, "");
+static_assert(foo<int[2][5][3]>, "");
+static_assert(!foo<double[2][5][3]>, "");