Passing a variable to std::move now counts as a use for -Wuninitialized

llvm-svn: 216438
This commit is contained in:
Richard Trieu 2014-08-26 04:30:55 +00:00
parent 43ccec8e53
commit 11fd079b6e
4 changed files with 95 additions and 2 deletions

View File

@ -341,6 +341,16 @@ void ClassifyRefs::VisitUnaryOperator(UnaryOperator *UO) {
}
void ClassifyRefs::VisitCallExpr(CallExpr *CE) {
// Classify arguments to std::move as used.
if (CE->getNumArgs() == 1) {
if (FunctionDecl *FD = CE->getDirectCallee()) {
if (FD->getIdentifier() && FD->getIdentifier()->isStr("move")) {
classify(CE->getArg(0), Use);
return;
}
}
}
// If a value is passed by const reference to a function, we should not assume
// that it is initialized by the call, and we conservatively do not assume
// that it is used.

View File

@ -8288,6 +8288,21 @@ namespace {
Inherited::VisitCXXConstructExpr(E);
}
void VisitCallExpr(CallExpr *E) {
// Treat std::move as a use.
if (E->getNumArgs() == 1) {
if (FunctionDecl *FD = E->getDirectCallee()) {
if (FD->getIdentifier() && FD->getIdentifier()->isStr("move")) {
if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E->getArg(0))) {
HandleDeclRefExpr(DRE);
}
}
}
}
Inherited::VisitCallExpr(E);
}
void HandleDeclRefExpr(DeclRefExpr *DRE) {
Decl* ReferenceDecl = DRE->getDecl();
if (OrigDecl != ReferenceDecl) return;

View File

@ -2337,6 +2337,21 @@ namespace {
Inherited::VisitCXXMemberCallExpr(E);
}
void VisitCallExpr(CallExpr *E) {
// Treat std::move as a use.
if (E->getNumArgs() == 1) {
if (FunctionDecl *FD = E->getDirectCallee()) {
if (FD->getIdentifier() && FD->getIdentifier()->isStr("move")) {
if (MemberExpr *ME = dyn_cast<MemberExpr>(E->getArg(0))) {
HandleMemberExpr(ME, false /*CheckReferenceOnly*/);
}
}
}
}
Inherited::VisitCallExpr(E);
}
void VisitBinaryOperator(BinaryOperator *E) {
// If a field assignment is detected, remove the field from the
// uninitiailized field set.

View File

@ -1,9 +1,21 @@
// RUN: %clang_cc1 -fsyntax-only -Wall -Wuninitialized -Wno-unused-value -std=c++11 -verify %s
// definitions for std::move
namespace std {
inline namespace foo {
template <class T> struct remove_reference { typedef T type; };
template <class T> struct remove_reference<T&> { typedef T type; };
template <class T> struct remove_reference<T&&> { typedef T type; };
template <class T> typename remove_reference<T>::type&& move(T&& t);
}
}
int foo(int x);
int bar(int* x);
int boo(int& x);
int far(const int& x);
int moved(int&& x);
// Test self-references within initializers which are guaranteed to be
// uninitialized.
@ -24,6 +36,9 @@ int k = __alignof__(k);
int l = k ? l : l; // expected-warning 2{{variable 'l' is uninitialized when used within its own initialization}}
int m = 1 + (k ? m : m); // expected-warning 2{{variable 'm' is uninitialized when used within its own initialization}}
int n = -n; // expected-warning {{variable 'n' is uninitialized when used within its own initialization}}
int o = std::move(o); // expected-warning {{variable 'o' is uninitialized when used within its own initialization}}
const int p = std::move(p); // expected-warning {{variable 'p' is uninitialized when used within its own initialization}}
int q = moved(std::move(q)); // expected-warning {{variable 'q' is uninitialized when used within its own initialization}}
void test_stuff () {
int a = a; // no-warning: used to signal intended lack of initialization.
@ -44,6 +59,9 @@ void test_stuff () {
int l = k ? l : l; // expected-warning {{variable 'l' is uninitialized when used within its own initialization}}
int m = 1 + (k ? m : m); // expected-warning {{'m' is uninitialized when used within its own initialization}}
int n = -n; // expected-warning {{variable 'n' is uninitialized when used within its own initialization}}
int o = std::move(o); // expected-warning {{variable 'o' is uninitialized when used within its own initialization}}
const int p = std::move(p); // expected-warning {{variable 'p' is uninitialized when used within its own initialization}}
int q = moved(std::move(q)); // expected-warning {{variable 'q' is uninitialized when used within its own initialization}}
for (;;) {
int a = a; // no-warning: used to signal intended lack of initialization.
@ -64,6 +82,9 @@ void test_stuff () {
int l = k ? l : l; // expected-warning {{variable 'l' is uninitialized when used within its own initialization}}
int m = 1 + (k ? m : m); // expected-warning {{'m' is uninitialized when used within its own initialization}}
int n = -n; // expected-warning {{variable 'n' is uninitialized when used within its own initialization}}
int o = std::move(o); // expected-warning {{variable 'o' is uninitialized when used within its own initialization}}
const int p = std::move(p); // expected-warning {{variable 'p' is uninitialized when used within its own initialization}}
int q = moved(std::move(q)); // expected-warning {{variable 'q' is uninitialized when used within its own initialization}}
}
}
@ -84,6 +105,7 @@ class A {
A(int x) {}
A(int *x) {}
A(A *a) {}
A(A &&a) {}
~A();
};
@ -91,6 +113,7 @@ A getA() { return A(); }
A getA(int x) { return A(); }
A getA(A* a) { return A(); }
A getA(A a) { return A(); }
A moveA(A&& a) { return A(); }
void setupA(bool x) {
A a1;
@ -130,6 +153,11 @@ void setupA(bool x) {
const A a29(a29); // expected-warning {{variable 'a29' is uninitialized when used within its own initialization}}
const A a30 = a30; // expected-warning {{variable 'a30' is uninitialized when used within its own initialization}}
A a31 = std::move(a31); // expected-warning {{variable 'a31' is uninitialized when used within its own initialization}}
A a32 = moveA(std::move(a32)); // expected-warning {{variable 'a32' is uninitialized when used within its own initialization}}
A a33 = A(std::move(a33)); // expected-warning {{variable 'a33' is uninitialized when used within its own initialization}}
A a34(std::move(a34)); // expected-warning {{variable 'a34' is uninitialized when used within its own initialization}}
}
bool x;
@ -169,6 +197,10 @@ A *a28 = new A(a28->num); // expected-warning {{variable 'a28' is uninitialized
const A a29(a29); // expected-warning {{variable 'a29' is uninitialized when used within its own initialization}}
const A a30 = a30; // expected-warning {{variable 'a30' is uninitialized when used within its own initialization}}
A a31 = std::move(a31); // expected-warning {{variable 'a31' is uninitialized when used within its own initialization}}
A a32 = moveA(std::move(a32)); // expected-warning {{variable 'a32' is uninitialized when used within its own initialization}}
A a33 = A(std::move(a33)); // expected-warning {{variable 'a33' is uninitialized when used within its own initialization}}
A a34(std::move(a34)); // expected-warning {{variable 'a34' is uninitialized when used within its own initialization}}
struct B {
// POD struct.
int x;
@ -179,6 +211,7 @@ B getB() { return B(); };
B getB(int x) { return B(); };
B getB(int *x) { return B(); };
B getB(B *b) { return B(); };
B moveB(B &&b) { return B(); };
B* getPtrB() { return 0; };
B* getPtrB(int x) { return 0; };
@ -219,6 +252,9 @@ void setupB() {
const B b19 = b19; // expected-warning {{variable 'b19' is uninitialized when used within its own initialization}}
const B b20(b20); // expected-warning {{variable 'b20' is uninitialized when used within its own initialization}}
B b21 = std::move(b21); // expected-warning {{variable 'b21' is uninitialized when used within its own initialization}}
B b22 = moveB(std::move(b22)); // expected-warning {{variable 'b22' is uninitialized when used within its own initialization}}
B b23 = B(std::move(b23)); // expected-warning {{variable 'b23' is uninitialized when used within its own initialization}}
}
B b1;
@ -247,6 +283,10 @@ B b18 = { b18.x + 1, b18.y }; // expected-warning 2{{variable 'b18' is uninitia
const B b19 = b19; // expected-warning {{variable 'b19' is uninitialized when used within its own initialization}}
const B b20(b20); // expected-warning {{variable 'b20' is uninitialized when used within its own initialization}}
B b21 = std::move(b21); // expected-warning {{variable 'b21' is uninitialized when used within its own initialization}}
B b22 = moveB(std::move(b22)); // expected-warning {{variable 'b22' is uninitialized when used within its own initialization}}
B b23 = B(std::move(b23)); // expected-warning {{variable 'b23' is uninitialized when used within its own initialization}}
// Also test similar constructs in a field's initializer.
struct S {
int x;
@ -558,6 +598,7 @@ namespace record_fields {
A const_ref(const A&);
A pointer(A*);
A normal(A);
A rref(A&&);
struct B {
A a;
@ -570,9 +611,12 @@ namespace record_fields {
B(char (*)[7]) : a(const_ref(a)) {}
B(char (*)[8]) : a(pointer(&a)) {}
B(char (*)[9]) : a(normal(a)) {} // expected-warning {{uninitialized}}
B(char (*)[10]) : a(std::move(a)) {} // expected-warning {{uninitialized}}
B(char (*)[11]) : a(A(std::move(a))) {} // expected-warning {{uninitialized}}
B(char (*)[12]) : a(rref(std::move(a))) {} // expected-warning {{uninitialized}}
};
struct C {
C() {} // expected-note5{{in this constructor}}
C() {} // expected-note8{{in this constructor}}
A a1 = a1; // expected-warning {{uninitialized}}
A a2 = a2.get(); // expected-warning {{uninitialized}}
A a3 = a3.num();
@ -583,8 +627,11 @@ namespace record_fields {
A a8 = pointer(&a8);
A a9 = normal(a9); // expected-warning {{uninitialized}}
const A a10 = a10; // expected-warning {{uninitialized}}
A a11 = std::move(a11); // expected-warning {{uninitialized}}
A a12 = A(std::move(a12)); // expected-warning {{uninitialized}}
A a13 = rref(std::move(a13)); // expected-warning {{uninitialized}}
};
struct D { // expected-note5{{in the implicit default constructor}}
struct D { // expected-note8{{in the implicit default constructor}}
A a1 = a1; // expected-warning {{uninitialized}}
A a2 = a2.get(); // expected-warning {{uninitialized}}
A a3 = a3.num();
@ -595,6 +642,9 @@ namespace record_fields {
A a8 = pointer(&a8);
A a9 = normal(a9); // expected-warning {{uninitialized}}
const A a10 = a10; // expected-warning {{uninitialized}}
A a11 = std::move(a11); // expected-warning {{uninitialized}}
A a12 = A(std::move(a12)); // expected-warning {{uninitialized}}
A a13 = rref(std::move(a13)); // expected-warning {{uninitialized}}
};
D d;
struct E {
@ -608,6 +658,9 @@ namespace record_fields {
A a8 = pointer(&a8);
A a9 = normal(a9);
const A a10 = a10;
A a11 = std::move(a11);
A a12 = A(std::move(a12));
A a13 = rref(std::move(a13));
};
}