From: Nick Lewycky Date: Sat, 14 May 2016 17:44:14 +0000 (+0000) Subject: Warn when a reference is bound to an empty l-value (dereferenced null pointer). X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=774ff762b3e885e1098bbef30046a722b4c1010e;p=clang 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 --- diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index ba6db97c13..322427862f 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -5371,7 +5371,11 @@ def ext_typecheck_indirection_through_void_pointer : ExtWarn< "ISO C++ does not allow indirection on operand of type %0">, InGroup>; def warn_indirection_through_null : Warning< - "indirection of non-volatile null pointer will be deleted, not trap">, InGroup; + "indirection of non-volatile null pointer will be deleted, not trap">, + InGroup; +def warn_binding_null_to_reference : Warning< + "binding dereferenced null pointer to reference has undefined behavior">, + InGroup; def note_indirection_through_null : Note< "consider using __builtin_trap() or qualifying pointer with 'volatile'">; def warn_pointer_indirection_from_incompatible_type : Warning< diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp index 3563bf7b18..c162007349 100644 --- a/lib/Sema/SemaInit.cpp +++ b/lib/Sema/SemaInit.cpp @@ -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(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: { diff --git a/test/CXX/expr/expr.prim/expr.prim.lambda/p5.cpp b/test/CXX/expr/expr.prim/expr.prim.lambda/p5.cpp index dc2c209af2..b8504d4906 100644 --- a/test/CXX/expr/expr.prim/expr.prim.lambda/p5.cpp +++ b/test/CXX/expr/expr.prim/expr.prim.lambda/p5.cpp @@ -11,7 +11,7 @@ void test_attributes() { template 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 bogus; + bogus_override_if_virtual 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 diff --git a/test/Parser/cxx-casting.cpp b/test/Parser/cxx-casting.cpp index 43885bff27..b1ae591865 100644 --- a/test/Parser/cxx-casting.cpp +++ b/test/Parser/cxx-casting.cpp @@ -37,7 +37,7 @@ char postfix_expr_test() // This was being incorrectly tentatively parsed. namespace test1 { template class A {}; // expected-note 2{{here}} - void foo() { A(*(A*)0); } + void foo() { A(*(A*)0); } // expected-warning {{binding dereferenced null pointer to reference has undefined behavior}} } typedef char* c; diff --git a/test/SemaCXX/cstyle-cast.cpp b/test/SemaCXX/cstyle-cast.cpp index afac6a137e..2327d7b51d 100644 --- a/test/SemaCXX/cstyle-cast.cpp +++ b/test/SemaCXX/cstyle-cast.cpp @@ -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 diff --git a/test/SemaCXX/functional-cast.cpp b/test/SemaCXX/functional-cast.cpp index 9db95e80d0..216ee240c8 100644 --- a/test/SemaCXX/functional-cast.cpp +++ b/test/SemaCXX/functional-cast.cpp @@ -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)(); diff --git a/test/SemaCXX/new-delete.cpp b/test/SemaCXX/new-delete.cpp index 7bc724b210..e96603d69e 100644 --- a/test/SemaCXX/new-delete.cpp +++ b/test/SemaCXX/new-delete.cpp @@ -444,11 +444,11 @@ namespace r150682 { template 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(); + tfn(); // expected-note {{in instantiation of function template specialization 'r150682::tfn' requested here}} } } diff --git a/test/SemaCXX/static-cast.cpp b/test/SemaCXX/static-cast.cpp index b3fe49a88c..ff47c0bb4d 100644 --- a/test/SemaCXX/static-cast.cpp +++ b/test/SemaCXX/static-cast.cpp @@ -43,11 +43,11 @@ void t_529_2() (void)static_cast((int*)0); (void)static_cast((const int*)0); (void)static_cast((B*)0); - (void)static_cast(*((B*)0)); + (void)static_cast(*((B*)0)); // expected-warning {{binding dereferenced null pointer to reference has undefined behavior}} (void)static_cast((C1*)0); - (void)static_cast(*((C1*)0)); + (void)static_cast(*((C1*)0)); // expected-warning {{binding dereferenced null pointer to reference has undefined behavior}} (void)static_cast((D*)0); - (void)static_cast(*((D*)0)); + (void)static_cast(*((D*)0)); // expected-warning {{binding dereferenced null pointer to reference has undefined behavior}} (void)static_cast((int A::*)0); (void)static_cast((void (A::*)())0);