My recent patch for -Winit-list-lifetime added a warning for returning
a temporary initializer_list, but the bug report is correct that we
*could* promote the constant array to .rodata as an optimization, did
in GCC 7, and don't in GCC 8.  That we did in GCC 7 was for the wrong
reason, because we were treating it as a C compound literal, but this
patch allows arbitrary constant aggregate temporaries to be allocated
to .rodata if appropriate.

Tested x86_64-pc-linux-gnu, applying to trunk.
commit 7f55bc360af52bd19996f030ad4c506dd153ff66
Author: Jason Merrill <ja...@redhat.com>
Date:   Fri May 25 12:43:29 2018 -0400

            PR c++/85873 - constant initializer_list array not in .rodata.
    
            * tree.c (build_target_expr): Set TREE_READONLY.
            * call.c (set_up_extended_ref_temp): Set TREE_READONLY.

diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 2bbf9837487..67e404d1cb2 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -10923,13 +10923,11 @@ set_up_extended_ref_temp (tree decl, tree expr, vec<tree, va_gc> **cleanups,
 	     lvalue-rvalue conversion applied to "a glvalue of literal type
 	     that refers to a non-volatile temporary object initialized
 	     with a constant expression".  Rather than try to communicate
-	     that this VAR_DECL is a temporary, just mark it constexpr.
-
-	     Currently this is only useful for initializer_list temporaries,
-	     since reference vars can't appear in constant expressions.  */
+	     that this VAR_DECL is a temporary, just mark it constexpr.  */
 	  DECL_DECLARED_CONSTEXPR_P (var) = true;
 	  DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (var) = true;
 	  TREE_CONSTANT (var) = true;
+	  TREE_READONLY (var) = true;
 	}
       DECL_INITIAL (var) = init;
       init = NULL_TREE;
diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
index f21daaca1d0..53bc9c7176f 100644
--- a/gcc/cp/tree.c
+++ b/gcc/cp/tree.c
@@ -461,6 +461,14 @@ build_target_expr (tree decl, tree value, tsubst_flags_t complain)
 		       || useless_type_conversion_p (TREE_TYPE (decl),
 						     TREE_TYPE (value)));
 
+  /* Set TREE_READONLY for optimization, such as gimplify_init_constructor
+     moving a constant aggregate into .rodata.  */
+  if (CP_TYPE_CONST_NON_VOLATILE_P (type)
+      && !TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type)
+      && !VOID_TYPE_P (TREE_TYPE (value))
+      && reduced_constant_expression_p (value))
+    TREE_READONLY (decl) = true;
+
   if (complain & tf_no_cleanup)
     /* The caller is building a new-expr and does not need a cleanup.  */
     t = NULL_TREE;
diff --git a/gcc/testsuite/g++.dg/tree-ssa/array-temp1.C b/gcc/testsuite/g++.dg/tree-ssa/array-temp1.C
new file mode 100644
index 00000000000..97c2e0521c9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/tree-ssa/array-temp1.C
@@ -0,0 +1,21 @@
+// PR c++/85873
+// Test that these array temporaries are promoted to static variables as an
+// optimization.
+
+// { dg-do compile { target c++11 } }
+// { dg-additional-options -fdump-tree-gimple }
+// { dg-final { scan-tree-dump-not "= 42" "gimple" } }
+
+#include <initializer_list>
+
+int f()
+{
+  using AR = const int[];
+  return AR{ 1,42,3,4,5,6,7,8,9,0 }[5];
+}
+
+int g()
+{
+  std::initializer_list<int> a = {1,42,3};
+  return a.begin()[0];
+}

Reply via email to