当constexpr在union中初始化struct时,msvc visual c ++ silent生成错误的代码

时间:2016-12-21 19:53:14

标签: c++ visual-c++ visual-studio-2015 constexpr compiler-bug

考虑下面的片段,以说明问题:

#include <cstdio>

struct A {
    union {
        struct { int a0, a1; } aa;
        int bb[2];
    };
#if 1 //bug
    constexpr A(int a0, int a1) : aa{a0, a1} {}
#else //OK
    constexpr A(int a0, int a1) : bb{a0, a1} {}
#endif
};
int main() {
                     A t0{2, 3}; std::printf("%d %d\n", t0.aa.a0, t0.aa.a1); //2 3 (OK)
    static           A t1{2, 3}; std::printf("%d %d\n", t1.aa.a0, t1.aa.a1); //2 3 (OK)
           constexpr A t2{2, 3}; std::printf("%d %d\n", t2.aa.a0, t2.aa.a1); //2 3 (OK)
    static constexpr A t3{2, 3}; std::printf("%d %d\n", t3.aa.a0, t3.aa.a1); //0 0 (??)
}

msvc 2015更新3和2017 rc1 通过零初始化t3而不是使用给定值正确初始化来静默生成错误代码。 gcc和clang很好。

我研究报告了一个错误,但这太麻烦了(我不使用IDE)。如果您在意,请确认这是一个错误,并告知微软可能关注谁。

1 个答案:

答案 0 :(得分:2)

我可以在VS 2015上使用x86-32和x86-64编译器重现这一点。

我还可以确认当前版本的GCC,Clang和ICC正确编译它。我也无法在禁止您正在做的事情的语言标准中找到任何内容。无论是在编译时(如您所期望的那样)还是在运行时初始化对象,都允许实现一些余地,但MSVC根本不对其进行初始化。

正如可能预期的那样,当对象的声明被移动到命名空间范围时,会出现同样的问题,例如

$scope.filepath = function () {
            console.log($scope.mdphoto);
        }

...以及如果对象被声明为其他空结构的静态成员。

虽然可见效果是零初始化,但实际上并不是编译器正在做的事情。相反,它在相应的数据段中根本无法发出值,因此当代码在调用#include <cstdio> struct A { union { struct { int a0, a1; } aa; int bb[2]; }; constexpr A(int a0, int a1) : aa{a0, a1} { } }; namespace { constexpr A t3 { 2, 3 }; }; int main() { std::printf("%d %d\n", t3.aa.a0, t3.aa.a1); } 时尝试从该地址加载一个值以推送到堆栈时,它最终会推送零

似乎这里printf是重现错误的关键。如果union仅包含结构A,则没有问题。简单地删除aa以留下一个成员联盟也可以解决问题。

请注意,您在submit a bug report to Microsoft for the VS 2017 compiler处拥有所需的一切(不需要使用IDE)。问题中包含的代码是一个独立的示例,可以很好地演示问题。如果你真的不想自己做,请告诉我,我会提交错误。