diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -12326,6 +12326,13 @@ case UO_AddrOf: // should be impossible return IntRange::forValueOfType(C, GetExprType(E)); + case UO_Not: + // unary not promotes boolean to integer + if (UO->getSubExpr()->isKnownToHaveBooleanValue()) + return IntRange(MaxWidth, false); + + LLVM_FALLTHROUGH; + default: return GetExprRange(C, UO->getSubExpr(), MaxWidth, InConstantContext, Approximate); diff --git a/clang/test/Sema/compare.c b/clang/test/Sema/compare.c --- a/clang/test/Sema/compare.c +++ b/clang/test/Sema/compare.c @@ -419,3 +419,25 @@ if (x == y) x = y; // no warning if (y == x) y = x; // no warning } + +int warn_on_different_sign_after_unary_operator(unsigned a, int b) { + return + // unary not promotes boolean to int + (a > ~(!b)) // expected-warning {{comparison of integers of different signs: 'unsigned int' and 'int'}} + && + (a > -(b)) // expected-warning {{comparison of integers of different signs: 'unsigned int' and 'int'}} + && + (a > ++b) // expected-warning {{comparison of integers of different signs: 'unsigned int' and 'int'}} + && + (a > --b) // expected-warning {{comparison of integers of different signs: 'unsigned int' and 'int'}} + && + // unary not promotes boolean to int + (b > ~(!a)) // no warning + && + (b > -(a)) // expected-warning {{comparison of integers of different signs: 'int' and 'unsigned int'}} + && + (b > ++a) // expected-warning {{comparison of integers of different signs: 'int' and 'unsigned int'}} + && + (b > --a) // expected-warning {{comparison of integers of different signs: 'int' and 'unsigned int'}} + ; +}