Patchwork C++ PATCH for c++/48707 (c++0x ice on initialization in template)

login
register
mail settings
Submitter Jason Merrill
Date April 25, 2011, 9:53 p.m.
Message ID <4DB5ED5E.1040700@redhat.com>
Download mbox | patch
Permalink /patch/92814/
State New
Headers show

Comments

Jason Merrill - April 25, 2011, 9:53 p.m.
In C++0x we can have an initializer that is potentially constant and yet 
still type-dependent if it involves a call, so we need to handle that.

For 4.7 I'm explicitly testing for type-dependency; for 4.6 I've made a 
smaller change to make value_dependent_expression_p return true for 
type-dependent expressions as well.

Tested x86_64-pc-linux-gnu, applied to trunk and 4.6.
commit 8d43d26b5dc0392f91ad6015955b92b1905e64ce
Author: Jason Merrill <jason@redhat.com>
Date:   Sat Apr 23 23:18:00 2011 -0400

    	PR c++/48707
    	* decl.c (type_dependent_init_p): New.
    	(cp_finish_decl): Check it.
    	* pt.c (any_type_dependent_elements_p): New.
    	* cp-tree.h: Declare it.
commit 6b978a4d2e33771d8fd95f39a301f8df180ac98c
Author: Jason Merrill <jason@redhat.com>
Date:   Mon Apr 25 16:44:03 2011 -0400

    	PR c++/48707
    	* pt.c (value_dependent_expression_p): Handle type-dependent
    	expression.

diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index ed48203..fc5177d 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -18068,6 +18068,11 @@ value_dependent_expression_p (tree expression)
   if (DECL_P (expression) && type_dependent_expression_p (expression))
     return true;
 
