diff --git a/gcc/tree-core.h b/gcc/tree-core.h
index 9d44c04bf03..6dd7b680b57 100644
--- a/gcc/tree-core.h
+++ b/gcc/tree-core.h
@@ -1803,7 +1803,8 @@ struct GTY(()) tree_decl_common {
      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. */
diff --git a/gcc/tree.h b/gcc/tree.h
index 0b72663e6a1..8a4beba1230 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -3233,6 +3233,12 @@ extern void decl_fini_priority_insert (tree, priority_type);
 #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) \
diff --git a/gcc/cgraph.cc b/gcc/cgraph.cc
index e8f9bec8227..e41e5ad3ae7 100644
--- a/gcc/cgraph.cc
+++ b/gcc/cgraph.cc
@@ -158,7 +158,7 @@ symtab_node::address_can_be_compared_p ()
      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;
diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc
index 6c36c755481..d6154f1a319 100644
--- a/gcc/cp/call.cc
+++ b/gcc/cp/call.cc
@@ -4274,7 +4274,9 @@ maybe_init_list_as_array (tree elttype, tree init)
 
   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
@@ -8558,6 +8560,8 @@ convert_like_internal (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);
+	    /* 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);
@@ -13602,8 +13606,13 @@ set_up_extended_ref_temp (tree decl, tree expr, vec<tree, va_gc> **cleanups,
      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))
diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc
index 19dfb3ed782..4d5e3f53c5e 100644
--- a/gcc/cp/tree.cc
+++ b/gcc/cp/tree.cc
@@ -5045,7 +5045,14 @@ handle_no_unique_addr_attribute (tree* node,
 				 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);
diff --git a/gcc/gimplify.cc b/gcc/gimplify.cc
index d0d16a24820..bd5d0bf2bd8 100644
--- a/gcc/gimplify.cc
+++ b/gcc/gimplify.cc
@@ -5253,7 +5253,8 @@ gimplify_init_constructor (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
 	    && 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
diff --git a/gcc/testsuite/g++.dg/opt/icf1.C b/gcc/testsuite/g++.dg/opt/icf1.C
new file mode 100644
index 00000000000..fbb275e635a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/opt/icf1.C
@@ -0,0 +1,16 @@
+// 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);
+}
diff --git a/gcc/testsuite/g++.dg/opt/icf2.C b/gcc/testsuite/g++.dg/opt/icf2.C
new file mode 100644
index 00000000000..1ad48f6173d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/opt/icf2.C
@@ -0,0 +1,17 @@
+// 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());
+}
diff --git a/gcc/testsuite/g++.dg/tree-ssa/initlist-opt1.C b/gcc/testsuite/g++.dg/tree-ssa/initlist-opt1.C
index 053317b59d8..b1d2d25faf4 100644
--- a/gcc/testsuite/g++.dg/tree-ssa/initlist-opt1.C
+++ b/gcc/testsuite/g++.dg/tree-ssa/initlist-opt1.C
@@ -4,6 +4,7 @@
 
 // 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>
diff --git a/gcc/testsuite/g++.dg/tree-ssa/initlist-opt2.C b/gcc/testsuite/g++.dg/tree-ssa/initlist-opt2.C
index c20713afc6a..1e9ac739b2d 100644
--- a/gcc/testsuite/g++.dg/tree-ssa/initlist-opt2.C
+++ b/gcc/testsuite/g++.dg/tree-ssa/initlist-opt2.C
@@ -4,6 +4,8 @@
 
 // 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>
diff --git a/gcc/testsuite/g++.dg/tree-ssa/initlist-opt4.C b/gcc/testsuite/g++.dg/tree-ssa/initlist-opt4.C
new file mode 100644
index 00000000000..16e2e53c720
--- /dev/null
+++ b/gcc/testsuite/g++.dg/tree-ssa/initlist-opt4.C
@@ -0,0 +1,13 @@
+// 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);
+}
diff --git a/gcc/varasm.cc b/gcc/varasm.cc
index 9552f90f923..b66d1f86bb3 100644
--- a/gcc/varasm.cc
+++ b/gcc/varasm.cc
@@ -7032,7 +7032,7 @@ categorize_decl_for_section (const_tree decl, int reloc)
 	}
       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
