From 7ef655a78863c0a7550bfe51174b9c340ab1dce0 Mon Sep 17 00:00:00 2001 From: Chris Lattner Date: Tue, 12 Jan 2010 21:23:57 +0000 Subject: [PATCH] implement PR6004, warning about divide and remainder by zero. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@93256 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Basic/DiagnosticSemaKinds.td | 8 ++-- lib/Sema/Sema.h | 3 +- lib/Sema/SemaExpr.cpp | 41 +++++++++++++------- test/Analysis/misc-ps.m | 12 +++--- test/Sema/exprs.c | 8 ++++ test/Sema/i-c-e.c | 5 ++- test/SemaTemplate/instantiate-expr-1.cpp | 3 +- test/SemaTemplate/instantiate-static-var.cpp | 2 +- 8 files changed, 53 insertions(+), 29 deletions(-) diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 4cd8a95223..82c5544e9f 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -1557,10 +1557,10 @@ def warn_floatingpoint_eq : Warning< "comparing floating point with == or != is unsafe">, InGroup>, DefaultIgnore; -def warn_shift_negative : Warning< - "shift count is negative">; -def warn_shift_gt_typewidth : Warning< - "shift count >= width of type">; +def warn_division_by_zero : Warning<"division by zero is undefined">; +def warn_remainder_by_zero : Warning<"remainder by zero is undefined">; +def warn_shift_negative : Warning<"shift count is negative">; +def warn_shift_gt_typewidth : Warning<"shift count >= width of type">; def warn_precedence_bitwise_rel : Warning< "%0 has lower precedence than %1; %1 will be evaluated first">, diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 7099d27f0c..d46bfc6cff 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -3644,7 +3644,8 @@ public: QualType CheckPointerToMemberOperands( // C++ 5.5 Expr *&lex, Expr *&rex, SourceLocation OpLoc, bool isIndirect); QualType CheckMultiplyDivideOperands( // C99 6.5.5 - Expr *&lex, Expr *&rex, SourceLocation OpLoc, bool isCompAssign = false); + Expr *&lex, Expr *&rex, SourceLocation OpLoc, bool isCompAssign, + bool isDivide); QualType CheckRemainderOperands( // C99 6.5.5 Expr *&lex, Expr *&rex, SourceLocation OpLoc, bool isCompAssign = false); QualType CheckAdditionOperands( // C99 6.5.6 diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 02af661095..7dc13c4ad8 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -4793,8 +4793,7 @@ QualType Sema::InvalidOperands(SourceLocation Loc, Expr *&lex, Expr *&rex) { return QualType(); } -inline QualType Sema::CheckVectorOperands(SourceLocation Loc, Expr *&lex, - Expr *&rex) { +QualType Sema::CheckVectorOperands(SourceLocation Loc, Expr *&lex, Expr *&rex) { // For conversion purposes, we ignore any qualifiers. // For example, "const float" and "float" are equivalent. QualType lhsType = @@ -4855,19 +4854,26 @@ inline QualType Sema::CheckVectorOperands(SourceLocation Loc, Expr *&lex, return QualType(); } -inline QualType Sema::CheckMultiplyDivideOperands( - Expr *&lex, Expr *&rex, SourceLocation Loc, bool isCompAssign) { +QualType Sema::CheckMultiplyDivideOperands( + Expr *&lex, Expr *&rex, SourceLocation Loc, bool isCompAssign, bool isDiv) { if (lex->getType()->isVectorType() || rex->getType()->isVectorType()) return CheckVectorOperands(Loc, lex, rex); QualType compType = UsualArithmeticConversions(lex, rex, isCompAssign); - if (lex->getType()->isArithmeticType() && rex->getType()->isArithmeticType()) - return compType; - return InvalidOperands(Loc, lex, rex); + if (!lex->getType()->isArithmeticType() || + !rex->getType()->isArithmeticType()) + return InvalidOperands(Loc, lex, rex); + + // Check for division by zero. + if (isDiv && + rex->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNotNull)) + Diag(Loc, diag::warn_division_by_zero) << rex->getSourceRange(); + + return compType; } -inline QualType Sema::CheckRemainderOperands( +QualType Sema::CheckRemainderOperands( Expr *&lex, Expr *&rex, SourceLocation Loc, bool isCompAssign) { if (lex->getType()->isVectorType() || rex->getType()->isVectorType()) { if (lex->getType()->isIntegerType() && rex->getType()->isIntegerType()) @@ -4877,12 +4883,17 @@ inline QualType Sema::CheckRemainderOperands( QualType compType = UsualArithmeticConversions(lex, rex, isCompAssign); - if (lex->getType()->isIntegerType() && rex->getType()->isIntegerType()) - return compType; - return InvalidOperands(Loc, lex, rex); + if (!lex->getType()->isIntegerType() || !rex->getType()->isIntegerType()) + return InvalidOperands(Loc, lex, rex); + + // Check for remainder by zero. + if (rex->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNotNull)) + Diag(Loc, diag::warn_remainder_by_zero) << rex->getSourceRange(); + + return compType; } -inline QualType Sema::CheckAdditionOperands( // C99 6.5.6 +QualType Sema::CheckAdditionOperands( // C99 6.5.6 Expr *&lex, Expr *&rex, SourceLocation Loc, QualType* CompLHSTy) { if (lex->getType()->isVectorType() || rex->getType()->isVectorType()) { QualType compType = CheckVectorOperands(Loc, lex, rex); @@ -6082,7 +6093,8 @@ Action::OwningExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc, break; case BinaryOperator::Mul: case BinaryOperator::Div: - ResultTy = CheckMultiplyDivideOperands(lhs, rhs, OpLoc); + ResultTy = CheckMultiplyDivideOperands(lhs, rhs, OpLoc, false, + Opc == BinaryOperator::Div); break; case BinaryOperator::Rem: ResultTy = CheckRemainderOperands(lhs, rhs, OpLoc); @@ -6118,7 +6130,8 @@ Action::OwningExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc, break; case BinaryOperator::MulAssign: case BinaryOperator::DivAssign: - CompResultTy = CheckMultiplyDivideOperands(lhs, rhs, OpLoc, true); + CompResultTy = CheckMultiplyDivideOperands(lhs, rhs, OpLoc, true, + Opc == BinaryOperator::DivAssign); CompLHSTy = CompResultTy; if (!CompResultTy.isNull()) ResultTy = CheckAssignmentOperands(lhs, rhs, OpLoc, CompResultTy); diff --git a/test/Analysis/misc-ps.m b/test/Analysis/misc-ps.m index f3ea13b1ea..149be03ac2 100644 --- a/test/Analysis/misc-ps.m +++ b/test/Analysis/misc-ps.m @@ -91,16 +91,16 @@ void r6268365() { void divzeroassume(unsigned x, unsigned j) { x /= j; - if (j == 0) x /= 0; // no-warning - if (j == 0) x /= j; // no-warning - if (j == 0) x = x / 0; // no-warning + if (j == 0) x /= 0; // no static-analyzer warning expected-warning {{division by zero is undefined}} + if (j == 0) x /= j; // no static-analyzer warning + if (j == 0) x = x / 0; // no static-analyzer warning expected-warning {{division by zero is undefined}} } void divzeroassumeB(unsigned x, unsigned j) { x = x / j; - if (j == 0) x /= 0; // no-warning - if (j == 0) x /= j; // no-warning - if (j == 0) x = x / 0; // no-warning + if (j == 0) x /= 0; // no static-analyzer warning expected-warning {{division by zero is undefined}} + if (j == 0) x /= j; // no static-analyzer warning + if (j == 0) x = x / 0; // no static-analyzer warning expected-warning {{division by zero is undefined}} } // InitListExpr processing diff --git a/test/Sema/exprs.c b/test/Sema/exprs.c index e6cfa5fbe3..b2f92e2c01 100644 --- a/test/Sema/exprs.c +++ b/test/Sema/exprs.c @@ -114,3 +114,11 @@ test15_t test15(void) { // rdar://7446395 void test16(float x) { x == ((void*) 0); } // expected-error {{invalid operands to binary expression}} +// PR6004 +void test17(int x) { + x = x / 0; // expected-warning {{division by zero is undefined}} + x = x % 0; // expected-warning {{remainder by zero is undefined}} + x /= 0; // expected-warning {{division by zero is undefined}} + x %= 0; // expected-warning {{remainder by zero is undefined}} +} + diff --git a/test/Sema/i-c-e.c b/test/Sema/i-c-e.c index c561fe01c6..97d9f43cfb 100644 --- a/test/Sema/i-c-e.c +++ b/test/Sema/i-c-e.c @@ -57,8 +57,9 @@ int comma3[(1,2)]; // expected-warning {{size of static array must be an integer // Pointer + __builtin_constant_p char pbcp[__builtin_constant_p(4) ? (intptr_t)&expr : 0]; // expected-error {{variable length array declaration not allowed at file scope}} -int illegaldiv1[1 || 1/0]; -int illegaldiv2[1/0]; // expected-error {{variable length array declaration not allowed at file scope}} +int illegaldiv1[1 || 1/0]; // expected-warning {{division by zero is undefined}} +int illegaldiv2[1/0]; // expected-error {{variable length array declaration not allowed at file scope}} \ + // expected-warning {{division by zero is undefined}} int illegaldiv3[INT_MIN / -1]; // expected-error {{variable length array declaration not allowed at file scope}} int chooseexpr[__builtin_choose_expr(1, 1, expr)]; diff --git a/test/SemaTemplate/instantiate-expr-1.cpp b/test/SemaTemplate/instantiate-expr-1.cpp index 663749ddce..5752033fbd 100644 --- a/test/SemaTemplate/instantiate-expr-1.cpp +++ b/test/SemaTemplate/instantiate-expr-1.cpp @@ -35,7 +35,8 @@ void test_BitfieldMinus() { template struct BitfieldDivide { int bitfield : I / J; // expected-error{{expression is not an integer constant expression}} \ - // expected-note{{division by zero}} + // expected-note{{division by zero}} \ + // expected-warning {{division by zero is undefined}} }; void test_BitfieldDivide() { diff --git a/test/SemaTemplate/instantiate-static-var.cpp b/test/SemaTemplate/instantiate-static-var.cpp index 789fe3db87..1fcc36b43c 100644 --- a/test/SemaTemplate/instantiate-static-var.cpp +++ b/test/SemaTemplate/instantiate-static-var.cpp @@ -2,7 +2,7 @@ template class X { public: - static const T value = 10 / Divisor; // expected-error{{in-class initializer is not an integral constant expression}} + static const T value = 10 / Divisor; // expected-error{{in-class initializer is not an integral constant expression}} expected-warning {{division by zero is undefined}} }; int array1[X::value == 5? 1 : -1];