https://gcc.gnu.org/bugzilla/show_bug.cgi?id=117067
Bug ID: 117067 Summary: false warning: array subscript 'int (**)(...)[ 0]' is partly outside array bounds Product: gcc Version: 13.3.1 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: lobel.krivic at proton dot me Target Milestone: --- The following source code: ``` #include <cstddef> #include <functional> #include <type_traits> #include <utility> #include <iostream> /////////////////////////////////////////////////////// template <typename... Args> class VTable { public: virtual void func(Args...) = 0; virtual ~VTable() = default; }; template <typename T, typename... Args> class Handler final : public VTable<Args...> { private: T* _ptr; public: template <typename... CArgs> Handler(CArgs&&... args) noexcept { _ptr = new T(std::forward<CArgs>(args)...); } virtual void func(Args... args) final { return std::invoke(*_ptr, std::forward<Args>(args)...); } ~Handler() final { delete _ptr; } }; /////////////////////////////////////////////////////// template <typename... Args> struct F { using V = VTable<Args...>; static constexpr int S = sizeof(void*) + sizeof(V); std::byte _data[S]; template <typename T> F(T&& t) { static_assert(sizeof(Handler<std::decay_t<T>, Args...>) <= S); ::new (&_data[0]) Handler<std::decay_t<T>, Args...>(std::forward<T>(t)); } void func(Args... args) { std::cout << "" << std::endl; // removing this line removes the warning! V& tmp = *static_cast<V*>(static_cast<void*>(&_data[0])); return tmp.func(std::forward<Args>(args)...); } ~F() { static_cast<V*>(static_cast<void*>(&_data[0]))->~V(); } }; /////////////////////////////////////////////////////// struct Testor { // long y; // this removes the warning! Testor() = default; ~Testor() = default; void memfunc(int x) { std::cout << x << std::endl; } }; /////////////////////////////////////////////////////// // warning: array subscript 'int (**)(...)[0]' is partly outside array bounds of 'Testor [1]' [-Warray-bounds=] // this happens for -O2/O3 -Wall (but not for -O0/-O1) int main() { Testor testor_small; F<Testor&, int> f{&Testor::memfunc}; f.func(testor_small, 42); return 0; } ``` produces a probably false warning: ``` In file included from /usr/lib/gcc/x86_64-pc-linux-gnu/13/include/g++-v13/tuple:41, from /usr/lib/gcc/x86_64-pc-linux-gnu/13/include/g++-v13/functional:53, from ./bug.cpp:2: In function 'constexpr _Res std::__invoke_impl(__invoke_memfun_ref, _MemFun&&, _Tp&&, _Args&& ...) [with _Res = v oid; _MemFun = void (Testor::*&)(int); _Tp = Testor&; _Args = {int}]', inlined from 'constexpr typename std::__invoke_result<_Functor, _ArgTypes>::type std::__invoke(_Callable&&, _ Args&& ...) [with _Callable = void (Testor::*&)(int); _Args = {Testor&, int}]' at /usr/lib/gcc/x86_64-pc-linux-gn u/13/include/g++-v13/bits/invoke.h:96:40, inlined from 'std::invoke_result_t<_Callable, _Args ...> std::invoke(_Callable&&, _Args&& ...) [with _Callabl e = void (Testor::*&)(int); _Args = {Testor&, int}]' at /usr/lib/gcc/x86_64-pc-linux-gnu/13/include/g++-v13/funct ional:113:27, inlined from 'void Handler<T, Args>::func(Args ...) [with T = void (Testor::*)(int); Args = {Testor&, int}]' at ./bug.cpp:31:21, inlined from 'void F<Args>::func(Args ...) [with Args = {Testor&, int}]' at ./bug.cpp:57:18, inlined from 'int main()' at ./bug.cpp:84:8: /usr/lib/gcc/x86_64-pc-linux-gnu/13/include/g++-v13/bits/invoke.h:67:39: warning: array subscript 'int (**)(...)[ 0]' is partly outside array bounds of 'Testor [1]' [-Warray-bounds=] 67 | { return (__invfwd<_Tp>(__t).*__f)(std::forward<_Args>(__args)...); } | ~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ./bug.cpp: In function 'int main()': ./bug.cpp:82:16: note: object 'testor_small' of size 1 82 | Testor testor_small; | ^~~~~~~~~~~~ ``` when compiled with `O2` or `O3` and `Wall`, but not when compiled with `O0` or `O1`. Also, `-fsanitize=undefined` removes the warning for `O2`, but not for `O3`. All gcc versions prior to 12.1 do not emit any warnings. Clang does not emit any warnings. Here is the link to the source code: https://gcc.godbolt.org/z/WsfdsGb7M The complete command line that triggers the bug: `g++ -O2 -Wall ./bug.cpp` Bug reports that may be related: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=106247 https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105523 Output of `gcc -v`: Using built-in specs. COLLECT_GCC=gcc COLLECT_LTO_WRAPPER=/usr/libexec/gcc/x86_64-pc-linux-gnu/13/lto-wrapper Target: x86_64-pc-linux-gnu Configured with: /var/tmp/portage/sys-devel/gcc-13.3.1_p20240614/work/gcc-13-20240614/configure --host=x86_64-pc- linux-gnu --build=x86_64-pc-linux-gnu --prefix=/usr --bindir=/usr/x86_64-pc-linux-gnu/gcc-bin/13 --includedir=/us r/lib/gcc/x86_64-pc-linux-gnu/13/include --datadir=/usr/share/gcc-data/x86_64-pc-linux-gnu/13 --mandir=/usr/share /gcc-data/x86_64-pc-linux-gnu/13/man --infodir=/usr/share/gcc-data/x86_64-pc-linux-gnu/13/info --with-gxx-include -dir=/usr/lib/gcc/x86_64-pc-linux-gnu/13/include/g++-v13 --disable-silent-rules --disable-dependency-tracking --w ith-python-dir=/share/gcc-data/x86_64-pc-linux-gnu/13/python --enable-languages=c,c++,fortran --enable-obsolete - -enable-secureplt --disable-werror --with-system-zlib --disable-nls --disable-libunwind-exceptions --enable-check ing=release --with-bugurl=https://bugs.gentoo.org/ --with-pkgversion='Gentoo 13.3.1_p20240614 p17' --with-gcc-maj or-version-only --enable-libstdcxx-time --enable-lto --disable-libstdcxx-pch --enable-shared --enable-threads=pos ix --enable-__cxa_atexit --enable-clocale=gnu --disable-multilib --with-multilib-list=m64 --disable-fixed-point - -enable-targets=all --enable-libgomp --disable-libssp --disable-libada --enable-cet --disable-systemtap --disable -valgrind-annotations --disable-vtable-verify --disable-libvtv --with-zstd --without-isl --enable-default-pie --e nable-default-ssp --disable-fixincludes --with-build-config=bootstrap-cet Thread model: posix Supported LTO compression algorithms: zlib zstd gcc version 13.3.1 20240614 (Gentoo 13.3.1_p20240614 p17)