From 2a6e528cbd687e22744d5d7eba428afea99da300 Mon Sep 17 00:00:00 2001 From: Richard Trieu Date: Wed, 17 Apr 2013 02:12:45 +0000 Subject: [PATCH] Add warning group -Woverloaded-shift-op-parentheses to -Wparentheses. This will fire on code such as: cout << x == 0; which the compiler will intrepret as (cout << x) == 0; This warning comes with two fixits attached to notes, one for parentheses to silence the warning, and another to evaluate the comparison first. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@179662 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Basic/DiagnosticGroups.td | 2 ++ include/clang/Basic/DiagnosticSemaKinds.td | 7 +++++ lib/Sema/SemaExpr.cpp | 32 ++++++++++++++++++++++ test/Sema/parentheses.cpp | 6 ++++ 4 files changed, 47 insertions(+) diff --git a/include/clang/Basic/DiagnosticGroups.td b/include/clang/Basic/DiagnosticGroups.td index a12a4f974e..a7ef2185df 100644 --- a/include/clang/Basic/DiagnosticGroups.td +++ b/include/clang/Basic/DiagnosticGroups.td @@ -122,6 +122,7 @@ def GlobalConstructors : DiagGroup<"global-constructors">; def BitwiseOpParentheses: DiagGroup<"bitwise-op-parentheses">; def LogicalOpParentheses: DiagGroup<"logical-op-parentheses">; def ShiftOpParentheses: DiagGroup<"shift-op-parentheses">; +def OverloadedShiftOpParentheses: DiagGroup<"overloaded-shift-op-parentheses">; def DanglingElse: DiagGroup<"dangling-else">; def DanglingField : DiagGroup<"dangling-field">; def DistributedObjectModifiers : DiagGroup<"distributed-object-modifiers">; @@ -352,6 +353,7 @@ def Parentheses : DiagGroup<"parentheses", [LogicalOpParentheses, BitwiseOpParentheses, ShiftOpParentheses, + OverloadedShiftOpParentheses, ParenthesesOnEquality, DanglingElse]>; diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index fd9ea51df5..1330ad68b6 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -4041,6 +4041,13 @@ def warn_bitwise_and_in_bitwise_or : Warning< def warn_logical_and_in_logical_or : Warning< "'&&' within '||'">, InGroup; +def warn_overloaded_shift_in_comparison :Warning< + "overloaded operator %select{>>|<<}0 has lower precedence than " + "comparison operator">, + InGroup; +def note_evaluate_comparison_first :Note< + "place parentheses around comparison expression to evaluate it first">; + def warn_addition_in_bitshift : Warning< "operator '%0' has lower precedence than '%1'; " "'%1' will be evaluated first">, InGroup; diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index cdfdc09e06..ce60f9171f 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -8877,6 +8877,33 @@ static void DiagnoseAdditionInShift(Sema &S, SourceLocation OpLoc, } } +static void DiagnoseShiftCompare(Sema &S, SourceLocation OpLoc, + Expr *LHSExpr, Expr *RHSExpr) { + CXXOperatorCallExpr *OCE = dyn_cast(LHSExpr); + if (!OCE) + return; + + FunctionDecl *FD = OCE->getDirectCallee(); + if (!FD || !FD->isOverloadedOperator()) + return; + + OverloadedOperatorKind Kind = FD->getOverloadedOperator(); + if (Kind != OO_LessLess && Kind != OO_GreaterGreater) + return; + + S.Diag(OpLoc, diag::warn_overloaded_shift_in_comparison) + << LHSExpr->getSourceRange() << RHSExpr->getSourceRange() + << (Kind == OO_LessLess); + SuggestParentheses(S, OpLoc, + S.PDiag(diag::note_evaluate_comparison_first), + SourceRange(OCE->getArg(1)->getLocStart(), + RHSExpr->getLocEnd())); + SuggestParentheses(S, OCE->getOperatorLoc(), + S.PDiag(diag::note_precedence_silence) + << (Kind == OO_LessLess ? "<<" : ">>"), + OCE->getSourceRange()); +} + /// DiagnoseBinOpPrecedence - Emit warnings for expressions with tricky /// precedence. static void DiagnoseBinOpPrecedence(Sema &Self, BinaryOperatorKind Opc, @@ -8905,6 +8932,11 @@ static void DiagnoseBinOpPrecedence(Sema &Self, BinaryOperatorKind Opc, DiagnoseAdditionInShift(Self, OpLoc, LHSExpr, Shift); DiagnoseAdditionInShift(Self, OpLoc, RHSExpr, Shift); } + + // Warn on overloaded shift operators and comparisons, such as: + // cout << 5 == 4; + if (BinaryOperator::isComparisonOp(Opc)) + DiagnoseShiftCompare(Self, OpLoc, LHSExpr, RHSExpr); } // Binary Operators. 'Tok' is the token for the operator. diff --git a/test/Sema/parentheses.cpp b/test/Sema/parentheses.cpp index 145414a53a..58edc0ba29 100644 --- a/test/Sema/parentheses.cpp +++ b/test/Sema/parentheses.cpp @@ -29,6 +29,12 @@ void f(Stream& s, bool b) { (void)(s << b ? "foo" : "bar"); // expected-warning {{operator '?:' has lower precedence than '<<'}} \ // expected-note {{place parentheses around the '?:' expression to evaluate it first}} \ // expected-note {{place parentheses around the '<<' expression to silence this warning}} + (void)(s << 5 == 1); // expected-warning {{overloaded operator << has lower precedence than comparison operator}} \ + // expected-note {{place parentheses around the '<<' expression to silence this warning}} \ + // expected-note {{place parentheses around comparison expression to evaluate it first}} + (void)(s >> 5 == 1); // expected-warning {{overloaded operator >> has lower precedence than comparison operator}} \ + // expected-note {{place parentheses around the '>>' expression to silence this warning}} \ + // expected-note {{place parentheses around comparison expression to evaluate it first}} } struct S { -- 2.40.0