diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -14099,7 +14099,7 @@ } static void CheckIdentityFieldAssignment(Expr *LHSExpr, Expr *RHSExpr, - SourceLocation Loc, + bool IsCompound, SourceLocation Loc, Sema &Sema) { if (Sema.inTemplateInstantiation()) return; @@ -14116,6 +14116,10 @@ if (ML && MR) { if (!(isa(ML->getBase()) && isa(MR->getBase()))) return; + // For compound case, only warning on this->x -= x or x -= this->x. + if (IsCompound && ML->getBase()->isImplicitCXXThis() == + MR->getBase()->isImplicitCXXThis()) + return; const ValueDecl *LHSDecl = cast(ML->getMemberDecl()->getCanonicalDecl()); const ValueDecl *RHSDecl = @@ -14127,7 +14131,7 @@ if (const ReferenceType *RefTy = LHSDecl->getType()->getAs()) if (RefTy->getPointeeType().isVolatileQualified()) return; - + Sema.Diag(Loc, diag::warn_identity_field_assign) << 0; } @@ -14171,7 +14175,8 @@ if (CompoundType.isNull()) { Expr *RHSCheck = RHS.get(); - CheckIdentityFieldAssignment(LHSExpr, RHSCheck, Loc, *this); + CheckIdentityFieldAssignment(LHSExpr, RHSCheck, /*IsCompound*/ false, Loc, + *this); QualType LHSTy(LHSType); ConvTy = CheckSingleAssignmentConstraints(LHSTy, RHS); @@ -15644,14 +15649,17 @@ Expr *LHS, Expr *RHS) { switch (Opc) { case BO_Assign: + // Skip diagnose on compound assignment. + DiagnoseSelfAssignment(S, LHS, RHS, OpLoc, false); + [[fallthrough]]; case BO_DivAssign: case BO_RemAssign: case BO_SubAssign: case BO_AndAssign: case BO_OrAssign: case BO_XorAssign: - DiagnoseSelfAssignment(S, LHS, RHS, OpLoc, false); - CheckIdentityFieldAssignment(LHS, RHS, OpLoc, S); + CheckIdentityFieldAssignment(LHS, RHS, /*IsCompound*/ (Opc != BO_Assign), + OpLoc, S); break; default: break; diff --git a/clang/test/SemaCXX/warn-self-assign-field-overloaded.cpp b/clang/test/SemaCXX/warn-self-assign-field-overloaded.cpp --- a/clang/test/SemaCXX/warn-self-assign-field-overloaded.cpp +++ b/clang/test/SemaCXX/warn-self-assign-field-overloaded.cpp @@ -58,15 +58,49 @@ #ifndef DUMMY a *= a; - a /= a; // expected-warning {{assigning field to itself}} - a %= a; // expected-warning {{assigning field to itself}} + a /= a; + a %= a; a += a; - a -= a; // expected-warning {{assigning field to itself}} + a -= a; a <<= a; a >>= a; - a &= a; // expected-warning {{assigning field to itself}} - a |= a; // expected-warning {{assigning field to itself}} - a ^= a; // expected-warning {{assigning field to itself}} + a &= a; + a |= a; + a ^= a; + + this->a *= a; + this->a /= a; // expected-warning {{assigning field to itself}} + this->a %= a; // expected-warning {{assigning field to itself}} + this->a += a; + this->a -= a; // expected-warning {{assigning field to itself}} + this->a <<= a; + this->a >>= a; + this->a &= a; // expected-warning {{assigning field to itself}} + this->a |= a; // expected-warning {{assigning field to itself}} + this->a ^= a; // expected-warning {{assigning field to itself}} + + a *= this->a; + a /= this->a; // expected-warning {{assigning field to itself}} + a %= this->a; // expected-warning {{assigning field to itself}} + a += this->a; + a -= this->a; // expected-warning {{assigning field to itself}} + a <<= this->a; + a >>= this->a; + a &= this->a; // expected-warning {{assigning field to itself}} + a |= this->a; // expected-warning {{assigning field to itself}} + a ^= this->a; // expected-warning {{assigning field to itself}} + + this->a *= this->a; + this->a /= this->a; + this->a %= this->a; + this->a += this->a; + this->a -= this->a; + this->a <<= this->a; + this->a >>= this->a; + this->a &= this->a; + this->a |= this->a; + this->a ^= this->a; + #endif } diff --git a/clang/test/SemaCXX/warn-self-assign-overloaded.cpp b/clang/test/SemaCXX/warn-self-assign-overloaded.cpp --- a/clang/test/SemaCXX/warn-self-assign-overloaded.cpp +++ b/clang/test/SemaCXX/warn-self-assign-overloaded.cpp @@ -53,15 +53,15 @@ #ifndef DUMMY a *= a; - a /= a; // expected-warning {{explicitly assigning}} - a %= a; // expected-warning {{explicitly assigning}} + a /= a; + a %= a; a += a; - a -= a; // expected-warning {{explicitly assigning}} + a -= a; a <<= a; a >>= a; - a &= a; // expected-warning {{explicitly assigning}} - a |= a; // expected-warning {{explicitly assigning}} - a ^= a; // expected-warning {{explicitly assigning}} + a &= a; + a |= a; + a ^= a; #endif }