Using pointer graphs in constexpr functions

Viewed 155

I'm trying to wrap my head around constexpr rules as they relate to pointers, contained within constexpr data structures, which reference other parts of that constexpr data structure.

Consider the following code fragment:

struct selfref{
    selfref *next{nullptr};
};

struct exec{
    selfref mem[1] = {selfref{}};
    constexpr exec(){
    mem[0].next = &mem[0];
    }
};

If I attempt to instantiate exec as a constexpr local, I can follow pointers from it:

int main(){
    static constexpr exec ret;
    static constexpr selfref *ptr = ret.mem[0].next;
}

But if I instead return it from a trivial function and change nothing else:

constexpr exec do_thing(){
    return exec{};
}

int main(){
    static constexpr auto ret = do_thing();
    static constexpr selfref *ptr = ret.mem[0].next;
}

I suddenly get an error with g++-11 and g++-12:

minimal-interesting-example2.cpp: In function ‘int main()’:
minimal-interesting-example2.cpp:18:42: error: ‘exec{selfref [1]{selfref{(&<anonymous>.exec::mem[0])}}}’ is not a constant expression
   18 |     static constexpr auto ret = do_thing();
      |            

But not with clang++-13. Demo

Which compiler is right? And regardless of that answer, what's going on here???

EDIT: It looks like GCC at least thinks that this code should work according to this bug report: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=64989#c8. I would still be very interested to hear if there's someone with the standard in their head who is able to confirm that this should work!

0 Answers
Related