From cc7a6484d8afd6f8bede2757666c42248228e408 Mon Sep 17 00:00:00 2001 From: Sebastian Redl Date: Tue, 1 Nov 2011 15:53:09 +0000 Subject: [PATCH] Enable function call and some overload resolution with parameters of aggregate class type and initializer list arguments. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@143462 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Sema/Overload.h | 25 ++++++++-- lib/Sema/SemaExprCXX.cpp | 1 + lib/Sema/SemaOverload.cpp | 47 ++++++++++++++++--- test/SemaCXX/cxx0x-initializer-aggregates.cpp | 35 +++++++++++++- 4 files changed, 95 insertions(+), 13 deletions(-) diff --git a/include/clang/Sema/Overload.h b/include/clang/Sema/Overload.h index dbc0926f03..e9ca3359c5 100644 --- a/include/clang/Sema/Overload.h +++ b/include/clang/Sema/Overload.h @@ -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. diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index c96ab42b88..f1cb5ea040 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -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(FD)) { CastKind = CK_UserDefinedConversion; diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index f5494dee17..153c0f8c24 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -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 + // 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 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; } diff --git a/test/SemaCXX/cxx0x-initializer-aggregates.cpp b/test/SemaCXX/cxx0x-initializer-aggregates.cpp index 687d27246c..d8b79deb62 100644 --- a/test/SemaCXX/cxx0x-initializer-aggregates.cpp +++ b/test/SemaCXX/cxx0x-initializer-aggregates.cpp @@ -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"); + } } -- 2.40.0