diff options
author | Jason Merrill <jason@redhat.com> | 2025-01-27 18:30:18 -0500 |
---|---|---|
committer | Jason Merrill <jason@redhat.com> | 2025-01-28 12:31:00 -0500 |
commit | d0f230adf0e888d9218a123ac620c9a5b3020c2d (patch) | |
tree | c657de3ee932d57a8fa58104c29ede7305be9674 /gcc | |
parent | 0204dcf930b5093d0811a007b7f47aa42e55e787 (diff) | |
download | gcc-d0f230adf0e888d9218a123ac620c9a5b3020c2d.zip gcc-d0f230adf0e888d9218a123ac620c9a5b3020c2d.tar.gz gcc-d0f230adf0e888d9218a123ac620c9a5b3020c2d.tar.bz2 |
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.
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/cp/call.cc | 9 | ||||
-rw-r--r-- | gcc/cp/cp-tree.h | 4 | ||||
-rw-r--r-- | gcc/cp/tree.cc | 21 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp0x/initlist-opt6.C | 26 |
4 files changed, 57 insertions, 3 deletions
diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc index 469af83..3a56a82 100644 --- a/gcc/cp/call.cc +++ b/gcc/cp/call.cc @@ -4374,6 +4374,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/cp-tree.h b/gcc/cp/cp-tree.h index 7bf9557..21011d0b 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -5679,7 +5679,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 @@ -8191,6 +8192,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/tree.cc b/gcc/cp/tree.cc index e35432f..fb6b2b1 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 @@ -6495,11 +6512,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 0000000..8019289 --- /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(); +} |