Index: include/clang/Basic/DiagnosticGroups.td =================================================================== --- include/clang/Basic/DiagnosticGroups.td +++ include/clang/Basic/DiagnosticGroups.td @@ -38,7 +38,9 @@ def StringConversion : DiagGroup<"string-conversion">; def SignConversion : DiagGroup<"sign-conversion">; def PointerBoolConversion : DiagGroup<"pointer-bool-conversion">; -def BoolConversion : DiagGroup<"bool-conversion", [ PointerBoolConversion ] >; +def UndefinedBoolConversion : DiagGroup<"undefined-bool-conversion">; +def BoolConversion : DiagGroup<"bool-conversion", [PointerBoolConversion, + UndefinedBoolConversion]>; def IntConversion : DiagGroup<"int-conversion">; def EnumConversion : DiagGroup<"enum-conversion">; def FloatConversion : DiagGroup<"float-conversion">; @@ -298,10 +300,12 @@ def TautologicalOutOfRangeCompare : DiagGroup<"tautological-constant-out-of-range-compare">; def TautologicalPointerCompare : DiagGroup<"tautological-pointer-compare">; def TautologicalOverlapCompare : DiagGroup<"tautological-overlap-compare">; +def TautologicalUndefinedCompare : DiagGroup<"tautological-undefined-compare">; def TautologicalCompare : DiagGroup<"tautological-compare", [TautologicalOutOfRangeCompare, TautologicalPointerCompare, - TautologicalOverlapCompare]>; + TautologicalOverlapCompare, + TautologicalUndefinedCompare]>; def HeaderHygiene : DiagGroup<"header-hygiene">; def DuplicateDeclSpecifier : DiagGroup<"duplicate-decl-specifier">; def CompareDistinctPointerType : DiagGroup<"compare-distinct-pointer-types">; Index: include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- include/clang/Basic/DiagnosticSemaKinds.td +++ include/clang/Basic/DiagnosticSemaKinds.td @@ -2388,10 +2388,29 @@ "address of%select{| function| array}0 '%1' will always evaluate to " "'true'">, InGroup; +def warn_this_bool_conversion : Warning< + "this pointer can only be false in undefined contexts, which may be " + "removed during optimization">, + InGroup, DefaultIgnore; +def warn_address_of_reference_bool_conversion : Warning< + "pointer to reference can only be false in undefined contexts, which may be " + "removed during optimization">, + InGroup, DefaultIgnore; + def warn_null_pointer_compare : Warning< "comparison of %select{address of|function|array}0 '%1' %select{not |}2" "equal to a null pointer is always %select{true|false}2">, InGroup; +def warn_this_null_compare : Warning< + "this pointer %select{not |}0equal to null pointer can only be " + "%select{false|true}0 in undefined contexts, which may be removed during " + "optimization">, + InGroup, DefaultIgnore; +def warn_address_of_reference_null_compare : Warning< + "pointer to reference %select{not |}0equal to null pointer can only be " + "%select{false|true}0 in undefined contexts, which may be removed during " + "optimization">, + InGroup, DefaultIgnore; def note_function_warning_silence : Note< "prefix with the address-of operator to silence this warning">; Index: lib/Sema/SemaChecking.cpp =================================================================== --- lib/Sema/SemaChecking.cpp +++ lib/Sema/SemaChecking.cpp @@ -6168,6 +6168,13 @@ const bool IsCompare = NullKind != Expr::NPCK_NotNull; + if (isa(E)) { + unsigned DiagID = IsCompare ? diag::warn_this_null_compare + : diag::warn_this_bool_conversion; + Diag(E->getExprLoc(), DiagID) << E->getSourceRange() << Range << IsEqual; + return; + } + bool IsAddressOf = false; if (UnaryOperator *UO = dyn_cast(E)) { @@ -6197,9 +6204,14 @@ // Address of function is used to silence the function warning. if (IsFunction) return; - // Address of reference can be null. - if (T->isReferenceType()) + + if (T->isReferenceType()) { + unsigned DiagID = IsCompare + ? diag::warn_address_of_reference_null_compare + : diag::warn_address_of_reference_bool_conversion; + Diag(E->getExprLoc(), DiagID) << E->getSourceRange() << Range << IsEqual; return; + } } // Found nothing. Index: test/SemaCXX/warn-tautological-undefined-compare.cpp =================================================================== --- test/SemaCXX/warn-tautological-undefined-compare.cpp +++ test/SemaCXX/warn-tautological-undefined-compare.cpp @@ -0,0 +1,32 @@ +// RUN: %clang_cc1 -fsyntax-only -verify -Wtautological-undefined-compare %s +// RUN: %clang_cc1 -fsyntax-only -verify -Wtautological-compare %s + +void test1(int &x) { + if (x == 1) { } + if (&x == 0) { } + // expected-warning@-1{{pointer to reference equal to null pointer can only be true in undefined contexts, which may be removed during optimization}} + if (&x != 0) { } + // expected-warning@-1{{pointer to reference not equal to null pointer can only be false in undefined contexts, which may be removed during optimization}} +} + +class test2 { + test2() : x(y) {} + + void foo() { + if (this == 0) { } + // expected-warning@-1{{this pointer equal to null pointer can only be true in undefined contexts, which may be removed during optimization}} + if (this != 0) { } + // expected-warning@-1{{this pointer not equal to null pointer can only be false in undefined contexts, which may be removed during optimization}} + } + + void bar() { + if (x == 1) { } + if (&x == 0) { } + // expected-warning@-1{{pointer to reference equal to null pointer can only be true in undefined contexts, which may be removed during optimization}} + if (&x != 0) { } + // expected-warning@-1{{pointer to reference not equal to null pointer can only be false in undefined contexts, which may be removed during optimization}} + } + + int &x; + int y; +}; Index: test/SemaCXX/warn-undefined-bool-conversion.cpp =================================================================== --- test/SemaCXX/warn-undefined-bool-conversion.cpp +++ test/SemaCXX/warn-undefined-bool-conversion.cpp @@ -0,0 +1,35 @@ +// RUN: %clang_cc1 -fsyntax-only -verify -Wundefined-bool-conversion %s +// RUN: %clang_cc1 -fsyntax-only -verify -Wbool-conversion %s + +void test1(int &x) { + if (x == 1) { } + if (&x) { } + // expected-warning@-1{{pointer to reference can only be false in undefined contexts, which may be removed during optimization}} + + if (!&x) { } + // expected-warning@-1{{pointer to reference can only be false in undefined contexts, which may be removed during optimization}} +} + +class test2 { + test2() : x(y) {} + + void foo() { + if (this) { } + // expected-warning@-1{{this pointer can only be false in undefined contexts, which may be removed during optimization}} + + if (!this) { } + // expected-warning@-1{{this pointer can only be false in undefined contexts, which may be removed during optimization}} + } + + void bar() { + if (x == 1) { } + if (&x) { } + // expected-warning@-1{{pointer to reference can only be false in undefined contexts, which may be removed during optimization}} + + if (!&x) { } + // expected-warning@-1{{pointer to reference can only be false in undefined contexts, which may be removed during optimization}} + } + + int &x; + int y; +};