]> granicus.if.org Git - clang/commitdiff
More progress on array initializers.
authorSteve Naroff <snaroff@apple.com>
Sun, 2 Sep 2007 20:30:18 +0000 (20:30 +0000)
committerSteve Naroff <snaroff@apple.com>
Sun, 2 Sep 2007 20:30:18 +0000 (20:30 +0000)
- Added Expr::isConstantExpr().
- Added type checking for InitListExpr elements.
- Added diagnostic for trying to initialize a variable sized object.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@41674 91177308-0d34-0410-b5e6-96231b3b80d8

AST/Expr.cpp
Sema/Sema.h
Sema/SemaDecl.cpp
Sema/SemaExpr.cpp
include/clang/AST/Expr.h
include/clang/Basic/DiagnosticKinds.def
test/Sema/array-init.c

index d664c46081ea883610ae8a3892a3c85bd4d12fc8..c257b3b8e6640d74968aa006cb067802b91da510 100644 (file)
@@ -350,6 +350,120 @@ Expr::isModifiableLvalueResult Expr::isModifiableLvalue() const {
   return MLV_Valid;    
 }
 
+bool Expr::isConstantExpr(ASTContext &Ctx, SourceLocation *Loc) const {
+  
+  switch (getStmtClass()) {
+  default:
+    if (Loc) *Loc = getLocStart();
+    return false;
+  case ParenExprClass:
+    return cast<ParenExpr>(this)->getSubExpr()->isConstantExpr(Ctx, Loc);
+  case StringLiteralClass:
+  case FloatingLiteralClass:
+  case IntegerLiteralClass:
+  case CharacterLiteralClass:
+  case ImaginaryLiteralClass:
+  case TypesCompatibleExprClass: 
+    break;
+  case CallExprClass: {
+    const CallExpr *CE = cast<CallExpr>(this);
+    llvm::APSInt Result(32);
+    Result.zextOrTrunc(Ctx.getTypeSize(getType(), CE->getLocStart()));
+    if (CE->isBuiltinClassifyType(Result))
+      break;
+    if (Loc) *Loc = getLocStart();
+    return false;
+  }
+  case DeclRefExprClass:
+    if (isa<EnumConstantDecl>(cast<DeclRefExpr>(this)->getDecl()))
+      break;
+    if (Loc) *Loc = getLocStart();
+    return false;
+  case UnaryOperatorClass: {
+    const UnaryOperator *Exp = cast<UnaryOperator>(this);
+    
+    // Get the operand value.  If this is sizeof/alignof, do not evalute the
+    // operand.  This affects C99 6.6p3.
+    if (!Exp->isSizeOfAlignOfOp() &&
+        !Exp->getSubExpr()->isConstantExpr(Ctx, Loc))
+      return false;
+  
+    switch (Exp->getOpcode()) {
+    // Address, indirect, pre/post inc/dec, etc are not valid constant exprs.
+    // See C99 6.6p3.
+    default:
+      if (Loc) *Loc = Exp->getOperatorLoc();
+      return false;
+    case UnaryOperator::Extension:
+      return true;  // FIXME: this is wrong.
+    case UnaryOperator::SizeOf:
+    case UnaryOperator::AlignOf:
+      // sizeof(vla) is not a constantexpr: C99 6.5.3.4p2.
+      if (!Exp->getSubExpr()->getType()->isConstantSizeType(Ctx, Loc))
+        return false;
+      break;
+    case UnaryOperator::LNot:
+    case UnaryOperator::Plus:
+    case UnaryOperator::Minus:
+    case UnaryOperator::Not:
+      break;
+    }
+    break;
+  }
+  case SizeOfAlignOfTypeExprClass: {
+    const SizeOfAlignOfTypeExpr *Exp = cast<SizeOfAlignOfTypeExpr>(this);
+    // alignof always evaluates to a constant.
+    if (Exp->isSizeOf() && !Exp->getArgumentType()->isConstantSizeType(Ctx,Loc))
+      return false;
+    break;
+  }
+  case BinaryOperatorClass: {
+    const BinaryOperator *Exp = cast<BinaryOperator>(this);
+    
+    // The LHS of a constant expr is always evaluated and needed.
+    if (!Exp->getLHS()->isConstantExpr(Ctx, Loc))
+      return false;
+
+    if (!Exp->getRHS()->isConstantExpr(Ctx, Loc))
+      return false;
+    
+    break;
+  }
+  case ImplicitCastExprClass:
+  case CastExprClass: {
+    const Expr *SubExpr;
+    SourceLocation CastLoc;
+    if (const CastExpr *C = dyn_cast<CastExpr>(this)) {
+      SubExpr = C->getSubExpr();
+      CastLoc = C->getLParenLoc();
+    } else {
+      SubExpr = cast<ImplicitCastExpr>(this)->getSubExpr();
+      CastLoc = getLocStart();
+    }
+    if (!SubExpr->isConstantExpr(Ctx, Loc)) {
+      if (Loc) *Loc = SubExpr->getLocStart();
+      return false;
+    }
+    break;
+  }
+  case ConditionalOperatorClass: {
+    const ConditionalOperator *Exp = cast<ConditionalOperator>(this);
+    
+    if (!Exp->getCond()->isConstantExpr(Ctx, Loc))
+      return false;
+
+    if (!Exp->getLHS()->isConstantExpr(Ctx, Loc))
+      return false;
+
+    if (!Exp->getRHS()->isConstantExpr(Ctx, Loc))
+      return false;
+    break;
+  }
+  }
+
+  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
index 38c11a014aad082f7706245a6dc468cc091b7185..a741657bf6f024d8da2330eda60e8f5d4cb475c1 100644 (file)
@@ -445,7 +445,7 @@ private:
   QualType CheckInitializer(Expr *simpleInit_or_initList, QualType declType,
                             bool isStatic);
   bool CheckSingleInitializer(Expr *simpleInit, QualType declType);
-  bool RequireConstantExprs(InitListExpr *IList);
+  bool CheckInitList(InitListExpr *IList, QualType DType, bool isStatic);
   
   /// ConvertIntegerToTypeWarnOnOverflow - Convert the specified APInt to have
   /// the specified width and sign.  If an overflow occurs, detect it and emit
index 5eac645727775dec09d68f8676a3e742504351d9..c2f03a373c5686f8c89aeb194ca242bb17f2372a 100644 (file)
@@ -289,19 +289,21 @@ bool Sema::CheckSingleInitializer(Expr *Init, QualType DeclType) {
   return false;
 }
 
-bool Sema::RequireConstantExprs(InitListExpr *IList) {
+bool Sema::CheckInitList(InitListExpr *IList, QualType DType, bool isStatic) {
   bool hadError = false;
   for (unsigned i = 0; i < IList->getNumInits(); i++) {
     Expr *expr = IList->getInit(i);
     
     if (InitListExpr *InitList = dyn_cast<InitListExpr>(expr))
-      RequireConstantExprs(InitList);
+      CheckInitList(InitList, DType, isStatic);
     else {
       SourceLocation loc;
-      // FIXME: should be isConstantExpr()...
-      if (!expr->isIntegerConstantExpr(Context, &loc)) {
+
+      if (isStatic && !expr->isConstantExpr(Context, &loc)) { // C99 6.7.8p4.
         Diag(loc, diag::err_init_element_not_constant, expr->getSourceRange());
         hadError = true;
+      } else if (CheckSingleInitializer(expr, DType)) {
+        hadError = true; // types didn't match.
       }
     }
   }
@@ -316,10 +318,27 @@ QualType Sema::CheckInitializer(Expr *Init, QualType DeclType, bool isStatic) {
   // We have an InitListExpr, make sure we set the type.
   Init->setType(DeclType);
   
-  if (isStatic) // C99 6.7.8p4.
-    RequireConstantExprs(InitList);
-  
-  // FIXME: Lot of checking still to do...
+  // C99 6.7.8p3: The type of the entity to be initialized shall be an array
+  // of unknown size ("[]") or an object type that is not a variable array type.
+  if (const VariableArrayType *VAT = DeclType->getAsVariableArrayType()) { 
+    Expr *expr = VAT->getSizeExpr();
+    if (expr) { 
+      Diag(expr->getLocStart(), diag::err_variable_object_no_init, 
+           expr->getSourceRange());
+      return QualType();
+    }
+  }
+  if (const ArrayType *Ary = DeclType->getAsArrayType()) {
+    // We have a ConstantArrayType or VariableArrayType with unknown size.
+    QualType ElmtType = Ary->getElementType();
+    
+    // If we have a multi-dimensional array, navigate to the base type.
+    while ((Ary = ElmtType->getAsArrayType()))
+      ElmtType = Ary->getElementType();
+
+    CheckInitList(InitList, ElmtType, isStatic);
+  }
+  // FIXME: Handle struct/union types.
   return DeclType;
 }
 
index 713ddb446d8c66927c03ac63b5625b19238e3618..8788c2f9dce71b0c708ceeb05043e6010dc87f9c 100644 (file)
@@ -649,7 +649,9 @@ ParseInitList(SourceLocation LBraceLoc, ExprTy **initlist, unsigned NumInit,
   // doing the semantic analysis will likely be located elsewhere (i.e. in 
   // consumers of InitListExpr (e.g. ParseDeclarator, ParseCompoundLiteral).
   
-  return new InitListExpr(LBraceLoc, InitList, NumInit, RBraceLoc);
+  InitListExpr *e = new InitListExpr(LBraceLoc, InitList, NumInit, RBraceLoc);
+  e->setType(Context.VoidTy); // FIXME: just a place holder for now.
+  return e;
 }
 
 Action::ExprResult Sema::
index 8f5247af184acfa82a630857537847050ae637dd..037fecb64c87313660e24a0e096cc72ba5b8d74b 100644 (file)
@@ -99,6 +99,8 @@ public:
     llvm::APSInt X(32);
     return isIntegerConstantExpr(X, Ctx, Loc);
   }
+  /// isConstantExpr - Return true if this expression is a valid constant expr.
+  bool isConstantExpr(ASTContext &Ctx, SourceLocation *Loc) const;
   
   static bool classof(const Stmt *T) { 
     return T->getStmtClass() >= firstExprConstant &&
index 5de34aa774a5896daaeeb4931bd4a24c4ea1b33b..e396d95b55cfd1c24bcfdcbbfc1a52d73a49c68e 100644 (file)
@@ -548,6 +548,8 @@ DIAG(err_block_extern_cant_init, ERROR,
      "'extern' variable cannot have an initializer")
 DIAG(warn_extern_init, WARNING,
      "'extern' variable has an initializer")
+DIAG(err_variable_object_no_init, ERROR,
+     "variable-sized object may not be initialized")
 
 DIAG(err_redefinition_of_label, ERROR,
      "redefinition of label '%0'")
index 3ab2f4e5781cfa56d8f65f411eec592d368f30ad..209b73463adc863ace22331d4b0822f80a8caa8f 100644 (file)
@@ -7,12 +7,14 @@ int ary2[] = { x, y, z }; // expected-error{{initializer element is not constant
 
 extern int fileScopeExtern[3] = { 1, 3, 5 }; // expected-warning{{'extern' variable has an initializer}}
 
+static int ary3[] = { 1, "abc", 3 }; // expected-warning{{incompatible types assigning 'char *' to 'int'}}
+
 void func() {
   int x = 1;
 
   //int x2[] = { 1, 3, 5 };
 
-  int x3[x] = { 1, 2 }; // gcc-error {{variable-sized object may not be initialized}}
+  int x3[x] = { 1, 2 }; // expected-error{{variable-sized object may not be initialized}}
 
   int x4 = { 1, 2 }; // gcc-warning {{excess elements in array initializer}}
 
@@ -33,4 +35,6 @@ void func() {
   struct threeElements *p = 7; // expected-warning{{incompatible types assigning 'int' to 'struct threeElements *'}}
   
   extern int blockScopeExtern[3] = { 1, 3, 5 }; // expected-error{{'extern' variable cannot have an initializer}}
+  
+  static int x2[3] = { 1.0, "abc" , 5.8 }; // expected-warning{{incompatible types assigning 'char *' to 'int'}}
 }