From 1560cc94e8a6c309a74d0a1a24820087e149733b Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Mon, 18 Sep 2023 22:16:04 -0400 Subject: [PATCH] c++: inherited default constructor [CWG2799] In this testcase, it seems clear that B should be trivially default-constructible, since the inherited default constructor is trivial and there are no other subobjects to initialize. But we were saying no because we don't define triviality of inherited constructors. CWG discussion suggested that the solution is to implicitly declare a default constructor when inheriting a default constructor; that makes sense to me. DR 2799 gcc/cp/ChangeLog: * class.cc (add_implicit_default_ctor): Split out... (add_implicitly_declared_members): ...from here. Also call it when inheriting a default ctor. gcc/testsuite/ChangeLog: * g++.dg/cpp0x/inh-ctor38.C: New test. --- gcc/cp/class.cc | 36 ++++++++++++++++++++++----------- gcc/testsuite/g++.dg/cpp0x/inh-ctor38.C | 19 +++++++++++++++++ 2 files changed, 43 insertions(+), 12 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp0x/inh-ctor38.C diff --git a/gcc/cp/class.cc b/gcc/cp/class.cc index d270dcbb14c..469e98ed8b7 100644 --- a/gcc/cp/class.cc +++ b/gcc/cp/class.cc @@ -3292,6 +3292,22 @@ one_inherited_ctor (tree ctor, tree t, tree using_decl) } } +/* Implicitly declare T(). */ + +static void +add_implicit_default_ctor (tree t) +{ + TYPE_HAS_DEFAULT_CONSTRUCTOR (t) = 1; + CLASSTYPE_LAZY_DEFAULT_CTOR (t) = 1; + if (cxx_dialect >= cxx11) + TYPE_HAS_CONSTEXPR_CTOR (t) + /* Don't force the declaration to get a hard answer; if the + definition would have made the class non-literal, it will still be + non-literal because of the base or member in question, and that + gives a better diagnostic. */ + = type_maybe_constexpr_default_constructor (t); +} + /* Create default constructors, assignment operators, and so forth for the type indicated by T, if they are needed. CANT_HAVE_CONST_CTOR, and CANT_HAVE_CONST_ASSIGNMENT are nonzero if, for whatever reason, @@ -3320,17 +3336,7 @@ add_implicitly_declared_members (tree t, tree* access_decls, If there is no user-declared constructor for a class, a default constructor is implicitly declared. */ if (! TYPE_HAS_USER_CONSTRUCTOR (t)) - { - TYPE_HAS_DEFAULT_CONSTRUCTOR (t) = 1; - CLASSTYPE_LAZY_DEFAULT_CTOR (t) = 1; - if (cxx_dialect >= cxx11) - TYPE_HAS_CONSTEXPR_CTOR (t) - /* Don't force the declaration to get a hard answer; if the - definition would have made the class non-literal, it will still be - non-literal because of the base or member in question, and that - gives a better diagnostic. */ - = type_maybe_constexpr_default_constructor (t); - } + add_implicit_default_ctor (t); /* [class.ctor] @@ -3394,7 +3400,13 @@ add_implicitly_declared_members (tree t, tree* access_decls, location_t loc = input_location; input_location = DECL_SOURCE_LOCATION (using_decl); for (tree fn : ovl_range (ctor_list)) - one_inherited_ctor (fn, t, using_decl); + { + if (!TYPE_HAS_DEFAULT_CONSTRUCTOR (t) && default_ctor_p (fn)) + /* CWG2799: Inheriting a default constructor gives us a default + constructor, not just an inherited constructor. */ + add_implicit_default_ctor (t); + one_inherited_ctor (fn, t, using_decl); + } *access_decls = TREE_CHAIN (*access_decls); input_location = loc; } diff --git a/gcc/testsuite/g++.dg/cpp0x/inh-ctor38.C b/gcc/testsuite/g++.dg/cpp0x/inh-ctor38.C new file mode 100644 index 00000000000..56217be1aae --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/inh-ctor38.C @@ -0,0 +1,19 @@ +// CWG 2799 +// Test that inheriting a trivial default constructor produces a trivial +// default constructor. + +// { dg-do compile { target c++11 } } + +#include + +struct A { + A() = default; +}; + +struct B : A +{ + using A::A; + B(int); +}; + +static_assert (std::is_trivially_constructible::value, ""); -- 2.11.4.GIT