The issue here was that we've been trying to treat C++
list-initialized temporaries (which are rvalues) the same as C99
compound literals (which are lvalues).  This patch distinguishes
between them so we can treat them each correctly.

This leaves open the question of how compound literals ought to work
in C++; currently we mostly treat them as rvalues, like other
temporaries, except for constant arrays, which we treat as lvalues, as
in C.  Now that we distinguish between C and C++ syntax for
list-initialization of a temporary object, we could go back to
treating all C-style compound literals as lvalues for better C
compatibility.  Or we could decide that following the C++ temporary
model consistently is more important. But this patch doesn't do
either.

Tested x86_64-pc-linux-gnu, applying to trunk.
commit 929e7c870d235fea4a475928001f073b76829580
Author: Jason Merrill <ja...@redhat.com>
Date:   Mon Apr 17 10:30:15 2017 -0400

            PR c++/70167 - array prvalue treated as lvalue
    
            * cp-tree.h (CONSTRUCTOR_C99_COMPOUND_LITERAL): New.
            (enum fcl_t): New.
            * semantics.c (finish_compound_literal): Add fcl_context parameter.
            Only make a static variable for C99 syntax.
            * parser.c (cp_parser_postfix_expression): Pass it.
            * pt.c (tsubst_copy_and_build): Likewise.
            * call.c (extend_ref_init_temps): Set
            DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P.

diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index d9accd1..dee236e 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -10516,6 +10516,9 @@ extend_ref_init_temps (tree decl, tree init, vec<tree, 
va_gc> **cleanups)
              FOR_EACH_VEC_SAFE_ELT (elts, i, p)
                p->value = extend_ref_init_temps (decl, p->value, cleanups);
            }
+         recompute_constructor_flags (ctor);
+         if (decl_maybe_constant_var_p (decl) && TREE_CONSTANT (ctor))
+           DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl) = true;
        }
     }
 
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index b64fa6d..100f85c 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -369,6 +369,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX];
       DECL_NON_TRIVIALLY_INITIALIZED_P (in VAR_DECL)
       CALL_EXPR_ORDERED_ARGS (in CALL_EXPR, AGGR_INIT_EXPR)
       DECLTYPE_FOR_REF_CAPTURE (in DECLTYPE_TYPE)
+      CONSTUCTOR_C99_COMPOUND_LITERAL (in CONSTRUCTOR)
    4: TREE_HAS_CONSTRUCTOR (in INDIRECT_REF, SAVE_EXPR, CONSTRUCTOR,
          CALL_EXPR, or FIELD_DECL).
       IDENTIFIER_TYPENAME_P (in IDENTIFIER_NODE)
@@ -3898,6 +3899,11 @@ more_aggr_init_expr_args_p (const 
aggr_init_expr_arg_iterator *iter)
 #define CONSTRUCTOR_MUTABLE_POISON(NODE) \
   (TREE_LANG_FLAG_2 (CONSTRUCTOR_CHECK (NODE)))
 
+/* True if this typed CONSTRUCTOR represents C99 compound-literal syntax rather
+   than C++11 functional cast syntax.  */
+#define CONSTRUCTOR_C99_COMPOUND_LITERAL(NODE) \
+  (TREE_LANG_FLAG_3 (CONSTRUCTOR_CHECK (NODE)))
+
 #define DIRECT_LIST_INIT_P(NODE) \
    (BRACE_ENCLOSED_INITIALIZER_P (NODE) && CONSTRUCTOR_IS_DIRECT_INIT (NODE))
 
@@ -6483,7 +6489,10 @@ extern tree finish_this_expr                     (void);
 extern tree finish_pseudo_destructor_expr       (tree, tree, tree, location_t);
 extern cp_expr finish_unary_op_expr            (location_t, enum tree_code, 
cp_expr,
                                                 tsubst_flags_t);
-extern tree finish_compound_literal            (tree, tree, tsubst_flags_t);
+/* Whether this call to finish_compound_literal represents a C++11 functional
+   cast or a C99 compound literal.  */
+enum fcl_t { fcl_functional, fcl_c99 };
+extern tree finish_compound_literal            (tree, tree, tsubst_flags_t, 
fcl_t = fcl_functional);
 extern tree finish_fname                       (tree);
 extern void finish_translation_unit            (void);
 extern tree finish_template_type_parm          (tree, tree);
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index ab56f12..1951452 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -6770,7 +6770,7 @@ cp_parser_postfix_expression (cp_parser *parser, bool 
address_p, bool cast_p,
                /* Form the representation of the compound-literal.  */
                postfix_expression
                  = finish_compound_literal (type, initializer,
-                                            tf_warning_or_error);
+                                            tf_warning_or_error, fcl_c99);
                postfix_expression.set_location (initializer.get_location ());
                break;
              }
