Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

noexcept, inheriting constructors and the invalid use of an incomplete type that is actually complete

I'm not sure if it's a bug of the GCC compiler or the intended behavior of noexcept.
Consider the following example:

struct B {
    B(int) noexcept { }
    virtual void f() = 0;
};

struct D: public B {
    using B::B;
    D() noexcept(noexcept(D{42})): B{42} { }
    void f() override { }
};

int main() {
    B *b = new D{};
}

If the noexcept is removed, it compiles.
Anyway, as it is in the example, I got this error from GCC v5.3.1:

test.cpp:8:31: error: invalid use of incomplete type ‘struct D’
     D() noexcept(noexcept(D{42})): B{42} { }
                               ^

As far as I know, struct D is not an incomplete type, but inheriting constructors are involved in the statement and it looks like the compiler is actually considering the completeness of the base struct B more than of D.

Is that the intended behavior or is it legal code?

For the sake of clarity:

  • here the compilation succeeds using clang 3.7.1
  • here the compilation fails using GCC 5.3.0

See this link to the bugzilla for the GCC compiler for further details.
Currently, the bug is still unconfirmed. I'll update the question as soon as possible.

like image 737
skypjack Avatar asked Mar 04 '16 07:03

skypjack


People also ask

What is the use of Noexcept in C++?

The noexcept operator performs a compile-time check that returns true if an expression is declared to not throw any exceptions. It can be used within a function template's noexcept specifier to declare that the function will throw exceptions for some types but not others.

Can a constructor be Noexcept?

Using noexcept in the big four (constructors, assignment, not destructors as they're already noexcept ) will likely cause the best improvements as noexcept checks are 'common' in template code such as in std containers.

What does Noexcept false do?

In contrast, noexcept(false) means that the function may throw an exception. The noexcept specification is part of the function type but can not be used for function overloading. There are two good reasons for the use of noexcept: First, an exception specifier documents the behaviour of the function.

Is Noexcept required?

Explicit instantiations may use the noexcept specifier, but it is not required. If used, the exception specification must be the same as for all other declarations.


1 Answers

Your code is legal, even though GCC claims otherwise. It takes offense at this funny-looking declaration:

D() noexcept(noexcept(D{42}));

The outermost noexcept is a noexcept specifier, stating that D::D() is noexcept if and only if its constant-expression argument evaluates to true. The inner noexcept is a noexcept operator that checks at compile time whether its argument expression, which is not actually evaluated, throws no exceptions. Because D::D(int) is noexcept (inherited from B), this should be true.

cppreference.com explicitly notes that using the operator inside the specifier is allowed (emphasis added):

The noexcept operator performs a compile-time check that returns true if an expression is declared to not throw any exceptions.

It can be used within a function template's noexcept specifier to declare that the function will throw exceptions for some types but not others.

Now, the class should be considered complete within the noexcept specifier due to §9.2.2 of the Standard (bold emphasis added):

A class is considered a completely-defined object type (3.9) (or complete type) at the closing } of the class-specifier. Within the class member-specification, the class is regarded as complete within function bodies, default arguments, using-declarations introducing inheriting constructors (12.9), exception-specifications, and brace-or-equal-initializers for non-static data members (including such things in nested classes). Otherwise it is regarded as incomplete within its own class member-specification.

§15.4.1 defines an exception-specification as the following grammar:

exception-specification:

  • dynamic-exception-specification

  • noexcept-specification

So GCC should not reject your code.

like image 67
George Hilliard Avatar answered Nov 15 '22 08:11

George Hilliard