PR16074, implement warnings to catch pointer to boolean true and pointer to

null comparison when the pointer is known to be non-null.

This catches the array to pointer decay, function to pointer decay and
address of variables.  This does not catch address of function since this
has been previously used to silence a warning.

Pointer to bool conversion is under -Wbool-conversion.
Pointer to null comparison is under -Wtautological-pointer-compare, a sub-group
of -Wtautological-compare.

void foo() {
  int arr[5];
  int x;
  // warn on these conditionals
  if (foo);
  if (arr);
  if (&x);
  if (foo == null);
  if (arr == null);
  if (&x == null);

  if (&foo);  // no warning
}

llvm-svn: 202216
This commit is contained in:
Richard Trieu 2014-02-26 02:36:06 +00:00
parent f9be75f538
commit 3bb8b56a5d
21 changed files with 393 additions and 96 deletions

View File

@ -285,8 +285,10 @@ def StringPlusInt : DiagGroup<"string-plus-int">;
def StringPlusChar : DiagGroup<"string-plus-char">;
def StrncatSize : DiagGroup<"strncat-size">;
def TautologicalOutOfRangeCompare : DiagGroup<"tautological-constant-out-of-range-compare">;
def TautologicalPointerCompare : DiagGroup<"tautological-pointer-compare">;
def TautologicalCompare : DiagGroup<"tautological-compare",
[TautologicalOutOfRangeCompare]>;
[TautologicalOutOfRangeCompare,
TautologicalPointerCompare]>;
def HeaderHygiene : DiagGroup<"header-hygiene">;
def DuplicateDeclSpecifier : DiagGroup<"duplicate-decl-specifier">;
def CompareDistinctPointerType : DiagGroup<"compare-distinct-pointer-types">;

View File

@ -2322,12 +2322,19 @@ def warn_impcast_null_pointer_to_integer : Warning<
def warn_impcast_floating_point_to_bool : Warning<
"implicit conversion turns floating-point number into bool: %0 to %1">,
InGroup<ImplicitConversionFloatingPointToBool>;
def warn_impcast_function_to_bool : Warning<
"address of function %q0 will always evaluate to 'true'">,
def warn_impcast_pointer_to_bool : Warning<
"address of%select{| function| array}0 '%1' will always evaluate to "
"'true'">,
InGroup<BoolConversion>;
def note_function_to_bool_silence : Note<
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 note_function_warning_silence : Note<
"prefix with the address-of operator to silence this warning">;
def note_function_to_bool_call : Note<
def note_function_to_function_call : Note<
"suffix with parentheses to turn this into a function call">;
def warn_impcast_objective_c_literal_to_bool : Warning<
"implicit boolean conversion of Objective-C object literal always "

View File

@ -7470,6 +7470,10 @@ public:
bool DiagnoseConditionalForNull(Expr *LHSExpr, Expr *RHSExpr,
SourceLocation QuestionLoc);
void DiagnoseAlwaysNonNullPointer(Expr *E,
Expr::NullPointerConstantKind NullType,
bool IsEqual, SourceRange Range);
/// type checking for vector binary operators.
QualType CheckVectorOperands(ExprResult &LHS, ExprResult &RHS,
SourceLocation Loc, bool IsCompAssign);

View File