@@ -26834,7 +26834,7 @@ cp_parser_functional_cast (cp_parser* parser, tree type)
        type = TREE_TYPE (type);
 
       cast = finish_compound_literal (type, expression_list,
-                                     tf_warning_or_error);
+                                     tf_warning_or_error, fcl_functional);
       /* Create a location of the form:
            type_name{i, f}
            ^~~~~~~~~~~~~~~
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index b42b1fc..a4a0d83 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -17709,7 +17709,12 @@ tsubst_copy_and_build (tree t,
        CONSTRUCTOR_IS_DIRECT_INIT (r) = CONSTRUCTOR_IS_DIRECT_INIT (t);
 
        if (TREE_HAS_CONSTRUCTOR (t))
-         RETURN (finish_compound_literal (type, r, complain));
+         {
+           fcl_t cl = fcl_functional;
+           if (CONSTRUCTOR_C99_COMPOUND_LITERAL (t))
+             cl = fcl_c99;
+           RETURN (finish_compound_literal (type, r, complain, cl));
+         }
 
        TREE_TYPE (r) = type;
        RETURN (r);
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index b15763d..238dfff 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -2647,12 +2647,14 @@ finish_unary_op_expr (location_t op_loc, enum tree_code 
code, cp_expr expr,
   return result;
 }
 
-/* Finish a compound-literal expression.  TYPE is the type to which
-   the CONSTRUCTOR in COMPOUND_LITERAL is being cast.  */
+/* Finish a compound-literal expression or C++11 functional cast with aggregate
+   initializer.  TYPE is the type to which the CONSTRUCTOR in COMPOUND_LITERAL
+   is being cast.  */
 
 tree
 finish_compound_literal (tree type, tree compound_literal,
-                        tsubst_flags_t complain)
+                        tsubst_flags_t complain,
+                        fcl_t fcl_context)
 {
   if (type == error_mark_node)
     return error_mark_node;
@@ -2661,7 +2663,7 @@ finish_compound_literal (tree type, tree compound_literal,
     {
       compound_literal
        = finish_compound_literal (TREE_TYPE (type), compound_literal,
-                                  complain);
+                                  complain, fcl_context);
       return cp_build_c_cast (type, compound_literal, complain);
     }
 
@@ -2682,6 +2684,8 @@ finish_compound_literal (tree type, tree compound_literal,
       TREE_TYPE (compound_literal) = type;
       /* Mark the expression as a compound literal.  */
       TREE_HAS_CONSTRUCTOR (compound_literal) = 1;
+      if (fcl_context == fcl_c99)
+       CONSTRUCTOR_C99_COMPOUND_LITERAL (compound_literal) = 1;
       return compound_literal;
     }
 
@@ -2717,10 +2721,17 @@ finish_compound_literal (tree type, tree 
compound_literal,
   compound_literal = digest_init_flags (type, compound_literal, LOOKUP_NORMAL,
                                        complain);
   if (TREE_CODE (compound_literal) == CONSTRUCTOR)
-    TREE_HAS_CONSTRUCTOR (compound_literal) = true;
+    {
+      TREE_HAS_CONSTRUCTOR (compound_literal) = true;
+      if (fcl_context == fcl_c99)
+       CONSTRUCTOR_C99_COMPOUND_LITERAL (compound_literal) = 1;
+    }
 
   /* Put static/constant array temporaries in static variables.  */
+  /* FIXME all C99 compound literals should be variables rather than C++
+     temporaries, unless they are used as an aggregate initializer.  */
   if ((!at_function_scope_p () || CP_TYPE_CONST_P (type))
+      && fcl_context == fcl_c99
       && TREE_CODE (type) == ARRAY_TYPE
       && !TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type)
       && initializer_constant_valid_p (compound_literal, type))
diff --git a/gcc/testsuite/g++.dg/cpp0x/initlist-array6.C 
b/gcc/testsuite/g++.dg/cpp0x/initlist-array6.C
new file mode 100644
index 0000000..fdfde0a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/initlist-array6.C
@@ -0,0 +1,11 @@
+// PR c++/70167
+// { dg-do compile { target c++11 } }
+
+template<class T, unsigned S> void f(T(&&)[S]) { }
+
+using arr = const int[2];
+
+int main()
+{
+  f(arr{1, 2});
+}

Reply via email to