diff options
Diffstat (limited to 'lib/Sema/SemaInit.cpp')
-rw-r--r-- | lib/Sema/SemaInit.cpp | 305 |
1 files changed, 80 insertions, 225 deletions
diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp index d2122a45ae..835d837e4c 100644 --- a/lib/Sema/SemaInit.cpp +++ b/lib/Sema/SemaInit.cpp @@ -7,7 +7,9 @@ // //===----------------------------------------------------------------------===// // -// This file implements semantic analysis for initializers. +// This file implements semantic analysis for initializers. The main entry +// point is Sema::CheckInitList(), but all of the work is performed +// within the InitListChecker class. // //===----------------------------------------------------------------------===// @@ -710,7 +712,7 @@ void InitListChecker::CheckSubElementType(const InitializedEntity &Entity, } else if (SemaRef.getLangOptions().CPlusPlus) { // C++ [dcl.init.aggr]p12: // All implicit type conversions (clause 4) are considered when - // initializing the aggregate member with an initializer from + // initializing the aggregate member with an ini- tializer from // an initializer-list. If the initializer can initialize a // member, the member is initialized. [...] @@ -2382,10 +2384,52 @@ static void MaybeProduceObjCObject(Sema &S, } } -static void SelectInitialization(Sema &S, const InitializedEntity &Entity, - const InitializationKind &Kind, - Expr **Args, unsigned NumArgs, - InitializationSequence &Sequence); +/// \brief Attempt list initialization (C++0x [dcl.init.list]) +static void TryListInitialization(Sema &S, + const InitializedEntity &Entity, + const InitializationKind &Kind, + InitListExpr *InitList, + InitializationSequence &Sequence) { + // 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. 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. + + QualType DestType = Entity.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 /// function. @@ -3244,185 +3288,6 @@ static void checkIndirectCopyRestoreSource(Sema &S, Expr *src) { << src->getSourceRange(); } -static bool hasDefaultConstructor(Sema &S, CXXRecordDecl *decl) { - DeclContext::lookup_const_iterator Con, ConEnd; - for (llvm::tie(Con, ConEnd) = S.LookupConstructors(decl); - Con != ConEnd; ++Con) { - // FIXME: A constructor template can be a default constructor, but we don't - // handle this in other places as well. - if (isa<FunctionTemplateDecl>(*Con)) - continue; - CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(*Con); - if (Constructor->isDefaultConstructor()) - return true; - } - return false; -} - -/// \brief Attempt list initialization (C++0x [dcl.init.list]) -static void TryListInitialization(Sema &S, - const InitializedEntity &Entity, - const InitializationKind &Kind, - InitListExpr *InitList, - InitializationSequence &Sequence) { - QualType DestType = Entity.getType(); - - // If we're not in C++ mode, defer everything to the init list checker. - if (!S.getLangOptions().CPlusPlus) { - Sequence.AddListInitializationStep(DestType); - return; - } - - // Early error return for some C++11 features when we're in 98 mode. - if (!S.getLangOptions().CPlusPlus0x) { - if (DestType->isReferenceType()) { - Sequence.SetFailed(InitializationSequence::FK_ReferenceBindingToInitList); - return; - } - if (DestType->isRecordType() && !DestType->isAggregateType()) { - Sequence.SetFailed(InitializationSequence::FK_InitListBadDestinationType); - return; - } - } - - // If we have a reference and not exactly one initializer (see below), unwrap - // the reference. - bool wasReference = false; - if (InitList->getNumInits() != 1) { - if (const ReferenceType *ref = DestType->getAs<ReferenceType>()) { - wasReference = true; - DestType = ref->getPointeeType(); - } - } - // Create an object that automatically adds a ref binding step on successful - // return. - class AddRefBinding { - InitializationSequence &Sequence; - bool Bind; - QualType RefType; - public: - AddRefBinding(InitializationSequence &sequence, bool bind, QualType refType) - : Sequence(sequence), Bind(bind), RefType(refType) {} - ~AddRefBinding() { - if (Bind && Sequence) { - Sequence.AddReferenceBindingStep(RefType, /*temporary*/true); - } - } - } addRefBinding(Sequence, wasReference, Entity.getType()); - - // C++11 [dcl.init.list]p3: - // List-initialization of an object or reference of type T is defined as - // follows: - // - // - If the initializer list has no elements and T is a class type with - // a default constructor, the object is value-initialized. - // - // See DR990. This case is handled specially because if we let it get to - // overload resolution, std::initializer_list constructors would be chosen - // over the default constructor. When there's more than one initlist ctor, - // this would actually be ambiguous and fail. - - const RecordType *recordType = DestType->getAs<RecordType>(); - CXXRecordDecl *recordDecl = recordType ? - dyn_cast<CXXRecordDecl>(recordType->getDecl()) : 0; - if (recordDecl && InitList->getNumInits() == 0 && - hasDefaultConstructor(S, recordDecl)) { - TryValueInitialization(S, Entity, Kind, Sequence); - return; - } - - // - Otherwise, if T is an aggregate, aggregate initialization is - // performed. - // - // Aggregate initialization is the most complicated part. We delegate to - // an InitListChecker to build a representation of what's happening. - // We also treat vector types the same as aggregates. - if (DestType->isAggregateType() || DestType->isVectorType()) { - // FIXME: Deeper analysis necessary. - Sequence.AddListInitializationStep(DestType); - return; - } - - // - Otherwise, if T is a specialization of std::initializer_list<E>, an - // initializer_list object is constructed as described below and used - // to initialize the object according to the rules for initialization - // of an object from a class of the same type. - // - // FIXME: Implement this case. - - // - Otherwise, if T is a class type, constructors are considered. The - // applicable constructors are enumerated and the best one is chosen - // through overload resolution. - if (recordDecl) { - // FIXME: initializer_list constructors are applicable. - TryConstructorInitialization(S, Entity, Kind, InitList->getInits(), - InitList->getNumInits(), DestType, Sequence); - return; - } - - // At this point, there is most likely a defect in the standard. The next - // bullet grabs all reference targets and creates temporaries from the init - // list. However, this means that code such as this doesn't work: - // int i; - // int &ri { i }; // error: non-const lvalue ref cannot bind to temporary. - // This is rather startling, since this code works: - // int &si ( i ); - // - // DR934 (CD2 status) tried to address the problem by making the bullet about - // references be only about references to class types, letting references to - // other things fall through. This means the above works, but this still - // doesn't: - // string s; - // string &rs { s }; // cannot bind to temporary - // string &ss ( s ); // fine - // And this works, but has different semantics: - // const string &cs { s }; // binds to temporary copy - // const string &ds ( s ); // binds directly to s - // Also, the wording change from that DR somehow got lost in the FDIS. - // - // DR1095 (FDIS status) again discovered the problem, but didn't actually - // fix it. - // - // GCC implements it this way. We swap the next two bullets instead, thus - // always letting a reference bind to the single element of an initializer - // list, and constructing a temporary only if the isn't exactly one element. - // So in our order, the next bullet is: - // - // - Otherwise, if the initializer list has a single element, the object - // or reference is initialized from that element; - if (InitList->getNumInits() == 1) { - SelectInitialization(S, Entity, Kind, InitList->getInits(), - InitList->getNumInits(), Sequence); - // Adjust the type of the whole init list to be the same as that of the - // single initializer. - InitList->setType(InitList->getInits()[0]->getType()); - return; - } - - // - Otherwise, if T is a reference type, a prvalue temporary of the type - // referenced by T is list-initialized, and the reference is bound to - // that temporary. - // - // We implement this by unwrapping references at the start of the function - // and adding a reference binding step at the bottom. - - // - Otherwise, if the initializer list has no elements, the object is - // value-initialized. - if (InitList->getNumInits() == 0) { - TryValueInitialization(S, Entity, Kind, Sequence); - return; - } - - // - Otherwise, the program is ill-formed. - // - // The only way to get here ought to be for scalar types with > 1 inits. - assert(DestType->isScalarType() && "Something strange is list-initialized."); - assert(InitList->getNumInits() > 1 && "Strange number of initializers."); - - Sequence.SetFailed(InitializationSequence::FK_TooManyInitsForScalar); - return; -} - /// \brief Determine whether we have compatible array types for the /// purposes of GNU by-copy array initialization. static bool hasCompatibleArrayTypes(ASTContext &Context, @@ -3495,6 +3360,7 @@ InitializationSequence::InitializationSequence(Sema &S, Expr **Args, unsigned NumArgs) : FailedCandidateSet(Kind.getLocation()) { + ASTContext &Context = S.Context; // C++0x [dcl.init]p16: // The semantics of initializers are as follows. The destination type is @@ -3502,8 +3368,9 @@ InitializationSequence::InitializationSequence(Sema &S, // type is the type of the initializer expression. The source type is not // defined when the initializer is a braced-init-list or when it is a // parenthesized list of expressions. + QualType DestType = Entity.getType(); - if (Entity.getType()->isDependentType() || + if (DestType->isDependentType() || Expr::hasAnyTypeDependentArguments(Args, NumArgs)) { SequenceKind = DependentSequence; return; @@ -3512,22 +3379,11 @@ InitializationSequence::InitializationSequence(Sema &S, // Almost everything is a normal sequence. setSequenceKind(NormalSequence); - SelectInitialization(S, Entity, Kind, Args, NumArgs, *this); -} - -static void SelectInitialization(Sema &S, const InitializedEntity &Entity, - const InitializationKind &Kind, - Expr **Args, unsigned NumArgs, - InitializationSequence &Sequence) { - ASTContext &Context = S.Context; - QualType DestType = Entity.getType(); - for (unsigned I = 0; I != NumArgs; ++I) if (Args[I]->getObjectKind() == OK_ObjCProperty) { ExprResult Result = S.ConvertPropertyForRValue(Args[I]); if (Result.isInvalid()) { - Sequence.SetFailed( - InitializationSequence::FK_ConversionFromPropertyFailed); + SetFailed(FK_ConversionFromPropertyFailed); return; } Args[I] = Result.take(); @@ -3544,7 +3400,7 @@ static void SelectInitialization(Sema &S, const InitializedEntity &Entity, // - If the initializer is a braced-init-list, the object is // list-initialized (8.5.4). if (InitListExpr *InitList = dyn_cast_or_null<InitListExpr>(Initializer)) { - TryListInitialization(S, Entity, Kind, InitList, Sequence); + TryListInitialization(S, Entity, Kind, InitList, *this); return; } @@ -3556,22 +3412,22 @@ static void SelectInitialization(Sema &S, const InitializedEntity &Entity, // by an object that can be converted into a T. // (Therefore, multiple arguments are not permitted.) if (NumArgs != 1) - Sequence.SetFailed(InitializationSequence::FK_TooManyInitsForReference); + SetFailed(FK_TooManyInitsForReference); else - TryReferenceInitialization(S, Entity, Kind, Args[0], Sequence); + TryReferenceInitialization(S, Entity, Kind, Args[0], *this); return; } // - If the initializer is (), the object is value-initialized. if (Kind.getKind() == InitializationKind::IK_Value || (Kind.getKind() == InitializationKind::IK_Direct && NumArgs == 0)) { - TryValueInitialization(S, Entity, Kind, Sequence); + TryValueInitialization(S, Entity, Kind, *this); return; } // Handle default initialization. if (Kind.getKind() == InitializationKind::IK_Default) { - TryDefaultInitialization(S, Entity, Kind, Sequence); + TryDefaultInitialization(S, Entity, Kind, *this); return; } @@ -3582,7 +3438,7 @@ static void SelectInitialization(Sema &S, const InitializedEntity &Entity, // ill-formed. if (const ArrayType *DestAT = Context.getAsArrayType(DestType)) { if (Initializer && IsStringInit(Initializer, DestAT, Context)) { - TryStringLiteralInitialization(S, Entity, Kind, Initializer, Sequence); + TryStringLiteralInitialization(S, Entity, Kind, Initializer, *this); return; } @@ -3595,17 +3451,16 @@ static void SelectInitialization(Sema &S, const InitializedEntity &Entity, const ArrayType *SourceAT = Context.getAsArrayType(Initializer->getType()); if (!hasCompatibleArrayTypes(S.Context, DestAT, SourceAT)) - Sequence.SetFailed(InitializationSequence::FK_ArrayTypeMismatch); + SetFailed(FK_ArrayTypeMismatch); else if (Initializer->HasSideEffects(S.Context)) - Sequence.SetFailed(InitializationSequence::FK_NonConstantArrayInit); + SetFailed(FK_NonConstantArrayInit); else { - Sequence.AddArrayInitStep(DestType); + AddArrayInitStep(DestType); } } else if (DestAT->getElementType()->isAnyCharacterType()) - Sequence.SetFailed( - InitializationSequence::FK_ArrayNeedsInitListOrStringLiteral); + SetFailed(FK_ArrayNeedsInitListOrStringLiteral); else - Sequence.SetFailed(InitializationSequence::FK_ArrayNeedsInitList); + SetFailed(FK_ArrayNeedsInitList); return; } @@ -3620,13 +3475,13 @@ static void SelectInitialization(Sema &S, const InitializedEntity &Entity, if (!S.getLangOptions().CPlusPlus) { // If allowed, check whether this is an Objective-C writeback conversion. if (allowObjCWritebackConversion && - tryObjCWritebackConversion(S, Sequence, Entity, Initializer)) { + tryObjCWritebackConversion(S, *this, Entity, Initializer)) { return; } // Handle initialization in C - Sequence.AddCAssignmentStep(DestType); - MaybeProduceObjCObject(S, Sequence, Entity); + AddCAssignmentStep(DestType); + MaybeProduceObjCObject(S, *this, Entity); return; } @@ -3643,7 +3498,7 @@ static void SelectInitialization(Sema &S, const InitializedEntity &Entity, (Context.hasSameUnqualifiedType(SourceType, DestType) || S.IsDerivedFrom(SourceType, DestType)))) TryConstructorInitialization(S, Entity, Kind, Args, NumArgs, - Entity.getType(), Sequence); + Entity.getType(), *this); // - Otherwise (i.e., for the remaining copy-initialization cases), // user-defined conversion sequences that can convert from the source // type to the destination type or (when a conversion function is @@ -3651,12 +3506,12 @@ static void SelectInitialization(Sema &S, const InitializedEntity &Entity, // 13.3.1.4, and the best one is chosen through overload resolution // (13.3). else - TryUserDefinedConversion(S, Entity, Kind, Initializer, Sequence); + TryUserDefinedConversion(S, Entity, Kind, Initializer, *this); return; } if (NumArgs > 1) { - Sequence.SetFailed(InitializationSequence::FK_TooManyInitsForScalar); + SetFailed(FK_TooManyInitsForScalar); return; } assert(NumArgs == 1 && "Zero-argument case handled above"); @@ -3664,8 +3519,8 @@ static void SelectInitialization(Sema &S, const InitializedEntity &Entity, // - Otherwise, if the source type is a (possibly cv-qualified) class // type, conversion functions are considered. if (!SourceType.isNull() && SourceType->isRecordType()) { - TryUserDefinedConversion(S, Entity, Kind, Initializer, Sequence); - MaybeProduceObjCObject(S, Sequence, Entity); + TryUserDefinedConversion(S, Entity, Kind, Initializer, *this); + MaybeProduceObjCObject(S, *this, Entity); return; } @@ -3701,22 +3556,22 @@ static void SelectInitialization(Sema &S, const InitializedEntity &Entity, LvalueICS.Standard.setAsIdentityConversion(); LvalueICS.Standard.setAllToTypes(ICS.Standard.getToType(0)); LvalueICS.Standard.First = ICS.Standard.First; - Sequence.AddConversionSequenceStep(LvalueICS, ICS.Standard.getToType(0)); + AddConversionSequenceStep(LvalueICS, ICS.Standard.getToType(0)); } - - Sequence.AddPassByIndirectCopyRestoreStep(Entity.getType(), ShouldCopy); + + AddPassByIndirectCopyRestoreStep(Entity.getType(), ShouldCopy); } else if (ICS.isBad()) { DeclAccessPair dap; if (Initializer->getType() == Context.OverloadTy && !S.ResolveAddressOfOverloadedFunction(Initializer , DestType, false, dap)) - Sequence.SetFailed(InitializationSequence::FK_AddressOfOverloadFailed); + SetFailed(InitializationSequence::FK_AddressOfOverloadFailed); else - Sequence.SetFailed(InitializationSequence::FK_ConversionFailed); + SetFailed(InitializationSequence::FK_ConversionFailed); } else { - Sequence.AddConversionSequenceStep(ICS, Entity.getType()); + AddConversionSequenceStep(ICS, Entity.getType()); - MaybeProduceObjCObject(S, Sequence, Entity); + MaybeProduceObjCObject(S, *this, Entity); } } |