From: Richard Trieu Date: Wed, 27 Aug 2014 22:15:10 +0000 (+0000) Subject: More -Wuninitialized updates X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=9b25aa4ae0f7e040e365e25360b5fcd03cd1eb68;p=clang More -Wuninitialized updates Fix r216438 to catch more complicated self-initialized in std::move. For instance, "Foo f = std::move(cond ? OtherFoo : (UNUSED_VALUE, f));" Make sure that BinaryConditionalOperator, ConditionalOperator, BinaryOperator with comma operator, and OpaqueValueExpr perform the correct usage forwarding across the three uninitialized value checkers. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@216627 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Analysis/UninitializedValues.cpp b/lib/Analysis/UninitializedValues.cpp index da4d072807..ef2cf36f3c 100644 --- a/lib/Analysis/UninitializedValues.cpp +++ b/lib/Analysis/UninitializedValues.cpp @@ -300,13 +300,28 @@ void ClassifyRefs::classify(const Expr *E, Class C) { // The result of a ?: could also be an lvalue. E = E->IgnoreParens(); if (const ConditionalOperator *CO = dyn_cast(E)) { - const Expr *TrueExpr = CO->getTrueExpr(); - if (!isa(TrueExpr)) - classify(TrueExpr, C); + classify(CO->getTrueExpr(), C); classify(CO->getFalseExpr(), C); return; } + if (const BinaryConditionalOperator *BCO = + dyn_cast(E)) { + classify(BCO->getFalseExpr(), C); + return; + } + + if (const OpaqueValueExpr *OVE = dyn_cast(E)) { + classify(OVE->getSourceExpr(), C); + return; + } + + if (const BinaryOperator *BO = dyn_cast(E)) { + if (BO->getOpcode() == BO_Comma) + classify(BO->getRHS(), C); + return; + } + FindVarResult Var = findVar(E, DC); if (const DeclRefExpr *DRE = Var.getDeclRefExpr()) Classification[DRE] = std::max(Classification[DRE], C); diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 2d2f97316d..c7af3b488c 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -8211,7 +8211,7 @@ namespace { void HandleValue(Expr *E) { if (isReferenceType) return; - E = E->IgnoreParenImpCasts(); + E = E->IgnoreParens(); if (DeclRefExpr* DRE = dyn_cast(E)) { HandleDeclRefExpr(DRE); return; @@ -8223,6 +8223,23 @@ namespace { return; } + if (BinaryConditionalOperator *BCO = + dyn_cast(E)) { + HandleValue(BCO->getFalseExpr()); + return; + } + + if (OpaqueValueExpr *OVE = dyn_cast(E)) { + HandleValue(OVE->getSourceExpr()); + return; + } + + if (BinaryOperator *BO = dyn_cast(E)) { + if (BO->getOpcode() == BO_Comma) + HandleValue(BO->getRHS()); + return; + } + if (isa(E)) { Expr *Base = E->IgnoreParenImpCasts(); while (MemberExpr *ME = dyn_cast(Base)) { @@ -8313,9 +8330,7 @@ namespace { if (E->getNumArgs() == 1) { if (FunctionDecl *FD = E->getDirectCallee()) { if (FD->getIdentifier() && FD->getIdentifier()->isStr("move")) { - if (DeclRefExpr *DRE = dyn_cast(E->getArg(0))) { - HandleDeclRefExpr(DRE); - } + HandleValue(E->getArg(0)); } } } diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 1332eac840..081d91e050 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -2279,11 +2279,15 @@ namespace { if (BinaryConditionalOperator *BCO = dyn_cast(E)) { - HandleValue(BCO->getCommon()); HandleValue(BCO->getFalseExpr()); return; } + if (OpaqueValueExpr *OVE = dyn_cast(E)) { + HandleValue(OVE->getSourceExpr()); + return; + } + if (BinaryOperator *BO = dyn_cast(E)) { switch (BO->getOpcode()) { default: @@ -2342,9 +2346,7 @@ namespace { if (E->getNumArgs() == 1) { if (FunctionDecl *FD = E->getDirectCallee()) { if (FD->getIdentifier() && FD->getIdentifier()->isStr("move")) { - if (MemberExpr *ME = dyn_cast(E->getArg(0))) { - HandleMemberExpr(ME, false /*CheckReferenceOnly*/); - } + HandleValue(E->getArg(0)); } } } diff --git a/test/SemaCXX/uninitialized.cpp b/test/SemaCXX/uninitialized.cpp index 8adb93a509..fa453cbb29 100644 --- a/test/SemaCXX/uninitialized.cpp +++ b/test/SemaCXX/uninitialized.cpp @@ -39,6 +39,9 @@ int n = -n; // expected-warning {{variable 'n' is uninitialized when used withi 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}} +int r = std::move((p ? q : (18, r))); // expected-warning {{variable 'r' is uninitialized when used within its own initialization}} +int s = r ?: s; // expected-warning {{variable 's' is uninitialized when used within its own initialization}} +int t = t ?: s; // expected-warning {{variable 't' is uninitialized when used within its own initialization}} void test_stuff () { int a = a; // no-warning: used to signal intended lack of initialization. @@ -62,6 +65,9 @@ void test_stuff () { 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}} + int r = std::move((p ? q : (18, r))); // expected-warning {{variable 'r' is uninitialized when used within its own initialization}} + int s = r ?: s; // expected-warning {{variable 's' is uninitialized when used within its own initialization}} + int t = t ?: s; // expected-warning {{variable 't' is uninitialized when used within its own initialization}} for (;;) { int a = a; // no-warning: used to signal intended lack of initialization. @@ -85,6 +91,9 @@ void test_stuff () { 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}} + int r = std::move((p ? q : (18, r))); // expected-warning {{variable 'r' is uninitialized when used within its own initialization}} + int s = r ?: s; // expected-warning {{variable 's' is uninitialized when used within its own initialization}} + int t = t ?: s; // expected-warning {{variable 't' is uninitialized when used within its own initialization}} } } @@ -158,6 +167,7 @@ void setupA(bool x) { 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}} + A a35 = std::move(x ? a34 : (37, a35)); // expected-warning {{variable 'a35' is uninitialized when used within its own initialization}} } bool x; @@ -201,6 +211,7 @@ A a31 = std::move(a31); // expected-warning {{variable 'a31' is uninitialized w 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}} +A a35 = std::move(x ? a34 : (37, a35)); // expected-warning {{variable 'a35' is uninitialized when used within its own initialization}} struct B { // POD struct. int x; @@ -218,7 +229,7 @@ B* getPtrB(int x) { return 0; }; B* getPtrB(int *x) { return 0; }; B* getPtrB(B **b) { return 0; }; -void setupB() { +void setupB(bool x) { B b1; B b2(b1); B b3 = { 5, &b3.x }; @@ -255,6 +266,7 @@ void setupB() { 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 b24 = std::move(x ? b23 : (18, b24)); // expected-warning {{variable 'b24' is uninitialized when used within its own initialization}} } B b1; @@ -286,6 +298,7 @@ const B b20(b20); // expected-warning {{variable 'b20' is uninitialized when us 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 b24 = std::move(x ? b23 : (18, b24)); // expected-warning {{variable 'b24' is uninitialized when used within its own initialization}} // Also test similar constructs in a field's initializer. struct S { @@ -412,6 +425,8 @@ namespace { E(char (*)[12]) : a((b + c, c, a)) {} // expected-warning {{field 'a' is uninitialized when used here}} E(char (*)[13]) : a((a, a, a, a)) {} // expected-warning {{field 'a' is uninitialized when used here}} E(char (*)[14]) : a((b, c, c)) {} + E(char (*)[15]) : a(b ?: a) {} // expected-warning {{field 'a' is uninitialized when used here}} + E(char (*)[16]) : a(a ?: b) {} // expected-warning {{field 'a' is uninitialized when used here}} }; struct F { @@ -463,6 +478,12 @@ namespace statics { static int l = k ? l : l; // expected-warning 2{{variable 'l' is uninitialized when used within its own initialization}} static int m = 1 + (k ? m : m); // expected-warning 2{{variable 'm' is uninitialized when used within its own initialization}} static int n = -n; // expected-warning {{variable 'n' is uninitialized when used within its own initialization}} + static int o = std::move(o); // expected-warning {{variable 'o' is uninitialized when used within its own initialization}} + static const int p = std::move(p); // expected-warning {{variable 'p' is uninitialized when used within its own initialization}} + static int q = moved(std::move(q)); // expected-warning {{variable 'q' is uninitialized when used within its own initialization}} + static int r = std::move((p ? q : (18, r))); // expected-warning {{variable 'r' is uninitialized when used within its own initialization}} + static int s = r ?: s; // expected-warning {{variable 's' is uninitialized when used within its own initialization}} + static int t = t ?: s; // expected-warning {{variable 't' is uninitialized when used within its own initialization}} void test() { static int a = a; // no-warning: used to signal intended lack of initialization. @@ -483,6 +504,12 @@ namespace statics { static int l = k ? l : l; // expected-warning 2{{static variable 'l' is suspiciously used within its own initialization}} static int m = 1 + (k ? m : m); // expected-warning 2{{static variable 'm' is suspiciously used within its own initialization}} static int n = -n; // expected-warning {{static variable 'n' is suspiciously used within its own initialization}} + static int o = std::move(o); // expected-warning {{static variable 'o' is suspiciously used within its own initialization}} + static const int p = std::move(p); // expected-warning {{static variable 'p' is suspiciously used within its own initialization}} + static int q = moved(std::move(q)); // expected-warning {{static variable 'q' is suspiciously used within its own initialization}} + static int r = std::move((p ? q : (18, r))); // expected-warning {{static variable 'r' is suspiciously used within its own initialization}} + static int s = r ?: s; // expected-warning {{static variable 's' is suspiciously used within its own initialization}} + static int t = t ?: s; // expected-warning {{static variable 't' is suspiciously used within its own initialization}} for (;;) { static int a = a; // no-warning: used to signal intended lack of initialization. static int b = b + 1; // expected-warning {{static variable 'b' is suspiciously used within its own initialization}} @@ -502,6 +529,12 @@ namespace statics { static int l = k ? l : l; // expected-warning 2{{static variable 'l' is suspiciously used within its own initialization}} static int m = 1 + (k ? m : m); // expected-warning 2{{static variable 'm' is suspiciously used within its own initialization}} static int n = -n; // expected-warning {{static variable 'n' is suspiciously used within its own initialization}} + static int o = std::move(o); // expected-warning {{static variable 'o' is suspiciously used within its own initialization}} + static const int p = std::move(p); // expected-warning {{static variable 'p' is suspiciously used within its own initialization}} + static int q = moved(std::move(q)); // expected-warning {{static variable 'q' is suspiciously used within its own initialization}} + static int r = std::move((p ? q : (18, r))); // expected-warning {{static variable 'r' is suspiciously used within its own initialization}} + static int s = r ?: s; // expected-warning {{static variable 's' is suspiciously used within its own initialization}} + static int t = t ?: s; // expected-warning {{static variable 't' is suspiciously used within its own initialization}} } } } @@ -530,13 +563,15 @@ namespace references { int &b(b); // expected-warning{{reference 'b' is not yet bound to a value when used within its own initialization}} int &c = a ? b : c; // expected-warning{{reference 'c' is not yet bound to a value when used within its own initialization}} int &d{d}; // expected-warning{{reference 'd' is not yet bound to a value when used within its own initialization}} + int &e = d ?: e; // expected-warning{{reference 'e' is not yet bound to a value when used within its own initialization}} + int &f = f ?: d; // expected-warning{{reference 'f' is not yet bound to a value when used within its own initialization}} struct S { S() : a(a) {} // expected-warning{{reference 'a' is not yet bound to a value when used here}} int &a; }; - void f() { + void test() { int &a = a; // expected-warning{{reference 'a' is not yet bound to a value when used within its own initialization}} int &b(b); // expected-warning{{reference 'b' is not yet bound to a value when used within its own initialization}} int &c = a ? b : c; // expected-warning{{reference 'c' is not yet bound to a value when used within its own initialization}} @@ -586,6 +621,7 @@ namespace lambdas { } namespace record_fields { + bool x; struct A { A() {} A get(); @@ -614,9 +650,10 @@ namespace record_fields { 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}} + B(char (*)[13]) : a(std::move(x ? a : (25, a))) {} // expected-warning 2{{uninitialized}} }; struct C { - C() {} // expected-note8{{in this constructor}} + C() {} // expected-note9{{in this constructor}} A a1 = a1; // expected-warning {{uninitialized}} A a2 = a2.get(); // expected-warning {{uninitialized}} A a3 = a3.num(); @@ -630,8 +667,9 @@ namespace record_fields { 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}} + A a14 = std::move(x ? a13 : (22, a14)); // expected-warning {{uninitialized}} }; - struct D { // expected-note8{{in the implicit default constructor}} + struct D { // expected-note9{{in the implicit default constructor}} A a1 = a1; // expected-warning {{uninitialized}} A a2 = a2.get(); // expected-warning {{uninitialized}} A a3 = a3.num(); @@ -645,6 +683,7 @@ namespace record_fields { 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}} + A a14 = std::move(x ? a13 : (22, a14)); // expected-warning {{uninitialized}} }; D d; struct E { @@ -661,6 +700,7 @@ namespace record_fields { A a11 = std::move(a11); A a12 = A(std::move(a12)); A a13 = rref(std::move(a13)); + A a14 = std::move(x ? a13 : (22, a14)); }; }