aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Mitchell <mark@codesourcery.com>2007-07-06 01:23:54 +0000
committerMark Mitchell <mmitchel@gcc.gnu.org>2007-07-06 01:23:54 +0000
commit32a11c08863764dfd6a3be749c0729fee6cd298c (patch)
tree17dc867104325855fe255d6858ff0978e0b8936c
parent22761ec3b9b4688e515019b6b97025fda5be6a44 (diff)
downloadgcc-32a11c08863764dfd6a3be749c0729fee6cd298c.zip
gcc-32a11c08863764dfd6a3be749c0729fee6cd298c.tar.gz
gcc-32a11c08863764dfd6a3be749c0729fee6cd298c.tar.bz2
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
-rw-r--r--gcc/cp/ChangeLog24
-rw-r--r--gcc/cp/call.c32
-rw-r--r--gcc/cp/cp-tree.h1
-rw-r--r--gcc/cp/decl.c52
-rw-r--r--gcc/cp/init.c5
-rw-r--r--gcc/cp/parser.c14
-rw-r--r--gcc/cp/pt.c20
-rw-r--r--gcc/cp/typeck2.c4
-rw-r--r--gcc/testsuite/ChangeLog11
-rw-r--r--gcc/testsuite/g++.dg/init/new21.C10
-rw-r--r--gcc/testsuite/g++.dg/init/ptrmem4.C13
-rw-r--r--gcc/testsuite/g++.dg/template/static30.C10
12 files changed, 165 insertions, 31 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 1621175..3aac996 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,27 @@
+2007-07-05 Mark Mitchell <mark@codesourcery.com>
+
+ 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 <doug.gregor@gmail.com>
* decl.c (build_ptrmemfunc_type): Always use structural equality
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 86d5fbc..82f8666 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 %<operator %s%> for %qT",
operator_name_info[(int)code].name, type);
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 654e258..68aeace 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 630cec1..bed426b 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 b000cfd..288d0fa 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 ae970d6..0bd33d6 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 <int N> struct A {
+ int a[B<N>::i];
+ };
+
+ is accepted. At template-instantiation time, we
+ will check that B<N>::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 63f8247..b822d95 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 66c8b9c..4ef082d 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 d2ff6b2..266cc59 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,14 @@
+2007-07-05 Mark Mitchell <mark@codesourcery.com>
+
+ 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 <dorit@il.ibm.com>
* 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 0000000..5797ea9
--- /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 0000000..44ab8cf
--- /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 0000000..01fa5dc
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/static30.C
@@ -0,0 +1,10 @@
+// PR c++/31992
+
+template <int> struct A
+{
+ static const int i1;
+ static const int i2;
+};
+
+template <int N> const int A<N>::i1(A<N>::i);
+template <int N> const int A<N>::i2(3, A<N>::i);