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
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index fa2fabc..9a5a664 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -1650,6 +1650,9 @@
def warn_impcast_null_pointer_to_integer : Warning<
"implicit conversion of NULL constant to integer">,
InGroup<DiagGroup<"conversion">>, DefaultIgnore;
+def warn_impcast_function_to_bool : Warning<
+ "address of function %q0 will always evaluate to 'true'">,
+ InGroup<BoolConversions>;
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 0d640a8..1ec7e39 100644
--- a/lib/Sema/SemaChecking.cpp
+++ b/lib/Sema/SemaChecking.cpp
@@ -3758,6 +3758,25 @@
// 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<DeclRefExpr>(E)) {
+ D = R->getDecl();
+ } else if (MemberExpr *M = dyn_cast<MemberExpr>(E)) {
+ D = M->getMemberDecl();
+ }
+
+ if (D && !D->isWeak()) {
+ FunctionDecl* F = cast<FunctionDecl>(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 1bd0d34..4708949 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 @@
{ (void) reinterpret_cast<int>(two); } //expected-error {{reinterpret_cast}}
{ (void) reinterpret_cast<int (*)(char, double)>(two); } //expected-error {{reinterpret_cast}}
- { bool b = (twoT<int>); } // ok
- { bool b = (twoT<int, int>); } //ok
+ { bool b = (twoT<int>); } // expected-warning {{address of function 'twoT<int>' will always evaluate to 'true'}}
+ { bool b = (twoT<int, int>); } // expected-warning {{address of function 'twoT<int, int>' will always evaluate to 'true'}}
{ bool b = &twoT<int>; //&foo<int>; }
b = &(twoT<int>); }
@@ -142,20 +142,20 @@
if (&s.f<char>) return; // expected-error {{cannot create a non-constant pointer to member function}}
if (&s.f<int>) return; // expected-error {{cannot create a non-constant pointer to member function}}
- if (S::g<char>) return;
- if (S::g<int>) return;
+ if (S::g<char>) return; // expected-warning {{address of function 'member_pointers::S::g<char>' will always evaluate to 'true'}}
+ if (S::g<int>) return; // expected-warning {{address of function 'member_pointers::S::g<int>' will always evaluate to 'true'}}
if (&S::g<char>) return;
if (&S::g<int>) return;
- if (s.g<char>) return;
- if (s.g<int>) return;
+ if (s.g<char>) return; // expected-warning {{address of function 'member_pointers::S::g<char>' will always evaluate to 'true'}}
+ if (s.g<int>) return; // expected-warning {{address of function 'member_pointers::S::g<int>' will always evaluate to 'true'}}
if (&s.g<char>) return;
if (&s.g<int>) 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<int>) 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<int>) 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<int>) 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<int>) return; // expected-error {{reference to overloaded function could not be resolved; did you mean to call it?}}
@@ -170,20 +170,20 @@
{ bool b = &s.f<char>; } // expected-error {{cannot create a non-constant pointer to member function}}
{ bool b = &s.f<int>; } // expected-error {{cannot create a non-constant pointer to member function}}
- { bool b = S::g<char>; }
- { bool b = S::g<int>; }
+ { bool b = S::g<char>; } // expected-warning {{address of function 'member_pointers::S::g<char>' will always evaluate to 'true'}}
+ { bool b = S::g<int>; } // expected-warning {{address of function 'member_pointers::S::g<int>' will always evaluate to 'true'}}
{ bool b = &S::g<char>; }
{ bool b = &S::g<int>; }
- { bool b = s.g<char>; }
- { bool b = s.g<int>; }
+ { bool b = s.g<char>; } // expected-warning {{address of function 'member_pointers::S::g<char>' will always evaluate to 'true'}}
+ { bool b = s.g<int>; } // expected-warning {{address of function 'member_pointers::S::g<int>' will always evaluate to 'true'}}
{ bool b = &s.g<char>; }
{ bool b = &s.g<int>; }
- { 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<int>; } // expected-error {{can't form member pointer of type 'bool' without '&' and class name}}
{ bool b = &S::h<42>; }
{ bool b = &S::h<int>; }
- { 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<int>; } // expected-error {{can't form member pointer of type 'bool' without '&' and class name}}
{ bool b = &s.h<42>; }
{ bool b = &s.h<int>; } // 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 3441bae..21671fa 100644
--- a/test/SemaCXX/condition.cpp
+++ b/test/SemaCXX/condition.cpp
@@ -49,6 +49,6 @@
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 b9833d8..1beb65a 100644
--- a/test/SemaTemplate/resolve-single-template-id.cpp
+++ b/test/SemaTemplate/resolve-single-template-id.cpp
@@ -41,7 +41,7 @@
*oneT<int>; // 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<int>; //expected-error {{reference to overloaded function could not be resolved; did you mean to call it?}}
- !oneT<int>; // expected-warning {{expression result unused}}
+ !oneT<int>; // expected-warning {{expression result unused}} expected-warning {{address of function 'oneT<int>' will always evaluate to 'true'}}
+oneT<int>; // expected-warning {{expression result unused}}
-oneT<int>; //expected-error {{invalid argument type}}
oneT<int> == 0; // expected-warning {{equality comparison result unused}} \
@@ -53,7 +53,7 @@
int i = (int) (false ? (void (*)(int))twoT<int> : oneT<int>); //expected-error {{incompatible operand}}
(twoT<int>) == oneT<int>; //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<int>;
+ bool b = oneT<int>; // expected-warning {{address of function 'oneT<int>' will always evaluate to 'true'}}
void (*p)() = oneT<int>;
test<oneT<int> > ti;
void (*u)(int) = oneT<int>;