diff options
Diffstat (limited to 'lib/Sema')
-rw-r--r-- | lib/Sema/Sema.h | 25 | ||||
-rw-r--r-- | lib/Sema/SemaCXXCast.cpp | 5 | ||||
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 34 | ||||
-rw-r--r-- | lib/Sema/SemaDeclCXX.cpp | 23 | ||||
-rw-r--r-- | lib/Sema/SemaExprCXX.cpp | 20 | ||||
-rw-r--r-- | lib/Sema/SemaInit.cpp | 970 | ||||
-rw-r--r-- | lib/Sema/SemaInit.h | 530 | ||||
-rw-r--r-- | lib/Sema/SemaOverload.cpp | 26 | ||||
-rw-r--r-- | lib/Sema/SemaOverload.h | 21 |
9 files changed, 1602 insertions, 52 deletions
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 6f47cd0bc9..ad903a0816 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -95,7 +95,10 @@ namespace clang { class CXXBasePaths; class CXXTemporary; class LookupResult; - + class InitializedEntity; + class InitializationKind; + class InitializationSequence; + /// BlockSemaInfo - When a block is being parsed, this contains information /// about the block. It is pointed to from Sema::CurBlock. struct BlockSemaInfo { @@ -812,16 +815,6 @@ public: return NULL; } - /// OverloadingResult - Capture the result of performing overload - /// resolution. - enum OverloadingResult { - OR_Success, ///< Overload resolution succeeded. - OR_No_Viable_Function, ///< No viable function found. - OR_Ambiguous, ///< Ambiguous candidates found. - OR_Deleted ///< Overload resoltuion refers to a deleted function. - }; - - /// Subroutines of ActOnDeclarator(). TypedefDecl *ParseTypedefDecl(Scope *S, Declarator &D, QualType T, TypeSourceInfo *TInfo); @@ -1011,6 +1004,8 @@ public: FunctionDecl *ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, bool Complain); Expr *FixOverloadedFunctionReference(Expr *E, FunctionDecl *Fn); + OwningExprResult FixOverloadedFunctionReference(OwningExprResult, + FunctionDecl *Fn); void AddOverloadedCallCandidates(llvm::SmallVectorImpl<NamedDecl*>& Callees, DeclarationName &UnqualifiedName, @@ -1854,14 +1849,6 @@ public: /// it simply returns the passed in expression. OwningExprResult MaybeBindToTemporary(Expr *E); - /// InitializationKind - Represents which kind of C++ initialization - /// [dcl.init] a routine is to perform. - enum InitializationKind { - IK_Direct, ///< Direct initialization - IK_Copy, ///< Copy initialization - IK_Default ///< Default initialization - }; - CXXConstructorDecl * TryInitializationByConstructor(QualType ClassType, Expr **Args, unsigned NumArgs, diff --git a/lib/Sema/SemaCXXCast.cpp b/lib/Sema/SemaCXXCast.cpp index f9138902a6..857241d714 100644 --- a/lib/Sema/SemaCXXCast.cpp +++ b/lib/Sema/SemaCXXCast.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "Sema.h" +#include "SemaInit.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/ASTContext.h" #include "clang/AST/CXXInheritance.h" @@ -864,7 +865,9 @@ TryStaticImplicitCast(Sema &Self, Expr *&SrcExpr, QualType DestType, if (CXXConstructorDecl *Constructor = Self.TryInitializationByConstructor(DestType, &SrcExpr, 1, OpRange.getBegin(), - Sema::IK_Direct)) { + InitializationKind::CreateDirect(OpRange.getBegin(), + OpRange.getBegin(), + OpRange.getEnd()))) { ConversionDecl = Constructor; Kind = CastExpr::CK_ConstructorConversion; return TC_Success; diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 96b6c16485..bf6863bbf4 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "Sema.h" +#include "SemaInit.h" #include "Lookup.h" #include "clang/AST/APValue.h" #include "clang/AST/ASTConsumer.h" @@ -3486,8 +3487,35 @@ 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 (CheckInitializerTypes(Init, DclT, VDecl->getLocation(), - VDecl->getDeclName(), DirectInit)) + if (VDecl->getType()->isReferenceType()) { + InitializedEntity Entity + = InitializedEntity::InitializeVariable(VDecl); + + // FIXME: Poor source location information. + InitializationKind Kind + = DirectInit? InitializationKind::CreateDirect(VDecl->getLocation(), + SourceLocation(), + SourceLocation()) + : InitializationKind::CreateCopy(VDecl->getLocation(), + SourceLocation()); + InitializationSequence InitSeq(*this, Entity, Kind, &Init, 1); + if (InitSeq) { + OwningExprResult Result = InitSeq.Perform(*this, Entity, Kind, + MultiExprArg(*this, (void**)&Init, 1)); + if (Result.isInvalid()) { + VDecl->setInvalidDecl(); + return; + } + + Init = Result.takeAs<Expr>(); + } else { + InitSeq.Diagnose(*this, Entity, Kind, &Init, 1); + VDecl->setInvalidDecl(); + return; + } + + } else if (CheckInitializerTypes(Init, DclT, VDecl->getLocation(), + VDecl->getDeclName(), DirectInit)) VDecl->setInvalidDecl(); // C++ 3.6.2p2, allow dynamic initialization of static initializers. @@ -3677,7 +3705,7 @@ void Sema::ActOnUninitializedDecl(DeclPtrTy dcl, SourceRange(Var->getLocation(), Var->getLocation()), Var->getDeclName(), - IK_Default, + InitializationKind::CreateDefault(Var->getLocation()), ConstructorArgs); // FIXME: Location info for the variable initialization? diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 6f8a4f16d3..d977ad6000 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "Sema.h" +#include "SemaInit.h" #include "Lookup.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" @@ -1108,7 +1109,8 @@ Sema::BuildMemberInitializer(FieldDecl *Member, Expr **Args, NumArgs), IdLoc, SourceRange(IdLoc, RParenLoc), - Member->getDeclName(), IK_Direct, + Member->getDeclName(), + InitializationKind::CreateDirect(IdLoc, LParenLoc, RParenLoc), ConstructorArgs); if (C) { @@ -1232,7 +1234,8 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo, (void**)Args, NumArgs), BaseLoc, SourceRange(BaseLoc, RParenLoc), - Name, IK_Direct, + Name, + InitializationKind::CreateDirect(BaseLoc, LParenLoc, RParenLoc), ConstructorArgs); if (C) { // Take over the constructor arguments as our own. @@ -3656,7 +3659,9 @@ void Sema::AddCXXDirectInitializerToDecl(DeclPtrTy Dcl, SourceRange(VDecl->getLocation(), RParenLoc), VDecl->getDeclName(), - IK_Direct, + InitializationKind::CreateDirect(VDecl->getLocation(), + LParenLoc, + RParenLoc), ConstructorArgs); if (!Constructor) RealDecl->setInvalidDecl(); @@ -3692,7 +3697,7 @@ static void AddConstructorInitializationCandidates(Sema &SemaRef, QualType ClassType, Expr **Args, unsigned NumArgs, - Sema::InitializationKind Kind, + InitializationKind Kind, OverloadCandidateSet &CandidateSet) { // C++ [dcl.init]p14: // If the initialization is direct-initialization, or if it is @@ -3727,10 +3732,12 @@ static void AddConstructorInitializationCandidates(Sema &SemaRef, else Constructor = cast<CXXConstructorDecl>(*Con); - if ((Kind == Sema::IK_Direct) || - (Kind == Sema::IK_Copy && + if ((Kind.getKind() == InitializationKind::IK_Direct) || + (Kind.getKind() == InitializationKind::IK_Value) || + (Kind.getKind() == InitializationKind::IK_Copy && Constructor->isConvertingConstructor(/*AllowExplicit=*/false)) || - (Kind == Sema::IK_Default && Constructor->isDefaultConstructor())) { + ((Kind.getKind() == InitializationKind::IK_Default) && + Constructor->isDefaultConstructor())) { if (ConstructorTmpl) SemaRef.AddTemplateOverloadCandidate(ConstructorTmpl, /*ExplicitArgs*/ 0, @@ -4002,7 +4009,7 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType, // real, update the initializer with the resulting function. if (!ICS) { if (DiagnoseUseOfDecl(Fn, DeclLoc)) - return true; + return true; Init = FixOverloadedFunctionReference(Init, Fn); } diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index 16c5275d7d..5e0ce666ea 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "Sema.h" +#include "SemaInit.h" #include "Lookup.h" #include "clang/AST/ASTContext.h" #include "clang/AST/CXXInheritance.h" @@ -225,7 +226,9 @@ Sema::ActOnCXXTypeConstructExpr(SourceRange TypeRange, TypeTy *TypeRep, SourceRange(TypeRange.getBegin(), RParenLoc), DeclarationName(), - IK_Direct, + InitializationKind::CreateDirect(TypeRange.getBegin(), + LParenLoc, + RParenLoc), ConstructorArgs); if (!Constructor) @@ -449,12 +452,17 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal, // Skip all the checks. } else if ((RT = AllocType->getAs<RecordType>()) && !AllocType->isAggregateType()) { + InitializationKind InitKind = InitializationKind::CreateDefault(TypeLoc); + if (NumConsArgs > 0) + InitKind = InitializationKind::CreateDirect(TypeLoc, + PlacementLParen, + PlacementRParen); Constructor = PerformInitializationByConstructor( AllocType, move(ConstructorArgs), TypeLoc, SourceRange(TypeLoc, ConstructorRParen), RT->getDecl()->getDeclName(), - NumConsArgs != 0 ? IK_Direct : IK_Default, + InitKind, ConvertedConstructorArgs); if (!Constructor) return ExprError(); @@ -1584,7 +1592,7 @@ static bool FindConditionalOverload(Sema &Self, Expr *&LHS, Expr *&RHS, OverloadCandidateSet::iterator Best; switch (Self.BestViableFunction(CandidateSet, Loc, Best)) { - case Sema::OR_Success: + case OR_Success: // We found a match. Perform the conversions on the arguments and move on. if (Self.PerformImplicitConversion(LHS, Best->BuiltinTypes.ParamTypes[0], Best->Conversions[0], "converting") || @@ -1593,13 +1601,13 @@ static bool FindConditionalOverload(Sema &Self, Expr *&LHS, Expr *&RHS, break; return false; - case Sema::OR_No_Viable_Function: + case OR_No_Viable_Function: Self.Diag(Loc, diag::err_typecheck_cond_incompatible_operands) << LHS->getType() << RHS->getType() << LHS->getSourceRange() << RHS->getSourceRange(); return true; - case Sema::OR_Ambiguous: + case OR_Ambiguous: Self.Diag(Loc, diag::err_conditional_ambiguous_ovl) << LHS->getType() << RHS->getType() << LHS->getSourceRange() << RHS->getSourceRange(); @@ -1607,7 +1615,7 @@ static bool FindConditionalOverload(Sema &Self, Expr *&LHS, Expr *&RHS, // the viable candidates. break; - case Sema::OR_Deleted: + case OR_Deleted: assert(false && "Conditional operator has only built-in overloads"); break; } diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp index 4b0fc84b30..d2ae906eff 100644 --- a/lib/Sema/SemaInit.cpp +++ b/lib/Sema/SemaInit.cpp @@ -15,11 +15,13 @@ // //===----------------------------------------------------------------------===// +#include "SemaInit.h" #include "Sema.h" #include "clang/Parse/Designator.h" #include "clang/AST/ASTContext.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/ExprObjC.h" +#include "llvm/Support/ErrorHandling.h" #include <map> using namespace clang; @@ -76,7 +78,7 @@ static bool CheckSingleInitializer(Expr *&Init, QualType DeclType, OverloadCandidateSet CandidateSet; if (S.IsUserDefinedConversion(Init, DeclType, ICS.UserDefined, CandidateSet, - true, false, false) != S.OR_Ambiguous) + true, false, false) != OR_Ambiguous) return S.Diag(Init->getSourceRange().getBegin(), diag::err_typecheck_convert_incompatible) << DeclType << Init->getType() << "initializing" @@ -230,13 +232,20 @@ bool Sema::CheckInitializerTypes(Expr *&Init, QualType &DeclType, ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(*this); + // FIXME: Poor location information + InitializationKind InitKind + = InitializationKind::CreateCopy(Init->getLocStart(), + SourceLocation()); + if (DirectInit) + InitKind = InitializationKind::CreateDirect(Init->getLocStart(), + SourceLocation(), + SourceLocation()); CXXConstructorDecl *Constructor = PerformInitializationByConstructor(DeclType, MultiExprArg(*this, (void **)&Init, 1), InitLoc, Init->getSourceRange(), - InitEntity, - DirectInit? IK_Direct : IK_Copy, + InitEntity, InitKind, ConstructorArgs); if (!Constructor) return true; @@ -1875,12 +1884,13 @@ bool Sema::CheckValueInitialization(QualType Type, SourceLocation Loc) { if (ClassDecl->hasUserDeclaredConstructor()) { ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(*this); + // FIXME: Poor location information CXXConstructorDecl *Constructor = PerformInitializationByConstructor(Type, MultiExprArg(*this, 0, 0), Loc, SourceRange(Loc), DeclarationName(), - IK_Direct, + InitializationKind::CreateValue(Loc, Loc, Loc), ConstructorArgs); if (!Constructor) return true; @@ -1908,3 +1918,955 @@ bool Sema::CheckValueInitialization(QualType Type, SourceLocation Loc) { return false; } + +//===----------------------------------------------------------------------===// +// Initialization entity +//===----------------------------------------------------------------------===// + +void InitializedEntity::InitDeclLoc() { + assert((Kind == EK_Variable || Kind == EK_Parameter || Kind == EK_Member) && + "InitDeclLoc cannot be used with non-declaration entities."); + + if (TypeSourceInfo *DI = VariableOrMember->getTypeSourceInfo()) { + TL = DI->getTypeLoc(); + return; + } + + // FIXME: Once we've gone through the effort to create the fake + // TypeSourceInfo, should we cache it in the declaration? + // (If not, we "leak" it). + TypeSourceInfo *DI = VariableOrMember->getASTContext() + .CreateTypeSourceInfo(VariableOrMember->getType()); + DI->getTypeLoc().initialize(VariableOrMember->getLocation()); + TL = DI->getTypeLoc(); +} + +InitializedEntity InitializedEntity::InitializeBase(ASTContext &Context, + CXXBaseSpecifier *Base) +{ + InitializedEntity Result; + Result.Kind = EK_Base; + Result.Base = Base; + // FIXME: CXXBaseSpecifier should store a TypeLoc. + TypeSourceInfo *DI = Context.CreateTypeSourceInfo(Base->getType()); + DI->getTypeLoc().initialize(Base->getSourceRange().getBegin()); + Result.TL = DI->getTypeLoc(); + return Result; +} + +//===----------------------------------------------------------------------===// +// Initialization sequence +//===----------------------------------------------------------------------===// + +void InitializationSequence::Step::Destroy() { + switch (Kind) { + case SK_ResolveAddressOfOverloadedFunction: + case SK_CastDerivedToBaseRValue: + case SK_CastDerivedToBaseLValue: + case SK_BindReference: + case SK_BindReferenceToTemporary: + case SK_UserConversion: + case SK_QualificationConversionRValue: + case SK_QualificationConversionLValue: + break; + + case SK_ConversionSequence: + delete ICS; + } +} + +void InitializationSequence::AddAddressOverloadResolutionStep( + FunctionDecl *Function) { + Step S; + S.Kind = SK_ResolveAddressOfOverloadedFunction; + S.Type = Function->getType(); + S.Function = Function; + Steps.push_back(S); +} + +void InitializationSequence::AddDerivedToBaseCastStep(QualType BaseType, + bool IsLValue) { + Step S; + S.Kind = IsLValue? SK_CastDerivedToBaseLValue : SK_CastDerivedToBaseRValue; + S.Type = BaseType; + Steps.push_back(S); +} + +void InitializationSequence::AddReferenceBindingStep(QualType T, + bool BindingTemporary) { + Step S; + S.Kind = BindingTemporary? SK_BindReferenceToTemporary : SK_BindReference; + S.Type = T; + Steps.push_back(S); +} + +void InitializationSequence::AddUserConversionStep(FunctionDecl *Function) { + Step S; + S.Kind = SK_UserConversion; + S.Type = Function->getResultType().getNonReferenceType(); + S.Function = Function; + Steps.push_back(S); +} + +void InitializationSequence::AddQualificationConversionStep(QualType Ty, + bool IsLValue) { + Step S; + S.Kind = IsLValue? SK_QualificationConversionLValue + : SK_QualificationConversionRValue; + S.Type = Ty; + Steps.push_back(S); +} + +void InitializationSequence::AddConversionSequenceStep( + const ImplicitConversionSequence &ICS, + QualType T) { + Step S; + S.Kind = SK_ConversionSequence; + S.Type = T; + S.ICS = new ImplicitConversionSequence(ICS); + Steps.push_back(S); +} + +void InitializationSequence::SetOverloadFailure(FailureKind Failure, + OverloadingResult Result) { + SequenceKind = FailedSequence; + this->Failure = Failure; + this->FailedOverloadResult = Result; +} + +//===----------------------------------------------------------------------===// +// Attempt initialization +//===----------------------------------------------------------------------===// + +/// \brief Attempt list initialization (C++0x [dcl.init.list]) +static bool 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; +} + +/// \brief Try a reference initialization that involves calling a conversion +/// function. +/// +/// FIXME: look intos DRs 656, 896 +static OverloadingResult TryRefInitWithConversionFunction(Sema &S, + const InitializedEntity &Entity, + const InitializationKind &Kind, + Expr *Initializer, + bool AllowRValues, + InitializationSequence &Sequence) { + QualType DestType = Entity.getType().getType(); + QualType cv1T1 = DestType->getAs<ReferenceType>()->getPointeeType(); + QualType T1 = cv1T1.getUnqualifiedType(); + QualType cv2T2 = Initializer->getType(); + QualType T2 = cv2T2.getUnqualifiedType(); + + bool DerivedToBase; + assert(!S.CompareReferenceRelationship(Initializer->getLocStart(), + T1, T2, DerivedToBase) && + "Must have incompatible references when binding via conversion"); + + // 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; + + const RecordType *T1RecordType = 0; + if (AllowRValues && (T1RecordType = T1->getAs<RecordType>())) { + // The type we're converting to is a class type. Enumerate its constructors + // to see if there is a suitable conversion. + CXXRecordDecl *T1RecordDecl = cast<CXXRecordDecl>(T1RecordType->getDecl()); + + DeclarationName ConstructorName + = S.Context.DeclarationNames.getCXXConstructorName( + S.Context.getCanonicalType(T1).getUnqualifiedType()); + DeclContext::lookup_iterator Con, ConEnd; + for (llvm::tie(Con, ConEnd) = T1RecordDecl->lookup(ConstructorName); + Con != ConEnd; ++Con) { + // Find the constructor (which may be a template). + CXXConstructorDecl *Constructor = 0; + FunctionTemplateDecl *ConstructorTmpl + = dyn_cast<FunctionTemplateDecl>(*Con); + if (ConstructorTmpl) + Constructor = cast<CXXConstructorDecl>( + ConstructorTmpl->getTemplatedDecl()); + else + Constructor = cast<CXXConstructorDecl>(*Con); + + if (!Constructor->isInvalidDecl() && + Constructor->isConvertingConstructor(AllowExplicit)) { + if (ConstructorTmpl) + S.AddTemplateOverloadCandidate(ConstructorTmpl, /*ExplicitArgs*/ 0, + &Initializer, 1, CandidateSet); + else + S.AddOverloadCandidate(Constructor, &Initializer, 1, CandidateSet); + } + } + } + + if (const RecordType *T2RecordType = T2->getAs<RecordType>()) { + // The type we're converting from is a class type, enumerate its conversion + // functions. + CXXRecordDecl *T2RecordDecl = cast<CXXRecordDecl>(T2RecordType->getDecl()); + + // Determine the type we are converting to. If we are allowed to + // convert to an rvalue, take the type that the destination type + // refers to. + QualType ToType = AllowRValues? cv1T1 : DestType; + + const UnresolvedSet *Conversions + = T2RecordDecl->getVisibleConversionFunctions(); + for (UnresolvedSet::iterator I = Conversions->begin(), + E = Conversions->end(); + I != E; ++I) { + NamedDecl *D = *I; + CXXRecordDecl *ActingDC = cast<CXXRecordDecl>(D->getDeclContext()); + if (isa<UsingShadowDecl>(D)) + D = cast<UsingShadowDecl>(D)->getTargetDecl(); + + FunctionTemplateDecl *ConvTemplate = dyn_cast<FunctionTemplateDecl>(D); + CXXConversionDecl *Conv; + if (ConvTemplate) + Conv = cast<CXXConversionDecl>(ConvTemplate->getTemplatedDecl()); + else + Conv = cast<CXXConversionDecl>(*I); + + // If the conversion function doesn't return a reference type, + // it can't be considered for this conversion unless we're allowed to + // consider rvalues. + // FIXME: Do we need to make sure that we only consider conversion + // candidates with reference-compatible results? That might be needed to + // break recursion. + if ((AllowExplicit || !Conv->isExplicit()) && + (AllowRValues || Conv->getConversionType()->isLValueReferenceType())){ + if (ConvTemplate) + S.AddTemplateConversionCandidate(ConvTemplate, ActingDC, Initializer, + ToType, CandidateSet); + else + S.AddConversionCandidate(Conv, ActingDC, Initializer, cv1T1, + CandidateSet); + } + } + } + + SourceLocation DeclLoc = Initializer->getLocStart(); + + // Perform overload resolution. If it fails, return the failed result. + OverloadCandidateSet::iterator Best; + if (OverloadingResult Result + = S.BestViableFunction(CandidateSet, DeclLoc, Best)) + return Result; + + // Add the user-defined conversion step. + FunctionDecl *Function = Best->Function; + Sequence.AddUserConversionStep(Function); + + // Determine whether we need to perform derived-to-base or + // cv-qualification adjustments. + if (isa<CXXConversionDecl>(Function)) + T2 = Function->getResultType(); + else + T2 = cv1T1; + + bool NewDerivedToBase = false; + Sema::ReferenceCompareResult NewRefRelationship + = S.CompareReferenceRelationship(DeclLoc, T1, T2.getNonReferenceType(), + NewDerivedToBase); + assert(NewRefRelationship != Sema::Ref_Incompatible && + "Overload resolution picked a bad conversion function"); + (void)NewRefRelationship; + if (NewDerivedToBase) + Sequence.AddDerivedToBaseCastStep( + S.Context.getQualifiedType(T1, + T2.getNonReferenceType().getQualifiers()), + /*isLValue=*/true); + + if (cv1T1.getQualifiers() != T2.getNonReferenceType().getQualifiers()) + Sequence.AddQualificationConversionStep(cv1T1, T2->isReferenceType()); + + Sequence.AddReferenceBindingStep(cv1T1, !T2->isReferenceType()); + return OR_Success; +} + +/// \brief Attempt reference initialization (C++0x [dcl.init.list]) +static void TryReferenceInitialization(Sema &S, + const InitializedEntity &Entity, + const InitializationKind &Kind, + Expr *Initializer, + InitializationSequence &Sequence) { + Sequence.setSequenceKind(InitializationSequence::ReferenceBinding); + + QualType DestType = Entity.getType().getType(); + QualType cv1T1 = DestType->getAs<ReferenceType>()->getPointeeType(); + QualType T1 = cv1T1.getUnqualifiedType(); + QualType cv2T2 = Initializer->getType(); + QualType T2 = cv2T2.getUnqualifiedType(); + SourceLocation DeclLoc = Initializer->getLocStart(); + + // If the initializer is the address of an overloaded function, try + // to resolve the overloaded function. If all goes well, T2 is the + // type of the resulting function. + if (S.Context.getCanonicalType(T2) == S.Context.OverloadTy) { + FunctionDecl *Fn = S.ResolveAddressOfOverloadedFunction(Initializer, + T1, + false); + if (!Fn) { + Sequence.SetFailed(InitializationSequence::FK_AddressOfOverloadFailed); + return; + } + + Sequence.AddAddressOverloadResolutionStep(Fn); + cv2T2 = Fn->getType(); + T2 = cv2T2.getUnqualifiedType(); + } + + // FIXME: Rvalue references + bool ForceRValue = false; + + // Compute some basic properties of the types and the initializer. + bool isLValueRef = DestType->isLValueReferenceType(); + bool isRValueRef = !isLValueRef; + bool DerivedToBase = false; + Expr::isLvalueResult InitLvalue = ForceRValue ? Expr::LV_InvalidExpression : + Initializer->isLvalue(S.Context); + Sema::ReferenceCompareResult RefRelationship + = S.CompareReferenceRelationship(DeclLoc, cv1T1, cv2T2, DerivedToBase); + + // C++0x [dcl.init.ref]p5: + // A reference to type "cv1 T1" is initialized by an expression of type + // "cv2 T2" as follows: + // + // - If the reference is an lvalue reference and the initializer + // expression + OverloadingResult ConvOvlResult = OR_Success; + if (isLValueRef) { + if (InitLvalue == Expr::LV_Valid && + RefRelationship >= Sema::Ref_Compatible_With_Added_Qualification) { + // - is an lvalue (but is not a bit-field), and "cv1 T1" is + // reference-compatible with "cv2 T2," or + // + // Per C++ [over.best.ics]p2, we ignore whether the lvalue is a + // bit-field when we're determining whether the reference initialization + // can occur. This property will be checked by PerformInitialization. + if (DerivedToBase) + Sequence.AddDerivedToBaseCastStep( + S.Context.getQualifiedType(T1, cv2T2.getQualifiers()), + /*isLValue=*/true); + if (cv1T1.getQualifiers() != cv2T2.getQualifiers()) + Sequence.AddQualificationConversionStep(cv1T1, /*IsLValue=*/true); + Sequence.AddReferenceBindingStep(cv1T1, /*bindingTemporary=*/false); + return; + } + + // - has a class type (i.e., T2 is a class type), where T1 is not + // reference-related to T2, and can be implicitly converted to an + // lvalue of type "cv3 T3," where "cv1 T1" is reference-compatible + // with "cv3 T3" (this conversion is selected by enumerating the + // applicable conversion functions (13.3.1.6) and choosing the best + // one through overload resolution (13.3)), + if (RefRelationship == Sema::Ref_Incompatible && T2->isRecordType()) { + ConvOvlResult = TryRefInitWithConversionFunction(S, Entity, Kind, + Initializer, + /*AllowRValues=*/false, + Sequence); + if (ConvOvlResult == OR_Success) + return; + } + } + + // - Otherwise, the reference shall be an lvalue reference to a + // non-volatile const type (i.e., cv1 shall be const), or the reference + // shall be an rvalue reference and the initializer expression shall + // be an rvalue. + if (!((isLValueRef && cv1T1.getCVRQualifiers() == Qualifiers::Const) || + (isRValueRef && InitLvalue != Expr::LV_Valid))) { + if (ConvOvlResult && !Sequence.getFailedCandidateSet().empty()) + Sequence.SetOverloadFailure( + InitializationSequence::FK_ReferenceInitOverloadFailed, + ConvOvlResult); + else if (isLValueRef) + Sequence.SetFailed(InitLvalue == Expr::LV_Valid + ? (RefRelationship == Sema::Ref_Related + ? InitializationSequence::FK_ReferenceInitDropsQualifiers + : InitializationSequence::FK_NonConstLValueReferenceBindingToUnrelated) + : InitializationSequence::FK_NonConstLValueReferenceBindingToTemporary); + else + Sequence.SetFailed( + InitializationSequence::FK_RValueReferenceBindingToLValue); + + return; + } + + // - If T1 and T2 are class types and + if (T1->isRecordType() && T2->isRecordType()) { + // - the initializer expression is an rvalue and "cv1 T1" is + // reference-compatible with "cv2 T2", or + if (InitLvalue != Expr::LV_Valid && + RefRelationship >= Sema::Ref_Compatible_With_Added_Qualification) { + if (DerivedToBase) + Sequence.AddDerivedToBaseCastStep( + S.Context.getQualifiedType(T1, cv2T2.getQualifiers()), + /*isLValue=*/false); + if (cv1T1.getQualifiers() != cv2T2.getQualifiers()) + Sequence.AddQualificationConversionStep(cv1T1, /*IsLValue=*/false); + Sequence.AddReferenceBindingStep(cv1T1, /*bindingTemporary=*/true); + return; + } + + // - T1 is not reference-related to T2 and the initializer expression + // can be implicitly converted to an rvalue of type "cv3 T3" (this + // conversion is selected by enumerating the applicable conversion + // functions (13.3.1.6) and choosing the best one through overload + // resolution (13.3)), + if (RefRelationship == Sema::Ref_Incompatible) { + ConvOvlResult = TryRefInitWithConversionFunction(S, Entity, + Kind, Initializer, + /*AllowRValues=*/true, + Sequence); + if (ConvOvlResult) + Sequence.SetOverloadFailure( + InitializationSequence::FK_ReferenceInitOverloadFailed, + ConvOvlResult); + + return; + } + + Sequence.SetFailed(InitializationSequence::FK_ReferenceInitDropsQualifiers); + return; + } + + // - If the initializer expression is an rvalue, with T2 an array type, + // and "cv1 T1" is reference-compatible with "cv2 T2," the reference + // is bound to the object represented by the rvalue (see 3.10). + // FIXME: How can an array type be reference-compatible with anything? + // Don't we mean the element types of T1 and T2? + + // - Otherwise, a temporary of type “cv1 T1” is created and initialized + // from the initializer expression using the rules for a non-reference + // copy initialization (8.5). The reference is then bound to the + // temporary. [...] + // Determine whether we are allowed to call explicit constructors or + // explicit conversion operators. + bool AllowExplicit = (Kind.getKind() == InitializationKind::IK_Direct); + ImplicitConversionSequence ICS + = S.TryImplicitConversion(Initializer, cv1T1, + /*SuppressUserConversions=*/false, AllowExplicit, + /*ForceRValue=*/false, + /*FIXME:InOverloadResolution=*/false, + /*UserCast=*/Kind.isExplicitCast()); + + if (ICS.ConversionKind == ImplicitConversionSequence::BadConversion) { + // FIXME: Use the conversion function set stored in ICS to turn + // 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); + return; + } + + // [...] If T1 is reference-related to T2, cv1 must be the + // same cv-qualification as, or greater cv-qualification + // than, cv2; otherwise, the program is ill-fo |