From: Steve Naroff Date: Thu, 10 Jan 2008 22:15:12 +0000 (+0000) Subject: - Teach Expr::isConstantExpr() about InitListExpr's (and offsetof, since I noticed... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=d0091aa3850a8c8be94c68710ed4ef1317729ba0;p=clang - Teach Expr::isConstantExpr() about InitListExpr's (and offsetof, since I noticed it was missing). - Rename CheckInitializer() to CheckInitializerTypes(). - Removed the isStatic argument to CheckInitializerTypes() and all of it's subroutines. Checking for constant expressions is now done separately. - Added CheckForConstantInitializer(). git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@45840 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/AST/Expr.cpp b/AST/Expr.cpp index 159122156f..e2f6c6210b 100644 --- a/AST/Expr.cpp +++ b/AST/Expr.cpp @@ -487,7 +487,8 @@ bool Expr::isConstantExpr(ASTContext &Ctx, SourceLocation *Loc) const { // Get the operand value. If this is sizeof/alignof, do not evalute the // operand. This affects C99 6.6p3. - if (!Exp->isSizeOfAlignOfOp() && + if (!Exp->isSizeOfAlignOfOp() && + Exp->getOpcode() != UnaryOperator::OffsetOf && !Exp->getSubExpr()->isConstantExpr(Ctx, Loc)) return false; @@ -501,6 +502,7 @@ bool Expr::isConstantExpr(ASTContext &Ctx, SourceLocation *Loc) const { return true; // FIXME: this is wrong. case UnaryOperator::SizeOf: case UnaryOperator::AlignOf: + case UnaryOperator::OffsetOf: // sizeof(vla) is not a constantexpr: C99 6.5.3.4p2. if (!Exp->getSubExpr()->getType()->isConstantSizeType(Ctx)) { if (Loc) *Loc = Exp->getOperatorLoc(); @@ -560,9 +562,18 @@ bool Expr::isConstantExpr(ASTContext &Ctx, SourceLocation *Loc) const { return false; return true; } + case InitListExprClass: { + const InitListExpr *Exp = cast(this); + unsigned numInits = Exp->getNumInits(); + for (unsigned i = 0; i < numInits; i++) { + if (!Exp->getInit(i)->isConstantExpr(Ctx, Loc)) { + if (Loc) *Loc = Exp->getInit(i)->getLocStart(); + return false; + } + } + return true; + } } - - return true; } /// isIntegerConstantExpr - this recursive routine will test if an expression is diff --git a/Sema/Sema.h b/Sema/Sema.h index 27885372db..ef20829053 100644 --- a/Sema/Sema.h +++ b/Sema/Sema.h @@ -722,21 +722,21 @@ private: IdentifierInfo &Comp, SourceLocation CmpLoc); /// type checking declaration initializers (C99 6.7.8) - bool CheckInitializer(Expr *&simpleInit_or_initList, QualType &declType, - bool isStatic); - bool CheckSingleInitializer(Expr *&simpleInit, bool isStatic, - QualType declType); + bool CheckInitializerTypes(Expr *&simpleInit_or_initList, QualType &declType); + bool CheckSingleInitializer(Expr *&simpleInit, QualType declType); bool CheckInitExpr(Expr *expr, InitListExpr *IList, unsigned slot, - bool isStatic, QualType ElementType); + QualType ElementType); + void CheckVariableInitList(QualType DeclType, InitListExpr *IList, - QualType ElementType, bool isStatic, + QualType ElementType, int &nInitializers, bool &hadError); void CheckConstantInitList(QualType DeclType, InitListExpr *IList, - QualType ElementType, bool isStatic, + QualType ElementType, int &nInitializers, bool &hadError); bool CheckForCharArrayInitializer(InitListExpr *IList, QualType ElementType, int &nInitializers, bool isConstant, bool &hadError); + bool CheckForConstantInitializer(Expr *e, QualType t); // CheckVectorCast - check type constraints for vectors. // Since vectors are an extension, there are no C standard reference for this. diff --git a/Sema/SemaDecl.cpp b/Sema/SemaDecl.cpp index 5e2526e451..cbcd79ea4f 100644 --- a/Sema/SemaDecl.cpp +++ b/Sema/SemaDecl.cpp @@ -354,18 +354,7 @@ Sema::DeclTy *Sema::ParsedFreeStandingDeclSpec(Scope *S, DeclSpec &DS) { return dyn_cast_or_null(static_cast(DS.getTypeRep())); } -bool Sema::CheckSingleInitializer(Expr *&Init, bool isStatic, - QualType DeclType) { - // FIXME: Remove the isReferenceType check and handle assignment - // to a reference. - SourceLocation loc; - if (isStatic && !DeclType->isReferenceType() && - !Init->isConstantExpr(Context, &loc)) { // C99 6.7.8p4. - assert(loc.isValid() && "isConstantExpr didn't return a loc!"); - Diag(loc, diag::err_init_element_not_constant, Init->getSourceRange()); - return true; - } - +bool Sema::CheckSingleInitializer(Expr *&Init, QualType DeclType) { // Get the type before calling CheckSingleAssignmentConstraints(), since // it can promote the expression. QualType InitType = Init->getType(); @@ -376,16 +365,9 @@ bool Sema::CheckSingleInitializer(Expr *&Init, bool isStatic, } bool Sema::CheckInitExpr(Expr *expr, InitListExpr *IList, unsigned slot, - bool isStatic, QualType ElementType) { - SourceLocation loc; - if (isStatic && !expr->isConstantExpr(Context, &loc)) { // C99 6.7.8p4. - assert(loc.isValid() && "isConstantExpr didn't return a loc!"); - Diag(loc, diag::err_init_element_not_constant, expr->getSourceRange()); - return true; - } - + QualType ElementType) { Expr *savExpr = expr; // Might be promoted by CheckSingleInitializer. - if (CheckSingleInitializer(expr, isStatic, ElementType)) + if (CheckSingleInitializer(expr, ElementType)) return true; // types weren't compatible. if (savExpr != expr) // The type was promoted, update initializer list. @@ -394,7 +376,7 @@ bool Sema::CheckInitExpr(Expr *expr, InitListExpr *IList, unsigned slot, } void Sema::CheckVariableInitList(QualType DeclType, InitListExpr *IList, - QualType ElementType, bool isStatic, + QualType ElementType, int &nInitializers, bool &hadError) { unsigned numInits = IList->getNumInits(); @@ -409,11 +391,11 @@ void Sema::CheckVariableInitList(QualType DeclType, InitListExpr *IList, if (InitListExpr *InitList = dyn_cast(expr)) { if (const ConstantArrayType *CAT = DeclType->getAsConstantArrayType()) { int maxElements = CAT->getMaximumElements(); - CheckConstantInitList(DeclType, InitList, ElementType, isStatic, + CheckConstantInitList(DeclType, InitList, ElementType, maxElements, hadError); } } else { - hadError = CheckInitExpr(expr, IList, i, isStatic, ElementType); + hadError = CheckInitExpr(expr, IList, i, ElementType); } nInitializers++; } @@ -469,7 +451,7 @@ bool Sema::CheckForCharArrayInitializer(InitListExpr *IList, // FIXME: Doesn't deal with arrays of structures yet. void Sema::CheckConstantInitList(QualType DeclType, InitListExpr *IList, - QualType ElementType, bool isStatic, + QualType ElementType, int &totalInits, bool &hadError) { int maxElementsAtThisLevel = 0; int nInitsAtLevel = 0; @@ -503,10 +485,10 @@ void Sema::CheckConstantInitList(QualType DeclType, InitListExpr *IList, Expr *expr = IList->getInit(i); if (InitListExpr *InitList = dyn_cast(expr)) { - CheckConstantInitList(DeclType, InitList, ElementType, isStatic, + CheckConstantInitList(DeclType, InitList, ElementType, totalInits, hadError); } else { - hadError = CheckInitExpr(expr, IList, i, isStatic, ElementType); + hadError = CheckInitExpr(expr, IList, i, ElementType); nInitsAtLevel++; // increment the number of initializers at this level. totalInits--; // decrement the total number of initializers. @@ -527,7 +509,7 @@ void Sema::CheckConstantInitList(QualType DeclType, InitListExpr *IList, } } -bool Sema::CheckInitializer(Expr *&Init, QualType &DeclType, bool isStatic) { +bool Sema::CheckInitializerTypes(Expr *&Init, QualType &DeclType) { bool hadError = false; InitListExpr *InitList = dyn_cast(Init); @@ -560,7 +542,7 @@ bool Sema::CheckInitializer(Expr *&Init, QualType &DeclType, bool isStatic) { return hadError; } } - return CheckSingleInitializer(Init, isStatic, DeclType); + return CheckSingleInitializer(Init, DeclType); } // We have an InitListExpr, make sure we set the type. Init->setType(DeclType); @@ -576,7 +558,7 @@ bool Sema::CheckInitializer(Expr *&Init, QualType &DeclType, bool isStatic) { // array can have unknown size. For example, "int [][]" is illegal. int numInits = 0; CheckVariableInitList(VAT->getElementType(), InitList, VAT->getBaseType(), - isStatic, numInits, hadError); + numInits, hadError); llvm::APSInt ConstVal(32); if (!hadError) @@ -595,19 +577,18 @@ bool Sema::CheckInitializer(Expr *&Init, QualType &DeclType, bool isStatic) { if (const ConstantArrayType *CAT = DeclType->getAsConstantArrayType()) { int maxElements = CAT->getMaximumElements(); CheckConstantInitList(DeclType, InitList, CAT->getBaseType(), - isStatic, maxElements, hadError); + maxElements, hadError); return hadError; } if (const VectorType *VT = DeclType->getAsVectorType()) { int maxElements = VT->getNumElements(); CheckConstantInitList(DeclType, InitList, VT->getElementType(), - isStatic, maxElements, hadError); + maxElements, hadError); return hadError; } if (DeclType->isScalarType()) { // C99 6.7.8p11: Allow "int x = { 1, 2 };" int maxElements = 1; - CheckConstantInitList(DeclType, InitList, DeclType, isStatic, maxElements, - hadError); + CheckConstantInitList(DeclType, InitList, DeclType, maxElements, hadError); return hadError; } // FIXME: Handle struct/union types, including those appearing in a @@ -752,6 +733,17 @@ Sema::ActOnDeclarator(Scope *S, Declarator &D, DeclTy *lastDecl) { 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()); + return true; + } + return false; +} + void Sema::AddInitializerToDecl(DeclTy *dcl, ExprTy *init) { Decl *RealDecl = static_cast(dcl); Expr *Init = static_cast(init); @@ -772,7 +764,7 @@ void Sema::AddInitializerToDecl(DeclTy *dcl, ExprTy *init) { return; } // Get the decls type and save a reference for later, since - // CheckInitializer may change it. + // CheckInitializerTypes may change it. QualType DclT = VDecl->getType(), SavT = DclT; if (BlockVarDecl *BVD = dyn_cast(VDecl)) { VarDecl::StorageClass SC = BVD->getStorageClass(); @@ -780,13 +772,18 @@ void Sema::AddInitializerToDecl(DeclTy *dcl, ExprTy *init) { Diag(VDecl->getLocation(), diag::err_block_extern_cant_init); BVD->setInvalidDecl(); } else if (!BVD->isInvalidDecl()) { - CheckInitializer(Init, DclT, SC == VarDecl::Static); + CheckInitializerTypes(Init, DclT); + if (SC == VarDecl::Static) // C99 6.7.8p4. + CheckForConstantInitializer(Init, DclT); } } else if (FileVarDecl *FVD = dyn_cast(VDecl)) { if (FVD->getStorageClass() == VarDecl::Extern) Diag(VDecl->getLocation(), diag::warn_extern_init); if (!FVD->isInvalidDecl()) - CheckInitializer(Init, DclT, true); + CheckInitializerTypes(Init, DclT); + + // C99 6.7.8p4. All file scoped initializers need to be constant. + CheckForConstantInitializer(Init, DclT); } // If the type changed, it means we had an incomplete type that was // completed by the initializer. For example: diff --git a/Sema/SemaExpr.cpp b/Sema/SemaExpr.cpp index 897432578b..a6808f83a7 100644 --- a/Sema/SemaExpr.cpp +++ b/Sema/SemaExpr.cpp @@ -664,10 +664,13 @@ ActOnCompoundLiteral(SourceLocation LParenLoc, TypeTy *Ty, Expr *literalExpr = static_cast(InitExpr); // FIXME: add more semantic analysis (C99 6.5.2.5). - bool requireConstantExprs = !CurFunctionDecl && !CurMethodDecl; - if (CheckInitializer(literalExpr, literalType, requireConstantExprs)) + if (CheckInitializerTypes(literalExpr, literalType)) return true; - + + if (!CurFunctionDecl && !CurMethodDecl) { // 6.5.2.5p3 + if (CheckForConstantInitializer(literalExpr, literalType)) + return true; + } return new CompoundLiteralExpr(LParenLoc, literalType, literalExpr); }