diff options
author | Nick Lewycky <nicholas@mxc.ca> | 2016-05-14 17:44:14 +0000 |
---|---|---|
committer | Nick Lewycky <nicholas@mxc.ca> | 2016-05-14 17:44:14 +0000 |
commit | 2eeddfb1efc8200468725c50647e3b250b28e902 (patch) | |
tree | 1c8b72219c1fce87621af755a546b18ce7ef6e63 | |
parent | 962b2cda9cfa93b48aa044783209a3939d66b73d (diff) | |
download | bcm5719-llvm-2eeddfb1efc8200468725c50647e3b250b28e902.tar.gz bcm5719-llvm-2eeddfb1efc8200468725c50647e3b250b28e902.zip |
Warn when a reference is bound to an empty l-value (dereferenced null pointer).
llvm-svn: 269572
-rw-r--r-- | clang/include/clang/Basic/DiagnosticSemaKinds.td | 6 | ||||
-rw-r--r-- | clang/lib/Sema/SemaInit.cpp | 15 | ||||
-rw-r--r-- | clang/test/CXX/expr/expr.prim/expr.prim.lambda/p5.cpp | 4 | ||||
-rw-r--r-- | clang/test/Parser/cxx-casting.cpp | 2 | ||||
-rw-r--r-- | clang/test/SemaCXX/cstyle-cast.cpp | 6 | ||||
-rw-r--r-- | clang/test/SemaCXX/functional-cast.cpp | 6 | ||||
-rw-r--r-- | clang/test/SemaCXX/new-delete.cpp | 4 | ||||
-rw-r--r-- | clang/test/SemaCXX/static-cast.cpp | 6 |
8 files changed, 34 insertions, 15 deletions
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index ba6db97c136..322427862f6 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/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<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< diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index 3563bf7b184..c162007349c 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/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<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: { diff --git a/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p5.cpp b/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p5.cpp index dc2c209af26..b8504d49065 100644 --- a/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p5.cpp +++ b/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p5.cpp @@ -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 diff --git a/clang/test/Parser/cxx-casting.cpp b/clang/test/Parser/cxx-casting.cpp index 43885bff27a..b1ae591865e 100644 --- a/clang/test/Parser/cxx-casting.cpp +++ b/clang/test/Parser/cxx-casting.cpp @@ -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; diff --git a/clang/test/SemaCXX/cstyle-cast.cpp b/clang/test/SemaCXX/cstyle-cast.cpp index afac6a137ec..2327d7b51d9 100644 --- a/clang/test/SemaCXX/cstyle-cast.cpp +++ b/clang/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/clang/test/SemaCXX/functional-cast.cpp b/clang/test/SemaCXX/functional-cast.cpp index 9db95e80d03..216ee240c83 100644 --- a/clang/test/SemaCXX/functional-cast.cpp +++ b/clang/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/clang/test/SemaCXX/new-delete.cpp b/clang/test/SemaCXX/new-delete.cpp index 7bc724b2101..e96603d69e1 100644 --- a/clang/test/SemaCXX/new-delete.cpp +++ b/clang/test/SemaCXX/new-delete.cpp @@ -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}} } } diff --git a/clang/test/SemaCXX/static-cast.cpp b/clang/test/SemaCXX/static-cast.cpp index b3fe49a88c6..ff47c0bb4dc 100644 --- a/clang/test/SemaCXX/static-cast.cpp +++ b/clang/test/SemaCXX/static-cast.cpp @@ -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); |