Submitted by:
Reviewed by:
- Unified isConstantExpr/isIntegerConstantExpr by creating a private function
named isConstantExpr (that takes a bool to indicate the flavor). isConstantExpr
and isIntegerConstantExpr are now inline wrapper/helper functions.
- Fixed bug in expression based sizeof (it needed to make sure the type is constant).
- Added Sema::CheckConditionalOperands() stub. Will add contraints in my next commit.

llvm-svn: 39446
This commit is contained in:
Steve Naroff 2007-05-15 20:29:32 +00:00
parent 043d45da72
commit f8a28c5379
6 changed files with 69 additions and 90 deletions

View File

@ -175,13 +175,26 @@ bool Expr::isModifiableLvalue() {
return true;
}
bool Expr::isConstantExpr() const {
/// isConstantExpr - this recursive routine will test if an expression is
/// either a constant expression (isIntConst == false) or an integer constant
/// expression (isIntConst == true). Note: With the introduction of VLA's in
/// C99 the result of the sizeof operator is no longer always a constant
/// expression. The generalization of the wording to include any subexpression
/// that is not evaluated (C99 6.6p3) means that nonconstant subexpressions
/// can appear as operands to other operators (e.g. &&, ||, ?:). For instance,
/// "0 || f()" can be treated as a constant expression. In C90 this expression,
/// occurring in a context requiring a constant, would have been a constraint
/// violation. FIXME: This routine currently implements C90 semantics.
/// To properly implement C99 semantics this routine will need to evaluate
/// expressions involving operators previously mentioned.
bool Expr::isConstantExpr(bool isIntConst) const {
switch (getStmtClass()) {
case IntegerLiteralClass:
case FloatingLiteralClass:
case CharacterLiteralClass:
case StringLiteralClass:
return true;
case FloatingLiteralClass:
case StringLiteralClass:
return isIntConst ? false : true;
case DeclRefExprClass:
return isa<EnumConstantDecl>(cast<DeclRefExpr>(this)->getDecl());
case UnaryOperatorClass:
@ -192,8 +205,8 @@ bool Expr::isConstantExpr() const {
// is an integer constant. This effective ignores any subexpression that
// isn't actually a constant expression (what an odd language:-)
if (uop->isSizeOfAlignOfOp())
return true;
return uop->getSubExpr()->isConstantExpr();
return uop->getSubExpr()->getType()->isConstantSizeType();
return uop->getSubExpr()->isConstantExpr(isIntConst);
case BinaryOperatorClass:
const BinaryOperator *bop = cast<BinaryOperator>(this);
// C99 6.6p3: shall not contain assignment, increment/decrement,
@ -201,7 +214,8 @@ bool Expr::isConstantExpr() const {
// within a subexpression that is not evaluated.
if (bop->isAssignmentOp() || bop->getOpcode() == BinaryOperator::Comma)
return false;
return bop->getLHS()->isConstantExpr() && bop->getRHS()->isConstantExpr();
return bop->getLHS()->isConstantExpr(isIntConst) &&
bop->getRHS()->isConstantExpr(isIntConst);
case ParenExprClass:
return cast<ParenExpr>(this)->getSubExpr()->isConstantExpr();
case CastExprClass:
@ -222,73 +236,10 @@ bool Expr::isConstantExpr() const {
return sizeExpr->getArgumentType()->isConstantSizeType();
return true; // alignof will always evaluate to a constant
case ConditionalOperatorClass:
// GCC currently ignores any subexpression that isn't evaluated.
// GCC currently considers the following legal: "1 ? 7 : printf("xx")"
// EDG still flags this as an error (which is great, since this predicate
// can do it's job *without* evaluating the expression).
const ConditionalOperator *condExpr = cast<ConditionalOperator>(this);
return condExpr->getCond()->isConstantExpr() &&
condExpr->getLHS()->isConstantExpr() &&
condExpr->getRHS()->isConstantExpr();
default:
return false;
}
}
bool Expr::isIntegerConstantExpr() const {
switch (getStmtClass()) {
case IntegerLiteralClass:
case CharacterLiteralClass:
return true;
case DeclRefExprClass:
return isa<EnumConstantDecl>(cast<DeclRefExpr>(this)->getDecl());
case UnaryOperatorClass:
const UnaryOperator *uop = cast<UnaryOperator>(this);
if (uop->isIncrementDecrementOp()) // C99 6.6p3
return false;
// C99 6.5.3.4p2: otherwise, the operand is *not* evaluated and the result
// is an integer constant. This effective ignores any subexpression that
// isn't actually a constant expression (what an odd language:-)
if (uop->isSizeOfAlignOfOp())
return true;
return uop->getSubExpr()->isIntegerConstantExpr();
case BinaryOperatorClass:
const BinaryOperator *bop = cast<BinaryOperator>(this);
// C99 6.6p3: shall not contain assignment, increment/decrement,
// function call, or comma operators, *except* when they are contained
// within a subexpression that is not evaluated.
if (bop->isAssignmentOp() || bop->getOpcode() == BinaryOperator::Comma)
return false;
return bop->getLHS()->isIntegerConstantExpr() &&
bop->getRHS()->isIntegerConstantExpr();
case ParenExprClass:
return cast<ParenExpr>(this)->getSubExpr()->isIntegerConstantExpr();
case CastExprClass:
const CastExpr *castExpr = cast<CastExpr>(this);
// C99 6.6p6: shall only convert arithmetic types to integer types.
if (!castExpr->getSubExpr()->getType()->isArithmeticType())
return false;
if (!castExpr->getDestType()->isIntegerType())
return false;
// allow floating constants that are the immediate operands of casts.
if (castExpr->getSubExpr()->isIntegerConstantExpr() ||
isa<FloatingLiteral>(castExpr->getSubExpr()))
return true;
return false;
case SizeOfAlignOfTypeExprClass:
const SizeOfAlignOfTypeExpr *sizeExpr = cast<SizeOfAlignOfTypeExpr>(this);
if (sizeExpr->isSizeOf())
return sizeExpr->getArgumentType()->isConstantSizeType();
return true; // alignof will always evaluate to a constant
case ConditionalOperatorClass:
// GCC currently ignores any subexpression that isn't evaluated.
// GCC currently considers the following legal: "1 ? 7 : printf("xx")"
// EDG still flags this as an error (which is great, since this predicate
// can do it's job *without* evaluating the expression).
const ConditionalOperator *condExpr = cast<ConditionalOperator>(this);
return condExpr->getCond()->isIntegerConstantExpr() &&
condExpr->getLHS()->isIntegerConstantExpr() &&
condExpr->getRHS()->isIntegerConstantExpr();
return condExpr->getCond()->isConstantExpr(isIntConst) &&
condExpr->getLHS()->isConstantExpr(isIntConst) &&
condExpr->getRHS()->isConstantExpr(isIntConst);
default:
return false;
}

View File

@ -274,6 +274,8 @@ private:
Expr *lex, Expr *rex, SourceLocation OpLoc, QualType convertedType);
inline QualType CheckCommaOperands( // C99 6.5.17
Expr *lex, Expr *rex, SourceLocation OpLoc);
inline QualType CheckConditionalOperands( // C99 6.5.15
Expr *cond, Expr *lhs, Expr *rhs, SourceLocation questionLoc);
/// type checking unary operators (subroutines of ParseUnaryOp).
QualType CheckIncrementDecrementOperand( // C99 6.5.3.1

View File

@ -384,20 +384,31 @@ ParseCastExpr(SourceLocation LParenLoc, TypeTy *Ty,
return new CastExpr(QualType::getFromOpaquePtr(Ty), (Expr*)Op);
}
inline QualType Sema::CheckConditionalOperands( // C99 6.5.15
Expr *Cond, Expr *LHS, Expr *RHS, SourceLocation questionLoc) {
QualType cond = Cond->getType().getCanonicalType();
QualType lhs = LHS->getType().getCanonicalType();
QualType rhs = RHS->getType().getCanonicalType();
assert(!cond.isNull() && "ParseConditionalOp(): no conditional type");
assert(!lhs.isNull() && "ParseConditionalOp(): no lhs type");
assert(!rhs.isNull() && "ParseConditionalOp(): no rhs type");
// C99 6.5.15p2,3
return rhs;
}
/// 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,
SourceLocation ColonLoc,
ExprTy *Cond, ExprTy *LHS,
ExprTy *RHS) {
QualType lhs = ((Expr *)LHS)->getType();
QualType rhs = ((Expr *)RHS)->getType();
assert(!lhs.isNull() && "ParseConditionalOp(): no lhs type");
assert(!rhs.isNull() && "ParseConditionalOp(): no rhs type");
QualType canonType = rhs.getCanonicalType(); // FIXME
return new ConditionalOperator((Expr*)Cond, (Expr*)LHS, (Expr*)RHS, canonType);
QualType result = CheckConditionalOperands((Expr *)Cond, (Expr *)LHS,
(Expr *)RHS, QuestionLoc);
if (result.isNull())
return true;
return new ConditionalOperator((Expr*)Cond, (Expr*)LHS, (Expr*)RHS, result);
}
/// UsualUnaryConversion - Performs various conversions that are common to most

View File

@ -274,6 +274,8 @@ private:
Expr *lex, Expr *rex, SourceLocation OpLoc, QualType convertedType);
inline QualType CheckCommaOperands( // C99 6.5.17
Expr *lex, Expr *rex, SourceLocation OpLoc);
inline QualType CheckConditionalOperands( // C99 6.5.15
Expr *cond, Expr *lhs, Expr *rhs, SourceLocation questionLoc);
/// type checking unary operators (subroutines of ParseUnaryOp).
QualType CheckIncrementDecrementOperand( // C99 6.5.3.1

View File

@ -384,20 +384,31 @@ ParseCastExpr(SourceLocation LParenLoc, TypeTy *Ty,
return new CastExpr(QualType::getFromOpaquePtr(Ty), (Expr*)Op);
}
inline QualType Sema::CheckConditionalOperands( // C99 6.5.15
Expr *Cond, Expr *LHS, Expr *RHS, SourceLocation questionLoc) {
QualType cond = Cond->getType().getCanonicalType();
QualType lhs = LHS->getType().getCanonicalType();
QualType rhs = RHS->getType().getCanonicalType();
assert(!cond.isNull() && "ParseConditionalOp(): no conditional type");
assert(!lhs.isNull() && "ParseConditionalOp(): no lhs type");
assert(!rhs.isNull() && "ParseConditionalOp(): no rhs type");
// C99 6.5.15p2,3
return rhs;
}
/// 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,
SourceLocation ColonLoc,
ExprTy *Cond, ExprTy *LHS,
ExprTy *RHS) {
QualType lhs = ((Expr *)LHS)->getType();
QualType rhs = ((Expr *)RHS)->getType();
assert(!lhs.isNull() && "ParseConditionalOp(): no lhs type");
assert(!rhs.isNull() && "ParseConditionalOp(): no rhs type");
QualType canonType = rhs.getCanonicalType(); // FIXME
return new ConditionalOperator((Expr*)Cond, (Expr*)LHS, (Expr*)RHS, canonType);
QualType result = CheckConditionalOperands((Expr *)Cond, (Expr *)LHS,
(Expr *)RHS, QuestionLoc);
if (result.isNull())
return true;
return new ConditionalOperator((Expr*)Cond, (Expr*)LHS, (Expr*)RHS, result);
}
/// UsualUnaryConversion - Performs various conversions that are common to most

View File

@ -56,8 +56,8 @@ public:
bool isNullPointerConstant() const;
bool isConstantExpr() const;
bool isIntegerConstantExpr() const;
bool isConstantExpr() const { return isConstantExpr(false); }
bool isIntegerConstantExpr() const { return isConstantExpr(true); }
virtual void visit(StmtVisitor &Visitor);
static bool classof(const Stmt *T) {
@ -65,6 +65,8 @@ public:
T->getStmtClass() <= lastExprConstant;
}
static bool classof(const Expr *) { return true; }
private:
bool isConstantExpr(bool isIntegerConstant) const;
};
//===----------------------------------------------------------------------===//