summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Trieu <rtrieu@google.com>2014-06-28 23:25:37 +0000
committerRichard Trieu <rtrieu@google.com>2014-06-28 23:25:37 +0000
commit00fb59690f98ef46666c640db5f7cd79ea4f5178 (patch)
tree25364008dcef78c909306e660833012e127fd959
parent8a905545a533f4fd355c3b3768fb07f287ae1072 (diff)
downloadclang-00fb59690f98ef46666c640db5f7cd79ea4f5178.tar.gz
Extend -Wtautological-undefined-compare and -Wundefined-bool-conversion to
trigger on taking the address of a reference that is returned from a function call. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@211989 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td1
-rw-r--r--lib/Sema/SemaChecking.cpp58
-rw-r--r--test/SemaCXX/warn-tautological-undefined-compare.cpp78
-rw-r--r--test/SemaCXX/warn-undefined-bool-conversion.cpp60
4 files changed, 185 insertions, 12 deletions
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index 72a2533f54..ac97e083fa 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -2433,6 +2433,7 @@ def warn_address_of_reference_null_compare : Warning<
"code; comparison may be assumed to always evaluate to "
"%select{true|false}0">,
InGroup<TautologicalUndefinedCompare>;
+def note_reference_is_return_value : Note<"%0 returns a reference">;
def note_function_warning_silence : Note<
"prefix with the address-of operator to silence this warning">;
diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp
index 72d3b2761d..1a49b4ac4f 100644
--- a/lib/Sema/SemaChecking.cpp
+++ b/lib/Sema/SemaChecking.cpp
@@ -6192,6 +6192,38 @@ enum {
ArrayPointer
};
+// Helper function for Sema::DiagnoseAlwaysNonNullPointer.
+// Returns true when emitting a warning about taking the address of a reference.
+static bool CheckForReference(Sema &SemaRef, const Expr *E,
+ PartialDiagnostic PD) {
+ E = E->IgnoreParenImpCasts();
+
+ const FunctionDecl *FD = nullptr;
+
+ if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) {
+ if (!DRE->getDecl()->getType()->isReferenceType())
+ return false;
+ } else if (const MemberExpr *M = dyn_cast<MemberExpr>(E)) {
+ if (!M->getMemberDecl()->getType()->isReferenceType())
+ return false;
+ } else if (const CallExpr *Call = dyn_cast<CallExpr>(E)) {
+ if (!Call->getCallReturnType()->isReferenceType())
+ return false;
+ FD = Call->getDirectCallee();
+ } else {
+ return false;
+ }
+
+ SemaRef.Diag(E->getExprLoc(), PD);
+
+ // If possible, point to location of function.
+ if (FD) {
+ SemaRef.Diag(FD->getLocation(), diag::note_reference_is_return_value) << FD;
+ }
+
+ return true;
+}
+
/// \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
@@ -6227,6 +6259,17 @@ void Sema::DiagnoseAlwaysNonNullPointer(Expr *E,
E = UO->getSubExpr();
}
+ if (IsAddressOf) {
+ unsigned DiagID = IsCompare
+ ? diag::warn_address_of_reference_null_compare
+ : diag::warn_address_of_reference_bool_conversion;
+ PartialDiagnostic PD = PDiag(DiagID) << E->getSourceRange() << Range
+ << IsEqual;
+ if (CheckForReference(*this, E, PD)) {
+ return;
+ }
+ }
+
// Expect to find a single Decl. Skip anything more complicated.
ValueDecl *D = nullptr;
if (DeclRefExpr *R = dyn_cast<DeclRefExpr>(E)) {
@@ -6243,18 +6286,9 @@ void Sema::DiagnoseAlwaysNonNullPointer(Expr *E,
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;
-
- if (T->isReferenceType()) {
- unsigned DiagID = IsCompare
- ? diag::warn_address_of_reference_null_compare
- : diag::warn_address_of_reference_bool_conversion;
- Diag(E->getExprLoc(), DiagID) << E->getSourceRange() << Range << IsEqual;
- return;
- }
+ // Address of function is used to silence the function warning.
+ if (IsAddressOf && IsFunction) {
+ return;
}
// Found nothing.
diff --git a/test/SemaCXX/warn-tautological-undefined-compare.cpp b/test/SemaCXX/warn-tautological-undefined-compare.cpp
index b30b576d35..ce05bfc14d 100644
--- a/test/SemaCXX/warn-tautological-undefined-compare.cpp
+++ b/test/SemaCXX/warn-tautological-undefined-compare.cpp
@@ -32,3 +32,81 @@ class test2 {
int &x;
int y;
};
+
+namespace function_return_reference {
+ int& get_int();
+ // expected-note@-1 4{{'get_int' returns a reference}}
+ class B {
+ public:
+ static int &stat();
+ // expected-note@-1 4{{'stat' returns a reference}}
+ int &get();
+ // expected-note@-1 8{{'get' returns a reference}}
+ };
+
+ void test() {
+ if (&get_int() == 0) {}
+ // expected-warning@-1{{reference cannot be bound to dereferenced null pointer in well-defined C++ code; comparison may be assumed to always evaluate to false}}
+ if (&(get_int()) == 0) {}
+ // expected-warning@-1{{reference cannot be bound to dereferenced null pointer in well-defined C++ code; comparison may be assumed to always evaluate to false}}
+
+ if (&get_int() != 0) {}
+ // expected-warning@-1{{reference cannot be bound to dereferenced null pointer in well-defined C++ code; comparison may be assumed to always evaluate to true}}
+ if (&(get_int()) != 0) {}
+ // expected-warning@-1{{reference cannot be bound to dereferenced null pointer in well-defined C++ code; comparison may be assumed to always evaluate to true}}
+
+ if (&B::stat() == 0) {}
+ // expected-warning@-1{{reference cannot be bound to dereferenced null pointer in well-defined C++ code; comparison may be assumed to always evaluate to false}}
+ if (&(B::stat()) == 0) {}
+ // expected-warning@-1{{reference cannot be bound to dereferenced null pointer in well-defined C++ code; comparison may be assumed to always evaluate to false}}
+
+ if (&B::stat() != 0) {}
+ // expected-warning@-1{{reference cannot be bound to dereferenced null pointer in well-defined C++ code; comparison may be assumed to always evaluate to true}}
+ if (&(B::stat()) != 0) {}
+ // expected-warning@-1{{reference cannot be bound to dereferenced null pointer in well-defined C++ code; comparison may be assumed to always evaluate to true}}
+
+ B b;
+ if (&b.get() == 0) {}
+ // expected-warning@-1{{reference cannot be bound to dereferenced null pointer in well-defined C++ code; comparison may be assumed to always evaluate to false}}
+ if (&(b.get()) == 0) {}
+ // expected-warning@-1{{reference cannot be bound to dereferenced null pointer in well-defined C++ code; comparison may be assumed to always evaluate to false}}
+
+ if (&b.get() != 0) {}
+ // expected-warning@-1{{reference cannot be bound to dereferenced null pointer in well-defined C++ code; comparison may be assumed to always evaluate to true}}
+ if (&(b.get()) != 0) {}
+ // expected-warning@-1{{reference cannot be bound to dereferenced null pointer in well-defined C++ code; comparison may be assumed to always evaluate to true}}
+
+ B* b_ptr = &b;
+ if (&b_ptr->get() == 0) {}
+ // expected-warning@-1{{reference cannot be bound to dereferenced null pointer in well-defined C++ code; comparison may be assumed to always evaluate to false}}
+ if (&(b_ptr->get()) == 0) {}
+ // expected-warning@-1{{reference cannot be bound to dereferenced null pointer in well-defined C++ code; comparison may be assumed to always evaluate to false}}
+
+ if (&b_ptr->get() != 0) {}
+ // expected-warning@-1{{reference cannot be bound to dereferenced null pointer in well-defined C++ code; comparison may be assumed to always evaluate to true}}
+ if (&(b_ptr->get()) != 0) {}
+ // expected-warning@-1{{reference cannot be bound to dereferenced null pointer in well-defined C++ code; comparison may be assumed to always evaluate to true}}
+
+ int& (B::*m_ptr)() = &B::get;
+ if (&(b.*m_ptr)() == 0) {}
+ // expected-warning@-1{{reference cannot be bound to dereferenced null pointer in well-defined C++ code; comparison may be assumed to always evaluate to false}}
+ if (&((b.*m_ptr)()) == 0) {}
+ // expected-warning@-1{{reference cannot be bound to dereferenced null pointer in well-defined C++ code; comparison may be assumed to always evaluate to false}}
+
+ if (&(b.*m_ptr)() != 0) {}
+ // expected-warning@-1{{reference cannot be bound to dereferenced null pointer in well-defined C++ code; comparison may be assumed to always evaluate to true}}
+ if (&((b.*m_ptr)()) != 0) {}
+ // expected-warning@-1{{reference cannot be bound to dereferenced null pointer in well-defined C++ code; comparison may be assumed to always evaluate to true}}
+
+ int& (*f_ptr)() = &get_int;
+ if (&(*f_ptr)() == 0) {}
+ // expected-warning@-1{{reference cannot be bound to dereferenced null pointer in well-defined C++ code; comparison may be assumed to always evaluate to false}}
+ if (&((*f_ptr)()) == 0) {}
+ // expected-warning@-1{{reference cannot be bound to dereferenced null pointer in well-defined C++ code; comparison may be assumed to always evaluate to false}}
+
+ if (&(*f_ptr)() != 0) {}
+ // expected-warning@-1{{reference cannot be bound to dereferenced null pointer in well-defined C++ code; comparison may be assumed to always evaluate to true}}
+ if (&((*f_ptr)()) != 0) {}
+ // expected-warning@-1{{reference cannot be bound to dereferenced null pointer in well-defined C++ code; comparison may be assumed to always evaluate to true}}
+ }
+}
diff --git a/test/SemaCXX/warn-undefined-bool-conversion.cpp b/test/SemaCXX/warn-undefined-bool-conversion.cpp
index 40bbbd84a8..1f8baa0e8d 100644
--- a/test/SemaCXX/warn-undefined-bool-conversion.cpp
+++ b/test/SemaCXX/warn-undefined-bool-conversion.cpp
@@ -35,3 +35,63 @@ class test2 {
int &x;
int y;
};
+
+namespace function_return_reference {
+ int& get_int();
+ // expected-note@-1 3{{'get_int' returns a reference}}
+ class B {
+ public:
+ static int &stat();
+ // expected-note@-1 3{{'stat' returns a reference}}
+ int &get();
+ // expected-note@-1 6{{'get' returns a reference}}
+ };
+
+ void test() {
+ if (&get_int()) {}
+ // expected-warning@-1{{reference cannot be bound to dereferenced null pointer in well-defined C++ code; pointer may be assumed to always convert to true}}
+ if (&(get_int())) {}
+ // expected-warning@-1{{reference cannot be bound to dereferenced null pointer in well-defined C++ code; pointer may be assumed to always convert to true}}
+ if (!&get_int()) {}
+ // expected-warning@-1{{reference cannot be bound to dereferenced null pointer in well-defined C++ code; pointer may be assumed to always convert to true}}
+
+ if (&B::stat()) {}
+ // expected-warning@-1{{reference cannot be bound to dereferenced null pointer in well-defined C++ code; pointer may be assumed to always convert to true}}
+ if (&(B::stat())) {}
+ // expected-warning@-1{{reference cannot be bound to dereferenced null pointer in well-defined C++ code; pointer may be assumed to always convert to true}}
+ if (!&B::stat()) {}
+ // expected-warning@-1{{reference cannot be bound to dereferenced null pointer in well-defined C++ code; pointer may be assumed to always convert to true}}
+
+ B b;
+ if (&b.get()) {}
+ // expected-warning@-1{{reference cannot be bound to dereferenced null pointer in well-defined C++ code; pointer may be assumed to always convert to true}}
+ if (&(b.get())) {}
+ // expected-warning@-1{{reference cannot be bound to dereferenced null pointer in well-defined C++ code; pointer may be assumed to always convert to true}}
+ if (!&b.get()) {}
+ // expected-warning@-1{{reference cannot be bound to dereferenced null pointer in well-defined C++ code; pointer may be assumed to always convert to true}}
+
+ B* b_ptr = &b;
+ if (&b_ptr->get()) {}
+ // expected-warning@-1{{reference cannot be bound to dereferenced null pointer in well-defined C++ code; pointer may be assumed to always convert to true}}
+ if (&(b_ptr->get())) {}
+ // expected-warning@-1{{reference cannot be bound to dereferenced null pointer in well-defined C++ code; pointer may be assumed to always convert to true}}
+ if (!&b_ptr->get()) {}
+ // expected-warning@-1{{reference cannot be bound to dereferenced null pointer in well-defined C++ code; pointer may be assumed to always convert to true}}
+
+ int& (B::*m_ptr)() = &B::get;
+ if (&(b.*m_ptr)()) {}
+ // expected-warning@-1{{reference cannot be bound to dereferenced null pointer in well-defined C++ code; pointer may be assumed to always convert to true}}
+ if (&((b.*m_ptr)())) {}
+ // expected-warning@-1{{reference cannot be bound to dereferenced null pointer in well-defined C++ code; pointer may be assumed to always convert to true}}
+ if (!&(b.*m_ptr)()) {}
+ // expected-warning@-1{{reference cannot be bound to dereferenced null pointer in well-defined C++ code; pointer may be assumed to always convert to true}}
+
+ int& (*f_ptr)() = &get_int;
+ if (&(*f_ptr)()) {}
+ // expected-warning@-1{{reference cannot be bound to dereferenced null pointer in well-defined C++ code; pointer may be assumed to always convert to true}}
+ if (&((*f_ptr)())) {}
+ // expected-warning@-1{{reference cannot be bound to dereferenced null pointer in well-defined C++ code; pointer may be assumed to always convert to true}}
+ if (!&(*f_ptr)()) {}
+ // expected-warning@-1{{reference cannot be bound to dereferenced null pointer in well-defined C++ code; pointer may be assumed to always convert to true}}
+ }
+}