Submitted by:
Reviewed by:
Implemented type checking for compound assignments (*=, /=, etc.).

This encouraged me to do a fairly dramatic refactoring of the Check* functions.
(since I wanted to reuse the existing work, rather than duplicate the logic).

For example, I changed all the Check* functions to return a QualType (instead
of returning an Expr). This had a very nice side benefit...there is now
only one instantiation point for BinaryOperator()! (A property I've always
wanted...separating type checking from AST building is *much* nicer). Another
change is to remove "code" from all the Check* functions (this allowed
me to remove the weird comment about enums/unsigned:-). Removing the
code forced me to add a few functions, however. For example,

<   ExprResult CheckAdditiveOperands( // C99 6.5.6
<     Expr *lex, Expr *rex, SourceLocation OpLoc, unsigned OpCode);

>   inline QualType CheckAdditionOperands( // C99 6.5.6
>     Expr *lex, Expr *rex, SourceLocation OpLoc);
>   inline QualType CheckSubtractionOperands( // C99 6.5.6
>     Expr *lex, Expr *rex, SourceLocation OpLoc);

While this isn't as terse, it more closely reflects the differences in
the typechecking logic. For example, I disliked having to check the code again
in CheckMultiplicativeOperands/CheckAdditiveOperands.

Created the following helper functions:
- Expr::isNullPointerConstant().
- SemaExpr.cpp: static inline BinaryOperator::Opcode ConvertTokenKindToBinaryOpcode().
This was purely asethetic, since ParseBinOp() is now larger. I didn't feel
like looking at 2 huge switch statements. ParseBinOp() now avoids using
any of the BinaryOperator predicates (since I switched to a switch statement:-)

Only one regret (minor). I couldn't figure out how to avoid having two assign functions,
CheckCompoundAssignmentOperands, CheckSimpleAssignmentOperands. Conceptually,
the two functions make sense. Unfortunately, their implementation contains a lot of
duplication (thought they aren't that be in the first place).

llvm-svn: 39433
This commit is contained in:
Steve Naroff 2007-05-04 21:54:46 +00:00
parent 17f76e04d2
commit 218bc2b32d
6 changed files with 682 additions and 389 deletions

View File

@ -153,3 +153,10 @@ bool Expr::isModifiableLvalue() {
return false;
}
}
bool Expr::isNullPointerConstant() const {
const IntegerLiteral *constant = dyn_cast<IntegerLiteral>(this);
if (!constant || constant->getValue() != 0)
return false;
return true;
}

View File

