diff options
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 56 | ||||
-rw-r--r-- | test/SemaCXX/null_in_arithmetic_ops.cpp | 28 |
2 files changed, 52 insertions, 32 deletions
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 42ec82ac4a..5d62910068 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -8945,31 +8945,39 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc, // are mainly cases where the null pointer is used as an integer instead // of a pointer. if (LeftNull || RightNull) { - if (Opc == BO_Mul || Opc == BO_Div || Opc == BO_Rem || Opc == BO_Add || - Opc == BO_Sub || Opc == BO_Shl || Opc == BO_Shr || Opc == BO_And || - Opc == BO_Xor || Opc == BO_Or || Opc == BO_MulAssign || - Opc == BO_DivAssign || Opc == BO_AddAssign || Opc == BO_SubAssign || - Opc == BO_RemAssign || Opc == BO_ShlAssign || Opc == BO_ShrAssign || - Opc == BO_AndAssign || Opc == BO_OrAssign || Opc == BO_XorAssign) { - // These are the operations that would not make sense with a null pointer - // no matter what the other expression is. - Diag(OpLoc, diag::warn_null_in_arithmetic_operation) - << (LeftNull ? lhs.get()->getSourceRange() : SourceRange()) - << (RightNull ? rhs.get()->getSourceRange() : SourceRange()); - } else if (Opc == BO_LE || Opc == BO_LT || Opc == BO_GE || Opc == BO_GT || - Opc == BO_EQ || Opc == BO_NE) { - // These are the operations that would not make sense with a null pointer - // if the other expression the other expression is not a pointer. - QualType LeftType = lhs.get()->getType(); - QualType RightType = rhs.get()->getType(); - if (LeftNull != RightNull && - !LeftType->isPointerLikeType() && - !LeftType->canDecayToPointerType() && - !RightType->isPointerLikeType() && - !RightType->canDecayToPointerType()) { + // Avoid analyzing cases where the result will either be invalid (and + // diagnosed as such) or entirely valid and not something to warn about. + QualType LeftType = lhs.get()->getType(); + QualType RightType = rhs.get()->getType(); + if (!LeftType->isBlockPointerType() && !LeftType->isMemberPointerType() && + !LeftType->isFunctionType() && + !RightType->isBlockPointerType() && + !RightType->isMemberPointerType() && + !RightType->isFunctionType()) { + if (Opc == BO_Mul || Opc == BO_Div || Opc == BO_Rem || Opc == BO_Add || + Opc == BO_Sub || Opc == BO_Shl || Opc == BO_Shr || Opc == BO_And || + Opc == BO_Xor || Opc == BO_Or || Opc == BO_MulAssign || + Opc == BO_DivAssign || Opc == BO_AddAssign || Opc == BO_SubAssign || + Opc == BO_RemAssign || Opc == BO_ShlAssign || Opc == BO_ShrAssign || + Opc == BO_AndAssign || Opc == BO_OrAssign || Opc == BO_XorAssign) { + // These are the operations that would not make sense with a null pointer + // no matter what the other expression is. Diag(OpLoc, diag::warn_null_in_arithmetic_operation) - << (LeftNull ? lhs.get()->getSourceRange() - : rhs.get()->getSourceRange()); + << (LeftNull ? lhs.get()->getSourceRange() : SourceRange()) + << (RightNull ? rhs.get()->getSourceRange() : SourceRange()); + } else if (Opc == BO_LE || Opc == BO_LT || Opc == BO_GE || Opc == BO_GT || + Opc == BO_EQ || Opc == BO_NE) { + // These are the operations that would not make sense with a null pointer + // if the other expression the other expression is not a pointer. + if (LeftNull != RightNull && + !LeftType->isAnyPointerType() && + !LeftType->canDecayToPointerType() && + !RightType->isAnyPointerType() && + !RightType->canDecayToPointerType()) { + Diag(OpLoc, diag::warn_null_in_arithmetic_operation) + << (LeftNull ? lhs.get()->getSourceRange() + : rhs.get()->getSourceRange()); + } } } } diff --git a/test/SemaCXX/null_in_arithmetic_ops.cpp b/test/SemaCXX/null_in_arithmetic_ops.cpp index 78c76e7e4c..9665c3959e 100644 --- a/test/SemaCXX/null_in_arithmetic_ops.cpp +++ b/test/SemaCXX/null_in_arithmetic_ops.cpp @@ -4,6 +4,12 @@ void f() { int a; bool b; + void (^c)(); + class X; + void (X::*d) (); + extern void e(); + int f[2]; + const void *v; a = 0 ? NULL + a : a + NULL; // expected-warning 2{{use of NULL in arithmetic operation}} a = 0 ? NULL - a : a - NULL; // expected-warning 2{{use of NULL in arithmetic operation}} @@ -18,6 +24,19 @@ void f() { a = 0 ? NULL | a : a | NULL; // expected-warning 2{{use of NULL in arithmetic operation}} a = 0 ? NULL ^ a : a ^ NULL; // expected-warning 2{{use of NULL in arithmetic operation}} + // Check for warnings or errors when doing arithmetic on pointers and other + // types. + v = 0 ? NULL + &a : &a + NULL; // expected-warning 2{{use of NULL in arithmetic operation}} + v = 0 ? NULL + c : c + NULL; // \ + expected-error {{invalid operands to binary expression ('long' and 'void (^)()')}} \ + expected-error {{invalid operands to binary expression ('void (^)()' and 'long')}} + v = 0 ? NULL + d : d + NULL; // \ + expected-error {{invalid operands to binary expression ('long' and 'void (X::*)()')}} \ + expected-error {{invalid operands to binary expression ('void (X::*)()' and 'long')}} + v = 0 ? NULL + e : e + NULL; // expected-error 2{{arithmetic on pointer to function type}} + v = 0 ? NULL + f : f + NULL; // expected-warning 2{{use of NULL in arithmetic operation}} + v = 0 ? NULL + "f" : "f" + NULL; // expected-warning 2{{use of NULL in arithmetic operation}} + // Using two NULLs should only give one error instead of two. a = NULL + NULL; // expected-warning{{use of NULL in arithmetic operation}} a = NULL - NULL; // expected-warning{{use of NULL in arithmetic operation}} @@ -65,17 +84,10 @@ void f() { b = ((NULL)) != a; // expected-warning{{use of NULL in arithmetic operation}} - void (^c)(); + // Check that even non-standard pointers don't warn. b = c == NULL || NULL == c || c != NULL || NULL != c; - - class X; - void (X::*d) (); b = d == NULL || NULL == d || d != NULL || NULL != d; - - extern void e(); b = e == NULL || NULL == e || e != NULL || NULL != e; - - int f[2]; b = f == NULL || NULL == f || f != NULL || NULL != f; b = "f" == NULL || NULL == "f" || "f" != NULL || NULL != "f"; } |