diff options
author | mmitchel <mmitchel@138bc75d-0d04-0410-961f-82ee72b054a4> | 2005-08-29 14:08:50 +0000 |
---|---|---|
committer | mmitchel <mmitchel@138bc75d-0d04-0410-961f-82ee72b054a4> | 2005-08-29 14:08:50 +0000 |
commit | e6ef0e42bc02d132e5b17790347ac7670ff69f61 (patch) | |
tree | a365e22cb324c02aefb465f5f8efd813b9e48964 | |
parent | dd350d42d405e367ced9bab20c95865c70e4855e (diff) | |
download | gcc-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/ChangeLog | 19 | ||||
-rw-r--r-- | gcc/cp/cp-tree.h | 1 | ||||
-rw-r--r-- | gcc/cp/decl.c | 17 | ||||
-rw-r--r-- | gcc/cp/init.c | 25 | ||||
-rw-r--r-- | gcc/cp/name-lookup.c | 3 | ||||
-rw-r--r-- | gcc/cp/pt.c | 71 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 8 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/init/member1.C | 5 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/template/static13.C | 14 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/template/static14.C | 13 |
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; +}; |