From: Richard Smith Date: Thu, 4 Sep 2014 22:13:39 +0000 (+0000) Subject: PR20844: If we fail to list-initialize a reference, map to the referenced type X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=68ecda23a560214703df9111b9aa6b5f48ae12f9;p=clang PR20844: If we fail to list-initialize a reference, map to the referenced type before retrying the initialization to produce diagnostics. Otherwise, we may fail to produce any diagnostics, and silently produce invalid AST in a -Asserts build. Also add a note to this codepath to make it more clear why we were trying to create a temporary. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@217197 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 600c5a3a81..e26374c8af 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -1517,6 +1517,9 @@ def note_block_var_fixit_add_initialization : Note< def note_in_omitted_aggregate_initializer : Note< "in implicit initialization of %select{array element %1|field %1}0 " "with omitted initializer">; +def note_in_reference_temporary_list_initializer : Note< + "in initialization of temporary of type %0 created to " + "list-initialize this reference">; def note_var_fixit_add_initialization : Note< "initialize the variable %0 to silence this warning">; def note_uninit_fixit_remove_cond : Note< diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp index 326bfc9087..7a2fa08e28 100644 --- a/lib/Sema/SemaInit.cpp +++ b/lib/Sema/SemaInit.cpp @@ -6431,6 +6431,19 @@ static void diagnoseListInit(Sema &S, const InitializedEntity &Entity, return diagnoseListInit(S, HiddenArray, InitList); } + if (DestType->isReferenceType()) { + // A list-initialization failure for a reference means that we tried to + // create a temporary of the inner type (per [dcl.init.list]p3.6) and the + // inner initialization failed. + QualType T = DestType->getAs()->getPointeeType(); + diagnoseListInit(S, InitializedEntity::InitializeTemporary(T), InitList); + SourceLocation Loc = InitList->getLocStart(); + if (auto *D = Entity.getDecl()) + Loc = D->getLocation(); + S.Diag(Loc, diag::note_in_reference_temporary_list_initializer) << T; + return; + } + InitListChecker DiagnoseInitList(S, Entity, InitList, DestType, /*VerifyOnly=*/false); assert(DiagnoseInitList.HadError() && diff --git a/test/CXX/dcl.decl/dcl.init/dcl.init.list/p3-0x.cpp b/test/CXX/dcl.decl/dcl.init/dcl.init.list/p3-0x.cpp index 971e0c11af..d7ffd0758a 100644 --- a/test/CXX/dcl.decl/dcl.init/dcl.init.list/p3-0x.cpp +++ b/test/CXX/dcl.decl/dcl.init/dcl.init.list/p3-0x.cpp @@ -4,7 +4,7 @@ namespace std { typedef decltype(sizeof(int)) size_t; template - struct initializer_list // expected-note 2{{candidate}} + struct initializer_list { const E *p; size_t n; @@ -112,15 +112,16 @@ namespace bullet8 { } namespace rdar13395022 { - struct MoveOnly { - MoveOnly(MoveOnly&&); + struct MoveOnly { // expected-note {{candidate}} + MoveOnly(MoveOnly&&); // expected-note 2{{copy constructor is implicitly deleted because}} expected-note {{candidate}} }; void test(MoveOnly mo) { - // FIXME: These diagnostics are poor. - auto &&list1 = {mo}; // expected-error{{no viable conversion}} - MoveOnly (&&list2)[1] = {mo}; // expected-error{{no viable conversion}} + auto &&list1 = {mo}; // expected-error {{call to implicitly-deleted copy constructor}} expected-note {{in initialization of temporary of type 'std::initializer_list}} + MoveOnly (&&list2)[1] = {mo}; // expected-error {{call to implicitly-deleted copy constructor}} expected-note {{in initialization of temporary of type 'rdar13395022::MoveOnly [1]'}} std::initializer_list &&list3 = {}; - MoveOnly (&&list4)[1] = {}; // expected-error{{uninitialized}} + MoveOnly (&&list4)[1] = {}; // expected-error {{no matching constructor}} + // expected-note@-1 {{in implicit initialization of array element 0 with omitted initializer}} + // expected-note@-2 {{in initialization of temporary of type 'rdar13395022::MoveOnly [1]' created to list-initialize this reference}} } } diff --git a/test/SemaCXX/cxx0x-initializer-references.cpp b/test/SemaCXX/cxx0x-initializer-references.cpp index 9096c8a1c2..d1a9ed3007 100644 --- a/test/SemaCXX/cxx0x-initializer-references.cpp +++ b/test/SemaCXX/cxx0x-initializer-references.cpp @@ -118,3 +118,9 @@ namespace inner_init { F f2 { { 0 } }; // expected-error {{chosen constructor is explicit}} F f3 { { { 0 } } }; // expected-error {{chosen constructor is explicit}} } + +namespace PR20844 { + struct A {}; + struct B { operator A&(); } b; + A &a{b}; // expected-error {{excess elements}} expected-note {{in initialization of temporary of type 'PR20844::A'}} +} diff --git a/test/SemaCXX/explicit.cpp b/test/SemaCXX/explicit.cpp index aa28bd85af..155141c058 100644 --- a/test/SemaCXX/explicit.cpp +++ b/test/SemaCXX/explicit.cpp @@ -86,7 +86,7 @@ namespace Conversion { // Y is an aggregate, so aggregate-initialization is performed and the // conversion function is not considered. const Y y10{z}; // expected-error {{excess elements}} - const Y& y11{z}; // expected-error {{no viable conversion from 'Z' to 'const Y'}} + const Y& y11{z}; // expected-error {{excess elements}} expected-note {{in initialization of temporary of type 'const Y'}} const int& y12{z}; // X is not an aggregate, so constructors are considered.