Extend -Wtautological-undefined-compare and -Wundefined-bool-conversion to

trigger on taking the address of a reference that is returned from a function
call.

llvm-svn: 211989
This commit is contained in:
Richard Trieu 2014-06-28 23:25:37 +00:00
parent e3d2ecbe86
commit c1888e0c6e
4 changed files with 185 additions and 12 deletions

View File

@ -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">;

View File

@ -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.

View File

@ -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}}
}
}

View File

@ -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}}
}
}