+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
int x_processing_specialization;
bool x_processing_explicit_instantiation;
int need_pop_function_context;
+ bool skip_evaluation;
struct stmt_tree_s x_stmt_tree;
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;
"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;
/* 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;
}
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);
}
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);
}
--processing_template_decl;
if (TREE_CODE (r) == VAR_DECL)
{
- tree init;
-
- 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);
-
+ /* In [temp.inst]:
+
+ [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));
}
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 ();
tree code_pattern;
tree spec;
tree gen_tmpl;
- int pattern_defined;
+ bool pattern_defined;
int need_push;
location_t saved_loc = input_location;
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);
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. */
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)
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
/* 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)
+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
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;
--- /dev/null
+// 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;
+};
--- /dev/null
+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;
+};