diff options
Diffstat (limited to 'clang')
| -rw-r--r-- | clang/include/clang/Basic/DiagnosticGroups.td | 2 | ||||
| -rw-r--r-- | clang/include/clang/Basic/DiagnosticSemaKinds.td | 3 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaExpr.cpp | 88 | ||||
| -rw-r--r-- | clang/test/SemaCXX/warn-self-move.cpp | 40 | 
4 files changed, 132 insertions, 1 deletions
diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td index d4610e0a3ff..75d40b17a67 100644 --- a/clang/include/clang/Basic/DiagnosticGroups.td +++ b/clang/include/clang/Basic/DiagnosticGroups.td @@ -294,6 +294,7 @@ def BindToTemporaryCopy : DiagGroup<"bind-to-temporary-copy",                                      [CXX98CompatBindToTemporaryCopy]>;  def SelfAssignmentField : DiagGroup<"self-assign-field">;  def SelfAssignment : DiagGroup<"self-assign", [SelfAssignmentField]>; +def SelfMove : DiagGroup<"self-move">;  def SemiBeforeMethodBody : DiagGroup<"semicolon-before-method-body">;  def Sentinel : DiagGroup<"sentinel">;  def MissingMethodReturnType : DiagGroup<"missing-method-return-type">; @@ -586,6 +587,7 @@ def Most : DiagGroup<"most", [      Reorder,      ReturnType,      SelfAssignment, +    SelfMove,      SizeofArrayArgument,      SizeofArrayDecay,      StringPlusInt, diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index cfe7b99b932..4bf83b6aede 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -4701,6 +4701,9 @@ def warn_addition_in_bitshift : Warning<  def warn_self_assignment : Warning<    "explicitly assigning value of variable of type %0 to itself">,    InGroup<SelfAssignment>, DefaultIgnore; +def warn_self_move : Warning< +  "explicitly moving variable of type %0 to itself">, +  InGroup<SelfMove>, DefaultIgnore;  def warn_string_plus_int : Warning<    "adding %0 to a string does not append to the string">, diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 68bad16ff38..c9125209839 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -9380,6 +9380,90 @@ static inline UnaryOperatorKind ConvertTokenKindToUnaryOpcode(    return Opc;  } +/// DiagnoseSelfMove - Emits a warning if a value is moved to itself. +static void DiagnoseSelfMove(Sema &S, const Expr *LHSExpr, const Expr *RHSExpr, +                             SourceLocation OpLoc) { +  if (!S.ActiveTemplateInstantiations.empty()) +    return; + +  // Strip parens and casts away. +  LHSExpr = LHSExpr->IgnoreParenImpCasts(); +  RHSExpr = RHSExpr->IgnoreParenImpCasts(); + +  // Check for a call expression +  const CallExpr *CE = dyn_cast<CallExpr>(RHSExpr); +  if (!CE || CE->getNumArgs() != 1) +    return; + +  // Check for a call to std::move +  const FunctionDecl *FD = CE->getDirectCallee(); +  if (!FD || !FD->isInStdNamespace() || !FD->getIdentifier() || +      !FD->getIdentifier()->isStr("move")) +    return; + +  // Get argument from std::move +  RHSExpr = CE->getArg(0); + +  const DeclRefExpr *LHSDeclRef = dyn_cast<DeclRefExpr>(LHSExpr); +  const DeclRefExpr *RHSDeclRef = dyn_cast<DeclRefExpr>(RHSExpr); + +  // Two DeclRefExpr's, check that the decls are the same. +  if (LHSDeclRef && RHSDeclRef) { +    if (!LHSDeclRef->getDecl() || !RHSDeclRef->getDecl()) +      return; +    if (LHSDeclRef->getDecl()->getCanonicalDecl() != +        RHSDeclRef->getDecl()->getCanonicalDecl()) +      return; + +    S.Diag(OpLoc, diag::warn_self_move) << LHSExpr->getType() +                                        << LHSExpr->getSourceRange() +                                        << RHSExpr->getSourceRange(); +    return; +  } + +  // Member variables require a different approach to check for self moves. +  // MemberExpr's are the same if every nested MemberExpr refers to the same +  // Decl and that the base Expr's are DeclRefExpr's with the same Decl or +  // the base Expr's are CXXThisExpr's. +  const Expr *LHSBase = LHSExpr; +  const Expr *RHSBase = RHSExpr; +  const MemberExpr *LHSME = dyn_cast<MemberExpr>(LHSExpr); +  const MemberExpr *RHSME = dyn_cast<MemberExpr>(RHSExpr); +  if (!LHSME || !RHSME) +    return; + +  while (LHSME && RHSME) { +    if (LHSME->getMemberDecl()->getCanonicalDecl() != +        RHSME->getMemberDecl()->getCanonicalDecl()) +      return; + +    LHSBase = LHSME->getBase(); +    RHSBase = RHSME->getBase(); +    LHSME = dyn_cast<MemberExpr>(LHSBase); +    RHSME = dyn_cast<MemberExpr>(RHSBase); +  } + +  LHSDeclRef = dyn_cast<DeclRefExpr>(LHSBase); +  RHSDeclRef = dyn_cast<DeclRefExpr>(RHSBase); +  if (LHSDeclRef && RHSDeclRef) { +    if (!LHSDeclRef->getDecl() || !RHSDeclRef->getDecl()) +      return; +    if (LHSDeclRef->getDecl()->getCanonicalDecl() != +        RHSDeclRef->getDecl()->getCanonicalDecl()) +      return; + +    S.Diag(OpLoc, diag::warn_self_move) << LHSExpr->getType() +                                        << LHSExpr->getSourceRange() +                                        << RHSExpr->getSourceRange(); +    return; +  } + +  if (isa<CXXThisExpr>(LHSBase) && isa<CXXThisExpr>(RHSBase)) +    S.Diag(OpLoc, diag::warn_self_move) << LHSExpr->getType() +                                        << LHSExpr->getSourceRange() +                                        << RHSExpr->getSourceRange(); +} +  /// DiagnoseSelfAssignment - Emits a warning if a value is assigned to itself.  /// This warning is only emitted for builtin assignment operations. It is also  /// suppressed in the event of macro expansions. @@ -9507,8 +9591,10 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,        VK = LHS.get()->getValueKind();        OK = LHS.get()->getObjectKind();      } -    if (!ResultTy.isNull()) +    if (!ResultTy.isNull()) {        DiagnoseSelfAssignment(*this, LHS.get(), RHS.get(), OpLoc); +      DiagnoseSelfMove(*this, LHS.get(), RHS.get(), OpLoc); +    }      RecordModifiableNonNullParam(*this, LHS.get());      break;    case BO_PtrMemD: diff --git a/clang/test/SemaCXX/warn-self-move.cpp b/clang/test/SemaCXX/warn-self-move.cpp new file mode 100644 index 00000000000..ae2dab1de10 --- /dev/null +++ b/clang/test/SemaCXX/warn-self-move.cpp @@ -0,0 +1,40 @@ +// RUN: %clang_cc1 -fsyntax-only -Wself-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); +} +} + +void int_test() { +  int x = 5; +  x = std::move(x);  // expected-warning{{explicitly moving}} +  (x) = std::move(x);  // expected-warning{{explicitly moving}} + +  using std::move; +  x = move(x);  // expected-warning{{explicitly moving}} +} + +int global; +void global_int_test() { +  global = std::move(global);  // expected-warning{{explicitly moving}} +  (global) = std::move(global);  // expected-warning{{explicitly moving}} + +  using std::move; +  global = move(global);  // expected-warning{{explicitly moving}} +} + +class field_test { +  int x; +  field_test(field_test&& other) { +    x = std::move(x);  // expected-warning{{explicitly moving}} +    x = std::move(other.x); +    other.x = std::move(x); +    other.x = std::move(other.x);  // expected-warning{{explicitly moving}} +  } +};  | 

