[cfe-commits] r39433 - in /cfe/cfe/trunk: AST/Expr.cpp AST/Sema.h AST/SemaExpr.cpp Sema/Sema.h Sema/SemaExpr.cpp include/clang/AST/Expr.h
Steve Naroff
snaroff at apple.com
Wed Jul 11 09:44:20 PDT 2007
Author: snaroff
Date: Wed Jul 11 11:44:20 2007
New Revision: 39433
URL: http://llvm.org/viewvc/llvm-project?rev=39433&view=rev
Log:
Bug #:
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).
Modified:
cfe/cfe/trunk/AST/Expr.cpp
cfe/cfe/trunk/AST/Sema.h
cfe/cfe/trunk/AST/SemaExpr.cpp
cfe/cfe/trunk/Sema/Sema.h
cfe/cfe/trunk/Sema/SemaExpr.cpp
cfe/cfe/trunk/include/clang/AST/Expr.h
Modified: cfe/cfe/trunk/AST/Expr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/AST/Expr.cpp?rev=39433&r1=39432&r2=39433&view=diff
==============================================================================
--- cfe/cfe/trunk/AST/Expr.cpp (original)
+++ cfe/cfe/trunk/AST/Expr.cpp Wed Jul 11 11:44:20 2007
@@ -153,3 +153,10 @@
return false;
}
}
+
+bool Expr::isNullPointerConstant() const {
+ const IntegerLiteral *constant = dyn_cast<IntegerLiteral>(this);
+ if (!constant || constant->getValue() != 0)
+ return false;
+ return true;
+}
Modified: cfe/cfe/trunk/AST/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/AST/Sema.h?rev=39433&r1=39432&r2=39433&view=diff
==============================================================================
--- cfe/cfe/trunk/AST/Sema.h (original)
+++ cfe/cfe/trunk/AST/Sema.h Wed Jul 11 11:44:20 2007
@@ -233,32 +233,39 @@
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).
Modified: cfe/cfe/trunk/AST/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/AST/SemaExpr.cpp?rev=39433&r1=39432&r2=39433&view=diff
==============================================================================
--- cfe/cfe/trunk/AST/SemaExpr.cpp (original)
+++ cfe/cfe/trunk/AST/SemaExpr.cpp Wed Jul 11 11:44:20 2007
@@ -365,7 +365,7 @@
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 @@
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 @@
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 @@
/// 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 @@
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 @@
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 resType = UsualArithmeticConversions(lex->getType(), rex->getType());
+ QualType lhsType = lex->getType(), rhsType = rex->getType();
+ QualType resType = UsualArithmeticConversions(lhsType, rhsType);
- if (!resType->isIntegerType())
- return Diag(loc, diag::err_typecheck_invalid_operands);
+ // 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();
+}
- return new BinaryOperator(lex, rex, (BOP)code, resType);
+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 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);
+ // 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 AST's are still created for extensions).
- switch (result) {
- case Compatible:
- break;
- case PointerFromInt:
+ // 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);
- 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);
+ 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;
}
- // FIXME: type check compound assignments...
- return new BinaryOperator(lex, rex, (BOP)code, Context.IntTy);
+ 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 @@
}
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);
+}
+
Modified: cfe/cfe/trunk/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/Sema/Sema.h?rev=39433&r1=39432&r2=39433&view=diff
==============================================================================
--- cfe/cfe/trunk/Sema/Sema.h (original)
+++ cfe/cfe/trunk/Sema/Sema.h Wed Jul 11 11:44:20 2007
@@ -233,32 +233,39 @@
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).
Modified: cfe/cfe/trunk/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/Sema/SemaExpr.cpp?rev=39433&r1=39432&r2=39433&view=diff
==============================================================================
--- cfe/cfe/trunk/Sema/SemaExpr.cpp (original)
+++ cfe/cfe/trunk/Sema/SemaExpr.cpp Wed Jul 11 11:44:20 2007
@@ -365,7 +365,7 @@
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 @@
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 @@
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 @@
/// 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 @@
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 @@
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 resType = UsualArithmeticConversions(lex->getType(), rex->getType());
+ QualType lhsType = lex->getType(), rhsType = rex->getType();
+ QualType resType = UsualArithmeticConversions(lhsType, rhsType);
- if (!resType->isIntegerType())
- return Diag(loc, diag::err_typecheck_invalid_operands);
+ // 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();
+}
- return new BinaryOperator(lex, rex, (BOP)code, resType);
+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 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);
+ // 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 AST's are still created for extensions).
- switch (result) {
- case Compatible:
- break;
- case PointerFromInt:
+ // 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);
- 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);
+ 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;
}
- // FIXME: type check compound assignments...
- return new BinaryOperator(lex, rex, (BOP)code, Context.IntTy);
+ 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 @@
}
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);
+}
+
Modified: cfe/cfe/trunk/include/clang/AST/Expr.h
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/include/clang/AST/Expr.h?rev=39433&r1=39432&r2=39433&view=diff
==============================================================================
--- cfe/cfe/trunk/include/clang/AST/Expr.h (original)
+++ cfe/cfe/trunk/include/clang/AST/Expr.h Wed Jul 11 11:44:20 2007
@@ -46,6 +46,8 @@
///
bool isModifiableLvalue();
+ bool isNullPointerConstant() const;
+
virtual void visit(StmtVisitor &Visitor);
static bool classof(const Stmt *T) {
return T->getStmtClass() >= firstExprConstant &&
@@ -365,9 +367,9 @@
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; }
More information about the cfe-commits
mailing list