diff options
author | Douglas Gregor <dgregor@apple.com> | 2011-01-26 19:30:28 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2011-01-26 19:30:28 +0000 |
commit | 2c9a03f3b249e4d9d76eadf758a33142adc4d0a4 (patch) | |
tree | 6ea67fdb6631ab511ed8dcbc2512f73f775e0e42 /lib/Sema/SemaOverload.cpp | |
parent | f99a3915389109a716caafacb41fd9c4a3b8f432 (diff) |
Rvalue references for *this: implement the implicit conversion rules
for the implicit object argument to a non-static member function with
a ref-qualifier (C++0x [over.match.funcs]p4).
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@124311 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema/SemaOverload.cpp')
-rw-r--r-- | lib/Sema/SemaOverload.cpp | 147 |
1 files changed, 104 insertions, 43 deletions
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index 6c25893758..62af5bb8ff 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -2345,9 +2345,10 @@ static bool isBetterReferenceBindingKind(const StandardConversionSequence &SCS1, // and std::reference_wrapper when dealing with references to functions. // Proposed wording changes submitted to CWG for consideration. // - // FIXME: Rvalue references. We don't know if we're dealing with the - // implicit object parameter, or if the member function in this case has a - // ref qualifier. (Of course, we don't have ref qualifiers yet.) + // Note: neither of these conditions will evalute true for the implicit + // object parameter, because we don't set either BindsToRvalue or + // BindsToFunctionLvalue when computing the conversion sequence for the + // implicit object parameter. return (!SCS1.IsLvalueReference && SCS1.BindsToRvalue && SCS2.IsLvalueReference) || (SCS1.IsLvalueReference && SCS1.BindsToFunctionLvalue && @@ -3182,6 +3183,7 @@ TryCopyInitialization(Sema &S, Expr *From, QualType ToType, /// expression @p From. static ImplicitConversionSequence TryObjectArgumentInitialization(Sema &S, QualType OrigFromType, + Expr::Classification FromClassification, CXXMethodDecl *Method, CXXRecordDecl *ActingContext) { QualType ClassType = S.Context.getTypeDeclType(ActingContext); @@ -3197,22 +3199,35 @@ TryObjectArgumentInitialization(Sema &S, QualType OrigFromType, // We need to have an object of class type. QualType FromType = OrigFromType; - if (const PointerType *PT = FromType->getAs<PointerType>()) + if (const PointerType *PT = FromType->getAs<PointerType>()) { FromType = PT->getPointeeType(); + // When we had a pointer, it's implicitly dereferenced, so we + // better have an lvalue. + assert(FromClassification.isLValue()); + } + assert(FromType->isRecordType()); - // The implicit object parameter is has the type "reference to cv X", - // where X is the class of which the function is a member - // (C++ [over.match.funcs]p4). However, when finding an implicit - // conversion sequence for the argument, we are not allowed to - // create temporaries or perform user-defined conversions + // C++0x [over.match.funcs]p4: + // For non-static member functions, the type of the implicit object + // parameter is + // + // — "lvalue reference to cv X" for functions declared without a + // ref-qualifier or with the & ref-qualifier + // — "rvalue reference to cv X" for functions declared with the && + // ref-qualifier + // + // where X is the class of which the function is a member and cv is the + // cv-qualification on the member function declaration. + // + // However, when finding an implicit conversion sequence for the argument, we + // are not allowed to create temporaries or perform user-defined conversions // (C++ [over.match.funcs]p5). We perform a simplified version of // reference binding here, that allows class rvalues to bind to // non-constant references. - // First check the qualifiers. We don't care about lvalue-vs-rvalue - // with the implicit object parameter (C++ [over.match.funcs]p5). + // First check the qualifiers. QualType FromTypeCanon = S.Context.getCanonicalType(FromType); if (ImplicitParamType.getCVRQualifiers() != FromTypeCanon.getLocalCVRQualifiers() && @@ -3236,6 +3251,31 @@ TryObjectArgumentInitialization(Sema &S, QualType OrigFromType, return ICS; } + // Check the ref-qualifier. + switch (Method->getRefQualifier()) { + case RQ_None: + // Do nothing; we don't care about lvalueness or rvalueness. + break; + + case RQ_LValue: + if (!FromClassification.isLValue() && Quals != Qualifiers::Const) { + // non-const lvalue reference cannot bind to an rvalue + ICS.setBad(BadConversionSequence::lvalue_ref_to_rvalue, FromType, + ImplicitParamType); + return ICS; + } + break; + + case RQ_RValue: + if (!FromClassification.isRValue()) { + // rvalue reference cannot bind to an lvalue + ICS.setBad(BadConversionSequence::rvalue_ref_to_lvalue, FromType, + ImplicitParamType); + return ICS; + } + break; + } + // Success. Mark this as a reference binding. ICS.setStandard(); ICS.Standard.setAsIdentityConversion(); @@ -3244,10 +3284,10 @@ TryObjectArgumentInitialization(Sema &S, QualType OrigFromType, ICS.Standard.setAllToTypes(ImplicitParamType); ICS.Standard.ReferenceBinding = true; ICS.Standard.DirectBinding = true; - - // FIXME: Rvalue references. - ICS.Standard.IsLvalueReference = true; + ICS.Standard.IsLvalueReference = Method->getRefQualifier() != RQ_RValue; ICS.Standard.BindsToFunctionLvalue = false; + + // Note: we intentionally don't set this; see isBetterReferenceBindingKind(). ICS.Standard.BindsToRvalue = false; return ICS; } @@ -3264,19 +3304,22 @@ Sema::PerformObjectArgumentInitialization(Expr *&From, QualType ImplicitParamRecordType = Method->getThisType(Context)->getAs<PointerType>()->getPointeeType(); + Expr::Classification FromClassification; if (const PointerType *PT = From->getType()->getAs<PointerType>()) { FromRecordType = PT->getPointeeType(); DestType = Method->getThisType(Context); + FromClassification = Expr::Classification::makeSimpleLValue(); } else { FromRecordType = From->getType(); DestType = ImplicitParamRecordType; + FromClassification = From->Classify(Context); } // Note that we always use the true parent context when performing // the actual argument initialization. ImplicitConversionSequence ICS - = TryObjectArgumentInitialization(*this, From->getType(), Method, - Method->getParent()); + = TryObjectArgumentInitialization(*this, From->getType(), FromClassification, + Method, Method->getParent()); if (ICS.isBad()) { if (ICS.Bad.Kind == BadConversionSequence::bad_qualifiers) { Qualifiers FromQs = FromRecordType.getQualifiers(); @@ -3549,7 +3592,7 @@ Sema::AddOverloadCandidate(FunctionDecl *Function, = dyn_cast<FunctionProtoType>(Function->getType()->getAs<FunctionType>()); assert(Proto && "Functions without a prototype cannot be overloaded"); assert(!Function->getDescribedFunctionTemplate() && - "Use AddTemplateOverloadCandidate for function templates"); + "Use AddTemp∫lateOverloadCandidate for function templates"); if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Function)) { if (!isa<CXXConstructorDecl>(Method)) { @@ -3561,7 +3604,8 @@ Sema::AddOverloadCandidate(FunctionDecl *Function, // object argument (C++ [over.call.func]p3), and the acting context // is irrelevant. AddMethodCandidate(Method, FoundDecl, Method->getParent(), - QualType(), Args, NumArgs, CandidateSet, + QualType(), Expr::Classification::makeSimpleLValue(), + Args, NumArgs, CandidateSet, SuppressUserConversions); return; } @@ -3662,7 +3706,8 @@ void Sema::AddFunctionCandidates(const UnresolvedSetImpl &Fns, if (isa<CXXMethodDecl>(FD) && !cast<CXXMethodDecl>(FD)->isStatic()) AddMethodCandidate(cast<CXXMethodDecl>(FD), F.getPair(), cast<CXXMethodDecl>(FD)->getParent(), - Args[0]->getType(), Args + 1, NumArgs - 1, + Args[0]->getType(), Args[0]->Classify(Context), + Args + 1, NumArgs - 1, CandidateSet, SuppressUserConversions); else AddOverloadCandidate(FD, F.getPair(), Args, NumArgs, CandidateSet, @@ -3674,7 +3719,9 @@ void Sema::AddFunctionCandidates(const UnresolvedSetImpl &Fns, AddMethodTemplateCandidate(FunTmpl, F.getPair(), cast<CXXRecordDecl>(FunTmpl->getDeclContext()), /*FIXME: explicit args */ 0, - Args[0]->getType(), Args + 1, NumArgs - 1, + Args[0]->getType(), + Args[0]->Classify(Context), + Args + 1, NumArgs - 1, CandidateSet, SuppressUserConversions); else @@ -3690,6 +3737,7 @@ void Sema::AddFunctionCandidates(const UnresolvedSetImpl &Fns, /// method) as a method candidate to the given overload set. void Sema::AddMethodCandidate(DeclAccessPair FoundDecl, QualType ObjectType, + Expr::Classification ObjectClassification, Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet, bool SuppressUserConversions) { @@ -3704,12 +3752,12 @@ void Sema::AddMethodCandidate(DeclAccessPair FoundDecl, "Expected a member function template"); AddMethodTemplateCandidate(TD, FoundDecl, ActingContext, /*ExplicitArgs*/ 0, - ObjectType, Args, NumArgs, + ObjectType, ObjectClassification, Args, NumArgs, CandidateSet, SuppressUserConversions); } else { AddMethodCandidate(cast<CXXMethodDecl>(Decl), FoundDecl, ActingContext, - ObjectType, Args, NumArgs, + ObjectType, ObjectClassification, Args, NumArgs, CandidateSet, SuppressUserConversions); } } @@ -3724,6 +3772,7 @@ void Sema::AddMethodCandidate(DeclAccessPair FoundDecl, void Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl, CXXRecordDecl *ActingContext, QualType ObjectType, + Expr::Classification ObjectClassification, Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet, bool SuppressUserConversions) { @@ -3782,8 +3831,8 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl, // Determine the implicit conversion sequence for the object // parameter. Candidate.Conversions[0] - = TryObjectArgumentInitialization(*this, ObjectType, Method, - ActingContext); + = TryObjectArgumentInitialization(*this, ObjectType, ObjectClassification, + Method, ActingContext); if (Candidate.Conversions[0].isBad()) { Candidate.Viable = false; Candidate.FailureKind = ovl_fail_bad_conversion; @@ -3827,6 +3876,7 @@ Sema::AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl, CXXRecordDecl *ActingContext, const TemplateArgumentListInfo *ExplicitTemplateArgs, QualType ObjectType, + Expr::Classification ObjectClassification, Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet, bool SuppressUserConversions) { @@ -3867,8 +3917,8 @@ Sema::AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl, assert(isa<CXXMethodDecl>(Specialization) && "Specialization is not a member function?"); AddMethodCandidate(cast<CXXMethodDecl>(Specialization), FoundDecl, - ActingContext, ObjectType, Args, NumArgs, - CandidateSet, SuppressUserConversions); + ActingContext, ObjectType, ObjectClassification, + Args, NumArgs, CandidateSet, SuppressUserConversions); } /// \brief Add a C++ function template specialization as a candidate @@ -3968,8 +4018,9 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion, = cast<CXXRecordDecl>(ImplicitParamType->getAs<RecordType>()->getDecl()); Candidate.Conversions[0] - = TryObjectArgumentInitialization(*this, From->getType(), Conversion, - ConversionContext); + = TryObjectArgumentInitialization(*this, From->getType(), + From->Classify(Context), + Conversion, ConversionContext); if (Candidate.Conversions[0].isBad()) { Candidate.Viable = false; @@ -4113,7 +4164,7 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion, DeclAccessPair FoundDecl, CXXRecordDecl *ActingContext, const FunctionProtoType *Proto, - QualType ObjectType, + Expr *Object, Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet) { if (!CandidateSet.isNewCandidate(Conversion)) @@ -4136,8 +4187,9 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion, // Determine the implicit conversion sequence for the implicit // object parameter. ImplicitConversionSequence ObjectInit - = TryObjectArgumentInitialization(*this, ObjectType, Conversion, - ActingContext); + = TryObjectArgumentInitialization(*this, Object->getType(), + Object->Classify(Context), + Conversion, ActingContext); if (ObjectInit.isBad()) { Candidate.Viable = false; Candidate.FailureKind = ovl_fail_bad_conversion; @@ -4249,7 +4301,8 @@ void Sema::AddMemberOperatorCandidates(OverloadedOperatorKind Op, Oper != OperEnd; ++Oper) AddMethodCandidate(Oper.getPair(), Args[0]->getType(), - Args + 1, NumArgs - 1, CandidateSet, + Args[0]->Classify(Context), Args + 1, NumArgs - 1, + CandidateSet, /* SuppressUserConversions = */ false); } } @@ -4901,8 +4954,8 @@ public: // T& operator*(T*); // // C++ [over.built]p7: - // For every function type T, there exist candidate operator - // functions of the form + // For every function type T that does not have cv-qualifiers or a + // ref-qualifier, there exist candidate operator functions of the form // T& operator*(T*); void addUnaryStarPointerOverloads() { for (BuiltinCandidateTypeSet::iterator @@ -4914,6 +4967,10 @@ public: if (!PointeeTy->isObjectType() && !PointeeTy->isFunctionType()) continue; + if (const FunctionProtoType *Proto =PointeeTy->getAs<FunctionProtoType>()) + if (Proto->getTypeQuals() || Proto->getRefQualifier()) + continue; + S.AddBuiltinCandidate(S.Context.getLValueReferenceType(PointeeTy), &ParamTy, Args, 1, CandidateSet); } @@ -7950,6 +8007,9 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, Qualifier = UnresExpr->getQualifier(); QualType ObjectType = UnresExpr->getBaseType(); + Expr::Classification ObjectClassification + = UnresExpr->isArrow()? Expr::Classification::makeSimpleLValue() + : UnresExpr->getBase()->Classify(Context); // Add overload candidates OverloadCandidateSet CandidateSet(UnresExpr->getMemberLoc()); @@ -7969,6 +8029,7 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, if (isa<UsingShadowDecl>(Func)) Func = cast<UsingShadowDecl>(Func)->getTargetDecl(); + // Microsoft supports direct constructor calls. if (getLangOptions().Microsoft && isa<CXXConstructorDecl>(Func)) { AddOverloadCandidate(cast<CXXConstructorDecl>(Func), I.getPair(), Args, NumArgs, @@ -7980,13 +8041,14 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, continue; AddMethodCandidate(Method, I.getPair(), ActingDC, ObjectType, - Args, NumArgs, - CandidateSet, /*SuppressUserConversions=*/false); + ObjectClassification, + Args, NumArgs, CandidateSet, + /*SuppressUserConversions=*/false); } else { AddMethodTemplateCandidate(cast<FunctionTemplateDecl>(Func), I.getPair(), ActingDC, TemplateArgs, - ObjectType, Args, NumArgs, - CandidateSet, + ObjectType, ObjectClassification, + Args, NumArgs, CandidateSet, /*SuppressUsedConversions=*/false); } } @@ -8113,7 +8175,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object, for (LookupResult::iterator Oper = R.begin(), OperEnd = R.end(); Oper != OperEnd; ++Oper) { AddMethodCandidate(Oper.getPair(), Object->getType(), - Args, NumArgs, CandidateSet, + Object->Classify(Context), Args, NumArgs, CandidateSet, /*SuppressUserConversions=*/ false); } @@ -8158,8 +8220,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object, if (const FunctionProtoType *Proto = ConvType->getAs<FunctionProtoType>()) AddSurrogateCandidate(Conv, I.getPair(), ActingContext, Proto, - Object->getType(), Args, NumArgs, - CandidateSet); + Object, Args, NumArgs, CandidateSet); } // Perform overload resolution. @@ -8369,8 +8430,8 @@ Sema::BuildOverloadedArrowExpr(Scope *S, Expr *Base, SourceLocation OpLoc) { for (LookupResult::iterator Oper = R.begin(), OperEnd = R.end(); Oper != OperEnd; ++Oper) { - AddMethodCandidate(Oper.getPair(), Base->getType(), 0, 0, CandidateSet, - /*SuppressUserConversions=*/false); + AddMethodCandidate(Oper.getPair(), Base->getType(), Base->Classify(Context), + 0, 0, CandidateSet, /*SuppressUserConversions=*/false); } // Perform overload resolution. |