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: r187916
This commit is contained in:
parent
c4c57c9cbe
commit
1f37c58399
9 changed files with 87 additions and 8 deletions
|
@ -1,3 +1,9 @@
|
|||
2012-05-26 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-26 Eric Botcazou <ebotcazou@adacore.com>
|
||||
|
||||
* cfgcleanup.c (try_optimize_cfg): Do not delete forwarder blocks
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -1,3 +1,10 @@
|
|||
2012-05-26 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-25 Paolo Carlini <paolo.carlini@oracle.com>
|
||||
|
||||
PR c++/32054
|
||||
|
|
|
@ -5849,11 +5849,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, complain));
|
||||
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);
|
||||
|
|
|
@ -1886,6 +1886,15 @@ decay_conversion (tree exp, tsubst_flags_t complain)
|
|||
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)
|
||||
{
|
||||
if (complain & tf_error)
|
||||
error_at (loc, "taking address of temporary array");
|
||||
return error_mark_node;
|
||||
}
|
||||
|
||||
ptrtype = build_pointer_type (TREE_TYPE (type));
|
||||
|
||||
if (TREE_CODE (exp) == VAR_DECL)
|
||||
|
|
|
@ -1759,7 +1759,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:
|
||||
|
@ -1785,8 +1786,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:
|
||||
|
@ -1822,6 +1824,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
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
2012-05-22 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-26 Eric Botcazou <ebotcazou@adacore.com>
|
||||
|
||||
PR ada/50294
|
||||
|
|
12
gcc/testsuite/c-c++-common/array-lit.c
Normal file
12
gcc/testsuite/c-c++-common/array-lit.c
Normal 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;
|
||||
}
|
|
@ -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;
|
||||
|
|
Loading…
Add table
Reference in a new issue