diff options
Diffstat (limited to 'lib/Sema')
-rw-r--r-- | lib/Sema/Sema.h | 3 | ||||
-rw-r--r-- | lib/Sema/SemaDeclCXX.cpp | 3 | ||||
-rw-r--r-- | lib/Sema/SemaExprCXX.cpp | 2 | ||||
-rw-r--r-- | lib/Sema/SemaInit.cpp | 299 | ||||
-rw-r--r-- | lib/Sema/SemaInit.h | 31 | ||||
-rw-r--r-- | lib/Sema/SemaStmt.cpp | 48 |
6 files changed, 342 insertions, 44 deletions
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 3d03dfd8ce..9d40a13786 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -935,6 +935,9 @@ public: bool PerformCopyInitialization(Expr *&From, QualType ToType, AssignmentAction Action, bool Elidable = false); + OwningExprResult PerformCopyInitialization(const InitializedEntity &Entity, + SourceLocation EqualLoc, + OwningExprResult Init); ImplicitConversionSequence TryObjectArgumentInitialization(QualType FromType, CXXMethodDecl *Method, CXXRecordDecl *ActingContext); diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index afddd9f02c..565fce8b5f 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -3776,6 +3776,9 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType, // FIXME: Is this enough? if (Constructor->isCopyConstructor(Context)) { Expr *E = ((Expr **)ExprArgs.get())[0]; + if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) + if (ICE->getCastKind() == CastExpr::CK_NoOp) + E = ICE->getSubExpr(); while (CXXBindTemporaryExpr *BE = dyn_cast<CXXBindTemporaryExpr>(E)) E = BE->getSubExpr(); if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index 9108137a00..7c4ab890d0 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -450,7 +450,7 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal, TypeSourceInfo *TInfo = Context.getTrivialTypeSourceInfo(AllocType, TypeLoc); InitializedEntity Entity - = InitializedEntity::InitializeTemporary(TInfo->getTypeLoc()); + = InitializedEntity::InitializeNew(StartLoc, TInfo->getTypeLoc()); InitializationSequence InitSeq(*this, Entity, Kind, ConsArgs, NumConsArgs); if (!InitSeq) { diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp index 629ab9adb3..60de672c0a 100644 --- a/lib/Sema/SemaInit.cpp +++ b/lib/Sema/SemaInit.cpp @@ -2003,6 +2003,7 @@ DeclarationName InitializedEntity::getName() const { case EK_Result: case EK_Exception: + case EK_New: case EK_Temporary: case EK_Base: case EK_ArrayOrVectorElement: @@ -2030,6 +2031,7 @@ void InitializationSequence::Step::Destroy() { case SK_ListInitialization: case SK_ConstructorInitialization: case SK_ZeroInitialization: + case SK_CAssignment: break; case SK_ConversionSequence: @@ -2115,6 +2117,13 @@ void InitializationSequence::AddZeroInitializationStep(QualType T) { Steps.push_back(S); } +void InitializationSequence::AddCAssignmentStep(QualType T) { + Step S; + S.Kind = SK_CAssignment; + S.Type = T; + Steps.push_back(S); +} + void InitializationSequence::SetOverloadFailure(FailureKind Failure, OverloadingResult Result) { SequenceKind = FailedSequence; @@ -2496,7 +2505,12 @@ static void TryReferenceInitialization(Sema &S, // this into an overloading ambiguity diagnostic. However, we need // to keep that set as an OverloadCandidateSet rather than as some // other kind of set. - Sequence.SetFailed(InitializationSequence::FK_ReferenceInitFailed); + if (ConvOvlResult && !Sequence.getFailedCandidateSet().empty()) + Sequence.SetOverloadFailure( + InitializationSequence::FK_ReferenceInitOverloadFailed, + ConvOvlResult); + else + Sequence.SetFailed(InitializationSequence::FK_ReferenceInitFailed); return; } @@ -2534,7 +2548,10 @@ static void TryConstructorInitialization(Sema &S, Expr **Args, unsigned NumArgs, QualType DestType, InitializationSequence &Sequence) { - Sequence.setSequenceKind(InitializationSequence::ConstructorInitialization); + if (Kind.getKind() == InitializationKind::IK_Copy) + Sequence.setSequenceKind(InitializationSequence::UserDefinedConversion); + else + Sequence.setSequenceKind(InitializationSequence::ConstructorInitialization); // Build the candidate set directly in the initialization sequence // structure, so that it will persist if we fail. @@ -2594,9 +2611,13 @@ static void TryConstructorInitialization(Sema &S, // Add the constructor initialization step. Any cv-qualification conversion is // subsumed by the initialization. - Sequence.AddConstructorInitializationStep( + if (Kind.getKind() == InitializationKind::IK_Copy) { + Sequence.AddUserConversionStep(Best->Function, DestType); + } else { + Sequence.AddConstructorInitializationStep( cast<CXXConstructorDecl>(Best->Function), - DestType); + DestType); + } } /// \brief Attempt value initialization (C++ [dcl.init]p7). @@ -2898,6 +2919,13 @@ InitializationSequence::InitializationSequence(Sema &S, TryDefaultInitialization(S, Entity, Kind, *this); return; } + + // Handle initialization in C + if (!S.getLangOptions().CPlusPlus) { + setSequenceKind(CAssignment); + AddCAssignmentStep(DestType); + return; + } // - Otherwise, if the destination type is an array, the program is // ill-formed. @@ -2965,6 +2993,151 @@ InitializationSequence::~InitializationSequence() { //===----------------------------------------------------------------------===// // Perform initialization //===----------------------------------------------------------------------===// +static Sema::AssignmentAction +getAssignmentAction(const InitializedEntity &Entity) { + switch(Entity.getKind()) { + case InitializedEntity::EK_Variable: + case InitializedEntity::EK_New: + return Sema::AA_Initializing; + + case InitializedEntity::EK_Parameter: + // FIXME: Can we tell when we're sending vs. passing? + return Sema::AA_Passing; + + case InitializedEntity::EK_Result: + return Sema::AA_Returning; + + case InitializedEntity::EK_Exception: + case InitializedEntity::EK_Base: + llvm_unreachable("No assignment action for C++-specific initialization"); + break; + + case InitializedEntity::EK_Temporary: + // FIXME: Can we tell apart casting vs. converting? + return Sema::AA_Casting; + + case InitializedEntity::EK_Member: + case InitializedEntity::EK_ArrayOrVectorElement: + return Sema::AA_Initializing; + } + + return Sema::AA_Converting; +} + +static bool shouldBindAsTemporary(const InitializedEntity &Entity, + bool IsCopy) { + switch (Entity.getKind()) { + case InitializedEntity::EK_Result: + case InitializedEntity::EK_Exception: + return !IsCopy; + + case InitializedEntity::EK_New: + case InitializedEntity::EK_Variable: + case InitializedEntity::EK_Base: + case InitializedEntity::EK_Member: + case InitializedEntity::EK_ArrayOrVectorElement: + return false; + + case InitializedEntity::EK_Parameter: + case InitializedEntity::EK_Temporary: + return true; + } + + llvm_unreachable("missed an InitializedEntity kind?"); +} + +/// \brief If we need to perform an additional copy of the initialized object +/// for this kind of entity (e.g., the result of a function or an object being +/// thrown), make the copy. +static Sema::OwningExprResult CopyIfRequiredForEntity(Sema &S, + const InitializedEntity &Entity, + Sema::OwningExprResult CurInit) { + SourceLocation Loc; + bool isReturn = false; + + switch (Entity.getKind()) { + case InitializedEntity::EK_Result: + if (Entity.getType().getType()->isReferenceType()) + return move(CurInit); + isReturn = true; + Loc = Entity.getReturnLoc(); + break; + + case InitializedEntity::EK_Exception: + isReturn = false; + Loc = Entity.getThrowLoc(); + break; + + case InitializedEntity::EK_Variable: + case InitializedEntity::EK_Parameter: + case InitializedEntity::EK_New: + case InitializedEntity::EK_Temporary: + case InitializedEntity::EK_Base: + case InitializedEntity::EK_Member: + case InitializedEntity::EK_ArrayOrVectorElement: + // We don't need to copy for any of these initialized entities. + return move(CurInit); + } + + Expr *CurInitExpr = (Expr *)CurInit.get(); + CXXRecordDecl *Class = 0; + if (const RecordType *Record = CurInitExpr->getType()->getAs<RecordType>()) + Class = cast<CXXRecordDecl>(Record->getDecl()); + if (!Class) + return move(CurInit); + + // Perform overload resolution using the class's copy constructors. + DeclarationName ConstructorName + = S.Context.DeclarationNames.getCXXConstructorName( + S.Context.getCanonicalType(S.Context.getTypeDeclType(Class))); + DeclContext::lookup_iterator Con, ConEnd; + OverloadCandidateSet CandidateSet; + for (llvm::tie(Con, ConEnd) = Class->lookup(ConstructorName); + Con != ConEnd; ++Con) { + // Find the constructor (which may be a template). + CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(*Con); + if (!Constructor || Constructor->isInvalidDecl() || + !Constructor->isCopyConstructor(S.Context)) + continue; + + S.AddOverloadCandidate(Constructor, &CurInitExpr, 1, CandidateSet); + } + + OverloadCandidateSet::iterator Best; + switch (S.BestViableFunction(CandidateSet, Loc, Best)) { + case OR_Success: + break; + + case OR_No_Viable_Function: + S.Diag(Loc, diag::err_temp_copy_no_viable) + << isReturn << CurInitExpr->getType() + << CurInitExpr->getSourceRange(); + S.PrintOverloadCandidates(CandidateSet, false); + return S.ExprError(); + + case OR_Ambiguous: + S.Diag(Loc, diag::err_temp_copy_ambiguous) + << isReturn << CurInitExpr->getType() + << CurInitExpr->getSourceRange(); + S.PrintOverloadCandidates(CandidateSet, true); + return S.ExprError(); + + case OR_Deleted: + S.Diag(Loc, diag::err_temp_copy_deleted) + << isReturn << CurInitExpr->getType() + << CurInitExpr->getSourceRange(); + S.Diag(Best->Function->getLocation(), diag::note_unavailable_here) + << Best->Function->isDeleted(); + return S.ExprError(); + } + + CurInit.release(); + return S.BuildCXXConstructExpr(Loc, CurInitExpr->getType(), + cast<CXXConstructorDecl>(Best->Function), + /*Elidable=*/true, + Sema::MultiExprArg(S, + (void**)&CurInitExpr, 1)); +} Action::OwningExprResult InitializationSequence::Perform(Sema &S, @@ -3040,26 +3213,26 @@ InitializationSequence::Perform(Sema &S, // grab the only argument out the Args and place it into the "current" // initializer. switch (Steps.front().Kind) { - case SK_ResolveAddressOfOverloadedFunction: - case SK_CastDerivedToBaseRValue: - case SK_CastDerivedToBaseLValue: - case SK_BindReference: - case SK_BindReferenceToTemporary: - case SK_UserConversion: - case SK_QualificationConversionLValue: - case SK_QualificationConversionRValue: - case SK_ConversionSequence: - case SK_ListInitialization: - assert(Args.size() == 1); - CurInit = Sema::OwningExprResult(S, - ((Expr **)(Args.get()))[0]->Retain()); - if (CurInit.isInvalid()) - return S.ExprError(); - break; - - case SK_ConstructorInitialization: - case SK_ZeroInitialization: - break; + case SK_ResolveAddressOfOverloadedFunction: + case SK_CastDerivedToBaseRValue: + case SK_CastDerivedToBaseLValue: + case SK_BindReference: + case SK_BindReferenceToTemporary: + case SK_UserConversion: + case SK_QualificationConversionLValue: + case SK_QualificationConversionRValue: + case SK_ConversionSequence: + case SK_ListInitialization: + case SK_CAssignment: + assert(Args.size() == 1); + CurInit = Sema::OwningExprResult(S, ((Expr **)(Args.get()))[0]->Retain()); + if (CurInit.isInvalid()) + return S.ExprError(); + break; + + case SK_ConstructorInitialization: + case SK_ZeroInitialization: + break; } // Walk through the computed steps for the initialization sequence, @@ -3131,6 +3304,7 @@ InitializationSequence::Perform(Sema &S, // We have a user-defined conversion that invokes either a constructor // or a conversion function. CastExpr::CastKind CastKind = CastExpr::CK_Unknown; + bool IsCopy = false; if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(Step->Function)) { // Build a call to the selected constructor. @@ -3154,10 +3328,14 @@ InitializationSequence::Perform(Sema &S, return S.ExprError(); CastKind = CastExpr::CK_ConstructorConversion; + QualType Class = S.Context.getTypeDeclType(Constructor->getParent()); + if (S.Context.hasSameUnqualifiedType(SourceType, Class) || + S.IsDerivedFrom(SourceType, Class)) + IsCopy = true; } else { // Build a call to the conversion function. CXXConversionDecl *Conversion = cast<CXXConversionDecl>(Step->Function); - + // FIXME: Should we move this initialization into a separate // derived-to-base conversion? I believe the answer is "no", because // we don't want to turn off access control here for c-style casts. @@ -3176,12 +3354,17 @@ InitializationSequence::Perform(Sema &S, CastKind = CastExpr::CK_UserDefinedConversion; } - CurInit = S.MaybeBindToTemporary(CurInit.takeAs<Expr>()); + if (shouldBindAsTemporary(Entity, IsCopy)) + CurInit = S.MaybeBindToTemporary(CurInit.takeAs<Expr>()); + CurInitExpr = CurInit.takeAs<Expr>(); CurInit = S.Owned(new (S.Context) ImplicitCastExpr(CurInitExpr->getType(), CastKind, CurInitExpr, - false)); + false)); + + if (!IsCopy) + CurInit = CopyIfRequiredForEntity(S, Entity, move(CurInit)); break; } @@ -3235,7 +3418,14 @@ InitializationSequence::Perform(Sema &S, ConstructorInitRequiresZeroInit); if (CurInit.isInvalid()) return S.ExprError(); - + + bool Elidable + = cast<CXXConstructExpr>((Expr *)CurInit.get())->isElidable(); + if (shouldBindAsTemporary(Entity, Elidable)) + CurInit = S.MaybeBindToTemporary(CurInit.takeAs<Expr>()); + + if (!Elidable) + CurInit = CopyIfRequiredForEntity(S, Entity, move(CurInit)); break; } @@ -3258,6 +3448,20 @@ InitializationSequence::Perform(Sema &S, } break; } + + case SK_CAssignment: { + QualType SourceType = CurInitExpr->getType(); + Sema::AssignConvertType ConvTy = + S.CheckSingleAssignmentConstraints(Step->Type, CurInitExpr); + if (S.DiagnoseAssignmentResult(ConvTy, Kind.getLocation(), + Step->Type, SourceType, + CurInitExpr, getAssignmentAction(Entity))) + return S.ExprError(); + + CurInit.release(); + CurInit = S.Owned(CurInitExpr); + break; + } } } @@ -3297,9 +3501,15 @@ bool InitializationSequence::Diagnose(Sema &S, case FK_UserConversionOverloadFailed: switch (FailedOverloadResult) { case OR_Ambiguous: - S.Diag(Kind.getLocation(), diag::err_typecheck_ambiguous_condition) - << Args[0]->getType() << DestType.getNonReferenceType() - << Args[0]->getSourceRange(); + if (Failure == FK_UserConversionOverloadFailed) + S.Diag(Kind.getLocation(), diag::err_typecheck_ambiguous_condition) + << Args[0]->getType() << DestType + << Args[0]->getSourceRange(); + else + S.Diag(Kind.getLocation(), diag::err_ref_init_ambiguous) + << DestType << Args[0]->getType() + << Args[0]->getSourceRange(); + S.PrintOverloadCandidates(FailedCandidateSet, true); break; @@ -3365,7 +3575,8 @@ bool InitializationSequence::Diagnose(Sema &S, break; case FK_ConversionFailed: - S.Diag(Kind.getLocation(), diag::err_cannot_initialize_decl_noname) + S.Diag(Kind.getLocation(), diag::err_init_conversion_failed) + << (int)Entity.getKind() << DestType << (Args[0]->isLvalue(S.Context) == Expr::LV_Valid) << Args[0]->getType() @@ -3448,3 +3659,27 @@ bool InitializationSequence::Diagnose(Sema &S, return true; } + +//===----------------------------------------------------------------------===// +// Initialization helper functions +//===----------------------------------------------------------------------===// +Sema::OwningExprResult +Sema::PerformCopyInitialization(const InitializedEntity &Entity, + SourceLocation EqualLoc, + OwningExprResult Init) { + if (Init.isInvalid()) + return ExprError(); + + Expr *InitE = (Expr *)Init.get(); + assert(InitE && "No initialization expression?"); + + if (EqualLoc.isInvalid()) + EqualLoc = InitE->getLocStart(); + + InitializationKind Kind = InitializationKind::CreateCopy(InitE->getLocStart(), + EqualLoc); + InitializationSequence Seq(*this, Entity, Kind, &InitE, 1); + Init.release(); + return Seq.Perform(*this, Entity, Kind, + MultiExprArg(*this, (void**)&InitE, 1)); +} diff --git a/lib/Sema/SemaInit.h b/lib/Sema/SemaInit.h index da6587bcca..c42badd3f8 100644 --- a/lib/Sema/SemaInit.h +++ b/lib/Sema/SemaInit.h @@ -47,6 +47,9 @@ public: /// \brief The entity being initialized is an exception object that /// is being thrown. EK_Exception, + /// \brief The entity being initialized is an object (or array of + /// objects) allocated via new. + EK_New, /// \brief The entity being initialized is a temporary object. EK_Temporary, /// \brief The entity being initialized is a base member subobject. @@ -76,9 +79,10 @@ private: /// the VarDecl, ParmVarDecl, or FieldDecl, respectively. DeclaratorDecl *VariableOrMember; - /// \brief When Kind == EK_Result or EK_Exception, the location of the - /// 'return' or 'throw' keyword, respectively. When Kind == EK_Temporary, - /// the location where the temporary is being created. + /// \brief When Kind == EK_Result, EK_Exception, or EK_New, the + /// location of the 'return', 'throw', or 'new' keyword, + /// respectively. When Kind == EK_Temporary, the location where + /// the temporary is being created. unsigned Location; /// \brief When Kind == EK_Base, the base specifier that provides the @@ -150,6 +154,11 @@ public: TypeLoc TL) { return InitializedEntity(EK_Exception, ThrowLoc, TL); } + + /// \brief Create the initialization entity for an object allocated via new. + static InitializedEntity InitializeNew(SourceLocation NewLoc, TypeLoc TL) { + return InitializedEntity(EK_New, NewLoc, TL); + } /// \brief Create the initialization entity for a temporary. static InitializedEntity InitializeTemporary(TypeLoc TL) { @@ -373,7 +382,10 @@ public: NoInitialization, /// \brief Standard conversion sequence. - StandardConversion + StandardConversion, + + /// \brief C conversion sequence. + CAssignment }; /// \brief Describes the kind of a particular step in an initialization @@ -404,7 +416,9 @@ public: /// \brief Perform initialization via a constructor. SK_ConstructorInitialization, /// \brief Zero-initialize the object - SK_ZeroInitialization + SK_ZeroInitialization, + /// \brief C assignment + SK_CAssignment }; /// \brief A single step in the initialization sequence. @@ -607,6 +621,13 @@ public: /// \brief Add a zero-initialization step. void AddZeroInitializationStep(QualType T); + /// \brief Add a C assignment step. + // + // FIXME: It isn't clear whether this should ever be needed; + // ideally, we would handle everything needed in C in the common + // path. However, that isn't the case yet. + void AddCAssignmentStep(QualType T); + /// \brief Note that this initialization sequence failed. void SetFailed(FailureKind Failure) { SequenceKind = FailedSequence; diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp index 10f0be6e67..e09243372e 100644 --- a/lib/Sema/SemaStmt.cpp +++ b/lib/Sema/SemaStmt.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "Sema.h" +#include "SemaInit.h" #include "clang/AST/APValue.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclObjC.h" @@ -1027,11 +1028,23 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, ExprArg rex) { return ActOnBlockReturnStmt(ReturnLoc, RetValExp); QualType FnRetType; + TypeLoc FnRetTypeLoc; if (const FunctionDecl *FD = getCurFunctionDecl()) { FnRetType = FD->getResultType(); if (FD->hasAttr<NoReturnAttr>()) Diag(ReturnLoc, diag::warn_noreturn_function_has_return_expr) << getCurFunctionOrMethodDecl()->getDeclName(); + +#if 0 + // FIXME: Useful, once we're sure it has all of the information we + // need. + if (TypeSourceInfo *TInfo = FD->getTypeSourceInfo()) { + TypeLoc TL = TInfo->getTypeLoc(); + if (FunctionTypeLoc *FTL = dyn_cast<FunctionTypeLoc>(&TL)) + FnRetTypeLoc = FTL->getResultLoc(); + } +#endif + } else if (ObjCMethodDecl *MD = getCurMethodDecl()) FnRetType = MD->getResultType(); else // If we don't have a function/method context, bail. @@ -1092,17 +1105,40 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, ExprArg rex) { bool Elidable = getLangOptions().CPlusPlus0x ? IsReturnCopyElidable(Context, FnRetType, RetValExp) : false; + // FIXME: Elidable + (void)Elidable; + + // If we somehow didn't get a + + // FIXME: Should we allocate the TypeSourceInfo and attach it to + // the declaration? Alternatively, we could require that all + // function and method declarations have TypeSourceInfos, so that + // this is never required. FIXME: Also, the allocated TInfo goes + // into the bump pointer, so it cannot actually be freed. + TypeSourceInfo *AllocatedTInfo = 0; + if (!FnRetTypeLoc) { + const FunctionDecl *FD = getCurFunctionDecl(); + SourceLocation Loc = FD? FD->getLocation() + : getCurMethodDecl()->getLocation(); + AllocatedTInfo = Context.getTrivialTypeSourceInfo(FnRetType, Loc); + FnRetTypeLoc = AllocatedTInfo->getTypeLoc(); + } // In C++ the return statement is handled via a copy initialization. // the C version of which boils down to CheckSingleAssignmentConstraints. - // FIXME: Leaks RetValExp on error. - if (PerformCopyInitialization(RetValExp, FnRetType, AA_Returning, Elidable)){ - // We should still clean up our temporaries, even when we're failing! - RetValExp = MaybeCreateCXXExprWithTemporaries(RetValExp); + rex = PerformCopyInitialization( + InitializedEntity::InitializeResult(ReturnLoc, + FnRetTypeLoc), + SourceLocation(), + Owned(RetValExp)); + if (rex.isInvalid()) { + // FIXME: Cleanup temporaries here, anyway? return StmtError(); } - - if (RetValExp) CheckReturnStackAddr(RetValExp, FnRetType, ReturnLoc); + + RetValExp = rex.takeAs<Expr>(); + if (RetValExp) + CheckReturnStackAddr(RetValExp, FnRetType, ReturnLoc); } if (RetValExp) |