@ -5690,35 +5690,10 @@ void CheckImplicitConversion(Sema &S, Expr *E, QualType T,
return DiagnoseImpCast(S, E, T, CC,
diag::warn_impcast_objective_c_literal_to_bool);
}
if (Source->isFunctionType()) {
// Warn on function to bool. Checks free functions and static member
// functions. Weakly imported functions are excluded from the check,
// since it's common to test their value to check whether the linker
// found a definition for them.
ValueDecl *D = 0;
if (DeclRefExpr* R = dyn_cast<DeclRefExpr>(E)) {
D = R->getDecl();
} else if (MemberExpr *M = dyn_cast<MemberExpr>(E)) {
D = M->getMemberDecl();
}
if (D && !D->isWeak()) {
if (FunctionDecl* F = dyn_cast<FunctionDecl>(D)) {
S.Diag(E->getExprLoc(), diag::warn_impcast_function_to_bool)
<< F << E->getSourceRange() << SourceRange(CC);
S.Diag(E->getExprLoc(), diag::note_function_to_bool_silence)
<< FixItHint::CreateInsertion(E->getExprLoc(), "&");
QualType ReturnType;
UnresolvedSet<4> NonTemplateOverloads;
S.tryExprAsCall(*E, ReturnType, NonTemplateOverloads);
if (!ReturnType.isNull()
&& ReturnType->isSpecificBuiltinType(BuiltinType::Bool))
S.Diag(E->getExprLoc(), diag::note_function_to_bool_call)
<< FixItHint::CreateInsertion(
S.getPreprocessor().getLocForEndOfToken(E->getLocEnd()), "()");
return;
}
}
if (Source->isPointerType() || Source->canDecayToPointerType()) {
// Warn on pointer to bool conversion that is always true.
S.DiagnoseAlwaysNonNullPointer(E, Expr::NPCK_NotNull, /*IsEqual*/ false,
SourceRange(CC));
}
}
@ -6055,6 +6030,125 @@ void AnalyzeImplicitConversions(Sema &S, Expr *OrigE, SourceLocation CC) {
} // end anonymous namespace
enum {
AddressOf,
FunctionPointer,
ArrayPointer
};
/// \brief Diagnose pointers that are always non-null.
/// \param E the expression containing the pointer
/// \param NullKind NPCK_NotNull if E is a cast to bool, otherwise, E is
/// compared to a null pointer
/// \param IsEqual True when the comparison is equal to a null pointer
/// \param Range Extra SourceRange to highlight in the diagnostic
void Sema::DiagnoseAlwaysNonNullPointer(Expr *E,
Expr::NullPointerConstantKind NullKind,
bool IsEqual, SourceRange Range) {
// Don't warn inside macros.
if (E->getExprLoc().isMacroID())
return;
E = E->IgnoreImpCasts();
const bool IsCompare = NullKind != Expr::NPCK_NotNull;
bool IsAddressOf = false;
if (UnaryOperator *UO = dyn_cast<UnaryOperator>(E)) {
if (UO->getOpcode() != UO_AddrOf)
return;
IsAddressOf = true;
E = UO->getSubExpr();
}
// Expect to find a single Decl. Skip anything more complicated.
ValueDecl *D = 0;
if (DeclRefExpr *R = dyn_cast<DeclRefExpr>(E)) {
D = R->getDecl();
} else if (MemberExpr *M = dyn_cast<MemberExpr>(E)) {
D = M->getMemberDecl();
}
// Weak Decls can be null.
if (!D || D->isWeak())
return;
QualType T = D->getType();
const bool IsArray = T->isArrayType();
const bool IsFunction = T->isFunctionType();
if (IsAddressOf) {
// Address of function is used to silence the function warning.
if (IsFunction)
return;
// Address of reference can be null.
if (T->isReferenceType())
return;
}
// Found nothing.
if (!IsAddressOf && !IsFunction && !IsArray)
return;
// Pretty print the expression for the diagnostic.
std::string Str;
llvm::raw_string_ostream S(Str);
E->printPretty(S, 0, getPrintingPolicy());
unsigned DiagID = IsCompare ? diag::warn_null_pointer_compare
: diag::warn_impcast_pointer_to_bool;
unsigned DiagType;
if (IsAddressOf)
DiagType = AddressOf;
else if (IsFunction)
DiagType = FunctionPointer;
else if (IsArray)
DiagType = ArrayPointer;
else
llvm_unreachable("Could not determine diagnostic.");
Diag(E->getExprLoc(), DiagID) << DiagType << S.str() << E->getSourceRange()
<< Range << IsEqual;
if (!IsFunction)
return;
// Suggest '&' to silence the function warning.
Diag(E->getExprLoc(), diag::note_function_warning_silence)
<< FixItHint::CreateInsertion(E->getLocStart(), "&");
// Check to see if '()' fixit should be emitted.
QualType ReturnType;
UnresolvedSet<4> NonTemplateOverloads;
tryExprAsCall(*E, ReturnType, NonTemplateOverloads);
if (ReturnType.isNull())
return;
if (IsCompare) {
// There are two cases here. If there is null constant, the only suggest
// for a pointer return type. If the null is 0, then suggest if the return
// type is a pointer or an integer type.
if (!ReturnType->isPointerType()) {
if (NullKind == Expr::NPCK_ZeroExpression ||
NullKind == Expr::NPCK_ZeroLiteral) {
if (!ReturnType->isIntegerType())
return;
} else {
return;
}
}
} else { // !IsCompare
// For function to bool, only suggest if the function pointer has bool
// return type.
if (!ReturnType->isSpecificBuiltinType(BuiltinType::Bool))
return;
}
Diag(E->getExprLoc(), diag::note_function_to_function_call)
<< FixItHint::CreateInsertion(
getPreprocessor().getLocForEndOfToken(E->getLocEnd()), "()");
}
/// Diagnoses "dangerous" implicit conversions within the given
/// expression (which is a full expression). Implements -Wconversion
/// and -Wsign-compare.

