diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index a220e57d0b322..a128726b99917 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -113,6 +113,10 @@ Attribute Changes in Clang Improvements to Clang's diagnostics ----------------------------------- +- Improve the diagnostics for deleted default constructor errors for C++ class + initializer lists that don't explicitly list a class member and thus attempt + to implicitly default construct that member. + Improvements to Clang's time-trace ---------------------------------- diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 8bacb1b73459f..5876b2a6ae0ea 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -6113,6 +6113,8 @@ def note_deleted_special_member_class_subobject : Note< "destructor}5" "%select{||s||}4" "|is an ObjC pointer}6">; +def note_default_constructed_field + : Note<"default constructed field %0 declared here">; def note_deleted_default_ctor_uninit_field : Note< "%select{default constructor of|constructor inherited by}0 " "%1 is implicitly deleted because field %2 of " diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index 450edcb52ae15..f206cd57eca89 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -9148,6 +9148,17 @@ bool InitializationSequence::Diagnose(Sema &S, << (Msg ? Msg->getString() : StringRef()) << ArgsRange; } + // If it's a default constructed member, but it's not in the + // constructor's initializer list, explicitly note where the member is + // declared so the user can see which member is erroneously initialized + // with a deleted default constructor. + if (Kind.getKind() == InitializationKind::IK_Default && + (Entity.getKind() == InitializedEntity::EK_Member || + Entity.getKind() == InitializedEntity::EK_ParenAggInitMember)) { + S.Diag(Entity.getDecl()->getLocation(), + diag::note_default_constructed_field) + << Entity.getDecl(); + } S.NoteDeletedFunction(Best->Function); break; } diff --git a/clang/test/CXX/class/class.init/p1.cpp b/clang/test/CXX/class/class.init/p1.cpp new file mode 100644 index 0000000000000..717dfba89763a --- /dev/null +++ b/clang/test/CXX/class/class.init/p1.cpp @@ -0,0 +1,14 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s + +namespace test_deleted_ctor_note { +struct A { + int a; + A() = delete; // expected-note {{'A' has been explicitly marked deleted here}} + A(int a_) : a(a_) { } +}; + +struct B { + A a1, a2, a3; // expected-note {{default constructed field 'a2' declared here}} + B(int a_) : a1(a_), a3(a_) { } // expected-error{{call to deleted constructor of 'A'}} +}; +} diff --git a/clang/test/CXX/dcl.decl/dcl.init/p14-0x.cpp b/clang/test/CXX/dcl.decl/dcl.init/p14-0x.cpp index e7f501352168c..d548f9c8c2fdf 100644 --- a/clang/test/CXX/dcl.decl/dcl.init/p14-0x.cpp +++ b/clang/test/CXX/dcl.decl/dcl.init/p14-0x.cpp @@ -27,7 +27,7 @@ class Friend { class S { - NoDefault nd1; + NoDefault nd1; // expected-note {{default constructed field 'nd1' declared here}} NoDefault nd2 = 42; Explicit e1; // expected-note {{here}} Explicit e2 = 42; // expected-error {{no viable conversion}} diff --git a/clang/test/SemaCUDA/inherited-ctor.cu b/clang/test/SemaCUDA/inherited-ctor.cu index 8ac59e7b539f3..ef3938555b983 100644 --- a/clang/test/SemaCUDA/inherited-ctor.cu +++ b/clang/test/SemaCUDA/inherited-ctor.cu @@ -81,7 +81,7 @@ namespace DefaultCtorInvalid { }; struct C { - struct B b; + struct B b; // expected-note{{default constructed field 'b' declared here}} C() {} // expected-error{{call to implicitly-deleted default constructor of 'struct B'}} // expected-note@-6{{default constructor of 'B' is implicitly deleted because field 's' has a deleted default constructor}} // expected-note@-15{{'S' has been explicitly marked deleted here}}