From d2d3fbf13186aa57a70b726b300cb4ea2c2bcb89 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Wed, 9 Oct 2019 02:04:54 +0000 Subject: [c++20] P1152R4: warn on any simple-assignment to a volatile lvalue whose value is not ignored. We don't warn on all the cases that are deprecated: specifically, we choose to not warn for now if there are parentheses around the assignment but its value is not actually used. This seems like a more defensible rule, particularly for cases like sizeof(v = a), where the parens are part of the operand rather than the sizeof syntax. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@374135 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Sema/SemaExpr.cpp | 51 +++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 43 insertions(+), 8 deletions(-) (limited to 'lib/Sema/SemaExpr.cpp') diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index b691668da8..23d3171505 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -3801,6 +3801,16 @@ bool Sema::CheckUnaryExprOrTypeTraitOperand(Expr *E, QualType ExprTy = E->getType(); assert(!ExprTy->isReferenceType()); + bool IsUnevaluatedOperand = + (ExprKind == UETT_SizeOf || ExprKind == UETT_AlignOf || + ExprKind == UETT_PreferredAlignOf); + if (IsUnevaluatedOperand) { + ExprResult Result = CheckUnevaluatedOperand(E); + if (Result.isInvalid()) + return true; + E = Result.get(); + } + if (ExprKind == UETT_VecStep) return CheckVecStepTraitOperandType(*this, ExprTy, E->getExprLoc(), E->getSourceRange()); @@ -3838,9 +3848,8 @@ bool Sema::CheckUnaryExprOrTypeTraitOperand(Expr *E, // The operand for sizeof and alignof is in an unevaluated expression context, // so side effects could result in unintended consequences. - if ((ExprKind == UETT_SizeOf || ExprKind == UETT_AlignOf || - ExprKind == UETT_PreferredAlignOf) && - !inTemplateInstantiation() && E->HasSideEffects(Context, false)) + if (IsUnevaluatedOperand && !inTemplateInstantiation() && + E->HasSideEffects(Context, false)) Diag(E->getExprLoc(), diag::warn_side_effects_unevaluated_context); if (CheckObjCTraitOperandConstraints(*this, ExprTy, E->getExprLoc(), @@ -3939,8 +3948,6 @@ bool Sema::CheckUnaryExprOrTypeTraitOperand(QualType ExprType, } static bool CheckAlignOfExpr(Sema &S, Expr *E, UnaryExprOrTypeTrait ExprKind) { - E = E->IgnoreParens(); - // Cannot know anything else if the expression is dependent. if (E->isTypeDependent()) return false; @@ -3952,9 +3959,10 @@ static bool CheckAlignOfExpr(Sema &S, Expr *E, UnaryExprOrTypeTrait ExprKind) { } ValueDecl *D = nullptr; - if (DeclRefExpr *DRE = dyn_cast(E)) { + Expr *Inner = E->IgnoreParens(); + if (DeclRefExpr *DRE = dyn_cast(Inner)) { D = DRE->getDecl(); - } else if (MemberExpr *ME = dyn_cast(E)) { + } else if (MemberExpr *ME = dyn_cast(Inner)) { D = ME->getMemberDecl(); } @@ -11944,7 +11952,7 @@ QualType Sema::CheckAssignmentOperands(Expr *LHSExpr, ExprResult &RHS, // A simple-assignment whose left operand is of a volatile-qualified // type is deprecated unless the assignment is either a discarded-value // expression or an unevaluated operand - // FIXME: Implement checks for this. + ExprEvalContexts.back().VolatileAssignmentLHSs.push_back(LHSExpr); } else { // C++2a [expr.ass]p6: // [Compound-assignment] expressions are deprecated if E1 has @@ -15082,6 +15090,26 @@ void Sema::WarnOnPendingNoDerefs(ExpressionEvaluationContextRecord &Rec) { Rec.PossibleDerefs.clear(); } +/// Check whether E, which is either a discarded-value expression or an +/// unevaluated operand, is a simple-assignment to a volatlie-qualified lvalue, +/// and if so, remove it from the list of volatile-qualified assignments that +/// we are going to warn are deprecated. +void Sema::CheckUnusedVolatileAssignment(Expr *E) { + if (!E->getType().isVolatileQualified() || !getLangOpts().CPlusPlus2a) + return; + + // Note: ignoring parens here is not justified by the standard rules, but + // ignoring parentheses seems like a more reasonable approach, and this only + // drives a deprecation warning so doesn't affect conformance. + if (auto *BO = dyn_cast(E->IgnoreParenImpCasts())) { + if (BO->getOpcode() == BO_Assign) { + auto &LHSs = ExprEvalContexts.back().VolatileAssignmentLHSs; + LHSs.erase(std::remove(LHSs.begin(), LHSs.end(), BO->getLHS()), + LHSs.end()); + } + } +} + void Sema::PopExpressionEvaluationContext() { ExpressionEvaluationContextRecord& Rec = ExprEvalContexts.back(); unsigned NumTypos = Rec.NumTypos; @@ -15116,6 +15144,13 @@ void Sema::PopExpressionEvaluationContext() { WarnOnPendingNoDerefs(Rec); + // Warn on any volatile-qualified simple-assignments that are not discarded- + // value expressions nor unevaluated operands (those cases get removed from + // this list by CheckUnusedVolatileAssignment). + for (auto *BO : Rec.VolatileAssignmentLHSs) + Diag(BO->getBeginLoc(), diag::warn_deprecated_simple_assign_volatile) + << BO->getType(); + // When are coming out of an unevaluated context, clear out any // temporaries that we may have created as part of the evaluation of // the expression in that context: they aren't relevant because they -- cgit v1.2.1