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

--- Comment #2 from Jonathan Wakely <redi at gcc dot gnu.org> ---
If you make everything constexpr then Clang will correctly diagnose the UB, but
GCC fails to:

constexpr int IntSize() { return sizeof(int); }

#include <cassert>

// -

template<typename T>
class Maybe {
    bool mIsSome = false;
    T mVal = {};

public:
    Maybe() = default;
    constexpr Maybe(const T& rhs) : mIsSome(true), mVal(rhs) {}

    constexpr T& operator*() {
        assert(mIsSome);
        return mVal;
    }
};

// -

struct Int {
    int val = {};

    Int() = default;
    constexpr Int(int x) : val(x) {}
};

struct Even : public Int {
public:
    constexpr static Maybe<Even> From(const Int x) {
        if (x.val & 1) return {};
        return Even{x.val};
    }

    Even() = default;
private:
    constexpr Even(int x) : Int(x) {
        assert((val & 1) == 0);
    }
};

constexpr 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?
}

int main()
{
    constexpr int i = Oops({});
}

GCC should not compile this.

Reply via email to