From e14ca9f509dc22d8fcc5d21d70d28a5848983b42 Mon Sep 17 00:00:00 2001 From: Lang Hames Date: Mon, 5 Dec 2011 20:49:50 +0000 Subject: [PATCH] Add a warning for implicit conversion from function literals (and static methods) to bool. E.g. void foo() {} if (f) { ... // <- Warns here. } Only applies to non-weak functions, and does not apply if the function address is taken explicitly with the addr-of operator. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@145849 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Basic/DiagnosticSemaKinds.td | 3 ++ lib/Sema/SemaChecking.cpp | 19 +++++++++++++ .../p2-resolve-single-template-id.cpp | 28 +++++++++---------- test/SemaCXX/condition.cpp | 2 +- .../resolve-single-template-id.cpp | 4 +-- 5 files changed, 39 insertions(+), 17 deletions(-) diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index fa2fabcdeb..9a5a664d69 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -1650,6 +1650,9 @@ def warn_impcast_bool_to_null_pointer : Warning< def warn_impcast_null_pointer_to_integer : Warning< "implicit conversion of NULL constant to integer">, InGroup>, DefaultIgnore; +def warn_impcast_function_to_bool : Warning< + "address of function %q0 will always evaluate to 'true'">, + InGroup; def warn_cast_align : Warning< "cast from %0 to %1 increases required alignment from %2 to %3">, diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp index 0d640a8c12..1ec7e39398 100644 --- a/lib/Sema/SemaChecking.cpp +++ b/lib/Sema/SemaChecking.cpp @@ -3758,6 +3758,25 @@ void CheckImplicitConversion(Sema &S, Expr *E, QualType T, // by a check in AnalyzeImplicitConversions(). return DiagnoseImpCast(S, E, T, CC, diag::warn_impcast_string_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()) { + FunctionDecl* F = cast(D); + S.Diag(E->getExprLoc(), diag::warn_impcast_function_to_bool) + << F << E->getSourceRange() << SourceRange(CC); + return; + } + } return; // Other casts to bool are not checked. } diff --git a/test/CXX/over/over.over/p2-resolve-single-template-id.cpp b/test/CXX/over/over.over/p2-resolve-single-template-id.cpp index 1bd0d34074..4708949900 100644 --- a/test/CXX/over/over.over/p2-resolve-single-template-id.cpp +++ b/test/CXX/over/over.over/p2-resolve-single-template-id.cpp @@ -100,8 +100,8 @@ int main() { (void) reinterpret_cast(two); } //expected-error {{reinterpret_cast}} { (void) reinterpret_cast(two); } //expected-error {{reinterpret_cast}} - { bool b = (twoT); } // ok - { bool b = (twoT); } //ok + { bool b = (twoT); } // expected-warning {{address of function 'twoT' will always evaluate to 'true'}} + { bool b = (twoT); } // expected-warning {{address of function 'twoT' will always evaluate to 'true'}} { bool b = &twoT; //&foo; } b = &(twoT); } @@ -142,20 +142,20 @@ namespace member_pointers { if (&s.f) return; // expected-error {{cannot create a non-constant pointer to member function}} if (&s.f) return; // expected-error {{cannot create a non-constant pointer to member function}} - if (S::g) return; - if (S::g) return; + if (S::g) return; // expected-warning {{address of function 'member_pointers::S::g' will always evaluate to 'true'}} + if (S::g) return; // expected-warning {{address of function 'member_pointers::S::g' will always evaluate to 'true'}} if (&S::g) return; if (&S::g) return; - if (s.g) return; - if (s.g) return; + if (s.g) return; // expected-warning {{address of function 'member_pointers::S::g' will always evaluate to 'true'}} + if (s.g) return; // expected-warning {{address of function 'member_pointers::S::g' will always evaluate to 'true'}} if (&s.g) return; if (&s.g) return; - if (S::h<42>) return; + if (S::h<42>) return; // expected-warning {{address of function 'member_pointers::S::h<42>' will always evaluate to 'true'}} if (S::h) return; // expected-error {{reference to overloaded function could not be resolved; did you mean to call it?}} if (&S::h<42>) return; if (&S::h) return; - if (s.h<42>) return; + if (s.h<42>) return; // expected-warning {{address of function 'member_pointers::S::h<42>' will always evaluate to 'true'}} if (s.h) return; // expected-error {{reference to overloaded function could not be resolved; did you mean to call it?}} if (&s.h<42>) return; if (&s.h) return; // expected-error {{reference to overloaded function could not be resolved; did you mean to call it?}} @@ -170,20 +170,20 @@ namespace member_pointers { { bool b = &s.f; } // expected-error {{cannot create a non-constant pointer to member function}} { bool b = &s.f; } // expected-error {{cannot create a non-constant pointer to member function}} - { bool b = S::g; } - { bool b = S::g; } + { bool b = S::g; } // expected-warning {{address of function 'member_pointers::S::g' will always evaluate to 'true'}} + { bool b = S::g; } // expected-warning {{address of function 'member_pointers::S::g' will always evaluate to 'true'}} { bool b = &S::g; } { bool b = &S::g; } - { bool b = s.g; } - { bool b = s.g; } + { bool b = s.g; } // expected-warning {{address of function 'member_pointers::S::g' will always evaluate to 'true'}} + { bool b = s.g; } // expected-warning {{address of function 'member_pointers::S::g' will always evaluate to 'true'}} { bool b = &s.g; } { bool b = &s.g; } - { bool b = S::h<42>; } + { bool b = S::h<42>; } // expected-warning {{address of function 'member_pointers::S::h<42>' will always evaluate to 'true'}} { bool b = S::h; } // expected-error {{can't form member pointer of type 'bool' without '&' and class name}} { bool b = &S::h<42>; } { bool b = &S::h; } - { bool b = s.h<42>; } + { bool b = s.h<42>; } // expected-warning {{address of function 'member_pointers::S::h<42>' will always evaluate to 'true'}} { bool b = s.h; } // expected-error {{can't form member pointer of type 'bool' without '&' and class name}} { bool b = &s.h<42>; } { bool b = &s.h; } // expected-error {{can't form member pointer of type 'bool' without '&' and class name}} diff --git a/test/SemaCXX/condition.cpp b/test/SemaCXX/condition.cpp index 3441bae670..21671fab3c 100644 --- a/test/SemaCXX/condition.cpp +++ b/test/SemaCXX/condition.cpp @@ -49,6 +49,6 @@ void test3() { if ("help") (void) 0; - if (test3) + if (test3) // expected-warning {{address of function 'test3' will always evaluate to 'true'}} (void) 0; } diff --git a/test/SemaTemplate/resolve-single-template-id.cpp b/test/SemaTemplate/resolve-single-template-id.cpp index b9833d8609..1beb65a0f5 100644 --- a/test/SemaTemplate/resolve-single-template-id.cpp +++ b/test/SemaTemplate/resolve-single-template-id.cpp @@ -41,7 +41,7 @@ int main() *oneT; // expected-warning {{expression result unused}} *two; //expected-error {{reference to overloaded function could not be resolved; did you mean to call it with no arguments?}} expected-error {{indirection requires pointer operand}} *twoT; //expected-error {{reference to overloaded function could not be resolved; did you mean to call it?}} - !oneT; // expected-warning {{expression result unused}} + !oneT; // expected-warning {{expression result unused}} expected-warning {{address of function 'oneT' will always evaluate to 'true'}} +oneT; // expected-warning {{expression result unused}} -oneT; //expected-error {{invalid argument type}} oneT == 0; // expected-warning {{equality comparison result unused}} \ @@ -53,7 +53,7 @@ int main() int i = (int) (false ? (void (*)(int))twoT : oneT); //expected-error {{incompatible operand}} (twoT) == oneT; //expected-error {{reference to overloaded function could not be resolved; did you mean to call it?}} {{cannot resolve overloaded function 'twoT' from context}} - bool b = oneT; + bool b = oneT; // expected-warning {{address of function 'oneT' will always evaluate to 'true'}} void (*p)() = oneT; test > ti; void (*u)(int) = oneT; -- 2.40.0