diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index 44e1a77a0d75..785e40b16526 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -1969,6 +1969,7 @@ void InitializationSequence::Step::Destroy() { case SK_QualificationConversionRValue: case SK_QualificationConversionLValue: case SK_ListInitialization: + case SK_ConstructorInitialization: break; case SK_ConversionSequence: @@ -2036,6 +2037,17 @@ void InitializationSequence::AddListInitializationStep(QualType T) { Steps.push_back(S); } +void +InitializationSequence::AddConstructorInitializationStep( + CXXConstructorDecl *Constructor, + QualType T) { + Step S; + S.Kind = SK_ConstructorInitialization; + S.Type = T; + S.Function = Constructor; + Steps.push_back(S); +} + void InitializationSequence::SetOverloadFailure(FailureKind Failure, OverloadingResult Result) { SequenceKind = FailedSequence; @@ -2462,7 +2474,70 @@ static void TryConstructorInitialization(Sema &S, const InitializationKind &Kind, Expr **Args, unsigned NumArgs, InitializationSequence &Sequence) { - // FIXME: Implement! + Sequence.setSequenceKind(InitializationSequence::ConstructorConversion); + + // Build the candidate set directly in the initialization sequence + // structure, so that it will persist if we fail. + OverloadCandidateSet &CandidateSet = Sequence.getFailedCandidateSet(); + CandidateSet.clear(); + + // Determine whether we are allowed to call explicit constructors or + // explicit conversion operators. + bool AllowExplicit = (Kind.getKind() == InitializationKind::IK_Direct || + Kind.getKind() == InitializationKind::IK_Value || + Kind.getKind() == InitializationKind::IK_Default); + + // The type we're converting to is a class type. Enumerate its constructors + // to see if one is suitable. + QualType DestType = Entity.getType().getType(); + const RecordType *DestRecordType = DestType->getAs(); + assert(DestRecordType && "Constructor initialization requires record type"); + CXXRecordDecl *DestRecordDecl + = cast(DestRecordType->getDecl()); + + DeclarationName ConstructorName + = S.Context.DeclarationNames.getCXXConstructorName( + S.Context.getCanonicalType(DestType).getUnqualifiedType()); + DeclContext::lookup_iterator Con, ConEnd; + for (llvm::tie(Con, ConEnd) = DestRecordDecl->lookup(ConstructorName); + Con != ConEnd; ++Con) { + // Find the constructor (which may be a template). + CXXConstructorDecl *Constructor = 0; + FunctionTemplateDecl *ConstructorTmpl + = dyn_cast(*Con); + if (ConstructorTmpl) + Constructor = cast( + ConstructorTmpl->getTemplatedDecl()); + else + Constructor = cast(*Con); + + if (!Constructor->isInvalidDecl() && + Constructor->isConvertingConstructor(AllowExplicit)) { + if (ConstructorTmpl) + S.AddTemplateOverloadCandidate(ConstructorTmpl, /*ExplicitArgs*/ 0, + Args, NumArgs, CandidateSet); + else + S.AddOverloadCandidate(Constructor, Args, NumArgs, CandidateSet); + } + } + + SourceLocation DeclLoc = Kind.getLocation(); + + // Perform overload resolution. If it fails, return the failed result. + OverloadCandidateSet::iterator Best; + if (OverloadingResult Result + = S.BestViableFunction(CandidateSet, DeclLoc, Best)) { + Sequence.SetOverloadFailure( + InitializationSequence::FK_ConstructorOverloadFailed, + Result); + return; + } + + // Add the constructor initialization step. Any cv-qualification conversion is + // subsumed by the initialization. + Sequence.AddConstructorInitializationStep( + cast(Best->Function), + DestType); } /// \brief Attempt a user-defined conversion between two types (C++ [dcl.init]), @@ -2968,6 +3043,30 @@ InitializationSequence::Perform(Sema &S, CurInit = S.Owned(InitList); break; } + + case SK_ConstructorInitialization: { + CXXConstructorDecl *Constructor + = cast(Step->Function); + + // Build a call to the selected constructor. + ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(S); + SourceLocation Loc = Kind.getLocation(); + + // Determine the arguments required to actually perform the constructor + // call. + if (S.CompleteConstructorCall(Constructor, move(Args), + Loc, ConstructorArgs)) + return S.ExprError(); + + // Build the an expression that constructs a temporary. + CurInit = S.BuildCXXConstructExpr(Loc, Step->Type, Constructor, + move_arg(ConstructorArgs)); + if (CurInit.isInvalid()) + return S.ExprError(); + + CurInit = S.MaybeBindToTemporary(CurInit.takeAs()); + break; + } } } @@ -3101,6 +3200,50 @@ bool InitializationSequence::Diagnose(Sema &S, S.Diag(Kind.getLocation(), diag::err_init_list_bad_dest_type) << (DestType->isRecordType()) << DestType << Args[0]->getSourceRange(); break; + + case FK_ConstructorOverloadFailed: { + SourceRange ArgsRange; + if (NumArgs) + ArgsRange = SourceRange(Args[0]->getLocStart(), + Args[NumArgs - 1]->getLocEnd()); + + // FIXME: Using "DestType" for the entity we're printing is probably + // bad. + switch (FailedOverloadResult) { + case OR_Ambiguous: + S.Diag(Kind.getLocation(), diag::err_ovl_ambiguous_init) + << DestType << ArgsRange; + S.PrintOverloadCandidates(FailedCandidateSet, true); + break; + + case OR_No_Viable_Function: + S.Diag(Kind.getLocation(), diag::err_ovl_no_viable_function_in_init) + << DestType << ArgsRange; + S.PrintOverloadCandidates(FailedCandidateSet, false); + break; + + case OR_Deleted: { + S.Diag(Kind.getLocation(), diag::err_ovl_deleted_init) + << true << DestType << ArgsRange; + OverloadCandidateSet::iterator Best; + OverloadingResult Ovl = S.BestViableFunction(FailedCandidateSet, + Kind.getLocation(), + Best); + if (Ovl == OR_Deleted) { + S.Diag(Best->Function->getLocation(), diag::note_unavailable_here) + << Best->Function->isDeleted(); + } else { + llvm_unreachable("Inconsistent overload resolution?"); + } + break; + } + + case OR_Success: + llvm_unreachable("Conversion did not fail!"); + break; + } + break; + } } return true; diff --git a/clang/lib/Sema/SemaInit.h b/clang/lib/Sema/SemaInit.h index 22484745da25..7f28baa9bd21 100644 --- a/clang/lib/Sema/SemaInit.h +++ b/clang/lib/Sema/SemaInit.h @@ -306,6 +306,9 @@ public: /// \brief A user-defined conversion sequence. UserDefinedConversion, + /// \brief A constructor call. + ConstructorConversion, + /// \brief A reference binding. ReferenceBinding, @@ -337,7 +340,9 @@ public: /// \brief Perform an implicit conversion sequence. SK_ConversionSequence, /// \brief Perform list-initialization - SK_ListInitialization + SK_ListInitialization, + /// \brief Perform initialization via a constructor. + SK_ConstructorInitialization }; /// \brief A single step in the initialization sequence. @@ -405,7 +410,9 @@ public: /// initializer list. FK_InitListBadDestinationType, /// \brief Overloading for a user-defined conversion failed. - FK_UserConversionOverloadFailed + FK_UserConversionOverloadFailed, + /// \brief Overloaded for initialization by constructor failed. + FK_ConstructorOverloadFailed }; private: @@ -529,6 +536,10 @@ public: /// \brief Add a list-initialiation step void AddListInitializationStep(QualType T); + /// \brief Add a a constructor-initialization step. + void AddConstructorInitializationStep(CXXConstructorDecl *Constructor, + QualType T); + /// \brief Note that this initialization sequence failed. void SetFailed(FailureKind Failure) { SequenceKind = FailedSequence;