View File

@ -7867,10 +7867,22 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
return ResultTy;
}
bool LHSIsNull = LHS.get()->isNullPointerConstant(Context,
Expr::NPC_ValueDependentIsNull);
bool RHSIsNull = RHS.get()->isNullPointerConstant(Context,
Expr::NPC_ValueDependentIsNull);
const Expr::NullPointerConstantKind LHSNullKind =
LHS.get()->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull);
const Expr::NullPointerConstantKind RHSNullKind =
RHS.get()->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull);
bool LHSIsNull = LHSNullKind != Expr::NPCK_NotNull;
bool RHSIsNull = RHSNullKind != Expr::NPCK_NotNull;
if (!IsRelational && LHSIsNull != RHSIsNull) {
bool IsEquality = Opc == BO_EQ;
if (RHSIsNull)
DiagnoseAlwaysNonNullPointer(LHS.get(), RHSNullKind, IsEquality,
RHS.get()->getSourceRange());
else
DiagnoseAlwaysNonNullPointer(RHS.get(), LHSNullKind, IsEquality,
LHS.get()->getSourceRange());
}
// All of the following pointer-related warnings are GCC extensions, except
// when handling null pointer constants.

View File

@ -110,7 +110,8 @@ void castsToBool() {
clang_analyzer_eval(symbolicPointer); // expected-warning{{TRUE}}
int localInt;
clang_analyzer_eval(&localInt); // expected-warning{{TRUE}}
int* ptr = &localInt;
clang_analyzer_eval(ptr); // expected-warning{{TRUE}}
clang_analyzer_eval(&castsToBool); // expected-warning{{TRUE}}
clang_analyzer_eval("abc"); // expected-warning{{TRUE}}

View File

@ -1,5 +1,5 @@
// RUN: %clang_cc1 -analyze -analyzer-checker=alpha.core.FixedAddr,alpha.core.PointerArithm,alpha.core.PointerSub,debug.ExprInspection -analyzer-store=region -verify -triple x86_64-apple-darwin9 %s
// RUN: %clang_cc1 -analyze -analyzer-checker=alpha.core.FixedAddr,alpha.core.PointerArithm,alpha.core.PointerSub,debug.ExprInspection -analyzer-store=region -verify -triple i686-apple-darwin9 %s
// RUN: %clang_cc1 -analyze -analyzer-checker=alpha.core.FixedAddr,alpha.core.PointerArithm,alpha.core.PointerSub,debug.ExprInspection -analyzer-store=region -verify -triple x86_64-apple-darwin9 -Wno-tautological-pointer-compare %s
// RUN: %clang_cc1 -analyze -analyzer-checker=alpha.core.FixedAddr,alpha.core.PointerArithm,alpha.core.PointerSub,debug.ExprInspection -analyzer-store=region -verify -triple i686-apple-darwin9 -Wno-tautological-pointer-compare %s
void clang_analyzer_eval(int);

View File

@ -1,5 +1,5 @@
// RUN: %clang_cc1 -analyze -analyzer-checker=core -verify -std=c99 -Dbool=_Bool %s
// RUN: %clang_cc1 -analyze -analyzer-checker=core -verify -x c++ %s
// RUN: %clang_cc1 -analyze -analyzer-checker=core -verify -std=c99 -Dbool=_Bool -Wno-bool-conversion %s
// RUN: %clang_cc1 -analyze -analyzer-checker=core -verify -x c++ -Wno-bool-conversion %s
typedef __INTPTR_TYPE__ intptr_t;
char const *p;

View File

@ -1,4 +1,4 @@
// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.core,debug.ExprInspection,unix.Malloc,unix.cstring,alpha.unix.cstring,unix.API,osx.API,osx.cocoa.RetainCount -Wno-null-dereference -analyzer-store=region -fblocks -verify %s
// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.core,debug.ExprInspection,unix.Malloc,unix.cstring,alpha.unix.cstring,unix.API,osx.API,osx.cocoa.RetainCount -Wno-null-dereference -Wno-tautological-compare -analyzer-store=region -fblocks -verify %s
#define NULL 0
void clang_analyzer_eval(int);
void myFunc();

View File

@ -163,7 +163,8 @@ void shrink_int() {
Agg<bool> b3 = {-1}; // expected-error {{ cannot be narrowed }} expected-note {{override}}
// Conversions from pointers to booleans aren't narrowing conversions.
Agg<bool> b = {&b1}; // OK
Agg<bool>* ptr = &b1;
Agg<bool> b = {ptr}; // OK
Agg<short> ce1 = { Convert<int>(100000) }; // expected-error {{constant expression evaluates to 100000 which cannot be narrowed to type 'short'}} expected-note {{override}} expected-warning {{changes value from 100000 to -31072}}
Agg<char> ce2 = { ConvertVar<short>() }; // expected-error {{non-constant-expression cannot be narrowed from type 'short' to 'char'}} expected-note {{override}}

View File

@ -164,7 +164,8 @@ void shrink_int() {
Agg<bool> b3 = {-1}; // expected-warning {{ cannot be narrowed }} expected-note {{override}}
// Conversions from pointers to booleans aren't narrowing conversions.
Agg<bool> b = {&b1}; // OK
Agg<bool>* ptr = &b1;
Agg<bool> b = {ptr}; // OK
Agg<short> ce1 = { Convert<int>(100000) }; // expected-warning {{constant expression evaluates to 100000 which cannot be narrowed to type 'short'}} expected-note {{override}} expected-warning {{changes value from 100000 to -31072}}
Agg<char> ce2 = { ConvertVar<short>() }; // expected-warning {{non-constant-expression cannot be narrowed from type 'short' to 'char'}} expected-note {{override}}

View File

@ -15,7 +15,7 @@ bool b4 = !E;
bool b5 = !F;
// -- pointer,
bool b6 = !&b4;
bool b6 = !&b4; // expected-warning{{address of 'b4' will always evaluate to 'true'}}
void f();
bool b61 = !&f;

View File

@ -1,4 +1,4 @@
// RUN: %clang_cc1 -fsyntax-only -verify -triple i686-linux %s
// RUN: %clang_cc1 -fsyntax-only -verify -triple i686-linux %s -Wno-tautological-pointer-compare
#define EVAL_EXPR(testno, expr) int test##testno = sizeof(struct{char qq[expr];});
int x;

View File

@ -1,4 +1,4 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
// RUN: %clang_cc1 -fsyntax-only -verify -Wno-bool-conversion %s
typedef __typeof((int*) 0 - (int*) 0) intptr_t;

View File

@ -1,4 +1,4 @@
// RUN: %clang_cc1 -triple i686-linux -Wno-string-plus-int -Wno-pointer-arith -Wno-zero-length-array -fsyntax-only -fcxx-exceptions -verify -std=c++11 -pedantic %s -Wno-comment
// RUN: %clang_cc1 -triple i686-linux -Wno-string-plus-int -Wno-pointer-arith -Wno-zero-length-array -fsyntax-only -fcxx-exceptions -verify -std=c++11 -pedantic %s -Wno-comment -Wno-tautological-pointer-compare -Wno-bool-conversion
namespace StaticAssertFoldTest {

View File

@ -1,4 +1,4 @@
// RUN: %clang_cc1 -triple x86_64-unknown-unknown -fsyntax-only -fblocks -Wnull-arithmetic -verify -Wno-string-plus-int %s
// RUN: %clang_cc1 -triple x86_64-unknown-unknown -fsyntax-only -fblocks -Wnull-arithmetic -verify -Wno-string-plus-int -Wno-tautological-pointer-compare %s
#include <stddef.h>
void f() {

View File

@ -1,4 +1,4 @@
// RUN: %clang_cc1 -fsyntax-only -fblocks -std=c++11 -verify %s
// RUN: %clang_cc1 -fsyntax-only -Wno-tautological-pointer-compare -fblocks -std=c++11 -verify %s
void foo() {
int a;

View File

@ -1,5 +1,6 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
namespace BooleanFalse {
int* j = false; // expected-warning{{initialization of pointer of type 'int *' to null from a constant boolean expression}}
void foo(int* i, int *j=(false)) // expected-warning{{initialization of pointer of type 'int *' to null from a constant boolean expression}}
@ -22,3 +23,98 @@ double f(...);
// isn't flagged.
template <int N> struct S {};
S<sizeof(f(false))> s;
}
namespace Function {
void f1();
struct S {
static void f2();
};
extern void f3() __attribute__((weak_import));
struct S2 {
static void f4() __attribute__((weak_import));
};
bool f5();
bool f6(int);
void bar() {
bool b;
b = f1; // expected-warning {{address of function 'f1' will always evaluate to 'true'}} \
expected-note {{prefix with the address-of operator to silence this warning}}
if (f1) {} // expected-warning {{address of function 'f1' will always evaluate to 'true'}} \
expected-note {{prefix with the address-of operator to silence this warning}}
b = S::f2; // expected-warning {{address of function 'S::f2' will always evaluate to 'true'}} \
expected-note {{prefix with the address-of operator to silence this warning}}
if (S::f2) {} // expected-warning {{address of function 'S::f2' will always evaluate to 'true'}} \
expected-note {{prefix with the address-of operator to silence this warning}}
b = f5; // expected-warning {{address of function 'f5' will always evaluate to 'true'}} \
expected-note {{prefix with the address-of operator to silence this warning}} \
expected-note {{suffix with parentheses to turn this into a function call}}
b = f6; // expected-warning {{address of function 'f6' will always evaluate to 'true'}} \
expected-note {{prefix with the address-of operator to silence this warning}}
// implicit casts of weakly imported symbols are ok:
b = f3;
if (f3) {}
b = S2::f4;
if (S2::f4) {}
}
}
namespace Array {
#define GetValue(ptr) ((ptr) ? ptr[0] : 0)
extern int a[] __attribute__((weak));
int b[] = {8,13,21};
struct {
int x[10];
} c;
const char str[] = "text";
void ignore() {
if (a) {}
if (a) {}
(void)GetValue(b);
}
void test() {
if (b) {}
// expected-warning@-1{{address of array 'b' will always evaluate to 'true'}}
if (b) {}
// expected-warning@-1{{address of array 'b' will always evaluate to 'true'}}
if (c.x) {}
// expected-warning@-1{{address of array 'c.x' will always evaluate to 'true'}}
if (str) {}
// expected-warning@-1{{address of array 'str' will always evaluate to 'true'}}
}
}
namespace Pointer {
extern int a __attribute__((weak));
int b;
static int c;
class S {
public:
static int a;
int b;
};
void ignored() {
if (&a) {}
}
void test() {
S s;
if (&b) {}
// expected-warning@-1{{address of 'b' will always evaluate to 'true'}}
if (&c) {}
// expected-warning@-1{{address of 'c' will always evaluate to 'true'}}
if (&s.a) {}
// expected-warning@-1{{address of 's.a' will always evaluate to 'true'}}
if (&s.b) {}
// expected-warning@-1{{address of 's.b' will always evaluate to 'true'}}
if (&S::a) {}
// expected-warning@-1{{address of 'S::a' will always evaluate to 'true'}}
}
}

View File

@ -1,40 +0,0 @@
// RUN: %clang_cc1 -x c++ -verify -fsyntax-only %s
void f1();
struct S {
static void f2();
};
extern void f3() __attribute__((weak_import));
struct S2 {
static void f4() __attribute__((weak_import));
};
bool f5();
bool f6(int);
void bar() {
bool b;
b = f1; // expected-warning {{address of function 'f1' will always evaluate to 'true'}} \
expected-note {{prefix with the address-of operator to silence this warning}}
if (f1) {} // expected-warning {{address of function 'f1' will always evaluate to 'true'}} \
expected-note {{prefix with the address-of operator to silence this warning}}
b = S::f2; // expected-warning {{address of function 'S::f2' will always evaluate to 'true'}} \
expected-note {{prefix with the address-of operator to silence this warning}}
if (S::f2) {} // expected-warning {{address of function 'S::f2' will always evaluate to 'true'}} \
expected-note {{prefix with the address-of operator to silence this warning}}
b = f5; // expected-warning {{address of function 'f5' will always evaluate to 'true'}} \
expected-note {{prefix with the address-of operator to silence this warning}} \
expected-note {{suffix with parentheses to turn this into a function call}}
b = f6; // expected-warning {{address of function 'f6' will always evaluate to 'true'}} \
expected-note {{prefix with the address-of operator to silence this warning}}
// implicit casts of weakly imported symbols are ok:
b = f3;
if (f3) {}
b = S2::f4;
if (S2::f4) {}
}

View File

@ -25,3 +25,114 @@ namespace RuntimeBehavior {
if (x < kintmax) {}
}
}
namespace ArrayCompare {
#define GetValue(ptr) ((ptr != 0) ? ptr[0] : 0)
extern int a[] __attribute__((weak));
int b[] = {8,13,21};
struct {
int x[10];
} c;
const char str[] = "text";
void ignore() {
if (a == 0) {}
if (a != 0) {}
(void)GetValue(b);
}
void test() {
if (b == 0) {}
// expected-warning@-1{{comparison of array 'b' equal to a null pointer is always false}}
if (b != 0) {}
// expected-warning@-1{{comparison of array 'b' not equal to a null pointer is always true}}
if (0 == b) {}
// expected-warning@-1{{comparison of array 'b' equal to a null pointer is always false}}
if (0 != b) {}
// expected-warning@-1{{comparison of array 'b' not equal to a null pointer is always true}}
if (c.x == 0) {}
// expected-warning@-1{{comparison of array 'c.x' equal to a null pointer is always false}}
if (c.x != 0) {}
// expected-warning@-1{{comparison of array 'c.x' not equal to a null pointer is always true}}
if (str == 0) {}
// expected-warning@-1{{comparison of array 'str' equal to a null pointer is always false}}
if (str != 0) {}
// expected-warning@-1{{comparison of array 'str' not equal to a null pointer is always true}}
}
}
namespace FunctionCompare {
#define CallFunction(f) ((f != 0) ? f() : 0)
extern void a() __attribute__((weak));
void fun1();
int fun2();
int* fun3();
int* fun4(int);
class S {
public:
static int foo();
};
void ignore() {
if (a == 0) {}
if (0 != a) {}
(void)CallFunction(fun2);
}
void test() {
if (fun1 == 0) {}
// expected-warning@-1{{comparison of function 'fun1' equal to a null pointer is always false}}
// expected-note@-2{{prefix with the address-of operator to silence this warning}}
if (fun2 == 0) {}
// expected-warning@-1{{comparison of function 'fun2' equal to a null pointer is always false}}
// expected-note@-2{{prefix with the address-of operator to silence this warning}}
// expected-note@-3{{suffix with parentheses to turn this into a function call}}
if (fun3 == 0) {}
// expected-warning@-1{{comparison of function 'fun3' equal to a null pointer is always false}}
// expected-note@-2{{prefix with the address-of operator to silence this warning}}
// expected-note@-3{{suffix with parentheses to turn this into a function call}}
if (fun4 == 0) {}
// expected-warning@-1{{comparison of function 'fun4' equal to a null pointer is always false}}
// expected-note@-2{{prefix with the address-of operator to silence this warning}}
if (nullptr != fun1) {}
// expected-warning@-1{{comparison of function 'fun1' not equal to a null pointer is always true}}
// expected-note@-2{{prefix with the address-of operator to silence this warning}}
if (nullptr != fun2) {}
// expected-warning@-1{{comparison of function 'fun2' not equal to a null pointer is always true}}
// expected-note@-2{{prefix with the address-of operator to silence this warning}}
if (nullptr != fun3) {}
// expected-warning@-1{{comparison of function 'fun3' not equal to a null pointer is always true}}
// expected-note@-2{{prefix with the address-of operator to silence this warning}}
// expected-note@-3{{suffix with parentheses to turn this into a function call}}
if (nullptr != fun4) {}
// expected-warning@-1{{comparison of function 'fun4' not equal to a null pointer is always true}}
// expected-note@-2{{prefix with the address-of operator to silence this warning}}
if (S::foo == 0) {}
// expected-warning@-1{{comparison of function 'S::foo' equal to a null pointer is always false}}
// expected-note@-2{{prefix with the address-of operator to silence this warning}}
// expected-note@-3{{suffix with parentheses to turn this into a function call}}
}
}
namespace PointerCompare {
extern int a __attribute__((weak));
int b;
static int c;
class S {
public:
static int a;
int b;
};
void ignored() {
if (&a == 0) {}
}
void test() {
S s;
if (&b == 0) {}
// expected-warning@-1{{comparison of address of 'b' equal to a null pointer is always false}}
if (&c == 0) {}
// expected-warning@-1{{comparison of address of 'c' equal to a null pointer is always false}}
if (&s.a == 0) {}
// expected-warning@-1{{comparison of address of 's.a' equal to a null pointer is always false}}
if (&s.b == 0) {}
// expected-warning@-1{{comparison of address of 's.b' equal to a null pointer is always false}}
if (&S::a == 0) {}
// expected-warning@-1{{comparison of address of 'S::a' equal to a null pointer is always false}}
}
}

View File

@ -45,9 +45,15 @@ int main()
+oneT<int>; // expected-warning {{expression result unused}}
-oneT<int>; //expected-error {{invalid argument type}}
oneT<int> == 0; // expected-warning {{equality comparison result unused}} \
// expected-note {{use '=' to turn this equality comparison into an assignment}}
0 == oneT<int>; // expected-warning {{equality comparison result unused}}
0 != oneT<int>; // expected-warning {{inequality comparison result unused}}
// expected-note {{use '=' to turn this equality comparison into an assignment}} \
// expected-warning {{comparison of function 'oneT<int>' equal to a null pointer is always false}} \
// expected-note {{prefix with the address-of operator to silence this warning}}
0 == oneT<int>; // expected-warning {{equality comparison result unused}} \
// expected-warning {{comparison of function 'oneT<int>' equal to a null pointer is always false}} \
// expected-note {{prefix with the address-of operator to silence this warning}}
0 != oneT<int>; // expected-warning {{inequality comparison result unused}} \
// expected-warning {{comparison of function 'oneT<int>' not equal to a null pointer is always true}} \
// expected-note {{prefix with the address-of operator to silence this warning}}
(false ? one : oneT<int>); // expected-warning {{expression result unused}}
void (*p1)(int); p1 = oneT<int>;
@ -69,7 +75,9 @@ int main()
two < two; //expected-error 2 {{reference to overloaded function could not be resolved; did you mean to call it with no arguments?}} expected-error {{invalid operands to binary expression ('void' and 'void')}}
twoT<int> < twoT<int>; //expected-error {{reference to overloaded function could not be resolved; did you mean to call it?}} {{cannot resolve overloaded function 'twoT' from context}}
oneT<int> == 0; // expected-warning {{equality comparison result unused}} \
// expected-note {{use '=' to turn this equality comparison into an assignment}}
// expected-note {{use '=' to turn this equality comparison into an assignment}} \
// expected-warning {{comparison of function 'oneT<int>' equal to a null pointer is always false}} \
// expected-note {{prefix with the address-of operator to silence this warning}}
}