Possible invalid code accepted in constexpr functions

Hi all,

I found some cases where clang accepts some invalid code. To give some context, here is what I was trying to do:

Given a pointer to a member subobject that I know lives inside an object of class type S, I would like to get a pointer to the enclosing S in a constexpr function. This seems like a reasonable thing to want to do, but I could not think of a way to do it that is standard-conforming, and the ways I did think of have the problems described below.

clang currently allows expressions in constexpr contexts that are explicitly excluded from being core constantant expressions in [expr.const] item (2.13) – i.e., “a conversion from type cv void * to a pointer-to-object type” cannot be a core constant expression.

gcc allows these too, and is actually far more liberal in what it accepts (it will accept a reinterpret_cast in a constexpr function). They track this as a bug although some code in libstdc++ apparently relies on it: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=49171

It seems that clang never allows a reinterpret_cast in constexpr function, but sometimes accepts a sneaky equivalent, i.e. this trick:

static_cast<char *>(static_cast<void *>(&x)) [and then back again]

But whether it accepts this or not seems random. The following compiles with clang 4.0:

struct S {
int a;
int b;
};

constexpr S *getS(int *pb) { // Note: pb is a pointer to a b inside S
char *pbC = static_cast<char *>(static_cast<void *>(pb)) -
__builtin_offsetof(S, b);
return static_cast<S *>(static_cast<void *>(pbC));
};

But the following does not compile:

constexpr S *getS(int *pb) {
int S::*memb = &S::b;

// Try to do something like the offsetof stuff above,
// but by deriving the offset from a member pointer
const auto pdiff = static_cast<char *>(static_cast<void *>(
&(static_cast(nullptr)->*memb))) - static_cast<char *>(nullptr);

char *pbC = static_cast<char *>(static_cast<void *>(pb)) - pdiff;
return static_cast<S *>(static_cast<void *>(pbC));
}

error: constexpr function never produces a constant expression

note: cast from ‘void *’ is not allowed in a constant expression

I could probably dig through libclangSema to find out why this is, but what I’m after is a bit more high level:

  1. Like the gcc guys, is there some reason (maybe specifically related to offsetof magic?) that you want to accept certain forms of this trick, or do you consider it a bug? I’m willing to rely on UB, but not a bug.

  2. There was a proposal I found on github to allow “limited reinterpret_cast” in constexpr (http://apolukhin.github.io/constexpr_algorithms/reinterpret.html) but it was never mailed out. Since many you of are involved with WG21: is this an issue anyone is interesting in pursuing, i.e., "“reasonable” limited use of casting for doing simple pointer math against the structure layout?

Thanks for your help,
Ken

Did you try actually calling getS in a context that requires a constant expression? The “constexpr function never produces a constant expression” diagnostic is strictly best-effort.