re PR c++/23099 (ICE in build_simple_base_path, at cp/class.c:460)

PR c++/23099
	* cp-tree.h (saved_scope): Add skip_evaluation.
	* decl.c (start_decl): Use DECL_INITIALIZED_IN_CLASS_P, not
	DECL_INITIAL, to determine whether or not a static data member was
	initialized in the class-specifier.
	(cp_finish_decl): Add comment.
	* init.c (integral_constant_value): Subtitute into the
	initializers for static data members in	templates.
	* name-lookup.c (push_to_top_level): Save skip_evaluation.
	(pop_from_top_level): Restore it.
	* pt.c (instantiate_class_template): Do not substitute into the
	intializers of static data members when instantiating a class.
	(regenerate_decl_from_template): Simplify.
	(instantiate_decl): Tidy.  Substitute into the initializer for a
	static data member even when the definition of the data member is
	not available.

	PR c++/23099
	* g++.dg/init/member1.C: Make sure erroneous static data member
	definitions are required.
	* g++.dg/template/static13.C: New test.
	* g++.dg/template/static14.C: Likewise.

From-SVN: r103604
This commit is contained in:
Mark Mitchell 2005-08-29 14:08:50 +00:00 committed by Mark Mitchell
parent 3a6ebcdcee
commit b794e321c1
10 changed files with 132 additions and 40 deletions

View File

@ -1,3 +1,22 @@
2005-08-28 Mark Mitchell <mark@codesourcery.com>
PR c++/23099
* cp-tree.h (saved_scope): Add skip_evaluation.
* decl.c (start_decl): Use DECL_INITIALIZED_IN_CLASS_P, not
DECL_INITIAL, to determine whether or not a static data member was
initialized in the class-specifier.
(cp_finish_decl): Add comment.
* init.c (integral_constant_value): Subtitute into the
initializers for static data members in templates.
* name-lookup.c (push_to_top_level): Save skip_evaluation.
(pop_from_top_level): Restore it.
* pt.c (instantiate_class_template): Do not substitute into the
intializers of static data members when instantiating a class.
(regenerate_decl_from_template): Simplify.
(instantiate_decl): Tidy. Substitute into the initializer for a
static data member even when the definition of the data member is
not available.
2005-08-26 Mark Mitchell <mark@codesourcery.com>
PR c++/19004

View File

@ -655,6 +655,7 @@ struct saved_scope GTY(())
int x_processing_specialization;
bool x_processing_explicit_instantiation;
int need_pop_function_context;
bool skip_evaluation;
struct stmt_tree_s x_stmt_tree;

View File

@ -3716,7 +3716,8 @@ start_decl (const cp_declarator *declarator,
declaration will have DECL_EXTERNAL set, but will have an
initialization. Thus, duplicate_decls won't warn
about this situation, and so we check here. */
if (DECL_INITIAL (decl) && DECL_INITIAL (field))
if (DECL_INITIAL (decl)
&& DECL_INITIALIZED_IN_CLASS_P (field))
error ("duplicate initialization of %qD", decl);
if (duplicate_decls (decl, field))
decl = field;
@ -4921,10 +4922,20 @@ cp_finish_decl (tree decl, tree init, tree asmspec_tree, int flags)
"initialized", decl);
init = NULL_TREE;
}
/* Check that the initializer for a static data member was a
constant. Althouh we check in the parser that the
initializer is an integral constant expression, we do not
simplify division-by-zero at the point at which it
occurs. Therefore, in:
struct S { static const int i = 7 / 0; };
we issue an error at this point. It would
probably be better to forbid division by zero in
integral constant expressions. */
if (DECL_EXTERNAL (decl) && init)
{
/* The static data member cannot be initialized by a
non-constant when being declared. */
error ("%qD cannot be initialized by a non-constant expression"
" when being declared", decl);
DECL_INITIALIZED_IN_CLASS_P (decl) = 0;

View File

@ -1572,12 +1572,25 @@ integral_constant_value (tree decl)
/* And so are variables with a 'const' type -- unless they
are also 'volatile'. */
&& CP_TYPE_CONST_NON_VOLATILE_P (TREE_TYPE (decl))
&& DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl)))
&& DECL_INITIAL (decl)
&& DECL_INITIAL (decl) != error_mark_node
&& TREE_TYPE (DECL_INITIAL (decl))
&& INTEGRAL_OR_ENUMERATION_TYPE_P (TREE_TYPE (DECL_INITIAL (decl))))
decl = DECL_INITIAL (decl);
&& DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl))))
{
tree init;
/* If DECL is a static data member in a template class, we must
instantiate it here. The initializer for the static data
member is not processed until needed; we need it now. */
mark_used (decl);
init = DECL_INITIAL (decl);
/* If we are currently processing a template, the
initializer for a static data member may not be dependent,
but it is not folded until instantiation time. */
if (init)
init = fold_non_dependent_expr (init);
if (!(init || init == error_mark_node)
|| !TREE_TYPE (init)
|| !INTEGRAL_OR_ENUMERATION_TYPE_P (TREE_TYPE (init)))
break;
decl = init;
}
return decl;
}

