r236075 - Add -Wpessimizing-move and -Wredundant-move warnings.
Benjamin Kramer
benny.kra at gmail.com
Wed Apr 29 02:41:01 PDT 2015
On Wed, Apr 29, 2015 at 5:59 AM, Richard Trieu <rtrieu at google.com> wrote:
> Since this warning did not exist when std::move was first introduced, and
> many people are not familiar with copy elision rules, there have been a lot
> of uses of the pessimizing move pattern. In relative numbers, the
> pessimizing move warning is over 5x more common than either the range loop
> warning (-Wrange-loop-analysis) or the proposed comma warning (-Wcomma).
> With such a high occurrence, it seemed better not to have it on by default.
And every single occurence is a potential performance issue and easy
to fix. While this may be too noisy for default, it's definitely a
candidate for -Wall imho.
- Benjamin
> On Tue, Apr 28, 2015 at 7:17 PM, Nico Weber <thakis at chromium.org> wrote:
>>
>> Why are these DefaultIgnore?
>>
>> On Tue, Apr 28, 2015 at 6:52 PM, Richard Trieu <rtrieu at google.com> wrote:
>>>
>>> Author: rtrieu
>>> Date: Tue Apr 28 20:52:17 2015
>>> New Revision: 236075
>>>
>>> URL: http://llvm.org/viewvc/llvm-project?rev=236075&view=rev
>>> Log:
>>> Add -Wpessimizing-move and -Wredundant-move warnings.
>>>
>>> -Wpessimizing-move warns when a call to std::move would prevent copy
>>> elision
>>> if the argument was not wrapped in a call. This happens when moving a
>>> local
>>> variable in a return statement when the variable is the same type as the
>>> return type or using a move to create a new object from a temporary
>>> object.
>>>
>>> -Wredundant-move warns when an implicit move would already be made, so
>>> the
>>> std::move call is not needed, such as when moving a local variable in a
>>> return
>>> that is different from the return type.
>>>
>>> Differential Revision: http://reviews.llvm.org/D7633
>>>
>>> Added:
>>> cfe/trunk/test/SemaCXX/warn-pessmizing-move.cpp
>>> cfe/trunk/test/SemaCXX/warn-redundant-move.cpp
>>> Modified:
>>> cfe/trunk/include/clang/Basic/DiagnosticGroups.td
>>> cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
>>> cfe/trunk/lib/Sema/SemaInit.cpp
>>>
>>> Modified: cfe/trunk/include/clang/Basic/DiagnosticGroups.td
>>> URL:
>>> http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticGroups.td?rev=236075&r1=236074&r2=236075&view=diff
>>>
>>> ==============================================================================
>>> --- cfe/trunk/include/clang/Basic/DiagnosticGroups.td (original)
>>> +++ cfe/trunk/include/clang/Basic/DiagnosticGroups.td Tue Apr 28 20:52:17
>>> 2015
>>> @@ -286,6 +286,7 @@ def DeprecatedObjCIsaUsage : DiagGroup<"
>>> def ExplicitInitializeCall : DiagGroup<"explicit-initialize-call">;
>>> def Packed : DiagGroup<"packed">;
>>> def Padded : DiagGroup<"padded">;
>>> +def PessimizingMove : DiagGroup<"pessimizing-move">;
>>> def PointerArith : DiagGroup<"pointer-arith">;
>>> def PoundWarning : DiagGroup<"#warnings">;
>>> def PoundPragmaMessage : DiagGroup<"#pragma-messages">,
>>> @@ -294,6 +295,7 @@ def : DiagGroup<"pointer-to-int-cast">;
>>> def : DiagGroup<"redundant-decls">;
>>> def RedeclaredClassMember : DiagGroup<"redeclared-class-member">;
>>> def GNURedeclaredEnum : DiagGroup<"gnu-redeclared-enum">;
>>> +def RedundantMove : DiagGroup<"redundant-move">;
>>> def ReturnStackAddress : DiagGroup<"return-stack-address">;
>>> def ReturnTypeCLinkage : DiagGroup<"return-type-c-linkage">;
>>> def ReturnType : DiagGroup<"return-type", [ReturnTypeCLinkage]>;
>>>
>>> Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
>>> URL:
>>> http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=236075&r1=236074&r2=236075&view=diff
>>>
>>> ==============================================================================
>>> --- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
>>> +++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Tue Apr 28
>>> 20:52:17 2015
>>> @@ -4777,6 +4777,17 @@ def warn_self_move : Warning<
>>> "explicitly moving variable of type %0 to itself">,
>>> InGroup<SelfMove>, DefaultIgnore;
>>>
>>> +def warn_redundant_move_on_return : Warning<
>>> + "redundant move in return statement">,
>>> + InGroup<RedundantMove>, DefaultIgnore;
>>> +def warn_pessimizing_move_on_return : Warning<
>>> + "moving a local object in a return statement prevents copy elision">,
>>> + InGroup<PessimizingMove>, DefaultIgnore;
>>> +def warn_pessimizing_move_on_initialization : Warning<
>>> + "moving a temporary object prevents copy elision">,
>>> + InGroup<PessimizingMove>, DefaultIgnore;
>>> +def note_remove_move : Note<"remove std::move call here">;
>>> +
>>> def warn_string_plus_int : Warning<
>>> "adding %0 to a string does not append to the string">,
>>> InGroup<StringPlusInt>;
>>>
>>> Modified: cfe/trunk/lib/Sema/SemaInit.cpp
>>> URL:
>>> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaInit.cpp?rev=236075&r1=236074&r2=236075&view=diff
>>>
>>> ==============================================================================
>>> --- cfe/trunk/lib/Sema/SemaInit.cpp (original)
>>> +++ cfe/trunk/lib/Sema/SemaInit.cpp Tue Apr 28 20:52:17 2015
>>> @@ -5768,6 +5768,112 @@ static void DiagnoseNarrowingInInitList(
>>> QualType EntityType,
>>> const Expr *PostInit);
>>>
>>> +/// Provide warnings when std::move is used on construction.
>>> +static void CheckMoveOnConstruction(Sema &S, const Expr *InitExpr,
>>> + bool IsReturnStmt) {
>>> + if (!InitExpr)
>>> + return;
>>> +
>>> + QualType DestType = InitExpr->getType();
>>> + if (!DestType->isRecordType())
>>> + return;
>>> +
>>> + unsigned DiagID = 0;
>>> + if (IsReturnStmt) {
>>> + const CXXConstructExpr *CCE =
>>> + dyn_cast<CXXConstructExpr>(InitExpr->IgnoreParens());
>>> + if (!CCE || CCE->getNumArgs() != 1)
>>> + return;
>>> +
>>> + if (!CCE->getConstructor()->isCopyOrMoveConstructor())
>>> + return;
>>> +
>>> + InitExpr = CCE->getArg(0)->IgnoreImpCasts();
>>> +
>>> + // Remove implicit temporary and constructor nodes.
>>> + if (const MaterializeTemporaryExpr *MTE =
>>> + dyn_cast<MaterializeTemporaryExpr>(InitExpr)) {
>>> + InitExpr = MTE->GetTemporaryExpr()->IgnoreImpCasts();
>>> + while (const CXXConstructExpr *CCE =
>>> + dyn_cast<CXXConstructExpr>(InitExpr)) {
>>> + if (isa<CXXTemporaryObjectExpr>(CCE))
>>> + return;
>>> + if (CCE->getNumArgs() == 0)
>>> + return;
>>> + if (CCE->getNumArgs() > 1 &&
>>> !isa<CXXDefaultArgExpr>(CCE->getArg(1)))
>>> + return;
>>> + InitExpr = CCE->getArg(0);
>>> + }
>>> + InitExpr = InitExpr->IgnoreImpCasts();
>>> + DiagID = diag::warn_redundant_move_on_return;
>>> + }
>>> + }
>>> +
>>> + // Find the std::move call and get the argument.
>>> + const CallExpr *CE = dyn_cast<CallExpr>(InitExpr->IgnoreParens());
>>> + if (!CE || CE->getNumArgs() != 1)
>>> + return;
>>> +
>>> + const FunctionDecl *MoveFunction = CE->getDirectCallee();
>>> + if (!MoveFunction || !MoveFunction->isInStdNamespace() ||
>>> + !MoveFunction->getIdentifier() ||
>>> + !MoveFunction->getIdentifier()->isStr("move"))
>>> + return;
>>> +
>>> + const Expr *Arg = CE->getArg(0)->IgnoreImplicit();
>>> +
>>> + if (IsReturnStmt) {
>>> + const DeclRefExpr *DRE =
>>> dyn_cast<DeclRefExpr>(Arg->IgnoreParenImpCasts());
>>> + if (!DRE || DRE->refersToEnclosingVariableOrCapture())
>>> + return;
>>> +
>>> + const VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl());
>>> + if (!VD || !VD->hasLocalStorage())
>>> + return;
>>> +
>>> + if (DiagID == 0) {
>>> + DiagID = S.Context.hasSameUnqualifiedType(DestType, VD->getType())
>>> + ? diag::warn_pessimizing_move_on_return
>>> + : diag::warn_redundant_move_on_return;
>>> + }
>>> + } else {
>>> + DiagID = diag::warn_pessimizing_move_on_initialization;
>>> + const Expr *ArgStripped = Arg->IgnoreImplicit()->IgnoreParens();
>>> + if (!ArgStripped->isRValue() ||
>>> !ArgStripped->getType()->isRecordType())
>>> + return;
>>> + }
>>> +
>>> + S.Diag(CE->getLocStart(), DiagID);
>>> +
>>> + // Get all the locations for a fix-it. Don't emit the fix-it if any
>>> location
>>> + // is within a macro.
>>> + SourceLocation CallBegin = CE->getCallee()->getLocStart();
>>> + if (CallBegin.isMacroID())
>>> + return;
>>> + SourceLocation RParen = CE->getRParenLoc();
>>> + if (RParen.isMacroID())
>>> + return;
>>> + SourceLocation LParen;
>>> + SourceLocation ArgLoc = Arg->getLocStart();
>>> +
>>> + // Special testing for the argument location. Since the fix-it needs
>>> the
>>> + // location right before the argument, the argument location can be in
>>> a
>>> + // macro only if it is at the beginning of the macro.
>>> + while (ArgLoc.isMacroID() &&
>>> +
>>> S.getSourceManager().isAtStartOfImmediateMacroExpansion(ArgLoc)) {
>>> + ArgLoc =
>>> S.getSourceManager().getImmediateExpansionRange(ArgLoc).first;
>>> + }
>>> +
>>> + if (LParen.isMacroID())
>>> + return;
>>> +
>>> + LParen = ArgLoc.getLocWithOffset(-1);
>>> +
>>> + S.Diag(CE->getLocStart(), diag::note_remove_move)
>>> + << FixItHint::CreateRemoval(SourceRange(CallBegin, LParen))
>>> + << FixItHint::CreateRemoval(SourceRange(RParen, RParen));
>>> +}
>>> +
>>> ExprResult
>>> InitializationSequence::Perform(Sema &S,
>>> const InitializedEntity &Entity,
>>> @@ -6497,6 +6603,12 @@ InitializationSequence::Perform(Sema &S,
>>> cast<FieldDecl>(Entity.getDecl()),
>>> CurInit.get());
>>>
>>> + // Check for std::move on construction.
>>> + if (const Expr *E = CurInit.get()) {
>>> + CheckMoveOnConstruction(S, E,
>>> + Entity.getKind() ==
>>> InitializedEntity::EK_Result);
>>> + }
>>> +
>>> return CurInit;
>>> }
>>>
>>>
>>> Added: cfe/trunk/test/SemaCXX/warn-pessmizing-move.cpp
>>> URL:
>>> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/warn-pessmizing-move.cpp?rev=236075&view=auto
>>>
>>> ==============================================================================
>>> --- cfe/trunk/test/SemaCXX/warn-pessmizing-move.cpp (added)
>>> +++ cfe/trunk/test/SemaCXX/warn-pessmizing-move.cpp Tue Apr 28 20:52:17
>>> 2015
>>> @@ -0,0 +1,203 @@
>>> +// RUN: %clang_cc1 -fsyntax-only -Wpessimizing-move -std=c++11 -verify
>>> %s
>>> +// RUN: %clang_cc1 -fsyntax-only -Wpessimizing-move -std=c++11
>>> -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %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);
>>> +}
>>> +}
>>> +
>>> +struct A {};
>>> +struct B {
>>> + B() {}
>>> + B(A) {}
>>> +};
>>> +
>>> +A test1(A a1) {
>>> + A a2;
>>> + return a1;
>>> + return a2;
>>> + return std::move(a1);
>>> + // expected-warning at -1{{prevents copy elision}}
>>> + // expected-note at -2{{remove std::move call}}
>>> + // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:10-[[@LINE-3]]:20}:""
>>> + // CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:22-[[@LINE-4]]:23}:""
>>> + return std::move(a2);
>>> + // expected-warning at -1{{prevents copy elision}}
>>> + // expected-note at -2{{remove std::move call}}
>>> + // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:10-[[@LINE-3]]:20}:""
>>> + // CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:22-[[@LINE-4]]:23}:""
>>> +}
>>> +
>>> +B test2(A a1, B b1) {
>>> + // Object is different than return type so don't warn.
>>> + A a2;
>>> + return a1;
>>> + return a2;
>>> + return std::move(a1);
>>> + return std::move(a2);
>>> +
>>> + B b2;
>>> + return b1;
>>> + return b2;
>>> + return std::move(b1);
>>> + // expected-warning at -1{{prevents copy elision}}
>>> + // expected-note at -2{{remove std::move call}}
>>> + // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:10-[[@LINE-3]]:20}:""
>>> + // CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:22-[[@LINE-4]]:23}:""
>>> + return std::move(b2);
>>> + // expected-warning at -1{{prevents copy elision}}
>>> + // expected-note at -2{{remove std::move call}}
>>> + // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:10-[[@LINE-3]]:20}:""
>>> + // CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:22-[[@LINE-4]]:23}:""
>>> +}
>>> +
>>> +A global_a;
>>> +A test3() {
>>> + // Don't warn when object is not local.
>>> + return global_a;
>>> + return std::move(global_a);
>>> + static A static_a;
>>> + return static_a;
>>> + return std::move(static_a);
>>> +
>>> +}
>>> +
>>> +A test4() {
>>> + return A();
>>> + return test3();
>>> +
>>> + return std::move(A());
>>> + // expected-warning at -1{{prevents copy elision}}
>>> + // expected-note at -2{{remove std::move call}}
>>> + // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:10-[[@LINE-3]]:20}:""
>>> + // CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:23-[[@LINE-4]]:24}:""
>>> + return std::move(test3());
>>> + // expected-warning at -1{{prevents copy elision}}
>>> + // expected-note at -2{{remove std::move call}}
>>> + // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:10-[[@LINE-3]]:20}:""
>>> + // CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:27-[[@LINE-4]]:28}:""
>>> +}
>>> +
>>> +void test5(A) {
>>> + test5(A());
>>> + test5(test4());
>>> +
>>> + test5(std::move(A()));
>>> + // expected-warning at -1{{prevents copy elision}}
>>> + // expected-note at -2{{remove std::move call}}
>>> + // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:19}:""
>>> + // CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:22-[[@LINE-4]]:23}:""
>>> + test5(std::move(test4()));
>>> + // expected-warning at -1{{prevents copy elision}}
>>> + // expected-note at -2{{remove std::move call}}
>>> + // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:19}:""
>>> + // CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:26-[[@LINE-4]]:27}:""
>>> +}
>>> +
>>> +void test6() {
>>> + A a1 = A();
>>> + A a2 = test3();
>>> +
>>> + A a3 = std::move(A());
>>> + // expected-warning at -1{{prevents copy elision}}
>>> + // expected-note at -2{{remove std::move call}}
>>> + // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:10-[[@LINE-3]]:20}:""
>>> + // CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:23-[[@LINE-4]]:24}:""
>>> + A a4 = std::move(test3());
>>> + // expected-warning at -1{{prevents copy elision}}
>>> + // expected-note at -2{{remove std::move call}}
>>> + // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:10-[[@LINE-3]]:20}:""
>>> + // CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:27-[[@LINE-4]]:28}:""
>>> +}
>>> +
>>> +A test7() {
>>> + A a1 = std::move(A());
>>> + // expected-warning at -1{{prevents copy elision}}
>>> + // expected-note at -2{{remove std::move call}}
>>> + // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:10-[[@LINE-3]]:20}:""
>>> + // CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:23-[[@LINE-4]]:24}:""
>>> + A a2 = std::move((A()));
>>> + // expected-warning at -1{{prevents copy elision}}
>>> + // expected-note at -2{{remove std::move call}}
>>> + // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:10-[[@LINE-3]]:20}:""
>>> + // CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:25-[[@LINE-4]]:26}:""
>>> + A a3 = (std::move(A()));
>>> + // expected-warning at -1{{prevents copy elision}}
>>> + // expected-note at -2{{remove std::move call}}
>>> + // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:11-[[@LINE-3]]:21}:""
>>> + // CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:24-[[@LINE-4]]:25}:""
>>> + A a4 = (std::move((A())));
>>> + // expected-warning at -1{{prevents copy elision}}
>>> + // expected-note at -2{{remove std::move call}}
>>> + // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:11-[[@LINE-3]]:21}:""
>>> + // CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:26-[[@LINE-4]]:27}:""
>>> +
>>> + return std::move(a1);
>>> + // expected-warning at -1{{prevents copy elision}}
>>> + // expected-note at -2{{remove std::move call}}
>>> + // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:10-[[@LINE-3]]:20}:""
>>> + // CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:22-[[@LINE-4]]:23}:""
>>> + return std::move((a1));
>>> + // expected-warning at -1{{prevents copy elision}}
>>> + // expected-note at -2{{remove std::move call}}
>>> + // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:10-[[@LINE-3]]:20}:""
>>> + // CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:24-[[@LINE-4]]:25}:""
>>> + return (std::move(a1));
>>> + // expected-warning at -1{{prevents copy elision}}
>>> + // expected-note at -2{{remove std::move call}}
>>> + // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:11-[[@LINE-3]]:21}:""
>>> + // CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:23-[[@LINE-4]]:24}:""
>>> + return (std::move((a1)));
>>> + // expected-warning at -1{{prevents copy elision}}
>>> + // expected-note at -2{{remove std::move call}}
>>> + // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:11-[[@LINE-3]]:21}:""
>>> + // CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:25-[[@LINE-4]]:26}:""
>>> +}
>>> +
>>> +#define wrap1(x) x
>>> +#define wrap2(x) x
>>> +
>>> +// Macro test. Since the std::move call is outside the macro, it is
>>> +// safe to suggest a fix-it.
>>> +A test8(A a) {
>>> + return std::move(a);
>>> + // expected-warning at -1{{prevents copy elision}}
>>> + // expected-note at -2{{remove std::move call}}
>>> + // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:10-[[@LINE-3]]:20}:""
>>> + // CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:21-[[@LINE-4]]:22}:""
>>> + return std::move(wrap1(a));
>>> + // expected-warning at -1{{prevents copy elision}}
>>> + // expected-note at -2{{remove std::move call}}
>>> + // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:10-[[@LINE-3]]:20}:""
>>> + // CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:28-[[@LINE-4]]:29}:""
>>> + return std::move(wrap1(wrap2(a)));
>>> + // expected-warning at -1{{prevents copy elision}}
>>> + // expected-note at -2{{remove std::move call}}
>>> + // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:10-[[@LINE-3]]:20}:""
>>> + // CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:35-[[@LINE-4]]:36}:""
>>> +}
>>> +
>>> +#define test9 \
>>> + A test9(A a) { \
>>> + return std::move(a); \
>>> + }
>>> +
>>> +// Macro test. The std::call is inside the macro, so no fix-it is
>>> suggested.
>>> +test9
>>> +// expected-warning at -1{{prevents copy elision}}
>>> +// CHECK-NOT: fix-it
>>> +
>>> +#define return_a return std::move(a)
>>> +
>>> +// Macro test. The std::call is inside the macro, so no fix-it is
>>> suggested.
>>> +A test10(A a) {
>>> + return_a;
>>> + // expected-warning at -1{{prevents copy elision}}
>>> + // CHECK-NOT: fix-it
>>> +}
>>>
>>> Added: cfe/trunk/test/SemaCXX/warn-redundant-move.cpp
>>> URL:
>>> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/warn-redundant-move.cpp?rev=236075&view=auto
>>>
>>> ==============================================================================
>>> --- cfe/trunk/test/SemaCXX/warn-redundant-move.cpp (added)
>>> +++ cfe/trunk/test/SemaCXX/warn-redundant-move.cpp Tue Apr 28 20:52:17
>>> 2015
>>> @@ -0,0 +1,68 @@
>>> +// RUN: %clang_cc1 -fsyntax-only -Wredundant-move -std=c++11 -verify %s
>>> +// RUN: %clang_cc1 -fsyntax-only -Wredundant-move -std=c++11
>>> -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %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);
>>> +}
>>> +}
>>> +
>>> +struct A {};
>>> +struct B : public A {};
>>> +
>>> +A test1(B b1) {
>>> + B b2;
>>> + //return b1;
>>> + //return b2;
>>> + return std::move(b1);
>>> + // expected-warning at -1{{redundant move}}
>>> + // expected-note at -2{{remove std::move call}}
>>> + // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:10-[[@LINE-3]]:20}:""
>>> + // CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:22-[[@LINE-4]]:23}:""
>>> + return std::move(b2);
>>> + // expected-warning at -1{{redundant move}}
>>> + // expected-note at -2{{remove std::move call}}
>>> + // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:10-[[@LINE-3]]:20}:""
>>> + // CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:22-[[@LINE-4]]:23}:""
>>> +}
>>> +
>>> +struct C {
>>> + C() {}
>>> + C(A) {}
>>> +};
>>> +
>>> +C test2(A a1, B b1) {
>>> + A a2;
>>> + B b2;
>>> +
>>> + return a1;
>>> + return a2;
>>> + return b1;
>>> + return b2;
>>> +
>>> + return std::move(a1);
>>> + // expected-warning at -1{{redundant move}}
>>> + // expected-note at -2{{remove std::move call}}
>>> + // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:10-[[@LINE-3]]:20}:""
>>> + // CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:22-[[@LINE-4]]:23}:""
>>> + return std::move(a2);
>>> + // expected-warning at -1{{redundant move}}
>>> + // expected-note at -2{{remove std::move call}}
>>> + // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:10-[[@LINE-3]]:20}:""
>>> + // CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:22-[[@LINE-4]]:23}:""
>>> + return std::move(b1);
>>> + // expected-warning at -1{{redundant move}}
>>> + // expected-note at -2{{remove std::move call}}
>>> + // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:10-[[@LINE-3]]:20}:""
>>> + // CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:22-[[@LINE-4]]:23}:""
>>> + return std::move(b2);
>>> + // expected-warning at -1{{redundant move}}
>>> + // expected-note at -2{{remove std::move call}}
>>> + // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:10-[[@LINE-3]]:20}:""
>>> + // CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:22-[[@LINE-4]]:23}:""
>>> +}
>>>
>>>
>>> _______________________________________________
>>> cfe-commits mailing list
>>> cfe-commits at cs.uiuc.edu
>>> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
>>
>>
>
>
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
>
More information about the cfe-commits
mailing list