Bug #:
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:
parent
043d45da72
commit
f8a28c5379
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
|
Loading…
Reference in New Issue