From: Mark Mitchell Date: Fri, 6 Jul 2007 01:23:54 +0000 (+0000) Subject: re PR c++/32245 (wrong POD type initialization with pointer to member) X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=32a11c08863764dfd6a3be749c0729fee6cd298c;p=gcc.git re PR c++/32245 (wrong POD type initialization with pointer to member) PR c++/32245 * init.c (build_zero_init): Always build an initializer for non-static storage. * typeck2.c (build_functional_cast): Use build_zero_init. PR c++/32251 * init.c (build_new_1): Always pass the allocation function to build_op_delete_call. * call.c (build_op_delete_call): Handle operator delete with a variable-argument list. Do not issue an error when no matching deallocation function is available for a new operator. PR c++/31992 * cp-tree.h (any_value_dependent_elements_p): Declare it. * decl.c (value_dependent_init_p): New function. (cp_finish_decl): Use it. * pt.c (value_dependent_expression_p): Use any_value_dependent_elements_p. * parser.c (cp_parser_primary_expression): Add comment about treating dependent qualified names as integral constant-expressions. PR c++/32245 * g++.dg/init/ptrmem4.C: New test. PR c++/32251 * g++.dg/init/new21.C: Likewise. PR c++/31992 * g++.dg/template/static30.C: Likewise. From-SVN: r126399 --- diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 1621175b846..3aac996e4b3 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,27 @@ +2007-07-05 Mark Mitchell + + PR c++/32245 + * init.c (build_zero_init): Always build an initializer for + non-static storage. + * typeck2.c (build_functional_cast): Use build_zero_init. + + PR c++/32251 + * init.c (build_new_1): Always pass the allocation function to + build_op_delete_call. + * call.c (build_op_delete_call): Handle operator delete with a + variable-argument list. Do not issue an error when no matching + deallocation function is available for a new operator. + + PR c++/31992 + * cp-tree.h (any_value_dependent_elements_p): Declare it. + * decl.c (value_dependent_init_p): New function. + (cp_finish_decl): Use it. + * pt.c (value_dependent_expression_p): Use + any_value_dependent_elements_p. + * parser.c (cp_parser_primary_expression): Add comment about + treating dependent qualified names as integral + constant-expressions. + 2007-07-04 Douglas Gregor * decl.c (build_ptrmemfunc_type): Always use structural equality diff --git a/gcc/cp/call.c b/gcc/cp/call.c index 86d5fbccd10..82f8666c42e 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -4062,8 +4062,12 @@ build_new_op (enum tree_code code, int flags, tree arg1, tree arg2, tree arg3, GLOBAL_P is true if the delete-expression should not consider class-specific delete operators. PLACEMENT is the corresponding placement new call, or NULL_TREE. - If PLACEMENT is non-NULL, then ALLOC_FN is the allocation function - called to perform the placement new. */ + + If this call to "operator delete" is being generated as part to + deallocate memory allocated via a new-expression (as per [expr.new] + which requires that if the initialization throws an exception then + we call a deallocation function), then ALLOC_FN is the allocation + function. */ tree build_op_delete_call (enum tree_code code, tree addr, tree size, @@ -4151,9 +4155,13 @@ build_op_delete_call (enum tree_code code, tree addr, tree size, if (!a && !t) break; } - /* On the second pass, the second argument must be - "size_t". */ + /* On the second pass, look for a function with exactly two + arguments: "void *" and "size_t". */ else if (pass == 1 + /* For "operator delete(void *, ...)" there will be + no second argument, but we will not get an exact + match above. */ + && t && same_type_p (TREE_VALUE (t), size_type_node) && TREE_CHAIN (t) == void_list_node) break; @@ -4201,10 +4209,18 @@ build_op_delete_call (enum tree_code code, tree addr, tree size, } } - /* If we are doing placement delete we do nothing if we don't find a - matching op delete. */ - if (placement) - return NULL_TREE; + /* [expr.new] + + If no unambiguous matching deallocation function can be found, + propagating the exception does not cause the object's memory to + be freed. */ + if (alloc_fn) + { + if (!placement) + warning (0, "no corresponding deallocation function for `%D'", + alloc_fn); + return NULL_TREE; + } error ("no suitable % for %qT", operator_name_info[(int)code].name, type); diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 654e25809b1..68aeace6e44 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -4444,6 +4444,7 @@ extern bool dependent_template_id_p (tree, tree); extern bool type_dependent_expression_p (tree); extern bool any_type_dependent_arguments_p (tree); extern bool value_dependent_expression_p (tree); +extern bool any_value_dependent_elements_p (tree); extern tree resolve_typename_type (tree, bool); extern tree template_for_substitution (tree); extern tree build_non_dependent_expr (tree); diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 630cec1295f..bed426bb9c4 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -5099,6 +5099,36 @@ initialize_artificial_var (tree decl, tree init) make_rtl_for_nonlocal_decl (decl, init, /*asmspec=*/NULL); } +/* INIT is the initializer for a variable, as represented by the + parser. Returns true iff INIT is value-dependent. */ + +static bool +value_dependent_init_p (tree init) +{ + if (TREE_CODE (init) == TREE_LIST) + /* A parenthesized initializer, e.g.: int i (3, 2); ? */ + return any_value_dependent_elements_p (init); + else if (TREE_CODE (init) == CONSTRUCTOR) + /* A brace-enclosed initializer, e.g.: int i = { 3 }; ? */ + { + VEC(constructor_elt, gc) *elts; + size_t nelts; + size_t i; + + elts = CONSTRUCTOR_ELTS (init); + nelts = VEC_length (constructor_elt, elts); + for (i = 0; i < nelts; ++i) + if (value_dependent_init_p (VEC_index (constructor_elt, + elts, i)->value)) + return true; + } + else + /* It must be a simple expression, e.g., int i = 3; */ + return value_dependent_expression_p (init); + + return false; +} + /* Finish processing of a declaration; install its line number and initial value. If the length of an array type is not known before, @@ -5171,18 +5201,16 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p, TREE_CONSTANT (decl) = 1; } - if (!init - || !DECL_CLASS_SCOPE_P (decl) - || !DECL_INTEGRAL_CONSTANT_VAR_P (decl) - || type_dependent_p - || value_dependent_expression_p (init) - /* Check also if initializer is a value dependent - { integral_constant_expression }. */ - || (TREE_CODE (init) == CONSTRUCTOR - && VEC_length (constructor_elt, CONSTRUCTOR_ELTS (init)) == 1 - && value_dependent_expression_p - (VEC_index (constructor_elt, - CONSTRUCTOR_ELTS (init), 0)->value))) + /* Generally, initializers in templates are expanded when the + template is instantiated. But, if DECL is an integral + constant static data member, then it can be used in future + integral constant expressions, and its value must be + available. */ + if (!(init + && DECL_CLASS_SCOPE_P (decl) + && DECL_INTEGRAL_CONSTANT_VAR_P (decl) + && !type_dependent_p + && !value_dependent_init_p (init))) { if (init) DECL_INITIAL (decl) = init; diff --git a/gcc/cp/init.c b/gcc/cp/init.c index b000cfd0fa8..288d0faff35 100644 --- a/gcc/cp/init.c +++ b/gcc/cp/init.c @@ -196,7 +196,7 @@ build_zero_init (tree type, tree nelts, bool static_storage_p) corresponding to base classes as well. Thus, iterating over TYPE_FIELDs will result in correct initialization of all of the subobjects. */ - if (static_storage_p && !zero_init_p (TREE_TYPE (field))) + if (!static_storage_p || !zero_init_p (TREE_TYPE (field))) { tree value = build_zero_init (TREE_TYPE (field), /*nelts=*/NULL_TREE, @@ -2038,8 +2038,7 @@ build_new_1 (tree placement, tree type, tree nelts, tree init, globally_qualified_p, (placement_allocation_fn_p ? alloc_call : NULL_TREE), - (placement_allocation_fn_p - ? alloc_fn : NULL_TREE)); + alloc_fn); if (!cleanup) /* We're done. */; diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index ae970d68da8..0bd33d692a1 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -3368,7 +3368,19 @@ cp_parser_primary_expression (cp_parser *parser, /* If name lookup gives us a SCOPE_REF, then the qualifying scope was dependent. */ if (TREE_CODE (decl) == SCOPE_REF) - return decl; + { + /* At this point, we do not know if DECL is a valid + integral constant expression. We assume that it is + in fact such an expression, so that code like: + + template struct A { + int a[B::i]; + }; + + is accepted. At template-instantiation time, we + will check that B::i is actually a constant. */ + return decl; + } /* Check to see if DECL is a local variable in a context where that is forbidden. */ if (parser->local_variables_forbidden_p diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 63f8247095e..b822d951463 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -15074,12 +15074,7 @@ value_dependent_expression_p (tree expression) } if (TREE_CODE (expression) == TREE_LIST) - { - for (; expression; expression = TREE_CHAIN (expression)) - if (value_dependent_expression_p (TREE_VALUE (expression))) - return true; - return false; - } + return any_value_dependent_elements_p (expression); return value_dependent_expression_p (expression); } @@ -15308,6 +15303,19 @@ any_type_dependent_arguments_p (tree args) return false; } +/* Returns TRUE if LIST (a TREE_LIST whose TREE_VALUEs are + expressions) contains any value-dependent expressions. */ + +bool +any_value_dependent_elements_p (tree list) +{ + for (; list; list = TREE_CHAIN (list)) + if (value_dependent_expression_p (TREE_VALUE (list))) + return true; + + return false; +} + /* Returns TRUE if the ARG (a template argument) is dependent. */ bool diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c index 66c8b9c4feb..4ef082d30ab 100644 --- a/gcc/cp/typeck2.c +++ b/gcc/cp/typeck2.c @@ -1340,7 +1340,9 @@ build_functional_cast (tree exp, tree parms) && !CLASSTYPE_NON_POD_P (type) && TYPE_HAS_DEFAULT_CONSTRUCTOR (type)) { - exp = build_constructor (type, NULL); + exp = build_zero_init (type, + /*nelts=*/NULL_TREE, + /*static_storage_p=*/false); return get_target_expr (exp); } diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index d2ff6b2b8d3..266cc595ba6 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,14 @@ +2007-07-05 Mark Mitchell + + PR c++/32245 + * g++.dg/init/ptrmem4.C: New test. + + PR c++/32251 + * g++.dg/init/new21.C: Likewise. + + PR c++/31992 + * g++.dg/template/static30.C: Likewise. + 2007-07-05 Dorit Nuzman * gcc.dg/vect/costmodel/ppc: New directory. diff --git a/gcc/testsuite/g++.dg/init/new21.C b/gcc/testsuite/g++.dg/init/new21.C new file mode 100644 index 00000000000..5797ea981c0 --- /dev/null +++ b/gcc/testsuite/g++.dg/init/new21.C @@ -0,0 +1,10 @@ +// PR c++/32251 + +struct A { + A(); + void operator delete(void *, ...); +}; + +void foo () { + new A; // { dg-warning "deallocation" } +} diff --git a/gcc/testsuite/g++.dg/init/ptrmem4.C b/gcc/testsuite/g++.dg/init/ptrmem4.C new file mode 100644 index 00000000000..44ab8cf6529 --- /dev/null +++ b/gcc/testsuite/g++.dg/init/ptrmem4.C @@ -0,0 +1,13 @@ +// PR c++/32245 +// { dg-do run } + +struct foo { + int mem1; + int foo::* mem2; +}; + +int main () { + foo x = { 0 } ; + if (x.mem2 != foo().mem2) + return 1; +} diff --git a/gcc/testsuite/g++.dg/template/static30.C b/gcc/testsuite/g++.dg/template/static30.C new file mode 100644 index 00000000000..01fa5dc1e0e --- /dev/null +++ b/gcc/testsuite/g++.dg/template/static30.C @@ -0,0 +1,10 @@ +// PR c++/31992 + +template struct A +{ + static const int i1; + static const int i2; +}; + +template const int A::i1(A::i); +template const int A::i2(3, A::i);