forked from OSchip/llvm-project
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:
parent
e3d2ecbe86
commit
c1888e0c6e
|
@ -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">;
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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}}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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}}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue