OSDN Git Service

PR c++/53220
authorjason <jason@138bc75d-0d04-0410-961f-82ee72b054a4>
Wed, 30 May 2012 14:51:54 +0000 (14:51 +0000)
committerjason <jason@138bc75d-0d04-0410-961f-82ee72b054a4>
Wed, 30 May 2012 14:51:54 +0000 (14:51 +0000)
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
gcc/c-typeck.c
gcc/cp/ChangeLog
gcc/cp/call.c
gcc/cp/typeck.c
gcc/doc/extend.texi
gcc/testsuite/ChangeLog
gcc/testsuite/c-c++-common/array-lit.c [new file with mode: 0644]
gcc/testsuite/g++.dg/ext/complit12.C

index 3e3e165..4708681 100644 (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
index 54018aa..d689215 100644 (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);
 }
index a1dd1f7..624034c 100644 (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
index e543528..59e6e49 100644 (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);
index 8a0c75b..8628e83 100644 (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)
index 5949786..27a9e4f 100644 (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
index 3910881..16eb625 100644 (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
diff --git a/gcc/testsuite/c-c++-common/array-lit.c b/gcc/testsuite/c-c++-common/array-lit.c
new file mode 100644 (file)
index 0000000..6505c20
--- /dev/null
@@ -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;
+}
index 29c9af1..5c6a731 100644 (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;