Warn when a reference is bound to an empty l-value (dereferenced null pointer).

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@269572 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Nick Lewycky 2016-05-14 17:44:14 +00:00
parent d5bb834945
commit 774ff762b3
8 changed files with 34 additions and 15 deletions

View File

@ -5371,7 +5371,11 @@ def ext_typecheck_indirection_through_void_pointer : ExtWarn<
"ISO C++ does not allow indirection on operand of type %0">,
InGroup<DiagGroup<"void-ptr-dereference">>;
def warn_indirection_through_null : Warning<
"indirection of non-volatile null pointer will be deleted, not trap">, InGroup<NullDereference>;
"indirection of non-volatile null pointer will be deleted, not trap">,
InGroup<NullDereference>;
def warn_binding_null_to_reference : Warning<
"binding dereferenced null pointer to reference has undefined behavior">,
InGroup<NullDereference>;
def note_indirection_through_null : Note<
"consider using __builtin_trap() or qualifying pointer with 'volatile'">;
def warn_pointer_indirection_from_incompatible_type : Warning<

View File

@ -6168,6 +6168,20 @@ static void CheckMoveOnConstruction(Sema &S, const Expr *InitExpr,
<< FixItHint::CreateRemoval(SourceRange(RParen, RParen));
}
static void CheckForNullPointerDereference(Sema &S, const Expr *E) {
// Check to see if we are dereferencing a null pointer. If so, this is
// undefined behavior, so warn about it. This only handles the pattern
// "*null", which is a very syntactic check.
if (const UnaryOperator *UO = dyn_cast<UnaryOperator>(E->IgnoreParenCasts()))
if (UO->getOpcode() == UO_Deref &&
UO->getSubExpr()->IgnoreParenCasts()->
isNullPointerConstant(S.Context, Expr::NPC_ValueDependentIsNotNull)) {
S.DiagRuntimeBehavior(UO->getOperatorLoc(), UO,
S.PDiag(diag::warn_binding_null_to_reference)
<< UO->getSubExpr()->getSourceRange());
}
}
ExprResult
InitializationSequence::Perform(Sema &S,
const InitializedEntity &Entity,
@ -6420,6 +6434,7 @@ InitializationSequence::Perform(Sema &S,
/*IsInitializerList=*/false,
ExtendingEntity->getDecl());
CheckForNullPointerDereference(S, CurInit.get());
break;
case SK_BindReferenceToTemporary: {

View File

@ -11,7 +11,7 @@ void test_attributes() {
template<typename T>
struct bogus_override_if_virtual : public T {
bogus_override_if_virtual() : T(*(T*)0) { }
bogus_override_if_virtual() : T(*(T*)0) { } // expected-warning {{binding dereferenced null pointer to reference has undefined behavior}}
int operator()() const;
};
@ -36,7 +36,7 @@ void test_quals() {
lv(); // expected-error{{no matching function for call to object of type}}
mlv(); // expected-error{{no matching function for call to object of type}}
bogus_override_if_virtual<decltype(l)> bogus;
bogus_override_if_virtual<decltype(l)> bogus; // expected-note{{in instantiation of member function 'bogus_override_if_virtual<(lambda}}
}
// Core issue 974: default arguments (8.3.6) may be specified in the

View File

@ -37,7 +37,7 @@ char postfix_expr_test()
// This was being incorrectly tentatively parsed.
namespace test1 {
template <class T> class A {}; // expected-note 2{{here}}
void foo() { A<int>(*(A<int>*)0); }
void foo() { A<int>(*(A<int>*)0); } // expected-warning {{binding dereferenced null pointer to reference has undefined behavior}}
}
typedef char* c;

View File

@ -84,11 +84,11 @@ void t_529_2()
(void)(void*)((int*)0);
(void)(volatile const void*)((const int*)0);
(void)(A*)((B*)0);
(void)(A&)(*((B*)0));
(void)(A&)(*((B*)0)); // expected-warning {{binding dereferenced null pointer to reference has undefined behavior}}
(void)(const B*)((C1*)0);
(void)(B&)(*((C1*)0));
(void)(B&)(*((C1*)0)); // expected-warning {{binding dereferenced null pointer to reference has undefined behavior}}
(void)(A*)((D*)0);
(void)(const A&)(*((D*)0));
(void)(const A&)(*((D*)0)); // expected-warning {{binding dereferenced null pointer to reference has undefined behavior}}
(void)(int B::*)((int A::*)0);
(void)(void (B::*)())((void (A::*)())0);
(void)(A*)((E*)0); // C-style cast ignores access control

View File

@ -126,14 +126,14 @@ void t_529_2()
typedef A *Ap;
(void)Ap((B*)0);
typedef A &Ar;
(void)Ar(*((B*)0));
(void)Ar(*((B*)0)); // expected-warning {{binding dereferenced null pointer to reference has undefined behavior}}
typedef const B *cBp;
(void)cBp((C1*)0);
typedef B &Br;
(void)Br(*((C1*)0));
(void)Br(*((C1*)0)); // expected-warning {{binding dereferenced null pointer to reference has undefined behavior}}
(void)Ap((D*)0);
typedef const A &cAr;
(void)cAr(*((D*)0));
(void)cAr(*((D*)0)); // expected-warning {{binding dereferenced null pointer to reference has undefined behavior}}
typedef int B::*Bmp;
(void)Bmp((int A::*)0);
typedef void (B::*Bmfp)();

View File

@ -444,11 +444,11 @@ namespace r150682 {
template<typename X>
void tfn() {
new (*(PlacementArg*)0) T[1];
new (*(PlacementArg*)0) T[1]; // expected-warning 2 {{binding dereferenced null pointer to reference has undefined behavior}}
}
void fn() {
tfn<int>();
tfn<int>(); // expected-note {{in instantiation of function template specialization 'r150682::tfn<int>' requested here}}
}
}

View File

@ -43,11 +43,11 @@ void t_529_2()
(void)static_cast<void*>((int*)0);
(void)static_cast<volatile const void*>((const int*)0);
(void)static_cast<A*>((B*)0);
(void)static_cast<A&>(*((B*)0));
(void)static_cast<A&>(*((B*)0)); // expected-warning {{binding dereferenced null pointer to reference has undefined behavior}}
(void)static_cast<const B*>((C1*)0);
(void)static_cast<B&>(*((C1*)0));
(void)static_cast<B&>(*((C1*)0)); // expected-warning {{binding dereferenced null pointer to reference has undefined behavior}}
(void)static_cast<A*>((D*)0);
(void)static_cast<const A&>(*((D*)0));
(void)static_cast<const A&>(*((D*)0)); // expected-warning {{binding dereferenced null pointer to reference has undefined behavior}}
(void)static_cast<int B::*>((int A::*)0);
(void)static_cast<void (B::*)()>((void (A::*)())0);