From 28b38c277a2941e9e891b2db30652cfd962f070b Mon Sep 17 00:00:00 2001 From: David Bolvansky Date: Mon, 23 Sep 2019 22:09:49 +0000 Subject: [PATCH] [Diagnostics] Warn for enum constants in bool context (-Wint-in-bool-context; GCC compatibility) Extracted from D63082. llvm-svn: 372664 --- clang/include/clang/Basic/DiagnosticSemaKinds.td | 7 ++++++ clang/lib/Sema/SemaExpr.cpp | 14 +++++++++++- clang/test/Sema/warn-int-in-bool-context.c | 28 +++++++++++++++++++++++- 3 files changed, 47 insertions(+), 2 deletions(-) diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 26b328b..9e00591 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -5720,6 +5720,9 @@ def warn_precedence_conditional : Warning< def note_precedence_conditional_first : Note< "place parentheses around the '?:' expression to evaluate it first">; +def warn_enum_constant_in_bool_context : Warning< + "converting the enum constant to a boolean">, + InGroup; def warn_left_shift_in_bool_context : Warning< "converting the result of '<<' to a boolean; did you mean '(%0) != 0'?">, InGroup; @@ -6156,6 +6159,10 @@ def warn_comparison_of_mixed_enum_types : Warning< "comparison of two values with different enumeration types" "%diff{ ($ and $)|}0,1">, InGroup; +def warn_conditional_mixed_enum_types : Warning< + "enumeration type mismatch in conditional expression" + "%diff{ ($ and $)|}0,1">, + InGroup; def warn_comparison_of_mixed_enum_types_switch : Warning< "comparison of two values with different enumeration types in switch statement" "%diff{ ($ and $)|}0,1">, diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 13463dc..a3808a9 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -11297,10 +11297,22 @@ inline QualType Sema::CheckLogicalOperands(ExprResult &LHS, ExprResult &RHS, if (LHS.get()->getType()->isVectorType() || RHS.get()->getType()->isVectorType()) return CheckVectorLogicalOperands(LHS, RHS, Loc); + bool EnumConstantInBoolContext = false; + for (const ExprResult &HS : {LHS, RHS}) { + if (const auto *DREHS = dyn_cast(HS.get())) { + const auto *ECDHS = dyn_cast(DREHS->getDecl()); + if (ECDHS && ECDHS->getInitVal() != 0 && ECDHS->getInitVal() != 1) + EnumConstantInBoolContext = true; + } + } + + if (EnumConstantInBoolContext) + Diag(Loc, diag::warn_enum_constant_in_bool_context); + // 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 (LHS.get()->getType()->isIntegerType() && + if (!EnumConstantInBoolContext && LHS.get()->getType()->isIntegerType() && !LHS.get()->getType()->isBooleanType() && RHS.get()->getType()->isIntegerType() && !RHS.get()->isValueDependent() && // Don't warn in macros or template instantiations. diff --git a/clang/test/Sema/warn-int-in-bool-context.c b/clang/test/Sema/warn-int-in-bool-context.c index 0a0d88f..f190fdf 100644 --- a/clang/test/Sema/warn-int-in-bool-context.c +++ b/clang/test/Sema/warn-int-in-bool-context.c @@ -14,7 +14,13 @@ typedef bool boolean; typedef _Bool boolean; #endif -int test(int a) { +enum num { + zero, + one, + two, +}; + +int test(int a, enum num n) { boolean r; r = (1 << 3); // expected-warning {{converting the result of '<<' to a boolean; did you mean '(1 << 3) != 0'?}} r = TWO << 7; // expected-warning {{converting the result of '<<' to a boolean; did you mean '(2 << 7) != 0'?}} @@ -26,6 +32,26 @@ int test(int a) { if (a << TWO) // expected-warning {{converting the result of '<<' to a boolean; did you mean '(a << 2) != 0'?}} return a; + if (n || two) + // expected-warning@-1 {{converting the enum constant to a boolean}} + return a; + + if (n == one || two) + // expected-warning@-1 {{converting the enum constant to a boolean}} + return a; + + if (r && two) + // expected-warning@-1 {{converting the enum constant to a boolean}} + return a; + + if (two && r) + // expected-warning@-1 {{converting the enum constant to a boolean}} + return a; + + if (n == one && two) + // expected-warning@-1 {{converting the enum constant to a boolean}} + return a; + // Don't warn in macros. return SHIFT(1, a); } -- 2.7.4