This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
C++ PATCH: PR 31992
- From: Mark Mitchell <mark at codesourcery dot com>
- To: gcc-patches at gcc dot gnu dot org
- Date: Thu, 5 Jul 2007 18:26:43 -0700
- Subject: C++ PATCH: PR 31992
- Reply-to: mark at codesourcery dot com
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);