From d87b61f6398bab21176f73818a8d11ca1c3632c8 Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Thu, 10 Dec 2009 17:56:55 +0000 Subject: [PATCH] Move initialization via initializer list over to InitializationSequences. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@91050 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Basic/DiagnosticSemaKinds.td | 6 +- lib/Sema/SemaDecl.cpp | 9 +- lib/Sema/SemaInit.cpp | 129 ++++++++++++++++-- lib/Sema/SemaInit.h | 34 ++++- .../dcl.decl/dcl.init/dcl.init.list/basic.cpp | 5 + 5 files changed, 164 insertions(+), 19 deletions(-) create mode 100644 test/CXX/dcl.decl/dcl.init/dcl.init.list/basic.cpp diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 4db1d15832..a35fd58cfa 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -542,7 +542,11 @@ def err_reference_bind_drops_quals : Error< def err_reference_bind_failed : Error< "reference to type %0 could not bind to an %select{rvalue|lvalue}1 of type " "%2">; - +def err_reference_bind_init_list : Error< + "reference to type %0 cannot bind to an initializer list">; +def err_init_list_bad_dest_type : Error< + "%select{|non-aggregate }0type %1 cannot be initialized with an initializer " + "list">; // FIXME: passing in an English string as %1! def err_reference_init_drops_quals : Error< diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 3fa7e6558b..a171217073 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -3499,7 +3499,8 @@ void Sema::AddInitializerToDecl(DeclPtrTy dcl, ExprArg init, bool DirectInit) { Diag(VDecl->getLocation(), diag::err_block_extern_cant_init); VDecl->setInvalidDecl(); } else if (!VDecl->isInvalidDecl()) { - if (VDecl->getType()->isReferenceType()) { + if (VDecl->getType()->isReferenceType() + || isa(Init)) { InitializedEntity Entity = InitializedEntity::InitializeVariable(VDecl); @@ -3513,7 +3514,8 @@ void Sema::AddInitializerToDecl(DeclPtrTy dcl, ExprArg init, bool DirectInit) { InitializationSequence InitSeq(*this, Entity, Kind, &Init, 1); if (InitSeq) { OwningExprResult Result = InitSeq.Perform(*this, Entity, Kind, - MultiExprArg(*this, (void**)&Init, 1)); + MultiExprArg(*this, (void**)&Init, 1), + &DclT); if (Result.isInvalid()) { VDecl->setInvalidDecl(); return; @@ -3524,8 +3526,7 @@ void Sema::AddInitializerToDecl(DeclPtrTy dcl, ExprArg init, bool DirectInit) { InitSeq.Diagnose(*this, Entity, Kind, &Init, 1); VDecl->setInvalidDecl(); return; - } - + } } else if (CheckInitializerTypes(Init, DclT, VDecl->getLocation(), VDecl->getDeclName(), DirectInit)) VDecl->setInvalidDecl(); diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp index d2ae906eff..08ae7cbfbe 100644 --- a/lib/Sema/SemaInit.cpp +++ b/lib/Sema/SemaInit.cpp @@ -1968,6 +1968,7 @@ void InitializationSequence::Step::Destroy() { case SK_UserConversion: case SK_QualificationConversionRValue: case SK_QualificationConversionLValue: + case SK_ListInitialization: break; case SK_ConversionSequence: @@ -2027,6 +2028,13 @@ void InitializationSequence::AddConversionSequenceStep( Steps.push_back(S); } +void InitializationSequence::AddListInitializationStep(QualType T) { + Step S; + S.Kind = SK_ListInitialization; + S.Type = T; + Steps.push_back(S); +} + void InitializationSequence::SetOverloadFailure(FailureKind Failure, OverloadingResult Result) { SequenceKind = FailedSequence; @@ -2039,16 +2047,51 @@ void InitializationSequence::SetOverloadFailure(FailureKind Failure, //===----------------------------------------------------------------------===// /// \brief Attempt list initialization (C++0x [dcl.init.list]) -static bool TryListInitialization(Sema &S, +static void TryListInitialization(Sema &S, const InitializedEntity &Entity, const InitializationKind &Kind, InitListExpr *InitList, InitializationSequence &Sequence) { - // FIXME: For now, it is safe to assume that list initialization always - // works. When we actually perform list initialization, we'll do all of the - // necessary checking. - // C++0x initializer lists will force us to perform more checking here. - return true; + // FIXME: We only perform rudimentary checking of list + // initializations at this point, then assume that any list + // initialization of an array, aggregate, or scalar will be + // well-formed. We we actually "perform" list initialization, we'll + // do all of the necessary checking. C++0x initializer lists will + // force us to perform more checking here. + Sequence.setSequenceKind(InitializationSequence::ListInitialization); + + QualType DestType = Entity.getType().getType(); + + // C++ [dcl.init]p13: + // If T is a scalar type, then a declaration of the form + // + // T x = { a }; + // + // is equivalent to + // + // T x = a; + if (DestType->isScalarType()) { + if (InitList->getNumInits() > 1 && S.getLangOptions().CPlusPlus) { + Sequence.SetFailed(InitializationSequence::FK_TooManyInitsForScalar); + return; + } + + // Assume scalar initialization from a single value works. + } else if (DestType->isAggregateType()) { + // Assume aggregate initialization works. + } else if (DestType->isVectorType()) { + // Assume vector initialization works. + } else if (DestType->isReferenceType()) { + // FIXME: C++0x defines behavior for this. + Sequence.SetFailed(InitializationSequence::FK_ReferenceBindingToInitList); + return; + } else if (DestType->isRecordType()) { + // FIXME: C++0x defines behavior for this + Sequence.SetFailed(InitializationSequence::FK_InitListBadDestinationType); + } + + // Add a general "list initialization" step. + Sequence.AddListInitializationStep(DestType); } /// \brief Try a reference initialization that involves calling a conversion @@ -2485,6 +2528,7 @@ InitializationSequence::InitializationSequence(Sema &S, // list-initialized (8.5.4). if (InitListExpr *InitList = dyn_cast_or_null(Initializer)) { TryListInitialization(S, Entity, Kind, InitList, *this); + return; } // - If the destination type is a reference type, see 8.5.3. @@ -2578,7 +2622,8 @@ Action::OwningExprResult InitializationSequence::Perform(Sema &S, const InitializedEntity &Entity, const InitializationKind &Kind, - Action::MultiExprArg Args) { + Action::MultiExprArg Args, + QualType *ResultType) { if (SequenceKind == FailedSequence) { unsigned NumArgs = Args.size(); Diagnose(S, Entity, Kind, (Expr **)Args.release(), NumArgs); @@ -2586,6 +2631,41 @@ InitializationSequence::Perform(Sema &S, } if (SequenceKind == DependentSequence) { + // If the declaration is a non-dependent, incomplete array type + // that has an initializer, then its type will be completed once + // the initializer is instantiated. + if (ResultType && !Entity.getType().getType()->isDependentType() && + Args.size() == 1) { + QualType DeclType = Entity.getType().getType(); + if (const IncompleteArrayType *ArrayT + = S.Context.getAsIncompleteArrayType(DeclType)) { + // FIXME: We don't currently have the ability to accurately + // compute the length of an initializer list without + // performing full type-checking of the initializer list + // (since we have to determine where braces are implicitly + // introduced and such). So, we fall back to making the array + // type a dependently-sized array type with no specified + // bound. + if (isa((Expr *)Args.get()[0])) { + SourceRange Brackets; + // Scavange the location of the brackets from the entity, if we can. + if (isa(Entity.getType())) { + IncompleteArrayTypeLoc ArrayLoc + = cast(Entity.getType()); + Brackets = ArrayLoc.getBracketsRange(); + } + + *ResultType + = S.Context.getDependentSizedArrayType(ArrayT->getElementType(), + /*NumElts=*/0, + ArrayT->getSizeModifier(), + ArrayT->getIndexTypeCVRQualifiers(), + Brackets); + } + + } + } + if (Kind.getKind() == InitializationKind::IK_Copy) return Sema::OwningExprResult(S, Args.release()[0]); @@ -2598,6 +2678,8 @@ InitializationSequence::Perform(Sema &S, } QualType DestType = Entity.getType().getType().getNonReferenceType(); + if (ResultType) + *ResultType = Entity.getType().getType(); Sema::OwningExprResult CurInit(S); // For copy initialization and any other initialization forms that @@ -2754,6 +2836,17 @@ InitializationSequence::Perform(Sema &S, CurInit.release(); CurInit = S.Owned(CurInitExpr); break; + + case SK_ListInitialization: { + InitListExpr *InitList = cast(CurInitExpr); + QualType Ty = Step->Type; + if (S.CheckInitList(InitList, ResultType? *ResultType : Ty)) + return S.ExprError(); + + CurInit.release(); + CurInit = S.Owned(InitList); + break; + } } } @@ -2865,7 +2958,27 @@ bool InitializationSequence::Diagnose(Sema &S, << (Args[0]->isLvalue(S.Context) == Expr::LV_Valid) << Args[0]->getType() << Args[0]->getSourceRange(); - break; + break; + + case FK_TooManyInitsForScalar: { + InitListExpr *InitList = cast(Args[0]); + + S.Diag(Kind.getLocation(), diag::err_excess_initializers) + << /*scalar=*/2 + << SourceRange(InitList->getInit(1)->getLocStart(), + InitList->getLocEnd()); + break; + } + + case FK_ReferenceBindingToInitList: + S.Diag(Kind.getLocation(), diag::err_reference_bind_init_list) + << DestType.getNonReferenceType() << Args[0]->getSourceRange(); + break; + + case FK_InitListBadDestinationType: + S.Diag(Kind.getLocation(), diag::err_init_list_bad_dest_type) + << (DestType->isRecordType()) << DestType << Args[0]->getSourceRange(); + break; } return true; diff --git a/lib/Sema/SemaInit.h b/lib/Sema/SemaInit.h index 85aa421db6..debb0deadd 100644 --- a/lib/Sema/SemaInit.h +++ b/lib/Sema/SemaInit.h @@ -1,4 +1,4 @@ -//===--- SemaInit.h - Semantic Analysis for Initializers ------------------===// +//===--- SemaInit.h - Semantic Analysis for Initializers --------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -304,7 +304,10 @@ public: DependentSequence, /// \brief A reference binding. - ReferenceBinding + ReferenceBinding, + + /// \brief List initialization + ListInitialization }; /// \brief Describes the kind of a particular step in an initialization @@ -329,7 +332,9 @@ public: /// \brief Perform a qualification conversion, producing an lvalue. SK_QualificationConversionLValue, /// \brief Perform an implicit conversion sequence. - SK_ConversionSequence + SK_ConversionSequence, + /// \brief Perform list-initialization + SK_ListInitialization }; /// \brief A single step in the initialization sequence. @@ -388,7 +393,14 @@ public: /// \brief Reference binding failed. FK_ReferenceInitFailed, /// \brief Implicit conversion failed. - FK_ConversionFailed + FK_ConversionFailed, + /// \brief Too many initializers for scalar + FK_TooManyInitsForScalar, + /// \brief Reference initialization from an initializer list + FK_ReferenceBindingToInitList, + /// \brief Initialization of some unused destination type with an + /// initializer list. + FK_InitListBadDestinationType }; private: @@ -437,13 +449,20 @@ public: /// \param Args the argument(s) provided for initialization, ownership of /// which is transfered into the routine. /// + /// \param ResultType if non-NULL, will be set to the type of the + /// initialized object, which is the type of the declaration in most + /// cases. However, when the initialized object is a variable of + /// incomplete array type and the initializer is an initializer + /// list, this type will be set to the completed array type. + /// /// \returns an expression that performs the actual object initialization, if /// the initialization is well-formed. Otherwise, emits diagnostics /// and returns an invalid expression. Action::OwningExprResult Perform(Sema &S, const InitializedEntity &Entity, const InitializationKind &Kind, - Action::MultiExprArg Args); + Action::MultiExprArg Args, + QualType *ResultType = 0); /// \brief Diagnose an potentially-invalid initialization sequence. /// @@ -501,7 +520,10 @@ public: /// \brief Add a new step that applies an implicit conversion sequence. void AddConversionSequenceStep(const ImplicitConversionSequence &ICS, QualType T); - + + /// \brief Add a list-initialiation step + void AddListInitializationStep(QualType T); + /// \brief Note that this initialization sequence failed. void SetFailed(FailureKind Failure) { SequenceKind = FailedSequence; diff --git a/test/CXX/dcl.decl/dcl.init/dcl.init.list/basic.cpp b/test/CXX/dcl.decl/dcl.init/dcl.init.list/basic.cpp new file mode 100644 index 0000000000..f62b4250ee --- /dev/null +++ b/test/CXX/dcl.decl/dcl.init/dcl.init.list/basic.cpp @@ -0,0 +1,5 @@ +// RUN: clang-cc -fsyntax-only -verify %s + +void f0() { + int &ir = { 17 }; // expected-error{{reference to type 'int' cannot bind to an initializer list}} +} -- 2.50.1