diff options
-rw-r--r-- | Sema/Sema.h | 7 | ||||
-rw-r--r-- | Sema/SemaDecl.cpp | 76 | ||||
-rw-r--r-- | Sema/SemaExpr.cpp | 6 | ||||
-rw-r--r-- | include/clang/Basic/DiagnosticKinds.def | 2 | ||||
-rw-r--r-- | test/Sema/array-init.c | 14 |
5 files changed, 73 insertions, 32 deletions
diff --git a/Sema/Sema.h b/Sema/Sema.h index a741657bf6..0979c607a0 100644 --- a/Sema/Sema.h +++ b/Sema/Sema.h @@ -442,10 +442,11 @@ private: IdentifierInfo &Comp, SourceLocation CmpLoc); /// type checking declaration initializers (C99 6.7.8) - QualType CheckInitializer(Expr *simpleInit_or_initList, QualType declType, - bool isStatic); + bool CheckInitializer(Expr *simpleInit_or_initList, QualType &declType, + bool isStatic); bool CheckSingleInitializer(Expr *simpleInit, QualType declType); - bool CheckInitList(InitListExpr *IList, QualType DType, bool isStatic); + void CheckInitList(InitListExpr *IList, QualType DType, bool isStatic, + int &nInitializers, int maxElements, bool &hadError); /// ConvertIntegerToTypeWarnOnOverflow - Convert the specified APInt to have /// the specified width and sign. If an overflow occurs, detect it and emit diff --git a/Sema/SemaDecl.cpp b/Sema/SemaDecl.cpp index c2f03a373c..15fe7c1033 100644 --- a/Sema/SemaDecl.cpp +++ b/Sema/SemaDecl.cpp @@ -289,15 +289,17 @@ bool Sema::CheckSingleInitializer(Expr *Init, QualType DeclType) { return false; } -bool Sema::CheckInitList(InitListExpr *IList, QualType DType, bool isStatic) { - bool hadError = false; +void Sema::CheckInitList(InitListExpr *IList, QualType DType, + bool isStatic, int &nInitializers, int maxElements, + bool &hadError) { for (unsigned i = 0; i < IList->getNumInits(); i++) { Expr *expr = IList->getInit(i); if (InitListExpr *InitList = dyn_cast<InitListExpr>(expr)) - CheckInitList(InitList, DType, isStatic); + CheckInitList(InitList, DType, isStatic, nInitializers, maxElements, + hadError); else { - SourceLocation loc; + SourceLocation loc = expr->getLocStart(); if (isStatic && !expr->isConstantExpr(Context, &loc)) { // C99 6.7.8p4. Diag(loc, diag::err_init_element_not_constant, expr->getSourceRange()); @@ -305,41 +307,71 @@ bool Sema::CheckInitList(InitListExpr *IList, QualType DType, bool isStatic) { } else if (CheckSingleInitializer(expr, DType)) { hadError = true; // types didn't match. } + // Does the element fit? + nInitializers++; + if ((maxElements >= 0) && (nInitializers > maxElements)) + Diag(loc, diag::warn_excess_initializers, expr->getSourceRange()); } } - return hadError; + return; } -QualType Sema::CheckInitializer(Expr *Init, QualType DeclType, bool isStatic) { +bool Sema::CheckInitializer(Expr *Init, QualType &DeclType, bool isStatic) { InitListExpr *InitList = dyn_cast<InitListExpr>(Init); - if (!InitList) { - return CheckSingleInitializer(Init, DeclType) ? QualType() : DeclType; - } + if (!InitList) + return CheckSingleInitializer(Init, DeclType); + // We have an InitListExpr, make sure we set the type. Init->setType(DeclType); + + bool hadError = false; + int nInits = 0; // 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 (expr) + return Diag(expr->getLocStart(), diag::err_variable_object_no_init, + expr->getSourceRange()); + + // We have a VariableArrayType with unknown size. + QualType ElmtType = VAT->getElementType(); + + // If we have a multi-dimensional array, navigate to the base type. + while ((VAT = ElmtType->getAsVariableArrayType())) { + ElmtType = VAT->getElementType(); + } + CheckInitList(InitList, ElmtType, isStatic, nInits, -1, hadError); + + if (!hadError) { + // Return a new array type from the number of initializers (C99 6.7.8p22). + llvm::APSInt ConstVal(32); + ConstVal = nInits; + DeclType = Context.getConstantArrayType(ElmtType, ConstVal, + ArrayType::Normal, 0); } + return hadError; } - if (const ArrayType *Ary = DeclType->getAsArrayType()) { - // We have a ConstantArrayType or VariableArrayType with unknown size. - QualType ElmtType = Ary->getElementType(); + if (const ConstantArrayType *CAT = DeclType->getAsConstantArrayType()) { + QualType ElmtType = CAT->getElementType(); + unsigned numElements = CAT->getSize().getZExtValue(); - // If we have a multi-dimensional array, navigate to the base type. - while ((Ary = ElmtType->getAsArrayType())) - ElmtType = Ary->getElementType(); - - CheckInitList(InitList, ElmtType, isStatic); + // If we have a multi-dimensional array, navigate to the base type. Also + // compute the absolute size of the array, so we can detect excess elements. + while ((CAT = ElmtType->getAsConstantArrayType())) { + ElmtType = CAT->getElementType(); + numElements *= CAT->getSize().getZExtValue(); + } + CheckInitList(InitList, ElmtType, isStatic, nInits, numElements, hadError); + return hadError; + } + if (DeclType->isScalarType()) { // C99 6.7.8p11 + CheckInitList(InitList, DeclType, isStatic, nInits, 1, hadError); + return hadError; } // FIXME: Handle struct/union types. - return DeclType; + return hadError; } Sema::DeclTy * diff --git a/Sema/SemaExpr.cpp b/Sema/SemaExpr.cpp index 8788c2f9dc..55b6d600c4 100644 --- a/Sema/SemaExpr.cpp +++ b/Sema/SemaExpr.cpp @@ -644,10 +644,8 @@ ParseInitList(SourceLocation LBraceLoc, ExprTy **initlist, unsigned NumInit, SourceLocation RBraceLoc) { Expr **InitList = reinterpret_cast<Expr**>(initlist); - // FIXME: add semantic analysis (C99 6.7.8). This involves - // knowledge of the object being intialized. As a result, the code for - // doing the semantic analysis will likely be located elsewhere (i.e. in - // consumers of InitListExpr (e.g. ParseDeclarator, ParseCompoundLiteral). + // Semantic analysis for initializers is done by ParseDeclarator() and + // CheckInitializer() - it requires knowledge of the object being intialized. InitListExpr *e = new InitListExpr(LBraceLoc, InitList, NumInit, RBraceLoc); e->setType(Context.VoidTy); // FIXME: just a place holder for now. diff --git a/include/clang/Basic/DiagnosticKinds.def b/include/clang/Basic/DiagnosticKinds.def index e396d95b55..85ed51bd79 100644 --- a/include/clang/Basic/DiagnosticKinds.def +++ b/include/clang/Basic/DiagnosticKinds.def @@ -550,6 +550,8 @@ 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(warn_excess_initializers, WARNING, + "excess elements in array initializer") DIAG(err_redefinition_of_label, ERROR, "redefinition of label '%0'") diff --git a/test/Sema/array-init.c b/test/Sema/array-init.c index 209b73463a..20daa45838 100644 --- a/test/Sema/array-init.c +++ b/test/Sema/array-init.c @@ -7,16 +7,16 @@ 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'}} +static int ary3[] = { 1, "abc", 3, 4 }; // expected-warning{{incompatible types assigning 'char *' to 'int'}} void func() { int x = 1; - //int x2[] = { 1, 3, 5 }; + int xComputeSize[] = { 1, 3, 5 }; 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}} + int x4 = { 1, 2 }; // // expected-warning{{excess elements in array initializer}} int y[4][3] = { { 1, 3, 5 }, @@ -28,6 +28,14 @@ void func() { 1, 3, 5, 2, 4, 6, 3, 5, 7 }; + int y3[4][3] = { + { 1, 3, 5 }, + { 2, 4, 6 }, + { 3, 5, 7 }, + { 4, 6, 8 }, + { 5 }, // expected-warning{{excess elements in array initializer}} + }; + struct threeElements { int a,b,c; } z = { 1 }; |