Why does returning an element of a copied Matrix3d result in incorrect output when using Clang 3.9?

Viewed 118

Compiling the following example with -O2 on Clang 3.9 results in the reproFunction returning garbage (1.9038e+185) when called in main:

Code

double reproFunction(const Eigen::Matrix3d& R_in)
{
  const Eigen::Matrix3d R = R_in;

  Eigen::Matrix3d Q = R.cwiseAbs();

  if(R(1,2) < 2) {
    Eigen::Vector3d n{0, 1, R(1, 2)};
    double s2 = R(1,2);
    s2 /= n.norm();
  }
  return R(1, 2);
}

int main() {
  Eigen::Matrix3d R;
  R = Eigen::Matrix3d::Zero(3,3); 

  // This fails - reproFunction(R) returns 0
  R(1, 2) = 0.7;
  double R12 = reproFunction(R);
  bool are_they_equal = (R12 == R(1,2));
  std::cout << "R12 == R(1,2): " << are_they_equal << std::endl;
  std::cout << "R12: " << R12 << std::endl;
  std::cout << "R(1, 2): " << R(1, 2) << std::endl;
}

Output

R12 == R(1,2): 0
R12: 1.9036e+185
R(1, 2): 0.7

reproFunction, initializes R (which is const) by assignment from R_in. It returns R(1, 2). Between the assignment and the return, reproFunction uses R in several operations, but none of them should be able to change R. Removing any of those operations results in reproFunction returning the correct value.

This behavior does not appear in any of the following cases:

  • The program is compiled with Clang 3.5, Clang 4.0,or g++-5.4.
  • The optimization level is -O1 or lower
  • Eigen 3.2.10 is used instead of Eigen 3.3.3

Now the question: Is this behavior due to a bug I've missed in the code above, a bug in Eigen 3.3.3, or a bug in Clang 3.9?

A self-contained reproduction example can be found at https://github.com/avalenzu/eigen-clang-weirdness.

1 Answers
Related