在GCC没有的情况下,Clang会产生非法指令

时间:2014-08-05 20:23:29

标签: c++ clang

我发现Clang产生非法指令的情况,gcc没有, 在尝试this问题时。

我的问题是:我做错了什么,或者这是Clang的实际问题?

我把它归结为重现问题所需的最小片段。

取档eigen.cpp

#include <iostream>

#define EIGEN_MATRIXBASE_PLUGIN "eigen_matrix_addons.hpp"
#include <Eigen/Dense>

int main() {
    Eigen::Matrix2d A;

    A << 0, 1, 2, 3;

    std::cout << A << "\n";
}

文件eigen_matrix_addons.hpp

friend std::ostream &operator<<(std::ostream &o, const Derived &m) {
    o << static_cast<const MatrixBase<Derived> &>(m);
}

(有关此文件的详细说明,请参阅here。简而言之,其内容直接放在template<class Derived> class MatrixBase;的类定义中。因此,这会在{{1}上引入另一个ostream运算符。调用Derived上的ostream运算符的Eigen实现。如果你阅读this question,这个动机就变得明显了。)

使用GCC编译并运行:

MatrixBase<Derived>

然后用Clang编译并运行:

$ g++ -std=c++11 -Wall -Wextra -pedantic -isystem/usr/include/eigen3 -I. -o eigen_gcc eigen.cpp
$ ./eigen_gcc
0 1
2 3
$ g++ --version
g++ (SUSE Linux) 4.8.1 20130909 [gcc-4_8-branch revision 202388]
Copyright (C) 2013 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

如您所见,执行非法指令后程序被中断。 gdb中的反向跟踪显示问题发生在$ clang++ -std=c++11 -Wall -Wextra -pedantic -isystem/usr/include/eigen3 -I. -o eigen_clang eigen.cpp $ ./eigen_clang 0 1 Illegal instruction $ clang++ --version clang version 3.4 (branches/release_34 198681) Target: x86_64-suse-linux Thread model: posix 的第二行:

eigen_matrix_addons.hpp

即。可能是(gdb) bt #0 0x00000000004013e1 in Eigen::operator<< (o=..., m=...) at ./eigen_matrix_addons.hpp:2 #1 0x00000000004010f0 in main () at eigen.cpp:15

根据static_cast,我的Eigen版本是3.2.0-2.1.4。

修改

@Mysticial要求的解散:

zypper

2 个答案:

答案 0 :(得分:24)

&#34;非法指令&#34;错误可能是因为您的&#34;运营商&lt;&lt;&#34;缺少一份退货声明。这导致了不确定的行为。

标准第6.6.3节说:

  

离开函数末尾相当于返回   没有价值;这会导致值返回函数中的未定义行为。

你应该添加:

return o;

在功能结束时。

答案 1 :(得分:2)

我使用谷歌的单元测试遇到了同样的事情。 我有一个模拟函数,其默认返回值设置为

ON_CALL(...).WillByDefault(Return(...));

然后在期待中我使用了SetArgReferee,如

EXPECT_CALL(...).WillOnce(SetArgReferee<...>(...))

clang在一些相同的期望中插入了一个ud2和SetArgReferee函数,但并不是所有这些。将其更正为

EXPECT_CALL(...).WillOnce(
    DoAll(
        SetArgReferee<...>(...),
        Return(...)));

修好了。