From 440a48318c53647d6416bcb1ff1af1452aa5d453 Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Wed, 26 Jan 2011 14:52:12 +0000 Subject: [PATCH] Reinstate r124236 (tweaking the rvalue-reference overload resolution rules), now that we've actually have a clean build for me to sully. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@124290 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Sema/Overload.h | 22 +++--- lib/Sema/SemaOverload.cpp | 71 ++++++++++++++----- .../over.match.best/over.ics.rank/p3-0x.cpp | 6 +- 3 files changed, 70 insertions(+), 29 deletions(-) diff --git a/include/clang/Sema/Overload.h b/include/clang/Sema/Overload.h index fa3c94b0ac..4a7cb20e61 100644 --- a/include/clang/Sema/Overload.h +++ b/include/clang/Sema/Overload.h @@ -133,24 +133,30 @@ namespace clang { /// Deprecated - Whether this the deprecated conversion of a /// string literal to a pointer to non-const character data /// (C++ 4.2p2). - bool DeprecatedStringLiteralToCharPtr : 1; + unsigned DeprecatedStringLiteralToCharPtr : 1; /// IncompatibleObjC - Whether this is an Objective-C conversion /// that we should warn about (if we actually use it). - bool IncompatibleObjC : 1; + unsigned IncompatibleObjC : 1; /// ReferenceBinding - True when this is a reference binding /// (C++ [over.ics.ref]). - bool ReferenceBinding : 1; + unsigned ReferenceBinding : 1; /// DirectBinding - True when this is a reference binding that is a /// direct binding (C++ [dcl.init.ref]). - bool DirectBinding : 1; - - /// RRefBinding - True when this is a reference binding of an rvalue - /// reference to an rvalue (C++0x [over.ics.rank]p3b4). - bool RRefBinding : 1; + unsigned DirectBinding : 1; + /// \brief Whether this is an lvalue reference binding (otherwise, it's + /// an rvalue reference binding). + unsigned IsLvalueReference : 1; + + /// \brief Whether we're binding to a function lvalue. + unsigned BindsToFunctionLvalue : 1; + + /// \brief Whether we're binding to an rvalue. + unsigned BindsToRvalue : 1; + /// FromType - The type that this conversion is converting /// from. This is an opaque pointer that can be translated into a /// QualType. diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index 85ae6f7326..602a118c3b 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -170,7 +170,9 @@ void StandardConversionSequence::setAsIdentityConversion() { DeprecatedStringLiteralToCharPtr = false; ReferenceBinding = false; DirectBinding = false; - RRefBinding = false; + IsLvalueReference = true; + BindsToFunctionLvalue = false; + BindsToRvalue = false; CopyConstructor = 0; } @@ -2324,6 +2326,33 @@ compareStandardConversionSubsets(ASTContext &Context, return ImplicitConversionSequence::Indistinguishable; } +/// \brief Determine whether one of the given reference bindings is better +/// than the other based on what kind of bindings they are. +static bool isBetterReferenceBindingKind(const StandardConversionSequence &SCS1, + const StandardConversionSequence &SCS2) { + // C++0x [over.ics.rank]p3b4: + // -- S1 and S2 are reference bindings (8.5.3) and neither refers to an + // implicit object parameter of a non-static member function declared + // without a ref-qualifier, and *either* S1 binds an rvalue reference + // to an rvalue and S2 binds an lvalue reference *or S1 binds an + // lvalue reference to a function lvalue and S2 binds an rvalue + // reference*. + // + // FIXME: Rvalue references. We're going rogue with the above edits, + // because the semantics in the current C++0x working paper (N3225 at the + // time of this writing) break the standard definition of std::forward + // 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.) + return (!SCS1.IsLvalueReference && SCS1.BindsToRvalue && + SCS2.IsLvalueReference) || + (SCS1.IsLvalueReference && SCS1.BindsToFunctionLvalue && + !SCS2.IsLvalueReference); +} + /// CompareStandardConversionSequences - Compare two standard /// conversion sequences to determine whether one is better than the /// other or if they are indistinguishable (C++ 13.3.3.2p3). @@ -2429,18 +2458,12 @@ CompareStandardConversionSequences(Sema &S, return QualCK; if (SCS1.ReferenceBinding && SCS2.ReferenceBinding) { - // C++0x [over.ics.rank]p3b4: - // -- S1 and S2 are reference bindings (8.5.3) and neither refers to an - // implicit object parameter of a non-static member function declared - // without a ref-qualifier, and S1 binds an rvalue reference to an - // rvalue and S2 binds an lvalue reference. - // 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.) - if (SCS1.RRefBinding != SCS2.RRefBinding) - return SCS1.RRefBinding ? ImplicitConversionSequence::Better - : ImplicitConversionSequence::Worse; - + // Check for a better reference binding based on the kind of bindings. + if (isBetterReferenceBindingKind(SCS1, SCS2)) + return ImplicitConversionSequence::Better; + else if (isBetterReferenceBindingKind(SCS2, SCS1)) + return ImplicitConversionSequence::Worse; + // C++ [over.ics.rank]p3b4: // -- S1 and S2 are reference bindings (8.5.3), and the types to // which the references refer are the same type except for @@ -2966,7 +2989,9 @@ TryReferenceInit(Sema &S, Expr *&Init, QualType DeclType, ICS.Standard.setToType(2, T1); ICS.Standard.ReferenceBinding = true; ICS.Standard.DirectBinding = true; - ICS.Standard.RRefBinding = isRValRef && InitCategory.isRValue(); + ICS.Standard.IsLvalueReference = !isRValRef; + ICS.Standard.BindsToFunctionLvalue = T2->isFunctionType(); + ICS.Standard.BindsToRvalue = false; ICS.Standard.CopyConstructor = 0; // Nothing more to do: the inaccessibility/ambiguity check for @@ -3036,7 +3061,9 @@ TryReferenceInit(Sema &S, Expr *&Init, QualType DeclType, ICS.Standard.DirectBinding = S.getLangOptions().CPlusPlus0x || (InitCategory.isPRValue() && !T2->isRecordType()); - ICS.Standard.RRefBinding = isRValRef && InitCategory.isRValue(); + ICS.Standard.IsLvalueReference = !isRValRef; + ICS.Standard.BindsToFunctionLvalue = T2->isFunctionType(); + ICS.Standard.BindsToRvalue = InitCategory.isRValue(); ICS.Standard.CopyConstructor = 0; return ICS; } @@ -3114,10 +3141,14 @@ TryReferenceInit(Sema &S, Expr *&Init, QualType DeclType, // Of course, that's still a reference binding. if (ICS.isStandard()) { ICS.Standard.ReferenceBinding = true; - ICS.Standard.RRefBinding = isRValRef; + ICS.Standard.IsLvalueReference = !isRValRef; + ICS.Standard.BindsToFunctionLvalue = T2->isFunctionType(); + ICS.Standard.BindsToRvalue = true; } else if (ICS.isUserDefined()) { ICS.UserDefined.After.ReferenceBinding = true; - ICS.UserDefined.After.RRefBinding = isRValRef; + ICS.Standard.IsLvalueReference = !isRValRef; + ICS.Standard.BindsToFunctionLvalue = T2->isFunctionType(); + ICS.Standard.BindsToRvalue = true; } return ICS; @@ -3212,7 +3243,11 @@ TryObjectArgumentInitialization(Sema &S, QualType OrigFromType, ICS.Standard.setAllToTypes(ImplicitParamType); ICS.Standard.ReferenceBinding = true; ICS.Standard.DirectBinding = true; - ICS.Standard.RRefBinding = false; + + // FIXME: Rvalue references. + ICS.Standard.IsLvalueReference = true; + ICS.Standard.BindsToFunctionLvalue = false; + ICS.Standard.BindsToRvalue = false; return ICS; } diff --git a/test/CXX/over/over.match/over.match.best/over.ics.rank/p3-0x.cpp b/test/CXX/over/over.match/over.match.best/over.ics.rank/p3-0x.cpp index faff058a50..ab171bc3f6 100644 --- a/test/CXX/over/over.match/over.match.best/over.ics.rank/p3-0x.cpp +++ b/test/CXX/over/over.match/over.match.best/over.ics.rank/p3-0x.cpp @@ -50,10 +50,10 @@ struct remove_reference { }; namespace FunctionReferencesOverloading { - template int &f(typename remove_reference::type&); // expected-note{{candidate function [with T = int (&)(int)]}} - template float &f(typename remove_reference::type&&); // expected-note{{candidate function [with T = int (&)(int)]}} + template int &f(typename remove_reference::type&); + template float &f(typename remove_reference::type&&); void test_f(int (&func_ref)(int)) { - f(func_ref); // expected-error{{call to 'f' is ambiguous}} + int &ir = f(func_ref); } } -- 2.40.0