Update fix-it hints for std::move warnings.
authorRichard Trieu <rtrieu@google.com>
Thu, 8 Aug 2019 00:12:51 +0000 (00:12 +0000)
committerRichard Trieu <rtrieu@google.com>
Thu, 8 Aug 2019 00:12:51 +0000 (00:12 +0000)
Fix -Wpessimizing-move and -Wredundant-move when warning on initializer lists.
The new fix-it hints for removing the std::move call will now also suggest
removing the braces for the initializer list so that the resulting code will
still be compilable.

This fixes PR42832

llvm-svn: 368237

clang/lib/Sema/SemaInit.cpp
clang/test/SemaCXX/warn-pessmizing-move.cpp
clang/test/SemaCXX/warn-redundant-move.cpp

index 7fbffd956c2d45c02ef82b4c6531a52d5e2ff0fb..693d759db2151a49f3eef60e50c6b98f1c01593d 100644 (file)
@@ -7305,27 +7305,34 @@ static void CheckMoveOnConstruction(Sema &S, const Expr *InitExpr,
   if (!DestType->isRecordType())
     return;
 
-  unsigned DiagID = 0;
-  if (IsReturnStmt) {
-    const CXXConstructExpr *CCE =
-        dyn_cast<CXXConstructExpr>(InitExpr->IgnoreParens());
-    if (!CCE || CCE->getNumArgs() != 1)
-      return;
+  const CXXConstructExpr *CCE =
+      dyn_cast<CXXConstructExpr>(InitExpr->IgnoreParens());
+  if (!CCE || CCE->getNumArgs() != 1)
+    return;
 
-    if (!CCE->getConstructor()->isCopyOrMoveConstructor())
-      return;
+  if (!CCE->getConstructor()->isCopyOrMoveConstructor())
+    return;
 
-    InitExpr = CCE->getArg(0)->IgnoreImpCasts();
-  }
+  InitExpr = CCE->getArg(0)->IgnoreImpCasts();
 
   // Find the std::move call and get the argument.
   const CallExpr *CE = dyn_cast<CallExpr>(InitExpr->IgnoreParens());
   if (!CE || !CE->isCallToStdMove())
     return;
 
-  const Expr *Arg = CE->getArg(0)->IgnoreImplicit();
+  const Expr *Arg = CE->getArg(0);
 
-  if (IsReturnStmt) {
+  unsigned DiagID = 0;
+
+  if (!IsReturnStmt && !isa<MaterializeTemporaryExpr>(Arg))
+    return;
+
+  if (isa<MaterializeTemporaryExpr>(Arg)) {
+    DiagID = diag::warn_pessimizing_move_on_initialization;
+    const Expr *ArgStripped = Arg->IgnoreImplicit()->IgnoreParens();
+    if (!ArgStripped->isRValue() || !ArgStripped->getType()->isRecordType())
+      return;
+  } else { // IsReturnStmt
     const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Arg->IgnoreParenImpCasts());
     if (!DRE || DRE->refersToEnclosingVariableOrCapture())
       return;
@@ -7352,24 +7359,18 @@ static void CheckMoveOnConstruction(Sema &S, const Expr *InitExpr,
       DiagID = diag::warn_redundant_move_on_return;
     else
       DiagID = diag::warn_pessimizing_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->getBeginLoc(), 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()->getBeginLoc();
-  if (CallBegin.isMacroID())
+  SourceLocation BeginLoc = CCE->getBeginLoc();
+  if (BeginLoc.isMacroID())
     return;
   SourceLocation RParen = CE->getRParenLoc();
   if (RParen.isMacroID())
     return;
-  SourceLocation LParen;
   SourceLocation ArgLoc = Arg->getBeginLoc();
 
   // Special testing for the argument location.  Since the fix-it needs the
@@ -7380,14 +7381,16 @@ static void CheckMoveOnConstruction(Sema &S, const Expr *InitExpr,
     ArgLoc = S.getSourceManager().getImmediateExpansionRange(ArgLoc).getBegin();
   }
 
+  SourceLocation LParen = ArgLoc.getLocWithOffset(-1);
   if (LParen.isMacroID())
     return;
-
-  LParen = ArgLoc.getLocWithOffset(-1);
+  SourceLocation EndLoc = CCE->getEndLoc();
+  if (EndLoc.isMacroID())
+    return;
 
   S.Diag(CE->getBeginLoc(), diag::note_remove_move)
-      << FixItHint::CreateRemoval(SourceRange(CallBegin, LParen))
-      << FixItHint::CreateRemoval(SourceRange(RParen, RParen));
+      << FixItHint::CreateRemoval(SourceRange(BeginLoc, LParen))
+      << FixItHint::CreateRemoval(SourceRange(RParen, EndLoc));
 }
 
 static void CheckForNullPointerDereference(Sema &S, const Expr *E) {
index 71e99dca007b2f1e2c089a76220e2d7a57c5b067..deedec41bd766f6ec3e46d3169d535eaaae2d239 100644 (file)
@@ -122,13 +122,13 @@ A test7() {
   A a3 = (std::move(A()));
   // expected-warning@-1{{prevents copy elision}}
   // expected-note@-2{{remove std::move call}}
-  // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:11-[[@LINE-3]]:21}:""
-  // CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:24-[[@LINE-4]]:25}:""
+  // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:10-[[@LINE-3]]:21}:""
+  // CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:24-[[@LINE-4]]:26}:""
   A a4 = (std::move((A())));
   // expected-warning@-1{{prevents copy elision}}
   // expected-note@-2{{remove std::move call}}
-  // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:11-[[@LINE-3]]:21}:""
-  // CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:26-[[@LINE-4]]:27}:""
+  // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:10-[[@LINE-3]]:21}:""
+  // CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:26-[[@LINE-4]]:28}:""
 
   return std::move(a1);
   // expected-warning@-1{{prevents copy elision}}
@@ -143,13 +143,13 @@ A test7() {
   return (std::move(a1));
   // expected-warning@-1{{prevents copy elision}}
   // expected-note@-2{{remove std::move call}}
-  // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:11-[[@LINE-3]]:21}:""
-  // CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:23-[[@LINE-4]]:24}:""
+  // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:10-[[@LINE-3]]:21}:""
+  // CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:23-[[@LINE-4]]:25}:""
   return (std::move((a1)));
   // expected-warning@-1{{prevents copy elision}}
   // expected-note@-2{{remove std::move call}}
-  // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:11-[[@LINE-3]]:21}:""
-  // CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:25-[[@LINE-4]]:26}:""
+  // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:10-[[@LINE-3]]:21}:""
+  // CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:25-[[@LINE-4]]:27}:""
 }
 
 #define wrap1(x) x
@@ -227,3 +227,30 @@ namespace templates {
     test2<B, A>();
   }
 }
+
+A init_list() {
+  A a1;
+  return { std::move(a1) };
+  // expected-warning@-1{{prevents copy elision}}
+  // expected-note@-2{{remove std::move call}}
+  // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:10-[[@LINE-3]]:22}:""
+  // CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:24-[[@LINE-4]]:27}:""
+
+  return { (std::move(a1)) };
+  // expected-warning@-1{{prevents copy elision}}
+  // expected-note@-2{{remove std::move call}}
+  // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:10-[[@LINE-3]]:23}:""
+  // CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:25-[[@LINE-4]]:29}:""
+
+  A a2 = { std::move(A()) };
+  // expected-warning@-1{{prevents copy elision}}
+  // expected-note@-2{{remove std::move call}}
+  // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:10-[[@LINE-3]]:22}:""
+  // CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:25-[[@LINE-4]]:28}:""
+
+  A a3 = { (std::move(A())) };
+  // expected-warning@-1{{prevents copy elision}}
+  // expected-note@-2{{remove std::move call}}
+  // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:10-[[@LINE-3]]:23}:""
+  // CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:26-[[@LINE-4]]:30}:""
+}
index 2bfc8c9312f02e952ad881192b0b7bae79ab41c9..e04a5256417385a1d6f7241ad2fa5f90d47bc3a5 100644 (file)
@@ -114,3 +114,17 @@ namespace templates {
     test2<B, A>(A());\r
   }\r
 }\r
+\r
+A init_list(A a) {\r
+  return { std::move(a) };\r
+  // expected-warning@-1{{redundant move in return statement}}\r
+  // expected-note@-2{{remove std::move call here}}\r
+  // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:10-[[@LINE-3]]:22}:""\r
+  // CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:23-[[@LINE-4]]:26}:""\r
+\r
+  return { (std::move(a)) };\r
+  // expected-warning@-1{{redundant move in return statement}}\r
+  // expected-note@-2{{remove std::move call here}}\r
+  // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:10-[[@LINE-3]]:23}:""\r
+  // CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:24-[[@LINE-4]]:28}:""\r
+}\r