Index: lib/StaticAnalyzer/Checkers/MoveChecker.cpp =================================================================== --- lib/StaticAnalyzer/Checkers/MoveChecker.cpp +++ lib/StaticAnalyzer/Checkers/MoveChecker.cpp @@ -26,7 +26,6 @@ using namespace ento; namespace { - struct RegionState { private: enum Kind { Moved, Reported } K; @@ -64,6 +63,14 @@ enum MisuseKind { MK_FunCall, MK_Copy, MK_Move, MK_Dereference }; enum StdObjectKind { SK_NonStd, SK_Unsafe, SK_Safe, SK_SmartPtr }; + enum AggressivenessKind { // In any case, don't warn after a reset. + AK_Invalid = -1, + AK_KnownsOnly = 0, // Warn only about known move-unsafe classes. + AK_KnownsAndLocals = 1, // Also warn about all local objects. + AK_All = 2, // Warn on any use-after-move. + AK_NumKinds = AK_All + }; + static bool misuseCausesCrash(MisuseKind MK) { return MK == MK_Dereference; } @@ -117,8 +124,9 @@ // In aggressive mode, warn on any use-after-move because the user has // intentionally asked us to completely eliminate use-after-move // in his code. - return IsAggressive || OK.IsLocal - || OK.StdKind == SK_Unsafe || OK.StdKind == SK_SmartPtr; + return (Aggressiveness == AK_All) || + (Aggressiveness >= AK_KnownsAndLocals && OK.IsLocal) || + OK.StdKind == SK_Unsafe || OK.StdKind == SK_SmartPtr; } // Some objects only suffer from some kinds of misuses, but we need to track @@ -127,8 +135,9 @@ // Additionally, only warn on smart pointers when they are dereferenced (or // local or we are aggressive). return shouldBeTracked(OK) && - (IsAggressive || OK.IsLocal - || OK.StdKind != SK_SmartPtr || MK == MK_Dereference); + ((Aggressiveness == AK_All) || + (Aggressiveness >= AK_KnownsAndLocals && OK.IsLocal) || + OK.StdKind != SK_SmartPtr || MK == MK_Dereference); } // Obtains ObjectKind of an object. Because class declaration cannot always @@ -173,10 +182,17 @@ bool Found; }; - bool IsAggressive = false; + AggressivenessKind Aggressiveness; public: - void setAggressiveness(bool Aggressive) { IsAggressive = Aggressive; } + void setAggressiveness(StringRef Str) { + Aggressiveness = + llvm::StringSwitch(Str) + .Case("KnownsOnly", AK_KnownsOnly) + .Case("KnownsAndLocals", AK_KnownsAndLocals) + .Case("All", AK_All) + .Default(AK_KnownsAndLocals); // A sane default. + }; private: mutable std::unique_ptr BT; @@ -717,6 +733,6 @@ } void ento::registerMoveChecker(CheckerManager &mgr) { MoveChecker *chk = mgr.registerChecker(); - chk->setAggressiveness(mgr.getAnalyzerOptions().getCheckerBooleanOption( - "Aggressive", false, chk)); + chk->setAggressiveness( + mgr.getAnalyzerOptions().getCheckerStringOption("WarnOn", "", chk)); } Index: test/Analysis/use-after-move.cpp =================================================================== --- test/Analysis/use-after-move.cpp +++ test/Analysis/use-after-move.cpp @@ -9,12 +9,22 @@ // RUN: %clang_analyze_cc1 -analyzer-checker=alpha.cplusplus.Move -verify %s\ // RUN: -std=c++11 -analyzer-output=text -analyzer-config eagerly-assume=false\ // RUN: -analyzer-config exploration_strategy=unexplored_first_queue\ -// RUN: -analyzer-config alpha.cplusplus.Move:Aggressive=true -DAGGRESSIVE\ +// RUN: -analyzer-config alpha.cplusplus.Move:WarnOn=KnownsOnly -DPEACEFUL\ // RUN: -analyzer-checker debug.ExprInspection // RUN: %clang_analyze_cc1 -analyzer-checker=alpha.cplusplus.Move -verify %s\ // RUN: -std=c++11 -analyzer-output=text -analyzer-config eagerly-assume=false\ // RUN: -analyzer-config exploration_strategy=dfs -DDFS=1\ -// RUN: -analyzer-config alpha.cplusplus.Move:Aggressive=true -DAGGRESSIVE\ +// RUN: -analyzer-config alpha.cplusplus.Move:WarnOn=KnownsOnly -DPEACEFUL\ +// RUN: -analyzer-checker debug.ExprInspection +// RUN: %clang_analyze_cc1 -analyzer-checker=alpha.cplusplus.Move -verify %s\ +// RUN: -std=c++11 -analyzer-output=text -analyzer-config eagerly-assume=false\ +// RUN: -analyzer-config exploration_strategy=unexplored_first_queue\ +// RUN: -analyzer-config alpha.cplusplus.Move:WarnOn=All -DAGGRESSIVE\ +// RUN: -analyzer-checker debug.ExprInspection +// RUN: %clang_analyze_cc1 -analyzer-checker=alpha.cplusplus.Move -verify %s\ +// RUN: -std=c++11 -analyzer-output=text -analyzer-config eagerly-assume=false\ +// RUN: -analyzer-config exploration_strategy=dfs -DDFS=1\ +// RUN: -analyzer-config alpha.cplusplus.Move:WarnOn=All -DAGGRESSIVE\ // RUN: -analyzer-checker debug.ExprInspection #include "Inputs/system-header-simulator-cxx.h" @@ -119,18 +129,33 @@ void simpleMoveCtorTest() { { A a; - A b = std::move(a); // expected-note {{Object 'a' is moved}} - a.foo(); // expected-warning {{Method called on moved-from object 'a'}} expected-note {{Method called on moved-from object 'a'}} + A b = std::move(a); + a.foo(); +#ifndef PEACEFUL + // expected-note@-3 {{Object 'a' is moved}} + // expected-warning@-3 {{Method called on moved-from object 'a'}} + // expected-note@-4 {{Method called on moved-from object 'a'}} +#endif } { A a; - A b = std::move(a); // expected-note {{Object 'a' is moved}} - b = a; // expected-warning {{Moved-from object 'a' is copied}} expected-note {{Moved-from object 'a' is copied}} + A b = std::move(a); + b = a; +#ifndef PEACEFUL + // expected-note@-3 {{Object 'a' is moved}} + // expected-warning@-3 {{Moved-from object 'a' is copied}} + // expected-note@-4 {{Moved-from object 'a' is copied}} +#endif } { A a; - A b = std::move(a); // expected-note {{Object 'a' is moved}} - b = std::move(a); // expected-warning {{Moved-from object 'a' is moved}} expected-note {{Moved-from object 'a' is moved}} + A b = std::move(a); + b = std::move(a); +#ifndef PEACEFUL + // expected-note@-3 {{Object 'a' is moved}} + // expected-warning@-3 {{Moved-from object 'a' is moved}} + // expected-note@-4 {{Moved-from object 'a' is moved}} +#endif } } @@ -138,20 +163,35 @@ { A a; A b; - b = std::move(a); // expected-note {{Object 'a' is moved}} - a.foo(); // expected-warning {{Method called on moved-from object 'a'}} expected-note {{Method called on moved-from object 'a'}} + b = std::move(a); + a.foo(); +#ifndef PEACEFUL + // expected-note@-3 {{Object 'a' is moved}} + // expected-warning@-3 {{Method called on moved-from object 'a'}} + // expected-note@-4 {{Method called on moved-from object 'a'}} +#endif } { A a; A b; - b = std::move(a); // expected-note {{Object 'a' is moved}} - A c(a); // expected-warning {{Moved-from object 'a' is copied}} expected-note {{Moved-from object 'a' is copied}} + b = std::move(a); + A c(a); +#ifndef PEACEFUL + // expected-note@-3 {{Object 'a' is moved}} + // expected-warning@-3 {{Moved-from object 'a' is copied}} + // expected-note@-4 {{Moved-from object 'a' is copied}} +#endif } { A a; A b; - b = std::move(a); // expected-note {{Object 'a' is moved}} - A c(std::move(a)); // expected-warning {{Moved-from object 'a' is moved}} expected-note {{Moved-from object 'a' is moved}} + b = std::move(a); + A c(std::move(a)); +#ifndef PEACEFUL + // expected-note@-3 {{Object 'a' is moved}} + // expected-warning@-3 {{Moved-from object 'a' is moved}} + // expected-note@-4 {{Moved-from object 'a' is moved}} +#endif } } @@ -160,8 +200,13 @@ A a; }; A a; - S s{std::move(a)}; // expected-note {{Object 'a' is moved}} - a.foo(); // expected-warning {{Method called on moved-from object 'a'}} expected-note {{Method called on moved-from object 'a'}} + S s{std::move(a)}; + a.foo(); +#ifndef PEACEFUL + // expected-note@-3 {{Object 'a' is moved}} + // expected-warning@-3 {{Method called on moved-from object 'a'}} + // expected-note@-4 {{Method called on moved-from object 'a'}} +#endif } // Don't report a bug if the variable was assigned to in the meantime. @@ -175,23 +220,43 @@ } { A a; - if (i == 1) { // expected-note {{Assuming 'i' is not equal to 1}} expected-note {{Taking false branch}} - // expected-note@-1 {{Assuming 'i' is not equal to 1}} expected-note@-1 {{Taking false branch}} + if (i == 1) { +#ifndef PEACEFUL + // expected-note@-2 {{Assuming 'i' is not equal to 1}} + // expected-note@-3 {{Taking false branch}} + // And the other report: + // expected-note@-5 {{Assuming 'i' is not equal to 1}} + // expected-note@-6 {{Taking false branch}} +#endif A b; b = std::move(a); a = A(); } - if (i == 2) { // expected-note {{Assuming 'i' is not equal to 2}} expected-note {{Taking false branch}} - //expected-note@-1 {{Assuming 'i' is not equal to 2}} expected-note@-1 {{Taking false branch}} + if (i == 2) { +#ifndef PEACEFUL + // expected-note@-2 {{Assuming 'i' is not equal to 2}} + // expected-note@-3 {{Taking false branch}} + // And the other report: + // expected-note@-5 {{Assuming 'i' is not equal to 2}} + // expected-note@-6 {{Taking false branch}} +#endif a.foo(); // no-warning } } { A a; - if (i == 1) { // expected-note {{Taking false branch}} expected-note {{Taking false branch}} + if (i == 1) { +#ifndef PEACEFUL + // expected-note@-2 {{Taking false branch}} + // expected-note@-3 {{Taking false branch}} +#endif std::move(a); } - if (i == 2) { // expected-note {{Taking false branch}} expected-note {{Taking false branch}} + if (i == 2) { +#ifndef PEACEFUL + // expected-note@-2 {{Taking false branch}} + // expected-note@-3 {{Taking false branch}} +#endif a = A(); a.foo(); } @@ -209,19 +274,36 @@ A b; b = std::move(a); a = A(); - b = std::move(a); // expected-note {{Object 'a' is moved}} - a.foo(); // expected-warning {{Method called on moved-from object 'a'}} expected-note {{Method called on moved-from object 'a'}} + b = std::move(a); + a.foo(); +#ifndef PEACEFUL + // expected-note@-3 {{Object 'a' is moved}} + // expected-warning@-3 {{Method called on moved-from object 'a'}} + // expected-note@-4 {{Method called on moved-from object 'a'}} +#endif } // If a path exist where we not reinitialize the variable we report a bug. { A a; A b; - b = std::move(a); // expected-note {{Object 'a' is moved}} - if (i < 10) { // expected-note {{Assuming 'i' is >= 10}} expected-note {{Taking false branch}} + b = std::move(a); +#ifndef PEACEFUL + // expected-note@-2 {{Object 'a' is moved}} +#endif + if (i < 10) { +#ifndef PEACEFUL + // expected-note@-2 {{Assuming 'i' is >= 10}} + // expected-note@-3 {{Taking false branch}} +#endif a = A(); } - if (i > 5) { // expected-note {{Taking true branch}} - a.foo(); // expected-warning {{Method called on moved-from object 'a'}} expected-note {{Method called on moved-from object 'a'}} + if (i > 5) { + a.foo(); +#ifndef PEACEFUL + // expected-note@-3 {{Taking true branch}} + // expected-warning@-3 {{Method called on moved-from object 'a'}} + // expected-note@-4 {{Method called on moved-from object 'a'}} +#endif } } } @@ -236,79 +318,117 @@ void loopTest() { { A a; - for (int i = 0; i < bignum(); i++) { // expected-note {{Loop condition is false. Execution jumps to the end of the function}} + for (int i = 0; i < bignum(); i++) { +#ifndef PEACEFUL + // expected-note@-2 {{Loop condition is false. Execution jumps to the end of the function}} +#endif rightRefCall(std::move(a)); // no-warning } } { A a; - for (int i = 0; i < 2; i++) { // expected-note {{Loop condition is true. Entering loop body}} - //expected-note@-1 {{Loop condition is true. Entering loop body}} - //expected-note@-2 {{Loop condition is false. Execution jumps to the end of the function}} + for (int i = 0; i < 2; i++) { +#ifndef PEACEFUL + // expected-note@-2 {{Loop condition is true. Entering loop body}} + // expected-note@-3 {{Loop condition is true. Entering loop body}} + // expected-note@-4 {{Loop condition is false. Execution jumps to the end of the function}} +#endif rightRefCall(std::move(a)); // no-warning } } { A a; - for (int i = 0; i < bignum(); i++) { // expected-note {{Loop condition is false. Execution jumps to the end of the function}} + for (int i = 0; i < bignum(); i++) { +#ifndef PEACEFUL + // expected-note@-2 {{Loop condition is false. Execution jumps to the end of the function}} +#endif leftRefCall(a); // no-warning } } { A a; - for (int i = 0; i < 2; i++) { // expected-note {{Loop condition is true. Entering loop body}} - //expected-note@-1 {{Loop condition is true. Entering loop body}} - //expected-note@-2 {{Loop condition is false. Execution jumps to the end of the function}} + for (int i = 0; i < 2; i++) { +#ifndef PEACEFUL + // expected-note@-2 {{Loop condition is true. Entering loop body}} + // expected-note@-3 {{Loop condition is true. Entering loop body}} + // expected-note@-4 {{Loop condition is false. Execution jumps to the end of the function}} +#endif leftRefCall(a); // no-warning } } { A a; - for (int i = 0; i < bignum(); i++) { // expected-note {{Loop condition is false. Execution jumps to the end of the function}} + for (int i = 0; i < bignum(); i++) { +#ifndef PEACEFUL + // expected-note@-2 {{Loop condition is false. Execution jumps to the end of the function}} +#endif constCopyOrMoveCall(a); // no-warning } } { A a; - for (int i = 0; i < 2; i++) { // expected-note {{Loop condition is true. Entering loop body}} - //expected-note@-1 {{Loop condition is true. Entering loop body}} - //expected-note@-2 {{Loop condition is false. Execution jumps to the end of the function}} + for (int i = 0; i < 2; i++) { +#ifndef PEACEFUL + // expected-note@-2 {{Loop condition is true. Entering loop body}} + // expected-note@-3 {{Loop condition is true. Entering loop body}} + // expected-note@-4 {{Loop condition is false. Execution jumps to the end of the function}} +#endif constCopyOrMoveCall(a); // no-warning } } { A a; - for (int i = 0; i < bignum(); i++) { // expected-note {{Loop condition is false. Execution jumps to the end of the function}} + for (int i = 0; i < bignum(); i++) { +#ifndef PEACEFUL + // expected-note@-2 {{Loop condition is false. Execution jumps to the end of the function}} +#endif moveInsideFunctionCall(a); // no-warning } } { A a; - for (int i = 0; i < 2; i++) { // expected-note {{Loop condition is true. Entering loop body}} - //expected-note@-1 {{Loop condition is true. Entering loop body}} - //expected-note@-2 {{Loop condition is false. Execution jumps to the end of the function}} + for (int i = 0; i < 2; i++) { +#ifndef PEACEFUL + // expected-note@-2 {{Loop condition is true. Entering loop body}} + // expected-note@-3 {{Loop condition is true. Entering loop body}} + // expected-note@-4 {{Loop condition is false. Execution jumps to the end of the function}} +#endif moveInsideFunctionCall(a); // no-warning } } { A a; - for (int i = 0; i < bignum(); i++) { // expected-note {{Loop condition is false. Execution jumps to the end of the function}} + for (int i = 0; i < bignum(); i++) { +#ifndef PEACEFUL + // expected-note@-2 {{Loop condition is false. Execution jumps to the end of the function}} +#endif copyOrMoveCall(a); // no-warning } } { A a; - for (int i = 0; i < 2; i++) { // expected-note {{Loop condition is true.}} - //expected-note@-1 {{Loop condition is true. Entering loop body}} - //expected-note@-2 {{Loop condition is false. Execution jumps to the end of the function}} + for (int i = 0; i < 2; i++) { +#ifndef PEACEFUL + // expected-note@-2 {{Loop condition is true. Entering loop body}} + // expected-note@-3 {{Loop condition is true. Entering loop body}} + // expected-note@-4 {{Loop condition is false. Execution jumps to the end of the function}} +#endif copyOrMoveCall(a); // no-warning } } { A a; - for (int i = 0; i < bignum(); i++) { // expected-note {{Loop condition is true. Entering loop body}} expected-note {{Loop condition is true. Entering loop body}} - constCopyOrMoveCall(std::move(a)); // expected-warning {{Moved-from object 'a' is moved}} expected-note {{Moved-from object 'a' is moved}} - // expected-note@-1 {{Object 'a' is moved}} + for (int i = 0; i < bignum(); i++) { +#ifndef PEACEFUL + // expected-note@-2 {{Loop condition is true. Entering loop body}} + // expected-note@-3 {{Loop condition is true. Entering loop body}} +#endif + constCopyOrMoveCall(std::move(a)); +#ifndef PEACEFUL + // expected-note@-2 {{Object 'a' is moved}} + // expected-warning@-3 {{Moved-from object 'a' is moved}} + // expected-note@-4 {{Moved-from object 'a' is moved}} +#endif } } @@ -326,14 +446,21 @@ } } -//report a usage of a moved-from object only at the first use +// Report a usage of a moved-from object only at the first use. void uniqueTest(bool cond) { A a(42, 42.0); A b; - b = std::move(a); // expected-note {{Object 'a' is moved}} + b = std::move(a); - if (cond) { // expected-note {{Assuming 'cond' is not equal to 0}} expected-note {{Taking true branch}} - a.foo(); // expected-warning {{Method called on moved-from object 'a'}} expected-note {{Method called on moved-from object 'a'}} + if (cond) { + a.foo(); +#ifndef PEACEFUL + // expected-note@-5 {{Object 'a' is moved}} + // expected-note@-4 {{Assuming 'cond' is not equal to 0}} + // expected-note@-5 {{Taking true branch}} + // expected-warning@-5 {{Method called on moved-from object 'a'}} + // expected-note@-6 {{Method called on moved-from object 'a'}} +#endif } if (cond) { a.bar(); // no-warning @@ -344,8 +471,13 @@ void uniqueTest2() { A a; - A a1 = std::move(a); // expected-note {{Object 'a' is moved}} - a.foo(); // expected-warning {{Method called on moved-from object 'a'}} expected-note {{Method called on moved-from object 'a'}} + A a1 = std::move(a); + a.foo(); +#ifndef PEACEFUL + // expected-note@-3 {{Object 'a' is moved}} + // expected-warning@-3 {{Method called on moved-from object 'a'}} + // expected-note@-4 {{Method called on moved-from object 'a'}} +#endif A a2 = std::move(a); // no-warning a.foo(); // no-warning @@ -355,12 +487,19 @@ //even on moved-from objects. void moveSafeFunctionsTest() { A a; - A b = std::move(a); // expected-note {{Object 'a' is moved}} + A b = std::move(a); +#ifndef PEACEFUL + // expected-note@-2 {{Object 'a' is moved}} +#endif a.empty(); // no-warning a.isEmpty(); // no-warning (void)a; // no-warning (bool)a; // expected-warning {{expression result unused}} - a.foo(); // expected-warning {{Method called on moved-from object 'a'}} expected-note {{Method called on moved-from object 'a'}} + a.foo(); +#ifndef PEACEFUL + // expected-warning@-2 {{Method called on moved-from object 'a'}} + // expected-note@-3 {{Method called on moved-from object 'a'}} +#endif } void moveStateResetFunctionsTest() { @@ -496,7 +635,11 @@ // Don't warn if the use is in a different branch from the move. { A a; - if (i > 0) { // expected-note {{Assuming 'i' is > 0}} expected-note {{Taking true branch}} + if (i > 0) { +#ifndef PEACEFUL + // expected-note@-2 {{Assuming 'i' is > 0}} + // expected-note@-3 {{Taking true branch}} +#endif A b; b = std::move(a); } else { @@ -506,24 +649,40 @@ // Same thing, but with a ternary operator. { A a, b; - i > 0 ? (void)(b = std::move(a)) : a.bar(); // no-warning // expected-note {{'?' condition is true}} + i > 0 ? (void)(b = std::move(a)) : a.bar(); // no-warning +#ifndef PEACEFUL + // expected-note@-2 {{'?' condition is true}} +#endif } // A variation on the theme above. { A a; + a.foo() > 0 ? a.foo() : A(std::move(a)).foo(); #ifdef DFS - a.foo() > 0 ? a.foo() : A(std::move(a)).foo(); // expected-note {{Assuming the condition is false}} expected-note {{'?' condition is false}} + #ifndef PEACEFUL + // expected-note@-3 {{Assuming the condition is false}} + // expected-note@-4 {{'?' condition is false}} + #endif #else - a.foo() > 0 ? a.foo() : A(std::move(a)).foo(); // expected-note {{Assuming the condition is true}} expected-note {{'?' condition is true}} + #ifndef PEACEFUL + // expected-note@-8 {{Assuming the condition is true}} + // expected-note@-9 {{'?' condition is true}} + #endif #endif } // Same thing, but with a switch statement. { A a, b; - switch (i) { // expected-note {{Control jumps to 'case 1:'}} + switch (i) { +#ifndef PEACEFUL + // expected-note@-2 {{Control jumps to 'case 1:'}} +#endif case 1: b = std::move(a); // no-warning - break; // expected-note {{Execution jumps to the end of the function}} + break; +#ifndef PEACEFUL + // expected-note@-2 {{Execution jumps to the end of the function}} +#endif case 2: a.foo(); // no-warning break; @@ -532,11 +691,21 @@ // However, if there's a fallthrough, we do warn. { A a, b; - switch (i) { // expected-note {{Control jumps to 'case 1:'}} + switch (i) { +#ifndef PEACEFUL + // expected-note@-2 {{Control jumps to 'case 1:'}} +#endif case 1: - b = std::move(a); // expected-note {{Object 'a' is moved}} + b = std::move(a); +#ifndef PEACEFUL + // expected-note@-2 {{Object 'a' is moved}} +#endif case 2: - a.foo(); // expected-warning {{Method called on moved-from object}} expected-note {{Method called on moved-from object 'a'}} + a.foo(); +#ifndef PEACEFUL + // expected-warning@-2 {{Method called on moved-from object}} + // expected-note@-3 {{Method called on moved-from object 'a'}} +#endif break; } } @@ -551,14 +720,22 @@ } void interFunTest1(A &a) { - a.bar(); // expected-warning {{Method called on moved-from object 'a'}} expected-note {{Method called on moved-from object 'a'}} + a.bar(); +#ifndef PEACEFUL + // expected-warning@-2 {{Method called on moved-from object 'a'}} + // expected-note@-3 {{Method called on moved-from object 'a'}} +#endif } void interFunTest2() { A a; A b; - b = std::move(a); // expected-note {{Object 'a' is moved}} - interFunTest1(a); // expected-note {{Calling 'interFunTest1'}} + b = std::move(a); + interFunTest1(a); +#ifndef PEACEFUL + // expected-note@-3 {{Object 'a' is moved}} + // expected-note@-3 {{Calling 'interFunTest1'}} +#endif } void foobar(A a, int i); @@ -566,8 +743,12 @@ void paramEvaluateOrderTest() { A a; - foobar(std::move(a), a.getI()); // expected-warning {{Method called on moved-from object 'a'}} expected-note {{Method called on moved-from object 'a'}} - // expected-note@-1 {{Object 'a' is moved}} + foobar(std::move(a), a.getI()); +#ifndef PEACEFUL + // expected-note@-2 {{Object 'a' is moved}} + // expected-warning@-3 {{Method called on moved-from object 'a'}} + // expected-note@-4 {{Method called on moved-from object 'a'}} +#endif //FALSE NEGATIVE since parameters evaluate order is undefined foobar(a.getI(), std::move(a)); //no-warning @@ -590,10 +771,14 @@ { A a; A b; - b = std::move(a); // expected-note{{Object 'a' is moved}} + b = std::move(a); not_known_pass_by_const_ref(a); - a.foo(); // expected-warning{{Method called on moved-from object 'a'}} - // expected-note@-1{{Method called on moved-from object 'a'}} + a.foo(); +#ifndef PEACEFUL + // expected-note@-4{{Object 'a' is moved}} + // expected-warning@-3{{Method called on moved-from object 'a'}} + // expected-note@-4 {{Method called on moved-from object 'a'}} +#endif } { A a; @@ -612,10 +797,14 @@ { A a; A b; - b = std::move(a); // expected-note{{Object 'a' is moved}} + b = std::move(a); not_known_pass_by_const_ptr(&a); - a.foo(); // expected-warning{{Method called on moved-from object 'a'}} - // expected-note@-1{{Method called on moved-from object 'a'}} + a.foo(); +#ifndef PEACEFUL + // expected-note@-4{{Object 'a' is moved}} + // expected-warning@-3{{Method called on moved-from object 'a'}} + // expected-note@-4 {{Method called on moved-from object 'a'}} +#endif } } @@ -628,8 +817,12 @@ } { A a; - A a1 = std::move(a), a2 = a; // expected-warning {{Moved-from object 'a' is copied}} expected-note {{Moved-from object 'a' is copied}} - // expected-note@-1 {{Object 'a' is moved}} + A a1 = std::move(a), a2 = a; +#ifndef PEACEFUL + // expected-note@-2 {{Object 'a' is moved}} + // expected-warning@-3 {{Moved-from object 'a' is copied}} + // expected-note@-4 {{Moved-from object 'a' is copied}} +#endif } } @@ -637,43 +830,74 @@ void logicalOperatorsSequenceTest() { { A a; - if (a.foo() > 0 && A(std::move(a)).foo() > 0) { // expected-note {{Assuming the condition is false}} expected-note {{Assuming the condition is false}} - // expected-note@-1 {{Left side of '&&' is false}} expected-note@-1 {{Left side of '&&' is false}} - //expected-note@-2 {{Taking false branch}} expected-note@-2 {{Taking false branch}} + if (a.foo() > 0 && A(std::move(a)).foo() > 0) { +#ifndef PEACEFUL + // expected-note@-2 {{Assuming the condition is false}} + // expected-note@-3 {{Left side of '&&' is false}} + // expected-note@-4 {{Taking false branch}} + // And the other report: + // expected-note@-6 {{Assuming the condition is false}} + // expected-note@-7 {{Left side of '&&' is false}} + // expected-note@-8 {{Taking false branch}} A().bar(); +#endif } } // A variation: Negate the result of the && (which pushes the && further down // into the AST). { A a; - if (!(a.foo() > 0 && A(std::move(a)).foo() > 0)) { // expected-note {{Assuming the condition is false}} expected-note {{Assuming the condition is false}} - // expected-note@-1 {{Left side of '&&' is false}} expected-note@-1 {{Left side of '&&' is false}} - // expected-note@-2 {{Taking true branch}} expected-note@-2 {{Taking true branch}} + if (!(a.foo() > 0 && A(std::move(a)).foo() > 0)) { +#ifndef PEACEFUL + // expected-note@-2 {{Assuming the condition is false}} + // expected-note@-3 {{Left side of '&&' is false}} + // expected-note@-4 {{Taking true branch}} + // And the other report: + // expected-note@-6 {{Assuming the condition is false}} + // expected-note@-7 {{Left side of '&&' is false}} + // expected-note@-8 {{Taking true branch}} +#endif A().bar(); } } { A a; - if (A(std::move(a)).foo() > 0 && a.foo() > 0) { // expected-warning {{Method called on moved-from object 'a'}} expected-note {{Method called on moved-from object 'a'}} - // expected-note@-1 {{Object 'a' is moved}} expected-note@-1 {{Assuming the condition is true}} expected-note@-1 {{Assuming the condition is false}} - // expected-note@-2 {{Left side of '&&' is false}} expected-note@-2 {{Left side of '&&' is true}} - // expected-note@-3 {{Taking false branch}} + if (A(std::move(a)).foo() > 0 && a.foo() > 0) { +#ifndef PEACEFUL + // expected-note@-2 {{Object 'a' is moved}} + // expected-note@-3 {{Assuming the condition is true}} + // expected-note@-4 {{Left side of '&&' is true}} + // expected-warning@-5 {{Method called on moved-from object 'a'}} + // expected-note@-6 {{Method called on moved-from object 'a'}} + // And the other report: + // expected-note@-8 {{Assuming the condition is false}} + // expected-note@-9 {{Left side of '&&' is false}} + // expected-note@-10{{Taking false branch}} +#endif A().bar(); } } { A a; - if (a.foo() > 0 || A(std::move(a)).foo() > 0) { // expected-note {{Assuming the condition is true}} - //expected-note@-1 {{Left side of '||' is true}} - //expected-note@-2 {{Taking true branch}} + if (a.foo() > 0 || A(std::move(a)).foo() > 0) { +#ifndef PEACEFUL + // expected-note@-2 {{Assuming the condition is true}} + // expected-note@-3 {{Left side of '||' is true}} + // expected-note@-4 {{Taking true branch}} +#endif A().bar(); } } { A a; - if (A(std::move(a)).foo() > 0 || a.foo() > 0) { // expected-warning {{Method called on moved-from object 'a'}} expected-note {{Method called on moved-from object 'a'}} - // expected-note@-1 {{Object 'a' is moved}} expected-note@-1 {{Assuming the condition is false}} expected-note@-1 {{Left side of '||' is false}} + if (A(std::move(a)).foo() > 0 || a.foo() > 0) { +#ifndef PEACEFUL + // expected-note@-2 {{Object 'a' is moved}} + // expected-note@-3 {{Assuming the condition is false}} + // expected-note@-4 {{Left side of '||' is false}} + // expected-warning@-5 {{Method called on moved-from object 'a'}} + // expected-note@-6 {{Method called on moved-from object 'a'}} +#endif A().bar(); } } @@ -729,14 +953,24 @@ // Don't report a misuse if any SuperRegion is already reported. { A a; - A a1 = std::move(a); // expected-note {{Object 'a' is moved}} - a.foo(); // expected-warning {{Method called on moved-from object 'a'}} expected-note {{Method called on moved-from object 'a'}} + A a1 = std::move(a); + a.foo(); +#ifndef PEACEFUL + // expected-note@-3 {{Object 'a' is moved}} + // expected-warning@-3 {{Method called on moved-from object 'a'}} + // expected-note@-4 {{Method called on moved-from object 'a'}} +#endif a.b.foo(); // no-warning } { C c; - C c1 = std::move(c); // expected-note {{Object 'c' is moved}} - c.foo(); // expected-warning {{Method called on moved-from object 'c'}} expected-note {{Method called on moved-from object 'c'}} + C c1 = std::move(c); + c.foo(); +#ifndef PEACEFUL + // expected-note@-3 {{Object 'c' is moved}} + // expected-warning@-3 {{Method called on moved-from object 'c'}} + // expected-note@-4 {{Method called on moved-from object 'c'}} +#endif c.b.foo(); // no-warning } } @@ -757,8 +991,13 @@ void reportSuperClass() { C c; - C c1 = std::move(c); // expected-note {{Object 'c' is moved}} - c.foo(); // expected-warning {{Method called on moved-from object 'c'}} expected-note {{Method called on moved-from object 'c'}} + C c1 = std::move(c); + c.foo(); +#ifndef PEACEFUL + // expected-note@-3 {{Object 'c' is moved}} + // expected-warning@-3 {{Method called on moved-from object 'c'}} + // expected-note@-4 {{Method called on moved-from object 'c'}} +#endif C c2 = c; // no-warning } @@ -872,17 +1111,25 @@ }; void localRValueMove(A &&a) { - A b = std::move(a); // expected-note{{Object 'a' is moved}} - a.foo(); // expected-warning{{Method called on moved-from object 'a'}} - // expected-note@-1{{Method called on moved-from object 'a'}} + A b = std::move(a); + a.foo(); +#ifndef PEACEFUL + // expected-note@-3 {{Object 'a' is moved}} + // expected-warning@-3 {{Method called on moved-from object 'a'}} + // expected-note@-4 {{Method called on moved-from object 'a'}} +#endif } void localUniquePtr(std::unique_ptr P) { // Even though unique_ptr is safe to use after move, // reusing a local variable this way usually indicates a bug. - std::unique_ptr Q = std::move(P); // expected-note{{Object 'P' is moved}} - P.get(); // expected-warning{{Method called on moved-from object 'P'}} - // expected-note@-1{{Method called on moved-from object 'P'}} + std::unique_ptr Q = std::move(P); + P.get(); +#ifndef PEACEFUL + // expected-note@-3 {{Object 'P' is moved}} + // expected-warning@-3 {{Method called on moved-from object 'P'}} + // expected-note@-4 {{Method called on moved-from object 'P'}} +#endif } void localUniquePtrWithArrow(std::unique_ptr P) {