View File

@ -4872,12 +4872,14 @@ push_to_top_level (void)
s->bindings = b;
s->need_pop_function_context = need_pop;
s->function_decl = current_function_decl;
s->skip_evaluation = skip_evaluation;
scope_chain = s;
current_function_decl = NULL_TREE;
current_lang_base = VEC_alloc (tree, gc, 10);
current_lang_name = lang_name_cplusplus;
current_namespace = global_namespace;
skip_evaluation = 0;
timevar_pop (TV_NAME_LOOKUP);
}
@ -4909,6 +4911,7 @@ pop_from_top_level (void)
if (s->need_pop_function_context)
pop_function_context_from (NULL_TREE);
current_function_decl = s->function_decl;
skip_evaluation = s->skip_evaluation;
timevar_pop (TV_NAME_LOOKUP);
}

View File

@ -5699,17 +5699,22 @@ instantiate_class_template (tree type)
--processing_template_decl;
if (TREE_CODE (r) == VAR_DECL)
{
tree init;
/* In [temp.inst]:
if (DECL_INITIALIZED_IN_CLASS_P (r))
init = tsubst_expr (DECL_INITIAL (t), args,
tf_error | tf_warning, NULL_TREE);
else
init = NULL_TREE;
finish_static_data_member_decl
(r, init, /*asmspec_tree=*/NULL_TREE, /*flags=*/0);
[t]he initialization (and any associated
side-effects) of a static data member does
not occur unless the static data member is
itself used in a way that requires the
definition of the static data member to
exist.
Therefore, we do not substitute into the
initialized for the static data member here. */
finish_static_data_member_decl
(r,
/*init=*/NULL_TREE,
/*asmspec_tree=*/NULL_TREE,
/*flags=*/0);
if (DECL_INITIALIZED_IN_CLASS_P (r))
check_static_variable_definition (r, TREE_TYPE (r));
}
@ -11278,13 +11283,9 @@ regenerate_decl_from_template (tree decl, tree tmpl)
DECL_INLINE (decl) = 1;
}
else if (TREE_CODE (decl) == VAR_DECL)
{
if (!DECL_INITIALIZED_IN_CLASS_P (decl)
&& DECL_INITIAL (code_pattern))
DECL_INITIAL (decl) =
tsubst_expr (DECL_INITIAL (code_pattern), args,
tf_error, DECL_TI_TEMPLATE (decl));
}
DECL_INITIAL (decl) =
tsubst_expr (DECL_INITIAL (code_pattern), args,
tf_error, DECL_TI_TEMPLATE (decl));
else
gcc_unreachable ();
@ -11367,7 +11368,7 @@ instantiate_decl (tree d, int defer_ok,
tree code_pattern;
tree spec;
tree gen_tmpl;
int pattern_defined;
bool pattern_defined;
int need_push;
location_t saved_loc = input_location;
@ -11415,9 +11416,6 @@ instantiate_decl (tree d, int defer_ok,
timevar_push (TV_PARSE);
/* We may be in the middle of deferred access check. Disable it now. */
push_deferring_access_checks (dk_no_deferred);
/* Set TD to the template whose DECL_TEMPLATE_RESULT is the pattern
for the instantiation. */
td = template_for_substitution (d);
@ -11437,6 +11435,10 @@ instantiate_decl (tree d, int defer_ok,
pattern_defined = (DECL_SAVED_TREE (code_pattern) != NULL_TREE);
else
pattern_defined = ! DECL_IN_AGGR_P (code_pattern);
/* We may be in the middle of deferred access check. Disable it now. */
push_deferring_access_checks (dk_no_deferred);
/* Unless an explicit instantiation directive has already determined
the linkage of D, remember that a definition is available for
this entity. */
@ -11486,12 +11488,6 @@ instantiate_decl (tree d, int defer_ok,
pop_access_scope (d);
}
/* We should have set up DECL_INITIAL in instantiate_class_template
for in-class definitions of static data members. */
gcc_assert (!(TREE_CODE (d) == VAR_DECL
&& DECL_INITIALIZED_IN_CLASS_P (d)
&& DECL_INITIAL (d) == NULL_TREE));
/* Do not instantiate templates that we know will be defined
elsewhere. */
if (DECL_INTERFACE_KNOWN (d)
@ -11504,6 +11500,20 @@ instantiate_decl (tree d, int defer_ok,
because it's used by add_pending_template. */
else if (! pattern_defined || defer_ok)
{
/* The definition of the static data member is now required so
we must substitute the initializer. */
if (TREE_CODE (d) == VAR_DECL
&& !DECL_INITIAL (d)
&& DECL_INITIAL (code_pattern))
{
push_nested_class (DECL_CONTEXT (d));
DECL_INITIAL (d)
= tsubst_expr (DECL_INITIAL (code_pattern),
args,
tf_error | tf_warning, NULL_TREE);
pop_nested_class ();
}
input_location = saved_loc;
if (at_eof && !pattern_defined
@ -11570,10 +11580,7 @@ instantiate_decl (tree d, int defer_ok,
/* Enter the scope of D so that access-checking works correctly. */
push_nested_class (DECL_CONTEXT (d));
cp_finish_decl (d,
(!DECL_INITIALIZED_IN_CLASS_P (d)
? DECL_INITIAL (d) : NULL_TREE),
NULL_TREE, 0);
cp_finish_decl (d, DECL_INITIAL (d), NULL_TREE, 0);
pop_nested_class ();
}
else if (TREE_CODE (d) == FUNCTION_DECL)

View File

@ -1,3 +1,11 @@
2005-08-28 Mark Mitchell <mark@codesourcery.com>
PR c++/23099
* g++.dg/init/member1.C: Make sure erroneous static data member
definitions are required.
* g++.dg/template/static13.C: New test.
* g++.dg/template/static14.C: Likewise.
2005-08-29 Jakub Jelinek <jakub@redhat.com>
* gcc.target/i386/pr23575.c: Use -msse2 instead of

View File

@ -11,8 +11,11 @@ template<int> struct B {};
template<typename T> struct C
{
static const int i = A<T>::i; // { dg-error "incomplete" }
static const int j = i; // { dg-error "initialized by a non-const" }
static const int j = i;
B<j> b; // { dg-error "not a valid template arg" }
};
C<int> c;
int i = C<int>::i;
int j = C<int>::j;

View File

@ -0,0 +1,14 @@
// PR c++/23099
struct Base {
int x;
};
template <typename T>
struct A {
static const int N = sizeof(static_cast<Base*>(T()));
};
struct Derived : Base {
A<Derived*> a;
};

View File

@ -0,0 +1,13 @@
struct Base {
int x;
};
template <typename T>
struct A {
static const int N = sizeof(static_cast<Base*>(T()));
int a[N];
};
struct Derived : Base {
A<Derived*> a;
};