@ -233,32 +233,39 @@ private:
IntFromPointer,
IncompatiblePointer
};
// Conversions for assignment, argument passing, initialization, or return
QualType UsualAssignmentConversions(QualType lhs, Expr *rex, // C99 6.5.16
// Conversions for assignment, argument passing, initialization, and
// function return values. UsualAssignmentConversions is currently used by
// CheckSimpleAssignment, CheckCompoundAssignment and ParseCallExpr.
QualType UsualAssignmentConversions(QualType lhs, QualType rhs, // C99 6.5.16
AssignmentConversionResult &r);
/// the following "Check" methods will either return a well formed AST node
/// or will return true if the expressions didn't type check properly.
/// type checking binary operators (subroutines of ParseBinOp).
/// The unsigned arguments are really enums (BinaryOperator::Opcode)
ExprResult CheckMultiplicativeOperands( // C99 6.5.5
Expr *lex, Expr *rex, SourceLocation OpLoc, unsigned OpCode);
ExprResult CheckAdditiveOperands( // C99 6.5.6
Expr *lex, Expr *rex, SourceLocation OpLoc, unsigned OpCode);
ExprResult CheckShiftOperands( // C99 6.5.7
Expr *lex, Expr *rex, SourceLocation OpLoc, unsigned OpCode);
ExprResult CheckRelationalOperands( // C99 6.5.8
Expr *lex, Expr *rex, SourceLocation OpLoc, unsigned OpCode);
ExprResult CheckEqualityOperands( // C99 6.5.9
Expr *lex, Expr *rex, SourceLocation OpLoc, unsigned OpCode);
ExprResult CheckBitwiseOperands( // C99 6.5.[10...12]
Expr *lex, Expr *rex, SourceLocation OpLoc, unsigned OpCode);
ExprResult CheckLogicalOperands( // C99 6.5.[13,14]
Expr *lex, Expr *rex, SourceLocation OpLoc, unsigned OpCode);
ExprResult CheckAssignmentOperands( // C99 6.5.16
Expr *lex, Expr *rex, SourceLocation OpLoc, unsigned OpCode);
ExprResult CheckCommaOperands( // C99 6.5.17
inline QualType CheckMultiplyDivideOperands( // C99 6.5.5
Expr *lex, Expr *rex, SourceLocation OpLoc);
inline QualType CheckRemainderOperands( // C99 6.5.5
Expr *lex, Expr *rex, SourceLocation OpLoc);
inline QualType CheckAdditionOperands( // C99 6.5.6
Expr *lex, Expr *rex, SourceLocation OpLoc);
inline QualType CheckSubtractionOperands( // C99 6.5.6
Expr *lex, Expr *rex, SourceLocation OpLoc);
inline QualType CheckShiftOperands( // C99 6.5.7
Expr *lex, Expr *rex, SourceLocation OpLoc);
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);
inline QualType CheckLogicalOperands( // C99 6.5.[13,14]
Expr *lex, Expr *rex, SourceLocation OpLoc);
inline QualType CheckSimpleAssignmentOperands( // C99 6.5.16.1
Expr *lex, Expr *rex, SourceLocation OpLoc);
inline QualType CheckCompoundAssignmentOperands( // C99 6.5.16.2
Expr *lex, QualType, SourceLocation OpLoc);
inline QualType CheckCommaOperands( // C99 6.5.17
Expr *lex, Expr *rex, SourceLocation OpLoc);
/// type checking unary operators (subroutines of ParseUnaryOp).

View File

@ -365,7 +365,7 @@ ParseCallExpr(ExprTy *Fn, SourceLocation LParenLoc,
if (lhsType == rhsType) // common case, fast path...
continue;
AssignmentConversionResult result;
UsualAssignmentConversions(lhsType, ((Expr **)Args)[i], result);
UsualAssignmentConversions(lhsType, rhsType, result);
SourceLocation l = (i == 0) ? LParenLoc : CommaLocs[i-1];
@ -377,7 +377,9 @@ ParseCallExpr(ExprTy *Fn, SourceLocation LParenLoc,
case Compatible:
break;
case PointerFromInt:
Diag(l, diag::ext_typecheck_passing_pointer_from_int, utostr(i+1));
// check for null pointer constant (C99 6.3.2.3p3)
if (!((Expr **)Args)[i]->isNullPointerConstant())
Diag(l, diag::ext_typecheck_passing_pointer_from_int, utostr(i+1));
break;
case IntFromPointer:
Diag(l, diag::ext_typecheck_passing_int_from_pointer, utostr(i+1));
@ -401,73 +403,6 @@ ParseCastExpr(SourceLocation LParenLoc, TypeTy *Ty,
return new CastExpr(QualType::getFromOpaquePtr(Ty), (Expr*)Op);
}
// Binary Operators. 'Tok' is the token for the operator.
Action::ExprResult Sema::ParseBinOp(SourceLocation TokLoc, tok::TokenKind Kind,
ExprTy *LHS, ExprTy *RHS) {
BinaryOperator::Opcode Opc;
switch (Kind) {
default: assert(0 && "Unknown binop!");
case tok::star: Opc = BinaryOperator::Mul; break;
case tok::slash: Opc = BinaryOperator::Div; break;
case tok::percent: Opc = BinaryOperator::Rem; break;
case tok::plus: Opc = BinaryOperator::Add; break;
case tok::minus: Opc = BinaryOperator::Sub; break;
case tok::lessless: Opc = BinaryOperator::Shl; break;
case tok::greatergreater: Opc = BinaryOperator::Shr; break;
case tok::lessequal: Opc = BinaryOperator::LE; break;
case tok::less: Opc = BinaryOperator::LT; break;
case tok::greaterequal: Opc = BinaryOperator::GE; break;
case tok::greater: Opc = BinaryOperator::GT; break;
case tok::exclaimequal: Opc = BinaryOperator::NE; break;
case tok::equalequal: Opc = BinaryOperator::EQ; break;
case tok::amp: Opc = BinaryOperator::And; break;
case tok::caret: Opc = BinaryOperator::Xor; break;
case tok::pipe: Opc = BinaryOperator::Or; break;
case tok::ampamp: Opc = BinaryOperator::LAnd; break;
case tok::pipepipe: Opc = BinaryOperator::LOr; break;
case tok::equal: Opc = BinaryOperator::Assign; break;
case tok::starequal: Opc = BinaryOperator::MulAssign; break;
case tok::slashequal: Opc = BinaryOperator::DivAssign; break;
case tok::percentequal: Opc = BinaryOperator::RemAssign; break;
case tok::plusequal: Opc = BinaryOperator::AddAssign; break;
case tok::minusequal: Opc = BinaryOperator::SubAssign; break;
case tok::lesslessequal: Opc = BinaryOperator::ShlAssign; break;
case tok::greatergreaterequal: Opc = BinaryOperator::ShrAssign; break;
case tok::ampequal: Opc = BinaryOperator::AndAssign; break;
case tok::caretequal: Opc = BinaryOperator::XorAssign; break;
case tok::pipeequal: Opc = BinaryOperator::OrAssign; break;
case tok::comma: Opc = BinaryOperator::Comma; break;
}
Expr *lhs = (Expr *)LHS, *rhs = (Expr*)RHS;
assert((lhs != 0) && "ParseBinOp(): missing left expression");
assert((rhs != 0) && "ParseBinOp(): missing right expression");
if (BinaryOperator::isMultiplicativeOp(Opc))
return CheckMultiplicativeOperands(lhs, rhs, TokLoc, Opc);
else if (BinaryOperator::isAdditiveOp(Opc))
return CheckAdditiveOperands(lhs, rhs, TokLoc, Opc);
else if (BinaryOperator::isShiftOp(Opc))
return CheckShiftOperands(lhs, rhs, TokLoc, Opc);
else if (BinaryOperator::isRelationalOp(Opc))
return CheckRelationalOperands(lhs, rhs, TokLoc, Opc);
else if (BinaryOperator::isEqualityOp(Opc))
return CheckEqualityOperands(lhs, rhs, TokLoc, Opc);
else if (BinaryOperator::isBitwiseOp(Opc))
return CheckBitwiseOperands(lhs, rhs, TokLoc, Opc);
else if (BinaryOperator::isLogicalOp(Opc))
return CheckLogicalOperands(lhs, rhs, TokLoc, Opc);
else if (BinaryOperator::isAssignmentOp(Opc))
return CheckAssignmentOperands(lhs, rhs, TokLoc, Opc);
else if (Opc == BinaryOperator::Comma)
return CheckCommaOperands(lhs, rhs, TokLoc);
assert(0 && "ParseBinOp(): illegal binary op");
}
/// ParseConditionalOp - Parse a ?: operation. Note that 'LHS' may be null
/// in the case of a the GNU conditional expr extension.
Action::ExprResult Sema::ParseConditionalOp(SourceLocation QuestionLoc,
@ -562,10 +497,8 @@ QualType Sema::UsualArithmeticConversions(QualType t1, QualType t2) {
/// C99 spec dictates.
/// Note: the warning above turn into errors when -pedantic-errors is enabled.
///
QualType Sema::UsualAssignmentConversions(QualType lhsType, Expr *rex,
QualType Sema::UsualAssignmentConversions(QualType lhsType, QualType rhsType,
AssignmentConversionResult &r) {
QualType rhsType = rex->getType();
// this check seems unnatural, however it necessary to insure the proper
// conversion of functions/arrays. If the conversion where done for all
// DeclExpr's (created by ParseIdentifierExpr), it would mess up the
@ -578,10 +511,7 @@ QualType Sema::UsualAssignmentConversions(QualType lhsType, Expr *rex,
return lhsType;
else if (lhsType->isPointerType()) {
if (rhsType->isIntegerType()) {
// check for null pointer constant (C99 6.3.2.3p3)
const IntegerLiteral *constant = dyn_cast<IntegerLiteral>(rex);
if (!constant || constant->getValue() != 0)
r = PointerFromInt;
r = PointerFromInt;
return rhsType;
}
// FIXME: make sure the qualifier are matching
@ -616,160 +546,223 @@ QualType Sema::UsualAssignmentConversions(QualType lhsType, Expr *rex,
return QualType();
}
Action::ExprResult Sema::CheckMultiplicativeOperands(
Expr *lex, Expr *rex, SourceLocation loc, unsigned code)
inline QualType Sema::CheckMultiplyDivideOperands(
Expr *lex, Expr *rex, SourceLocation loc)
{
QualType resType = UsualArithmeticConversions(lex->getType(), rex->getType());
if ((BOP)code == BinaryOperator::Rem) {
if (!resType->isIntegerType())
return Diag(loc, diag::err_typecheck_invalid_operands);
} else { // *, /
if (!resType->isArithmeticType())
return Diag(loc, diag::err_typecheck_invalid_operands);
}
return new BinaryOperator(lex, rex, (BOP)code, resType);
if (resType->isArithmeticType())
return resType;
Diag(loc, diag::err_typecheck_invalid_operands);
return QualType();
}
Action::ExprResult Sema::CheckAdditiveOperands( // C99 6.5.6
Expr *lex, Expr *rex, SourceLocation loc, unsigned code)
inline QualType Sema::CheckRemainderOperands(
Expr *lex, Expr *rex, SourceLocation loc)
{
QualType resType = UsualArithmeticConversions(lex->getType(), rex->getType());
if (resType->isIntegerType())
return resType;
Diag(loc, diag::err_typecheck_invalid_operands);
return QualType();
}
inline QualType Sema::CheckAdditionOperands( // C99 6.5.6
Expr *lex, Expr *rex, SourceLocation loc)
{
QualType lhsType = lex->getType(), rhsType = rex->getType();
QualType resType = UsualArithmeticConversions(lhsType, rhsType);
// handle the common case first (both operands are arithmetic).
if (resType->isArithmeticType())
return new BinaryOperator(lex, rex, (BOP)code, resType);
else {
if ((BOP)code == BinaryOperator::Add) {
if ((lhsType->isPointerType() && rhsType->isIntegerType()) ||
(lhsType->isIntegerType() && rhsType->isPointerType()))
return new BinaryOperator(lex, rex, (BOP)code, resType);
} else { // -
if ((lhsType->isPointerType() && rhsType->isIntegerType()) ||
(lhsType->isPointerType() && rhsType->isPointerType()))
return new BinaryOperator(lex, rex, (BOP)code, resType);
}
}
return Diag(loc, diag::err_typecheck_invalid_operands);
return resType;
if ((lhsType->isPointerType() && rhsType->isIntegerType()) ||
(lhsType->isIntegerType() && rhsType->isPointerType()))
return resType;
Diag(loc, diag::err_typecheck_invalid_operands);
return QualType();
}
Action::ExprResult Sema::CheckShiftOperands( // C99 6.5.7
Expr *lex, Expr *rex, SourceLocation loc, unsigned code)
inline QualType Sema::CheckSubtractionOperands( // C99 6.5.6
Expr *lex, Expr *rex, SourceLocation loc)
{
QualType lhsType = lex->getType(), rhsType = rex->getType();
QualType resType = UsualArithmeticConversions(lhsType, rhsType);
// handle the common case first (both operands are arithmetic).
if (resType->isArithmeticType())
return resType;
if ((lhsType->isPointerType() && rhsType->isIntegerType()) ||
(lhsType->isPointerType() && rhsType->isPointerType()))
return resType;
Diag(loc, diag::err_typecheck_invalid_operands);
return QualType();
}
inline QualType Sema::CheckShiftOperands( // C99 6.5.7
Expr *lex, Expr *rex, SourceLocation loc)
{
QualType resType = UsualArithmeticConversions(lex->getType(), rex->getType());
if (!resType->isIntegerType())
return Diag(loc, diag::err_typecheck_invalid_operands);
return new BinaryOperator(lex, rex, (BOP)code, resType);
if (resType->isIntegerType())
return resType;
Diag(loc, diag::err_typecheck_invalid_operands);
return QualType();
}
Action::ExprResult Sema::CheckRelationalOperands( // C99 6.5.8
Expr *lex, Expr *rex, SourceLocation loc, unsigned code)
inline QualType Sema::CheckRelationalOperands( // C99 6.5.8
Expr *lex, Expr *rex, SourceLocation loc)
{
QualType lType = lex->getType(), rType = rex->getType();
if (lType->isRealType() && rType->isRealType())
return new BinaryOperator(lex, rex, (BOP)code, Context.IntTy);
return Context.IntTy;
if (lType->isPointerType() && rType->isPointerType())
return new BinaryOperator(lex, rex, (BOP)code, Context.IntTy);
return Context.IntTy;
if (lType->isIntegerType() || rType->isIntegerType()) // GCC extension.
return Diag(loc, diag::ext_typecheck_comparison_of_pointer_integer);
return Diag(loc, diag::err_typecheck_invalid_operands);
Diag(loc, diag::ext_typecheck_comparison_of_pointer_integer);
else
Diag(loc, diag::err_typecheck_invalid_operands);
return QualType();
}
Action::ExprResult Sema::CheckEqualityOperands( // C99 6.5.9
Expr *lex, Expr *rex, SourceLocation loc, unsigned code)
inline QualType Sema::CheckEqualityOperands( // C99 6.5.9
Expr *lex, Expr *rex, SourceLocation loc)
{
QualType lType = lex->getType(), rType = rex->getType();
if (lType->isArithmeticType() && rType->isArithmeticType())
return new BinaryOperator(lex, rex, (BOP)code, Context.IntTy);
return Context.IntTy;
if (lType->isPointerType() && rType->isPointerType())
return new BinaryOperator(lex, rex, (BOP)code, Context.IntTy);
return Context.IntTy;
if (lType->isIntegerType() || rType->isIntegerType()) // GCC extension.
return Diag(loc, diag::ext_typecheck_comparison_of_pointer_integer);
return Diag(loc, diag::err_typecheck_invalid_operands);
Diag(loc, diag::ext_typecheck_comparison_of_pointer_integer);
else
Diag(loc, diag::err_typecheck_invalid_operands);
return QualType();
}
Action::ExprResult Sema::CheckBitwiseOperands(
Expr *lex, Expr *rex, SourceLocation loc, unsigned code)
inline QualType Sema::CheckBitwiseOperands(
Expr *lex, Expr *rex, SourceLocation loc)
{
QualType resType = UsualArithmeticConversions(lex->getType(), rex->getType());
if (!resType->isIntegerType())
return Diag(loc, diag::err_typecheck_invalid_operands);
return new BinaryOperator(lex, rex, (BOP)code, resType);
if (resType->isIntegerType())
return resType;
Diag(loc, diag::err_typecheck_invalid_operands);
return QualType();
}
Action::ExprResult Sema::CheckLogicalOperands( // C99 6.5.[13,14]
Expr *lex, Expr *rex, SourceLocation loc, unsigned code)
inline QualType Sema::CheckLogicalOperands( // C99 6.5.[13,14]
Expr *lex, Expr *rex, SourceLocation loc)
{
QualType lhsType = UsualUnaryConversion(lex->getType());
QualType rhsType = UsualUnaryConversion(rex->getType());
if (!lhsType->isScalarType() || !rhsType->isScalarType())
return Diag(loc, diag::err_typecheck_invalid_operands);
return new BinaryOperator(lex, rex, (BOP)code, Context.IntTy);
if (lhsType->isScalarType() || rhsType->isScalarType())
return Context.IntTy;
Diag(loc, diag::err_typecheck_invalid_operands);
return QualType();
}
Action::ExprResult Sema::CheckAssignmentOperands(
Expr *lex, Expr *rex, SourceLocation loc, unsigned code)
inline QualType Sema::CheckSimpleAssignmentOperands( // C99 6.5.16.1
Expr *lex, Expr *rex, SourceLocation loc)
{
QualType lhsType = lex->getType();
QualType rhsType = rex->getType();
if ((BOP)code == BinaryOperator::Assign) { // C99 6.5.16.1
// FIXME: consider hacking isModifiableLvalue to return an enum that
// communicates why the expression/type wasn't a modifiableLvalue.
// this check is done first to give a more precise diagnostic.
if (lhsType.isConstQualified())
return Diag(loc, diag::err_typecheck_assign_const);
if (!lex->isModifiableLvalue()) // this includes checking for "const"
return Diag(loc, diag::ext_typecheck_assign_non_lvalue);
if (lhsType == rhsType) // common case, fast path...
return new BinaryOperator(lex, rex, (BOP)code, lhsType);
AssignmentConversionResult result;
QualType resType = UsualAssignmentConversions(lhsType, rex, result);
// decode the result (notice that AST's are still created for extensions).
switch (result) {
case Compatible:
break;
case PointerFromInt:
Diag(loc, diag::ext_typecheck_assign_pointer_from_int);
break;
case IntFromPointer:
Diag(loc, diag::ext_typecheck_assign_int_from_pointer);
break;
case IncompatiblePointer:
Diag(loc, diag::ext_typecheck_assign_incompatible_pointer);
break;
case Incompatible:
return Diag(loc, diag::err_typecheck_assign_incompatible);
}
return new BinaryOperator(lex, rex, (BOP)code, resType);
// FIXME: consider hacking isModifiableLvalue to return an enum that
// communicates why the expression/type wasn't a modifiableLvalue.
// this check is done first to give a more precise diagnostic.
if (lhsType.isConstQualified()) {
Diag(loc, diag::err_typecheck_assign_const);
return QualType();
}
// FIXME: type check compound assignments...
return new BinaryOperator(lex, rex, (BOP)code, Context.IntTy);
if (!lex->isModifiableLvalue()) { // this includes checking for "const"
Diag(loc, diag::ext_typecheck_assign_non_lvalue);
return QualType();
}
if (lhsType == rhsType) // common case, fast path...
return lhsType;
AssignmentConversionResult result;
QualType resType = UsualAssignmentConversions(lhsType, rhsType, result);
// decode the result (notice that extensions still return a type).
switch (result) {
case Compatible:
return resType;
case Incompatible:
Diag(loc, diag::err_typecheck_assign_incompatible);
return QualType();
case PointerFromInt:
// check for null pointer constant (C99 6.3.2.3p3)
if (!rex->isNullPointerConstant())
Diag(loc, diag::ext_typecheck_assign_pointer_from_int);
return resType;
case IntFromPointer:
Diag(loc, diag::ext_typecheck_assign_int_from_pointer);
return resType;
case IncompatiblePointer:
Diag(loc, diag::ext_typecheck_assign_incompatible_pointer);
return resType;
}
assert(0 && "should never get here");
}
Action::ExprResult Sema::CheckCommaOperands( // C99 6.5.17
inline QualType Sema::CheckCompoundAssignmentOperands( // C99 6.5.16.2
Expr *lex, QualType rhsType, SourceLocation loc)
{
QualType lhsType = lex->getType();
// FIXME: consider hacking isModifiableLvalue to return an enum that
// communicates why the expression/type wasn't a modifiableLvalue.
// this check is done first to give a more precise diagnostic.
if (lhsType.isConstQualified()) {
Diag(loc, diag::err_typecheck_assign_const);
return QualType();
}
if (!lex->isModifiableLvalue()) { // this includes checking for "const"
Diag(loc, diag::ext_typecheck_assign_non_lvalue);
return QualType();
}
if (lhsType == rhsType) // common case, fast path...
return lhsType;
AssignmentConversionResult result;
QualType resType = UsualAssignmentConversions(lhsType, rhsType, result);
// decode the result (notice that extensions still return a type).
switch (result) {
case Compatible:
return resType;
case Incompatible:
Diag(loc, diag::err_typecheck_assign_incompatible);
return QualType();
case PointerFromInt:
Diag(loc, diag::ext_typecheck_assign_pointer_from_int);
return resType;
case IntFromPointer:
Diag(loc, diag::ext_typecheck_assign_int_from_pointer);
return resType;
case IncompatiblePointer:
Diag(loc, diag::ext_typecheck_assign_incompatible_pointer);
return resType;
}
assert(0 && "should never get here");
}
inline QualType Sema::CheckCommaOperands( // C99 6.5.17
Expr *lex, Expr *rex, SourceLocation loc)
{
QualType rhsType = UsualUnaryConversion(rex->getType());
return new BinaryOperator(lex, rex, BinaryOperator::Comma, rhsType);
return UsualUnaryConversion(rex->getType());
}
Action::ExprResult
@ -886,3 +879,145 @@ Sema::CheckArithmeticOperand(Expr *op, SourceLocation OpLoc, unsigned Opc) {
}
return new UnaryOperator(op, (UOP)Opc, resultType);
}
static inline BinaryOperator::Opcode ConvertTokenKindToBinaryOpcode(
tok::TokenKind Kind) {
BinaryOperator::Opcode Opc;
switch (Kind) {
default: assert(0 && "Unknown binop!");
case tok::star: Opc = BinaryOperator::Mul; break;
case tok::slash: Opc = BinaryOperator::Div; break;
case tok::percent: Opc = BinaryOperator::Rem; break;
case tok::plus: Opc = BinaryOperator::Add; break;
case tok::minus: Opc = BinaryOperator::Sub; break;
case tok::lessless: Opc = BinaryOperator::Shl; break;
case tok::greatergreater: Opc = BinaryOperator::Shr; break;
case tok::lessequal: Opc = BinaryOperator::LE; break;
case tok::less: Opc = BinaryOperator::LT; break;
case tok::greaterequal: Opc = BinaryOperator::GE; break;
case tok::greater: Opc = BinaryOperator::GT; break;
case tok::exclaimequal: Opc = BinaryOperator::NE; break;
case tok::equalequal: Opc = BinaryOperator::EQ; break;
case tok::amp: Opc = BinaryOperator::And; break;
case tok::caret: Opc = BinaryOperator::Xor; break;
case tok::pipe: Opc = BinaryOperator::Or; break;
case tok::ampamp: Opc = BinaryOperator::LAnd; break;
case tok::pipepipe: Opc = BinaryOperator::LOr; break;
case tok::equal: Opc = BinaryOperator::Assign; break;
case tok::starequal: Opc = BinaryOperator::MulAssign; break;
case tok::slashequal: Opc = BinaryOperator::DivAssign; break;
case tok::percentequal: Opc = BinaryOperator::RemAssign; break;
case tok::plusequal: Opc = BinaryOperator::AddAssign; break;
case tok::minusequal: Opc = BinaryOperator::SubAssign; break;
case tok::lesslessequal: Opc = BinaryOperator::ShlAssign; break;
case tok::greatergreaterequal: Opc = BinaryOperator::ShrAssign; break;
case tok::ampequal: Opc = BinaryOperator::AndAssign; break;
case tok::caretequal: Opc = BinaryOperator::XorAssign; break;
case tok::pipeequal: Opc = BinaryOperator::OrAssign; break;
case tok::comma: Opc = BinaryOperator::Comma; break;
}
return Opc;
}
// Binary Operators. 'Tok' is the token for the operator.
Action::ExprResult Sema::ParseBinOp(SourceLocation TokLoc, tok::TokenKind Kind,
ExprTy *LHS, ExprTy *RHS) {
BinaryOperator::Opcode Opc = ConvertTokenKindToBinaryOpcode(Kind);
Expr *lhs = (Expr *)LHS, *rhs = (Expr*)RHS;
assert((lhs != 0) && "ParseBinOp(): missing left expression");
assert((rhs != 0) && "ParseBinOp(): missing right expression");
QualType result;
switch (Opc) {
default:
assert(0 && "Unknown binary expr!");
case BinaryOperator::Assign:
result = CheckSimpleAssignmentOperands(lhs, rhs, TokLoc);
break;
case BinaryOperator::Mul:
case BinaryOperator::Div:
result = CheckMultiplyDivideOperands(lhs, rhs, TokLoc);
break;
case BinaryOperator::Rem:
result = CheckRemainderOperands(lhs, rhs, TokLoc);
break;
case BinaryOperator::Add:
result = CheckAdditionOperands(lhs, rhs, TokLoc);
break;
case BinaryOperator::Sub:
result = CheckSubtractionOperands(lhs, rhs, TokLoc);
break;
case BinaryOperator::Shl:
case BinaryOperator::Shr:
result = CheckShiftOperands(lhs, rhs, TokLoc);
break;
case BinaryOperator::LE:
case BinaryOperator::LT:
case BinaryOperator::GE:
case BinaryOperator::GT:
result = CheckRelationalOperands(lhs, rhs, TokLoc);
break;
case BinaryOperator::EQ:
case BinaryOperator::NE:
result = CheckEqualityOperands(lhs, rhs, TokLoc);
break;
case BinaryOperator::And:
case BinaryOperator::Xor:
case BinaryOperator::Or:
result = CheckBitwiseOperands(lhs, rhs, TokLoc);
break;
case BinaryOperator::LAnd:
case BinaryOperator::LOr:
result = CheckLogicalOperands(lhs, rhs, TokLoc);
break;
case BinaryOperator::MulAssign:
case BinaryOperator::DivAssign:
result = CheckMultiplyDivideOperands(lhs, rhs, TokLoc);
if (result.isNull())
return true;
result = CheckCompoundAssignmentOperands(lhs, result, TokLoc);
break;
case BinaryOperator::RemAssign:
result = CheckRemainderOperands(lhs, rhs, TokLoc);
if (result.isNull())
return true;
result = CheckCompoundAssignmentOperands(lhs, result, TokLoc);
break;
case BinaryOperator::AddAssign:
result = CheckAdditionOperands(lhs, rhs, TokLoc);
if (result.isNull())
return true;
result = CheckCompoundAssignmentOperands(lhs, result, TokLoc);
break;
case BinaryOperator::SubAssign:
result = CheckSubtractionOperands(lhs, rhs, TokLoc);
if (result.isNull())
return true;
result = CheckCompoundAssignmentOperands(lhs, result, TokLoc);
break;
case BinaryOperator::ShlAssign:
case BinaryOperator::ShrAssign:
result = CheckShiftOperands(lhs, rhs, TokLoc);
if (result.isNull())
return true;
result = CheckCompoundAssignmentOperands(lhs, result, TokLoc);
break;
case BinaryOperator::AndAssign:
case BinaryOperator::XorAssign:
case BinaryOperator::OrAssign:
result = CheckBitwiseOperands(lhs, rhs, TokLoc);
if (result.isNull())
return true;
result = CheckCompoundAssignmentOperands(lhs, result, TokLoc);
break;
case BinaryOperator::Comma:
result = CheckCommaOperands(lhs, rhs, TokLoc);
break;
}
if (result.isNull())
return true;
return new BinaryOperator(lhs, rhs, Opc, result);
}

View File

@ -233,32 +233,39 @@ private:
IntFromPointer,
IncompatiblePointer
};
// Conversions for assignment, argument passing, initialization, or return
QualType UsualAssignmentConversions(QualType lhs, Expr *rex, // C99 6.5.16
// Conversions for assignment, argument passing, initialization, and
// function return values. UsualAssignmentConversions is currently used by
// CheckSimpleAssignment, CheckCompoundAssignment and ParseCallExpr.
QualType UsualAssignmentConversions(QualType lhs, QualType rhs, // C99 6.5.16
AssignmentConversionResult &r);
/// the following "Check" methods will either return a well formed AST node
/// or will return true if the expressions didn't type check properly.
/// type checking binary operators (subroutines of ParseBinOp).
/// The unsigned arguments are really enums (BinaryOperator::Opcode)
ExprResult CheckMultiplicativeOperands( // C99 6.5.5
Expr *lex, Expr *rex, SourceLocation OpLoc, unsigned OpCode);
ExprResult CheckAdditiveOperands( // C99 6.5.6
Expr *lex, Expr *rex, SourceLocation OpLoc, unsigned OpCode);
ExprResult CheckShiftOperands( // C99 6.5.7
Expr *lex, Expr *rex, SourceLocation OpLoc, unsigned OpCode);
ExprResult CheckRelationalOperands( // C99 6.5.8
Expr *lex, Expr *rex, SourceLocation OpLoc, unsigned OpCode);
ExprResult CheckEqualityOperands( // C99 6.5.9
Expr *lex, Expr *rex, SourceLocation OpLoc, unsigned OpCode);
ExprResult CheckBitwiseOperands( // C99 6.5.[10...12]
Expr *lex, Expr *rex, SourceLocation OpLoc, unsigned OpCode);
ExprResult CheckLogicalOperands( // C99 6.5.[13,14]
Expr *lex, Expr *rex, SourceLocation OpLoc, unsigned OpCode);
ExprResult CheckAssignmentOperands( // C99 6.5.16
Expr *lex, Expr *rex, SourceLocation OpLoc, unsigned OpCode);
ExprResult CheckCommaOperands( // C99 6.5.17
inline QualType CheckMultiplyDivideOperands( // C99 6.5.5
Expr *lex, Expr *rex, SourceLocation OpLoc);
inline QualType CheckRemainderOperands( // C99 6.5.5
Expr *lex, Expr *rex, SourceLocation OpLoc);
inline QualType CheckAdditionOperands( // C99 6.5.6
Expr *lex, Expr *rex, SourceLocation OpLoc);
inline QualType CheckSubtractionOperands( // C99 6.5.6
Expr *lex, Expr *rex, SourceLocation OpLoc);
inline QualType CheckShiftOperands( // C99 6.5.7
Expr *lex, Expr *rex, SourceLocation OpLoc);
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);
inline QualType CheckLogicalOperands( // C99 6.5.[13,14]
Expr *lex, Expr *rex, SourceLocation OpLoc);
inline QualType CheckSimpleAssignmentOperands( // C99 6.5.16.1
Expr *lex, Expr *rex, SourceLocation OpLoc);
inline QualType CheckCompoundAssignmentOperands( // C99 6.5.16.2
Expr *lex, QualType, SourceLocation OpLoc);
inline QualType CheckCommaOperands( // C99 6.5.17
Expr *lex, Expr *rex, SourceLocation OpLoc);
/// type checking unary operators (subroutines of ParseUnaryOp).

View File

@ -365,7 +365,7 @@ ParseCallExpr(ExprTy *Fn, SourceLocation LParenLoc,
if (lhsType == rhsType) // common case, fast path...
continue;
AssignmentConversionResult result;
UsualAssignmentConversions(lhsType, ((Expr **)Args)[i], result);
UsualAssignmentConversions(lhsType, rhsType, result);
SourceLocation l = (i == 0) ? LParenLoc : CommaLocs[i-1];
@ -377,7 +377,9 @@ ParseCallExpr(ExprTy *Fn, SourceLocation LParenLoc,
case Compatible:
break;
case PointerFromInt:
Diag(l, diag::ext_typecheck_passing_pointer_from_int, utostr(i+1));
// check for null pointer constant (C99 6.3.2.3p3)
if (!((Expr **)Args)[i]->isNullPointerConstant())
Diag(l, diag::ext_typecheck_passing_pointer_from_int, utostr(i+1));
break;
case IntFromPointer:
Diag(l, diag::ext_typecheck_passing_int_from_pointer, utostr(i+1));
@ -401,73 +403,6 @@ ParseCastExpr(SourceLocation LParenLoc, TypeTy *Ty,
return new CastExpr(QualType::getFromOpaquePtr(Ty), (Expr*)Op);
}
// Binary Operators. 'Tok' is the token for the operator.
Action::ExprResult Sema::ParseBinOp(SourceLocation TokLoc, tok::TokenKind Kind,
ExprTy *LHS, ExprTy *RHS) {
BinaryOperator::Opcode Opc;
switch (Kind) {
default: assert(0 && "Unknown binop!");
case tok::star: Opc = BinaryOperator::Mul; break;
case tok::slash: Opc = BinaryOperator::Div; break;
case tok::percent: Opc = BinaryOperator::Rem; break;
case tok::plus: Opc = BinaryOperator::Add; break;
case tok::minus: Opc = BinaryOperator::Sub; break;
case tok::lessless: Opc = BinaryOperator::Shl; break;
case tok::greatergreater: Opc = BinaryOperator::Shr; break;
case tok::lessequal: Opc = BinaryOperator::LE; break;
case tok::less: Opc = BinaryOperator::LT; break;
case tok::greaterequal: Opc = BinaryOperator::GE; break;
case tok::greater: Opc = BinaryOperator::GT; break;
case tok::exclaimequal: Opc = BinaryOperator::NE; break;
case tok::equalequal: Opc = BinaryOperator::EQ; break;
case tok::amp: Opc = BinaryOperator::And; break;
case tok::caret: Opc = BinaryOperator::Xor; break;
case tok::pipe: Opc = BinaryOperator::Or; break;
case tok::ampamp: Opc = BinaryOperator::LAnd; break;
case tok::pipepipe: Opc = BinaryOperator::LOr; break;
case tok::equal: Opc = BinaryOperator::Assign; break;
case tok::starequal: Opc = BinaryOperator::MulAssign; break;
case tok::slashequal: Opc = BinaryOperator::DivAssign; break;
case tok::percentequal: Opc = BinaryOperator::RemAssign; break;
case tok::plusequal: Opc = BinaryOperator::AddAssign; break;
case tok::minusequal: Opc = BinaryOperator::SubAssign; break;
case tok::lesslessequal: Opc = BinaryOperator::ShlAssign; break;
case tok::greatergreaterequal: Opc = BinaryOperator::ShrAssign; break;
case tok::ampequal: Opc = BinaryOperator::AndAssign; break;
case tok::caretequal: Opc = BinaryOperator::XorAssign; break;
case tok::pipeequal: Opc = BinaryOperator::OrAssign; break;
case tok::comma: Opc = BinaryOperator::Comma; break;
}
Expr *lhs = (Expr *)LHS, *rhs = (Expr*)RHS;
assert((lhs != 0) && "ParseBinOp(): missing left expression");
assert((rhs != 0) && "ParseBinOp(): missing right expression");
if (BinaryOperator::isMultiplicativeOp(Opc))
return CheckMultiplicativeOperands(lhs, rhs, TokLoc, Opc);
else if (BinaryOperator::isAdditiveOp(Opc))
return CheckAdditiveOperands(lhs, rhs, TokLoc, Opc);
else if (BinaryOperator::isShiftOp(Opc))
return CheckShiftOperands(lhs, rhs, TokLoc, Opc);
else if (BinaryOperator::isRelationalOp(Opc))
return CheckRelationalOperands(lhs, rhs, TokLoc, Opc);
else if (BinaryOperator::isEqualityOp(Opc))
return CheckEqualityOperands(lhs, rhs, TokLoc, Opc);
else if (BinaryOperator::isBitwiseOp(Opc))
return CheckBitwiseOperands(lhs, rhs, TokLoc, Opc);
else if (BinaryOperator::isLogicalOp(Opc))
return CheckLogicalOperands(lhs, rhs, TokLoc, Opc);
else if (BinaryOperator::isAssignmentOp(Opc))
return CheckAssignmentOperands(lhs, rhs, TokLoc, Opc);
else if (Opc == BinaryOperator::Comma)
return CheckCommaOperands(lhs, rhs, TokLoc);
assert(0 && "ParseBinOp(): illegal binary op");
}
/// ParseConditionalOp - Parse a ?: operation. Note that 'LHS' may be null
/// in the case of a the GNU conditional expr extension.
Action::ExprResult Sema::ParseConditionalOp(SourceLocation QuestionLoc,
@ -562,10 +497,8 @@ QualType Sema::UsualArithmeticConversions(QualType t1, QualType t2) {
/// C99 spec dictates.
/// Note: the warning above turn into errors when -pedantic-errors is enabled.
///
QualType Sema::UsualAssignmentConversions(QualType lhsType, Expr *rex,
QualType Sema::UsualAssignmentConversions(QualType lhsType, QualType rhsType,
AssignmentConversionResult &r) {
QualType rhsType = rex->getType();
// this check seems unnatural, however it necessary to insure the proper
// conversion of functions/arrays. If the conversion where done for all
// DeclExpr's (created by ParseIdentifierExpr), it would mess up the
@ -578,10 +511,7 @@ QualType Sema::UsualAssignmentConversions(QualType lhsType, Expr *rex,
return lhsType;
else if (lhsType->isPointerType()) {
if (rhsType->isIntegerType()) {
// check for null pointer constant (C99 6.3.2.3p3)
const IntegerLiteral *constant = dyn_cast<IntegerLiteral>(rex);
if (!constant || constant->getValue() != 0)
r = PointerFromInt;
r = PointerFromInt;
return rhsType;
}
// FIXME: make sure the qualifier are matching
@ -616,160 +546,223 @@ QualType Sema::UsualAssignmentConversions(QualType lhsType, Expr *rex,
return QualType();
}
Action::ExprResult Sema::CheckMultiplicativeOperands(
Expr *lex, Expr *rex, SourceLocation loc, unsigned code)
inline QualType Sema::CheckMultiplyDivideOperands(
Expr *lex, Expr *rex, SourceLocation loc)
{
QualType resType = UsualArithmeticConversions(lex->getType(), rex->getType());
if ((BOP)code == BinaryOperator::Rem) {
if (!resType->isIntegerType())
return Diag(loc, diag::err_typecheck_invalid_operands);
} else { // *, /
if (!resType->isArithmeticType())
return Diag(loc, diag::err_typecheck_invalid_operands);
}
return new BinaryOperator(lex, rex, (BOP)code, resType);
if (resType->isArithmeticType())
return resType;
Diag(loc, diag::err_typecheck_invalid_operands);
return QualType();
}
Action::ExprResult Sema::CheckAdditiveOperands( // C99 6.5.6
Expr *lex, Expr *rex, SourceLocation loc, unsigned code)
inline QualType Sema::CheckRemainderOperands(
Expr *lex, Expr *rex, SourceLocation loc)
{
QualType resType = UsualArithmeticConversions(lex->getType(), rex->getType());
if (resType->isIntegerType())
return resType;
Diag(loc, diag::err_typecheck_invalid_operands);
return QualType();
}
inline QualType Sema::CheckAdditionOperands( // C99 6.5.6
Expr *lex, Expr *rex, SourceLocation loc)
{
QualType lhsType = lex->getType(), rhsType = rex->getType();
QualType resType = UsualArithmeticConversions(lhsType, rhsType);
// handle the common case first (both operands are arithmetic).
if (resType->isArithmeticType())
return new BinaryOperator(lex, rex, (BOP)code, resType);
else {
if ((BOP)code == BinaryOperator::Add) {
if ((lhsType->isPointerType() && rhsType->isIntegerType()) ||
(lhsType->isIntegerType() && rhsType->isPointerType()))
return new BinaryOperator(lex, rex, (BOP)code, resType);
} else { // -
if ((lhsType->isPointerType() && rhsType->isIntegerType()) ||
(lhsType->isPointerType() && rhsType->isPointerType()))
return new BinaryOperator(lex, rex, (BOP)code, resType);
}
}
return Diag(loc, diag::err_typecheck_invalid_operands);
return resType;
if ((lhsType->isPointerType() && rhsType->isIntegerType()) ||
(lhsType->isIntegerType() && rhsType->isPointerType()))
return resType;
Diag(loc, diag::err_typecheck_invalid_operands);
return QualType();
}
Action::ExprResult Sema::CheckShiftOperands( // C99 6.5.7
Expr *lex, Expr *rex, SourceLocation loc, unsigned code)
inline QualType Sema::CheckSubtractionOperands( // C99 6.5.6
Expr *lex, Expr *rex, SourceLocation loc)
{
QualType lhsType = lex->getType(), rhsType = rex->getType();
QualType resType = UsualArithmeticConversions(lhsType, rhsType);
// handle the common case first (both operands are arithmetic).
if (resType->isArithmeticType())
return resType;
if ((lhsType->isPointerType() && rhsType->isIntegerType()) ||
(lhsType->isPointerType() && rhsType->isPointerType()))
return resType;
Diag(loc, diag::err_typecheck_invalid_operands);
return QualType();
}
inline QualType Sema::CheckShiftOperands( // C99 6.5.7
Expr *lex, Expr *rex, SourceLocation loc)
{
QualType resType = UsualArithmeticConversions(lex->getType(), rex->getType());
if (!resType->isIntegerType())
return Diag(loc, diag::err_typecheck_invalid_operands);
return new BinaryOperator(lex, rex, (BOP)code, resType);
if (resType->isIntegerType())
return resType;
Diag(loc, diag::err_typecheck_invalid_operands);
return QualType();
}
Action::ExprResult Sema::CheckRelationalOperands( // C99 6.5.8
Expr *lex, Expr *rex, SourceLocation loc, unsigned code)
inline QualType Sema::CheckRelationalOperands( // C99 6.5.8
Expr *lex, Expr *rex, SourceLocation loc)
{
QualType lType = lex->getType(), rType = rex->getType();
if (lType->isRealType() && rType->isRealType())
return new BinaryOperator(lex, rex, (BOP)code, Context.IntTy);
return Context.IntTy;
if (lType->isPointerType() && rType->isPointerType())
return new BinaryOperator(lex, rex, (BOP)code, Context.IntTy);
return Context.IntTy;
if (lType->isIntegerType() || rType->isIntegerType()) // GCC extension.
return Diag(loc, diag::ext_typecheck_comparison_of_pointer_integer);
return Diag(loc, diag::err_typecheck_invalid_operands);
Diag(loc, diag::ext_typecheck_comparison_of_pointer_integer);
else
Diag(loc, diag::err_typecheck_invalid_operands);
return QualType();
}
Action::ExprResult Sema::CheckEqualityOperands( // C99 6.5.9
Expr *lex, Expr *rex, SourceLocation loc, unsigned code)
inline QualType Sema::CheckEqualityOperands( // C99 6.5.9
Expr *lex, Expr *rex, SourceLocation loc)
{
QualType lType = lex->getType(), rType = rex->getType();
if (lType->isArithmeticType() && rType->isArithmeticType())
return new BinaryOperator(lex, rex, (BOP)code, Context.IntTy);
return Context.IntTy;
if (lType->isPointerType() && rType->isPointerType())
return new BinaryOperator(lex, rex, (BOP)code, Context.IntTy);
return Context.IntTy;
if (lType->isIntegerType() || rType->isIntegerType()) // GCC extension.
return Diag(loc, diag::ext_typecheck_comparison_of_pointer_integer);
return Diag(loc, diag::err_typecheck_invalid_operands);
Diag(loc, diag::ext_typecheck_comparison_of_pointer_integer);
else
Diag(loc, diag::err_typecheck_invalid_operands);
return QualType();
}
Action::ExprResult Sema::CheckBitwiseOperands(
Expr *lex, Expr *rex, SourceLocation loc, unsigned code)
inline QualType Sema::CheckBitwiseOperands(
Expr *lex, Expr *rex, SourceLocation loc)
{
QualType resType = UsualArithmeticConversions(lex->getType(), rex->getType());
if (!resType->isIntegerType())
return Diag(loc, diag::err_typecheck_invalid_operands);
return new BinaryOperator(lex, rex, (BOP)code, resType);
if (resType->isIntegerType())
return resType;
Diag(loc, diag::err_typecheck_invalid_operands);
return QualType();
}
Action::ExprResult Sema::CheckLogicalOperands( // C99 6.5.[13,14]
Expr *lex, Expr *rex, SourceLocation loc, unsigned code)
inline QualType Sema::CheckLogicalOperands( // C99 6.5.[13,14]
Expr *lex, Expr *rex, SourceLocation loc)
{
QualType lhsType = UsualUnaryConversion(lex->getType());
QualType rhsType = UsualUnaryConversion(rex->getType());
if (!lhsType->isScalarType() || !rhsType->isScalarType())
return Diag(loc, diag::err_typecheck_invalid_operands);
return new BinaryOperator(lex, rex, (BOP)code, Context.IntTy);
if (lhsType->isScalarType() || rhsType->isScalarType())
return Context.IntTy;
Diag(loc, diag::err_typecheck_invalid_operands);
return QualType();
}
Action::ExprResult Sema::CheckAssignmentOperands(
Expr *lex, Expr *rex, SourceLocation loc, unsigned code)
inline QualType Sema::CheckSimpleAssignmentOperands( // C99 6.5.16.1
Expr *lex, Expr *rex, SourceLocation loc)
{
QualType lhsType = lex->getType();
QualType rhsType = rex->getType();
if ((BOP)code == BinaryOperator::Assign) { // C99 6.5.16.1
// FIXME: consider hacking isModifiableLvalue to return an enum that
// communicates why the expression/type wasn't a modifiableLvalue.
// this check is done first to give a more precise diagnostic.
if (lhsType.isConstQualified())
return Diag(loc, diag::err_typecheck_assign_const);
if (!lex->isModifiableLvalue()) // this includes checking for "const"
return Diag(loc, diag::ext_typecheck_assign_non_lvalue);
if (lhsType == rhsType) // common case, fast path...
return new BinaryOperator(lex, rex, (BOP)code, lhsType);
AssignmentConversionResult result;
QualType resType = UsualAssignmentConversions(lhsType, rex, result);
// decode the result (notice that AST's are still created for extensions).
switch (result) {
case Compatible:
break;
case PointerFromInt:
Diag(loc, diag::ext_typecheck_assign_pointer_from_int);
break;
case IntFromPointer:
Diag(loc, diag::ext_typecheck_assign_int_from_pointer);
break;
case IncompatiblePointer:
Diag(loc, diag::ext_typecheck_assign_incompatible_pointer);
break;
case Incompatible:
return Diag(loc, diag::err_typecheck_assign_incompatible);
}
return new BinaryOperator(lex, rex, (BOP)code, resType);
// FIXME: consider hacking isModifiableLvalue to return an enum that
// communicates why the expression/type wasn't a modifiableLvalue.
// this check is done first to give a more precise diagnostic.
if (lhsType.isConstQualified()) {
Diag(loc, diag::err_typecheck_assign_const);
return QualType();
}
// FIXME: type check compound assignments...
return new BinaryOperator(lex, rex, (BOP)code, Context.IntTy);
if (!lex->isModifiableLvalue()) { // this includes checking for "const"
Diag(loc, diag::ext_typecheck_assign_non_lvalue);
return QualType();
}
if (lhsType == rhsType) // common case, fast path...
return lhsType;
AssignmentConversionResult result;
QualType resType = UsualAssignmentConversions(lhsType, rhsType, result);
// decode the result (notice that extensions still return a type).
switch (result) {
case Compatible:
return resType;
case Incompatible:
Diag(loc, diag::err_typecheck_assign_incompatible);
return QualType();
case PointerFromInt:
// check for null pointer constant (C99 6.3.2.3p3)
if (!rex->isNullPointerConstant())
Diag(loc, diag::ext_typecheck_assign_pointer_from_int);
return resType;
case IntFromPointer:
Diag(loc, diag::ext_typecheck_assign_int_from_pointer);
return resType;
case IncompatiblePointer:
Diag(loc, diag::ext_typecheck_assign_incompatible_pointer);
return resType;
}
assert(0 && "should never get here");
}
Action::ExprResult Sema::CheckCommaOperands( // C99 6.5.17
inline QualType Sema::CheckCompoundAssignmentOperands( // C99 6.5.16.2
Expr *lex, QualType rhsType, SourceLocation loc)
{
QualType lhsType = lex->getType();
// FIXME: consider hacking isModifiableLvalue to return an enum that
// communicates why the expression/type wasn't a modifiableLvalue.
// this check is done first to give a more precise diagnostic.
if (lhsType.isConstQualified()) {
Diag(loc, diag::err_typecheck_assign_const);
return QualType();
}
if (!lex->isModifiableLvalue()) { // this includes checking for "const"
Diag(loc, diag::ext_typecheck_assign_non_lvalue);
return QualType();
}
if (lhsType == rhsType) // common case, fast path...
return lhsType;
AssignmentConversionResult result;
QualType resType = UsualAssignmentConversions(lhsType, rhsType, result);
// decode the result (notice that extensions still return a type).
switch (result) {
case Compatible:
return resType;
case Incompatible:
Diag(loc, diag::err_typecheck_assign_incompatible);
return QualType();
case PointerFromInt:
Diag(loc, diag::ext_typecheck_assign_pointer_from_int);
return resType;
case IntFromPointer:
Diag(loc, diag::ext_typecheck_assign_int_from_pointer);
return resType;
case IncompatiblePointer:
Diag(loc, diag::ext_typecheck_assign_incompatible_pointer);
return resType;
}
assert(0 && "should never get here");
}
inline QualType Sema::CheckCommaOperands( // C99 6.5.17
Expr *lex, Expr *rex, SourceLocation loc)
{
QualType rhsType = UsualUnaryConversion(rex->getType());
return new BinaryOperator(lex, rex, BinaryOperator::Comma, rhsType);
return UsualUnaryConversion(rex->getType());
}
Action::ExprResult
@ -886,3 +879,145 @@ Sema::CheckArithmeticOperand(Expr *op, SourceLocation OpLoc, unsigned Opc) {
}
return new UnaryOperator(op, (UOP)Opc, resultType);
}
static inline BinaryOperator::Opcode ConvertTokenKindToBinaryOpcode(
tok::TokenKind Kind) {
BinaryOperator::Opcode Opc;
switch (Kind) {
default: assert(0 && "Unknown binop!");
case tok::star: Opc = BinaryOperator::Mul; break;
case tok::slash: Opc = BinaryOperator::Div; break;
case tok::percent: Opc = BinaryOperator::Rem; break;
case tok::plus: Opc = BinaryOperator::Add; break;
case tok::minus: Opc = BinaryOperator::Sub; break;
case tok::lessless: Opc = BinaryOperator::Shl; break;
case tok::greatergreater: Opc = BinaryOperator::Shr; break;
case tok::lessequal: Opc = BinaryOperator::LE; break;
case tok::less: Opc = BinaryOperator::LT; break;
case tok::greaterequal: Opc = BinaryOperator::GE; break;
case tok::greater: Opc = BinaryOperator::GT; break;
case tok::exclaimequal: Opc = BinaryOperator::NE; break;
case tok::equalequal: Opc = BinaryOperator::EQ; break;
case tok::amp: Opc = BinaryOperator::And; break;
case tok::caret: Opc = BinaryOperator::Xor; break;
case tok::pipe: Opc = BinaryOperator::Or; break;
case tok::ampamp: Opc = BinaryOperator::LAnd; break;
case tok::pipepipe: Opc = BinaryOperator::LOr; break;
case tok::equal: Opc = BinaryOperator::Assign; break;
case tok::starequal: Opc = BinaryOperator::MulAssign; break;
case tok::slashequal: Opc = BinaryOperator::DivAssign; break;
case tok::percentequal: Opc = BinaryOperator::RemAssign; break;
case tok::plusequal: Opc = BinaryOperator::AddAssign; break;
case tok::minusequal: Opc = BinaryOperator::SubAssign; break;
case tok::lesslessequal: Opc = BinaryOperator::ShlAssign; break;
case tok::greatergreaterequal: Opc = BinaryOperator::ShrAssign; break;
case tok::ampequal: Opc = BinaryOperator::AndAssign; break;
case tok::caretequal: Opc = BinaryOperator::XorAssign; break;
case tok::pipeequal: Opc = BinaryOperator::OrAssign; break;
case tok::comma: Opc = BinaryOperator::Comma; break;
}
return Opc;
}
// Binary Operators. 'Tok' is the token for the operator.
Action::ExprResult Sema::ParseBinOp(SourceLocation TokLoc, tok::TokenKind Kind,
ExprTy *LHS, ExprTy *RHS) {
BinaryOperator::Opcode Opc = ConvertTokenKindToBinaryOpcode(Kind);
Expr *lhs = (Expr *)LHS, *rhs = (Expr*)RHS;
assert((lhs != 0) && "ParseBinOp(): missing left expression");
assert((rhs != 0) && "ParseBinOp(): missing right expression");
QualType result;
switch (Opc) {
default:
assert(0 && "Unknown binary expr!");
case BinaryOperator::Assign:
result = CheckSimpleAssignmentOperands(lhs, rhs, TokLoc);
break;
case BinaryOperator::Mul:
case BinaryOperator::Div:
result = CheckMultiplyDivideOperands(lhs, rhs, TokLoc);
break;
case BinaryOperator::Rem:
result = CheckRemainderOperands(lhs, rhs, TokLoc);
break;
case BinaryOperator::Add:
result = CheckAdditionOperands(lhs, rhs, TokLoc);
break;
case BinaryOperator::Sub:
result = CheckSubtractionOperands(lhs, rhs, TokLoc);
break;
case BinaryOperator::Shl:
case BinaryOperator::Shr:
result = CheckShiftOperands(lhs, rhs, TokLoc);
break;
case BinaryOperator::LE:
case BinaryOperator::LT:
case BinaryOperator::GE:
case BinaryOperator::GT:
result = CheckRelationalOperands(lhs, rhs, TokLoc);
break;
case BinaryOperator::EQ:
case BinaryOperator::NE:
result = CheckEqualityOperands(lhs, rhs, TokLoc);
break;
case BinaryOperator::And:
case BinaryOperator::Xor:
case BinaryOperator::Or:
result = CheckBitwiseOperands(lhs, rhs, TokLoc);
break;
case BinaryOperator::LAnd:
case BinaryOperator::LOr:
result = CheckLogicalOperands(lhs, rhs, TokLoc);
break;
case BinaryOperator::MulAssign:
case BinaryOperator::DivAssign:
result = CheckMultiplyDivideOperands(lhs, rhs, TokLoc);
if (result.isNull())
return true;
result = CheckCompoundAssignmentOperands(lhs, result, TokLoc);
break;
case BinaryOperator::RemAssign:
result = CheckRemainderOperands(lhs, rhs, TokLoc);
if (result.isNull())
return true;
result = CheckCompoundAssignmentOperands(lhs, result, TokLoc);
break;
case BinaryOperator::AddAssign:
result = CheckAdditionOperands(lhs, rhs, TokLoc);
if (result.isNull())
return true;
result = CheckCompoundAssignmentOperands(lhs, result, TokLoc);
break;
case BinaryOperator::SubAssign:
result = CheckSubtractionOperands(lhs, rhs, TokLoc);
if (result.isNull())
return true;
result = CheckCompoundAssignmentOperands(lhs, result, TokLoc);
break;
case BinaryOperator::ShlAssign:
case BinaryOperator::ShrAssign:
result = CheckShiftOperands(lhs, rhs, TokLoc);
if (result.isNull())
return true;
result = CheckCompoundAssignmentOperands(lhs, result, TokLoc);
break;
case BinaryOperator::AndAssign:
case BinaryOperator::XorAssign:
case BinaryOperator::OrAssign:
result = CheckBitwiseOperands(lhs, rhs, TokLoc);
if (result.isNull())
return true;
result = CheckCompoundAssignmentOperands(lhs, result, TokLoc);
break;
case BinaryOperator::Comma:
result = CheckCommaOperands(lhs, rhs, TokLoc);
break;
}
if (result.isNull())
return true;
return new BinaryOperator(lhs, rhs, Opc, result);
}

View File

@ -46,6 +46,8 @@ public:
///
bool isModifiableLvalue();
bool isNullPointerConstant() const;
virtual void visit(StmtVisitor &Visitor);
static bool classof(const Stmt *T) {
return T->getStmtClass() >= firstExprConstant &&
@ -365,9 +367,9 @@ public:
static bool isMultiplicativeOp(Opcode Op) { return Op >= Mul && Op <= Rem; }
static bool isAdditiveOp(Opcode Op) { return Op == Add || Op == Sub; }
static bool isShiftOp(Opcode Op) { return Op == Shl || Op == Shr; }
static bool isBitwiseOp(Opcode Op) { return Op >= And && Op <= Or; }
static bool isRelationalOp(Opcode Op) { return Op >= LT && Op <= GE; }
static bool isEqualityOp(Opcode Op) { return Op == EQ || Op == NE; }
static bool isBitwiseOp(Opcode Op) { return Op >= And && Op <= Or; }
static bool isLogicalOp(Opcode Op) { return Op == LAnd || Op == LOr; }
static bool isAssignmentOp(Opcode Op) { return Op >= Assign && Op<=OrAssign; }