【问题标题】:Are new C++17 [[nodiscard]] warnings since Visual Studio 15.6.2 compiler update standards-compliant?自 Visual Studio 15.6.2 编译器更新后的新 C++17 [[nodiscard]] 警告是否符合标准?
【发布时间】:2018-08-25 20:50:00
【问题描述】:

最近的 Visual Studio Studio 升级到 15.6.2 版包含一个 Visual C++ 编译器更新,由于[[nodiscard]],导致push_back 行中的以下代码出现警告:

#include <vector>

struct [[nodiscard]] S
{
    int i;
};

int main()
{
    std::vector<S> v;
    v.push_back({ 1 }); // causes warning C4834
}

编译器是这样调用的(注意,重现不需要指定高警告级别,但/std:c++latest是必需的,/permissive-是可选的):

cl /nologo /EHsc /permissive- /std:c++latest test.cpp

警告来自 Visual C++ 自己的std::vector-实现代码并说:

warning C4834: discarding return value of function with 'nodiscard' attribute

(完整的警告输出见下文)

编译器版本:

Microsoft (R) C/C++ Optimizing Compiler Version 19.13.26128 for x64

我的理论是这个警告是由以下原因引起的:

  1. Visual C++ 在 emplace_back 方面实现 push_back
  2. emplace_back 在 C++17 中返回一个引用,并且
  3. 如果设置了 _HAS_CXX17 宏,在 Visual C++ 中后一个函数的实现有点奇怪(对我来说)。

但是,不管任何内部库代码如何,Visual C++ 在生成这些诊断消息时是否违反了标准? wandbox.org 上的最新 Clang 和 GCC 版本不会对相同的代码产生任何警告。

我坚持认为 nodiscard 用户类型(如 S)的库内部使用不应引起警告,因为这会使该功能在实践中无法使用,但在 §10.6.7/2 中对 nodiscard 的简短描述[dcl.attr.nodiscard] 在那个话题上有点含糊。

或者标准只是简单地“阻止”此类警告,而这确实是一个 QoI 问题,尽管在这种情况下是一个相当严重的问题,严重到应该将其作为错误报告提交给 Microsoft?


这是完整的警告:

C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.13.26128\include\vector(996): warning C4834: discarding return value of function with 'nodiscard' attribute
C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.13.26128\include\vector(995): note: while compiling class template member function 'void std::vector<S,std::allocator<_Ty>>::push_back(_Ty &&)'
        with
        [
            _Ty=S
        ]
test.cpp(11): note: see reference to function template instantiation 'void std::vector<S,std::allocator<_Ty>>::push_back(_Ty &&)' being compiled
        with
        [
            _Ty=S
        ]
test.cpp(10): note: see reference to class template instantiation 'std::vector<S,std::allocator<_Ty>>' being compiled
        with
        [
            _Ty=S
        ]
C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.13.26128\include\vector(1934): warning C4834: discarding return value of function with 'nodiscard' attribute
C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.13.26128\include\vector(1933): note: while compiling class template member function 'void std::vector<S,std::allocator<_Ty>>::_Umove_if_noexcept1(S *,S *,S *,std::true_type)'
        with
        [
            _Ty=S
        ]
C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.13.26128\include\vector(1944): note: see reference to function template instantiation 'void std::vector<S,std::allocator<_Ty>>::_Umove_if_noexcept1(S *,S *,S *,std::true_type)' being compiled
        with
        [
            _Ty=S
        ]

【问题讨论】:

  • 返回引用不足以在[[nodiscard]] Demo 上触发警告,所以emplace_back 因为C++17 理论已经过时了。一定是发生了其他事情。
  • @AndyG:好好睡一觉之后再想一想,我认为这正是问题所在。 Visual C++ 现在会在非成员函数和成员函数(特别是复制赋值运算符...)中为引用返回类型生成这些警告。伙计,太糟糕了。我感觉微软根本不认为[[nodiscard]] 非常重要,否则这应该破坏了一些回归测试。
  • 这令人失望。您是否使用我提供的演示代码进行了测试? IIRC 标准实际上并不清楚警告是否应适用于引用类型,尽管我同意 gcc 和 clang
  • @AndyG:是的,return_self 不幸地产生了与return_copy/std:c++latest /W3 相同的警告。不过,有趣的是,它确实需要 /W3 标志,这与我的问题中的代码相反,无论任何警告标志如何都会产生警告。
  • 没有禁止警告之类的东西。如果编译器生成了一个正常运行的程序,那么它就是合规的。

标签: c++ visual-c++ c++17 language-lawyer nodiscard


【解决方案1】:

但是,不管任何内部库代码如何,Visual C++ 在生成这些诊断消息时都不会违反标准吗?

这个问题真的没有意义。该标准规定,如果程序违反可诊断规则,则实现必须发出诊断。该标准没有说明禁止对其他格式良好的程序进行诊断。

有很多常见的编译器警告是对格式良好的代码的诊断。太棒了!确保您收到的警告是有价值的,这确实是一个实施质量问题。在这种情况下,这显然不是一个有价值的警告,因此您应该向 Microsoft 提交错误报告。但不是因为这个警告违反了标准——只是因为它不是一个有用的警告。

【讨论】:

  • 你是对的,我从错误的角度处理了这个问题。这不是一个语言律师问题(至少不是一个有趣的问题,因为正如你所说,答案很明显),而是一个关于明显编译器错误的问题。谢谢!
  • 在此处提交了错误报告:developercommunity.visualstudio.com/content/problem/217312/…。与往常一样,愚蠢的 Visual Studio 报告表单已经弄乱了一些代码格式,即使它在编辑窗口中正确显示,我也不知道如何修复它。我上次就该主题寻求帮助的请求被忽略了。哦,好吧,让我们看看它是否完成了什么。
【解决方案2】:

这在技术上不是一个 MSVC 错误,但是在标准中不鼓励引用类型上的 [[nodiscard]] 警告,而不是禁止。

根据我们的谈话,这是一个复制示例:

struct [[nodiscard]] S{ int i;};

template<class T>
T& return_self(T& _in){
    return _in;
}
int main() {
    S s{1};
    return_self(s);
}

C++ 标准有一个非常相似的例子,他们不鼓励发出警告 ([dcl.attr.nodiscard]):

struct [[nodiscard]] error_info { /* ... */ };
error_info &foo();
void f() { foo(); } // warning not encouraged: not a nodiscard call, because neither
                    // the (reference) return type nor the function is declared nodiscard

【讨论】:

  • 是的,您可以使用 [dcl.attr.nodiscard] 中的确切示例并获得不鼓励的警告。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-09-05
  • 1970-01-01
  • 2017-11-25
  • 2013-04-07
  • 1970-01-01
  • 2023-03-09
  • 2021-11-29
相关资源
最近更新 更多