diff options
-rw-r--r-- | gcc/cp/ChangeLog | 12 | ||||
-rw-r--r-- | gcc/cp/cp-tree.h | 12 | ||||
-rw-r--r-- | gcc/cp/decl.c | 4 | ||||
-rw-r--r-- | gcc/cp/decl2.c | 4 | ||||
-rw-r--r-- | gcc/cp/pt.c | 24 | ||||
-rw-r--r-- | gcc/cp/semantics.c | 8 | ||||
-rw-r--r-- | gcc/cp/typeck.c | 20 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 2 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/template/dr408.C | 45 |
9 files changed, 126 insertions, 5 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index c044294..4ea2565 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,5 +1,17 @@ 2010-04-07 Jason Merrill <jason@redhat.com> + PR c++/11094, DR 408 + * cp-tree.h (VAR_HAD_UNKNOWN_BOUND, SET_VAR_HAD_UNKNOWN_BOUND): New. + * decl2.c (finish_static_data_member_decl): Set it. + * decl.c (duplicate_decls): Propagate it. + * pt.c (tsubst_decl): Don't substitute the domain of an array + VAR_DECL if it's set. + (regenerate_decl_from_template): Substitute it here. + (type_dependent_expression_p): Return true if it's set. + * semantics.c (finish_decltype_type): Instantiate such a variable. + * typeck.c (cxx_sizeof_expr): Likewise. + (strip_array_domain): New. + * name-lookup.c (current_decl_namespace): Non-static. (pop_nested_namespace): Sanity check. * cp-tree.h: Declare current_decl_namespace. diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index f71317b..941c49a 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -1758,7 +1758,7 @@ struct GTY(()) lang_decl_base { unsigned threadprivate_or_deleted_p : 1; /* var or fn */ unsigned anticipated_p : 1; /* fn or type */ unsigned friend_attr : 1; /* fn or type */ - unsigned template_conv_p : 1; /* template only? */ + unsigned template_conv_p : 1; /* var or template */ unsigned odr_used : 1; /* var or fn */ unsigned u2sel : 1; /* 1 spare bit */ @@ -2088,6 +2088,15 @@ struct GTY(()) lang_decl { #define DECL_TEMPLATE_CONV_FN_P(NODE) \ (DECL_LANG_SPECIFIC (TEMPLATE_DECL_CHECK (NODE))->u.base.template_conv_p) +/* Nonzero if NODE, a static data member, was declared in its class as an + array of unknown bound. */ +#define VAR_HAD_UNKNOWN_BOUND(NODE) \ + (DECL_LANG_SPECIFIC (VAR_DECL_CHECK (NODE)) \ + ? DECL_LANG_SPECIFIC (NODE)->u.base.template_conv_p \ + : false) +#define SET_VAR_HAD_UNKNOWN_BOUND(NODE) \ + (DECL_LANG_SPECIFIC (VAR_DECL_CHECK (NODE))->u.base.template_conv_p = true) + /* Set the overloaded operator code for NODE to CODE. */ #define SET_OVERLOADED_OPERATOR_CODE(NODE, CODE) \ (LANG_DECL_FN_CHECK (NODE)->operator_code = (CODE)) @@ -5393,6 +5402,7 @@ extern tree composite_pointer_type (tree, tree, tree, tree, composite_pointer_operation, tsubst_flags_t); extern tree merge_types (tree, tree); +extern tree strip_array_domain (tree); extern tree check_return_expr (tree, bool *); extern tree cp_build_binary_op (location_t, enum tree_code, tree, tree, diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index bfbe3ca..7a82ed6 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -1929,6 +1929,10 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend) if (DECL_VIRTUAL_P (newdecl)) DECL_THUNKS (newdecl) = DECL_THUNKS (olddecl); } + /* Only variables have this field. */ + else if (TREE_CODE (newdecl) == VAR_DECL + && VAR_HAD_UNKNOWN_BOUND (olddecl)) + SET_VAR_HAD_UNKNOWN_BOUND (newdecl); } if (TREE_CODE (newdecl) == FUNCTION_DECL) diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index 90adc68..d811c9e 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -785,6 +785,10 @@ finish_static_data_member_decl (tree decl, DECL_INITIAL (decl) = init; DECL_IN_AGGR_P (decl) = 1; + if (TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE + && TYPE_DOMAIN (TREE_TYPE (decl)) == NULL_TREE) + SET_VAR_HAD_UNKNOWN_BOUND (decl); + cp_finish_decl (decl, init, init_const_expr_p, asmspec_tree, flags); } diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 1c0e13e..367608f 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -9496,6 +9496,8 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain) type = DECL_ORIGINAL_TYPE (t); else type = TREE_TYPE (t); + if (TREE_CODE (t) == VAR_DECL && VAR_HAD_UNKNOWN_BOUND (t)) + type = strip_array_domain (type); type = tsubst (type, args, complain, in_decl); } if (TREE_CODE (r) == VAR_DECL) @@ -16456,10 +16458,15 @@ regenerate_decl_from_template (tree decl, tree tmpl) DECL_DECLARED_INLINE_P (decl) = 1; } else if (TREE_CODE (decl) == VAR_DECL) - DECL_INITIAL (decl) = - tsubst_expr (DECL_INITIAL (code_pattern), args, - tf_error, DECL_TI_TEMPLATE (decl), - /*integral_constant_expression_p=*/false); + { + DECL_INITIAL (decl) = + tsubst_expr (DECL_INITIAL (code_pattern), args, + tf_error, DECL_TI_TEMPLATE (decl), + /*integral_constant_expression_p=*/false); + if (VAR_HAD_UNKNOWN_BOUND (decl)) + TREE_TYPE (decl) = tsubst (TREE_TYPE (code_pattern), args, + tf_error, DECL_TI_TEMPLATE (decl)); + } else gcc_unreachable (); @@ -17730,6 +17737,15 @@ type_dependent_expression_p (tree expression) return false; } + /* A static data member of the current instantiation with incomplete + array type is type-dependent, as the definition and specializations + can have different bounds. */ + if (TREE_CODE (expression) == VAR_DECL + && DECL_CLASS_SCOPE_P (expression) + && dependent_type_p (DECL_CONTEXT (expression)) + && VAR_HAD_UNKNOWN_BOUND (expression)) + return true; + if (TREE_TYPE (expression) == unknown_type_node) { if (TREE_CODE (expression) == ADDR_EXPR) diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 5cf4b69..d425402 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -4836,6 +4836,14 @@ finish_decltype_type (tree expr, bool id_expression_or_member_access_p) /* The type denoted by decltype(e) is defined as follows: */ expr = resolve_nondeduced_context (expr); + + /* To get the size of a static data member declared as an array of + unknown bound, we need to instantiate it. */ + if (TREE_CODE (expr) == VAR_DECL + && VAR_HAD_UNKNOWN_BOUND (expr) + && DECL_TEMPLATE_INSTANTIATION (expr)) + instantiate_decl (expr, /*defer_ok*/true, /*expl_inst_mem*/false); + if (id_expression_or_member_access_p) { /* If e is an id-expression or a class member access (5.2.5 diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index 4b91912..f623717 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -878,6 +878,19 @@ merge_types (tree t1, tree t2) return cp_build_type_attribute_variant (t1, attributes); } +/* Return the ARRAY_TYPE type without its domain. */ + +tree +strip_array_domain (tree type) +{ + tree t2; + gcc_assert (TREE_CODE (type) == ARRAY_TYPE); + if (TYPE_DOMAIN (type) == NULL_TREE) + return type; + t2 = build_cplus_array_type (TREE_TYPE (type), NULL_TREE); + return cp_build_type_attribute_variant (t2, TYPE_ATTRIBUTES (type)); +} + /* Wrapper around cp_common_type that is used by c-common.c and other front end optimizations that remove promotions. @@ -1596,6 +1609,13 @@ cxx_sizeof_expr (tree e, tsubst_flags_t complain) return e; } + /* To get the size of a static data member declared as an array of + unknown bound, we need to instantiate it. */ + if (TREE_CODE (e) == VAR_DECL + && VAR_HAD_UNKNOWN_BOUND (e) + && DECL_TEMPLATE_INSTANTIATION (e)) + instantiate_decl (e, /*defer_ok*/true, /*expl_inst_mem*/false); + if (TREE_CODE (e) == COMPONENT_REF && TREE_CODE (TREE_OPERAND (e, 1)) == FIELD_DECL && DECL_C_BIT_FIELD (TREE_OPERAND (e, 1))) diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 4156ad4..32c64b3 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,5 +1,7 @@ 2010-04-07 Jason Merrill <jason@redhat.com> + * g++.dg/template/dr408.C: New. + * g++.dg/lookup/ns4.C: New. PR c++/38392 diff --git a/gcc/testsuite/g++.dg/template/dr408.C b/gcc/testsuite/g++.dg/template/dr408.C new file mode 100644 index 0000000..d118ce4 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/dr408.C @@ -0,0 +1,45 @@ +// DR 408 +// { dg-do link } + +// Test that a size given in the out-of-class definition isn't used until +// instantiation time. +template<typename T> +struct X +{ + static char s[]; + int c; +}; + +template<typename T> +char X<T>::s[sizeof(X<T>)]; + +#define sassert(EXP) int ar[(EXP)?1:-1] +sassert(sizeof (X<char>::s) == sizeof (int)); + +// Test that a specialization can have a different size. + +template <int> void g(); +template <> void g<2>() { } + +template <typename T> +struct S { + static int i[]; + void f(); +}; + +template <typename T> +int S<T>::i[] = { 1 }; + +template <typename T> +void S<T>::f() { + g<sizeof (i) / sizeof (int)>(); +} + +template <> +int S<int>::i[] = { 1, 2 }; + +int main() +{ + S<int> s; + s.f(); +} |