Search code examples
c++language-lawyer

UB status of initializing a reference to last+1 array element?


The following code compiles in GCC, CLANG, and MSVC. It initializes the int ir to refer to the non-existent a[1] which is one beyond the end of a.

consteval int foo()
{
    int a[1]{ 42 };
    int& ir = a[1];
    return *(&ir-1);
}

int main()
{
    constexpr int ci=foo();
    return ci;
}

This compiles in spite of the core constant expression evaluation seeming to contain UB. See this which contains "A reference shall be initialized to refer to a valid object or function."

A more recent n4950 draft removes this language.

Is this no longer UB?


Solution

  • CWG453 made the change to the working draft that you observed. It is closely related to CWG2823, which was approved a few months before CWG453, and addressed the issue of whether it's UB to dereference a null pointer or a past-the-end pointer.

    CWG2823 is what makes it clear that your code is invalid. The expression a[1] is equivalent to *(a + 1), and a + 1 is a past-the-end pointer. Because a + 1 does not point to an object, applying the * operator to it violates [expr.unary.op]/1 (as amended by CWG2823). This is UB at runtime, and a diagnosable error at compile time (but as you say, compilers haven't yet caught up). We never actually reach the question of whether or not the reference binding is valid.

    CWG453 was concerned about what it means for an object to be "valid" for the purposes of reference binding; this was never clear in the previous wording. Note that once CWG2823 was resolved, it was no longer necessary to ask the question of whether a reference is allowed to bind to a "null glvalue" or a "past-the-end glvalue" because it would always be invalid to produce such a glvalue in the first place. The only remaining issue was to address the case where (e.g. due to reinterpret_cast shenanigans) a program attempts to bind a reference to an object of the wrong type. This was made UB in most cases and the unclear "valid object or function" text was removed.