From bb86bcdff1719073969ec745e24ebd4e1dbd1a80 Mon Sep 17 00:00:00 2001 From: jason Date: Wed, 30 May 2012 14:51:54 +0000 Subject: [PATCH 1/1] 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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/gcc-4_7-branch@188020 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/ChangeLog | 6 ++++++ gcc/c-typeck.c | 12 ++++++++++++ gcc/cp/ChangeLog | 7 +++++++ gcc/cp/call.c | 6 +++++- gcc/cp/typeck.c | 8 ++++++++ gcc/doc/extend.texi | 27 ++++++++++++++++++++++++--- gcc/testsuite/ChangeLog | 6 ++++++ gcc/testsuite/c-c++-common/array-lit.c | 12 ++++++++++++ gcc/testsuite/g++.dg/ext/complit12.C | 10 ++++++---- 9 files changed, 86 insertions(+), 8 deletions(-) create mode 100644 gcc/testsuite/c-c++-common/array-lit.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 3e3e1657bc5..47086813a06 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,9 @@ +2012-05-30 Jason Merrill + + PR c++/53220 + * c-typeck.c (array_to_pointer_conversion): Give -Wc++-compat warning + about array compound literals. + 2012-05-30 Richard Guenther PR middle-end/53501 diff --git a/gcc/c-typeck.c b/gcc/c-typeck.c index 54018aa0745..d689215da5f 100644 --- a/gcc/c-typeck.c +++ b/gcc/c-typeck.c @@ -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); } diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index a1dd1f7acd0..624034c3f4b 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,10 @@ +2012-05-30 Jason Merrill + + 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 PR c++/53491 diff --git a/gcc/cp/call.c b/gcc/cp/call.c index e543528d1cb..59e6e49caa7 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -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); diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index 8a0c75b35c5..8628e832295 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -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) diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi index 5949786c373..27a9e4f9d77 100644 --- a/gcc/doc/extend.texi +++ b/gcc/doc/extend.texi @@ -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 diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 391088165d1..16eb625f629 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2012-05-30 Jason Merrill + + 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 PR middle-end/53501 diff --git a/gcc/testsuite/c-c++-common/array-lit.c b/gcc/testsuite/c-c++-common/array-lit.c new file mode 100644 index 00000000000..6505c2091b4 --- /dev/null +++ b/gcc/testsuite/c-c++-common/array-lit.c @@ -0,0 +1,12 @@ +/* { dg-options "-std=c99 -Wc++-compat -Werror" { target c } } */ +/* { dg-prune-output "treated as errors" } */ +#include + +int main() +{ + for (int *p = (int[]){ 1, 2, 3, 0 }; /* { dg-error "array" } */ + *p; ++p) { + printf("%d\n", *p); + } + return 0; +} diff --git a/gcc/testsuite/g++.dg/ext/complit12.C b/gcc/testsuite/g++.dg/ext/complit12.C index 29c9af1864f..5c6a731f9ac 100644 --- a/gcc/testsuite/g++.dg/ext/complit12.C +++ b/gcc/testsuite/g++.dg/ext/complit12.C @@ -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; -- 2.11.0