Implement overload resolution for reference-typed parameters supplied with initializer lists.

llvm-svn: 145769
This commit is contained in:
Sebastian Redl 2011-12-03 14:54:30 +00:00
parent 006e43bcc0
commit df88864273
2 changed files with 108 additions and 3 deletions

View File

@ -3619,7 +3619,7 @@ FindConversionForRefInit(Sema &S, ImplicitConversionSequence &ICS,
/// \brief Compute an implicit conversion sequence for reference
/// initialization.
static ImplicitConversionSequence
TryReferenceInit(Sema &S, Expr *&Init, QualType DeclType,
TryReferenceInit(Sema &S, Expr *Init, QualType DeclType,
SourceLocation DeclLoc,
bool SuppressUserConversions,
bool AllowExplicit) {
@ -3950,9 +3950,71 @@ TryListConversion(Sema &S, InitListExpr *From, QualType ToType,
// C++11 [over.ics.list]p5:
// Otherwise, if the parameter is a reference, see 13.3.3.1.4.
// FIXME: Implement this.
if (ToType->isReferenceType())
if (ToType->isReferenceType()) {
// The standard is notoriously unclear here, since 13.3.3.1.4 doesn't
// mention initializer lists in any way. So we go by what list-
// initialization would do and try to extrapolate from that.
QualType T1 = ToType->getAs<ReferenceType>()->getPointeeType();
// If the initializer list has a single element that is reference-related
// to the parameter type, we initialize the reference from that.
if (From->getNumInits() == 1) {
Expr *Init = From->getInit(0);
QualType T2 = Init->getType();
// If the initializer is the address of an overloaded function, try
// to resolve the overloaded function. If all goes well, T2 is the
// type of the resulting function.
if (S.Context.getCanonicalType(T2) == S.Context.OverloadTy) {
DeclAccessPair Found;
if (FunctionDecl *Fn = S.ResolveAddressOfOverloadedFunction(
Init, ToType, false, Found))
T2 = Fn->getType();
}
// Compute some basic properties of the types and the initializer.
bool dummy1 = false;
bool dummy2 = false;
bool dummy3 = false;
Sema::ReferenceCompareResult RefRelationship
= S.CompareReferenceRelationship(From->getLocStart(), T1, T2, dummy1,
dummy2, dummy3);
if (RefRelationship >= Sema::Ref_Related)
return TryReferenceInit(S, Init, ToType,
/*FIXME:*/From->getLocStart(),
SuppressUserConversions,
/*AllowExplicit=*/false);
}
// Otherwise, we bind the reference to a temporary created from the
// initializer list.
Result = TryListConversion(S, From, T1, SuppressUserConversions,
InOverloadResolution,
AllowObjCWritebackConversion);
if (Result.isFailure())
return Result;
assert(!Result.isEllipsis() &&
"Sub-initialization cannot result in ellipsis conversion.");
// Can we even bind to a temporary?
if (ToType->isRValueReferenceType() ||
(T1.isConstQualified() && !T1.isVolatileQualified())) {
StandardConversionSequence &SCS = Result.isStandard() ? Result.Standard :
Result.UserDefined.After;
SCS.ReferenceBinding = true;
SCS.IsLvalueReference = ToType->isLValueReferenceType();
SCS.BindsToRvalue = true;
SCS.BindsToFunctionLvalue = false;
SCS.BindsImplicitObjectArgumentWithoutRefQualifier = false;
SCS.ObjCLifetimeConversionBinding = false;
} else
Result.setBad(BadConversionSequence::lvalue_ref_to_rvalue,
From, ToType);
return Result;
}
// C++11 [over.ics.list]p6:
// Otherwise, if the parameter type is not a class:

View File

@ -1,5 +1,8 @@
// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
struct one { char c; };
struct two { char c[2]; };
namespace reference {
struct A {
int i1, i2;
@ -28,4 +31,44 @@ namespace reference {
static_assert(sizeof(arrayRef) == 3 * sizeof(int), "bad array size");
}
struct B {
int i1;
};
void call() {
void f(const int&);
f({1});
void g(int&); // expected-note {{passing argument}}
g({1}); // expected-error {{cannot bind to an initializer list temporary}}
int i = 0;
g({i});
void h(const B&);
h({1});
void a(B&); // expected-note {{passing argument}}
a({1}); // expected-error {{cannot bind to an initializer list temporary}}
B b{1};
a({b});
}
void overloading() {
one f(const int&);
two f(const B&);
// First is identity conversion, second is user-defined conversion.
static_assert(sizeof(f({1})) == sizeof(one), "bad overload resolution");
one g(int&);
two g(const B&);
static_assert(sizeof(g({1})) == sizeof(two), "bad overload resolution");
one h(const int&);
two h(const A&);
static_assert(sizeof(h({1, 2})) == sizeof(two), "bad overload resolution");
}
}