Index: Sema/Sema.h =================================================================== --- Sema/Sema.h (revision 46191) +++ Sema/Sema.h (working copy) @@ -739,7 +739,11 @@ bool CheckSingleInitializer(Expr *&simpleInit, QualType declType); bool CheckInitExpr(Expr *expr, InitListExpr *IList, unsigned slot, QualType ElementType); - + +bool CheckInitializerListTypes(InitListExpr*& IList, QualType &DeclType, + bool topLevel, unsigned& startIndex); +bool IsStringLiteralInit(Expr* Expr, QualType& DeclType); + void CheckVariableInitList(QualType DeclType, InitListExpr *IList, QualType ElementType, int &nInitializers, bool &hadError); Index: Sema/SemaDecl.cpp =================================================================== --- Sema/SemaDecl.cpp (revision 46191) +++ Sema/SemaDecl.cpp (working copy) @@ -354,7 +354,208 @@ return dyn_cast_or_null(static_cast(DS.getTypeRep())); } +#if 1 +bool Sema::IsStringLiteralInit(Expr* InitExpr, QualType& DeclType) { + if (const VariableArrayType *VAT = DeclType->getAsVariableArrayType()) + if (VAT->getSizeExpr()) + return false; + if (StringLiteral *strLiteral = dyn_cast(InitExpr)) { + if (const ArrayType* arrType = DeclType->getAsArrayType()) { + // Note that we don't want to try and promote literal strings + // initializing arrays + QualType arrayElementType = arrType->getElementType(); + const ConstantArrayType* strArrayType = strLiteral->getType()->getAsConstantArrayType(); + QualType strElementType = strArrayType->getElementType(); + if (Context.typesAreCompatible(strElementType, arrayElementType)) { + if (const ConstantArrayType* CAT = arrType->getAsConstantArrayType()) { + if (strArrayType->getMaximumElements() > CAT->getMaximumElements() + 1) { + Diag(strLiteral->getSourceRange().getBegin(), + diag::warn_initializer_string_for_char_array_too_long, + strLiteral->getSourceRange()); + } + strLiteral->setType(DeclType); + } else { + llvm::APSInt ConstVal(32); + ConstVal = strArrayType->getMaximumElements(); + // Return a new array type (C99 6.7.8p22). + DeclType = Context.getConstantArrayType(arrType->getElementType(), ConstVal, + ArrayType::Normal, 0); + // set type from "char *" to "constant array of char". + strLiteral->setType(DeclType); + } + return true; + } + } + } + return false; +} +// CheckInitializerListTypes - Checks the types of elements of an initializer +// list. This function is recursive: it calls itself to initialize subelements +// of aggregate types. Note that the topLevel parameter essentially refers to +// whether this expression "owns" the initializer list passed in, or if this +// initialization is taking elements out of a parent initializer. Each +// call to this function adds zero or more to startIndex, reports any errors, +// and returns true if it found any inconsistent types. +bool Sema::CheckInitializerListTypes(InitListExpr*& IList, QualType &DeclType, + bool topLevel, unsigned& startIndex) { + bool hadError = false; + + if (DeclType->isScalarType()) { + // The simplest case: initializing a single scalar + // FIXME: allow initializer lists for vectors + if (topLevel) { + Diag(IList->getLocStart(), diag::warn_braces_around_scalar_init, + IList->getSourceRange()); + } + if (startIndex < IList->getNumInits()) { + Expr* expr = IList->getInit(startIndex); + if (InitListExpr *SubInitList = dyn_cast(expr)) { + // FIXME: Should an error be reported here instead? + unsigned newIndex = 0; + CheckInitializerListTypes(SubInitList, DeclType, true, newIndex); + } else { + hadError |= CheckInitExpr(expr, IList, startIndex, DeclType); + } + ++startIndex; + } + // FIXME: Should an error be reported for empty initializer list + scalar? + } else if (DeclType->isAggregateType() || DeclType->isUnionType()) { + if (DeclType->isStructureType() || DeclType->isUnionType()) { + if (startIndex < IList->getNumInits() && + Context.typesAreCompatible(IList->getInit(startIndex)->getType(), DeclType)) { + // We found a compatible struct; per the standard, this initializes the + // struct. (The C standard technically says that this only applies for + // initializers for declarations with automatic scope; however, this + // construct is unambiguous anyway because a struct cannot contain + // a type compatible with itself. We'll output an error when we check + // if the initializer is constant.) + // FIXME: Is a call to CheckSingleInitializer required here? + ++startIndex; + } else { + RecordDecl* structDecl = DeclType->getAsRecordType()->getDecl(); + // If structDecl is a forward declaration, this loop won't do anything; + // That's okay, because an error should get printed out elsewhere. + // It might be worthwhile to skip over the rest of the initializer, though. + int numMembers = structDecl->getNumMembers() - + structDecl->hasFlexibleArrayMember(); + for (int i = 0; i < numMembers; i++) { + // Don't attempt to go past the end of the init list + if (startIndex >= IList->getNumInits()) + break; + FieldDecl * curField = structDecl->getMember(i); + if (!curField->getIdentifier()) { + // Don't initialize unnamed fields, e.g. "int : 20;" + continue; + } + QualType fieldType = curField->getType(); + Expr* expr = IList->getInit(startIndex); + if (InitListExpr *SubInitList = dyn_cast(expr)) { + unsigned newStart = 0; + hadError |= CheckInitializerListTypes(SubInitList, fieldType, true, newStart); + ++startIndex; + } else { + hadError |= CheckInitializerListTypes(IList, fieldType, false, startIndex); + } + if (DeclType->isUnionType()) + break; + } + // FIXME: Implement flexible array initialization GCC extension (it's a really + // messy extension to implement, unfortunately... the information needed + // isn't actually even here!) + } + } else if (DeclType->isArrayType()) { + // Check for the special-case of initializing an array with a string. + if (startIndex < IList->getNumInits() && + IsStringLiteralInit(IList->getInit(startIndex), DeclType)) { + ++startIndex; + return false; + } + int maxElements; + if (const VariableArrayType *VAT = DeclType->getAsVariableArrayType()) { + // FIXME: use a proper constant + maxElements = 0x7FFFFFFF; + // Check for VLAs; in standard C it would be possible to check this + // earlier, but I don't know where clang accepts VLAs (gcc accepts + // them in all sorts of strange places). + if (const Expr *expr = VAT->getSizeExpr()) { + Diag(expr->getLocStart(), diag::err_variable_object_no_init, + expr->getSourceRange()); + hadError = true; + } + } else { + const ConstantArrayType *CAT = DeclType->getAsConstantArrayType(); + // FIXME: Is this really the right way to get this number? + maxElements = static_cast(CAT->getSize().getZExtValue()); + } + QualType elementType = DeclType->getAsArrayType()->getElementType(); + int numElements = 0; + for (int i = 0; i < maxElements; ++i, ++numElements) { + // Don't attempt to go past the end of the init list + if (startIndex >= IList->getNumInits()) + break; + Expr* expr = IList->getInit(startIndex); + if (InitListExpr *SubInitList = dyn_cast(expr)) { + unsigned newIndex = 0; + hadError |= CheckInitializerListTypes(SubInitList, elementType, true, newIndex); + ++startIndex; + } else { + hadError |= CheckInitializerListTypes(IList, elementType, false, startIndex); + } + } + if (DeclType->getAsVariableArrayType()) { + // If this is an incomplete array type, the actual type needs to + // be calculated here + if (numElements == 0) { + // Sizing an array implicitly to zero is not allowed + // (It could in theory be allowed, but it doesn't really + // matter.) + Diag(IList->getLocStart(), + diag::err_at_least_one_initializer_needed_to_size_array); + hadError = true; + } else { + llvm::APSInt ConstVal(32); + ConstVal = numElements; + DeclType = Context.getConstantArrayType(elementType, ConstVal, + ArrayType::Normal, 0); + } + } + } else { + assert(0 && "Aggregate that isn't a function or array?!"); + } + } else { + // In C, all types are either scalars or aggregates, but + // additional handling is needed here for C++ (and possibly others?). + assert(0 && "Unsupported initializer type"); + } + + // If this init list is a base list, we set the type; an initializer doesn't + // fundamentally have a type, but this makes the ASTs a bit easier to read + if (topLevel) + IList->setType(DeclType); + + if (topLevel && startIndex < IList->getNumInits()) { + // We have leftover initializers; warn + Diag(IList->getLocStart(), diag::warn_excess_initializers, + IList->getSourceRange()); + } + return hadError; +} + +bool Sema::CheckInitializerTypes(Expr *&Init, QualType& DeclType) { + InitListExpr *InitList = dyn_cast(Init); + if (!InitList) { + // Check if this is a string literal initializing an array; we check + // here because CheckSingleInitializer expects a regular assignment. + if (IsStringLiteralInit(Init, DeclType)) + return false; + return CheckSingleInitializer(Init, DeclType); + } + + unsigned newIndex = 0; + return CheckInitializerListTypes(InitList, DeclType, true, newIndex); +} +#endif bool Sema::CheckSingleInitializer(Expr *&Init, QualType DeclType) { // Get the type before calling CheckSingleAssignmentConstraints(), since // it can promote the expression. @@ -375,7 +576,7 @@ IList->setInit(slot, expr); return false; } - +#if 0 void Sema::CheckVariableInitList(QualType DeclType, InitListExpr *IList, QualType ElementType, int &nInitializers, bool &hadError) { @@ -596,7 +797,7 @@ // CompoundLiteralExpr... return hadError; } - +#endif Sema::DeclTy * Sema::ActOnDeclarator(Scope *S, Declarator &D, DeclTy *lastDecl) { ScopedDecl *LastDeclarator = dyn_cast_or_null((Decl *)lastDecl);