This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

C++ PATCH: PR 31992


This patch fixes PR c++/31992, a GCC 4.2.x P1.  We were crashing when
initializing a constant integral static data member with a dependent
name.  The challenge there is that if the initializer is itself an
integral constant, we must process it at template-declaration time,
rather than at template-instantiation time.  But, if the initializer
is dependent, we can't do that.  This patch makes the test for
dependency more accurate, which means that for the attached test-case
we now correctly recognize that the initializer is dependent.

Tested on x86_64-unknown-linux-gnu, applied to mainline.  I will
backport to 4.2.

--
Mark Mitchell
CodeSourcery
mark@codesourcery.com
(650) 331-3385 x713

2007-07-05  Mark Mitchell  <mark@codesourcery.com>

	PR c++/31992
	* cp-tree.h (any_value_dependent_elements_p): Declare it.
	* decl.c (value_dependent_init_p): New function.
	(cp_finish_decl): Use it.
	* pt.c (value_dependent_expression_p): Use
	any_value_dependent_elements_p.
	* parser.c (cp_parser_primary_expression): Add comment about
	treating dependent qualified names as integral
	constant-expressions.

2007-07-05  Mark Mitchell  <mark@codesourcery.com>

	PR c++/31992
	* g++.dg/template/static30.C: Likewise.

Index: gcc/cp/decl.c
===================================================================
--- gcc/cp/decl.c	(revision 126287)
+++ gcc/cp/decl.c	(working copy)
@@ -5099,6 +5099,36 @@ initialize_artificial_var (tree decl, tr
   make_rtl_for_nonlocal_decl (decl, init, /*asmspec=*/NULL);
 }
 
+/* INIT is the initializer for a variable, as represented by the
+   parser.  Returns true iff INIT is value-dependent.  */
+
+static bool
+value_dependent_init_p (tree init)
+{
+  if (TREE_CODE (init) == TREE_LIST)
+    /* A parenthesized initializer, e.g.: int i (3, 2); ? */
+    return any_value_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 (value_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 value_dependent_expression_p (init);
+  
+  return false;
+}
+
 /* Finish processing of a declaration;
    install its line number and initial value.
    If the length of an array type is not known before,
@@ -5171,18 +5201,16 @@ cp_finish_decl (tree decl, tree init, bo
 	    TREE_CONSTANT (decl) = 1;
 	}
 
-      if (!init
-	  || !DECL_CLASS_SCOPE_P (decl)
-	  || !DECL_INTEGRAL_CONSTANT_VAR_P (decl)
-	  || type_dependent_p
-	  || value_dependent_expression_p (init)
-	     /* Check also if initializer is a value dependent
-		{ integral_constant_expression }.  */
-	  || (TREE_CODE (init) == CONSTRUCTOR
-	      && VEC_length (constructor_elt, CONSTRUCTOR_ELTS (init)) == 1
-	      && value_dependent_expression_p
-		   (VEC_index (constructor_elt,
-			       CONSTRUCTOR_ELTS (init), 0)->value)))
+      /* Generally, initializers in templates are expanded when the
+	 template is instantiated.  But, if DECL is an integral
+	 constant static data member, then it can be used in future
+	 integral constant expressions, and its value must be
+	 available. */
+      if (!(init
+	    && DECL_CLASS_SCOPE_P (decl)
+	    && DECL_INTEGRAL_CONSTANT_VAR_P (decl)
+	    && !type_dependent_p
+	    && !value_dependent_init_p (init)))
 	{
 	  if (init)
 	    DECL_INITIAL (decl) = init;
Index: gcc/cp/cp-tree.h
===================================================================
--- gcc/cp/cp-tree.h	(revision 126287)
+++ gcc/cp/cp-tree.h	(working copy)
@@ -4444,6 +4444,7 @@ extern bool dependent_template_id_p		(tr
 extern bool type_dependent_expression_p		(tree);
 extern bool any_type_dependent_arguments_p      (tree);
 extern bool value_dependent_expression_p	(tree);
+extern bool any_value_dependent_elements_p      (tree);
 extern tree resolve_typename_type		(tree, bool);
 extern tree template_for_substitution		(tree);
 extern tree build_non_dependent_expr		(tree);
Index: gcc/cp/pt.c
===================================================================
--- gcc/cp/pt.c	(revision 126287)
+++ gcc/cp/pt.c	(working copy)
@@ -15074,12 +15074,7 @@ value_dependent_expression_p (tree expre
 	  }
 
 	if (TREE_CODE (expression) == TREE_LIST)
-	  {
-	    for (; expression; expression = TREE_CHAIN (expression))
-	      if (value_dependent_expression_p (TREE_VALUE (expression)))
-		return true;
-	    return false;
-	  }
+	  return any_value_dependent_elements_p (expression);
 
 	return value_dependent_expression_p (expression);
       }
@@ -15308,6 +15303,19 @@ any_type_dependent_arguments_p (tree arg
   return false;
 }
 
+/* Returns TRUE if LIST (a TREE_LIST whose TREE_VALUEs are
+   expressions) contains any value-dependent expressions.  */
+
+bool
+any_value_dependent_elements_p (tree list)
+{
+  for (; list; list = TREE_CHAIN (list))
+    if (value_dependent_expression_p (TREE_VALUE (list)))
+      return true;
+
+  return false;
+}
+
 /* Returns TRUE if the ARG (a template argument) is dependent.  */
 
 bool
Index: gcc/cp/parser.c
===================================================================
--- gcc/cp/parser.c	(revision 126292)
+++ gcc/cp/parser.c	(working copy)
@@ -3368,7 +3368,19 @@ cp_parser_primary_expression (cp_parser 
 	    /* If name lookup gives us a SCOPE_REF, then the
 	       qualifying scope was dependent.  */
 	    if (TREE_CODE (decl) == SCOPE_REF)
-	      return decl;
+	      {
+		/* At this point, we do not know if DECL is a valid
+		   integral constant expression.  We assume that it is
+		   in fact such an expression, so that code like:
+
+		      template <int N> struct A {
+			int a[B<N>::i];
+		      };
+		     
+		   is accepted.  At template-instantiation time, we
+		   will check that B<N>::i is actually a constant.  */
+		return decl;
+	      }
 	    /* Check to see if DECL is a local variable in a context
 	       where that is forbidden.  */
 	    if (parser->local_variables_forbidden_p
Index: gcc/testsuite/g++.dg/template/static30.C
===================================================================
--- gcc/testsuite/g++.dg/template/static30.C	(revision 0)
+++ gcc/testsuite/g++.dg/template/static30.C	(revision 0)
@@ -0,0 +1,10 @@
+// PR c++/31992
+
+template <int> struct A 
+{
+  static const int i1;
+  static const int i2;
+};
+
+template <int N> const int A<N>::i1(A<N>::i);
+template <int N> const int A<N>::i2(3, A<N>::i);


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]