4

A recent Visual Studio Studio upgrade to version 15.6.2 included a Visual C++ compiler update which causes warnings for the following code at the push_back line due to [[nodiscard]]:

#include <vector>

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

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

The compiler is invoked like this (note that no high warning level needs to be specified to reproduce, but /std:c++latest is required, and /permissive- is optional):

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

The warning comes from within Visual C++'s own std::vector-implementation code and says:

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

(see below for complete warning output)

Compiler version:

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

My theory is that this warning is caused by:

  1. Visual C++ implementing push_back in terms of emplace_back,
  2. emplace_back returning a reference in C++17, and
  3. the somewhat curious (to me) implementation of the latter function in Visual C++ if the _HAS_CXX17 macro is set.

However, regardless of any internal library code, doesn't Visual C++ violate the standard in producing those diagnostic messages? The latest Clang and GCC versions over at wandbox.org do not produce any warnings for the same code.

I maintain that library-internal usages of nodiscard user types like S should never cause warnings, because this would render the feature unusable in practice, but the short description of nodiscard in §10.6.7/2 [dcl.attr.nodiscard] is a bit vague on that topic.

Or does the standard simply "discourage" such warnings, and it is all really a QoI issue, albeit a rather serious one in this case, so serious that it should probably be filed as a bug report at Microsoft?


Here's the complete warning:

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
        ]
Alex Guteniev
  • 12,039
  • 2
  • 34
  • 79
Christian Hackl
  • 27,051
  • 3
  • 32
  • 62
  • Returning a reference is not sufficient to trigger a warning on `[[nodiscard]]` [Demo](https://wandbox.org/permlink/oOWIm1cCuy5afzdC), so the `emplace_back` since C++17 theory is out. Something else must be happening. – AndyG Mar 16 '18 at 17:57
  • @AndyG: Thinking it over after a good night's sleep, I think that's exactly the problem. Visual C++ now produces those warnings for reference return types, both in non-member functions and in member functions (in particular, copy assignment operators...). Man, that sucks. I have the feeling that Microsoft do not consider `[[nodiscard]]` very important at all, or else this should have broken a few regression tests. – Christian Hackl Mar 17 '18 at 09:26
  • That's disappointing. Did you test with the demo code I provided? IIRC the standard wasn't actually very clear on whether the warning should apply to reference types, although I agree with gcc and clang – AndyG Mar 17 '18 at 12:45
  • 1
    @AndyG: Yes, `return_self` unfortunately produces the same warning as `return_copy` with `/std:c++latest /W3`. Interestingly, though, it does require the `/W3` flag here, in contrast to the code in my question, which will produce the warning irrespective of any warning flags. – Christian Hackl Mar 17 '18 at 13:01
  • There's no such thing as a prohibited warning. If the compiler produced a properly functioning program then it's in compliance. – Jim Balter Dec 19 '21 at 23:32
  • @JimBalter Compliant: maybe, useable: no. – Paul Sanders May 20 '22 at 09:10

2 Answers2

6

However, regardless of any internal library code, doesn't Visual C++ violate the standard in producing those diagnostic messages?

This question doesn't really make sense. The standard mandates that if a program violates a diagnosable rule, an implementation must issue a diagnostic. The standard doesn't say anything about disallowing diagnostics for otherwise well-formed programs.

There are many, many common compiler warnings that are diagnostics on well-formed code. Which is great! It's really a quality of implementation issue to ensure that the warnings you get are valuable. In this case, this obviously is not a valuable warning, so you should submit a bug report to Microsoft. But not because this warning violates the standard - simply because it's not a useful warning.

Barry
  • 286,269
  • 29
  • 621
  • 977
  • You are correct, I approached this issue from the wrong perspective. It's not a language-lawyer question (at least not an interesting one, because the answer is obvious, as you say), but really a question about an apparent compiler bug. Thanks! – Christian Hackl Mar 16 '18 at 19:07
  • 3
    Filed a bug report here: https://developercommunity.visualstudio.com/content/problem/217312/c17-nodiscard-warnings-from-library-code.html. As always, the stupid Visual Studio report form has messed up some code formatting even though it shows correctly in the edit window, and I don't know how to fix it. My last request for help on that topic was ignored. Oh well, let's see if it accomplishes anything. – Christian Hackl Mar 17 '18 at 09:09
2

This is not technically a MSVC bug, however warnings for [[nodiscard]] on reference types are discouraged in the standard, not prohibited.

Per our conversation, this is a reproducing example:

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

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

The C++ standard has a very similar example where they discourage the warning to be elicited ([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
AndyG
  • 39,700
  • 8
  • 109
  • 143