Enable function call and some overload resolution with parameters of aggregate class type and initializer list arguments.

llvm-svn: 143462
This commit is contained in:
Sebastian Redl 2011-11-01 15:53:09 +00:00
parent 56ce0932db
commit 72ef7bc2b5
4 changed files with 95 additions and 13 deletions

View File

@ -225,9 +225,10 @@ namespace clang {
/// UserDefinedConversionSequence - Represents a user-defined
/// conversion sequence (C++ 13.3.3.1.2).
struct UserDefinedConversionSequence {
/// Before - Represents the standard conversion that occurs before
/// the actual user-defined conversion. (C++ 13.3.3.1.2p1):
/// \brief Represents the standard conversion that occurs before
/// the actual user-defined conversion.
///
/// C++11 13.3.3.1.2p1:
/// If the user-defined conversion is specified by a constructor
/// (12.3.1), the initial standard conversion sequence converts
/// the source type to the type required by the argument of the
@ -255,7 +256,8 @@ namespace clang {
StandardConversionSequence After;
/// ConversionFunction - The function that will perform the
/// user-defined conversion.
/// user-defined conversion. Null if the conversion is an
/// aggregate initialization from an initializer list.
FunctionDecl* ConversionFunction;
/// \brief The declaration that we found via name lookup, which might be
@ -379,7 +381,10 @@ namespace clang {
};
/// ConversionKind - The kind of implicit conversion sequence.
unsigned ConversionKind;
unsigned ConversionKind : 31;
/// \brief Whether the argument is an initializer list.
bool ListInitializationSequence : 1;
void setKind(Kind K) {
destruct();
@ -499,6 +504,16 @@ namespace clang {
Ambiguous.construct();
}
/// \brief Whether this sequence was created by the rules of
/// list-initialization sequences.
bool isListInitializationSequence() const {
return ListInitializationSequence;
}
void setListInitializationSequence() {
ListInitializationSequence = true;
}
// The result of a comparison between implicit conversion
// sequences. Use Sema::CompareImplicitConversionSequences to
// actually perform the comparison.

View File

@ -2129,6 +2129,7 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
FunctionDecl *FD = ICS.UserDefined.ConversionFunction;
CastKind CastKind;
QualType BeforeToType;
assert(FD && "FIXME: aggregate initialization from init list");
if (const CXXConversionDecl *Conv = dyn_cast<CXXConversionDecl>(FD)) {
CastKind = CK_UserDefinedConversion;

View File

@ -305,7 +305,10 @@ void UserDefinedConversionSequence::DebugPrint() const {
Before.DebugPrint();
OS << " -> ";
}
if (ConversionFunction)
OS << '\'' << *ConversionFunction << '\'';
else
OS << "aggregate initialization";
if (After.First || After.Second || After.Third) {
OS << " -> ";
After.DebugPrint();
@ -2701,11 +2704,15 @@ CompareImplicitConversionSequences(Sema &S,
if (ICS1.getKind() != ICS2.getKind())
return ImplicitConversionSequence::Indistinguishable;
ImplicitConversionSequence::CompareKind Result =
ImplicitConversionSequence::Indistinguishable;
// Two implicit conversion sequences of the same form are
// indistinguishable conversion sequences unless one of the
// following rules apply: (C++ 13.3.3.2p3):
if (ICS1.isStandard())
return CompareStandardConversionSequences(S, ICS1.Standard, ICS2.Standard);
Result = CompareStandardConversionSequences(S,
ICS1.Standard, ICS2.Standard);
else if (ICS1.isUserDefined()) {
// User-defined conversion sequence U1 is a better conversion
// sequence than another user-defined conversion sequence U2 if
@ -2715,12 +2722,21 @@ CompareImplicitConversionSequences(Sema &S,
// U2 (C++ 13.3.3.2p3).
if (ICS1.UserDefined.ConversionFunction ==
ICS2.UserDefined.ConversionFunction)
return CompareStandardConversionSequences(S,
Result = CompareStandardConversionSequences(S,
ICS1.UserDefined.After,
ICS2.UserDefined.After);
}
return ImplicitConversionSequence::Indistinguishable;
// List-initialization sequence L1 is a better conversion sequence than
// list-initialization sequence L2 if L1 converts to std::initializer_list<X>
// for some X and L2 does not.
if (Result == ImplicitConversionSequence::Indistinguishable &&
ICS1.isListInitializationSequence() &&
ICS2.isListInitializationSequence()) {
// FIXME: Find out if ICS1 converts to initializer_list and ICS2 doesn't.
}
return Result;
}
static bool hasSimilarType(ASTContext &Context, QualType T1, QualType T2) {
@ -3780,6 +3796,7 @@ TryListConversion(Sema &S, InitListExpr *From, QualType ToType,
ImplicitConversionSequence Result;
Result.setBad(BadConversionSequence::no_conversion, From, ToType);
Result.setListInitializationSequence();
// C++11 [over.ics.list]p2:
// If the parameter type is std::initializer_list<X> or "array of X" and
@ -3805,8 +3822,24 @@ TryListConversion(Sema &S, InitListExpr *From, QualType ToType,
// Otherwise, if the parameter has an aggregate type which can be
// initialized from the initializer list [...] the implicit conversion
// sequence is a user-defined conversion sequence.
// FIXME: Implement this.
if (ToType->isAggregateType()) {
// Type is an aggregate, argument is an init list. At this point it comes
// down to checking whether the initialization works.
// FIXME: Find out whether this parameter is consumed or not.
InitializedEntity Entity =
InitializedEntity::InitializeParameter(S.Context, ToType,
/*Consumed=*/false);
if (S.CanPerformCopyInitialization(Entity, S.Owned(From))) {
Result.setUserDefined();
Result.UserDefined.Before.setAsIdentityConversion();
// Initializer lists don't have a type.
Result.UserDefined.Before.setFromType(QualType());
Result.UserDefined.Before.setAllToTypes(QualType());
Result.UserDefined.After.setAsIdentityConversion();
Result.UserDefined.After.setFromType(ToType);
Result.UserDefined.After.setAllToTypes(ToType);
}
return Result;
}

View File

@ -1,5 +1,8 @@
// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
struct one { char c[1]; };
struct two { char c[2]; };
namespace aggregate {
// Direct list initialization does NOT allow braces to be elided!
struct S {
@ -16,11 +19,41 @@ namespace aggregate {
} v;
};
void test() {
void bracing() {
S s1 = { 1, 2, 3 ,4, 5, 6, 7, 8 }; // no-error
S s2{ {1, 2}, {3, 4}, { {5}, {6} }, { {7, 8} } }; // completely braced
S s3{ 1, 2, 3, 4, 5, 6 }; // expected-error 5 {{cannot omit braces}}
S s4{ {1, 2}, {3, 4}, {5, 6}, { {7, 8} } }; // expected-error 2 {{cannot omit braces}}
S s5{ {1, 2}, {3, 4}, { {5}, {6} }, {7, 8} }; // expected-error {{cannot omit braces}}
}
struct String {
String(const char*);
};
struct A {
int m1;
int m2;
};
void function_call() {
void takes_A(A);
takes_A({1, 2});
}
struct B {
int m1;
String m2;
};
void overloaded_call() {
one overloaded(A);
two overloaded(B);
static_assert(sizeof(overloaded({1, 2})) == sizeof(one), "bad overload");
static_assert(sizeof(overloaded({1, "two"})) == sizeof(two),
"bad overload");
// String is not default-constructible
static_assert(sizeof(overloaded({1})) == sizeof(one), "bad overload");
}
}