diff --git a/clang/Driver/RewriteObjC.cpp b/clang/Driver/RewriteObjC.cpp index 4524920f5a5a..e2ddafe8d192 100644 --- a/clang/Driver/RewriteObjC.cpp +++ b/clang/Driver/RewriteObjC.cpp @@ -2310,7 +2310,7 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp) { // (struct objc_super) { } InitListExpr *ILE = new InitListExpr(SourceLocation(), &InitExprs[0], InitExprs.size(), - SourceLocation(), false); + SourceLocation()); SuperRep = new CompoundLiteralExpr(SourceLocation(), superType, ILE, false); // struct objc_super * @@ -2391,7 +2391,7 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp) { // (struct objc_super) { } InitListExpr *ILE = new InitListExpr(SourceLocation(), &InitExprs[0], InitExprs.size(), - SourceLocation(), false); + SourceLocation()); SuperRep = new CompoundLiteralExpr(SourceLocation(), superType, ILE, false); } MsgExprs.push_back(SuperRep); diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h index 988a7419a599..18d1c0546791 100644 --- a/clang/include/clang/AST/Decl.h +++ b/clang/include/clang/AST/Decl.h @@ -678,6 +678,9 @@ public: /// isBitfield - Determines whether this field is a bitfield. bool isBitField() const { return BitWidth != NULL; } + /// @brief Determines whether this is an unnamed bitfield. + bool isUnnamedBitfield() const { return BitWidth != NULL && !getDeclName(); } + /// isAnonymousStructOrUnion - Determines whether this field is a /// representative for an anonymous struct or union. Such fields are /// unnamed and are implicitly generated by the implementation to diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h index 5d768cd9dba3..861ac817ccac 100644 --- a/clang/include/clang/AST/Expr.h +++ b/clang/include/clang/AST/Expr.h @@ -185,6 +185,10 @@ public: /// initializer, which can be emitted at compile-time. bool isConstantInitializer(ASTContext &Ctx) const; + /// @brief Determines whether this expression (or any of its + /// subexpressions) has side effects. + bool hasSideEffects(ASTContext &Ctx) const; + /// EvalResult is a struct with detailed info about an evaluated expression. struct EvalResult { /// Val - This is the scalar value the expression can be folded to. @@ -1619,48 +1623,65 @@ public: static VAArgExpr* CreateImpl(llvm::Deserializer& D, ASTContext& C); }; -/// InitListExpr - used for struct and array initializers, such as: -/// struct foo x = { 1, { 2, 3 } }; +/// @brief Describes an C or C++ initializer list. /// -/// Because C is somewhat loose with braces, the AST does not necessarily -/// directly model the C source. Instead, the semantic analyzer aims to make -/// the InitListExprs match up with the type of the decl being initialized. We -/// have the following exceptions: +/// InitListExpr describes an initializer list, which can be used to +/// initialize objects of different types, including +/// struct/class/union types, arrays, and vectors. For example: /// -/// 1. Elements at the end of the list may be dropped from the initializer. -/// These elements are defined to be initialized to zero. For example: -/// int x[20] = { 1 }; -/// 2. Initializers may have excess initializers which are to be ignored by the -/// compiler. For example: -/// int x[1] = { 1, 2 }; -/// 3. Redundant InitListExprs may be present around scalar elements. These -/// always have a single element whose type is the same as the InitListExpr. -/// this can only happen for Type::isScalarType() types. -/// int x = { 1 }; int y[2] = { {1}, {2} }; +/// @code +/// struct foo x = { 1, { 2, 3 } }; +/// @endcode /// +/// Prior to semantic analysis, an initializer list will represent the +/// initializer list as written by the user, but will have the +/// placeholder type "void". This initializer list is called the +/// syntactic form of the initializer, and may contain C99 designated +/// initializers (represented as DesignatedInitExprs), initializations +/// of subobject members without explicit braces, and so on. Clients +/// interested in the original syntax of the initializer list should +/// use the syntactic form of the initializer list. +/// +/// After semantic analysis, the initializer list will represent the +/// semantic form of the initializer, where the initializations of all +/// subobjects are made explicit with nested InitListExpr nodes and +/// C99 designators have been eliminated by placing the designated +/// initializations into the subobject they initialize. Additionally, +/// any "holes" in the initialization, where no initializer has been +/// specified for a particular subobject, will be replaced with +/// implicitly-generated CXXZeroInitValueExpr expressions that +/// value-initialize the subobjects. Note, however, that the +/// initializer lists may still have fewer initializers than there are +/// elements to initialize within the object. +/// +/// Given the semantic form of the initializer list, one can retrieve +/// the original syntactic form of that initializer list (if it +/// exists) using getSyntacticForm(). Since many initializer lists +/// have the same syntactic and semantic forms, getSyntacticForm() may +/// return NULL, indicating that the current initializer list also +/// serves as its syntactic form. class InitListExpr : public Expr { std::vector InitExprs; SourceLocation LBraceLoc, RBraceLoc; - /// HadDesignators - Return true if there were any designators in this - /// init list expr. FIXME: this should be replaced by storing the designators - /// somehow and updating codegen. - bool HadDesignators; + /// Contains the initializer list that describes the syntactic form + /// written in the source code. + InitListExpr *SyntacticForm; + public: InitListExpr(SourceLocation lbraceloc, Expr **initexprs, unsigned numinits, - SourceLocation rbraceloc, bool HadDesignators); + SourceLocation rbraceloc); unsigned getNumInits() const { return InitExprs.size(); } - bool hadDesignators() const { return HadDesignators; } const Expr* getInit(unsigned Init) const { assert(Init < getNumInits() && "Initializer access out of range!"); - return cast(InitExprs[Init]); + return cast_or_null(InitExprs[Init]); } Expr* getInit(unsigned Init) { assert(Init < getNumInits() && "Initializer access out of range!"); - return cast(InitExprs[Init]); + return cast_or_null(InitExprs[Init]); } void setInit(unsigned Init, Expr *expr) { @@ -1668,13 +1689,22 @@ public: InitExprs[Init] = expr; } - // Dynamic removal/addition (for constructing implicit InitExpr's). - void removeInit(unsigned Init) { - InitExprs.erase(InitExprs.begin()+Init); - } - void addInit(unsigned Init, Expr *expr) { - InitExprs.insert(InitExprs.begin()+Init, expr); - } + /// @brief Specify the number of initializers + /// + /// If there are more than @p NumInits initializers, the remaining + /// initializers will be destroyed. If there are fewer than @p + /// NumInits initializers, NULL expressions will be added for the + /// unknown initializers. + void resizeInits(ASTContext &Context, unsigned NumInits); + + /// @brief Updates the initializer at index @p Init with the new + /// expression @p expr, and returns the old expression at that + /// location. + /// + /// When @p Init is out of range for this initializer list, the + /// initializer list will be extended with NULL expressions to + /// accomodate the new entry. + Expr *updateInit(unsigned Init, Expr *expr); // Explicit InitListExpr's originate from source code (and have valid source // locations). Implicit InitListExpr's are created by the semantic analyzer. @@ -1682,6 +1712,13 @@ public: return LBraceLoc.isValid() && RBraceLoc.isValid(); } + /// @brief Retrieve the initializer list that describes the + /// syntactic form of the initializer. + /// + /// + InitListExpr *getSyntacticForm() const { return SyntacticForm; } + void setSyntacticForm(InitListExpr *Init) { SyntacticForm = Init; } + virtual SourceRange getSourceRange() const { return SourceRange(LBraceLoc, RBraceLoc); } @@ -1885,6 +1922,13 @@ public: "Only valid on an array-range designator"); return SourceLocation::getFromRawEncoding(ArrayOrRange.EllipsisLoc); } + + SourceLocation getStartLocation() const { + if (Kind == FieldDesignator) + return getDotLoc().isInvalid()? getFieldLoc() : getDotLoc(); + else + return getLBracketLoc(); + } }; static DesignatedInitExpr *Create(ASTContext &C, Designator *Designators, diff --git a/clang/include/clang/AST/ExprCXX.h b/clang/include/clang/AST/ExprCXX.h index 669e790b3996..4f48eb3716a9 100644 --- a/clang/include/clang/AST/ExprCXX.h +++ b/clang/include/clang/AST/ExprCXX.h @@ -477,6 +477,12 @@ public: SourceLocation getTypeBeginLoc() const { return TyBeginLoc; } SourceLocation getRParenLoc() const { return RParenLoc; } + /// @brief Whether this initialization expression was + /// implicitly-generated. + bool isImplicit() const { + return TyBeginLoc.isInvalid() && RParenLoc.isInvalid(); + } + virtual SourceRange getSourceRange() const { return SourceRange(TyBeginLoc, RParenLoc); } diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.def b/clang/include/clang/Basic/DiagnosticSemaKinds.def index 2959f6186b74..222e39911b81 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.def +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.def @@ -50,8 +50,20 @@ DIAG(err_field_designator_nonfield, ERROR, "field designator %0 does not refer to a non-static data member") DIAG(note_field_designator_found, NOTE, "field designator refers here") +DIAG(err_field_designator_anon_class, ERROR, + "field designator %0 refers to a member of an anonymous %select{struct|class|union}1") DIAG(err_designator_for_scalar_init, ERROR, "designator in initializer for scalar type %0") +DIAG(warn_subobject_initializer_overrides, WARNING, + "subobject initialization overrides initialization of other fields within its enclosing subobject") +DIAG(warn_initializer_overrides, WARNING, + "initializer overrides prior initialization of this subobject") +DIAG(note_previous_initializer, NOTE, + "previous initialization %select{|with side effects }0is here%select{| (side effects may not occur at run time)}0") +DIAG(warn_gnu_array_range_designator_unsupported, WARNING, + "GNU array-range designator extension is unsupported") +DIAG(warn_designator_into_union_broken_init, WARNING, + "designated initialization of union member is broken") // Declarations. DIAG(ext_vla, EXTENSION, diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp index 8e43f99b6729..ed73bfae27b2 100644 --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -221,13 +221,31 @@ const char *BinaryOperator::getOpcodeStr(Opcode Op) { InitListExpr::InitListExpr(SourceLocation lbraceloc, Expr **initExprs, unsigned numInits, - SourceLocation rbraceloc, bool hadDesignators) + SourceLocation rbraceloc) : Expr(InitListExprClass, QualType()), - LBraceLoc(lbraceloc), RBraceLoc(rbraceloc), HadDesignators(hadDesignators) { + LBraceLoc(lbraceloc), RBraceLoc(rbraceloc), SyntacticForm(0) { InitExprs.insert(InitExprs.end(), initExprs, initExprs+numInits); } +void InitListExpr::resizeInits(ASTContext &Context, unsigned NumInits) { + for (unsigned Idx = NumInits, LastIdx = InitExprs.size(); Idx < LastIdx; ++Idx) + delete InitExprs[Idx]; + InitExprs.resize(NumInits, 0); +} + +Expr *InitListExpr::updateInit(unsigned Init, Expr *expr) { + if (Init >= InitExprs.size()) { + InitExprs.insert(InitExprs.end(), Init - InitExprs.size() + 1, 0); + InitExprs.back() = expr; + return 0; + } + + Expr *Result = cast_or_null(InitExprs[Init]); + InitExprs[Init] = expr; + return Result; +} + /// getFunctionType - Return the underlying function type for this block. /// const FunctionType *BlockExpr::getFunctionType() const { @@ -740,6 +758,12 @@ bool Expr::isConstantInitializer(ASTContext &Ctx) const { return isEvaluatable(Ctx); } +bool Expr::hasSideEffects(ASTContext &Ctx) const { + EvalResult Result; + Evaluate(Result, Ctx); + return Result.HasSideEffects; +} + /// 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 diff --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp index 80de5b8ae454..7a558ab8dd7b 100644 --- a/clang/lib/AST/StmtPrinter.cpp +++ b/clang/lib/AST/StmtPrinter.cpp @@ -872,13 +872,38 @@ void StmtPrinter::VisitInitListExpr(InitListExpr* Node) { OS << "{ "; for (unsigned i = 0, e = Node->getNumInits(); i != e; ++i) { if (i) OS << ", "; - PrintExpr(Node->getInit(i)); + if (Node->getInit(i)) + PrintExpr(Node->getInit(i)); + else + OS << "0"; } OS << " }"; } void StmtPrinter::VisitDesignatedInitExpr(DesignatedInitExpr *Node) { - // FIXME! + for (DesignatedInitExpr::designators_iterator D = Node->designators_begin(), + DEnd = Node->designators_end(); + D != DEnd; ++D) { + if (D->isFieldDesignator()) { + if (D->getDotLoc().isInvalid()) + OS << D->getFieldName()->getName() << ":"; + else + OS << "." << D->getFieldName()->getName(); + } else { + OS << "["; + if (D->isArrayDesignator()) { + PrintExpr(Node->getArrayIndex(*D)); + } else { + PrintExpr(Node->getArrayRangeStart(*D)); + OS << " ... "; + PrintExpr(Node->getArrayRangeEnd(*D)); + } + OS << "]"; + } + } + + OS << " = "; + PrintExpr(Node->getInit()); } void StmtPrinter::VisitVAArgExpr(VAArgExpr *Node) { @@ -1187,7 +1212,9 @@ void StmtPrinter::VisitBlockDeclRefExpr(BlockDeclRefExpr *Node) { //===----------------------------------------------------------------------===// void Stmt::dumpPretty() const { - printPretty(llvm::errs()); + llvm::raw_ostream &OS = llvm::errs(); + printPretty(OS); + OS.flush(); } void Stmt::printPretty(llvm::raw_ostream &OS, PrinterHelper* Helper) const { diff --git a/clang/lib/CodeGen/CGExprAgg.cpp b/clang/lib/CodeGen/CGExprAgg.cpp index 9181bf665450..2534a14cb6c5 100644 --- a/clang/lib/CodeGen/CGExprAgg.cpp +++ b/clang/lib/CodeGen/CGExprAgg.cpp @@ -71,7 +71,7 @@ public: void VisitArraySubscriptExpr(ArraySubscriptExpr *E) { EmitAggLoadOfLValue(E); } - + // Operators. // case Expr::UnaryOperatorClass: // case Expr::CastExprClass: @@ -303,11 +303,6 @@ void AggExprEmitter::VisitVAArgExpr(VAArgExpr *VE) { } void AggExprEmitter::EmitNonConstInit(InitListExpr *E) { - if (E->hadDesignators()) { - CGF.ErrorUnsupported(E, "initializer list with designators"); - return; - } - const llvm::PointerType *APType = cast(DestPtr->getType()); const llvm::Type *DestType = APType->getElementType(); @@ -346,6 +341,8 @@ void AggExprEmitter::EmitInitializationToLValue(Expr* E, LValue LV) { // FIXME: Are initializers affected by volatile? if (E->getType()->isComplexType()) { CGF.EmitComplexExprIntoAddr(E, LV.getAddress(), false); + } else if (isa(E)) { + EmitNullInitializationToLValue(LV, E->getType()); } else if (CGF.hasAggregateLLVMType(E->getType())) { CGF.EmitAnyExpr(E, LV.getAddress(), false); } else { @@ -380,11 +377,6 @@ void AggExprEmitter::EmitNullInitializationToLValue(LValue LV, QualType T) { } void AggExprEmitter::VisitInitListExpr(InitListExpr *E) { - if (E->hadDesignators()) { - CGF.ErrorUnsupported(E, "initializer list with designators"); - return; - } - #if 0 // FIXME: Disabled while we figure out what to do about // test/CodeGen/bitfield.c @@ -426,7 +418,7 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *E) { uint64_t NumArrayElements = AType->getNumElements(); QualType ElementType = CGF.getContext().getCanonicalType(E->getType()); - ElementType =CGF.getContext().getAsArrayType(ElementType)->getElementType(); + ElementType = CGF.getContext().getAsArrayType(ElementType)->getElementType(); unsigned CVRqualifier = ElementType.getCVRQualifiers(); @@ -479,7 +471,7 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *E) { } // Unions only initialize one field. - // (things can get weird with designators, but they aren't + // (FIXME: things can get weird with designators, but they aren't // supported yet.) if (isUnion) break; diff --git a/clang/lib/CodeGen/CGExprConstant.cpp b/clang/lib/CodeGen/CGExprConstant.cpp index 32d126e5903e..3b6ebb4d56f3 100644 --- a/clang/lib/CodeGen/CGExprConstant.cpp +++ b/clang/lib/CodeGen/CGExprConstant.cpp @@ -242,6 +242,8 @@ public: const llvm::Type *Ty = ConvertType(ILE->getType()); // Find the field decl we're initializing, if any + // FIXME: C99 designated initializers won't always initialize the + // first field int FieldNo = 0; // Field no in RecordDecl FieldDecl* curField = 0; for (RecordDecl::field_iterator Field = RD->field_begin(), @@ -304,12 +306,6 @@ public: return llvm::Constant::getNullValue(RetTy); } - // FIXME: We don't codegen or sema designators yet. - if (ILE->hadDesignators()) { - CGM.ErrorUnsupported(ILE, "initializer list with designators"); - return llvm::UndefValue::get(ConvertType(ILE->getType())); - } - if (ILE->getType()->isArrayType()) return EmitArrayInitialization(ILE); diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp index 33c5a6124bdc..dd8b30041e70 100644 --- a/clang/lib/CodeGen/CGExprScalar.cpp +++ b/clang/lib/CodeGen/CGExprScalar.cpp @@ -176,11 +176,6 @@ public: if (!VType) return Visit(E->getInit(0)); - if (E->hadDesignators()) { - CGF.ErrorUnsupported(E, "initializer list with designators"); - return llvm::UndefValue::get(CGF.ConvertType(E->getType())); - } - unsigned NumVectorElements = VType->getNumElements(); const llvm::Type *ElementType = VType->getElementType(); diff --git a/clang/lib/Sema/Sema.h b/clang/lib/Sema/Sema.h index d017e6f9c7bc..8cf10ff3e2a7 100644 --- a/clang/lib/Sema/Sema.h +++ b/clang/lib/Sema/Sema.h @@ -28,6 +28,7 @@ #include "llvm/ADT/OwningPtr.h" #include #include +#include namespace llvm { class APSInt; @@ -1835,38 +1836,67 @@ private: class InitListChecker { Sema *SemaRef; bool hadError; + std::map SyntacticToSemantic; + InitListExpr *FullyStructuredList; void CheckImplicitInitList(InitListExpr *ParentIList, QualType T, - unsigned &Index); + unsigned &Index, InitListExpr *StructuredInitList, + unsigned &StructuredInitIndex); void CheckExplicitInitList(InitListExpr *IList, QualType &T, - unsigned &Index); - + unsigned &Index, InitListExpr *StructuredInitList, + unsigned &StructuredInitIndex); void CheckListElementTypes(InitListExpr *IList, QualType &DeclType, bool SubobjectIsDesignatorContext, - unsigned &Index); + unsigned &Index, + InitListExpr *StructuredInitList, + unsigned &StructuredInitIndex); void CheckSubElementType(InitListExpr *IList, QualType ElemType, - Expr *expr, unsigned &Index); + Expr *expr, unsigned &Index, + InitListExpr *StructuredInitList, + unsigned &StructuredInitIndex); // FIXME: Does DeclType need to be a reference type? void CheckScalarType(InitListExpr *IList, QualType &DeclType, - Expr *expr, unsigned &Index); - void CheckVectorType(InitListExpr *IList, QualType DeclType, unsigned &Index); + Expr *expr, unsigned &Index, + InitListExpr *StructuredInitList, + unsigned &StructuredInitIndex); + void CheckVectorType(InitListExpr *IList, QualType DeclType, unsigned &Index, + InitListExpr *StructuredInitList, + unsigned &StructuredInitIndex); void CheckStructUnionTypes(InitListExpr *IList, QualType DeclType, RecordDecl::field_iterator Field, - bool SubobjectIsDesignatorContext, unsigned &Index); + bool SubobjectIsDesignatorContext, unsigned &Index, + InitListExpr *StructuredInitList, + unsigned &StructuredInitIndex); void CheckArrayType(InitListExpr *IList, QualType &DeclType, llvm::APSInt elementIndex, - bool SubobjectIsDesignatorContext, unsigned &Index); + bool SubobjectIsDesignatorContext, unsigned &Index, + InitListExpr *StructuredInitList, + unsigned &StructuredInitIndex); bool CheckDesignatedInitializer(InitListExpr *IList, DesignatedInitExpr *DIE, DesignatedInitExpr::designators_iterator D, QualType &CurrentObjectType, RecordDecl::field_iterator *NextField, llvm::APSInt *NextElementIndex, - unsigned &Index); + unsigned &Index, + InitListExpr *StructuredList, + unsigned &StructuredIndex); + InitListExpr *getStructuredSubobjectInit(InitListExpr *IList, unsigned Index, + QualType CurrentObjectType, + InitListExpr *StructuredList, + unsigned StructuredIndex, + SourceRange InitRange); + void UpdateStructuredListElement(InitListExpr *StructuredInitList, + unsigned &StructuredInitIndex, + Expr *expr); int numArrayElements(QualType DeclType); int numStructUnionElements(QualType DeclType); public: InitListChecker(Sema *S, InitListExpr *IL, QualType &T); bool HadError() { return hadError; } + + // @brief Retrieves the fully-structured initializer list used for + // semantic analysis and code generation. + InitListExpr *getFullyStructuredList() const { return FullyStructuredList; } }; /// BlockSemaInfo - When a block is being parsed, this contains information diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index cfbd288aaea9..79efc7df9c0c 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -1136,6 +1136,9 @@ bool Sema::CheckInitializerTypes(Expr *&Init, QualType &DeclType, } InitListChecker CheckInitList(this, InitList, DeclType); + if (!CheckInitList.HadError()) + Init = CheckInitList.getFullyStructuredList(); + return CheckInitList.HadError(); } @@ -2209,6 +2212,12 @@ bool Sema::CheckForConstantInitializer(Expr *Init, QualType DclT) { for (unsigned i = 0; i < numInits; i++) { // FIXME: Need to get the type of the declaration for C++, // because it could be a reference? + + // Implicitly-generated value initializations are okay. + if (isa(Exp->getInit(i)) && + cast(Exp->getInit(i))->isImplicit()) + continue; + if (CheckForConstantInitializer(Exp->getInit(i), Exp->getInit(i)->getType())) return true; diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 770404d82ac1..064b8517f7c3 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -1985,7 +1985,7 @@ Sema::ActOnInitList(SourceLocation LBraceLoc, MultiExprArg initlist, // CheckInitializer() - it requires knowledge of the object being intialized. InitListExpr *E = new (Context) InitListExpr(LBraceLoc, InitList, NumInit, - RBraceLoc, Designators.hasAnyDesignators()); + RBraceLoc); E->setType(Context.VoidTy); // FIXME: just a place holder for now. return Owned(E); } @@ -3988,8 +3988,7 @@ Sema::ExprResult Sema::ActOnBuiltinOffsetOf(Scope *S, // Otherwise, create a compound literal expression as the base, and // iteratively process the offsetof designators. InitListExpr *IList = - new (Context) InitListExpr(SourceLocation(), 0, 0, - SourceLocation(), false); + new (Context) InitListExpr(SourceLocation(), 0, 0, SourceLocation()); IList->setType(ArgTy); Expr *Res = new (Context) CompoundLiteralExpr(SourceLocation(), ArgTy, IList, false); diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index 041e994bca8f..511a394d8f26 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -15,19 +15,73 @@ #include "clang/Parse/Designator.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Expr.h" +#include "clang/AST/ExprCXX.h" #include "clang/Basic/DiagnosticSema.h" -#include // for std::count_if -#include // for std::mem_fun - using namespace clang; +/// Recursively replaces NULL values within the given initializer list +/// with expressions that perform value-initialization of the +/// appropriate type. +static void fillInValueInitializations(ASTContext &Context, InitListExpr *ILE) { + assert((ILE->getType() != Context.VoidTy) && "Should not have void type"); + if (const RecordType *RType = ILE->getType()->getAsRecordType()) { + unsigned Init = 0, NumInits = ILE->getNumInits(); + for (RecordDecl::field_iterator Field = RType->getDecl()->field_begin(), + FieldEnd = RType->getDecl()->field_end(); + Field != FieldEnd; ++Field) { + if (Field->isUnnamedBitfield()) + continue; + + if (Init >= NumInits) + break; + + // FIXME: Check for fields with reference type in C++? + if (!ILE->getInit(Init)) + ILE->setInit(Init, + new (Context) CXXZeroInitValueExpr(Field->getType(), + SourceLocation(), + SourceLocation())); + else if (InitListExpr *InnerILE = dyn_cast(ILE->getInit(Init))) + fillInValueInitializations(Context, InnerILE); + ++Init; + } + + return; + } + + QualType ElementType; + + if (const ArrayType *AType = Context.getAsArrayType(ILE->getType())) + ElementType = AType->getElementType(); + else if (const VectorType *VType = ILE->getType()->getAsVectorType()) + ElementType = VType->getElementType(); + else + ElementType = ILE->getType(); + + for (unsigned Init = 0, NumInits = ILE->getNumInits(); Init != NumInits; + ++Init) { + if (!ILE->getInit(Init)) + ILE->setInit(Init, new (Context) CXXZeroInitValueExpr(ElementType, + SourceLocation(), + SourceLocation())); + else if (InitListExpr *InnerILE = dyn_cast(ILE->getInit(Init))) + fillInValueInitializations(Context, InnerILE); + } +} + InitListChecker::InitListChecker(Sema *S, InitListExpr *IL, QualType &T) { hadError = false; SemaRef = S; unsigned newIndex = 0; + unsigned newStructuredIndex = 0; + FullyStructuredList + = getStructuredSubobjectInit(IL, newIndex, T, 0, 0, SourceRange()); + CheckExplicitInitList(IL, T, newIndex, FullyStructuredList, newStructuredIndex); - CheckExplicitInitList(IL, T, newIndex); + if (!hadError) { + fillInValueInitializations(SemaRef->Context, FullyStructuredList); + } } int InitListChecker::numArrayElements(QualType DeclType) { @@ -42,17 +96,22 @@ int InitListChecker::numArrayElements(QualType DeclType) { int InitListChecker::numStructUnionElements(QualType DeclType) { RecordDecl *structDecl = DeclType->getAsRecordType()->getDecl(); - const int InitializableMembers - = std::count_if(structDecl->field_begin(), structDecl->field_end(), - std::mem_fun(&FieldDecl::getDeclName)); + int InitializableMembers = 0; + for (RecordDecl::field_iterator Field = structDecl->field_begin(), + FieldEnd = structDecl->field_end(); + Field != FieldEnd; ++Field) { + if ((*Field)->getIdentifier() || !(*Field)->isBitField()) + ++InitializableMembers; + } if (structDecl->isUnion()) return std::min(InitializableMembers, 1); return InitializableMembers - structDecl->hasFlexibleArrayMember(); } void InitListChecker::CheckImplicitInitList(InitListExpr *ParentIList, - QualType T, unsigned &Index) { - llvm::SmallVector InitExprs; + QualType T, unsigned &Index, + InitListExpr *StructuredList, + unsigned &StructuredIndex) { int maxElements = 0; if (T->isArrayType()) @@ -64,45 +123,39 @@ void InitListChecker::CheckImplicitInitList(InitListExpr *ParentIList, else assert(0 && "CheckImplicitInitList(): Illegal type"); + // FIXME: Perhaps we should move this warning elsewhere? if (maxElements == 0) { SemaRef->Diag(ParentIList->getInit(Index)->getLocStart(), diag::err_implicit_empty_initializer); + ++Index; hadError = true; return; } - // 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, false, NewIndex); + // Build a structured initializer list corresponding to this subobject. + InitListExpr *StructuredSubobjectInitList + = getStructuredSubobjectInit(ParentIList, Index, T, StructuredList, + StructuredIndex, + ParentIList->getInit(Index)->getSourceRange()); + unsigned StructuredSubobjectInitIndex = 0; - for (int i = 0; i < maxElements; ++i) { - // Don't attempt to go past the end of the init list - if (Index >= ParentIList->getNumInits()) - break; - Expr* expr = ParentIList->getInit(Index); - - // Add the expr to the new implicit init list and remove if from the old. - InitExprs.push_back(expr); - ParentIList->removeInit(Index); - } - // Synthesize an "implicit" InitListExpr (marked by the invalid source locs). - InitListExpr *ILE = new InitListExpr(SourceLocation(), - &InitExprs[0], InitExprs.size(), - SourceLocation(), - ParentIList->hadDesignators()); - ILE->setType(T); - - // Modify the parent InitListExpr to point to the implicit InitListExpr. - ParentIList->addInit(Index, ILE); + // Check the element types and build the structural subobject. + CheckListElementTypes(ParentIList, T, false, Index, + StructuredSubobjectInitList, + StructuredSubobjectInitIndex); } void InitListChecker::CheckExplicitInitList(InitListExpr *IList, QualType &T, - unsigned &Index) { + unsigned &Index, + InitListExpr *StructuredList, + unsigned &StructuredIndex) { assert(IList->isExplicit() && "Illegal Implicit InitListExpr"); - - CheckListElementTypes(IList, T, true, Index); + SyntacticToSemantic[IList] = StructuredList; + StructuredList->setSyntacticForm(IList); + CheckListElementTypes(IList, T, true, Index, StructuredList, + StructuredIndex); IList->setType(T); + StructuredList->setType(T); if (hadError) return; @@ -131,27 +184,31 @@ void InitListChecker::CheckExplicitInitList(InitListExpr *IList, QualType &T, void InitListChecker::CheckListElementTypes(InitListExpr *IList, QualType &DeclType, bool SubobjectIsDesignatorContext, - unsigned &Index) { + unsigned &Index, + InitListExpr *StructuredList, + unsigned &StructuredIndex) { if (DeclType->isScalarType()) { - CheckScalarType(IList, DeclType, 0, Index); + CheckScalarType(IList, DeclType, 0, Index, StructuredList, StructuredIndex); } else if (DeclType->isVectorType()) { - CheckVectorType(IList, DeclType, Index); + CheckVectorType(IList, DeclType, Index, StructuredList, StructuredIndex); } else if (DeclType->isAggregateType() || DeclType->isUnionType()) { if (DeclType->isStructureType() || DeclType->isUnionType()) { RecordDecl *RD = DeclType->getAsRecordType()->getDecl(); CheckStructUnionTypes(IList, DeclType, RD->field_begin(), - SubobjectIsDesignatorContext, Index); + SubobjectIsDesignatorContext, Index, + StructuredList, StructuredIndex); } else if (DeclType->isArrayType()) { llvm::APSInt Zero( SemaRef->Context.getTypeSize(SemaRef->Context.getSizeType()), false); - CheckArrayType(IList, DeclType, Zero, SubobjectIsDesignatorContext, Index); + CheckArrayType(IList, DeclType, Zero, SubobjectIsDesignatorContext, Index, + StructuredList, StructuredIndex); } else - assert(0 && "Aggregate that isn't a function or array?!"); + assert(0 && "Aggregate that isn't a structure or array?!"); } else if (DeclType->isVoidType() || DeclType->isFunctionType()) { // This type is invalid, issue a diagnostic. - Index++; + ++Index; SemaRef->Diag(IList->getLocStart(), diag::err_illegal_initializer_type) << DeclType; hadError = true; @@ -165,31 +222,46 @@ void InitListChecker::CheckListElementTypes(InitListExpr *IList, void InitListChecker::CheckSubElementType(InitListExpr *IList, QualType ElemType, Expr *expr, - unsigned &Index) { + unsigned &Index, + InitListExpr *StructuredList, + unsigned &StructuredIndex) { if (InitListExpr *SubInitList = dyn_cast(expr)) { unsigned newIndex = 0; - CheckExplicitInitList(SubInitList, ElemType, newIndex); - Index++; + unsigned newStructuredIndex = 0; + InitListExpr *newStructuredList + = getStructuredSubobjectInit(IList, Index, ElemType, + StructuredList, StructuredIndex, + SubInitList->getSourceRange()); + CheckExplicitInitList(SubInitList, ElemType, newIndex, + newStructuredList, newStructuredIndex); + ++StructuredIndex; + ++Index; } else if (StringLiteral *lit = SemaRef->IsStringLiteralInit(expr, ElemType)) { SemaRef->CheckStringLiteralInit(lit, ElemType); - Index++; + UpdateStructuredListElement(StructuredList, StructuredIndex, lit); + ++Index; } else if (ElemType->isScalarType()) { - CheckScalarType(IList, ElemType, expr, Index); + CheckScalarType(IList, ElemType, expr, Index, StructuredList, + StructuredIndex); } else if (expr->getType()->getAsRecordType() && SemaRef->Context.typesAreCompatible( expr->getType().getUnqualifiedType(), ElemType.getUnqualifiedType())) { - Index++; + UpdateStructuredListElement(StructuredList, StructuredIndex, expr); + ++Index; // FIXME: Add checking } else { - CheckImplicitInitList(IList, ElemType, Index); - Index++; - } + CheckImplicitInitList(IList, ElemType, Index, StructuredList, + StructuredIndex); + ++StructuredIndex; + } } void InitListChecker::CheckScalarType(InitListExpr *IList, QualType &DeclType, - Expr *expr, unsigned &Index) { + Expr *expr, unsigned &Index, + InitListExpr *StructuredList, + unsigned &StructuredIndex) { if (Index < IList->getNumInits()) { if (!expr) expr = IList->getInit(Index); @@ -199,6 +271,7 @@ void InitListChecker::CheckScalarType(InitListExpr *IList, QualType &DeclType, << IList->getSourceRange(); hadError = true; ++Index; + ++StructuredIndex; return; } else if (isa(expr)) { SemaRef->Diag(expr->getSourceRange().getBegin(), @@ -206,6 +279,7 @@ void InitListChecker::CheckScalarType(InitListExpr *IList, QualType &DeclType, << DeclType << expr->getSourceRange(); hadError = true; ++Index; + ++StructuredIndex; return; } @@ -219,18 +293,27 @@ void InitListChecker::CheckScalarType(InitListExpr *IList, QualType &DeclType, DIE->setInit(expr); else IList->setInit(Index, expr); + } + if (hadError) + ++StructuredIndex; + else + UpdateStructuredListElement(StructuredList, StructuredIndex, expr); ++Index; } else { SemaRef->Diag(IList->getLocStart(), diag::err_empty_scalar_initializer) << IList->getSourceRange(); hadError = true; + ++Index; + ++StructuredIndex; return; } } void InitListChecker::CheckVectorType(InitListExpr *IList, QualType DeclType, - unsigned &Index) { + unsigned &Index, + InitListExpr *StructuredList, + unsigned &StructuredIndex) { if (Index < IList->getNumInits()) { const VectorType *VT = DeclType->getAsVectorType(); int maxElements = VT->getNumElements(); @@ -240,7 +323,8 @@ void InitListChecker::CheckVectorType(InitListExpr *IList, QualType DeclType, // Don't attempt to go past the end of the init list if (Index >= IList->getNumInits()) break; - CheckSubElementType(IList, elementType, IList->getInit(Index), Index); + CheckSubElementType(IList, elementType, IList->getInit(Index), Index, + StructuredList, StructuredIndex); } } } @@ -248,12 +332,21 @@ void InitListChecker::CheckVectorType(InitListExpr *IList, QualType DeclType, void InitListChecker::CheckArrayType(InitListExpr *IList, QualType &DeclType, llvm::APSInt elementIndex, bool SubobjectIsDesignatorContext, - unsigned &Index) { + unsigned &Index, + InitListExpr *StructuredList, + unsigned &StructuredIndex) { // Check for the special-case of initializing an array with a string. if (Index < IList->getNumInits()) { if (StringLiteral *lit = SemaRef->IsStringLiteralInit(IList->getInit(Index), DeclType)) { SemaRef->CheckStringLiteralInit(lit, DeclType); + // We place the string literal directly into the resulting + // initializer list. This is the only place where the structure + // of the structured initializer list doesn't match exactly, + // because doing so would involve allocating one character + // constant for each string. + UpdateStructuredListElement(StructuredList, StructuredIndex, lit); + StructuredList->resizeInits(SemaRef->Context, StructuredIndex); ++Index; return; } @@ -267,11 +360,14 @@ void InitListChecker::CheckArrayType(InitListExpr *IList, QualType &DeclType, diag::err_variable_object_no_init) << VAT->getSizeExpr()->getSourceRange(); hadError = true; + ++Index; + ++StructuredIndex; return; } // We might know the maximum number of elements in advance. - llvm::APSInt maxElements(elementIndex.getBitWidth(), elementIndex.isUnsigned()); + llvm::APSInt maxElements(elementIndex.getBitWidth(), + elementIndex.isUnsigned()); bool maxElementsKnown = false; if (const ConstantArrayType *CAT = SemaRef->Context.getAsConstantArrayType(DeclType)) { @@ -295,7 +391,8 @@ void InitListChecker::CheckArrayType(InitListExpr *IList, QualType &DeclType, // 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)) { + DeclType, 0, &elementIndex, Index, + StructuredList, StructuredIndex)) { hadError = true; continue; } @@ -320,7 +417,8 @@ void InitListChecker::CheckArrayType(InitListExpr *IList, QualType &DeclType, break; // Check this element. - CheckSubElementType(IList, elementType, IList->getInit(Index), Index); + CheckSubElementType(IList, elementType, IList->getInit(Index), Index, + StructuredList, StructuredIndex); ++elementIndex; // If the array is of incomplete type, keep track of the number of @@ -348,7 +446,9 @@ void InitListChecker::CheckStructUnionTypes(InitListExpr *IList, QualType DeclType, RecordDecl::field_iterator Field, bool SubobjectIsDesignatorContext, - unsigned &Index) { + unsigned &Index, + InitListExpr *StructuredList, + unsigned &StructuredIndex) { RecordDecl* structDecl = DeclType->getAsRecordType()->getDecl(); // If the record is invalid, some of it's members are invalid. To avoid @@ -376,7 +476,8 @@ void InitListChecker::CheckStructUnionTypes(InitListExpr *IList, // 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)) + DeclType, &Field, 0, Index, + StructuredList, StructuredIndex)) hadError = true; continue; @@ -391,13 +492,14 @@ void InitListChecker::CheckStructUnionTypes(InitListExpr *IList, if (Field->getType()->isIncompleteArrayType()) break; - if (!Field->getIdentifier()) { - // Don't initialize unnamed fields, e.g. "int : 20;" + if (!Field->getIdentifier() && Field->isBitField()) { + // Don't initialize unnamed bitfields, e.g. "int : 20;" ++Field; continue; } - CheckSubElementType(IList, Field->getType(), IList->getInit(Index), Index); + CheckSubElementType(IList, Field->getType(), IList->getInit(Index), Index, + StructuredList, StructuredIndex); if (DeclType->isUnionType()) // FIXME: designated initializers? break; @@ -416,8 +518,7 @@ void InitListChecker::CheckStructUnionTypes(InitListExpr *IList, /// IList, is well-formed for a current object of type @p DeclType /// (C99 6.7.8). The actual subobject that this designator refers to /// within the current subobject is returned in either -/// @p DesignatedField or @p DesignatedIndex (whichever is -/// appropriate). +/// @p NextField or @p NextElementIndex (whichever is appropriate). /// /// @param IList The initializer list in which this designated /// initializer occurs. @@ -439,6 +540,10 @@ void InitListChecker::CheckStructUnionTypes(InitListExpr *IList, /// @param Index Index into @p IList where the designated initializer /// @p DIE occurs. /// +/// @param StructuredList The initializer list expression that +/// describes all of the subobject initializers in the order they'll +/// actually be initialized. +/// /// @returns true if there was an error, false otherwise. bool InitListChecker::CheckDesignatedInitializer(InitListExpr *IList, @@ -447,16 +552,30 @@ InitListChecker::CheckDesignatedInitializer(InitListExpr *IList, QualType &CurrentObjectType, RecordDecl::field_iterator *NextField, llvm::APSInt *NextElementIndex, - unsigned &Index) { - bool IsFirstDesignator = (D == DIE->designators_begin()); - + unsigned &Index, + InitListExpr *StructuredList, + unsigned &StructuredIndex) { if (D == DIE->designators_end()) { // Check the actual initialization for the designated object type. bool prevHadError = hadError; - CheckSubElementType(IList, CurrentObjectType, DIE->getInit(), Index); + CheckSubElementType(IList, CurrentObjectType, DIE->getInit(), Index, + StructuredList, StructuredIndex); return hadError && !prevHadError; } + bool IsFirstDesignator = (D == DIE->designators_begin()); + assert((IsFirstDesignator || StructuredList) && + "Need a non-designated initializer list to start from"); + + // Determine the structural initializer list that corresponds to the + // current subobject. + StructuredList = IsFirstDesignator? SyntacticToSemantic[IList] + : getStructuredSubobjectInit(IList, Index, CurrentObjectType, StructuredList, + StructuredIndex, + SourceRange(D->getStartLocation(), + DIE->getSourceRange().getEnd())); + assert(StructuredList && "Expected a structured initializer list"); + if (D->isFieldDesignator()) { // C99 6.7.8p7: // @@ -478,56 +597,95 @@ InitListChecker::CheckDesignatedInitializer(InitListExpr *IList, return true; } + // Note: we perform a linear search of the fields here, despite + // the fact that we have a faster lookup method, because we always + // need to compute the field's index. 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); + unsigned FieldIndex = 0; + RecordDecl::field_iterator Field = RT->getDecl()->field_begin(), + FieldEnd = RT->getDecl()->field_end(); + for (; Field != FieldEnd; ++Field) { + if (Field->isUnnamedBitfield()) + continue; + + if (Field->getIdentifier() == FieldName) + break; + + ++FieldIndex; } - if (!DesignatedField) { + if (Field == FieldEnd) { + // We did not find the field we're looking for. Produce a + // suitable diagnostic and return a failure. + DeclContext::lookup_result Lookup = RT->getDecl()->lookup(FieldName); + if (Lookup.first == Lookup.second) { + // Name lookup didn't find anything. + SemaRef->Diag(D->getFieldLoc(), diag::err_field_designator_unknown) + << FieldName << CurrentObjectType; + } 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); + } + + ++Index; + return true; + } else if (cast((*Field)->getDeclContext()) + ->isAnonymousStructOrUnion()) { + SemaRef->Diag(D->getFieldLoc(), diag::err_field_designator_anon_class) + << FieldName + << (cast((*Field)->getDeclContext())->isUnion()? 2 : + (int)SemaRef->getLangOptions().CPlusPlus); + SemaRef->Diag((*Field)->getLocation(), diag::note_field_designator_found); ++Index; return true; } - + + // All of the fields of a union are located at the same place in + // the initializer list. + // FIXME: Need to tell CodeGen which type to initialize to. ImplicitCastExpr? + if (RT->getDecl()->isUnion() && FieldIndex != 0) { + SemaRef->Diag(D->getStartLocation(), + diag::warn_designator_into_union_broken_init) + << SourceRange(D->getStartLocation(), DIE->getSourceRange().getEnd()); + FieldIndex = 0; + } + // Update the designator with the field declaration. - D->setField(DesignatedField); + D->setField(*Field); + // Make sure that our non-designated initializer list has space + // for a subobject corresponding to this field. + if (FieldIndex >= StructuredList->getNumInits()) + StructuredList->resizeInits(SemaRef->Context, FieldIndex + 1); + // Recurse to check later designated subobjects. - QualType FieldType = DesignatedField->getType(); - if (CheckDesignatedInitializer(IList, DIE, ++D, FieldType, 0, 0, Index)) + QualType FieldType = (*Field)->getType(); + unsigned newStructuredIndex = FieldIndex; + if (CheckDesignatedInitializer(IList, DIE, ++D, FieldType, 0, 0, Index, + StructuredList, newStructuredIndex)) 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; + ++FieldIndex; // If this the first designator, our caller will continue checking // the rest of this struct/class/union subobject. if (IsFirstDesignator) { if (NextField) *NextField = Field; + StructuredIndex = FieldIndex; return false; } // Check the remaining fields within this class/struct/union subobject. bool prevHadError = hadError; - CheckStructUnionTypes(IList, CurrentObjectType, Field, false, Index); + CheckStructUnionTypes(IList, CurrentObjectType, Field, false, Index, + StructuredList, FieldIndex); return hadError && !prevHadError; } @@ -561,6 +719,9 @@ InitListChecker::CheckDesignatedInitializer(InitListExpr *IList, else { assert(D->isArrayRangeDesignator() && "Need array-range designator"); IndexExpr = DIE->getArrayRangeEnd(*D); + SemaRef->Diag(D->getEllipsisLoc(), + diag::warn_gnu_array_range_designator_unsupported) + << SourceRange(D->getLBracketLoc(), D->getRBracketLoc()); } bool ConstExpr @@ -581,28 +742,115 @@ InitListChecker::CheckDesignatedInitializer(InitListExpr *IList, } } + // Make sure that our non-designated initializer list has space + // for a subobject corresponding to this array element. + unsigned ElementIndex = DesignatedIndex.getZExtValue(); + if (ElementIndex >= StructuredList->getNumInits()) + StructuredList->resizeInits(SemaRef->Context, ElementIndex + 1); + // Recurse to check later designated subobjects. QualType ElementType = AT->getElementType(); - if (CheckDesignatedInitializer(IList, DIE, ++D, ElementType, 0, 0, Index)) + if (CheckDesignatedInitializer(IList, DIE, ++D, ElementType, 0, 0, Index, + StructuredList, ElementIndex)) return true; // Move to the next index in the array that we'll be initializing. ++DesignatedIndex; + ElementIndex = DesignatedIndex.getZExtValue(); // If this the first designator, our caller will continue checking // the rest of this array subobject. if (IsFirstDesignator) { if (NextElementIndex) *NextElementIndex = DesignatedIndex; + StructuredIndex = ElementIndex; return false; } // Check the remaining elements within this array subobject. bool prevHadError = hadError; - CheckArrayType(IList, CurrentObjectType, DesignatedIndex, true, Index); + CheckArrayType(IList, CurrentObjectType, DesignatedIndex, true, Index, + StructuredList, ElementIndex); return hadError && !prevHadError; } +// Get the structured initializer list for a subobject of type +// @p CurrentObjectType. +InitListExpr * +InitListChecker::getStructuredSubobjectInit(InitListExpr *IList, unsigned Index, + QualType CurrentObjectType, + InitListExpr *StructuredList, + unsigned StructuredIndex, + SourceRange InitRange) { + Expr *ExistingInit = 0; + if (!StructuredList) + ExistingInit = SyntacticToSemantic[IList]; + else if (StructuredIndex < StructuredList->getNumInits()) + ExistingInit = StructuredList->getInit(StructuredIndex); + + if (InitListExpr *Result = dyn_cast_or_null(ExistingInit)) + return Result; + + if (ExistingInit) { + // We are creating an initializer list that initializes the + // subobjects of the current object, but there was already an + // initialization that completely initialized the current + // subobject, e.g., by a compound literal: + // + // struct X { int a, b; }; + // struct X xs[] = { [0] = (struct X) { 1, 2 }, [0].b = 3 }; + // + // Here, xs[0].a == 0 and xs[0].b == 3, since the second, + // designated initializer re-initializes the whole + // subobject [0], overwriting previous initializers. + SemaRef->Diag(InitRange.getBegin(), diag::warn_subobject_initializer_overrides) + << InitRange; + SemaRef->Diag(ExistingInit->getSourceRange().getBegin(), + diag::note_previous_initializer) + << ExistingInit->hasSideEffects(SemaRef->Context) + << ExistingInit->getSourceRange(); + } + + InitListExpr *Result + = new (SemaRef->Context) InitListExpr(SourceLocation(), 0, 0, + SourceLocation()); + Result->setType(CurrentObjectType); + + // Link this new initializer list into the structured initializer + // lists. + if (StructuredList) + StructuredList->updateInit(StructuredIndex, Result); + else { + Result->setSyntacticForm(IList); + SyntacticToSemantic[IList] = Result; + } + + return Result; +} + +/// Update the initializer at index @p StructuredIndex within the +/// structured initializer list to the value @p expr. +void InitListChecker::UpdateStructuredListElement(InitListExpr *StructuredList, + unsigned &StructuredIndex, + Expr *expr) { + // No structured initializer list to update + if (!StructuredList) + return; + + if (Expr *PrevInit = StructuredList->updateInit(StructuredIndex, expr)) { + // This initializer overwrites a previous initializer. Warn. + SemaRef->Diag(expr->getSourceRange().getBegin(), + diag::warn_initializer_overrides) + << expr->getSourceRange(); + SemaRef->Diag(PrevInit->getSourceRange().getBegin(), + diag::note_previous_initializer) + << (int)PrevInit->hasSideEffects(SemaRef->Context) + << PrevInit->getSourceRange(); + } + + ++StructuredIndex; +} + /// Check that the given Index expression is a valid array designator /// value. This is essentailly just a wrapper around /// Expr::isIntegerConstantExpr that also checks for negative values diff --git a/clang/test/Sema/array-init.c b/clang/test/Sema/array-init.c index 9d2a942410ae..3d2cf6912744 100644 --- a/clang/test/Sema/array-init.c +++ b/clang/test/Sema/array-init.c @@ -1,4 +1,4 @@ -// RUN: clang -fsyntax-only -verify -pedantic %s +// RUN: clang -fsyntax-only -pedantic -verify %s extern int foof() = 1; // expected-error{{illegal initializer (only variables can be initialized)}} @@ -101,6 +101,7 @@ void legal() { { 2, 3 }, { 4, 5, 6 } }; + int q_sizecheck[(sizeof(q) / sizeof(short [3][2])) == 3? 1 : -1]; } unsigned char asso_values[] = { 34 }; @@ -134,15 +135,19 @@ typedef int AryT[]; void testTypedef() { AryT a = { 1, 2 }, b = { 3, 4, 5 }; + int a_sizecheck[(sizeof(a) / sizeof(int)) == 2? 1 : -1]; + int b_sizecheck[(sizeof(b) / sizeof(int)) == 3? 1 : -1]; } static char const xx[] = "test"; +int xx_sizecheck[(sizeof(xx) / sizeof(char)) == 5? 1 : -1]; static char const yy[5] = "test"; static char const zz[3] = "test"; // expected-warning{{initializer-string for char array is too long}} void charArrays() { static char const test[] = "test"; + int test_sizecheck[(sizeof(test) / sizeof(char)) == 5? 1 : -1]; static char const test2[] = { "weird stuff" }; static char const test3[] = { "test", "excess stuff" }; // expected-error{{excess elements in char array initializer}} @@ -171,6 +176,7 @@ void variableArrayInit() { float r1[10] = {{7}}; //expected-warning{{braces around scalar initializer}} float r2[] = {{8}}; //expected-warning{{braces around scalar initializer}} char r3[][5] = {1,2,3,4,5,6}; +int r3_sizecheck[(sizeof(r3) / sizeof(char[5])) == 2? 1 : -1]; char r3_2[sizeof r3 == 10 ? 1 : -1]; float r4[1][2] = {1,{2},3,4}; //expected-warning{{braces around scalar initializer}} expected-warning{{excess elements in array initializer}} char r5[][5] = {"aa", "bbb", "ccccc"}; @@ -195,7 +201,7 @@ int bar (void) { return z.z; } struct s3 {void (*a)(void);} t5 = {autoStructTest}; -// GCC extension; flexible array init. Once this is implemented, the warning should be removed. +// FIXME: GCC extension; flexible array init. Once this is implemented, the warning should be removed. // Note that clang objc implementation depends on this extension. struct {int a; int b[];} t6 = {1, {1, 2, 3}}; //expected-warning{{excess elements in array initializer}} union {char a; int b;} t7[] = {1, 2, 3}; @@ -238,3 +244,21 @@ struct soft_segment_descriptor gdt_segs[] = { static void sppp_ipv6cp_up(); const struct {} ipcp = { sppp_ipv6cp_up }; //expected-warning{{empty struct extension}} expected-warning{{excess elements in array initializer}} + +struct _Matrix { union { float m[4][4]; }; }; //expected-warning{{anonymous unions are a GNU extension in C}} +typedef struct _Matrix Matrix; +void test_matrix() { + const Matrix mat1 = { + { { 1.0f, 2.0f, 3.0f, 4.0f, + 5.0f, 6.0f, 7.0f, 8.0f, + 9.0f, 10.0f, 11.0f, 12.0f, + 13.0f, 14.0f, 15.0f, 16.0f } } + }; + + const Matrix mat2 = { + 1.0f, 2.0f, 3.0f, 4.0f, + 5.0f, 6.0f, 7.0f, 8.0f, + 9.0f, 10.0f, 11.0f, 12.0f, + 13.0f, 14.0f, 15.0f, 16.0f + }; +} diff --git a/clang/test/Sema/designated-initializers.c b/clang/test/Sema/designated-initializers.c index fd4873193cfd..c9a0aa7f05bd 100644 --- a/clang/test/Sema/designated-initializers.c +++ b/clang/test/Sema/designated-initializers.c @@ -18,7 +18,8 @@ int iarray2[10] = { }; int iarray3[10] = { - [5 ... 12] = 2 // expected-error{{array designator index (12) exceeds array bounds (10)}} + [5 ... 12] = 2 // expected-error{{array designator index (12) exceeds array bounds (10)}}\ + // expected-warning{{GNU array-range designator extension is unsupported}} }; struct point { @@ -44,8 +45,8 @@ struct point array[10] = { 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 ... 5].y = 2.0, // expected-warning{{GNU array-range designator extension is unsupported}} + [4 ... 6] = { .x = 3, .y = 4.0 } // expected-warning{{GNU array-range designator extension is unsupported}} }; struct point array3[10] = { @@ -116,4 +117,25 @@ struct disklabel_ops disklabel64_ops = { // PR clang/3378 int bitwidth[] = { [(long long int)1] = 5, [(short int)2] = 2 }; int a[]= { [sizeof(int)] = 0 }; -int a2[]= { [0 ... sizeof(int)] = 0 }; +int a2[]= { [0 ... sizeof(int)] = 0 }; // expected-warning{{GNU array-range designator extension is unsupported}} + +// Test warnings about initializers overriding previous initializers +struct X { + int a, b, c; +}; + +int counter = 0; +int get8() { ++counter; return 8; } + +void test() { + struct X xs[] = { + [0] = (struct X){1, 2}, // expected-note{{previous initialization is here}} + [0].c = 3, // expected-warning{{subobject initialization overrides initialization of other fields within its enclosing subobject}} + (struct X) {4, 5, 6}, // expected-note{{previous initialization is here}} + [1].b = get8(), // expected-warning{{subobject initialization overrides initialization of other fields within its enclosing subobject}} + [0].b = 8 + }; +} + +// FIXME: we need to +union { char c; long l; } u1 = { .l = 0xFFFF }; // expected-warning{{designated initialization of union member is broken}} diff --git a/clang/test/Sema/vector-init.c b/clang/test/Sema/vector-init.c index 1e2ba012c8f2..6913082228ca 100644 --- a/clang/test/Sema/vector-init.c +++ b/clang/test/Sema/vector-init.c @@ -1,5 +1,15 @@ -// RUN: clang %s -verify -fsyntax-only +// RUN: clang %s -fsyntax-only -verify typedef __attribute__(( ext_vector_type(4) )) float float4; +//typedef float float4 __attribute__((vector_size(16))); float4 foo = (float4){ 1.0, 2.0, 3.0, 4.0 }; + +float4 array[] = { 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0}; +int array_sizecheck[(sizeof(array) / sizeof(float4)) == 3? 1 : -1]; + +float4 array2[2] = { 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, + 9.0 }; // expected-warning {{excess elements in array initializer}} + +float4 array3[2] = { {1.0, 2.0, 3.0}, 5.0, 6.0, 7.0, 8.0, + 9.0 }; // expected-warning {{excess elements in array initializer}}