summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormmitchel <mmitchel@138bc75d-0d04-0410-961f-82ee72b054a4>2005-08-29 14:08:50 +0000
committermmitchel <mmitchel@138bc75d-0d04-0410-961f-82ee72b054a4>2005-08-29 14:08:50 +0000
commite6ef0e42bc02d132e5b17790347ac7670ff69f61 (patch)
treea365e22cb324c02aefb465f5f8efd813b9e48964
parentdd350d42d405e367ced9bab20c95865c70e4855e (diff)
downloadgcc-e6ef0e42bc02d132e5b17790347ac7670ff69f61.tar.gz
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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@103604 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r--gcc/cp/ChangeLog19
-rw-r--r--gcc/cp/cp-tree.h1
-rw-r--r--gcc/cp/decl.c17
-rw-r--r--gcc/cp/init.c25
-rw-r--r--gcc/cp/name-lookup.c3
-rw-r--r--gcc/cp/pt.c71
-rw-r--r--gcc/testsuite/ChangeLog8
-rw-r--r--gcc/testsuite/g++.dg/init/member1.C5
-rw-r--r--gcc/testsuite/g++.dg/template/static13.C14
-rw-r--r--gcc/testsuite/g++.dg/template/static14.C13
10 files changed, 134 insertions, 42 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 4c2c72ed066..40513367888 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -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
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 17e074dc99f..e8d5fe77049 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -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;
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 4199b241b9b..a32be093c74 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -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;
diff --git a/gcc/cp/init.c b/gcc/cp/init.c
index 690e35f8913..8a8dc782ca3 100644
--- a/gcc/cp/init.c
+++ b/gcc/cp/init.c
@@ -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;
}
diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c
index 2beb3e7eaec..7270a9dd112 100644
--- a/gcc/cp/name-lookup.c
+++ b/gcc/cp/name-lookup.c
@@ -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);
}
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 386dc2ff0d7..773d8650891 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -5699,17 +5699,22 @@ instantiate_class_template (tree type)
--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));
}
@@ -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)
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 229e55b3701..c896f324496 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -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
diff --git a/gcc/testsuite/g++.dg/init/member1.C b/gcc/testsuite/g++.dg/init/member1.C
index 1c89d5a1d43..aededf23e7b 100644
--- a/gcc/testsuite/g++.dg/init/member1.C
+++ b/gcc/testsuite/g++.dg/init/member1.C
@@ -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;
diff --git a/gcc/testsuite/g++.dg/template/static13.C b/gcc/testsuite/g++.dg/template/static13.C
new file mode 100644
index 00000000000..c43f5554739
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/static13.C
@@ -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;
+};
diff --git a/gcc/testsuite/g++.dg/template/static14.C b/gcc/testsuite/g++.dg/template/static14.C
new file mode 100644
index 00000000000..5bc0e731ac3
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/static14.C
@@ -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;
+};