[cfe-dev] Possible invalid code accepted in constexpr functions
Kenneth Camann via cfe-dev
cfe-dev at lists.llvm.org
Thu Aug 17 04:23:53 PDT 2017
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
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-dev/attachments/20170817/d593e40d/attachment.html>
More information about the cfe-dev
mailing list