constexpr 在联合中初始化结构时,msvc visual c++ 静默错误代码生成

Posted

技术标签:

【中文标题】constexpr 在联合中初始化结构时,msvc visual c++ 静默错误代码生成【英文标题】:msvc visual c++ silent incorrect code generation when constexpr initializing struct within union 【发布时间】:2016-12-21 19:53:13 【问题描述】:

考虑以下 sn-p 修剪以说明问题:

#include <cstdio>

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

msvc 2015 update 3 和 2017 rc1 通过对 t3 进行零初始化而不是使用给定值正确初始化它来静默生成错误代码。 gcc 和 clang 都可以。

我考虑报告一个错误,但它太麻烦了(我不使用 IDE)。如果您关心,请确认这是一个错误,并让微软可能关注的人知道它。

【问题讨论】:

你不需要使用IDE来report a bug。 虽然您可能有理由,但编写这样的代码有什么好的理由吗?对我来说 staticconstexpr 似乎相反。 只是好奇...如果您不关心举报,我为什么要举报? 此错误已报告here。 【参考方案1】:

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

我还可以确认当前版本的 GCC、Clang 和 ICC 可以正确编译它。我在语言标准中也找不到任何禁止您所做的事情。无论是在编译时(如您所料)还是在运行时初始化对象,该实现都有一定的余地,但 MSVC 根本不初始化它。

正如所料,当对象的声明被移动到命名空间范围时,也会出现同样的问题,例如

#include <cstdio>

struct A 
    union 
        struct  int a0, a1;  aa;
        int bb[2];
    ;

    constexpr A(int a0, int a1) : aaa0, a1  
;

namespace 
    constexpr A t3  2, 3 ;
;

int main() 
    std::printf("%d %d\n", t3.aa.a0, t3.aa.a1);

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

虽然可见效果是零初始化,但这实际上并不是编译器正在做的事情。相反,它根本无法在相应的数据段中发出值,因此当代码在调用printf 时尝试从该地址加载一个值以压入堆栈时,它最终会压入一个零。

这里的union 似乎是重现该错误的关键。如果A 只包含结构aa,则没有问题。简单地删除bb 以离开一个成员工会也可以解决问题。

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

【讨论】:

感谢您的分析。请提交错误。

以上是关于constexpr 在联合中初始化结构时,msvc visual c++ 静默错误代码生成的主要内容,如果未能解决你的问题,请参考以下文章

将函数指针分配给 constexpr 结构中的 typedef 函数的正确 C++ 方法是啥?

与 MSVC 链接错误,但与 constexpr 的 g++ 无关

当值是非常量但使用常量表达式初始化时使用 constexpr?

为啥从 constexpr 引用生成的汇编代码与 constexpr 指针不同?

使用 constexpr 成员函数初始化 constexpr 成员变量

我们应该在函数中用 constexpr 定义变量吗