re PR c++/53220 (g++ mis-compiles compound literals)

PR c++/53220
gcc/
	* c-typeck.c (array_to_pointer_conversion): Give -Wc++-compat warning
	about array compound literals.
gcc/cp/
	* call.c (convert_like_real) [ck_list]: Take array address directly.
	* typeck.c (decay_conversion): Reject decay of an array compound
	literal.

From-SVN: r188020
This commit is contained in:
Jason Merrill 2012-05-30 10:51:54 -04:00 committed by Jason Merrill
parent a822893aee
commit 10df929392
9 changed files with 86 additions and 8 deletions

View File

@ -1,3 +1,9 @@
2012-05-30 Jason Merrill <jason@redhat.com>
PR c++/53220
* c-typeck.c (array_to_pointer_conversion): Give -Wc++-compat warning
about array compound literals.
2012-05-30 Richard Guenther <rguenther@suse.de>
PR middle-end/53501

View File

@ -1785,6 +1785,18 @@ array_to_pointer_conversion (location_t loc, tree exp)
if (TREE_CODE (exp) == INDIRECT_REF)
return convert (ptrtype, TREE_OPERAND (exp, 0));
/* In C++ array compound literals are temporary objects unless they are
const or appear in namespace scope, so they are destroyed too soon
to use them for much of anything (c++/53220). */
if (warn_cxx_compat && TREE_CODE (exp) == COMPOUND_LITERAL_EXPR)
{
tree decl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
if (!TREE_READONLY (decl) && !TREE_STATIC (decl))
warning_at (DECL_SOURCE_LOCATION (decl), OPT_Wc___compat,
"converting an array compound literal to a pointer "
"is ill-formed in C++");
}
adr = build_unary_op (loc, ADDR_EXPR, exp, 1);
return convert (ptrtype, adr);
}

View File

@ -1,3 +1,10 @@
2012-05-30 Jason Merrill <jason@redhat.com>
PR c++/53220
* call.c (convert_like_real) [ck_list]: Take array address directly.
* typeck.c (decay_conversion): Reject decay of an array compound
literal.
2012-05-29 Paolo Carlini <paolo.carlini@oracle.com>
PR c++/53491

View File

@ -5772,11 +5772,15 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum,
(elttype, cp_type_quals (elttype) | TYPE_QUAL_CONST);
array = build_array_of_n_type (elttype, len);
array = finish_compound_literal (array, new_ctor, complain);
/* Take the address explicitly rather than via decay_conversion
to avoid the error about taking the address of a temporary. */
array = cp_build_addr_expr (array, complain);
array = cp_convert (build_pointer_type (elttype), array);
/* Build up the initializer_list object. */
totype = complete_type (totype);
field = next_initializable_field (TYPE_FIELDS (totype));
CONSTRUCTOR_APPEND_ELT (vec, field, decay_conversion (array));
CONSTRUCTOR_APPEND_ELT (vec, field, array);
field = next_initializable_field (DECL_CHAIN (field));
CONSTRUCTOR_APPEND_ELT (vec, field, size_int (len));
new_ctor = build_constructor (totype, vec);

View File

@ -1876,6 +1876,14 @@ decay_conversion (tree exp)
return error_mark_node;
}
/* Don't let an array compound literal decay to a pointer. It can
still be used to initialize an array or bind to a reference. */
if (TREE_CODE (exp) == TARGET_EXPR)
{
error ("taking address of temporary array");
return error_mark_node;
}
ptrtype = build_pointer_type (TREE_TYPE (type));
if (TREE_CODE (exp) == VAR_DECL)

View File

@ -1758,7 +1758,8 @@ ISO C99 supports compound literals. A compound literal looks like
a cast containing an initializer. Its value is an object of the
type specified in the cast, containing the elements specified in
the initializer; it is an lvalue. As an extension, GCC supports
compound literals in C90 mode and in C++.
compound literals in C90 mode and in C++, though the semantics are
somewhat different in C++.
Usually, the specified type is a structure. Assume that
@code{struct foo} and @code{structure} are declared as shown:
@ -1784,8 +1785,9 @@ This is equivalent to writing the following:
@}
@end smallexample
You can also construct an array. If all the elements of the compound literal
are (made up of) simple constant expressions, suitable for use in
You can also construct an array, though this is dangerous in C++, as
explained below. If all the elements of the compound literal are
(made up of) simple constant expressions, suitable for use in
initializers of objects of static storage duration, then the compound
literal can be coerced to a pointer to its first element and used in
such an initializer, as shown here:
@ -1821,6 +1823,25 @@ static int y[] = @{1, 2, 3@};
static int z[] = @{1, 0, 0@};
@end smallexample
In C, a compound literal designates an unnamed object with static or
automatic storage duration. In C++, a compound literal designates a
temporary object, which only lives until the end of its
full-expression. As a result, well-defined C code that takes the
address of a subobject of a compound literal can be undefined in C++.
For instance, if the array compound literal example above appeared
inside a function, any subsequent use of @samp{foo} in C++ has
undefined behavior because the lifetime of the array ends after the
declaration of @samp{foo}. As a result, the C++ compiler now rejects
the conversion of a temporary array to a pointer.
As an optimization, the C++ compiler sometimes gives array compound
literals longer lifetimes: when the array either appears outside a
function or has const-qualified type. If @samp{foo} and its
initializer had elements of @samp{char *const} type rather than
@samp{char *}, or if @samp{foo} were a global variable, the array
would have static storage duration. But it is probably safest just to
avoid the use of array compound literals in code compiled as C++.
@node Designated Inits
@section Designated Initializers
@cindex initializers with labeled elements

View File

@ -1,3 +1,9 @@
2012-05-30 Jason Merrill <jason@redhat.com>
PR c++/53220
* c-c++-common/array-lit.c: New.
* g++.dg/ext/complit12.C: #if 0 out decay-to-pointer test.
2012-05-30 Richard Guenther <rguenther@suse.de>
PR middle-end/53501

View File

@ -0,0 +1,12 @@
/* { dg-options "-std=c99 -Wc++-compat -Werror" { target c } } */
/* { dg-prune-output "treated as errors" } */
#include <stdio.h>
int main()
{
for (int *p = (int[]){ 1, 2, 3, 0 }; /* { dg-error "array" } */
*p; ++p) {
printf("%d\n", *p);
}
return 0;
}

View File

@ -53,12 +53,14 @@ int main ()
T t;
if (c != 11)
return 5;
MA ma = bar ((M[2]) { M(), M() }, m);
if (c != 12)
return 7;
M mm[2] = ((M[2]) { f(M()), f(M()) });
if (c != 14)
if (c != 13)
return 8;
#if 0
MA ma = bar ((M[2]) { M(), M() }, m);
if (c != 14)
return 7;
#endif
}
if (c != 0)
return 6;