Higuoxing updated this revision to Diff 151290. Higuoxing added a comment. Ping, well, I think I understand `@dexonsmith`'s idea.
`Actionable` macro argument is just like something like this #define foo(x) ( (void)(x) ) when we using it by foo(a && b || c); we could add parentheses for it by foo((a && b) || c); However, the following example is `not actionable` #define foo(op0, op1, x, y, z) ( (void)(x op0 y op1 z) ) when we using it by foo(&&, ||, x, y, z); because, we also probably use it by foo(+, *, x, y, z) So, we cannot add parentheses for it carelessly... My opinion is that, to judge if an `expr` is actionable is to test if the op and both LHS and RHS are from same context or same argument position from macro... But I cannot find such API for indicating a `expression` expanded position exactly. There are API like: `isMacroArgExpansion` and `isMacroBodyExpansion` which is determined by row string positions... So, what I can do now for this is that using API `isMacroArgExpansion()` to let it check the parentheses defined or expanded totally inside a macro like #define foo(x, y, z) ( x && y || z ) The shortage is that we cannot check parentheses for this case: foo(x && y || z); because the operator is expanded from macro arguments. Thanks https://reviews.llvm.org/D47687 Files: lib/Sema/SemaExpr.cpp test/Sema/logical-op-parentheses-in-macros.c
Index: test/Sema/logical-op-parentheses-in-macros.c =================================================================== --- test/Sema/logical-op-parentheses-in-macros.c +++ test/Sema/logical-op-parentheses-in-macros.c @@ -0,0 +1,49 @@ +// RUN: %clang_cc1 -Wparentheses -fsyntax-only -verify=logical_op_parentheses_check %s + +// operator of this case is expanded from macro function argument +#define macro_op_parentheses_check(x) ( \ + ( (void)(x) ) \ +) + +// operator of this case is expanded from macro function body +#define macro_op_parentheses_check_ops_args(op0, op1, x, y, z) ( \ + ( (void) (x op0 y op1 z ) ) \ +) + +// operator of this case is expanded from macro function body +#define macro_op_parentheses_check_ops_args2(op0, op1, op2, w, x, y, z) ( \ + ( (void) (w op0 x op1 y op2 z) ) \ +) + +// operator of this case is expanded from marco body +#define macro_op_parentheses_check_ops_body(x, y, z) ( \ + ( (void) (x && y || z) ) \ +) + +void logical_op_from_macro_arguments(unsigned i) { + macro_op_parentheses_check(i || i && i); // no warning. + macro_op_parentheses_check(i || i && "I love LLVM"); // no warning. + macro_op_parentheses_check("I love LLVM" && i || i); // no warning. + + macro_op_parentheses_check(i || i && "I love LLVM" || i); // no warning. + macro_op_parentheses_check(i || "I love LLVM" && i || i); // no warning. + macro_op_parentheses_check(i && i || 0); // no warning. + macro_op_parentheses_check(0 || i && i); // no warning. +} + +void logical_op_from_macro_arguments2(unsigned i) { + macro_op_parentheses_check_ops_args(||, &&, i, i, i); // no warning. + macro_op_parentheses_check_ops_args(||, &&, i, i, "I love LLVM"); // no warning. + macro_op_parentheses_check_ops_args(&&, ||, "I love LLVM", i, i); // no warning. + + macro_op_parentheses_check_ops_args2(||, &&, ||, i, i, "I love LLVM", i); // no warning. + macro_op_parentheses_check_ops_args2(||, &&, ||, i, "I love LLVM", i, i); // no warning. + + macro_op_parentheses_check_ops_args(&&, ||, i, i, 0); // no warning. + macro_op_parentheses_check_ops_args(||, &&, 0, i, i); // no warning. +} + +void logical_op_from_macro_body(unsigned i) { + macro_op_parentheses_check_ops_body(i, i, i); // logical_op_parentheses_check-warning {{'&&' within '||'}} \ + // logical_op_parentheses_check-note {{place parentheses around the '&&' expression to silence this warning}} +} \ No newline at end of file Index: lib/Sema/SemaExpr.cpp =================================================================== --- lib/Sema/SemaExpr.cpp +++ lib/Sema/SemaExpr.cpp @@ -12172,7 +12172,7 @@ EmitDiagnosticForLogicalAndInLogicalOr(Sema &Self, SourceLocation OpLoc, BinaryOperator *Bop) { assert(Bop->getOpcode() == BO_LAnd); - Self.Diag(Bop->getOperatorLoc(), diag::warn_logical_and_in_logical_or) + Self.Diag(Bop->getOperatorLoc(), diag::warn_logical_and_in_logical_or) << Bop->getSourceRange() << OpLoc; SuggestParentheses(Self, Bop->getOperatorLoc(), Self.PDiag(diag::note_precedence_silence) @@ -12205,6 +12205,7 @@ if (EvaluatesAsFalse(S, RHSExpr)) return; // If it's "1 && a || b" don't warn since the precedence doesn't matter. + // And 'assert("some message" && a || b)' don't warn as well. if (!EvaluatesAsTrue(S, Bop->getLHS())) return EmitDiagnosticForLogicalAndInLogicalOr(S, OpLoc, Bop); } else if (Bop->getOpcode() == BO_LOr) { @@ -12227,6 +12228,7 @@ if (EvaluatesAsFalse(S, LHSExpr)) return; // If it's "a || b && 1" don't warn since the precedence doesn't matter. + // And 'assert(a || b && "some message")' don't warn as well. if (!EvaluatesAsTrue(S, Bop->getRHS())) return EmitDiagnosticForLogicalAndInLogicalOr(S, OpLoc, Bop); } @@ -12309,8 +12311,16 @@ } // Warn about arg1 || arg2 && arg3, as GCC 4.3+ does. - // We don't warn for 'assert(a || b && "bad")' since this is safe. - if (Opc == BO_LOr && !OpLoc.isMacroID()/* Don't warn in macros. */) { + // Here we will not skip 'logical and in logical or' checking + // in macros, since 'assert(a || b && "some message")' is equal + // to '(a || b && 1)' and 'assert("some message" && a || b)' is + // equal to '(1 && a || b)'. + if (Opc == BO_LOr && + !Self.getSourceManager().isMacroArgExpansion(OpLoc)) { + // FIXME: we need a smarter parentheses checker to prevent emit + // useless warnings when logical operator comes from macro + // arguments like: + // #define DOUBLE_OP(OP1, OP2, X, Y, Z) (X OP1 Y OP2 Z) DiagnoseLogicalAndInLogicalOrLHS(Self, OpLoc, LHSExpr, RHSExpr); DiagnoseLogicalAndInLogicalOrRHS(Self, OpLoc, LHSExpr, RHSExpr); }
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits