Bug 92590 - [10 Regression] Cannot expose protected default constructor with "using" keyword in gcc 10
Summary: [10 Regression] Cannot expose protected default constructor with "using" keyw...
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 10.0
: P3 normal
Target Milestone: 10.0
Assignee: Jason Merrill
Keywords: rejects-valid
Depends on:
Reported: 2019-11-20 01:13 UTC by Pavel Roskin
Modified: 2020-01-15 19:15 UTC (History)
2 users (show)

See Also:
Known to work: 9.2.0
Known to fail:
Last reconfirmed: 2019-11-20 00:00:00


Note You need to log in before you can comment on or make changes to this bug.
Description Pavel Roskin 2019-11-20 01:13:34 UTC
This code fails to compile with the current gcc (commit d9be9f34fbb018c448dc5a02aaa95d6a6932135c)

class Base {

class Derived : public Base {
    using Base::Base;

Derived d;

test.ii:11:9: error: ‘Base::Base()’ is protected within this context
   11 | Derived d;
      |         ^
test.ii:3:5: note: declared protected here
    3 |     Base();
      |     ^~~~

The error is emitted for any standard from c++11 to c++2a. No optimization or other flags are needed.

The same code is compiled without any errors by gcc 9.2.1. Testing on godbolt.org shows that all other compilers accept it - all recent versions of clang, msvc, icc.

I don't see any relevant changes mentioned in the GCC 10 release notes https://gcc.gnu.org/gcc-10/changes.html

An inline implementation of the protected constructor fails too:

class Base {
    Base() {}

class Derived : public Base {
    using Base::Base;

Derived d;

However, the code compiles with the default constructor:

class Base {
    Base() = default;

class Derived : public Base {
    using Base::Base;

Derived d;
Comment 1 Jonathan Wakely 2019-11-20 08:34:04 UTC
Regressed with r276968:

            PR c++/91930 - ICE with constrained inherited default ctor.
    The testcase was crashing because lazily_declare_fn was failing to add a
    defaulted constructor, because the implicit declaration was less constrained
    than the inherited default constructor.  But when we have an inherited
    constructor, we shouldn't be trying to declare a default constructor in the
    first place, because it counts as "a user-declared constructor".  With that
    fixed I needed to adjust a couple of inherited constructor testcases that
    previously had been diagnosing the default constructor as deleted rather
    than not declared.
            * name-lookup.c (do_class_using_decl): Set TYPE_HAS_USER_CONSTRUCTOR
            for inherited constructor.
Comment 2 Jason Merrill 2020-01-14 18:31:38 UTC
This is a consequence of the change Jonathan cites, to treat the inherited constructor as a user-declared constructor that prevents the implicit declaration of a default constructor in Derived.

The difference in access behavior follows from this; the standard says,

"A synonym created by a using-declaration has the usual accessibility for a member-declaration. A using-declarator that names a constructor does not create a synonym; instead, the additional constructors are accessible if they would be accessible when used to construct an object of the corresponding base class, and the accessibility of the using-declaration is ignored."

So if constructing 'd' calls the inherited constructor, it's ill-formed; if it calls the implicitly-declared default constructor, it's well-formed.

I thought my change was an obvious bug fix, but it seems that other compilers have the old semantics, so I should probably undo it.
Comment 3 CVS Commits 2020-01-14 20:21:15 UTC
The master branch has been updated by Jason Merrill <jason@gcc.gnu.org>:


commit r10-5949-g08c8c973c082457a7d6192673e87475f1fdfdbef
Author: Jason Merrill <jason@redhat.com>
Date:   Tue Jan 14 13:59:54 2020 -0500

    PR c++/92590 - wrong handling of inherited default ctor.
    I thought my earlier fix for 91930 was an obvious bug fix, but apparently an
    inherited constructor does not count as user-declared.  So this patch
    reverts that change and the other follow-on patches, and fixes 91930
    differently, by not letting the inherited default constructor hide the
    implicitly-declared default constructor.
    	* class.c (add_method): A constrained inherited ctor doesn't hide an
    	implicit derived ctor.
    	PR c++/91930 - ICE with constrained inherited default ctor.
    	* name-lookup.c (do_class_using_decl): Set TYPE_HAS_USER_CONSTRUCTOR
    	for inherited constructor.
    	PR c++/92552 - ICE with inherited constrained default ctor.
    	* pt.c (instantiate_class_template_1): Copy
    	PR c++/92594 - ICE with inherited trivial default ctor.
    	* method.c (trivial_fn_p): Treat an inherited default constructor
    	like a normal default constructor.
Comment 4 Jason Merrill 2020-01-14 20:23:37 UTC
Comment 5 Pavel Roskin 2020-01-15 19:15:41 UTC
Confirming fix on the original code. Thank you!