[Bug c++/98665] lvalue ref lifetime extension missing for via sub-object of temporary expression

2021-01-13 Thread jgilbert at mozilla dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=98665

Jeff Gilbert  changed:

   What|Removed |Added

 Status|UNCONFIRMED |RESOLVED
 Resolution|--- |INVALID

--- Comment #5 from Jeff Gilbert  ---
Thanks for the clarification!

[Bug c++/98665] lvalue ref lifetime extension missing for via sub-object of temporary expression

2021-01-13 Thread jgilbert at mozilla dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=98665

--- Comment #3 from Jeff Gilbert  ---
Ok, but this is ok, right?

const auto& i2 = f().i;

[Bug c++/98665] New: lvalue ref lifetime extension missing for via sub-object of temporary expression

2021-01-13 Thread jgilbert at mozilla dot com via Gcc-bugs
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?
> }