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:
-
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.
-
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