Index: lib/AST/Expr.cpp =================================================================== --- lib/AST/Expr.cpp (revision 52091) +++ lib/AST/Expr.cpp (working copy) @@ -659,6 +659,451 @@ } } +bool Expr::TryEvaluateExprFloat(llvm::APFloat& Result, ASTContext &Ctx) const { + // FIXME: Implement! + return false; +} + +bool Expr::TryEvaluateExprComplex(llvm::APFloat& RealResult, + llvm::APFloat& ImagResult, + ASTContext &Ctx) const { + // FIXME: Implement! + return false; +} + +bool Expr::TryEvaluateExprLValueAddress(const Expr*& ResultBase, + llvm::APInt& ResultOffset, + ASTContext &Ctx) const { + // FIXME: Implement! + return false; +} + +bool Expr::TryEvaluateExprPointer(const Expr*& ResultBase, + llvm::APInt& ResultOffset, + ASTContext &Ctx) const { + if (!getType()->isPointerType()) + return false; + + switch (getStmtClass()) { + default: + return false; + case ParenExprClass: { + const ParenExpr* PE = cast(this); + return PE->getSubExpr()->TryEvaluateExprPointer(ResultBase, ResultOffset, Ctx); + } + case Expr::StringLiteralClass: + case Expr::ObjCStringLiteralClass: + return false; + case Expr::CallExprClass: { + const CallExpr *CE = cast(this); + if (CE->isBuiltinConstantExpr()) { + ResultBase = this; + ResultOffset.zextOrTrunc(static_cast(Ctx.getTypeSize(getType()))); + ResultOffset = 0; + return true; + } + return false; + } + case Expr::UnaryOperatorClass: { + const UnaryOperator *Exp = cast(this); + + if (Exp->getOpcode() == UnaryOperator::AddrOf) + return Exp->getSubExpr()->TryEvaluateExprLValueAddress(ResultBase, ResultOffset, Ctx); + + if (Exp->getOpcode() == UnaryOperator::Extension) + return Exp->getSubExpr()->TryEvaluateExprPointer(ResultBase, ResultOffset, Ctx); + + return false; + } + case Expr::BinaryOperatorClass: { + const BinaryOperator *Exp = cast(this); + + if (Exp->getOpcode() != BinaryOperator::Add && + Exp->getOpcode() != BinaryOperator::Sub) + return false; + + Expr *PExp = Exp->getLHS(); + Expr *IExp = Exp->getRHS(); + if (IExp->getType()->isPointerType()) + std::swap(PExp, IExp); + + llvm::APSInt AdditionalOffset(32); + if (!PExp->TryEvaluateExprPointer(ResultBase, ResultOffset, Ctx) || + !IExp->TryEvaluateExprInt(AdditionalOffset, Ctx)) + return false; + + AdditionalOffset.extOrTrunc(ResultOffset.getBitWidth()); + if (Exp->getOpcode() == BinaryOperator::Add) + ResultOffset += AdditionalOffset; + else + ResultOffset -= AdditionalOffset; + return true; + } + case Expr::ImplicitCastExprClass: { + const Expr* SubExpr = cast(this)->getSubExpr(); + + // Check for implicit promotion + if (SubExpr->getType()->isFunctionType() || + SubExpr->getType()->isArrayType()) + return SubExpr->TryEvaluateExprLValueAddress(ResultBase, ResultOffset, Ctx); + + // Check for pointer->pointer cast + if (SubExpr->getType()->isPointerType()) + return SubExpr->TryEvaluateExprPointer(ResultBase, ResultOffset, Ctx); + + if (SubExpr->getType()->isArithmeticType()) { + llvm::APSInt Offset(32); + if (SubExpr->TryEvaluateExprInt(Offset, Ctx)) { + Offset.extOrTrunc(static_cast(Ctx.getTypeSize(getType()))); + ResultBase = 0; + ResultOffset = Offset; + return true; + } + } + + return false; + } + case Expr::CastExprClass: { + const Expr* SubExpr = cast(this)->getSubExpr(); + + // Check for pointer->pointer cast + if (SubExpr->getType()->isPointerType()) + return SubExpr->TryEvaluateExprPointer(ResultBase, ResultOffset, Ctx); + + if (SubExpr->getType()->isArithmeticType()) { + llvm::APSInt Result(32); + if (SubExpr->TryEvaluateExprInt(Result, Ctx)) { + Result.extOrTrunc(static_cast(Ctx.getTypeSize(getType()))); + ResultBase = 0; + ResultOffset = Result; + return true; + } + } + + return true; + } + case Expr::ConditionalOperatorClass: { + const ConditionalOperator *Exp = cast(this); + if (!Exp->getCond()->getType()->isIntegralType()) { + // FIXME: Need to handle more cases + return false; + } + llvm::APSInt CondResult(32); + if (!Exp->getCond()->TryEvaluateExprInt(CondResult, Ctx)) + return false; + if (CondResult != 0) + return Exp->getLHS()->TryEvaluateExprPointer(ResultBase, ResultOffset, Ctx); + return Exp->getRHS()->TryEvaluateExprPointer(ResultBase, ResultOffset, Ctx); + } + case Expr::AddrLabelExprClass: + ResultBase = this; + ResultOffset.zextOrTrunc(static_cast(Ctx.getTypeSize(getType()))); + ResultOffset = 0; + return true; + } +} + +bool Expr::TryEvaluateExprInt(llvm::APSInt &Result, ASTContext &Ctx) const { + if (!getType()->isIntegralType()) + return false; + + switch (getStmtClass()) { + default: + return false; + case ParenExprClass: { + const Expr* SE = cast(this)->getSubExpr(); + return SE->TryEvaluateExprInt(Result, Ctx); + } + case IntegerLiteralClass: + Result = cast(this)->getValue(); + break; + case CharacterLiteralClass: { + const CharacterLiteral *CL = cast(this); + Result.zextOrTrunc(static_cast(Ctx.getTypeSize(getType()))); + Result = CL->getValue(); + Result.setIsUnsigned(!getType()->isSignedIntegerType()); + break; + } + case TypesCompatibleExprClass: { + const TypesCompatibleExpr *TCE = cast(this); + Result.zextOrTrunc(static_cast(Ctx.getTypeSize(getType()))); + Result = Ctx.typesAreCompatible(TCE->getArgType1(), TCE->getArgType2()); + break; + } + case CallExprClass: { + const CallExpr *CE = cast(this); + Result.zextOrTrunc(static_cast(Ctx.getTypeSize(getType()))); + if (CE->isBuiltinClassifyType(Result)) + break; + return false; + } + case DeclRefExprClass: + if (const EnumConstantDecl *D = + dyn_cast(cast(this)->getDecl())) { + Result = D->getInitVal(); + break; + } + return false; + case UnaryOperatorClass: { + const UnaryOperator *Exp = cast(this); + + if (Exp->isOffsetOfOp()) { + Result = Exp->evaluateOffsetOf(Ctx); + break; + } + + if (Exp->isSizeOfAlignOfOp()) { + // Return the result in the right width. + Result.zextOrTrunc(static_cast(Ctx.getTypeSize(getType()))); + + // sizeof(void) and __alignof__(void) = 1 as a gcc extension. + if (Exp->getSubExpr()->getType()->isVoidType()) { + Result = 1; + break; + } + + // sizeof(vla) is not a constantexpr: C99 6.5.3.4p2. + if (!Exp->getSubExpr()->getType()->isConstantSizeType()) { + // FIXME: Should we attempt to evaluate this? + return false; + } + + // Get information about the size or align. + if (Exp->getSubExpr()->getType()->isFunctionType()) { + // GCC extension: sizeof(function) = 1. + // FIXME: AlignOf shouldn't be unconditionally 4! + Result = Exp->getOpcode() == UnaryOperator::AlignOf ? 4 : 1; + } else { + unsigned CharSize = Ctx.Target.getCharWidth(); + if (Exp->getOpcode() == UnaryOperator::AlignOf) + Result = Ctx.getTypeAlign(Exp->getSubExpr()->getType()) / CharSize; + else + Result = Ctx.getTypeSize(Exp->getSubExpr()->getType()) / CharSize; + } + break; + } + + // Get the operand value. If this is sizeof/alignof, do not evalute the + // operand. This affects C99 6.6p3. + if (!Exp->getSubExpr()->TryEvaluateExprInt(Result, Ctx)) + return false; + + switch (Exp->getOpcode()) { + // Address, indirect, pre/post inc/dec, etc are not valid constant exprs. + // See C99 6.6p3. + default: + return false; + case UnaryOperator::Extension: + return true; // FIXME: this is wrong. + case UnaryOperator::LNot: { + bool Val = Result == 0; + Result.zextOrTrunc(static_cast(Ctx.getTypeSize(getType()))); + Result = Val; + break; + } + case UnaryOperator::Plus: + break; + case UnaryOperator::Minus: + Result = -Result; + break; + case UnaryOperator::Not: + Result = ~Result; + break; + } + break; + } + case SizeOfAlignOfTypeExprClass: { + const SizeOfAlignOfTypeExpr *Exp = cast(this); + + // Return the result in the right width. + Result.zextOrTrunc(static_cast(Ctx.getTypeSize(getType()))); + + // sizeof(void) and __alignof__(void) = 1 as a gcc extension. + if (Exp->getArgumentType()->isVoidType()) { + Result = 1; + break; + } + + // alignof always evaluates to a constant, sizeof does if arg is not VLA. + if (Exp->isSizeOf() && !Exp->getArgumentType()->isConstantSizeType()) { + return false; + } + + // Get information about the size or align. + if (Exp->getArgumentType()->isFunctionType()) { + // GCC extension: sizeof(function) = 1. + Result = Exp->isSizeOf() ? 1 : 4; + } else { + unsigned CharSize = Ctx.Target.getCharWidth(); + if (Exp->isSizeOf()) + Result = Ctx.getTypeSize(Exp->getArgumentType()) / CharSize; + else + Result = Ctx.getTypeAlign(Exp->getArgumentType()) / CharSize; + } + break; + } + case BinaryOperatorClass: { + const BinaryOperator *Exp = cast(this); + + // The LHS of a constant expr is always evaluated and needed. + if (!Exp->getLHS()->TryEvaluateExprInt(Result, Ctx)) + return false; + + if (Exp->getOpcode() == BinaryOperator::LAnd && Result == 0) { + Result.zextOrTrunc(static_cast(Ctx.getTypeSize(getType()))); + break; + } + if (Exp->getOpcode() == BinaryOperator::LOr && Result != 0) { + Result.zextOrTrunc(static_cast(Ctx.getTypeSize(getType()))); + Result = 1; + break; + } + + llvm::APSInt RHS(32); + if (!Exp->getRHS()->TryEvaluateExprInt(RHS, Ctx)) + return false; + + switch (Exp->getOpcode()) { + default: + return false; + case BinaryOperator::Mul: + Result *= RHS; + break; + case BinaryOperator::Div: + if (RHS == 0) + return false; + Result /= RHS; + break; + case BinaryOperator::Rem: + if (RHS == 0) + return false; + Result %= RHS; + break; + case BinaryOperator::Add: Result += RHS; break; + case BinaryOperator::Sub: Result -= RHS; break; + case BinaryOperator::Shl: + Result <<= + static_cast(RHS.getLimitedValue(Result.getBitWidth()-1)); + break; + case BinaryOperator::Shr: + Result >>= + static_cast(RHS.getLimitedValue(Result.getBitWidth()-1)); + break; + case BinaryOperator::LT: Result = Result < RHS; break; + case BinaryOperator::GT: Result = Result > RHS; break; + case BinaryOperator::LE: Result = Result <= RHS; break; + case BinaryOperator::GE: Result = Result >= RHS; break; + case BinaryOperator::EQ: Result = Result == RHS; break; + case BinaryOperator::NE: Result = Result != RHS; break; + case BinaryOperator::And: Result &= RHS; break; + case BinaryOperator::Xor: Result ^= RHS; break; + case BinaryOperator::Or: Result |= RHS; break; + + case BinaryOperator::Comma: + // C99 6.6p3: "shall not contain assignment, ..., or comma operators, + // *except* when they are contained within a subexpression that is not + // evaluated". Note that Assignment can never happen due to constraints + // on the LHS subexpr, so we don't need to check it here. + // FIXME: Need to come up with an efficient way to deal with the C99 + // rules on evaluation while still evaluating this. Maybe a + // "evaluated comma" out parameter? + return false; + } + + break; + } + case ImplicitCastExprClass: + case CastExprClass: { + const Expr *SubExpr; + SourceLocation CastLoc; + if (const CastExpr *C = dyn_cast(this)) { + SubExpr = C->getSubExpr(); + CastLoc = C->getLParenLoc(); + } else { + SubExpr = cast(this)->getSubExpr(); + CastLoc = getLocStart(); + } + + uint32_t DestWidth = static_cast(Ctx.getTypeSize(getType())); + + // Handle simple integer->integer casts. + if (SubExpr->getType()->isIntegerType()) { + if (!SubExpr->TryEvaluateExprInt(Result, Ctx)) + return false; + + // Figure out if this is a truncate, extend or noop cast. + // If the input is signed, do a sign extend, noop, or truncate. + if (getType()->isBooleanType()) { + // Conversion to bool compares against zero. + Result = Result != 0; + Result.zextOrTrunc(DestWidth); + } + else + Result.extOrTrunc(DestWidth); + break; + } + + if (SubExpr->getType()->isPointerType()) { + const Expr* ResultBase; + llvm::APInt ResultOffset; + if (!SubExpr->TryEvaluateExprPointer(ResultBase, ResultOffset, Ctx)) + return false; + if (ResultBase) + return false; + Result = ResultOffset.sextOrTrunc(DestWidth); + break; + } + + // Allow floating constants that are the immediate operands of casts or that + // are parenthesized. + const Expr *Operand = SubExpr; + while (const ParenExpr *PE = dyn_cast(Operand)) + Operand = PE->getSubExpr(); + + // If this isn't a floating literal, we can't handle it. + const FloatingLiteral *FL = dyn_cast(Operand); + if (!FL) { + return false; + } + + // If the destination is boolean, compare against zero. + if (getType()->isBooleanType()) { + Result = !FL->getValue().isZero(); + Result.zextOrTrunc(DestWidth); + break; + } + + // Determine whether we are converting to unsigned or signed. + bool DestSigned = getType()->isSignedIntegerType(); + + // TODO: Warn on overflow, but probably not here: isIntegerConstantExpr can + // be called multiple times per AST. + uint64_t Space[4]; + (void)FL->getValue().convertToInteger(Space, DestWidth, DestSigned, + llvm::APFloat::rmTowardZero); + Result = llvm::APInt(DestWidth, 4, Space); + break; + } + case ConditionalOperatorClass: { + const ConditionalOperator *Exp = cast(this); + + if (!Exp->getCond()->TryEvaluateExprInt(Result, Ctx)) + return false; + + const Expr* EvalExp = Result == 0 ? Exp->getRHS() : Exp->getLHS(); + + return EvalExp->TryEvaluateExprInt(Result, Ctx); + } + case CXXDefaultArgExprClass: + return cast(this) + ->TryEvaluateExprInt(Result, Ctx); + } + + // Cases that are valid constant exprs fall through to here. + Result.setIsUnsigned(getType()->isUnsignedIntegerType()); + return true; +} + /// isIntegerConstantExpr - this recursive routine will test if an expression is /// an integer constant expression. Note: With the introduction of VLA's in /// C99 the result of the sizeof operator is no longer always a constant @@ -928,11 +1373,6 @@ if (!SubExpr->getType()->isArithmeticType() || !getType()->isIntegerType()) { if (Loc) *Loc = SubExpr->getLocStart(); - // GCC accepts pointers as an extension. - // FIXME: check getLangOptions().NoExtensions. At the moment, it doesn't - // appear possible to get langOptions() from the Expr. - if (SubExpr->getType()->isPointerType()) // && !NoExtensions - return true; return false; } Index: include/clang/AST/Expr.h =================================================================== --- include/clang/AST/Expr.h (revision 52091) +++ include/clang/AST/Expr.h (working copy) @@ -107,6 +107,12 @@ } /// isConstantExpr - Return true if this expression is a valid constant expr. bool isConstantExpr(ASTContext &Ctx, SourceLocation *Loc) const; + + bool TryEvaluateExprFloat(llvm::APFloat& Result, ASTContext &Ctx) const; + bool TryEvaluateExprInt(llvm::APSInt& Result, ASTContext &Ctx) const; + bool TryEvaluateExprLValueAddress(const Expr*& ResultBase, llvm::APInt& ResultOffset, ASTContext &Ctx) const; + bool TryEvaluateExprPointer(const Expr*& ResultBase, llvm::APInt& ResultOffset, ASTContext &Ctx) const; + bool TryEvaluateExprComplex(llvm::APFloat& RealResult, llvm::APFloat& ImagResult, ASTContext &Ctx) const; /// hasGlobalStorage - Return true if this expression has static storage /// duration. This means that the address of this expression is a link-time Index: lib/Sema/SemaDecl.cpp =================================================================== --- lib/Sema/SemaDecl.cpp (revision 52091) +++ lib/Sema/SemaDecl.cpp (working copy) @@ -1633,35 +1741,6 @@ return New; } -static bool CalcFakeICEVal(const Expr* Expr, - llvm::APSInt& Result, - ASTContext& Context) { - // Calculate the value of an expression that has a calculatable - // value, but isn't an ICE. Currently, this only supports - // a very narrow set of extensions, but it can be expanded if needed. - if (const ParenExpr *PE = dyn_cast(Expr)) - return CalcFakeICEVal(PE->getSubExpr(), Result, Context); - - if (const CastExpr *CE = dyn_cast(Expr)) { - QualType CETy = CE->getType(); - if ((CETy->isIntegralType() && !CETy->isBooleanType()) || - CETy->isPointerType()) { - if (CalcFakeICEVal(CE->getSubExpr(), Result, Context)) { - Result.extOrTrunc(Context.getTypeSize(CETy)); - // FIXME: This assumes pointers are signed. - Result.setIsSigned(CETy->isSignedIntegerType() || - CETy->isPointerType()); - return true; - } - } - } - - if (Expr->getType()->isIntegralType()) - return Expr->isIntegerConstantExpr(Result, Context); - - return false; -} - QualType Sema::TryFixInvalidVariablyModifiedType(QualType T) { // This method tries to turn a variable array into a constant // array even when the size isn't an ICE. This is necessary @@ -1670,7 +1749,7 @@ if (const VariableArrayType* VLATy = dyn_cast(T)) { llvm::APSInt Result(32); if (VLATy->getSizeExpr() && - CalcFakeICEVal(VLATy->getSizeExpr(), Result, Context) && + VLATy->getSizeExpr()->TryEvaluateExprInt(Result, Context) && Result > llvm::APSInt(Result.getBitWidth(), Result.isUnsigned())) { return Context.getConstantArrayType(VLATy->getElementType(), Result, ArrayType::Normal, 0);