[cfe-commits] r124311 - in /cfe/trunk: include/clang/AST/Expr.h include/clang/Sema/Overload.h include/clang/Sema/Sema.h lib/Sema/SemaOverload.cpp test/CXX/over/over.match/over.match.funcs/p4-0x.cpp
Douglas Gregor
dgregor at apple.com
Wed Jan 26 11:30:29 PST 2011
Author: dgregor
Date: Wed Jan 26 13:30:28 2011
New Revision: 124311
URL: http://llvm.org/viewvc/llvm-project?rev=124311&view=rev
Log:
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).
Added:
cfe/trunk/test/CXX/over/over.match/over.match.funcs/p4-0x.cpp (with props)
Modified:
cfe/trunk/include/clang/AST/Expr.h
cfe/trunk/include/clang/Sema/Overload.h
cfe/trunk/include/clang/Sema/Sema.h
cfe/trunk/lib/Sema/SemaOverload.cpp
Modified: cfe/trunk/include/clang/AST/Expr.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Expr.h?rev=124311&r1=124310&r2=124311&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Expr.h (original)
+++ cfe/trunk/include/clang/AST/Expr.h Wed Jan 26 13:30:28 2011
@@ -268,6 +268,12 @@
bool isPRValue() const { return Kind >= CL_Function; }
bool isRValue() const { return Kind >= CL_XValue; }
bool isModifiable() const { return getModifiable() == CM_Modifiable; }
+
+ /// \brief Create a simple, modifiably lvalue
+ static Classification makeSimpleLValue() {
+ return Classification(CL_LValue, CM_Modifiable);
+ }
+
};
/// \brief Classify - Classify this expression according to the C++0x
/// expression taxonomy.
Modified: cfe/trunk/include/clang/Sema/Overload.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Overload.h?rev=124311&r1=124310&r2=124311&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Overload.h (original)
+++ cfe/trunk/include/clang/Sema/Overload.h Wed Jan 26 13:30:28 2011
@@ -294,7 +294,9 @@
no_conversion,
unrelated_class,
suppressed_user,
- bad_qualifiers
+ bad_qualifiers,
+ lvalue_ref_to_rvalue,
+ rvalue_ref_to_lvalue
};
// This can be null, e.g. for implicit object arguments.
Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=124311&r1=124310&r2=124311&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Wed Jan 26 13:30:28 2011
@@ -20,7 +20,7 @@
#include "clang/Sema/IdentifierResolver.h"
#include "clang/Sema/ObjCMethodList.h"
#include "clang/Sema/DeclSpec.h"
-#include "clang/AST/OperationKinds.h"
+#include "clang/AST/Expr.h"
#include "clang/AST/DeclarationName.h"
#include "clang/AST/ExternalASTSource.h"
#include "clang/AST/TypeLoc.h"
@@ -1080,12 +1080,14 @@
bool SuppressUserConversions = false);
void AddMethodCandidate(DeclAccessPair FoundDecl,
QualType ObjectType,
+ Expr::Classification ObjectClassification,
Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet,
bool SuppressUserConversion = false);
void AddMethodCandidate(CXXMethodDecl *Method,
DeclAccessPair FoundDecl,
CXXRecordDecl *ActingContext, QualType ObjectType,
+ Expr::Classification ObjectClassification,
Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet,
bool SuppressUserConversions = false);
@@ -1094,6 +1096,7 @@
CXXRecordDecl *ActingContext,
const TemplateArgumentListInfo *ExplicitTemplateArgs,
QualType ObjectType,
+ Expr::Classification ObjectClassification,
Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet,
bool SuppressUserConversions = false);
@@ -1117,7 +1120,7 @@
DeclAccessPair FoundDecl,
CXXRecordDecl *ActingContext,
const FunctionProtoType *Proto,
- QualType ObjectTy, Expr **Args, unsigned NumArgs,
+ Expr *Object, Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet);
void AddMemberOperatorCandidates(OverloadedOperatorKind Op,
SourceLocation OpLoc,
Modified: cfe/trunk/lib/Sema/SemaOverload.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=124311&r1=124310&r2=124311&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOverload.cpp Wed Jan 26 13:30:28 2011
@@ -2345,9 +2345,10 @@
// 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 @@
/// 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 @@
// 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 @@
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 @@
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 @@
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 @@
= 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 @@
// 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 @@
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 @@
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 @@
/// 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 @@
"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(CXXMethodDecl *Method, DeclAccessPair FoundDecl,
CXXRecordDecl *ActingContext, QualType ObjectType,
+ Expr::Classification ObjectClassification,
Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet,
bool SuppressUserConversions) {
@@ -3782,8 +3831,8 @@
// 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 @@
CXXRecordDecl *ActingContext,
const TemplateArgumentListInfo *ExplicitTemplateArgs,
QualType ObjectType,
+ Expr::Classification ObjectClassification,
Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet,
bool SuppressUserConversions) {
@@ -3867,8 +3917,8 @@
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 @@
= 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 @@
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 @@
// 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 @@
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 @@
// 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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.
Added: cfe/trunk/test/CXX/over/over.match/over.match.funcs/p4-0x.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/over/over.match/over.match.funcs/p4-0x.cpp?rev=124311&view=auto
==============================================================================
--- cfe/trunk/test/CXX/over/over.match/over.match.funcs/p4-0x.cpp (added)
+++ cfe/trunk/test/CXX/over/over.match/over.match.funcs/p4-0x.cpp Wed Jan 26 13:30:28 2011
@@ -0,0 +1,65 @@
+// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+
+template<typename T> T &lvalue();
+template<typename T> T &&xvalue();
+template<typename T> T prvalue();
+
+struct X0 {
+ int &f() &;
+ float &f() &&;
+
+ template<typename T> int &ft(T) &;
+ template<typename T> float &ft(T) &&;
+
+ typedef int &(*func_int_ref)();
+ typedef float &(*func_float_ref)();
+
+ operator func_int_ref() &;
+ operator func_float_ref() &&;
+
+ void g();
+
+ int &operator+(const X0&) &;
+ float &operator+(const X0&) &&;
+
+ template<typename T> int &operator+(const T&) &;
+ template<typename T> float &operator+(const T&) &&;
+
+ int &h() const&;
+ float &h() &&;
+};
+
+void X0::g() {
+ int &ir1 = f();
+ int &ir2 = X0::f();
+}
+
+void test_ref_qualifier_binding() {
+ int &ir1 = lvalue<X0>().f();
+ float &fr1 = xvalue<X0>().f();
+ float &fr2 = prvalue<X0>().f();
+ int &ir2 = lvalue<X0>().ft(1);
+ float &fr3 = xvalue<X0>().ft(2);
+ float &fr4 = prvalue<X0>().ft(3);
+}
+
+void test_ref_qualifier_binding_with_surrogates() {
+ int &ir1 = lvalue<X0>()();
+ float &fr1 = xvalue<X0>()();
+ float &fr2 = prvalue<X0>()();
+}
+
+void test_ref_qualifier_binding_operators() {
+ int &ir1 = lvalue<X0>() + prvalue<X0>();
+ float &fr1 = xvalue<X0>() + prvalue<X0>();
+ float &fr2 = prvalue<X0>() + prvalue<X0>();
+ int &ir2 = lvalue<X0>() + 1;
+ float &fr3 = xvalue<X0>() + 2;
+ float &fr4 = prvalue<X0>() + 3;
+}
+
+void test_ref_qualifier_overloading() {
+ int &ir1 = lvalue<X0>().h();
+ float &fr1 = xvalue<X0>().h();
+ float &fr2 = prvalue<X0>().h();
+}
Propchange: cfe/trunk/test/CXX/over/over.match/over.match.funcs/p4-0x.cpp
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: cfe/trunk/test/CXX/over/over.match/over.match.funcs/p4-0x.cpp
------------------------------------------------------------------------------
svn:keywords = Id
Propchange: cfe/trunk/test/CXX/over/over.match/over.match.funcs/p4-0x.cpp
------------------------------------------------------------------------------
svn:mime-type = text/plain
More information about the cfe-commits
mailing list