+  /* We shouldn't have gotten here for a type-dependent expression, but
+     let's handle it properly anyway.  */
+  if (TREE_TYPE (expression) == NULL_TREE)
+    return true;
+
   switch (TREE_CODE (expression))
     {
     case IDENTIFIER_NODE:
diff --git a/gcc/testsuite/g++.dg/cpp0x/regress/template-const2.C b/gcc/testsuite/g++.dg/cpp0x/regress/template-const2.C
new file mode 100644
index 0000000..25354b3
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/regress/template-const2.C
@@ -0,0 +1,14 @@
+// PR c++/48707
+// { dg-options -std=c++0x }
+
+struct A {
+  static int a();
+};
+
+template<typename X>
+struct B: A {
+  static int const b;
+};
+
+template<typename X>
+int const B<X>::b=B<X>::a();
H.J. Lu - Aug. 13, 2012, 9:19 p.m.
On Mon, Apr 25, 2011 at 2:53 PM, Jason Merrill <jason@redhat.com> wrote:
> In C++0x we can have an initializer that is potentially constant and yet
> still type-dependent if it involves a call, so we need to handle that.
>
> For 4.7 I'm explicitly testing for type-dependency; for 4.6 I've made a
> smaller change to make value_dependent_expression_p return true for
> type-dependent expressions as well.
>

> commit 6b978a4d2e33771d8fd95f39a301f8df180ac98c
> Author: Jason Merrill <jason@redhat.com>
> Date:   Mon Apr 25 16:44:03 2011 -0400
>
>         PR c++/48707
>         * pt.c (value_dependent_expression_p): Handle type-dependent
>         expression.
>
> diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
> index ed48203..fc5177d 100644
> --- a/gcc/cp/pt.c
> +++ b/gcc/cp/pt.c
> @@ -18068,6 +18068,11 @@ value_dependent_expression_p (tree expression)
>    if (DECL_P (expression) && type_dependent_expression_p (expression))
>      return true;
>
> +  /* We shouldn't have gotten here for a type-dependent expression, but
> +     let's handle it properly anyway.  */
> +  if (TREE_TYPE (expression) == NULL_TREE)
> +    return true;
> +
>    switch (TREE_CODE (expression))
>      {
>      case IDENTIFIER_NODE:

Any particular reason why it was only applied to 4.6 branch?
The same patch also fixes:

http://gcc.gnu.org/bugzilla/show_bug.cgi?id=53836

on trunk which is a regression from 4.6.

Patch

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 6a612e9..fd477a4 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -5106,6 +5106,7 @@  extern bool dependent_template_p		(tree);
 extern bool dependent_template_id_p		(tree, tree);
 extern bool type_dependent_expression_p		(tree);
 extern bool any_type_dependent_arguments_p      (const VEC(tree,gc) *);
+extern bool any_type_dependent_elements_p       (const_tree);
 extern bool type_dependent_expression_p_push	(tree);
 extern bool value_dependent_expression_p	(tree);
 extern bool any_value_dependent_elements_p      (const_tree);
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index d97ccf3..92e0d48 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -5701,6 +5701,36 @@  initialize_artificial_var (tree decl, VEC(constructor_elt,gc) *v)
 }
 
 /* INIT is the initializer for a variable, as represented by the
+   parser.  Returns true iff INIT is type-dependent.  */
+
+static bool
+type_dependent_init_p (tree init)
+{
+  if (TREE_CODE (init) == TREE_LIST)
+    /* A parenthesized initializer, e.g.: int i (3, 2); ? */
+    return any_type_dependent_elements_p (init);
+  else if (TREE_CODE (init) == CONSTRUCTOR)
+  /* A brace-enclosed initializer, e.g.: int i = { 3 }; ? */
+    {
+      VEC(constructor_elt, gc) *elts;
+      size_t nelts;
+      size_t i;
+
+      elts = CONSTRUCTOR_ELTS (init);
+      nelts = VEC_length (constructor_elt, elts);
+      for (i = 0; i < nelts; ++i)
+	if (type_dependent_init_p (VEC_index (constructor_elt,
+					      elts, i)->value))
+	  return true;
+    }
+  else
+    /* It must be a simple expression, e.g., int i = 3;  */
+    return type_dependent_expression_p (init);
+
+  return false;
+}
+
+/* INIT is the initializer for a variable, as represented by the
    parser.  Returns true iff INIT is value-dependent.  */
 
 static bool
@@ -5876,19 +5906,25 @@  cp_finish_decl (tree decl, tree init, bool init_const_expr_p,
 	 template is instantiated.  But, if DECL is a variable constant
 	 then it can be used in future constant expressions, so its value
 	 must be available. */
-      if (init
-	  && init_const_expr_p
-	  && !type_dependent_p
-	  && decl_maybe_constant_var_p (decl)
-	  && !value_dependent_init_p (init))
+
+      if (TREE_CODE (decl) != VAR_DECL || dependent_type_p (type))
+	/* We can't do anything if the decl has dependent type.  */;
+      else if (init
+	       && init_const_expr_p
+	       && !type_dependent_p
+	       && decl_maybe_constant_var_p (decl)
+	       && !type_dependent_init_p (init)
+	       && !value_dependent_init_p (init))
 	{
+	  /* This variable seems to be a non-dependent constant, so process
+	     its initializer.  If check_initializer returns non-null the
+	     initialization wasn't constant after all.  */
 	  tree init_code = check_initializer (decl, init, flags, &cleanup);
 	  if (init_code == NULL_TREE)
 	    init = NULL_TREE;
 	}
-      else if (TREE_CODE (decl) == VAR_DECL
-	       && !DECL_PRETTY_FUNCTION_P (decl)
-	       && !type_dependent_p)
+      else if (!DECL_PRETTY_FUNCTION_P (decl))
+	/* Deduce array size even if the initializer is dependent.  */
 	maybe_deduce_size_from_array_init (decl, init);
 
       if (init)
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index cb8ebfd..6765931 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -18457,6 +18457,19 @@  any_type_dependent_arguments_p (const VEC(tree,gc) *args)
 }
 
 /* Returns TRUE if LIST (a TREE_LIST whose TREE_VALUEs are
+   expressions) contains any type-dependent expressions.  */
+
+bool
+any_type_dependent_elements_p (const_tree list)
+{
+  for (; list; list = TREE_CHAIN (list))
+    if (value_dependent_expression_p (TREE_VALUE (list)))
+      return true;
+
+  return false;
+}
+
+/* Returns TRUE if LIST (a TREE_LIST whose TREE_VALUEs are
    expressions) contains any value-dependent expressions.  */
 
 bool
diff --git a/gcc/testsuite/g++.dg/cpp0x/regress/template-const2.C b/gcc/testsuite/g++.dg/cpp0x/regress/template-const2.C
new file mode 100644
index 0000000..25354b3
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/regress/template-const2.C
@@ -0,0 +1,14 @@ 
+// PR c++/48707
+// { dg-options -std=c++0x }
+
+struct A {
+  static int a();
+};
+
+template<typename X>
+struct B: A {
+  static int const b;
+};
+
+template<typename X>
+int const B<X>::b=B<X>::a();