https://gcc.gnu.org/bugzilla/show_bug.cgi?id=98665
Bug ID: 98665
Summary: lvalue ref lifetime extension missing for via
sub-object of temporary expression
Product: gcc
Version: unknown
Status: UNCONFIRMED
Keywords: wrong-code
Severity: normal
Priority: P3
Component: c++
Assignee: unassigned at gcc dot gnu.org
Reporter: jgilbert at mozilla dot com
Target Milestone: ---
This is like bug 81420.
Taking an lvalue ref of a sub-object expression should extend the lifetimes of
the needed sub-objects to the lifetime of the lvalue ref.
I believe that apples to this case, and clang and msvc seem to compile it that
way. (which doesn't mean it's not UB, of course)
It's possible that this example is past some complexity limit where the lvalue
ref rule becomes impossible to handle, but this seems suspect enough
(especially given bug 81420 which we've had trouble with before) that I'm
filing this bug.
In the example below, GCC compile Oops() into `return 9`:
https://godbolt.org/z/MYPhaW
> #include
>
> // -
>
> template
> class Maybe {
> bool mIsSome = false;
> T mVal = {};
>
> public:
> Maybe() = default;
> Maybe(const T& rhs) : mIsSome(true), mVal(rhs) {}
>
> T& operator*() {
> assert(mIsSome);
> return mVal;
> }
> };
>
> // -
>
> struct Int {
> int val = {};
>
> Int() = default;
> Int(int x) : val(x) {}
> };
>
> struct Even : public Int {
> public:
> static Maybe From(const Int x) {
> if (x.val & 1) return {};
> return Even{x.val};
> }
>
> Even() = default;
> private:
> Even(int x) : Int(x) {
> assert((val & 1) == 0);
> }
> };
>
> // -
>
> int Oops(const Int i) {
> const auto& e = *Even::From(i); // lvalue ref lifetime extension of
> sub-object
> // of temporary?
> return e.val + 9; // or UB access?
> }