"place parentheses around the %0 expression to evaluate it first">;
def note_precedence_bitwise_silence : Note<
"place parentheses around the %0 expression to silence this warning">;
+
+def warn_logical_instead_of_bitwise : Warning<
+ "use of logical %0 with constant operand; switch to bitwise %1 or "
+ "remove constant">, InGroup<DiagGroup<"logical-bitwise-confusion">>;
def err_sizeof_nonfragile_interface : Error<
"invalid application of '%select{alignof|sizeof}1' to interface %0 in "
QualType CheckBitwiseOperands( // C99 6.5.[10...12]
Expr *&lex, Expr *&rex, SourceLocation OpLoc, bool isCompAssign = false);
QualType CheckLogicalOperands( // C99 6.5.[13,14]
- Expr *&lex, Expr *&rex, SourceLocation OpLoc);
+ Expr *&lex, Expr *&rex, SourceLocation OpLoc, unsigned Opc);
// CheckAssignmentOperands is used for both simple and compound assignment.
// For simple assignment, pass both expressions and a null converted type.
// For compound assignment, pass both expressions and the converted type.
}
inline QualType Sema::CheckLogicalOperands( // C99 6.5.[13,14]
- Expr *&lex, Expr *&rex, SourceLocation Loc) {
+ Expr *&lex, Expr *&rex, SourceLocation Loc, unsigned Opc) {
+
+ // Diagnose cases where the user write a logical and/or but probably meant a
+ // bitwise one. We do this when the LHS is a non-bool integer and the RHS
+ // is a constant.
+ if (lex->getType()->isIntegerType() && !lex->getType()->isBooleanType() &&
+ rex->getType()->isIntegerType() && rex->isEvaluatable(Context) &&
+ !Loc.isMacroID())
+ Diag(Loc, diag::warn_logical_instead_of_bitwise)
+ << rex->getSourceRange()
+ << (Opc == BinaryOperator::LAnd ? "&&" : "||")
+ << (Opc == BinaryOperator::LAnd ? "&" : "|");
+
+
+
if (!Context.getLangOptions().CPlusPlus) {
UsualUnaryConversions(lex);
UsualUnaryConversions(rex);
break;
case BinaryOperator::LAnd:
case BinaryOperator::LOr:
- ResultTy = CheckLogicalOperands(lhs, rhs, OpLoc);
+ ResultTy = CheckLogicalOperands(lhs, rhs, OpLoc, Opc);
break;
case BinaryOperator::MulAssign:
case BinaryOperator::DivAssign:
// Make sure we don't crash generating y; its value is constant, but the
// initializer has side effects, so EmitConstantExpr should fail.
int x();
-int y = x() && 0;
+int y = x() && 0; // expected-warning {{use of logical && with constant operand}}
*(volatile int*)0 = 0; // Ok.
}
+int test20(int x) {
+ return x && 4; // expected-warning {{use of logical && with constant operand; switch to bitwise & or remove constant}}
+}
// Comma tests
int comma1[0?1,2:3]; // expected-warning {{expression result unused}}
-int comma2[1||(1,2)]; // expected-warning {{expression result unused}}
+int comma2[1||(1,2)]; // expected-warning {{expression result unused}} \
+ // expected-warning {{use of logical || with constant operand}}
int comma3[(1,2)]; // expected-warning {{size of static array must be an integer constant expression}} \
// expected-warning {{expression result unused}}
}
switch (cond) {
- case g() && 0: // expected-error {{expression is not an integer constant expression}} // expected-note {{subexpression not valid in an integer constant expression}}
+ case g() && 0: // expected-error {{expression is not an integer constant expression}} // expected-note {{subexpression not valid in an integer constant expression}} \
+ expected-warning {{use of logical && with constant operand}}
break;
}
switch (cond) {
- case 0 ... g() || 1: // expected-error {{expression is not an integer constant expression}} // expected-note {{subexpression not valid in an integer constant expression}}
+ case 0 ... g() || 1: // expected-error {{expression is not an integer constant expression}} // expected-note {{subexpression not valid in an integer constant expression}} \\
+ expected-warning {{use of logical || with constant operand}}
break;
}
}
void test2() {
int n = 2;
- static_assert_arg_is_bool(n && 4);
- static_assert_arg_is_bool(n || 5);
+ static_assert_arg_is_bool(n && 4); // expected-warning {{use of logical && with constant operand}}
+ static_assert_arg_is_bool(n || 5); // expected-warning {{use of logical || with constant operand}}
}
}
int n = 3;
- switch (n && 1) { // expected-warning {{bool}}
+ switch (n && 1) { // expected-warning {{bool}} \
+ // expected-warning {{use of logical && with constant operand}}
case 1:
break;
}