From b794e321c163674e83fa0b8f7a7aa1b4359c918c Mon Sep 17 00:00:00 2001 From: Mark Mitchell Date: Mon, 29 Aug 2005 14:08:50 +0000 Subject: [PATCH] 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 --- gcc/cp/ChangeLog | 19 +++++++ gcc/cp/cp-tree.h | 1 + gcc/cp/decl.c | 17 ++++-- gcc/cp/init.c | 25 ++++++--- gcc/cp/name-lookup.c | 3 ++ gcc/cp/pt.c | 67 +++++++++++++----------- gcc/testsuite/ChangeLog | 8 +++ gcc/testsuite/g++.dg/init/member1.C | 5 +- gcc/testsuite/g++.dg/template/static13.C | 14 +++++ gcc/testsuite/g++.dg/template/static14.C | 13 +++++ 10 files changed, 132 insertions(+), 40 deletions(-) create mode 100644 gcc/testsuite/g++.dg/template/static13.C create mode 100644 gcc/testsuite/g++.dg/template/static14.C 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 + + 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 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; + /* 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) 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 + + 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 * 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 struct B {}; template struct C { static const int i = A::i; // { dg-error "incomplete" } - static const int j = i; // { dg-error "initialized by a non-const" } + static const int j = i; B b; // { dg-error "not a valid template arg" } }; C c; + +int i = C::i; +int j = C::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 +struct A { + static const int N = sizeof(static_cast(T())); +}; + +struct Derived : Base { + A 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 +struct A { + static const int N = sizeof(static_cast(T())); + int a[N]; +}; + +struct Derived : Base { + A a; +};