https://gcc.gnu.org/g:b4f66a79e0c9b65d78aed6c982bdcff48ed098d5

commit r14-11347-gb4f66a79e0c9b65d78aed6c982bdcff48ed098d5
Author: Jason Merrill <ja...@redhat.com>
Date:   Mon Jan 27 18:30:18 2025 -0500

    c++: init-list opt and lvalue initializers [PR118673]
    
    When fn returns {extension}, the ArrayRef in the initializer_list is
    constructed to point to 'extension', the variable with static storage
    duration.  The optimization was copying extension's value into a temporary
    array and constructing the ArrayRef to point to that temporary copy instead,
    resulting in a dangling pointer.  So suppress this optimization if the
    element constructor takes a reference and the initializer is a non-mergeable
    lvalue.
    
            PR c++/118673
    
    gcc/cp/ChangeLog:
    
            * call.cc (maybe_init_list_as_array): Check for lvalue
            initializers.
            * cp-tree.h (enum cp_lvalue_kind_flags): Add clk_mergeable.
            * tree.cc (lvalue_kind): Return it.
            (non_mergeable_glvalue_p): New.
            (test_lvalue_kind): Adjust.
    
    gcc/testsuite/ChangeLog:
    
            * g++.dg/cpp0x/initlist-opt6.C: New test.

Diff:
---
 gcc/cp/cp-tree.h                           |  4 +++-
 gcc/cp/call.cc                             |  9 +++++++++
 gcc/cp/tree.cc                             | 21 +++++++++++++++++++--
 gcc/testsuite/g++.dg/cpp0x/initlist-opt6.C | 26 ++++++++++++++++++++++++++
 4 files changed, 57 insertions(+), 3 deletions(-)

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index a9a4a7abc40d..a9a14d6267c8 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -5582,7 +5582,8 @@ enum cp_lvalue_kind_flags {
   clk_class = 4,    /* A prvalue of class or array type.  */
   clk_bitfield = 8, /* An lvalue for a bit-field.  */
   clk_packed = 16,  /* An lvalue for a packed field.  */
-  clk_implicit_rval = 1<<5 /* An lvalue being treated as an xvalue.  */
+  clk_implicit_rval = 1<<5, /* An lvalue being treated as an xvalue.  */
+  clk_mergeable = 1<<6
 };
 
 /* This type is used for parameters and variables which hold
@@ -8035,6 +8036,7 @@ extern bool glvalue_p                             
(const_tree);
 extern bool obvalue_p                          (const_tree);
 extern bool xvalue_p                           (const_tree);
 extern bool bitfield_p                         (const_tree);
+extern bool non_mergeable_glvalue_p            (const_tree);
 extern tree cp_stabilize_reference             (tree);
 extern bool builtin_valid_in_constant_expr_p    (const_tree);
 extern tree build_min                          (enum tree_code, tree, ...);
diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc
index 1609a64c3fa6..bb376d9cb136 100644
--- a/gcc/cp/call.cc
+++ b/gcc/cp/call.cc
@@ -4331,6 +4331,15 @@ maybe_init_list_as_array (tree elttype, tree init)
     /* Let the normal code give the error.  */
     return NULL_TREE;
 
+  /* A glvalue initializer might be significant to a reference constructor
+     or conversion operator.  */
+  if (!DECL_CONSTRUCTOR_P (c->cand->fn)
+      || (TYPE_REF_P (TREE_VALUE
+                     (FUNCTION_FIRST_USER_PARMTYPE (c->cand->fn)))))
+    for (auto &ce : CONSTRUCTOR_ELTS (init))
+      if (non_mergeable_glvalue_p (ce.value))
+       return NULL_TREE;
+
   tree first = CONSTRUCTOR_ELT (init, 0)->value;
   conversion *fc = implicit_conversion (elttype, init_elttype, first, false,
                                        LOOKUP_IMPLICIT|LOOKUP_NO_NARROWING,
diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc
index 01e6c1cb892c..b37d4605e06c 100644
--- a/gcc/cp/tree.cc
+++ b/gcc/cp/tree.cc
@@ -191,6 +191,8 @@ lvalue_kind (const_tree ref)
       return op1_lvalue_kind;
 
     case STRING_CST:
+      return clk_ordinary | clk_mergeable;
+
     case COMPOUND_LITERAL_EXPR:
       return clk_ordinary;
 
@@ -210,6 +212,10 @@ lvalue_kind (const_tree ref)
          && DECL_LANG_SPECIFIC (ref)
          && DECL_IN_AGGR_P (ref))
        return clk_none;
+
+      if (DECL_MERGEABLE (ref))
+       return clk_ordinary | clk_mergeable;
+
       /* FALLTHRU */
     case INDIRECT_REF:
     case ARROW_EXPR:
@@ -407,6 +413,17 @@ bitfield_p (const_tree ref)
   return (lvalue_kind (ref) & clk_bitfield);
 }
 
+/* True if REF is a glvalue with a unique address, excluding mergeable glvalues
+   such as string constants.  */
+
+bool
+non_mergeable_glvalue_p (const_tree ref)
+{
+  auto kind = lvalue_kind (ref);
+  return (kind != clk_none
+         && !(kind & (clk_class|clk_mergeable)));
+}
+
 /* C++-specific version of stabilize_reference.  */
 
 tree
@@ -6353,11 +6370,11 @@ test_lvalue_kind ()
   tree string_lit = build_string (4, "foo");
   TREE_TYPE (string_lit) = char_array_type_node;
   string_lit = fix_string_type (string_lit);
-  ASSERT_EQ (clk_ordinary, lvalue_kind (string_lit));
+  ASSERT_EQ (clk_ordinary|clk_mergeable, lvalue_kind (string_lit));
 
   tree wrapped_string_lit = maybe_wrap_with_location (string_lit, loc);
   ASSERT_TRUE (location_wrapper_p (wrapped_string_lit));
-  ASSERT_EQ (clk_ordinary, lvalue_kind (wrapped_string_lit));
+  ASSERT_EQ (clk_ordinary|clk_mergeable, lvalue_kind (wrapped_string_lit));
 
   tree parm = build_decl (UNKNOWN_LOCATION, PARM_DECL,
                          get_identifier ("some_parm"),
diff --git a/gcc/testsuite/g++.dg/cpp0x/initlist-opt6.C 
b/gcc/testsuite/g++.dg/cpp0x/initlist-opt6.C
new file mode 100644
index 000000000000..80192892b8a5
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/initlist-opt6.C
@@ -0,0 +1,26 @@
+// PR c++/118673
+// { dg-do run { target c++11 } }
+
+#include <initializer_list>
+
+struct ArrayRef {
+  const int *Data = nullptr;
+  ArrayRef(const int &OneElt) : Data(&OneElt) {}
+};
+
+struct Vec
+{
+  ArrayRef Elts[1];
+  Vec(std::initializer_list<ArrayRef> IL)
+    : Elts{*IL.begin()}
+    {  }
+};
+
+[[gnu::noinline]] Vec fn() {
+  static const auto extension = 42;
+  return {extension};
+}
+int main() {
+  auto t = fn();
+  if (t.Elts[0].Data[0] != 42) __builtin_abort();
+}

Reply via email to