From 168319c81b8f4e7addf36ad15ef24919faf23504 Mon Sep 17 00:00:00 2001 From: Sebastian Redl Date: Sun, 12 Feb 2012 16:37:24 +0000 Subject: [PATCH] Employ DirectList initialized entities to properly sort through some initialization edge cases. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@150342 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Sema/Initialization.h | 8 +++-- lib/Sema/SemaDecl.cpp | 9 +++-- lib/Sema/SemaInit.cpp | 33 ++++++++++++------- .../SemaCXX/cxx0x-initializer-constructor.cpp | 29 ++++++++++++++++ test/SemaCXX/generalized-initializers.cpp | 23 ------------- 5 files changed, 62 insertions(+), 40 deletions(-) diff --git a/include/clang/Sema/Initialization.h b/include/clang/Sema/Initialization.h index 853f8897f2..dde46a2ff4 100644 --- a/include/clang/Sema/Initialization.h +++ b/include/clang/Sema/Initialization.h @@ -470,9 +470,13 @@ public: assert(Kind == SIK_Copy && "Only copy initialization has an '='"); return Locations[1]; } - + bool isCopyInit() const { return Kind == SIK_Copy; } - + + /// \brief Retrieve whether this initialization allows the use of explicit + /// constructors. + bool AllowExplicit() const { return !isCopyInit(); } + /// \brief Retrieve the source range containing the locations of the open /// and closing parentheses for value and direct initializations. SourceRange getParenRange() const { diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index feffaf13fa..52789c781c 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -6143,9 +6143,12 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, if (!VDecl->isInvalidDecl()) { InitializedEntity Entity = InitializedEntity::InitializeVariable(VDecl); InitializationKind Kind - = DirectInit ? InitializationKind::CreateDirect(VDecl->getLocation(), - Init->getLocStart(), - Init->getLocEnd()) + = DirectInit ? + CXXDirectInit ? InitializationKind::CreateDirect(VDecl->getLocation(), + Init->getLocStart(), + Init->getLocEnd()) + : InitializationKind::CreateDirectList( + VDecl->getLocation()) : InitializationKind::CreateCopy(VDecl->getLocation(), Init->getLocStart()); diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp index 0532cdc392..c5d4913539 100644 --- a/lib/Sema/SemaInit.cpp +++ b/lib/Sema/SemaInit.cpp @@ -2860,9 +2860,7 @@ static void TryConstructorInitialization(Sema &S, // Determine whether we are allowed to call explicit constructors or // explicit conversion operators. - bool AllowExplicit = (Kind.getKind() == InitializationKind::IK_Direct || - Kind.getKind() == InitializationKind::IK_Value || - Kind.getKind() == InitializationKind::IK_Default); + bool AllowExplicit = Kind.AllowExplicit(); bool CopyInitialization = Kind.getKind() == InitializationKind::IK_Copy; // - Otherwise, if T is a class type, constructors are considered. The @@ -3065,8 +3063,10 @@ static void TryListInitialization(Sema &S, if (DestType->isRecordType() && !DestType->isAggregateType()) { if (S.getLangOptions().CPlusPlus0x) { Expr *Arg = InitList; + // A direct-initializer is not list-syntax, i.e. there's no special + // treatment of "A a({1, 2});". TryConstructorInitialization(S, Entity, Kind, &Arg, 1, DestType, - Sequence, /*InitListSyntax=*/true); + Sequence, Kind.getKind() != InitializationKind::IK_Direct); } else Sequence.SetFailed(InitializationSequence::FK_InitListBadDestinationType); return; @@ -3074,7 +3074,7 @@ static void TryListInitialization(Sema &S, InitListChecker CheckInitList(S, Entity, InitList, DestType, /*VerifyOnly=*/true, - Kind.getKind() != InitializationKind::IK_Direct || + Kind.getKind() != InitializationKind::IK_DirectList || !S.getLangOptions().CPlusPlus0x); if (CheckInitList.HadError()) { Sequence.SetFailed(InitializationSequence::FK_ListInitializationFailed); @@ -3118,7 +3118,7 @@ static OverloadingResult TryRefInitWithConversionFunction(Sema &S, // Determine whether we are allowed to call explicit constructors or // explicit conversion operators. - bool AllowExplicit = Kind.getKind() == InitializationKind::IK_Direct; + bool AllowExplicit = Kind.AllowExplicit(); const RecordType *T1RecordType = 0; if (AllowRValues && (T1RecordType = T1->getAs()) && @@ -3480,7 +3480,7 @@ static void TryReferenceInitializationCore(Sema &S, // Determine whether we are allowed to call explicit constructors or // explicit conversion operators. - bool AllowExplicit = (Kind.getKind() == InitializationKind::IK_Direct); + bool AllowExplicit = Kind.AllowExplicit(); InitializedEntity TempEntity = InitializedEntity::InitializeTemporary(cv1T1); @@ -3643,7 +3643,7 @@ static void TryUserDefinedConversion(Sema &S, // Determine whether we are allowed to call explicit constructors or // explicit conversion operators. - bool AllowExplicit = Kind.getKind() == InitializationKind::IK_Direct; + bool AllowExplicit = Kind.AllowExplicit(); if (const RecordType *DestRecordType = DestType->getAs()) { // The type we're converting to is a class type. Enumerate its constructors @@ -5028,7 +5028,7 @@ InitializationSequence::Perform(Sema &S, InitializedEntity TempEntity = InitializedEntity::InitializeTemporary(Ty); InitListChecker PerformInitList(S, IsTemporary ? TempEntity : Entity, InitList, Ty, /*VerifyOnly=*/false, - Kind.getKind() != InitializationKind::IK_Direct || + Kind.getKind() != InitializationKind::IK_DirectList || !S.getLangOptions().CPlusPlus0x); if (PerformInitList.HadError()) return ExprError(); @@ -5050,10 +5050,19 @@ InitializationSequence::Perform(Sema &S, } case SK_ListConstructorCall: { + // When an initializer list is passed for a parameter of type "reference + // to object", we don't get an EK_Temporary entity, but instead an + // EK_Parameter entity with reference type. + // FIXME: This is a hack. Why is this necessary here, but not in other + // places where implicit temporaries are created? + InitializedEntity TempEntity = InitializedEntity::InitializeTemporary( + Entity.getType().getNonReferenceType()); + bool UseTemporary = Entity.getType()->isReferenceType(); InitListExpr *InitList = cast(CurInit.get()); MultiExprArg Arg(InitList->getInits(), InitList->getNumInits()); - CurInit = PerformConstructorInitialization(S, Entity, Kind, - move(Arg), *Step, + CurInit = PerformConstructorInitialization(S, UseTemporary ? TempEntity : + Entity, + Kind, move(Arg), *Step, ConstructorInitRequiresZeroInit); break; } @@ -5549,7 +5558,7 @@ bool InitializationSequence::Diagnose(Sema &S, QualType DestType = Entity.getType(); InitListChecker DiagnoseInitList(S, Entity, InitList, DestType, /*VerifyOnly=*/false, - Kind.getKind() != InitializationKind::IK_Direct || + Kind.getKind() != InitializationKind::IK_DirectList || !S.getLangOptions().CPlusPlus0x); assert(DiagnoseInitList.HadError() && "Inconsistent init list check result."); diff --git a/test/SemaCXX/cxx0x-initializer-constructor.cpp b/test/SemaCXX/cxx0x-initializer-constructor.cpp index 4858d7af9d..3e74ad777f 100644 --- a/test/SemaCXX/cxx0x-initializer-constructor.cpp +++ b/test/SemaCXX/cxx0x-initializer-constructor.cpp @@ -146,4 +146,33 @@ namespace objects { static_assert(sizeof(ov2({1})) == sizeof(one), "bad overload"); // list -> int ranks as identity static_assert(sizeof(ov2({1, 2, 3})) == sizeof(two), "bad overload"); // list -> F only viable } + + struct G { // expected-note 2 {{not viable}} + // This is not an initializer-list constructor. + template + G(std::initializer_list, T ...); // expected-note {{not viable}} + }; + + struct H { // expected-note 2 {{not viable}} + explicit H(int, int); // expected-note {{not viable}} + H(int, void*); // expected-note {{not viable}} + }; + + void edge_cases() { + // invalid (the first phase only considers init-list ctors) + // (for the second phase, no constructor is viable) + G g1{1, 2, 3}; // expected-error {{no matching constructor}} + + // valid (T deduced to <>). + G g2({1, 2, 3}); + + // invalid + H h1({1, 2}); // expected-error {{no matching constructor}} + + // valid (by copy constructor). + H h2({1, nullptr}); + + // valid + H h3{1, 2}; + } } diff --git a/test/SemaCXX/generalized-initializers.cpp b/test/SemaCXX/generalized-initializers.cpp index e62ff365e9..1228d300d1 100644 --- a/test/SemaCXX/generalized-initializers.cpp +++ b/test/SemaCXX/generalized-initializers.cpp @@ -49,27 +49,4 @@ namespace litb { // invalid int const &b({0}); // expected-error {{}} - struct C { explicit C(int, int); C(int, long); }; - - // invalid - C c({1, 2}); // expected-error {{}} - - // valid (by copy constructor). - C d({1, 2L}); - - // valid - C e{1, 2}; - - struct B { - template - B(std::initializer_list, T ...); - }; - - // invalid (the first phase only considers init-list ctors) - // (for the second phase, no constructor is viable) - B f{1, 2, 3}; - - // valid (T deduced to <>). - B g({1, 2, 3}); - } -- 2.40.0