Skip to content
This repository was archived by the owner on Nov 1, 2021. It is now read-only.

Commit a1f8d5a

Browse files
committed
Superficial fix for PR20218: binding a function lvalue to a const reference to
a function pointer is neither better nor worse than binding a function lvalue to a function rvalue reference. Don't get confused and think that both bindings are binding to a function lvalue (which would make the lvalue form win); the const reference is binding to an rvalue. The "real" bug in PR20218 is still present: we're getting the wrong answer from template argument deduction, and that's what leads us to this weird overload set. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@212916 91177308-0d34-0410-b5e6-96231b3b80d8
1 parent 03fb337 commit a1f8d5a

File tree

2 files changed

+50
-17
lines changed

2 files changed

+50
-17
lines changed

Diff for: lib/Sema/SemaOverload.cpp

+28-17
Original file line numberDiff line numberDiff line change
@@ -3465,8 +3465,9 @@ compareStandardConversionSubsets(ASTContext &Context,
34653465

34663466
/// \brief Determine whether one of the given reference bindings is better
34673467
/// than the other based on what kind of bindings they are.
3468-
static bool isBetterReferenceBindingKind(const StandardConversionSequence &SCS1,
3469-
const StandardConversionSequence &SCS2) {
3468+
static bool
3469+
isBetterReferenceBindingKind(const StandardConversionSequence &SCS1,
3470+
const StandardConversionSequence &SCS2) {
34703471
// C++0x [over.ics.rank]p3b4:
34713472
// -- S1 and S2 are reference bindings (8.5.3) and neither refers to an
34723473
// implicit object parameter of a non-static member function declared
@@ -3487,7 +3488,7 @@ static bool isBetterReferenceBindingKind(const StandardConversionSequence &SCS1,
34873488
return (!SCS1.IsLvalueReference && SCS1.BindsToRvalue &&
34883489
SCS2.IsLvalueReference) ||
34893490
(SCS1.IsLvalueReference && SCS1.BindsToFunctionLvalue &&
3490-
!SCS2.IsLvalueReference);
3491+
!SCS2.IsLvalueReference && SCS2.BindsToFunctionLvalue);
34913492
}
34923493

34933494
/// CompareStandardConversionSequences - Compare two standard
@@ -4372,6 +4373,10 @@ TryReferenceInit(Sema &S, Expr *Init, QualType DeclType,
43724373
return ICS;
43734374
}
43744375

4376+
// A temporary of function type cannot be created; don't even try.
4377+
if (T1->isFunctionType())
4378+
return ICS;
4379+
43754380
// -- Otherwise, a temporary of type "cv1 T1" is created and
43764381
// initialized from the initializer expression using the
43774382
// rules for a non-reference copy initialization (8.5). The
@@ -4433,28 +4438,34 @@ TryReferenceInit(Sema &S, Expr *Init, QualType DeclType,
44334438
if (ICS.isStandard()) {
44344439
ICS.Standard.ReferenceBinding = true;
44354440
ICS.Standard.IsLvalueReference = !isRValRef;
4436-
ICS.Standard.BindsToFunctionLvalue = T2->isFunctionType();
4441+
ICS.Standard.BindsToFunctionLvalue = false;
44374442
ICS.Standard.BindsToRvalue = true;
44384443
ICS.Standard.BindsImplicitObjectArgumentWithoutRefQualifier = false;
44394444
ICS.Standard.ObjCLifetimeConversionBinding = false;
44404445
} else if (ICS.isUserDefined()) {
4441-
// Don't allow rvalue references to bind to lvalues.
4442-
if (DeclType->isRValueReferenceType()) {
4443-
if (const ReferenceType *RefType =
4444-
ICS.UserDefined.ConversionFunction->getReturnType()
4445-
->getAs<LValueReferenceType>()) {
4446-
if (!RefType->getPointeeType()->isFunctionType()) {
4447-
ICS.setBad(BadConversionSequence::lvalue_ref_to_rvalue, Init,
4448-
DeclType);
4449-
return ICS;
4450-
}
4451-
}
4446+
const ReferenceType *LValRefType =
4447+
ICS.UserDefined.ConversionFunction->getReturnType()
4448+
->getAs<LValueReferenceType>();
4449+
4450+
// C++ [over.ics.ref]p3:
4451+
// Except for an implicit object parameter, for which see 13.3.1, a
4452+
// standard conversion sequence cannot be formed if it requires [...]
4453+
// binding an rvalue reference to an lvalue other than a function
4454+
// lvalue.
4455+
// Note that the function case is not possible here.
4456+
if (DeclType->isRValueReferenceType() && LValRefType) {
4457+
// FIXME: This is the wrong BadConversionSequence. The problem is binding
4458+
// an rvalue reference to a (non-function) lvalue, not binding an lvalue
4459+
// reference to an rvalue!
4460+
ICS.setBad(BadConversionSequence::lvalue_ref_to_rvalue, Init, DeclType);
4461+
return ICS;
44524462
}
4463+
44534464
ICS.UserDefined.Before.setAsIdentityConversion();
44544465
ICS.UserDefined.After.ReferenceBinding = true;
44554466
ICS.UserDefined.After.IsLvalueReference = !isRValRef;
4456-
ICS.UserDefined.After.BindsToFunctionLvalue = T2->isFunctionType();
4457-
ICS.UserDefined.After.BindsToRvalue = true;
4467+
ICS.UserDefined.After.BindsToFunctionLvalue = false;
4468+
ICS.UserDefined.After.BindsToRvalue = !LValRefType;
44584469
ICS.UserDefined.After.BindsImplicitObjectArgumentWithoutRefQualifier = false;
44594470
ICS.UserDefined.After.ObjCLifetimeConversionBinding = false;
44604471
}

Diff for: test/SemaCXX/overload-call.cpp

+22
Original file line numberDiff line numberDiff line change
@@ -590,3 +590,25 @@ void test5() {
590590
} callable;
591591
callable(); // expected-error{{no matching function for call}}
592592
}
593+
594+
namespace PR20218 {
595+
void f(void (*const &)()); // expected-note{{candidate}}
596+
void f(void (&&)()) = delete; // expected-note{{candidate}} expected-warning 2{{extension}}
597+
void g(void (&&)()) = delete; // expected-note{{candidate}} expected-warning 2{{extension}}
598+
void g(void (*const &)()); // expected-note{{candidate}}
599+
600+
void x();
601+
typedef void (&fr)();
602+
struct Y { operator fr(); } y;
603+
604+
void h() {
605+
f(x); // expected-error {{ambiguous}}
606+
g(x); // expected-error {{ambiguous}}
607+
608+
// OK! These ones try to copy-initialize a temporary of the reference's
609+
// underlying type, which only works for the pointer case and not for the
610+
// reference case.
611+
f(y);
612+
g(y);
613+
}
614+
}

0 commit comments

Comments
 (0)