Extend tautological compare and bool conversion warnings to undefined pointer
operations. These are cases where all defined behavior will give the
expression one value, while the other value can only result from undefined
behavior, which the optimizer can remove. These cases are addresses of
references and the this pointer. This warning was requested in PR19899 in
response to commit r209723.
http://reviews.llvm.org/D3999
Files:
include/clang/Basic/DiagnosticGroups.td
include/clang/Basic/DiagnosticSemaKinds.td
lib/Sema/SemaChecking.cpp
test/SemaCXX/warn-tautological-undefined-compare.cpp
test/SemaCXX/warn-undefined-bool-conversion.cpp
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<CXXThisExpr>(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<UnaryOperator>(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;
+};
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<PointerBoolConversion>;
+def warn_this_bool_conversion : Warning<
+ "this pointer can only be false in undefined contexts, which may be "
+ "removed during optimization">,
+ InGroup<UndefinedBoolConversion>, 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<UndefinedBoolConversion>, 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<TautologicalPointerCompare>;
+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<TautologicalUndefinedCompare>, 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<TautologicalUndefinedCompare>, DefaultIgnore;
def note_function_warning_silence : Note<
"prefix with the address-of operator to silence this warning">;
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits