flag_merge_constants permits us to assume the same on readonly vars. */
if (is_a <varpool_node *> (this)
&& (DECL_IN_CONSTANT_POOL (decl)
- || (flag_merge_constants >= 2
+ || ((flag_merge_constants >= 2 || DECL_MERGEABLE (decl))
&& TREE_READONLY (decl) && !TREE_THIS_VOLATILE (decl))))
return false;
return true;
init_elttype = cp_build_qualified_type (init_elttype, TYPE_QUAL_CONST);
tree arr = build_array_of_n_type (init_elttype, CONSTRUCTOR_NELTS (init));
- return finish_compound_literal (arr, init, tf_none);
+ arr = finish_compound_literal (arr, init, tf_none);
+ DECL_MERGEABLE (TARGET_EXPR_SLOT (arr)) = true;
+ return arr;
}
/* If we were going to call e.g. vector(initializer_list<string>) starting
(elttype, cp_type_quals (elttype) | TYPE_QUAL_CONST);
array = build_array_of_n_type (elttype, len);
array = finish_compound_literal (array, new_ctor, complain);
+ /* This is dubious now, should be blessed by P2752. */
+ DECL_MERGEABLE (TARGET_EXPR_SLOT (array)) = true;
/* 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);
VAR. */
if (TREE_CODE (expr) != TARGET_EXPR)
expr = get_target_expr (expr);
- else if (TREE_ADDRESSABLE (expr))
- TREE_ADDRESSABLE (var) = 1;
+ else
+ {
+ if (TREE_ADDRESSABLE (expr))
+ TREE_ADDRESSABLE (var) = 1;
+ if (DECL_MERGEABLE (TARGET_EXPR_SLOT (expr)))
+ DECL_MERGEABLE (var) = true;
+ }
if (TREE_CODE (decl) == FIELD_DECL
&& extra_warnings && !warning_suppressed_p (decl))
int /*flags*/,
bool* no_add_attrs)
{
- if (TREE_CODE (*node) != FIELD_DECL)
+ if (TREE_CODE (*node) == VAR_DECL)
+ {
+ DECL_MERGEABLE (*node) = true;
+ if (pedantic)
+ warning (OPT_Wattributes, "%qE attribute can only be applied to "
+ "non-static data members", name);
+ }
+ else if (TREE_CODE (*node) != FIELD_DECL)
{
warning (OPT_Wattributes, "%qE attribute can only be applied to "
"non-static data members", name);
&& TREE_READONLY (object)
&& VAR_P (object)
&& !DECL_REGISTER (object)
- && (flag_merge_constants >= 2 || !TREE_ADDRESSABLE (object))
+ && (flag_merge_constants >= 2 || !TREE_ADDRESSABLE (object)
+ || DECL_MERGEABLE (object))
/* For ctors that have many repeated nonzero elements
represented through RANGE_EXPRs, prefer initializing
those through runtime loops over copies of large amounts
--- /dev/null
+// Test that -fipa-icf combines i and j.
+// { dg-do run { target c++11 } }
+// { dg-options -fipa-icf }
+
+[[no_unique_address]] extern const int i[] = { 1,2,3 };
+[[no_unique_address]] extern const int j[] = { 1,2,3 };
+
+[[gnu::noipa]] void f (const void *a, const void *b)
+{
+ if (a != b) __builtin_abort();
+}
+
+int main()
+{
+ f (&i, &j);
+}
--- /dev/null
+// Test that -fipa-icf combines the backing arrays for a and b.
+// { dg-do run { target c++11 } }
+// { dg-options -fipa-icf }
+
+#include <initializer_list>
+
+[[gnu::noipa]] void f (const void *a, const void *b)
+{
+ if (a != b) __builtin_abort();
+}
+
+int main()
+{
+ auto a = { 1, 2 };
+ auto b = { 1, 2 };
+ f (a.begin(), b.begin());
+}
--- /dev/null
+// Test that -fipa-icf combines the backing arrays for a and b.
+// { dg-do run { target c++11 } }
+// { dg-options -fipa-icf }
+
+#include <initializer_list>
+
+template <class T>
+[[gnu::noipa]] void f (std::initializer_list<T> a,
+ std::initializer_list<T> b)
+{
+ if (a.begin() != b.begin()) __builtin_abort();
+}
+
+int main()
+{
+ f ({1,2}, {1,2});
+}
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];
+}
// Test that we do range-initialization from const char *.
// { dg-final { scan-tree-dump {_M_range_initialize<const char\* const\*>} "gimple" } }
+// { dg-final { scan-tree-dump {static const char.*72} "gimple" } }
#include <string>
#include <vector>
// Test that we do range-initialization from const char *.
// { dg-final { scan-tree-dump {_M_range_initialize<const char\* const\*>} "gimple" } }
+// And that the backing array is static.
+// { dg-final { scan-tree-dump {static const char.*72} "gimple" } }
#include <string>
#include <vector>
--- /dev/null
+// PR c++/110070
+// { dg-additional-options -fdump-tree-gimple }
+// { dg-do compile { target c++11 } }
+
+// { dg-final { scan-tree-dump {static const int [^\n]*\[4\] = } "gimple" } }
+
+#include <initializer_list>
+extern void ext(int);
+void foo()
+{
+ for (int i: {1,2,4,6})
+ ext(i);
+}
In VAR_DECL, PARM_DECL and RESULT_DECL, this is
DECL_HAS_VALUE_EXPR_P. */
unsigned decl_flag_2 : 1;
- /* In FIELD_DECL, this is DECL_PADDING_P. */
+ /* In FIELD_DECL, this is DECL_PADDING_P.
+ In VAR_DECL, this is DECL_MERGEABLE. */
unsigned decl_flag_3 : 1;
/* Logically, these two would go in a theoretical base shared by var and
parm decl. */
#define DECL_NONALIASED(NODE) \
(VAR_DECL_CHECK (NODE)->base.nothrow_flag)
+/* In a VAR_DECL, nonzero if this variable is not required to have a distinct
+ address from other variables with the same constant value. In other words,
+ consider -fmerge-all-constants to be on for this VAR_DECL. */
+#define DECL_MERGEABLE(NODE) \
+ (VAR_DECL_CHECK (NODE)->decl_common.decl_flag_3)
+
/* This field is used to reference anything in decl.result and is meant only
for use by the garbage collector. */
#define DECL_RESULT_FLD(NODE) \
}
else if (reloc & targetm.asm_out.reloc_rw_mask ())
ret = reloc == 1 ? SECCAT_DATA_REL_RO_LOCAL : SECCAT_DATA_REL_RO;
- else if (reloc || flag_merge_constants < 2
+ else if (reloc || (flag_merge_constants < 2 && !DECL_MERGEABLE (decl))
|| ((flag_sanitize & SANITIZE_ADDRESS)
/* PR 81697: for architectures that use section anchors we
need to ignore DECL_RTL_SET_P (decl) for string constants