Index: lib/Sema/SemaDecl.cpp =================================================================== --- lib/Sema/SemaDecl.cpp (revision 51204) +++ lib/Sema/SemaDecl.cpp (working copy) @@ -24,6 +24,7 @@ #include "clang/Basic/LangOptions.h" #include "clang/Basic/TargetInfo.h" #include "clang/Basic/SourceManager.h" +#include "clang/AST/ExprCXX.h" // FIXME: layering (ideally, Sema shouldn't be dependent on Lex API's) #include "clang/Lex/Preprocessor.h" #include "clang/Lex/HeaderSearch.h" @@ -989,17 +990,353 @@ return New; } -bool Sema::CheckForConstantInitializer(Expr *Init, QualType DclT) { - SourceLocation loc; - // FIXME: Remove the isReference check and handle assignment to a reference. - if (!DclT->isReferenceType() && !Init->isConstantExpr(Context, &loc)) { - assert(loc.isValid() && "isConstantExpr didn't return a loc!"); - Diag(loc, diag::err_init_element_not_constant, Init->getSourceRange()); +bool Sema::CheckAddressConstantExpressionLValue(const Expr* Init) { + switch (Init->getStmtClass()) { + default: + Diag(Init->getExprLoc(), + diag::err_init_element_not_constant, Init->getSourceRange()); return true; + case Expr::ParenExprClass: { + const ParenExpr* PE = cast(Init); + return CheckAddressConstantExpressionLValue(PE->getSubExpr()); } - return false; + case Expr::CompoundLiteralExprClass: + return cast(Init)->isFileScope(); + case Expr::DeclRefExprClass: { + const Decl *D = cast(Init)->getDecl(); + if (const VarDecl *VD = dyn_cast(D)) + return VD->hasGlobalStorage(); + if (isa(D)) + return false; + Diag(Init->getExprLoc(), + diag::err_init_element_not_constant, Init->getSourceRange()); + return true; + } + case Expr::MemberExprClass: { + const MemberExpr *M = cast(Init); + if (M->isArrow()) + return CheckAddressConstantExpression(M->getBase()); + return CheckAddressConstantExpressionLValue(M->getBase()); + } + case Expr::ArraySubscriptExprClass: { + // FIXME: Should we pedwarn for "x[0+0]" (where x is a pointer)? + const ArraySubscriptExpr *ASE = cast(Init); + return CheckAddressConstantExpression(ASE->getBase()) || + CheckArithmeticConstantExpression(ASE->getIdx()); + } + case Expr::StringLiteralClass: + case Expr::PreDefinedExprClass: + return false; + case Expr::UnaryOperatorClass: { + const UnaryOperator *Exp = cast(Init); + + // C99 6.6p9 + if (Exp->getOpcode() == UnaryOperator::Deref) + return CheckAddressConstantExpressionLValue(Exp->getSubExpr()); + + Diag(Init->getExprLoc(), + diag::err_init_element_not_constant, Init->getSourceRange()); + return true; + } + } } +bool Sema::CheckAddressConstantExpression(const Expr* Init) { + switch (Init->getStmtClass()) { + default: + Diag(Init->getExprLoc(), + diag::err_init_element_not_constant, Init->getSourceRange()); + return true; + case Expr::ParenExprClass: { + const ParenExpr* PE = cast(Init); + return CheckAddressConstantExpression(PE->getSubExpr()); + } + case Expr::StringLiteralClass: + case Expr::ObjCStringLiteralClass: + return false; + case Expr::CallExprClass: { + const CallExpr *CE = cast(Init); + if (CE->isBuiltinConstantExpr()) + return false; + Diag(Init->getExprLoc(), + diag::err_init_element_not_constant, Init->getSourceRange()); + return true; + } + case Expr::UnaryOperatorClass: { + const UnaryOperator *Exp = cast(Init); + + // C99 6.6p9 + if (Exp->getOpcode() == UnaryOperator::AddrOf) + return CheckAddressConstantExpressionLValue(Exp->getSubExpr()); + + if (Exp->getOpcode() == UnaryOperator::Extension) + return CheckAddressConstantExpression(Exp->getSubExpr()); + + Diag(Init->getExprLoc(), + diag::err_init_element_not_constant, Init->getSourceRange()); + return true; + } + case Expr::BinaryOperatorClass: { + // FIXME: Should we pedwarn for expressions like "a + 1 + 2"? + const BinaryOperator *Exp = cast(Init); + + Expr *PExp = Exp->getLHS(); + Expr *IExp = Exp->getRHS(); + if (IExp->getType()->isPointerType()) + std::swap(PExp, IExp); + + // FIXME: Should we pedwarn if IExp isn't an integer constant expression? + return CheckAddressConstantExpression(PExp) || + CheckArithmeticConstantExpression(IExp); + } + case Expr::ImplicitCastExprClass: { + const Expr* SubExpr = cast(Init)->getSubExpr(); + + // Check for implicit promotion + if (SubExpr->getType()->isFunctionType() || + SubExpr->getType()->isArrayType()) + return CheckAddressConstantExpressionLValue(SubExpr); + + // Check for pointer->pointer cast + if (SubExpr->getType()->isPointerType()) + return CheckAddressConstantExpression(SubExpr); + + if (SubExpr->getType()->isArithmeticType()) + return CheckArithmeticConstantExpression(SubExpr); + + Diag(Init->getExprLoc(), + diag::err_init_element_not_constant, Init->getSourceRange()); + return true; + } + case Expr::CastExprClass: { + const Expr* SubExpr = cast(Init)->getSubExpr(); + + // Check for pointer->pointer cast + if (SubExpr->getType()->isPointerType()) + return CheckAddressConstantExpression(SubExpr); + + // FIXME: Should we pedwarn for (int*)(0+0)? + if (SubExpr->getType()->isArithmeticType()) + return CheckArithmeticConstantExpression(SubExpr); + + Diag(Init->getExprLoc(), + diag::err_init_element_not_constant, Init->getSourceRange()); + return true; + } + case Expr::ConditionalOperatorClass: { + // FIXME: Should we pedwarn here? + const ConditionalOperator *Exp = cast(Init); + if (!Exp->getCond()->getType()->isArithmeticType()) { + Diag(Init->getExprLoc(), + diag::err_init_element_not_constant, Init->getSourceRange()); + return true; + } + if (CheckArithmeticConstantExpression(Exp->getCond())) + return true; + if (Exp->getLHS() && + CheckAddressConstantExpression(Exp->getLHS())) + return true; + return CheckAddressConstantExpression(Exp->getRHS()); + } + case Expr::AddrLabelExprClass: + return false; + } +} + +bool Sema::CheckArithmeticConstantExpression(const Expr* Init) { + switch (Init->getStmtClass()) { + default: + Diag(Init->getExprLoc(), + diag::err_init_element_not_constant, Init->getSourceRange()); + return true; + case Expr::ParenExprClass: { + const ParenExpr* PE = cast(Init); + return CheckArithmeticConstantExpression(PE->getSubExpr()); + } + case Expr::FloatingLiteralClass: + case Expr::IntegerLiteralClass: + case Expr::CharacterLiteralClass: + case Expr::ImaginaryLiteralClass: + case Expr::TypesCompatibleExprClass: + case Expr::CXXBoolLiteralExprClass: + return false; + case Expr::CallExprClass: { + const CallExpr *CE = cast(Init); + if (CE->isBuiltinConstantExpr()) + return false; + Diag(Init->getExprLoc(), + diag::err_init_element_not_constant, Init->getSourceRange()); + return true; + } + case Expr::DeclRefExprClass: { + const Decl *D = cast(Init)->getDecl(); + if (isa(D)) + return false; + Diag(Init->getExprLoc(), + diag::err_init_element_not_constant, Init->getSourceRange()); + return true; + } + case Expr::CompoundLiteralExprClass: + // Allow "(vector type){2,4}"; normal C constraints don't allow this, + // but vectors are allowed to be magic. + if (Init->getType()->isVectorType()) + return false; + Diag(Init->getExprLoc(), + diag::err_init_element_not_constant, Init->getSourceRange()); + return true; + case Expr::UnaryOperatorClass: { + const UnaryOperator *Exp = cast(Init); + + switch (Exp->getOpcode()) { + // Address, indirect, pre/post inc/dec, etc are not valid constant exprs. + // See C99 6.6p3. + default: + Diag(Init->getExprLoc(), + diag::err_init_element_not_constant, Init->getSourceRange()); + return true; + case UnaryOperator::SizeOf: + case UnaryOperator::AlignOf: + case UnaryOperator::OffsetOf: + // sizeof(E) is a constantexpr if and only if E is not evaluted. + // See C99 6.5.3.4p2 and 6.6p3. + if (Exp->getSubExpr()->getType()->isConstantSizeType()) + return false; + Diag(Init->getExprLoc(), + diag::err_init_element_not_constant, Init->getSourceRange()); + return true; + case UnaryOperator::Extension: + case UnaryOperator::LNot: + case UnaryOperator::Plus: + case UnaryOperator::Minus: + case UnaryOperator::Not: + return CheckArithmeticConstantExpression(Exp->getSubExpr()); + } + } + case Expr::SizeOfAlignOfTypeExprClass: { + const SizeOfAlignOfTypeExpr *Exp = cast(Init); + // Special check for void types, which are allowed as an extension + if (Exp->getArgumentType()->isVoidType()) + return false; + // alignof always evaluates to a constant. + // FIXME: is sizeof(int[3.0]) a constant expression? + if (Exp->isSizeOf() && !Exp->getArgumentType()->isConstantSizeType()) { + Diag(Init->getExprLoc(), + diag::err_init_element_not_constant, Init->getSourceRange()); + return true; + } + return false; + } + case Expr::BinaryOperatorClass: { + const BinaryOperator *Exp = cast(Init); + + if (Exp->getLHS()->getType()->isArithmeticType() && + Exp->getRHS()->getType()->isArithmeticType()) { + return CheckArithmeticConstantExpression(Exp->getLHS()) || + CheckArithmeticConstantExpression(Exp->getRHS()); + } + + Diag(Init->getExprLoc(), + diag::err_init_element_not_constant, Init->getSourceRange()); + return true; + } + case Expr::ImplicitCastExprClass: + case Expr::CastExprClass: { + const Expr *SubExpr; + if (const CastExpr *C = dyn_cast(Init)) { + SubExpr = C->getSubExpr(); + } else { + SubExpr = cast(Init)->getSubExpr(); + } + + if (SubExpr->getType()->isArithmeticType()) + return CheckArithmeticConstantExpression(SubExpr); + + Diag(Init->getExprLoc(), + diag::err_init_element_not_constant, Init->getSourceRange()); + return true; + } + case Expr::ConditionalOperatorClass: { + const ConditionalOperator *Exp = cast(Init); + if (CheckArithmeticConstantExpression(Exp->getCond())) + return true; + if (Exp->getLHS() && + CheckArithmeticConstantExpression(Exp->getLHS())) + return true; + return CheckArithmeticConstantExpression(Exp->getRHS()); + } + } +} + +bool Sema::CheckForConstantInitializer(Expr *Init, QualType DclT) { + // Look through CXXDefaultArgExprs; they have no meaning in this context. + if (CXXDefaultArgExpr* DAE = dyn_cast(Init)) + return CheckForConstantInitializer(DAE->getExpr(), DclT); + + if (Init->getType()->isReferenceType()) { + // FIXME: Work out how the heck reference types work + return false; +#if 0 + // A reference is constant if the address of the expression + // is constant + // We look through initlists here to simplify + // CheckAddressConstantExpressionLValue. + if (InitListExpr *Exp = dyn_cast(Init)) { + assert(Exp->getNumInits() > 0 && + "Refernce initializer cannot be empty"); + Init = Exp->getInit(0); + } + return CheckAddressConstantExpressionLValue(Init); +#endif + } + + if (InitListExpr *Exp = dyn_cast(Init)) { + unsigned numInits = Exp->getNumInits(); + for (unsigned i = 0; i < numInits; i++) { + // FIXME: Need to get the type of the declaration for C++, + // because it could be a reference? + if (CheckForConstantInitializer(Exp->getInit(i), + Exp->getInit(i)->getType())) + return true; + } + return false; + } + + if (Init->isNullPointerConstant(Context)) + return false; + if (Init->getType()->isArithmeticType()) { + // Special check for pointer cast to int; we allow + // an address constant cast to an integer if the integer + // is of an appropriate width (this sort of code is apparently used + // in some places). + // FIXME: Add pedwarn? + Expr* SubE; + if (ImplicitCastExpr* ICE = dyn_cast(Init)) + SubE = ICE->getSubExpr(); + else if (CastExpr* CE = dyn_cast(Init)) + SubE = CE->getSubExpr(); + if (SubE && (SubE->getType()->isPointerType() || + SubE->getType()->isArrayType() || + SubE->getType()->isFunctionType())) { + unsigned IntWidth = Context.getTypeSize(Init->getType()); + unsigned PointerWidth = Context.getTypeSize(Context.VoidPtrTy); + if (IntWidth >= PointerWidth) + return CheckAddressConstantExpression(Init); + } + + return CheckArithmeticConstantExpression(Init); + } + + if (Init->getType()->isPointerType()) + return CheckAddressConstantExpression(Init); + + if (Init->getType()->isArrayType()) + return false; + + Diag(Init->getExprLoc(), diag::err_init_element_not_constant, + Init->getSourceRange()); + return true; +} + void Sema::AddInitializerToDecl(DeclTy *dcl, ExprTy *init) { Decl *RealDecl = static_cast(dcl); Expr *Init = static_cast(init); Index: lib/Sema/Sema.h =================================================================== --- lib/Sema/Sema.h (revision 51204) +++ lib/Sema/Sema.h (working copy) @@ -857,6 +857,9 @@ bool CheckInitializerListTypes(InitListExpr*& IList, QualType &DeclType, bool topLevel, unsigned& startIndex); bool CheckForConstantInitializer(Expr *e, QualType t); + bool CheckArithmeticConstantExpression(const Expr* e); + bool CheckAddressConstantExpression(const Expr* e); + bool CheckAddressConstantExpressionLValue(const Expr* e); StringLiteral *IsStringLiteralInit(Expr *Init, QualType DeclType); bool CheckStringLiteralInit(StringLiteral *strLiteral, QualType &DeclT);