forked from OSchip/llvm-project
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:
parent
56ce0932db
commit
72ef7bc2b5
|
@ -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,14 +256,15 @@ 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
|
||||
/// the same as \c ConversionFunction or it might be a using declaration
|
||||
/// that refers to \c ConversionFunction.
|
||||
DeclAccessPair FoundConversionFunction;
|
||||
|
||||
|
||||
void DebugPrint() const;
|
||||
};
|
||||
|
||||
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -305,7 +305,10 @@ void UserDefinedConversionSequence::DebugPrint() const {
|
|||
Before.DebugPrint();
|
||||
OS << " -> ";
|
||||
}
|
||||
OS << '\'' << *ConversionFunction << '\'';
|
||||
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,
|
||||
ICS1.UserDefined.After,
|
||||
ICS2.UserDefined.After);
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue