mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2024-12-12 09:41:26 +00:00
Implement overload resolution for reference-typed parameters supplied with initializer lists.
llvm-svn: 145769
This commit is contained in:
parent
006e43bcc0
commit
df88864273
@ -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:
|
||||
|
@ -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");
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user