This is an archive of the discontinued LLVM Phabricator instance.

Warn, if parameter is used in ctor body after being used for move-construct
Needs ReviewPublic

Authored by ismailp on Jun 12 2015, 3:53 PM.

Details

Reviewers
dblaikie
rsmith
Summary

If a member of type unique_ptr or shared_ptr is move-constructed from
a parameter in ctor-init, the parameter will be left with nullptr at
the completion of member's initialization. If the parameter's and
member's names are the same, use of member's name in the constructor
body will not refer to the member, but to the parameter.

#include <memory>
struct X {
  int v;
  X() : v() { }
  int f() { return v + 42; }
};

struct Y {
  std::unique_ptr<X> p;
  int x;
  explicit Y(std::unique_ptr<X> p)
    : p{std::move(p)} {
    x = p->f();  // 'p' is nullptr
    decltype(p->f()) v = x; // ignore unevaluated context
  }
  int f() const { return x; }
};

int main() {
  std::unique_ptr<X> p(new X);
  Y y(std::move(p));
  return y.f();
}

Diff Detail

Event Timeline

ismailp updated this revision to Diff 27614.Jun 12 2015, 3:53 PM
ismailp retitled this revision from to Warn, if parameter is used in ctor body after being used for move-construct.
ismailp updated this object.
ismailp edited the test plan for this revision. (Show Details)
ismailp added reviewers: rsmith, dblaikie.
ismailp added a subscriber: Unknown Object (MLST).
dblaikie edited edge metadata.Jun 25 2015, 10:26 AM

A few thoughts - but probably having some review by rtreiu would be good. He's more involved in the diagnostic development than I am.

Have you run this over any substantial existing codebase to see what the stats are like (true/false positives, etc)?

The other issue is that, of course, we'd like a much more general version of this warning but it's unclear how much work that'll be and what the right tradeoff is for compile time. Some common analysis might be shared between a bunch of such warnings - we already have "sometimes-uninitialized" which is a CFG diagnostic that could be useful (treat moved-from as the uninitialized state and do the same analysis).

lib/Sema/SemaDecl.cpp
10694

I'm not sure how much of an efficiency concern there is doing a generic RAV here, rather than something more targeted. I mean I suppose in general the std::move could happen in any subexpression of an init - but I assume the case you're trying to catch here is just the one where the name of the parameter and variable are the same (or very similar - like foo_ and foo, etc) and the user accidentally uses the parameter instead of the variable they moved-in-to?

10783

I forget, is CPlusPlus11 true in modes greater than 11? (so we still get the warning in 14, etc?)

test/SemaCXX/rval-references.cpp
95

This test case seems a bit long/verbose - you probably don't need to reproduce a substantial amount of this template machinery to reproduce the warning (a trivial movable type rather than a copy of a substantial amount of unique_ptr would suffice, for example - and there's no need for the extra type traits (remove_ref, etc) work in the faux-move implementation, etc)

A few thoughts - but probably having some review by rtreiu would be good. He's more involved in the diagnostic development than I am.

Have you run this over any substantial existing codebase to see what the stats are like (true/false positives, etc)?

No, I haven't, but I heard Google has a large C++11 codebase :) I saw this bug in clang's source code (I didn't submit patch for it yet, can do it in a few days).

The other issue is that, of course, we'd like a much more general version of this warning but it's unclear how much work that'll be and what the right tradeoff is for compile time. Some common analysis might be shared between a bunch of such warnings - we already have "sometimes-uninitialized" which is a CFG diagnostic that could be useful (treat moved-from as the uninitialized state and do the same analysis).

I'll take a look at that and see whether this analysis can be merged into sometimes-uninitialized.

lib/Sema/SemaDecl.cpp
10694

Yes, this patch is trying to find such accidental uses of parameters in constructor body. I chose constructor, because it's more likely to happen there. It's not deciding based on edit distance -- which sounds like a good idea -- but an exact match. Because it looks like a genuine bug (assuming parameter isn't assigned-to a sensible value again). In fact, whether parameter and member have the same name doesn't matter, if parameter is used after move. But I focused on the case where parameter and member both have the same name, because it's harder to see by looking at the code.

10783

Yes, CPlusPlus14 sets CPlusPlus11.

test/SemaCXX/rval-references.cpp
95

Yes, I hated that, too! I've had bigger plans; if it can't move-from but copy-from, then it should be fine! It's not applicable to unique_ptr, but for other types. These tests will change more to address a few more issues.