From: Steve Naroff Date: Fri, 24 Aug 2007 19:07:16 +0000 (+0000) Subject: Surpress ImplicitCastExprs for compound assignment expressions. For compound assignments, X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=9f5fa9bfc37c3e15895cd777e42f3dd8a7ec7a9d;p=clang Surpress ImplicitCastExprs for compound assignment expressions. For compound assignments, it is o.k. for the LHS and RHS to have different types. Converting the type can cause errors like the one Chris noticed (below). This change required a fair number of diffs (since there is a lot of shared code between single and compound assignments). This makes the API's look a bit uglier, however I couldn't think of a better way to do it (without duplicating code). Fix the following (incorrect) error: int A; long long B; void foo() { A /= B; } $ clang ~/scalar.c -emit-llvm /Users/sabre/scalar.c:6:5: error: expression is not assignable A /= B; ~ ^ Now it works properly... [dylan:~/llvm/tools/clang] admin% cat compound.c int A; long long B; void foo() { A /= B; } [dylan:~/llvm/tools/clang] admin% ../../Debug/bin/clang compound.c -parse-ast-dump Read top-level variable decl: 'A' Read top-level variable decl: 'B' void foo() (CompoundStmt 0x2605c40 (BinaryOperator 0x2605c20 'int' '/=' ComputeTy='long long' (DeclRefExpr 0x2605be0 'int' Decl='A' 0x2605a80) (DeclRefExpr 0x2605c00 'long long' Decl='B' 0x2605ab0))) git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@41364 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/Sema/Sema.h b/Sema/Sema.h index 99bb4343bf..b758c3dd60 100644 --- a/Sema/Sema.h +++ b/Sema/Sema.h @@ -349,8 +349,8 @@ private: // operators (C99 6.3.1.8). If both operands aren't arithmetic, this // routine returns the first non-arithmetic type found. The client is // responsible for emitting appropriate error diagnostics. - void UsualArithmeticConversions(Expr *&lExpr, Expr *&rExpr); - + QualType UsualArithmeticConversions(Expr *&lExpr, Expr *&rExpr, + bool isCompAssign = false); enum AssignmentCheckResult { Compatible, Incompatible, @@ -386,21 +386,21 @@ private: inline void InvalidOperands(SourceLocation l, Expr *&lex, Expr *&rex); inline QualType CheckVectorOperands(SourceLocation l, Expr *&lex, Expr *&rex); inline QualType CheckMultiplyDivideOperands( // C99 6.5.5 - Expr *&lex, Expr *&rex, SourceLocation OpLoc); + Expr *&lex, Expr *&rex, SourceLocation OpLoc, bool isCompAssign = false); inline QualType CheckRemainderOperands( // C99 6.5.5 - Expr *&lex, Expr *&rex, SourceLocation OpLoc); + Expr *&lex, Expr *&rex, SourceLocation OpLoc, bool isCompAssign = false); inline QualType CheckAdditionOperands( // C99 6.5.6 - Expr *&lex, Expr *&rex, SourceLocation OpLoc); + Expr *&lex, Expr *&rex, SourceLocation OpLoc, bool isCompAssign = false); inline QualType CheckSubtractionOperands( // C99 6.5.6 - Expr *&lex, Expr *&rex, SourceLocation OpLoc); + Expr *&lex, Expr *&rex, SourceLocation OpLoc, bool isCompAssign = false); inline QualType CheckShiftOperands( // C99 6.5.7 - Expr *&lex, Expr *&rex, SourceLocation OpLoc); + Expr *&lex, Expr *&rex, SourceLocation OpLoc, bool isCompAssign = false); inline QualType CheckRelationalOperands( // C99 6.5.8 Expr *&lex, Expr *&rex, SourceLocation OpLoc); inline QualType CheckEqualityOperands( // C99 6.5.9 Expr *&lex, Expr *&rex, SourceLocation OpLoc); inline QualType CheckBitwiseOperands( // C99 6.5.[10...12] - Expr *&lex, Expr *&rex, SourceLocation OpLoc); + Expr *&lex, Expr *&rex, SourceLocation OpLoc, bool isCompAssign = false); inline QualType CheckLogicalOperands( // C99 6.5.[13,14] Expr *&lex, Expr *&rex, SourceLocation OpLoc); // CheckAssignmentOperands is used for both simple and compound assignment. diff --git a/Sema/SemaExpr.cpp b/Sema/SemaExpr.cpp index 9efd229cc0..102642432c 100644 --- a/Sema/SemaExpr.cpp +++ b/Sema/SemaExpr.cpp @@ -752,7 +752,8 @@ void Sema::UsualUnaryConversions(Expr *&expr) { /// binary operators (C99 6.3.1.8). If both operands aren't arithmetic, this /// routine returns the first non-arithmetic type found. The client is /// responsible for emitting appropriate error diagnostics. -void Sema::UsualArithmeticConversions(Expr *&lhsExpr, Expr *&rhsExpr) { +QualType Sema::UsualArithmeticConversions(Expr *&lhsExpr, Expr *&rhsExpr, + bool isCompAssign) { UsualUnaryConversions(lhsExpr); UsualUnaryConversions(rhsExpr); @@ -761,12 +762,12 @@ void Sema::UsualArithmeticConversions(Expr *&lhsExpr, Expr *&rhsExpr) { // If both types are identical, no conversion is needed. if (lhs == rhs) - return; + return lhs; // If either side is a non-arithmetic type (e.g. a pointer), we are done. // The caller can deal with this (e.g. pointer + int). if (!lhs->isArithmeticType() || !rhs->isArithmeticType()) - return; + return lhs; // At this point, we have two different arithmetic types. @@ -774,48 +775,48 @@ void Sema::UsualArithmeticConversions(Expr *&lhsExpr, Expr *&rhsExpr) { if (lhs->isComplexType() || rhs->isComplexType()) { // if we have an integer operand, the result is the complex type. if (rhs->isIntegerType()) { // convert the rhs to the lhs complex type. - promoteExprToType(rhsExpr, lhs); - return; + if (!isCompAssign) promoteExprToType(rhsExpr, lhs); + return lhs; } if (lhs->isIntegerType()) { // convert the lhs to the rhs complex type. - promoteExprToType(lhsExpr, rhs); - return; + if (!isCompAssign) promoteExprToType(lhsExpr, rhs); + return rhs; } // Two complex types. Convert the smaller operand to the bigger result. if (Context.maxComplexType(lhs, rhs) == lhs) { // convert the rhs - promoteExprToType(rhsExpr, lhs); - return; + if (!isCompAssign) promoteExprToType(rhsExpr, lhs); + return lhs; } - promoteExprToType(lhsExpr, rhs); // convert the lhs - return; + if (!isCompAssign) promoteExprToType(lhsExpr, rhs); // convert the lhs + return rhs; } // Now handle "real" floating types (i.e. float, double, long double). if (lhs->isRealFloatingType() || rhs->isRealFloatingType()) { // if we have an integer operand, the result is the real floating type. if (rhs->isIntegerType()) { // convert rhs to the lhs floating point type. - promoteExprToType(rhsExpr, lhs); - return; + if (!isCompAssign) promoteExprToType(rhsExpr, lhs); + return lhs; } if (lhs->isIntegerType()) { // convert lhs to the rhs floating point type. - promoteExprToType(lhsExpr, rhs); - return; + if (!isCompAssign) promoteExprToType(lhsExpr, rhs); + return rhs; } // We have two real floating types, float/complex combos were handled above. // Convert the smaller operand to the bigger result. if (Context.maxFloatingType(lhs, rhs) == lhs) { // convert the rhs - promoteExprToType(rhsExpr, lhs); - return; + if (!isCompAssign) promoteExprToType(rhsExpr, lhs); + return lhs; } - promoteExprToType(lhsExpr, rhs); // convert the lhs - return; + if (!isCompAssign) promoteExprToType(lhsExpr, rhs); // convert the lhs + return rhs; } // Finally, we have two differing integer types. if (Context.maxIntegerType(lhs, rhs) == lhs) { // convert the rhs - promoteExprToType(rhsExpr, lhs); - return; + if (!isCompAssign) promoteExprToType(rhsExpr, lhs); + return lhs; } - promoteExprToType(lhsExpr, rhs); // convert the lhs - return; + if (!isCompAssign) promoteExprToType(lhsExpr, rhs); // convert the lhs + return rhs; } // CheckPointerTypesForAssignment - This is a very tricky routine (despite @@ -949,47 +950,45 @@ inline QualType Sema::CheckVectorOperands(SourceLocation loc, Expr *&lex, } inline QualType Sema::CheckMultiplyDivideOperands( - Expr *&lex, Expr *&rex, SourceLocation loc) + Expr *&lex, Expr *&rex, SourceLocation loc, bool isCompAssign) { QualType lhsType = lex->getType(), rhsType = rex->getType(); if (lhsType->isVectorType() || rhsType->isVectorType()) return CheckVectorOperands(loc, lex, rex); - UsualArithmeticConversions(lex, rex); + QualType compType = UsualArithmeticConversions(lex, rex, isCompAssign); - // handle the common case first (both operands are arithmetic). if (lex->getType()->isArithmeticType() && rex->getType()->isArithmeticType()) - return lex->getType(); + return compType; InvalidOperands(loc, lex, rex); return QualType(); } inline QualType Sema::CheckRemainderOperands( - Expr *&lex, Expr *&rex, SourceLocation loc) + Expr *&lex, Expr *&rex, SourceLocation loc, bool isCompAssign) { QualType lhsType = lex->getType(), rhsType = rex->getType(); - UsualArithmeticConversions(lex, rex); + QualType compType = UsualArithmeticConversions(lex, rex, isCompAssign); - // handle the common case first (both operands are arithmetic). if (lex->getType()->isIntegerType() && rex->getType()->isIntegerType()) - return lex->getType(); + return compType; InvalidOperands(loc, lex, rex); return QualType(); } inline QualType Sema::CheckAdditionOperands( // C99 6.5.6 - Expr *&lex, Expr *&rex, SourceLocation loc) + Expr *&lex, Expr *&rex, SourceLocation loc, bool isCompAssign) { if (lex->getType()->isVectorType() || rex->getType()->isVectorType()) return CheckVectorOperands(loc, lex, rex); - UsualArithmeticConversions(lex, rex); + QualType compType = UsualArithmeticConversions(lex, rex, isCompAssign); // handle the common case first (both operands are arithmetic). if (lex->getType()->isArithmeticType() && rex->getType()->isArithmeticType()) - return lex->getType(); + return compType; if (lex->getType()->isPointerType() && rex->getType()->isIntegerType()) return lex->getType(); @@ -1000,19 +999,19 @@ inline QualType Sema::CheckAdditionOperands( // C99 6.5.6 } inline QualType Sema::CheckSubtractionOperands( // C99 6.5.6 - Expr *&lex, Expr *&rex, SourceLocation loc) + Expr *&lex, Expr *&rex, SourceLocation loc, bool isCompAssign) { if (lex->getType()->isVectorType() || rex->getType()->isVectorType()) return CheckVectorOperands(loc, lex, rex); - UsualArithmeticConversions(lex, rex); + QualType compType = UsualArithmeticConversions(lex, rex, isCompAssign); // handle the common case first (both operands are arithmetic). if (lex->getType()->isArithmeticType() && rex->getType()->isArithmeticType()) - return lex->getType(); + return compType; if (lex->getType()->isPointerType() && rex->getType()->isIntegerType()) - return lex->getType(); + return compType; if (lex->getType()->isPointerType() && rex->getType()->isPointerType()) return Context.getPointerDiffType(); InvalidOperands(loc, lex, rex); @@ -1020,15 +1019,15 @@ inline QualType Sema::CheckSubtractionOperands( // C99 6.5.6 } inline QualType Sema::CheckShiftOperands( // C99 6.5.7 - Expr *&lex, Expr *&rex, SourceLocation loc) + Expr *&lex, Expr *&rex, SourceLocation loc, bool isCompAssign) { // FIXME: Shifts don't perform usual arithmetic conversions. This is wrong // for int << longlong -> the result type should be int, not long long. - UsualArithmeticConversions(lex, rex); + QualType compType = UsualArithmeticConversions(lex, rex, isCompAssign); // handle the common case first (both operands are arithmetic). if (lex->getType()->isIntegerType() && rex->getType()->isIntegerType()) - return lex->getType(); + return compType; InvalidOperands(loc, lex, rex); return QualType(); } @@ -1132,15 +1131,15 @@ inline QualType Sema::CheckEqualityOperands( // C99 6.5.9 } inline QualType Sema::CheckBitwiseOperands( - Expr *&lex, Expr *&rex, SourceLocation loc) + Expr *&lex, Expr *&rex, SourceLocation loc, bool isCompAssign) { if (lex->getType()->isVectorType() || rex->getType()->isVectorType()) return CheckVectorOperands(loc, lex, rex); - UsualArithmeticConversions(lex, rex); + QualType compType = UsualArithmeticConversions(lex, rex, isCompAssign); if (lex->getType()->isIntegerType() && rex->getType()->isIntegerType()) - return lex->getType(); + return compType; InvalidOperands(loc, lex, rex); return QualType(); } @@ -1486,35 +1485,35 @@ Action::ExprResult Sema::ParseBinOp(SourceLocation TokLoc, tok::TokenKind Kind, break; case BinaryOperator::MulAssign: case BinaryOperator::DivAssign: - CompTy = CheckMultiplyDivideOperands(lhs, rhs, TokLoc); + CompTy = CheckMultiplyDivideOperands(lhs, rhs, TokLoc, true); if (!CompTy.isNull()) ResultTy = CheckAssignmentOperands(lhs, rhs, TokLoc, CompTy); break; case BinaryOperator::RemAssign: - CompTy = CheckRemainderOperands(lhs, rhs, TokLoc); + CompTy = CheckRemainderOperands(lhs, rhs, TokLoc, true); if (!CompTy.isNull()) ResultTy = CheckAssignmentOperands(lhs, rhs, TokLoc, CompTy); break; case BinaryOperator::AddAssign: - CompTy = CheckAdditionOperands(lhs, rhs, TokLoc); + CompTy = CheckAdditionOperands(lhs, rhs, TokLoc, true); if (!CompTy.isNull()) ResultTy = CheckAssignmentOperands(lhs, rhs, TokLoc, CompTy); break; case BinaryOperator::SubAssign: - CompTy = CheckSubtractionOperands(lhs, rhs, TokLoc); + CompTy = CheckSubtractionOperands(lhs, rhs, TokLoc, true); if (!CompTy.isNull()) ResultTy = CheckAssignmentOperands(lhs, rhs, TokLoc, CompTy); break; case BinaryOperator::ShlAssign: case BinaryOperator::ShrAssign: - CompTy = CheckShiftOperands(lhs, rhs, TokLoc); + CompTy = CheckShiftOperands(lhs, rhs, TokLoc, true); if (!CompTy.isNull()) ResultTy = CheckAssignmentOperands(lhs, rhs, TokLoc, CompTy); break; case BinaryOperator::AndAssign: case BinaryOperator::XorAssign: case BinaryOperator::OrAssign: - CompTy = CheckBitwiseOperands(lhs, rhs, TokLoc); + CompTy = CheckBitwiseOperands(lhs, rhs, TokLoc, true); if (!CompTy.isNull()) ResultTy = CheckAssignmentOperands(lhs, rhs, TokLoc, CompTy); break; diff --git a/include/clang/AST/StmtNodes.def b/include/clang/AST/StmtNodes.def index 6a67e76cda..5f8ac72989 100644 --- a/include/clang/AST/StmtNodes.def +++ b/include/clang/AST/StmtNodes.def @@ -78,7 +78,7 @@ STMT(55, CXXBoolLiteralExpr , Expr) STMT(56, ObjCStringLiteral , Expr) STMT(57, ObjCEncodeExpr , Expr) -LAST_EXPR(56) +LAST_EXPR(57) #undef STMT #undef FIRST_STMT