diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td index d80b4931dc81..9802370a6056 100644 --- a/clang/include/clang/Basic/DiagnosticGroups.td +++ b/clang/include/clang/Basic/DiagnosticGroups.td @@ -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">; diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 41d683fcb88e..229e2bbb5a30 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -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; -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; -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; + +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 " diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 3659214ec63a..09c1db4c2c24 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -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); diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 936399ed9698..e9e9742b7ceb 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -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(E)) { - D = R->getDecl(); - } else if (MemberExpr *M = dyn_cast(E)) { - D = M->getMemberDecl(); - } - - if (D && !D->isWeak()) { - if (FunctionDecl* F = dyn_cast(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(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(E)) { + D = R->getDecl(); + } else if (MemberExpr *M = dyn_cast(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. diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 5e2497111238..f23b035277c3 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -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. diff --git a/clang/test/Analysis/casts.c b/clang/test/Analysis/casts.c index 3e2f8077ede0..42c05beb5945 100644 --- a/clang/test/Analysis/casts.c +++ b/clang/test/Analysis/casts.c @@ -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}} diff --git a/clang/test/Analysis/ptr-arith.c b/clang/test/Analysis/ptr-arith.c index 4a15bc24b906..96dc8bacbce3 100644 --- a/clang/test/Analysis/ptr-arith.c +++ b/clang/test/Analysis/ptr-arith.c @@ -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); diff --git a/clang/test/Analysis/stackaddrleak.c b/clang/test/Analysis/stackaddrleak.c index 4f81f6623e51..21a15d75eca0 100644 --- a/clang/test/Analysis/stackaddrleak.c +++ b/clang/test/Analysis/stackaddrleak.c @@ -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; diff --git a/clang/test/Analysis/weak-functions.c b/clang/test/Analysis/weak-functions.c index 96e3b44d03b8..a983f92f81aa 100644 --- a/clang/test/Analysis/weak-functions.c +++ b/clang/test/Analysis/weak-functions.c @@ -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(); diff --git a/clang/test/CXX/dcl.decl/dcl.init/dcl.init.list/p7-0x.cpp b/clang/test/CXX/dcl.decl/dcl.init/dcl.init.list/p7-0x.cpp index 9b1727fd04af..de2a76cbc9f5 100644 --- a/clang/test/CXX/dcl.decl/dcl.init/dcl.init.list/p7-0x.cpp +++ b/clang/test/CXX/dcl.decl/dcl.init/dcl.init.list/p7-0x.cpp @@ -163,7 +163,8 @@ void shrink_int() { Agg b3 = {-1}; // expected-error {{ cannot be narrowed }} expected-note {{override}} // Conversions from pointers to booleans aren't narrowing conversions. - Agg b = {&b1}; // OK + Agg* ptr = &b1; + Agg b = {ptr}; // OK Agg ce1 = { Convert(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 ce2 = { ConvertVar() }; // expected-error {{non-constant-expression cannot be narrowed from type 'short' to 'char'}} expected-note {{override}} diff --git a/clang/test/CXX/dcl.decl/dcl.init/dcl.init.list/p7-cxx11-nowarn.cpp b/clang/test/CXX/dcl.decl/dcl.init/dcl.init.list/p7-cxx11-nowarn.cpp index 4bcf113d7142..cbeae4f0bb0f 100644 --- a/clang/test/CXX/dcl.decl/dcl.init/dcl.init.list/p7-cxx11-nowarn.cpp +++ b/clang/test/CXX/dcl.decl/dcl.init/dcl.init.list/p7-cxx11-nowarn.cpp @@ -164,7 +164,8 @@ void shrink_int() { Agg b3 = {-1}; // expected-warning {{ cannot be narrowed }} expected-note {{override}} // Conversions from pointers to booleans aren't narrowing conversions. - Agg b = {&b1}; // OK + Agg* ptr = &b1; + Agg b = {ptr}; // OK Agg ce1 = { Convert(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 ce2 = { ConvertVar() }; // expected-warning {{non-constant-expression cannot be narrowed from type 'short' to 'char'}} expected-note {{override}} diff --git a/clang/test/CXX/expr/expr.unary/expr.unary.op/p6.cpp b/clang/test/CXX/expr/expr.unary/expr.unary.op/p6.cpp index 2646264273eb..833a4014e868 100644 --- a/clang/test/CXX/expr/expr.unary/expr.unary.op/p6.cpp +++ b/clang/test/CXX/expr/expr.unary/expr.unary.op/p6.cpp @@ -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; diff --git a/clang/test/Sema/const-eval.c b/clang/test/Sema/const-eval.c index 16d028eaf60e..883cced9f3b0 100644 --- a/clang/test/Sema/const-eval.c +++ b/clang/test/Sema/const-eval.c @@ -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; diff --git a/clang/test/Sema/static-init.c b/clang/test/Sema/static-init.c index bbf9038ef381..a2ed55197bcb 100644 --- a/clang/test/Sema/static-init.c +++ b/clang/test/Sema/static-init.c @@ -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; diff --git a/clang/test/SemaCXX/constant-expression-cxx11.cpp b/clang/test/SemaCXX/constant-expression-cxx11.cpp index 6724be7c8204..4e617776439d 100644 --- a/clang/test/SemaCXX/constant-expression-cxx11.cpp +++ b/clang/test/SemaCXX/constant-expression-cxx11.cpp @@ -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 { diff --git a/clang/test/SemaCXX/null_in_arithmetic_ops.cpp b/clang/test/SemaCXX/null_in_arithmetic_ops.cpp index a919213fb208..3b42ab44feb9 100644 --- a/clang/test/SemaCXX/null_in_arithmetic_ops.cpp +++ b/clang/test/SemaCXX/null_in_arithmetic_ops.cpp @@ -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 void f() { diff --git a/clang/test/SemaCXX/nullptr_in_arithmetic_ops.cpp b/clang/test/SemaCXX/nullptr_in_arithmetic_ops.cpp index 9671353907c7..60b4670b3a5e 100644 --- a/clang/test/SemaCXX/nullptr_in_arithmetic_ops.cpp +++ b/clang/test/SemaCXX/nullptr_in_arithmetic_ops.cpp @@ -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; diff --git a/clang/test/SemaCXX/warn-bool-conversion.cpp b/clang/test/SemaCXX/warn-bool-conversion.cpp index b3d136ecf2b1..b4628947f06e 100644 --- a/clang/test/SemaCXX/warn-bool-conversion.cpp +++ b/clang/test/SemaCXX/warn-bool-conversion.cpp @@ -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 struct S {}; S 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'}} + } +} diff --git a/clang/test/SemaCXX/warn-func-as-bool.cpp b/clang/test/SemaCXX/warn-func-as-bool.cpp deleted file mode 100644 index b5df744f9306..000000000000 --- a/clang/test/SemaCXX/warn-func-as-bool.cpp +++ /dev/null @@ -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) {} -} diff --git a/clang/test/SemaCXX/warn-tautological-compare.cpp b/clang/test/SemaCXX/warn-tautological-compare.cpp index caea6bf86e0e..b44f3f9d8fa3 100644 --- a/clang/test/SemaCXX/warn-tautological-compare.cpp +++ b/clang/test/SemaCXX/warn-tautological-compare.cpp @@ -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}} + } +} diff --git a/clang/test/SemaTemplate/resolve-single-template-id.cpp b/clang/test/SemaTemplate/resolve-single-template-id.cpp index 7fb16eb46745..915c42c85a60 100644 --- a/clang/test/SemaTemplate/resolve-single-template-id.cpp +++ b/clang/test/SemaTemplate/resolve-single-template-id.cpp @@ -45,9 +45,15 @@ int main() +oneT; // expected-warning {{expression result unused}} -oneT; //expected-error {{invalid argument type}} oneT == 0; // expected-warning {{equality comparison result unused}} \ - // expected-note {{use '=' to turn this equality comparison into an assignment}} - 0 == oneT; // expected-warning {{equality comparison result unused}} - 0 != oneT; // expected-warning {{inequality comparison result unused}} + // expected-note {{use '=' to turn this equality comparison into an assignment}} \ + // expected-warning {{comparison of function 'oneT' equal to a null pointer is always false}} \ + // expected-note {{prefix with the address-of operator to silence this warning}} + 0 == oneT; // expected-warning {{equality comparison result unused}} \ + // expected-warning {{comparison of function 'oneT' equal to a null pointer is always false}} \ + // expected-note {{prefix with the address-of operator to silence this warning}} + 0 != oneT; // expected-warning {{inequality comparison result unused}} \ + // expected-warning {{comparison of function 'oneT' not equal to a null pointer is always true}} \ + // expected-note {{prefix with the address-of operator to silence this warning}} (false ? one : oneT); // expected-warning {{expression result unused}} void (*p1)(int); p1 = oneT; @@ -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 < twoT; //expected-error {{reference to overloaded function could not be resolved; did you mean to call it?}} {{cannot resolve overloaded function 'twoT' from context}} oneT == 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' equal to a null pointer is always false}} \ + // expected-note {{prefix with the address-of operator to silence this warning}} }