From: Steve Naroff Date: Tue, 4 Sep 2007 02:20:04 +0000 (+0000) Subject: More fun with initializers! X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=371227d6dc3cf89a3165d592cd9a4cbb400ec45c;p=clang More fun with initializers! - Fixed many bugs, enhanced test case considerably, added a diagnostic, etc. - Refactored CheckInitList() into CheckVariableInitList()/CheckConstantInitList(). - Added CheckInitExpr(). - Support for multi-dimensional arrays looking good. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@41690 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/Sema/Sema.h b/Sema/Sema.h index 0979c607a0..ff3ec1bfbc 100644 --- a/Sema/Sema.h +++ b/Sema/Sema.h @@ -445,9 +445,14 @@ private: bool CheckInitializer(Expr *simpleInit_or_initList, QualType &declType, bool isStatic); bool CheckSingleInitializer(Expr *simpleInit, QualType declType); - void CheckInitList(InitListExpr *IList, QualType DType, bool isStatic, - int &nInitializers, int maxElements, bool &hadError); - + bool CheckInitExpr(Expr *expr, bool isStatic, QualType ElementType); + void CheckVariableInitList(QualType DeclType, InitListExpr *IList, + QualType ElementType, bool isStatic, + int &nInitializers, bool &hadError); + void CheckConstantInitList(QualType DeclType, InitListExpr *IList, + QualType ElementType, bool isStatic, + int &nInitializers, bool &hadError); + /// ConvertIntegerToTypeWarnOnOverflow - Convert the specified APInt to have /// the specified width and sign. If an overflow occurs, detect it and emit /// the specified diagnostic. diff --git a/Sema/SemaDecl.cpp b/Sema/SemaDecl.cpp index 15fe7c1033..f478bf3df9 100644 --- a/Sema/SemaDecl.cpp +++ b/Sema/SemaDecl.cpp @@ -289,29 +289,101 @@ bool Sema::CheckSingleInitializer(Expr *Init, QualType DeclType) { return false; } -void Sema::CheckInitList(InitListExpr *IList, QualType DType, - bool isStatic, int &nInitializers, int maxElements, - bool &hadError) { +bool Sema::CheckInitExpr(Expr *expr, bool isStatic, QualType ElementType) { + SourceLocation loc; + + if (isStatic && !expr->isConstantExpr(Context, &loc)) { // C99 6.7.8p4. + Diag(loc, diag::err_init_element_not_constant, expr->getSourceRange()); + return true; + } else if (CheckSingleInitializer(expr, ElementType)) { + return true; // types weren't compatible. + } + return false; +} + +void Sema::CheckVariableInitList(QualType DeclType, InitListExpr *IList, + QualType ElementType, bool isStatic, + int &nInitializers, bool &hadError) { for (unsigned i = 0; i < IList->getNumInits(); i++) { Expr *expr = IList->getInit(i); - if (InitListExpr *InitList = dyn_cast(expr)) - CheckInitList(InitList, DType, isStatic, nInitializers, maxElements, - hadError); - else { - SourceLocation loc = expr->getLocStart(); + if (InitListExpr *InitList = dyn_cast(expr)) { + if (const ConstantArrayType *CAT = DeclType->getAsConstantArrayType()) { + QualType ElmtType = CAT->getElementType(); + int maxElements = CAT->getSize().getZExtValue(); + + // If we have a multi-dimensional array, navigate to the base type. Also + // compute the absolute array, so we can detect excess elements. + while ((CAT = ElmtType->getAsConstantArrayType())) { + ElmtType = CAT->getElementType(); + maxElements *= CAT->getSize().getZExtValue(); + } + CheckConstantInitList(DeclType, InitList, ElementType, isStatic, + maxElements, hadError); + } + } else { + hadError = CheckInitExpr(expr, isStatic, ElementType); + } + nInitializers++; + } + return; +} - 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. +// FIXME: Doesn't deal with arrays of structures yet. +void Sema::CheckConstantInitList(QualType DeclType, InitListExpr *IList, + QualType ElementType, bool isStatic, + int &totalInits, bool &hadError) { + int maxElementsAtThisLevel = 0; + int nInitsAtLevel = 0; + + if (const ConstantArrayType *CAT = DeclType->getAsConstantArrayType()) { + // We have a constant array type, compute maxElements *at this level*. + QualType ElmtType = CAT->getElementType(); + maxElementsAtThisLevel = CAT->getSize().getZExtValue(); + + // Set DeclType, important for correctly handling multi-dimensional arrays. + DeclType = ElmtType; + + // If we have a multi-dimensional array, navigate to the base type. Also + // compute the absolute size of the array *at this level* array, so we can + // detect excess elements. + while ((CAT = ElmtType->getAsConstantArrayType())) { + ElmtType = CAT->getElementType(); + maxElementsAtThisLevel *= CAT->getSize().getZExtValue(); + } + } else if (DeclType->isScalarType()) { + Diag(IList->getLocStart(), diag::warn_braces_around_scalar_init, + IList->getSourceRange()); + maxElementsAtThisLevel = 1; + } + // The empty init list "{ }" is treated specially below. + unsigned numInits = IList->getNumInits(); + if (numInits) { + for (unsigned i = 0; i < numInits; i++) { + Expr *expr = IList->getInit(i); + + if (InitListExpr *InitList = dyn_cast(expr)) { + CheckConstantInitList(DeclType, InitList, ElementType, isStatic, + totalInits, hadError); + } else { + hadError = CheckInitExpr(expr, isStatic, ElementType); + nInitsAtLevel++; // increment the number of initializers at this level. + totalInits--; // decrement the total number of initializers. + + // Check if we have space for another initializer. + if ((nInitsAtLevel > maxElementsAtThisLevel) || (totalInits < 0)) + Diag(expr->getLocStart(), diag::warn_excess_initializers, + expr->getSourceRange()); } - // Does the element fit? - nInitializers++; - if ((maxElements >= 0) && (nInitializers > maxElements)) - Diag(loc, diag::warn_excess_initializers, expr->getSourceRange()); } + if (nInitsAtLevel < maxElementsAtThisLevel) // fill the remaining elements. + totalInits -= (maxElementsAtThisLevel - nInitsAtLevel); + } else { + // we have an initializer list with no elements. + totalInits -= maxElementsAtThisLevel; + if (totalInits < 0) + Diag(IList->getLocStart(), diag::warn_excess_initializers, + IList->getSourceRange()); } return; } @@ -325,7 +397,6 @@ bool Sema::CheckInitializer(Expr *Init, QualType &DeclType, bool isStatic) { 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. @@ -338,36 +409,46 @@ bool Sema::CheckInitializer(Expr *Init, QualType &DeclType, bool isStatic) { // We have a VariableArrayType with unknown size. QualType ElmtType = VAT->getElementType(); + // Set DeclType, important for correctly handling multi-dimensional arrays. + DeclType = ElmtType; + // If we have a multi-dimensional array, navigate to the base type. - while ((VAT = ElmtType->getAsVariableArrayType())) { - ElmtType = VAT->getElementType(); + // Use getAsArrayType(), since it is illegal for an array to have an + // incomplete element type. For example, "int [][]" is illegal. + const ArrayType *ATY; + while ((ATY = ElmtType->getAsArrayType())) { + ElmtType = ATY->getElementType(); } - CheckInitList(InitList, ElmtType, isStatic, nInits, -1, hadError); - + int numInits = 0; + CheckVariableInitList(DeclType, InitList, ElmtType, isStatic, numInits, + 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, + ConstVal = numInits; + DeclType = Context.getConstantArrayType(DeclType, ConstVal, ArrayType::Normal, 0); } return hadError; } if (const ConstantArrayType *CAT = DeclType->getAsConstantArrayType()) { QualType ElmtType = CAT->getElementType(); - unsigned numElements = CAT->getSize().getZExtValue(); + int maxElements = CAT->getSize().getZExtValue(); // 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(); + maxElements *= CAT->getSize().getZExtValue(); } - CheckInitList(InitList, ElmtType, isStatic, nInits, numElements, hadError); + CheckConstantInitList(DeclType, InitList, ElmtType, isStatic, maxElements, + hadError); return hadError; } - if (DeclType->isScalarType()) { // C99 6.7.8p11 - CheckInitList(InitList, DeclType, isStatic, nInits, 1, hadError); + if (DeclType->isScalarType()) { // C99 6.7.8p11: Allow "int x = { 1, 2 };" + int maxElements = 1; + CheckConstantInitList(DeclType, InitList, DeclType, isStatic, maxElements, + hadError); return hadError; } // FIXME: Handle struct/union types. @@ -476,7 +557,8 @@ Sema::ParseDeclarator(Scope *S, Declarator &D, ExprTy *init, if (Init) { if (SC == VarDecl::Extern) Diag(D.getIdentifierLoc(), diag::warn_extern_init); - CheckInitializer(Init, R, true); + if (!D.getInvalidType()) + CheckInitializer(Init, R, true); } // File scope. C99 6.9.2p2: A declaration of an identifier for and // object that has file scope without an initializer, and without a @@ -520,7 +602,7 @@ Sema::ParseDeclarator(Scope *S, Declarator &D, ExprTy *init, if (SC == VarDecl::Extern) { // C99 6.7.8p5 Diag(D.getIdentifierLoc(), diag::err_block_extern_cant_init); InvalidDecl = true; - } else { + } else if (!D.getInvalidType()) { CheckInitializer(Init, R, SC == VarDecl::Static); } } diff --git a/include/clang/Basic/DiagnosticKinds.def b/include/clang/Basic/DiagnosticKinds.def index 85ed51bd79..9ccfe6390e 100644 --- a/include/clang/Basic/DiagnosticKinds.def +++ b/include/clang/Basic/DiagnosticKinds.def @@ -552,6 +552,8 @@ 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(warn_braces_around_scalar_init, WARNING, + "braces around scalar 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 20daa45838..98387bedd0 100644 --- a/test/Sema/array-init.c +++ b/test/Sema/array-init.c @@ -16,7 +16,7 @@ void func() { int x3[x] = { 1, 2 }; // expected-error{{variable-sized object may not be initialized}} - int x4 = { 1, 2 }; // // expected-warning{{excess elements in array initializer}} + int x4 = { 1, 2 }; // expected-warning{{braces around scalar initializer}} expected-warning{{excess elements in array initializer}} int y[4][3] = { { 1, 3, 5 }, @@ -46,3 +46,85 @@ void func() { static int x2[3] = { 1.0, "abc" , 5.8 }; // expected-warning{{incompatible types assigning 'char *' to 'int'}} } + +void test() { + int y1[3] = { + { 1, 2, 3 } // expected-warning{{braces around scalar initializer}} expected-warning{{excess elements in array initializer}} + }; + int y3[4][3] = { + { 1, 3, 5 }, + { 2, 4, 6 }, + { 3, 5, 7 }, + { 4, 6, 8 }, + { }, // expected-warning{{use of GNU empty initializer extension}} expected-warning{{excess elements in array initializer}} + }; + int y4[4][3] = { + { 1, 3, 5, 2 }, // expected-warning{{excess elements in array initializer}} + { 4, 6 }, + { 3, 5, 7 }, + { 4, 6, 8 }, // expected-warning{{excess elements in array initializer}} + }; +} + +void allLegalAndSynonymous() { + short q[4][3][2] = { + { 1 }, + { 2, 3 }, + { 4, 5, 6 } + }; + short q2[4][3][2] = { + { 1, 0, 0, 0, 0, 0 }, + { 2, 3, 0, 0, 0, 0 }, + { 4, 5, 6 } + }; + short q3[4][3][2] = { + { + { 1 }, + }, + { + { 2, 3 }, + }, + { + { 4, 5 }, + { 6 }, + }, + }; +} + +void legal() { + short q[][3][2] = { + { 1 }, + { 2, 3 }, + { 4, 5, 6 } + }; +} + +void illegal() { + short q2[4][][2] = { // expected-error{{array has incomplete element type 'short [][2]'}} + { 1, 0, 0, 0, 0, 0 }, + { 2, 3, 0, 0, 0, 0 }, + { 4, 5, 6 } + }; + short q3[4][3][] = { // expected-error{{array has incomplete element type 'short []'}} + { + { 1 }, + }, + { + { 2, 3 }, + }, + { + { 4, 5 }, + { 6 }, + }, + }; + // FIXME: the following two errors are redundant + int a[][] = { 1, 2 }; // expected-error{{array has incomplete element type 'int []'}} expected-error{{variable has incomplete type 'int []'}} +} + +typedef int AryT[]; + +void testTypedef() +{ + AryT a = { 1, 2 }, b = { 3, 4, 5 }; +} +