From 70e24fccc8ef4aa8be03a778e9655bfcfa79dd14 Mon Sep 17 00:00:00 2001 From: Sebastian Redl Date: Sun, 1 Apr 2012 19:54:59 +0000 Subject: [PATCH] Properly handle explicit constructors in list-initialization. Fixes PR12120. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@153849 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Basic/DiagnosticSemaKinds.td | 4 +++ include/clang/Sema/Initialization.h | 4 ++- lib/Sema/SemaInit.cpp | 29 +++++++++++++++++-- .../SemaCXX/cxx0x-initializer-constructor.cpp | 20 +++++++++---- 4 files changed, 48 insertions(+), 9 deletions(-) diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 32ac7be9e5..863f9db164 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -1189,6 +1189,10 @@ def warn_cxx98_compat_temp_copy : Warning< "an inaccessible constructor|find no viable constructor|find ambiguous " "constructors|invoke a deleted constructor}0 in C++98">, InGroup, DefaultIgnore; +def err_selected_explicit_constructor : Error< + "chosen constructor is explicit in copy-initialization">; +def note_constructor_declared_here : Note< + "constructor declared here">; // C++11 decltype def err_decltype_in_declarator : Error< diff --git a/include/clang/Sema/Initialization.h b/include/clang/Sema/Initialization.h index 9040703436..6d92df6322 100644 --- a/include/clang/Sema/Initialization.h +++ b/include/clang/Sema/Initialization.h @@ -719,7 +719,9 @@ public: FK_PlaceholderType, /// \brief Failed to initialize a std::initializer_list because copy /// construction of some element failed. - FK_InitListElementCopyFailure + FK_InitListElementCopyFailure, + /// \brief List-copy-initialization chose an explicit constructor. + FK_ExplicitConstructor }; private: diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp index 125149edc2..f748db943a 100644 --- a/lib/Sema/SemaInit.cpp +++ b/lib/Sema/SemaInit.cpp @@ -2465,6 +2465,7 @@ bool InitializationSequence::isAmbiguous() const { case FK_VariableLengthArrayHasInitializer: case FK_PlaceholderType: case FK_InitListElementCopyFailure: + case FK_ExplicitConstructor: return false; case FK_ReferenceInitOverloadFailed: @@ -2896,7 +2897,7 @@ static void TryConstructorInitialization(Sema &S, // Determine whether we are allowed to call explicit constructors or // explicit conversion operators. - bool AllowExplicit = Kind.AllowExplicit(); + bool AllowExplicit = Kind.AllowExplicit() || InitListSyntax; bool CopyInitialization = Kind.getKind() == InitializationKind::IK_Copy; // - Otherwise, if T is a class type, constructors are considered. The @@ -2961,10 +2962,18 @@ static void TryConstructorInitialization(Sema &S, return; } + // C++11 [over.match.list]p1: + // In copy-list-initialization, if an explicit constructor is chosen, the + // initializer is ill-formed. + CXXConstructorDecl *CtorDecl = cast(Best->Function); + if (InitListSyntax && !Kind.AllowExplicit() && CtorDecl->isExplicit()) { + Sequence.SetFailed(InitializationSequence::FK_ExplicitConstructor); + return; + } + // Add the constructor initialization step. Any cv-qualification conversion is // subsumed by the initialization. bool HadMultipleCandidates = (CandidateSet.size() > 1); - CXXConstructorDecl *CtorDecl = cast(Best->Function); Sequence.AddConstructorInitializationStep(CtorDecl, Best->FoundDecl.getAccess(), DestType, HadMultipleCandidates, @@ -5729,6 +5738,18 @@ bool InitializationSequence::Diagnose(Sema &S, } break; } + + case FK_ExplicitConstructor: { + S.Diag(Kind.getLocation(), diag::err_selected_explicit_constructor) + << Args[0]->getSourceRange(); + OverloadCandidateSet::iterator Best; + OverloadingResult Ovl + = FailedCandidateSet.BestViableFunction(S, Kind.getLocation(), Best); + assert(Ovl == OR_Success && "Inconsistent overload resolution"); + CXXConstructorDecl *CtorDecl = cast(Best->Function); + S.Diag(CtorDecl->getLocation(), diag::note_constructor_declared_here); + break; + } } PrintInitLocationNote(S, Entity); @@ -5843,6 +5864,10 @@ void InitializationSequence::dump(raw_ostream &OS) const { case FK_InitListElementCopyFailure: OS << "copy construction of initializer list element failed"; break; + + case FK_ExplicitConstructor: + OS << "list copy initialization chose explicit constructor"; + break; } OS << '\n'; return; diff --git a/test/SemaCXX/cxx0x-initializer-constructor.cpp b/test/SemaCXX/cxx0x-initializer-constructor.cpp index da10189257..68c149218a 100644 --- a/test/SemaCXX/cxx0x-initializer-constructor.cpp +++ b/test/SemaCXX/cxx0x-initializer-constructor.cpp @@ -38,7 +38,7 @@ namespace std { namespace objects { struct X1 { X1(int); }; - struct X2 { explicit X2(int); }; // expected-note 2 {{candidate constructor}} + struct X2 { explicit X2(int); }; // expected-note {{constructor declared here}} template struct A { @@ -94,7 +94,7 @@ namespace objects { { X1 x{0}; } { X1 x = {0}; } { X2 x{0}; } - { X2 x = {0}; } // expected-error {{no matching constructor}} + { X2 x = {0}; } // expected-error {{constructor is explicit}} } struct C { @@ -153,9 +153,9 @@ namespace objects { G(std::initializer_list, T ...); // expected-note 3 {{not viable}} }; - struct H { // expected-note 8 {{not viable}} - explicit H(int, int); // expected-note 3 {{not viable}} - H(int, void*); // expected-note 4 {{not viable}} + struct H { // expected-note 6 {{not viable}} + explicit H(int, int); // expected-note 3 {{not viable}} expected-note {{declared here}} + H(int, void*); // expected-note 3 {{not viable}} }; void edge_cases() { @@ -191,7 +191,7 @@ namespace objects { H h1{1, nullptr}; H h2 = {1, nullptr}; H h3{1, 1}; - H h4 = {1, 1}; // expected-error {{no matching constructor}} + H h4 = {1, 1}; // expected-error {{constructor is explicit}} }; } @@ -259,3 +259,11 @@ namespace PR12257_PR12241 { // 4 levels: init list, gen_pair, command_map via init list, command_pair const std::initializer_list y = {{{{1, 2}}}}; } + +namespace PR12120 { + struct A { explicit A(int); A(float); }; // expected-note {{declared here}} + A a = { 0 }; // expected-error {{constructor is explicit}} + + struct B { explicit B(short); B(long); }; // expected-note 2 {{candidate}} + B b = { 0 }; // expected-error {{ambiguous}} +} -- 2.40.0