Visual Studio 2013 是否在存在 /OPT:ICF 的情况下正确优化?

Is Visual Studio 2013 optimizing correctly in the presence of /OPT:ICF?

我希望以下程序始终为 return 0。但是对于 Visual Studio 2013(更新 4),程序在发布版本中退出 1。我不确定这是一个错误还是编译器的优化器是否正确并且依赖于某些边缘行为。如果关闭 CONST 宏,则释放 exe returns 0。如果优化器确实是正确的,我能得到允许它发出它发出的代码的原因吗?

#if 1
#   define CONST const
#else
#   define CONST
#endif


class TypeId {
public:
    bool operator== (TypeId const & other) const
    {
        return id == other.id;
    }

private:
    TypeId (void const * id)
        : id(id)
    {}

public:
    template <typename T>
    static TypeId Get ()
    {
        static char CONST uniqueMemLoc = 0;
        return TypeId(&uniqueMemLoc);
    }

private:
    void const * id;
};


int main(int, char **)
{
    typedef int A;
    typedef unsigned int B;

    if (TypeId::Get<A>() == TypeId::Get<B>()) {
        return 1;
    }
    return 0;
}

不,这个优化不符合C++标准。 uniqueMemLoc的声明为模板的每个实例定义了一个唯一的对象,每个对象都有自己的地址。

(如果你使用的是字符串字面量,那就另当别论了。优化在那种情况下是有效的。)

根据 C++11 标准部分草案 14.8 [temp.fct.spec] 说(强调我的前进):

Each function template specialization instantiated from a template has its own copy of any static variable. [ Example:

template<class T> void f(T* p) {
static T s;
};
void g(int a, char* b) {
    f(&a); // calls f<int>(int*)
    f(&b); // calls f<char*>(char**)
}

Here f(int*) has a static variable s of type int and f<char*>(char**) has a static variable s of type char*. —end example ]

由于您获取折叠变量的地址会影响可观察到的行为,这将违反 as-if rule

T.C。指出 /opt:noicf 可以防止不合格行为。

Matt McNabb 指出 /OPT (Optimizations) documentation 包含以下注释:

Because /OPT:ICF can cause the same address to be assigned to different functions or read-only data members (const variables compiled by using /Gy), it can break a program that depends on unique addresses for functions or read-only data members. For more information, see /Gy (Enable Function-Level Linking).

这表明这可能是故意的不合规行为。 Ben Voigt says in a comment now moved to chat 这确实意味着优化可能 不符合要求 但这一点值得商榷。

用户 usr to an MS blog post: Introducing ‘/Gw’ Compiler Switch 并且它说:

Please note, the ICF optimization will only be applied for identical COMDATs where their address is not taken, and they are read only. If a data is not address taken, then breaking address uniqueness by ICF won't lead to any observable difference, thus it is valid and conformant to the standard.

后来的评论说:

Even though it's on it's own completely standards complaint, when combined with /Gy potentially breaking behavior can result.

据我所知,为了 /Gy 影响 const 变量 __declspec(selectany)必须使用,但在文档中可能会更清楚。

至少我们可以看到 /Gw 不应引入不符合规范的行为,但 /Gy/Gw 相结合可能会引入。