[cfe-commits] r145769 - in /cfe/trunk: lib/Sema/SemaOverload.cpp test/SemaCXX/cxx0x-initializer-references.cpp
Sebastian Redl
sebastian.redl at getdesigned.at
Sat Dec 3 06:54:30 PST 2011
Author: cornedbee
Date: Sat Dec 3 08:54:30 2011
New Revision: 145769
URL: http://llvm.org/viewvc/llvm-project?rev=145769&view=rev
Log:
Implement overload resolution for reference-typed parameters supplied with initializer lists.
Modified:
cfe/trunk/lib/Sema/SemaOverload.cpp
cfe/trunk/test/SemaCXX/cxx0x-initializer-references.cpp
Modified: cfe/trunk/lib/Sema/SemaOverload.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=145769&r1=145768&r2=145769&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOverload.cpp Sat Dec 3 08:54:30 2011
@@ -3619,7 +3619,7 @@
/// \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 @@
// 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:
Modified: cfe/trunk/test/SemaCXX/cxx0x-initializer-references.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/cxx0x-initializer-references.cpp?rev=145769&r1=145768&r2=145769&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/cxx0x-initializer-references.cpp (original)
+++ cfe/trunk/test/SemaCXX/cxx0x-initializer-references.cpp Sat Dec 3 08:54:30 2011
@@ -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 @@
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");
+ }
+
}
More information about the cfe-commits
mailing list