mirror of https://github.com/microsoft/clang.git
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 } git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@202216 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
e1805368a8
commit
2a66e6e500
|
@ -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">;
|
||||
|
|
|
@ -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 "
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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}}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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}}
|
||||
|
|
|
@ -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}}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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'}}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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) {}
|
||||
}
|
|
@ -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}}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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}}
|
||||
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue