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]; +}