https://gcc.gnu.org/bugzilla/show_bug.cgi?id=126312

            Bug ID: 126312
           Summary: Bad ARM64 codegen: mandatory copy elision not enforced
                    creates dangling reference
           Product: gcc
           Version: 16.1.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: middle-end
          Assignee: unassigned at gcc dot gnu.org
          Reporter: gufideg at gmail dot com
  Target Milestone: ---

When returning from a function that returns by value using copy elision, it
seems GCC does not enforce copy elision and do copy the object.

    struct val_ref {
        constexpr val_ref() : val(42), ref(val) {}
        val_ref(val_ref&&) = delete;
        val_ref(val_ref const&) = delete;
        int val;
        int& ref;
    };

    struct wrapper {
        constexpr wrapper(): impl{} {}
        val_ref impl{};
    };

    constexpr auto make_s() {
        return wrapper{};
    }

    constexpr int test() {
        auto s = make_s();
        return s.impl.ref;
    }

I tagged it "middle-end" since bad code generation is possible, but it seems
like it's also a front end issue since the constexpr evaluator (on ARM64 only)
will reject the valid code.
    //static_assert(test());

    int main() {
        return test() == 42 ? 0 : 1;
    }

This self referential struct is immovable, yet the ARM64 codegen read garbage
bytes.

Uncommenting the static assert, the compiler will refuse to execute the code
claiming `s.impl.ref` is read outside of its lifetime, even though the object
is still alive at this point.

Strangely, this only happen on ARM64. x86-64 and ARM 32 bit compile this code
correctly, and does not diagnose the static assert. 

Compiler explorer link: https://godbolt.org/z/7hnbh94b5

Reply via email to