This is an archive of the discontinued LLVM Phabricator instance.

[Sema] -Wunused-value: diagnose unused std::move() call results.
AbandonedPublic

Authored by lebedev.ri on Apr 2 2018, 7:28 AM.

Details

Summary

I have seen such a problem when reviewing D43341.
https://godbolt.org/g/aJYcaa

#include <utility>

struct S {};

void test(S a) {
    std::move(a);
}

Since std::move() is not marked with nodiscard attribute in the standard
(should it be? how complicated would it be to write such a proposal?),
nothing diagnoses such code. But i really don't see why one would intentionally write that.
You have either forgot to assign/pass the result, or you wanted to cast to void.

Stage-2 self-hosting is green, no preparatory changes needed!

Diff Detail

Repository
rC Clang

Event Timeline

lebedev.ri created this revision.Apr 2 2018, 7:28 AM

LGTM. I think it wouldn't be unreasonable to ask standard library maintainers to add [[nodiscard]] to std::move, but it's also not unreasonable for us to special-case some functions.

thakis added a subscriber: thakis.Apr 2 2018, 10:37 AM

(See also https://bugs.llvm.org/show_bug.cgi?id=10011 for a somewhat related discussion.)

Yeah, actually, I'm second-guessing myself. Maybe this should just be a libc++ / libstdc++ bug.

So.
https://bugs.llvm.org/show_bug.cgi?id=10011 was resolved by https://wg21.link/P0600 (which added [[nodiscard]] to string.empty()

We can do the same for move.
However, I have been promised a comprehensive paper listing all the (100s?) of places in the standard library which should be so marked, and I'm inclined to wait for it (but not for too long).
[ The next WG21 meeting is in June ]

That seems reasonable. And this summer would still be in time for the next release.

I think it wouldn't be unreasonable to ask standard library maintainers to add [[nodiscard]] to std::move

+1. Also std::forward, for sure. Basically any metaprogramming function that is statically known to return a reference to its argument.
This knowledge is already in the brains of library vendors; they ought to just write it down in the form of [[nodiscard]] annotations. This PR smells like Clang is trying to "cut out the middleman" and just make up its own proprietary list of metaprogramming functions that are statically known to return references to arguments, which is not the most effective or futureproof way to go about it. Let the library vendors deal with it, please, says me.

I think it wouldn't be unreasonable to ask standard library maintainers to add [[nodiscard]] to std::move

+1. Also std::forward, for sure. Basically any metaprogramming function that is statically known to return a reference to its argument.
This knowledge is already in the brains of library vendors; they ought to just write it down in the form of [[nodiscard]] annotations. This PR smells like Clang is trying to "cut out the middleman" and just make up its own proprietary list of metaprogramming functions that are statically known to return references to arguments, which is not the most effective or futureproof way to go about it. Let the library vendors deal with it, please, says me.

A few updates:

  • std::move() *should* be a part of the next paper about [[nodiscard]]. Yay!
  • D45179 *should* make those attributes usable in pre-C++17 code. For people using libc++.

But, some points still remain:

  • std::move() is not [[nodiscard]] yet
  • D45179 is not merged yet
  • Even when either/both things happen, it won't really help those not using libc++ [trunk] / C++17-or-later. That is a *lot* of people.

I do agree with @Quuxplusone, we wouldn't want to pull the list of all the [[nodiscard]] functions from the standard into clang just because. (we could do that with clang-tidy)
But maybe std::move() is a bit special in this regard... ?

std::move would definitely be special in this regard if there were a pressing benefit to be gained — i.e., if people were currently getting bitten by accidentally discarded calls of std::move(x). But you haven't shown that people are getting bitten today; in fact I think you said the opposite, right? that there were *no* instances of this happening in the real codebases you tested? So in that case, this diagnostic doesn't have a pressing benefit IMHO, and Clang could safely wait for the library vendors to do the work.

std::move would definitely be special in this regard if there were a pressing benefit to be gained — i.e., if people were currently getting bitten by accidentally discarded calls of std::move(x). But you haven't shown that people are getting bitten today; in fact I think you said the opposite, right? that there were *no* instances of this happening in the real codebases you tested? So in that case, this diagnostic doesn't have a pressing benefit IMHO, and Clang could safely wait for the library vendors to do the work.

@Quuxplusone Like i said in the differential's description,

I have seen such a problem when reviewing D43341.

https://reviews.llvm.org/D43341?vs=137245&id=139869&whitespace=ignore-most#toc

Please see clang-doc/Representation.cpp, left hand side of that page, line 21:

static void mergeInfoBase(Info &L, Info &R) {
  assert(L.USR == R.USR);
  assert(L.Name == R.Name);
  if (L.Namespace.empty()) std::move(R.Namespace); // <- here
...

Well, we should feel welcome to submit patches to the C++ library implementations, I think. I can understand why Marshall is waiting to just do this until he gets a comprehensive committee paper, but he might consider taking a patch in the meantime. But I'm not sure what the rush is if it doesn't change what goes into any concrete release of the compiler + library.

Well, we should feel welcome to submit patches to the C++ library implementations, I think. I can understand why Marshall is waiting to just do this until he gets a comprehensive committee paper,

but he might consider taking a patch in the meantime.

That has been discussed, and it's not going to happen. Ask him if you want more info.

But I'm not sure what the rush is if it doesn't change what goes into any concrete release of the compiler + library.

TLDW: std::move() is "The Assign Operator (a = b;) of RAII". It would be good to diagnose such a problem, and not just rely that some day the std libs will mark it with the attribute.
BTW, even when they do, even for libcxx, it won't be of any immediate use to LLVM, we will need to provide a define (see D45179) to actually enable that attribute, because LLVM is using C++11, not C++17/something...
<insert "not everyone uses clang with libc++" rant>

Trust me, I understand that this is an important function, but a lot of functions are important, and we're not going to hardcode knowledge about all of them in the compiler.

It seems reasonable to ask libc++ to use __attribute__((warn_unused_result)) if [[nodiscard]] is unavailable.

Well, we should feel welcome to submit patches to the C++ library implementations, I think. I can understand why Marshall is waiting to just do this until he gets a comprehensive committee paper, but he might consider taking a patch in the meantime.

That has been discussed, and it's not going to happen. Ask him if you want more info.

You say a library patch is not going to happen, but isn't that library patch literally D45179, which has been accepted (although I just left a comment explaining why the current macro-soup is suboptimal)?

TLDW: std::move() is "The Assign Operator (a = b;) of RAII". It would be good to diagnose such a problem, and not just rely that some day the std libs will mark it with the attribute.
BTW, even when they do, even for libcxx, it won't be of any immediate use to LLVM, we will need to provide a define (see D45179) to actually enable that attribute, because LLVM is using C++11, not C++17/something...

Yes, but that patch (which you've written in D45179) is essentially just "if C++17, [[nodiscard]], else __attribute__((warn_unused_result))." The library vendor is completely free to mark nodiscard-ish function with [[nodiscard]] or any other attribute they want to. And if I'm not mistaken, D45179 is a step in that direction.

It seems reasonable to ask libc++ to use __attribute__((warn_unused_result)) if [[nodiscard]] is unavailable.

D45179 should hopefully add an opt-in define to allow doing just that. But it will then have to be enabled in the LLVM buildsystem.

Well, we should feel welcome to submit patches to the C++ library implementations, I think. I can understand why Marshall is waiting to just do this until he gets a comprehensive committee paper, but he might consider taking a patch in the meantime.

That has been discussed, and it's not going to happen. Ask him if you want more info.

You say a library patch is not going to happen, but isn't that library patch literally D45179, which has been accepted (although I just left a comment explaining why the current macro-soup is suboptimal)?

We may be talking about different things here.
I'm simply pointing out that libc++ will not be adding nodiscard attribute to functions unless it is mandated by the standard,
and that it *has* to be opt-in for earlier standards. I'm not saying that just to argue, i'm literally retranslating what @mclow.lists has said, it's his words.

lebedev.ri abandoned this revision.Jun 21 2019, 8:50 AM
Herald added a project: Restricted Project. · View Herald TranscriptJun 21 2019, 8:50 AM