From f40f59eddd225824abceaaf601e1132cae6de681 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Tue, 22 Nov 2016 22:55:12 +0000 Subject: [PATCH] Make diagnostic for use of default member initializer before enclosing class is complete a little more general; it is produced in other cases than the one that it previously talked about. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@287713 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Basic/DiagnosticSemaKinds.td | 11 +++++----- lib/Sema/SemaDeclCXX.cpp | 11 +++------- lib/Sema/SemaTemplateInstantiate.cpp | 12 ++++------- test/SemaCXX/constant-expression-cxx11.cpp | 4 ++-- test/SemaCXX/cxx1y-initializer-aggregates.cpp | 16 +++++++++++++++ test/SemaCXX/implicit-exception-spec.cpp | 18 ++++++++--------- test/SemaCXX/member-init.cpp | 20 +++++++++---------- 7 files changed, 49 insertions(+), 43 deletions(-) diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 0b459110a8..9b81a553dc 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -7099,12 +7099,11 @@ def err_in_class_initializer_literal_type : Error< "'constexpr' specifier">; def err_in_class_initializer_non_constant : Error< "in-class initializer for static data member is not a constant expression">; -def err_in_class_initializer_not_yet_parsed - : Error<"cannot use defaulted default constructor of %0 within the class " - "outside of member functions because %1 has an initializer">; -def err_in_class_initializer_not_yet_parsed_outer_class - : Error<"cannot use defaulted default constructor of %0 within " - "%1 outside of member functions because %2 has an initializer">; +def err_in_class_initializer_not_yet_parsed : Error< + "default member initializer for %1 needed within definition of enclosing " + "class %0 outside of member functions">; +def note_in_class_initializer_not_yet_parsed : Note< + "default member initializer declared here">; def err_in_class_initializer_cycle : Error<"default member initializer for %0 uses itself">; def err_exception_spec_cycle diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 7d208a43ad..b036e0c0dc 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -12378,14 +12378,9 @@ ExprResult Sema::BuildCXXDefaultInitExpr(SourceLocation Loc, FieldDecl *Field) { // constructor before the initializer is lexically complete will ultimately // come here at which point we can diagnose it. RecordDecl *OutermostClass = ParentRD->getOuterLexicalRecordContext(); - if (OutermostClass == ParentRD) { - Diag(Field->getLocEnd(), diag::err_in_class_initializer_not_yet_parsed) - << ParentRD << Field; - } else { - Diag(Field->getLocEnd(), - diag::err_in_class_initializer_not_yet_parsed_outer_class) - << ParentRD << OutermostClass << Field; - } + Diag(Loc, diag::err_in_class_initializer_not_yet_parsed) + << OutermostClass << Field; + Diag(Field->getLocEnd(), diag::note_in_class_initializer_not_yet_parsed); return ExprError(); } diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index 96b45d17d1..321fd6995b 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -2198,14 +2198,10 @@ bool Sema::InstantiateInClassInitializer( if (!OldInit) { RecordDecl *PatternRD = Pattern->getParent(); RecordDecl *OutermostClass = PatternRD->getOuterLexicalRecordContext(); - if (OutermostClass == PatternRD) { - Diag(Pattern->getLocEnd(), diag::err_in_class_initializer_not_yet_parsed) - << PatternRD << Pattern; - } else { - Diag(Pattern->getLocEnd(), - diag::err_in_class_initializer_not_yet_parsed_outer_class) - << PatternRD << OutermostClass << Pattern; - } + Diag(PointOfInstantiation, + diag::err_in_class_initializer_not_yet_parsed) + << OutermostClass << Pattern; + Diag(Pattern->getLocEnd(), diag::note_in_class_initializer_not_yet_parsed); Instantiation->setInvalidDecl(); return true; } diff --git a/test/SemaCXX/constant-expression-cxx11.cpp b/test/SemaCXX/constant-expression-cxx11.cpp index 8524bed9e4..00bf5bd19b 100644 --- a/test/SemaCXX/constant-expression-cxx11.cpp +++ b/test/SemaCXX/constant-expression-cxx11.cpp @@ -1862,8 +1862,8 @@ namespace ZeroSizeTypes { namespace BadDefaultInit { template struct X { static const int n = N; }; - struct A { - int k = // expected-error {{cannot use defaulted default constructor of 'A' within the class outside of member functions because 'k' has an initializer}} + struct A { // expected-error {{default member initializer for 'k' needed within definition of enclosing class}} + int k = // expected-note {{default member initializer declared here}} X::n; // expected-error {{not a constant expression}} expected-note {{implicit default constructor for 'BadDefaultInit::A' first required here}} }; diff --git a/test/SemaCXX/cxx1y-initializer-aggregates.cpp b/test/SemaCXX/cxx1y-initializer-aggregates.cpp index 9b542403de..3d5e7726a1 100644 --- a/test/SemaCXX/cxx1y-initializer-aggregates.cpp +++ b/test/SemaCXX/cxx1y-initializer-aggregates.cpp @@ -61,3 +61,19 @@ namespace nested_aggregate_init { }; static_assert(B(6).f() == 18, ""); } + +namespace use_self { + struct FibTree { + int n; + FibTree *l = // expected-note {{declared here}} + n > 1 ? new FibTree{n-1} : &fib0; // expected-error {{default member initializer for 'l' needed}} + FibTree *r = // expected-note {{declared here}} + n > 2 ? new FibTree{n-2} : &fib0; // expected-error {{default member initializer for 'r' needed}} + int v = l->v + r->v; + + static FibTree fib0; + }; + FibTree FibTree::fib0{0, nullptr, nullptr, 1}; + + int fib(int n) { return FibTree{n}.v; } +} diff --git a/test/SemaCXX/implicit-exception-spec.cpp b/test/SemaCXX/implicit-exception-spec.cpp index ff3d685d91..12871b8ce7 100644 --- a/test/SemaCXX/implicit-exception-spec.cpp +++ b/test/SemaCXX/implicit-exception-spec.cpp @@ -16,31 +16,31 @@ namespace InClassInitializers { // Noexcept::Noexcept is not declared constexpr, therefore noexcept(Noexcept()) // is false. bool ThrowSomething() noexcept(false); - struct ConstExpr { - bool b = noexcept(ConstExpr()) && ThrowSomething(); // expected-error {{cannot use defaulted default constructor of 'ConstExpr' within the class outside of member functions}} + struct ConstExpr { // expected-error {{default member initializer for 'b' needed}} + bool b = noexcept(ConstExpr()) && ThrowSomething(); // expected-note {{declared here}} // expected-note@-1 {{implicit default constructor for 'InClassInitializers::ConstExpr' first required here}} }; // Much more obviously broken: we can't parse the initializer without already // knowing whether it produces a noexcept expression. - struct TemplateArg { - int n = ExceptionIf::f(); // expected-error {{cannot use defaulted default constructor of 'TemplateArg' within the class outside of member functions}} + struct TemplateArg { // expected-error {{default member initializer for 'n' needed}} + int n = ExceptionIf::f(); // expected-note {{declared here}} // expected-note@-1 {{implicit default constructor for 'InClassInitializers::TemplateArg' first required here}} }; // And within a nested class. struct Nested { // expected-note {{implicit default constructor for 'InClassInitializers::Nested::Inner' first required here}} - struct Inner { - // expected-error@+1 {{cannot use defaulted default constructor of 'Inner' within 'Nested' outside of member functions}} - int n = ExceptionIf::f(); // expected-note {{implicit default constructor for 'InClassInitializers::Nested' first required here}} + struct Inner { // expected-error {{default member initializer for 'n' needed}} + int n = // expected-note {{declared here}} + ExceptionIf::f(); // expected-note {{implicit default constructor for 'InClassInitializers::Nested' first required here}} } inner; }; struct Nested2 { // expected-error {{implicit default constructor for 'InClassInitializers::Nested2' must explicitly initialize the member 'inner' which does not have a default constructor}} struct Inner; int n = Inner().n; // expected-note {{implicit default constructor for 'InClassInitializers::Nested2::Inner' first required here}} - struct Inner { // expected-note {{declared here}} - // expected-error@+1 {{cannot use defaulted default constructor of 'Inner' within 'Nested2' outside of member functions}} + struct Inner { // expected-error {{initializer for 'n' needed}} expected-note {{declared here}} + // expected-note@+1 {{declared here}} int n = ExceptionIf::f(); // expected-note@-1 {{implicit default constructor for 'InClassInitializers::Nested2' first required here}} } inner; // expected-note {{member is declared here}} diff --git a/test/SemaCXX/member-init.cpp b/test/SemaCXX/member-init.cpp index 65c8873117..836c1f7455 100644 --- a/test/SemaCXX/member-init.cpp +++ b/test/SemaCXX/member-init.cpp @@ -13,8 +13,8 @@ public: bool b(); int k; -struct Recurse { - int &n = // expected-error {{cannot use defaulted default constructor of 'Recurse' within the class outside of member functions because 'n' has an initializer}} +struct Recurse { // expected-error {{initializer for 'n' needed}} + int &n = // expected-note {{declared here}} b() ? Recurse().n : // expected-note {{implicit default constructor for 'Recurse' first required here}} k; @@ -128,8 +128,8 @@ A::A() {} namespace template_default_ctor { struct A { template - struct B { - int m1 = 0; // expected-error {{cannot use defaulted default constructor of 'B' within 'A' outside of member functions because 'm1' has an initializer}} + struct B { // expected-error {{initializer for 'm1' needed}} + int m1 = 0; // expected-note {{declared here}} }; // expected-note@+1 {{implicit default constructor for 'template_default_ctor::A::B' first required here}} enum { NOE = noexcept(B()) }; @@ -138,8 +138,8 @@ struct A { namespace default_ctor { struct A { - struct B { - int m1 = 0; // expected-error {{cannot use defaulted default constructor of 'B' within 'A' outside of member functions because 'm1' has an initializer}} + struct B { // expected-error {{initializer for 'm1' needed}} + int m1 = 0; // expected-note {{declared here}} }; // expected-note@+1 {{implicit default constructor for 'default_ctor::A::B' first required here}} enum { NOE = noexcept(B()) }; @@ -150,12 +150,12 @@ namespace member_template { struct A { template struct B { - struct C { - int m1 = 0; // expected-error {{cannot use defaulted default constructor of 'C' within 'A' outside of member functions because 'm1' has an initializer}} + struct C { // expected-error {{initializer for 'm1' needed}} + int m1 = 0; // expected-note {{declared here}} }; template - struct D { - int m1 = 0; // expected-error {{cannot use defaulted default constructor of 'D' within 'A' outside of member functions because 'm1' has an initializer}} + struct D { // expected-error {{initializer for 'm1' needed}} + int m1 = 0; // expected-note {{declared here}} }; }; enum { -- 2.40.0