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;
|
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()) {
|
switch (getStmtClass()) {
|
||||||
case IntegerLiteralClass:
|
case IntegerLiteralClass:
|
||||||
case FloatingLiteralClass:
|
|
||||||
case CharacterLiteralClass:
|
case CharacterLiteralClass:
|
||||||
case StringLiteralClass:
|
|
||||||
return true;
|
return true;
|
||||||
|
case FloatingLiteralClass:
|
||||||
|
case StringLiteralClass:
|
||||||
|
return isIntConst ? false : true;
|
||||||
case DeclRefExprClass:
|
case DeclRefExprClass:
|
||||||
return isa<EnumConstantDecl>(cast<DeclRefExpr>(this)->getDecl());
|
return isa<EnumConstantDecl>(cast<DeclRefExpr>(this)->getDecl());
|
||||||
case UnaryOperatorClass:
|
case UnaryOperatorClass:
|
||||||
|
@ -192,8 +205,8 @@ bool Expr::isConstantExpr() const {
|
||||||
// is an integer constant. This effective ignores any subexpression that
|
// is an integer constant. This effective ignores any subexpression that
|
||||||
// isn't actually a constant expression (what an odd language:-)
|
// isn't actually a constant expression (what an odd language:-)
|
||||||
if (uop->isSizeOfAlignOfOp())
|
if (uop->isSizeOfAlignOfOp())
|
||||||
return true;
|
return uop->getSubExpr()->getType()->isConstantSizeType();
|
||||||
return uop->getSubExpr()->isConstantExpr();
|
return uop->getSubExpr()->isConstantExpr(isIntConst);
|
||||||
case BinaryOperatorClass:
|
case BinaryOperatorClass:
|
||||||
const BinaryOperator *bop = cast<BinaryOperator>(this);
|
const BinaryOperator *bop = cast<BinaryOperator>(this);
|
||||||
// C99 6.6p3: shall not contain assignment, increment/decrement,
|
// C99 6.6p3: shall not contain assignment, increment/decrement,
|
||||||
|
@ -201,7 +214,8 @@ bool Expr::isConstantExpr() const {
|
||||||
// within a subexpression that is not evaluated.
|
// within a subexpression that is not evaluated.
|
||||||
if (bop->isAssignmentOp() || bop->getOpcode() == BinaryOperator::Comma)
|
if (bop->isAssignmentOp() || bop->getOpcode() == BinaryOperator::Comma)
|
||||||
return false;
|
return false;
|
||||||
return bop->getLHS()->isConstantExpr() && bop->getRHS()->isConstantExpr();
|
return bop->getLHS()->isConstantExpr(isIntConst) &&
|
||||||
|
bop->getRHS()->isConstantExpr(isIntConst);
|
||||||
case ParenExprClass:
|
case ParenExprClass:
|
||||||
return cast<ParenExpr>(this)->getSubExpr()->isConstantExpr();
|
return cast<ParenExpr>(this)->getSubExpr()->isConstantExpr();
|
||||||
case CastExprClass:
|
case CastExprClass:
|
||||||
|
@ -222,73 +236,10 @@ bool Expr::isConstantExpr() const {
|
||||||
return sizeExpr->getArgumentType()->isConstantSizeType();
|
return sizeExpr->getArgumentType()->isConstantSizeType();
|
||||||
return true; // alignof will always evaluate to a constant
|
return true; // alignof will always evaluate to a constant
|
||||||
case ConditionalOperatorClass:
|
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);
|
const ConditionalOperator *condExpr = cast<ConditionalOperator>(this);
|
||||||
return condExpr->getCond()->isConstantExpr() &&
|
return condExpr->getCond()->isConstantExpr(isIntConst) &&
|
||||||
condExpr->getLHS()->isConstantExpr() &&
|
condExpr->getLHS()->isConstantExpr(isIntConst) &&
|
||||||
condExpr->getRHS()->isConstantExpr();
|
condExpr->getRHS()->isConstantExpr(isIntConst);
|
||||||
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();
|
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -274,6 +274,8 @@ private:
|
||||||
Expr *lex, Expr *rex, SourceLocation OpLoc, QualType convertedType);
|
Expr *lex, Expr *rex, SourceLocation OpLoc, QualType convertedType);
|
||||||
inline QualType CheckCommaOperands( // C99 6.5.17
|
inline QualType CheckCommaOperands( // C99 6.5.17
|
||||||
Expr *lex, Expr *rex, SourceLocation OpLoc);
|
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).
|
/// type checking unary operators (subroutines of ParseUnaryOp).
|
||||||
QualType CheckIncrementDecrementOperand( // C99 6.5.3.1
|
QualType CheckIncrementDecrementOperand( // C99 6.5.3.1
|
||||||
|
|
|
@ -384,20 +384,31 @@ ParseCastExpr(SourceLocation LParenLoc, TypeTy *Ty,
|
||||||
return new CastExpr(QualType::getFromOpaquePtr(Ty), (Expr*)Op);
|
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
|
/// ParseConditionalOp - Parse a ?: operation. Note that 'LHS' may be null
|
||||||
/// in the case of a the GNU conditional expr extension.
|
/// in the case of a the GNU conditional expr extension.
|
||||||
Action::ExprResult Sema::ParseConditionalOp(SourceLocation QuestionLoc,
|
Action::ExprResult Sema::ParseConditionalOp(SourceLocation QuestionLoc,
|
||||||
SourceLocation ColonLoc,
|
SourceLocation ColonLoc,
|
||||||
ExprTy *Cond, ExprTy *LHS,
|
ExprTy *Cond, ExprTy *LHS,
|
||||||
ExprTy *RHS) {
|
ExprTy *RHS) {
|
||||||
QualType lhs = ((Expr *)LHS)->getType();
|
QualType result = CheckConditionalOperands((Expr *)Cond, (Expr *)LHS,
|
||||||
QualType rhs = ((Expr *)RHS)->getType();
|
(Expr *)RHS, QuestionLoc);
|
||||||
|
if (result.isNull())
|
||||||
assert(!lhs.isNull() && "ParseConditionalOp(): no lhs type");
|
return true;
|
||||||
assert(!rhs.isNull() && "ParseConditionalOp(): no rhs type");
|
return new ConditionalOperator((Expr*)Cond, (Expr*)LHS, (Expr*)RHS, result);
|
||||||
|
|
||||||
QualType canonType = rhs.getCanonicalType(); // FIXME
|
|
||||||
return new ConditionalOperator((Expr*)Cond, (Expr*)LHS, (Expr*)RHS, canonType);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// UsualUnaryConversion - Performs various conversions that are common to most
|
/// UsualUnaryConversion - Performs various conversions that are common to most
|
||||||
|
|
|
@ -274,6 +274,8 @@ private:
|
||||||
Expr *lex, Expr *rex, SourceLocation OpLoc, QualType convertedType);
|
Expr *lex, Expr *rex, SourceLocation OpLoc, QualType convertedType);
|
||||||
inline QualType CheckCommaOperands( // C99 6.5.17
|
inline QualType CheckCommaOperands( // C99 6.5.17
|
||||||
Expr *lex, Expr *rex, SourceLocation OpLoc);
|
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).
|
/// type checking unary operators (subroutines of ParseUnaryOp).
|
||||||
QualType CheckIncrementDecrementOperand( // C99 6.5.3.1
|
QualType CheckIncrementDecrementOperand( // C99 6.5.3.1
|
||||||
|
|
|
@ -384,20 +384,31 @@ ParseCastExpr(SourceLocation LParenLoc, TypeTy *Ty,
|
||||||
return new CastExpr(QualType::getFromOpaquePtr(Ty), (Expr*)Op);
|
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
|
/// ParseConditionalOp - Parse a ?: operation. Note that 'LHS' may be null
|
||||||
/// in the case of a the GNU conditional expr extension.
|
/// in the case of a the GNU conditional expr extension.
|
||||||
Action::ExprResult Sema::ParseConditionalOp(SourceLocation QuestionLoc,
|
Action::ExprResult Sema::ParseConditionalOp(SourceLocation QuestionLoc,
|
||||||
SourceLocation ColonLoc,
|
SourceLocation ColonLoc,
|
||||||
ExprTy *Cond, ExprTy *LHS,
|
ExprTy *Cond, ExprTy *LHS,
|
||||||
ExprTy *RHS) {
|
ExprTy *RHS) {
|
||||||
QualType lhs = ((Expr *)LHS)->getType();
|
QualType result = CheckConditionalOperands((Expr *)Cond, (Expr *)LHS,
|
||||||
QualType rhs = ((Expr *)RHS)->getType();
|
(Expr *)RHS, QuestionLoc);
|
||||||
|
if (result.isNull())
|
||||||
assert(!lhs.isNull() && "ParseConditionalOp(): no lhs type");
|
return true;
|
||||||
assert(!rhs.isNull() && "ParseConditionalOp(): no rhs type");
|
return new ConditionalOperator((Expr*)Cond, (Expr*)LHS, (Expr*)RHS, result);
|
||||||
|
|
||||||
QualType canonType = rhs.getCanonicalType(); // FIXME
|
|
||||||
return new ConditionalOperator((Expr*)Cond, (Expr*)LHS, (Expr*)RHS, canonType);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// UsualUnaryConversion - Performs various conversions that are common to most
|
/// UsualUnaryConversion - Performs various conversions that are common to most
|
||||||
|
|
|
@ -56,8 +56,8 @@ public:
|
||||||
|
|
||||||
bool isNullPointerConstant() const;
|
bool isNullPointerConstant() const;
|
||||||
|
|
||||||
bool isConstantExpr() const;
|
bool isConstantExpr() const { return isConstantExpr(false); }
|
||||||
bool isIntegerConstantExpr() const;
|
bool isIntegerConstantExpr() const { return isConstantExpr(true); }
|
||||||
|
|
||||||
virtual void visit(StmtVisitor &Visitor);
|
virtual void visit(StmtVisitor &Visitor);
|
||||||
static bool classof(const Stmt *T) {
|
static bool classof(const Stmt *T) {
|
||||||
|
@ -65,6 +65,8 @@ public:
|
||||||
T->getStmtClass() <= lastExprConstant;
|
T->getStmtClass() <= lastExprConstant;
|
||||||
}
|
}
|
||||||
static bool classof(const Expr *) { return true; }
|
static bool classof(const Expr *) { return true; }
|
||||||
|
private:
|
||||||
|
bool isConstantExpr(bool isIntegerConstant) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
Loading…
Reference in New Issue