diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h index 9d7370735966f48cee597001dea592212e521537..a93f0f467b1834124dfc5af30f940a2a08510f84 100644 --- a/clang/include/clang/AST/Expr.h +++ b/clang/include/clang/AST/Expr.h @@ -1853,6 +1853,11 @@ public: Field.NameOrField = reinterpret_cast(FD); } + SourceLocation getDotLoc() const { + assert(Kind == FieldDesignator && "Only valid on a field designator"); + return SourceLocation::getFromRawEncoding(Field.DotLoc); + } + SourceLocation getFieldLoc() const { assert(Kind == FieldDesignator && "Only valid on a field designator"); return SourceLocation::getFromRawEncoding(Field.FieldLoc); diff --git a/clang/lib/Sema/Sema.h b/clang/lib/Sema/Sema.h index 9f1f2a3c3189ed3380c7056eb17b0a4beb7aae26..128ba8813a1f1a3f0c1eff6c1fcb4de427e90355 100644 --- a/clang/lib/Sema/Sema.h +++ b/clang/lib/Sema/Sema.h @@ -19,6 +19,7 @@ #include "CXXFieldCollector.h" #include "SemaOverload.h" #include "clang/AST/DeclBase.h" +#include "clang/AST/Expr.h" #include "clang/Parse/Action.h" #include "clang/Basic/Diagnostic.h" #include "llvm/ADT/SmallVector.h" @@ -1838,6 +1839,7 @@ class InitListChecker { unsigned &Index); void CheckListElementTypes(InitListExpr *IList, QualType &DeclType, + bool SubobjectIsDesignatorContext, unsigned &Index); void CheckSubElementType(InitListExpr *IList, QualType ElemType, Expr *expr, unsigned &Index); @@ -1846,11 +1848,17 @@ class InitListChecker { Expr *expr, unsigned &Index); void CheckVectorType(InitListExpr *IList, QualType DeclType, unsigned &Index); void CheckStructUnionTypes(InitListExpr *IList, QualType DeclType, - unsigned &Index); - void CheckArrayType(InitListExpr *IList, QualType &DeclType, unsigned &Index); + RecordDecl::field_iterator Field, + bool SubobjectIsDesignatorContext, unsigned &Index); + void CheckArrayType(InitListExpr *IList, QualType &DeclType, + llvm::APSInt elementIndex, + bool SubobjectIsDesignatorContext, unsigned &Index); bool CheckDesignatedInitializer(InitListExpr *IList, DesignatedInitExpr *DIE, - QualType DeclType, FieldDecl *&DesignatedField, - llvm::APSInt &DesignatedIndex, unsigned &Index); + DesignatedInitExpr::designators_iterator D, + QualType &CurrentObjectType, + RecordDecl::field_iterator *NextField, + llvm::APSInt *NextElementIndex, + unsigned &Index); int numArrayElements(QualType DeclType); int numStructUnionElements(QualType DeclType); public: diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index 163dac94b92bd486bf1e3f3d5c21b11bc0959a34..e855840ea5dffd1a955d09f76252e8c5ad5dbadb 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -74,7 +74,7 @@ void InitListChecker::CheckImplicitInitList(InitListExpr *ParentIList, // Check the element types *before* we create the implicit init list; // otherwise, we might end up taking the wrong number of elements unsigned NewIndex = Index; - CheckListElementTypes(ParentIList, T, NewIndex); + CheckListElementTypes(ParentIList, T, false, NewIndex); for (int i = 0; i < maxElements; ++i) { // Don't attempt to go past the end of the init list @@ -101,7 +101,7 @@ void InitListChecker::CheckExplicitInitList(InitListExpr *IList, QualType &T, unsigned &Index) { assert(IList->isExplicit() && "Illegal Implicit InitListExpr"); - CheckListElementTypes(IList, T, Index); + CheckListElementTypes(IList, T, true, Index); IList->setType(T); if (hadError) return; @@ -130,16 +130,22 @@ void InitListChecker::CheckExplicitInitList(InitListExpr *IList, QualType &T, void InitListChecker::CheckListElementTypes(InitListExpr *IList, QualType &DeclType, + bool SubobjectIsDesignatorContext, unsigned &Index) { if (DeclType->isScalarType()) { CheckScalarType(IList, DeclType, 0, Index); } else if (DeclType->isVectorType()) { CheckVectorType(IList, DeclType, Index); } else if (DeclType->isAggregateType() || DeclType->isUnionType()) { - if (DeclType->isStructureType() || DeclType->isUnionType()) - CheckStructUnionTypes(IList, DeclType, Index); - else if (DeclType->isArrayType()) - CheckArrayType(IList, DeclType, Index); + if (DeclType->isStructureType() || DeclType->isUnionType()) { + RecordDecl *RD = DeclType->getAsRecordType()->getDecl(); + CheckStructUnionTypes(IList, DeclType, RD->field_begin(), + SubobjectIsDesignatorContext, Index); + } else if (DeclType->isArrayType()) { + // FIXME: Is 32 always large enough for array indices? + llvm::APSInt Zero(32, false); + CheckArrayType(IList, DeclType, Zero, SubobjectIsDesignatorContext, Index); + } else assert(0 && "Aggregate that isn't a function or array?!"); } else if (DeclType->isVoidType() || DeclType->isFunctionType()) { @@ -239,6 +245,8 @@ void InitListChecker::CheckVectorType(InitListExpr *IList, QualType DeclType, } void InitListChecker::CheckArrayType(InitListExpr *IList, QualType &DeclType, + llvm::APSInt elementIndex, + bool SubobjectIsDesignatorContext, unsigned &Index) { // Check for the special-case of initializing an array with a string. if (Index < IList->getNumInits()) { @@ -263,7 +271,6 @@ void InitListChecker::CheckArrayType(InitListExpr *IList, QualType &DeclType, // FIXME: Will 32 bits always be enough? I hope so. const unsigned ArraySizeBits = 32; - llvm::APSInt elementIndex(ArraySizeBits, 0); // We might know the maximum number of elements in advance. llvm::APSInt maxElements(ArraySizeBits, 0); @@ -279,16 +286,25 @@ void InitListChecker::CheckArrayType(InitListExpr *IList, QualType &DeclType, while (Index < IList->getNumInits()) { Expr *Init = IList->getInit(Index); if (DesignatedInitExpr *DIE = dyn_cast(Init)) { - // C99 6.7.8p17: - // [...] In contrast, a designation causes the following - // initializer to begin initialization of the subobject - // described by the designator. - FieldDecl *DesignatedField = 0; - if (CheckDesignatedInitializer(IList, DIE, DeclType, DesignatedField, - elementIndex, Index)) + // If we're not the subobject that matches up with the '{' for + // the designator, we shouldn't be handling the + // designator. Return immediately. + if (!SubobjectIsDesignatorContext) + return; + + // Handle this designated initializer. elementIndex will be + // updated to be the next array element we'll initialize. + if (CheckDesignatedInitializer(IList, DIE, DIE->designators_begin(), + DeclType, 0, &elementIndex, Index)) { hadError = true; + continue; + } + + // If the array is of incomplete type, keep track of the number of + // elements in the initializer. + if (!maxElementsKnown && elementIndex > maxElements) + maxElements = elementIndex; - ++elementIndex; continue; } @@ -324,6 +340,8 @@ void InitListChecker::CheckArrayType(InitListExpr *IList, QualType &DeclType, void InitListChecker::CheckStructUnionTypes(InitListExpr *IList, QualType DeclType, + RecordDecl::field_iterator Field, + bool SubobjectIsDesignatorContext, unsigned &Index) { RecordDecl* structDecl = DeclType->getAsRecordType()->getDecl(); @@ -338,30 +356,23 @@ void InitListChecker::CheckStructUnionTypes(InitListExpr *IList, // because an error should get printed out elsewhere. It might be // worthwhile to skip over the rest of the initializer, though. RecordDecl *RD = DeclType->getAsRecordType()->getDecl(); - RecordDecl::field_iterator Field = RD->field_begin(), - FieldEnd = RD->field_end(); + RecordDecl::field_iterator FieldEnd = RD->field_end(); while (Index < IList->getNumInits()) { Expr *Init = IList->getInit(Index); if (DesignatedInitExpr *DIE = dyn_cast(Init)) { - // C99 6.7.8p17: - // [...] In contrast, a designation causes the following - // initializer to begin initialization of the subobject - // described by the designator. Initialization then continues - // forward in order, beginning with the next subobject after - // that described by the designator. - FieldDecl *DesignatedField = 0; - llvm::APSInt LastElement; - if (CheckDesignatedInitializer(IList, DIE, DeclType, DesignatedField, - LastElement, Index)) { + // If we're not the subobject that matches up with the '{' for + // the designator, we shouldn't be handling the + // designator. Return immediately. + if (!SubobjectIsDesignatorContext) + return; + + // Handle this designated initializer. Field will be updated to + // the next field that we'll be initializing. + if (CheckDesignatedInitializer(IList, DIE, DIE->designators_begin(), + DeclType, &Field, 0, Index)) hadError = true; - continue; - } - Field = RecordDecl::field_iterator( - DeclContext::decl_iterator(DesignatedField), - DeclType->getAsRecordType()->getDecl()->decls_end()); - ++Field; continue; } @@ -411,136 +422,177 @@ void InitListChecker::CheckStructUnionTypes(InitListExpr *IList, /// @param DeclType The type of the "current object" (C99 6.7.8p17), /// into which the designation in @p DIE should refer. /// -/// @param DesignatedField If the first designator in @p DIE is a field, -/// this will be set to the field declaration corresponding to the -/// field named by the designator. +/// @param NextField If non-NULL and the first designator in @p DIE is +/// a field, this will be set to the field declaration corresponding +/// to the field named by the designator. /// -/// @param DesignatedIndex If the first designator in @p DIE is an -/// array designator or GNU array-range designator, this will be set -/// to the last index initialized by this designator. +/// @param NextElementIndex If non-NULL and the first designator in @p +/// DIE is an array designator or GNU array-range designator, this +/// will be set to the last index initialized by this designator. /// /// @param Index Index into @p IList where the designated initializer /// @p DIE occurs. /// /// @returns true if there was an error, false otherwise. -bool InitListChecker::CheckDesignatedInitializer(InitListExpr *IList, - DesignatedInitExpr *DIE, - QualType DeclType, - FieldDecl *&DesignatedField, - llvm::APSInt &DesignatedIndex, - unsigned &Index) { - // DeclType is always the type of the "current object" (C99 6.7.8p17). - - for (DesignatedInitExpr::designators_iterator D = DIE->designators_begin(), - DEnd = DIE->designators_end(); - D != DEnd; ++D) { - if (D->isFieldDesignator()) { - // C99 6.7.8p7: - // - // If a designator has the form - // - // . identifier - // - // then the current object (defined below) shall have - // structure or union type and the identifier shall be the - // name of a member of that type. - const RecordType *RT = DeclType->getAsRecordType(); - if (!RT) { - SemaRef->Diag(DIE->getSourceRange().getBegin(), - diag::err_field_designator_non_aggr) - << SemaRef->getLangOptions().CPlusPlus << DeclType; - ++Index; - return true; - } +bool +InitListChecker::CheckDesignatedInitializer(InitListExpr *IList, + DesignatedInitExpr *DIE, + DesignatedInitExpr::designators_iterator D, + QualType &CurrentObjectType, + RecordDecl::field_iterator *NextField, + llvm::APSInt *NextElementIndex, + unsigned &Index) { + bool IsFirstDesignator = (D == DIE->designators_begin()); - IdentifierInfo *FieldName = D->getFieldName(); - DeclContext::lookup_result Lookup = RT->getDecl()->lookup(FieldName); - FieldDecl *ThisField = 0; - if (Lookup.first == Lookup.second) { - // Lookup did not find anything with this name. - SemaRef->Diag(D->getFieldLoc(), diag::err_field_designator_unknown) - << FieldName << DeclType; - } else if (isa(*Lookup.first)) { - // Name lookup found a field. - ThisField = cast(*Lookup.first); - // FIXME: Make sure this isn't a field in an anonymous - // struct/union. - } else { - // Name lookup found something, but it wasn't a field. - SemaRef->Diag(D->getFieldLoc(), diag::err_field_designator_nonfield) - << FieldName; - SemaRef->Diag((*Lookup.first)->getLocation(), - diag::note_field_designator_found); - } + if (D == DIE->designators_end()) { + // Check the actual initialization for the designated object type. + bool prevHadError = hadError; + CheckSubElementType(IList, CurrentObjectType, DIE->getInit(), Index); + return hadError && !prevHadError; + } - if (!ThisField) { - ++Index; - return true; - } + if (D->isFieldDesignator()) { + // C99 6.7.8p7: + // + // If a designator has the form + // + // . identifier + // + // then the current object (defined below) shall have + // structure or union type and the identifier shall be the + // name of a member of that type. + const RecordType *RT = CurrentObjectType->getAsRecordType(); + if (!RT) { + SourceLocation Loc = D->getDotLoc(); + if (Loc.isInvalid()) + Loc = D->getFieldLoc(); + SemaRef->Diag(Loc, diag::err_field_designator_non_aggr) + << SemaRef->getLangOptions().CPlusPlus << CurrentObjectType; + ++Index; + return true; + } + + IdentifierInfo *FieldName = D->getFieldName(); + DeclContext::lookup_result Lookup = RT->getDecl()->lookup(FieldName); + FieldDecl *DesignatedField = 0; + if (Lookup.first == Lookup.second) { + // Lookup did not find anything with this name. + SemaRef->Diag(D->getFieldLoc(), diag::err_field_designator_unknown) + << FieldName << CurrentObjectType; + } else if (isa(*Lookup.first)) { + // Name lookup found a field. + DesignatedField = cast(*Lookup.first); + // FIXME: Make sure this isn't a field in an anonymous + // struct/union. + } else { + // Name lookup found something, but it wasn't a field. + SemaRef->Diag(D->getFieldLoc(), diag::err_field_designator_nonfield) + << FieldName; + SemaRef->Diag((*Lookup.first)->getLocation(), + diag::note_field_designator_found); + } + + if (!DesignatedField) { + ++Index; + return true; + } - // Update the designator with the field declaration. - D->setField(ThisField); + // Update the designator with the field declaration. + D->setField(DesignatedField); - if (D == DIE->designators_begin()) - DesignatedField = ThisField; + // Recurse to check later designated subobjects. + QualType FieldType = DesignatedField->getType(); + if (CheckDesignatedInitializer(IList, DIE, ++D, FieldType, 0, 0, Index)) + return true; + + // Find the position of the next field to be initialized in this + // subobject. + RecordDecl::field_iterator Field(DeclContext::decl_iterator(DesignatedField), + RT->getDecl()->decls_end()); + ++Field; - // The current object is now the type of this field. - DeclType = ThisField->getType(); - } else { - // C99 6.7.8p6: - // - // If a designator has the form - // - // [ constant-expression ] - // - // then the current object (defined below) shall have array - // type and the expression shall be an integer constant - // expression. If the array is of unknown size, any - // nonnegative value is valid. - const ArrayType *AT = SemaRef->Context.getAsArrayType(DeclType); - if (!AT) { - SemaRef->Diag(D->getLBracketLoc(), diag::err_array_designator_non_array) - << DeclType; - ++Index; - return true; - } + // If this the first designator, our caller will continue checking + // the rest of this struct/class/union subobject. + if (IsFirstDesignator) { + if (NextField) + *NextField = Field; + return false; + } - Expr *IndexExpr = 0; - llvm::APSInt ThisIndex; - if (D->isArrayDesignator()) - IndexExpr = DIE->getArrayIndex(*D); - else { - assert(D->isArrayRangeDesignator() && "Need array-range designator"); - IndexExpr = DIE->getArrayRangeEnd(*D); - } + // Check the remaining fields within this class/struct/union subobject. + bool prevHadError = hadError; + CheckStructUnionTypes(IList, CurrentObjectType, Field, false, Index); + return hadError && !prevHadError; + } - bool ConstExpr - = IndexExpr->isIntegerConstantExpr(ThisIndex, SemaRef->Context); - assert(ConstExpr && "Expression must be constant"); (void)ConstExpr; - - if (isa(AT)) { - llvm::APSInt MaxElements(cast(AT)->getSize(), false); - if (ThisIndex >= MaxElements) { - SemaRef->Diag(IndexExpr->getSourceRange().getBegin(), - diag::err_array_designator_too_large) - << ThisIndex.toString(10) << MaxElements.toString(10); - ++Index; - return true; - } - } + // C99 6.7.8p6: + // + // If a designator has the form + // + // [ constant-expression ] + // + // then the current object (defined below) shall have array + // type and the expression shall be an integer constant + // expression. If the array is of unknown size, any + // nonnegative value is valid. + // + // Additionally, cope with the GNU extension that permits + // designators of the form + // + // [ constant-expression ... constant-expression ] + const ArrayType *AT = SemaRef->Context.getAsArrayType(CurrentObjectType); + if (!AT) { + SemaRef->Diag(D->getLBracketLoc(), diag::err_array_designator_non_array) + << CurrentObjectType; + ++Index; + return true; + } - if (D == DIE->designators_begin()) - DesignatedIndex = ThisIndex; + Expr *IndexExpr = 0; + llvm::APSInt DesignatedIndex; + if (D->isArrayDesignator()) + IndexExpr = DIE->getArrayIndex(*D); + else { + assert(D->isArrayRangeDesignator() && "Need array-range designator"); + IndexExpr = DIE->getArrayRangeEnd(*D); + } - // The current object is now the element type of this array. - DeclType = AT->getElementType(); + bool ConstExpr + = IndexExpr->isIntegerConstantExpr(DesignatedIndex, SemaRef->Context); + assert(ConstExpr && "Expression must be constant"); (void)ConstExpr; + + if (isa(AT)) { + llvm::APSInt MaxElements(cast(AT)->getSize(), false); + if (DesignatedIndex >= MaxElements) { + SemaRef->Diag(IndexExpr->getSourceRange().getBegin(), + diag::err_array_designator_too_large) + << DesignatedIndex.toString(10) << MaxElements.toString(10) + << IndexExpr->getSourceRange(); + ++Index; + return true; } } - - // Check the actual initialization for the designated object type. + + // Recurse to check later designated subobjects. + QualType ElementType = AT->getElementType(); + if (CheckDesignatedInitializer(IList, DIE, ++D, ElementType, 0, 0, Index)) + return true; + + // Move to the next index in the array that we'll be initializing. + ++DesignatedIndex; + + // If this the first designator, our caller will continue checking + // the rest of this array subobject. + if (IsFirstDesignator) { + if (NextElementIndex) + *NextElementIndex = DesignatedIndex; + return false; + } + + // Check the remaining elements within this array subobject. bool prevHadError = hadError; - CheckSubElementType(IList, DeclType, DIE->getInit(), Index); - return hadError && !prevHadError; + CheckArrayType(IList, CurrentObjectType, DesignatedIndex, true, Index); + return hadError && !prevHadError; } /// Check that the given Index expression is a valid array designator diff --git a/clang/test/Sema/designated-initializers.c b/clang/test/Sema/designated-initializers.c index 5efb4444956bc3612d756c639a02cc2788b83abb..cc2c3468edc3aa603e90dc86711c4aa719c3acac 100644 --- a/clang/test/Sema/designated-initializers.c +++ b/clang/test/Sema/designated-initializers.c @@ -1,5 +1,9 @@ // RUN: clang -fsyntax-only -verify %s +int complete_array_from_init[] = { 1, 2, [10] = 5, 1, 2, [5] = 2, 6 }; + +int complete_array_from_init_check[((sizeof(complete_array_from_init) / sizeof(int)) == 13)? 1 : -1]; + int iarray[10] = { [0] = 1, [1 ... 5] = 2, @@ -11,6 +15,9 @@ int iarray[10] = { int iarray2[10] = { [10] = 1, // expected-error{{array designator index (10) exceeds array bounds (10)}} +}; + +int iarray3[10] = { [5 ... 12] = 2 // expected-error{{array designator index (12) exceeds array bounds (10)}} }; @@ -23,7 +30,9 @@ struct point p1 = { .y = 1.0, x: 2.0, .a = 4.0, // expected-error{{field designator 'a' does not refer to any field in type 'struct point'}} +}; +struct point p2 = { [1] = 1.0 // expected-error{{array designator cannot initialize non-array type}} }; @@ -31,9 +40,15 @@ struct point array[10] = { [0].x = 1.0, [1].y = 2.0, [2].z = 3.0, // expected-error{{field designator 'z' does not refer to any field in type 'struct point'}} +}; + +struct point array2[10] = { [10].x = 2.0, // expected-error{{array designator index (10) exceeds array bounds (10)}} [4 ... 5].y = 2.0, - [4 ... 6] = { .x = 3, .y = 4.0 }, + [4 ... 6] = { .x = 3, .y = 4.0 } +}; + +struct point array3[10] = { .x = 5 // expected-error{{field designator cannot initialize a non-struct, non-union type}} }; @@ -76,3 +91,24 @@ struct translator { .wonky = { 0 } }; +int anint; +struct {int x,*y;} z[] = {[0].x = 2, &z[0].x}; + +struct outer { struct inner { int x, *y; } in, *inp; } zz[] = { + [0].in.x = 2, &zz[0].in.x, &zz[0].in, + 0, &anint, &zz[1].in, + [3].in = { .y = &anint, .x = 17 }, + [7].in.y = &anint, &zz[0].in, + [4].in.y = &anint, [5].in.x = 12 +}; + +int zz_sizecheck[sizeof(zz) / sizeof(struct outer) == 8? 1 : -1 ]; + +struct disklabel_ops { + struct {} type; + int labelsize; +}; + +struct disklabel_ops disklabel64_ops = { + .labelsize = sizeof(struct disklabel_ops) +};