Search code examples
c++gccasserteigen3

assert() leads to maybe-uninitialized gcc warning


The following code compiles fine, with no warnings/errors:

#include <bitset>
#include <Eigen/Core>

using Array = Eigen::Array<float, -1, 1, 0, 3, 1>;

struct Tree {
  Array array;
  std::bitset<8> bitset;
};

auto func(Tree* tree) {
  int c = tree->array.rows();
  int d = tree->bitset.count();
  //assert(c==d);
  Array e(c);
  for (int k = 0; k < d; ++k) e(k) = k;
  return e.sum() / (e + 1);
}

int main() {
  Tree tree;
  func(&tree);
  return 0;
}

Compilation cmd:

g++ -O3 -Wall -I anaconda3/envs/dev/include/eigen3/ test.cpp

However, when I uncomment the assert(), I get a maybe-uninitialized warning:

In file included from anaconda3/envs/dev/include/eigen3/Eigen/Core:253,
                 from test.cpp:2:
In member function ‘Eigen::internal::scalar_sum_op<LhsScalar, RhsScalar>::result_type Eigen::internal::scalar_sum_op<LhsScalar, RhsScalar>::operator()(const LhsScalar&, const RhsScalar&) const [with LhsScalar = float; RhsScalar = float]’,
    inlined from ‘static Eigen::internal::redux_impl<Func, Evaluator, 3, 0>::Scalar Eigen::internal::redux_impl<Func, Evaluator, 3, 0>::run(const Evaluator&, const Func&, const XprType&) [with XprType = Eigen::Array<float, -1, 1, 0, 3, 1>; Func = Eigen::internal::scalar_sum_op<float, float>; Evaluator = Eigen::internal::redux_evaluator<Eigen::Array<float, -1, 1, 0, 3, 1> >]’ at anaconda3/envs/dev/include/eigen3/Eigen/src/Core/Redux.h:278:19,
    inlined from ‘typename Eigen::internal::traits<T>::Scalar Eigen::DenseBase<Derived>::redux(const Func&) const [with BinaryOp = Eigen::internal::scalar_sum_op<float, float>; Derived = Eigen::Array<float, -1, 1, 0, 3, 1>]’ at anaconda3/envs/dev/include/eigen3/Eigen/src/Core/Redux.h:418:56,
    inlined from ‘typename Eigen::internal::traits<T>::Scalar Eigen::DenseBase<Derived>::sum() const [with Derived = Eigen::Array<float, -1, 1, 0, 3, 1>]’ at anaconda3/envs/dev/include/eigen3/Eigen/src/Core/Redux.h:463:25,
    inlined from ‘auto func(Tree*)’ at test.cpp:17:15:
anaconda3/envs/dev/include/eigen3/Eigen/src/Core/functors/BinaryFunctors.h:42:122: warning: ‘((const float*)((char*)&e + offsetof(Eigen::Array, Eigen::Array<float, -1, 1, 0, 3, 1>::<unnamed>.Eigen::PlainObjectBase<Eigen::Array<float, -1, 1, 0, 3, 1> >::m_storage)))[3]’ may be used uninitialized [-Wmaybe-uninitialized]
   42 |   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE result_type operator() (const LhsScalar& a, const RhsScalar& b) const { return a + b; }
      |                                                                                                                        ~~^~~
test.cpp: In function ‘auto func(Tree*)’:
test.cpp:15:9: note: ‘e’ declared here
   15 |   Array e(c);
      |         ^

My question is this: why does the presence of the assert() affect whether or not gcc reports a maybe-uninitialized warning?

The example I show happens to use the eigen3 library, but I think my question is more general. How can the inclusion of an assert() that merely compares two int values lead to a compiler warning like this?

I want to note that this code is a minimal reproducible example for this assert-dependent-warning behavior. Removing the for-loop inside func(), for instance, makes the warning appear even without the assert. Replacing e.sum() / (e + 1) with a simpler expression like e + 1 makes the warning disappear with the assert. Replacing the std::bitset with something else also makes the warning disappear with the assert.

I am using gcc-11.3.0 and eigen-3.4.0.


Solution

  • This is apparently due to a gcc bug. The bug is present in gcc-12 or lower, and is fixed in gcc-13. A fix might be coming in gcc-12.

    Bug report: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108230