http://reviews.llvm.org/D7633

Files:
  include/clang/Basic/DiagnosticGroups.td
  include/clang/Basic/DiagnosticSemaKinds.td
  lib/Sema/SemaInit.cpp
  lib/Sema/SemaStmt.cpp
  test/SemaCXX/warn-pessmizing-move.cpp

EMAIL PREFERENCES
  http://reviews.llvm.org/settings/panel/emailpreferences/
Index: include/clang/Basic/DiagnosticGroups.td
===================================================================
--- include/clang/Basic/DiagnosticGroups.td
+++ include/clang/Basic/DiagnosticGroups.td
@@ -286,6 +286,7 @@
 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">,
Index: include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- include/clang/Basic/DiagnosticSemaKinds.td
+++ include/clang/Basic/DiagnosticSemaKinds.td
@@ -4764,6 +4764,14 @@
   "explicitly moving variable of type %0 to itself">,
   InGroup<SelfMove>, 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>;
Index: lib/Sema/SemaInit.cpp
===================================================================
--- lib/Sema/SemaInit.cpp
+++ lib/Sema/SemaInit.cpp
@@ -3239,6 +3239,36 @@
   return CandidateSet.BestViableFunction(S, DeclLoc, Best);
 }
 
+static void CheckMoveOnConstruction(Sema &SemaRef, const Expr *InitExpr) {
+  if (!InitExpr)
+    return;
+  if (SemaRef.Diags.isIgnored(diag::warn_pessimizing_move_on_initialization,
+                              InitExpr->getLocStart()))
+    return;
+
+  const CallExpr *CE = dyn_cast<CallExpr>(InitExpr);
+  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 (!Arg->isRValue() || !Arg->getType()->isRecordType())
+    return;
+
+  SemaRef.Diag(Arg->getLocStart(),
+               diag::warn_pessimizing_move_on_initialization);
+  SemaRef.Diag(InitExpr->getLocStart(), diag::note_remove_move)
+      << FixItHint::CreateRemoval(SourceRange(
+             CE->getLocStart(), Arg->getLocStart().getLocWithOffset(-1)))
+      << FixItHint::CreateRemoval(
+             SourceRange(CE->getRParenLoc(), CE->getRParenLoc()));
+}
+
 /// \brief Attempt initialization by constructor (C++ [dcl.init]), which
 /// enumerates the constructors of the initialized entity and performs overload
 /// resolution to select the best.
@@ -3358,6 +3388,9 @@
   Sequence.AddConstructorInitializationStep(
       CtorDecl, Best->FoundDecl.getAccess(), DestType, HadMultipleCandidates,
       IsListInit | IsInitListCopy, AsInitializerList);
+
+  if (Args.size() == 1)
+    CheckMoveOnConstruction(S, Args[0]);
 }
 
 static bool
Index: lib/Sema/SemaStmt.cpp
===================================================================
--- lib/Sema/SemaStmt.cpp
+++ lib/Sema/SemaStmt.cpp
@@ -3046,6 +3046,48 @@
   return false;
 }
 
+static void CheckMoveOnReturn(Sema &SemaRef, const Expr *ReturnExpr,
+                              const FunctionDecl *FD) {
+  if (!ReturnExpr || !FD)
+    return;
+
+  if (SemaRef.Diags.isIgnored(diag::warn_pessimizing_move_on_return,
+                              ReturnExpr->getLocStart()))
+    return;
+
+  QualType ReturnType = FD->getReturnType();
+  if (ReturnType->isReferenceType() || !ReturnType->isRecordType())
+    return;
+
+  const CallExpr *CE = dyn_cast<CallExpr>(ReturnExpr);
+  if (!CE || CE->getNumArgs() != 1)
+    return;
+
+  const FunctionDecl *MoveFunction = CE->getDirectCallee();
+  if (!MoveFunction || !MoveFunction->isInStdNamespace() ||
+      !MoveFunction->getIdentifier() ||
+      !MoveFunction->getIdentifier()->isStr("move"))
+    return;
+
+  const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(CE->getArg(0));
+  if (!DRE)
+    return;
+
+  const VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl());
+  if (!VD || !VD->hasLocalStorage())
+    return;
+
+  if (!SemaRef.Context.hasSameUnqualifiedType(ReturnType, VD->getType()))
+    return;
+
+  SemaRef.Diag(DRE->getLocStart(), diag::warn_pessimizing_move_on_return);
+  SemaRef.Diag(ReturnExpr->getLocStart(), diag::note_remove_move)
+      << FixItHint::CreateRemoval(SourceRange(
+             CE->getLocStart(), DRE->getLocStart().getLocWithOffset(-1)))
+      << FixItHint::CreateRemoval(
+             SourceRange(CE->getRParenLoc(), CE->getRParenLoc()));
+}
+
 StmtResult
 Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp,
                       Scope *CurScope) {
@@ -3063,6 +3105,8 @@
 
   CheckJumpOutOfSEHFinally(*this, ReturnLoc, *CurScope->getFnParent());
 
+  CheckMoveOnReturn(*this, RetValExp, getCurFunctionDecl());
+
   return R;
 }
 
Index: test/SemaCXX/warn-pessmizing-move.cpp
===================================================================
--- test/SemaCXX/warn-pessmizing-move.cpp
+++ test/SemaCXX/warn-pessmizing-move.cpp
@@ -0,0 +1,96 @@
+// RUN: %clang_cc1 -fsyntax-only -Wpessimizing-move -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);
+}
+}
+
+struct A {};
+struct B {
+  B() {}
+  B(A) {}
+};
+
+A test1(A a1) {
+  A a2;
+  return a1;
+  return a2;
+  return std::move(a1);
+  // expected-warning@-1{{prevents copy elision}}
+  // expected-note@-2{{remove std::move call}}
+  return std::move(a2);
+  // expected-warning@-1{{prevents copy elision}}
+  // expected-note@-2{{remove std::move call}}
+}
+
+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@-1{{prevents copy elision}}
+  // expected-note@-2{{remove std::move call}}
+  return std::move(b2);
+  // expected-warning@-1{{prevents copy elision}}
+  // expected-note@-2{{remove std::move call}}
+}
+
+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@-1{{prevents copy elision}}
+  // expected-note@-2{{remove std::move call}}
+  return std::move(test3());
+  // expected-warning@-1{{prevents copy elision}}
+  // expected-note@-2{{remove std::move call}}
+}
+
+void test5(A) {
+  test5(A());
+  test5(test4());
+
+  test5(std::move(A()));
+  // expected-warning@-1{{prevents copy elision}}
+  // expected-note@-2{{remove std::move call}}
+  test5(std::move(test4()));
+  // expected-warning@-1{{prevents copy elision}}
+  // expected-note@-2{{remove std::move call}}
+}
+
+void test6() {
+  A a1 = A();
+  A a2 = test3();
+
+  A a3 = std::move(A());
+  // expected-warning@-1{{prevents copy elision}}
+  // expected-note@-2{{remove std::move call}}
+  A a4 = std::move(test3());
+  // expected-warning@-1{{prevents copy elision}}
+  // expected-note@-2{{remove std::move call}}
+}
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to