// 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 &&
/// expression @p From.
static ImplicitConversionSequence
TryObjectArgumentInitialization(Sema &S, QualType OrigFromType,
+ Expr::Classification FromClassification,
CXXMethodDecl *Method,
CXXRecordDecl *ActingContext) {
QualType ClassType = S.Context.getTypeDeclType(ActingContext);
// 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() &&
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();
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;
}
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();
= 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)) {
// 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;
}
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,
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
/// 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) {
"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);
}
}
void
Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl,
CXXRecordDecl *ActingContext, QualType ObjectType,
+ Expr::Classification ObjectClassification,
Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet,
bool SuppressUserConversions) {
// 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;
CXXRecordDecl *ActingContext,
const TemplateArgumentListInfo *ExplicitTemplateArgs,
QualType ObjectType,
+ Expr::Classification ObjectClassification,
Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet,
bool SuppressUserConversions) {
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
= 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;
DeclAccessPair FoundDecl,
CXXRecordDecl *ActingContext,
const FunctionProtoType *Proto,
- QualType ObjectType,
+ Expr *Object,
Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet) {
if (!CandidateSet.isNewCandidate(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;
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);
}
}
// 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
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);
}
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());
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,
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);
}
}
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);
}
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.
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.