In an attempt to get a better understand of how pointer aliasing invariants manifested during optimization, I plugged some code into the renowned Compiler Explorer, which I'll repeat here:
#include <cstring>
bool a(int *foo, int *bar) {
(void) *foo, (void) *bar;
return foo == bar;
}
bool b(int *foo, float *bar) {
(void) *foo, (void) *bar;
return foo == reinterpret_cast<int *>(bar);
}
bool c(int *foo, int *bar) {
(void) *foo, (void) *bar;
// It's undefined behavior for memcpyed memory ranges to overlap (i.e. alias)
std::memcpy(foo, bar, sizeof(int));
return foo == bar;
}
bool d(int *__restrict foo, int *__restrict bar) {
(void) *foo, (void) *bar;
return foo == bar;
}
Neither the current versions of Clang nor GCC compile any of these functions to always return false
, so my question is then which of these functions, while still complying with the C++ standard, could have been compiled to always return false
? My (very limited) understanding says b
, c
, and d
should all be optimizable in that manner, but I'm not confident (I also recognize that __restrict
isn't in the standard, but pretending that it was with the semantics it's defined to have under either compiler).
Update
I've included dereferences of both pointers in the top of each function (so that they cannot be nullptr
), and made the std::memcpy
invocation actually copy one instance of int
.
Update 2
Added a comment explaining my intent with the std::memcpy
.
b()
can't, it's perfectly legal for both parameters to benullptr
without any strict aliasing violation. – Minutes__restrict__
is ignored in function definition matching. This means you only need to specify__restrict__
in a function definition, rather than in a function prototype as well." and that pretty much wipes out any ability to deduce inequality at a call site (c()
) – Minutes(void)*foo
(added in an edit) forces that conversion. – Minutes(void)*foo
? – Astralstatic_cast
. Astatic_cast
tovoid
is a discarded-value expression A discarded-value expression involving indirection forces an lvalue-to-rvalue conversion only if it is alsovolatile
So there is no lvalue-to-rvalue conversion here, one needs(void)*(volatile int*)foo
. – Minutes&*x
is equivalent withx
. – Dandiprat