GCC warns of out-of-bounds array access only when used in a static_cast even with most of the warning options enabled.
The sample code (live):
#include <iterator>
#include <numeric>
#include <print>
int main()
{
int arr[ 5 ] { };
std::iota( std::begin( arr ), std::end( arr ), 1 );
// <no warning> -<warning>-----
std::println( "{} at address: {:p}", *(arr - 1), static_cast<const void*>(&( *(arr - 1) )) );
// <no warning> -<warning>-
std::println( "{} at address: {:p}", arr[ -1 ], static_cast<const void*>(&arr[ -1 ]) );
int* const ptr { arr + 2 };
// <no warning> -<warning>-
std::println( "{} at address: {:p}", ptr[ -3 ], static_cast<const void*>(&ptr[ -3 ]) );
}
The compiler output:
<source>: In function 'int main()':
<source>:12:54: warning: array subscript -1 is outside array bounds of 'int [5]' [-Warray-bounds=]
12 | std::println( "{} at address: {:p}", *(arr - 1), static_cast<const void*>(&( *(arr - 1) )) );
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
<source>:8:9: note: at offset -4 into object 'arr' of size 20
8 | int arr[ 5 ] { };
| ^~~
<source>:14:78: warning: array subscript -1 is below array bounds of 'int [5]' [-Warray-bounds=]
14 | std::println( "{} at address: {:p}", arr[ -1 ], static_cast<const void*>(&arr[ -1 ]) );
| ^~~~~~~~~~
<source>:8:9: note: while referencing 'arr'
8 | int arr[ 5 ] { };
| ^~~
<source>:18:53: warning: array subscript -1 is outside array bounds of 'int [5]' [-Warray-bounds=]
18 | std::println( "{} at address: {:p}", ptr[ -3 ], static_cast<const void*>(&ptr[ -3 ]) );
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
<source>:8:9: note: at offset -4 into object 'arr' of size 20
8 | int arr[ 5 ] { };
| ^~~
For instance, I naturally expect to see a warning for *(arr - 1) too. But apparently, only the expressions in the static_casts (e.g. &( *(arr - 1) )) are pedantically checked for the presence of invalid accesses.
Is this a bug in GCC? Because the code is pretty trivial and explicit. I expect a compiler to display warnings at least in such simple scenarios.
Note: Clang is even worse and only warns about arr[ -1 ].
These warnings you will only occur when optimisation is enabled. The abstract interpretation that occurs in the optimiser allow it to detect some potential runtime errors at compile time. They are opportunistic warnings enabled by the way the optimiser works - you cannot expect the same results across all compilers, or even at different optimisation settings.
In this case you are passing the expressions as variadic arguments so although you have cast to a const pointer,
println()makes no promises to respect that - the variadic arguments have no specific type defined compile time. So the compiler sees that you are passing a const pointer with no idea how the receiving function is going to use it, so there is a potential for an out of bounds write access.It is not the
static_castthat causes this, it is the taking of address&. The cast is necessary to comply with the format specifier. I suspect if the compiler were not format specifier aware (which it need not be), you would get the warning without the cast.In the case of the expression
*(arr-1)that is a read access and pass by value (not a pointer) and although you may not get a useful result, you are not modifying the out-of-bounds location, so there is noting to warn about.You can simplify the test to demonstrate the behaviour is nothing to do with the static cast and everything to do with writing or potentially writing out-of-bounds using the following expressions: