]> granicus.if.org Git - clang/commitdiff
Properly handle explicit constructors in list-initialization. Fixes PR12120.
authorSebastian Redl <sebastian.redl@getdesigned.at>
Sun, 1 Apr 2012 19:54:59 +0000 (19:54 +0000)
committerSebastian Redl <sebastian.redl@getdesigned.at>
Sun, 1 Apr 2012 19:54:59 +0000 (19:54 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@153849 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Basic/DiagnosticSemaKinds.td
include/clang/Sema/Initialization.h
lib/Sema/SemaInit.cpp
test/SemaCXX/cxx0x-initializer-constructor.cpp

index 32ac7be9e55e319316431ef3cfbe767861037529..863f9db164f015a2d77aba4f963843ec2825e35e 100644 (file)
@@ -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<CXX98CompatBindToTemporaryCopy>, 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<
index 90407034362a82f527db6948bf5c3146c2005af7..6d92df63228eb793b3e523356b7c24e0ee691d7b 100644 (file)
@@ -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:
index 125149edc25518f9a27c806db512221712e66735..f748db943a121fb1c6928e3898c59b4cf66b02c5 100644 (file)
@@ -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<CXXConstructorDecl>(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<CXXConstructorDecl>(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<CXXConstructorDecl>(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;
index da10189257797374bc85ea8d79b0323f95097f2f..68c149218a738567c9b9a701657152c04022199e 100644 (file)
@@ -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 <int N>
   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<int>, 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<generator_pair> 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}}
+}