Question: Can the "main" function be declared with the "noexcept" specifier?

Question

Can the "main" function be declared with the "noexcept" specifier?

Answers 2
Added at 2017-11-30 23:11
Tags
Question

Is the following code valid in C++?

int main() noexcept
{
}

Both clang++ 3.8.0 and g++ 7.2.0 compile it fine (with -std=c++14 -O0 -Wall -Wextra -Werror -pedantic-errors compilation flags).

Is it allowed to use complex conditions (e.g. including noexcept operator) in the noexcept specification of the main function?

And what about C++17? As I know noexcept specifier becomes the part of the function type in this revision of the standard.

Answers to

Can the "main" function be declared with the "noexcept" specifier?

nr: #1 dodano: 2017-12-01 00:12

The standard [[basic.start.main]] specifies the following constraints on the main function:

An implementation shall allow both:

— a function of () returning int and

— a function of (int, pointer to pointer to char) returning int

Moreover:

A program that defines main as deleted or that declares main to be inline, static, or constexpr is ill-formed.

In practice, there is no specification about noexcept qualifier for main. On the other hands, noexcept is allowed as a specifier for whatever function. That would imply main noexcept is not ill-formed.


What's difference w/o noexcept main?

Since the standard is not very explicit about noexcept for main function as we've seen, we can try to deduct some behaviour and check the implementations.

From here:

Whenever an exception is thrown and the search for a handler encounters the outermost block of a non-throwing function, the function std::terminate is called.

While the general rule for exceptions, from here:

If an exception is thrown and not caught, including exceptions that escape the initial function of std::thread, the main function, and the constructor or destructor of any static or thread-local objects, then std::terminate is called. It is implementation-defined whether any stack unwinding takes place for uncaught exceptions.

This implies that throw from main function always generates a std::terminate invocation. Regardless of noexcept specification of the main.

Implementation side:

Indeed, the following codes:

int main(int argc, char* argvp[]) {
  throw 1;
  return 0;
}

and

int main(int argc, char* argvp[]) noexcept {
  throw 1;
  return 0;
}

will produce the same output assembly. For example in GCC:

main:
        movl    $4, %edi
        subq    $8, %rsp
        call    __cxa_allocate_exception
        xorl    %edx, %edx
        movl    $1, (%rax)
        movl    typeinfo for int, %esi
        movq    %rax, %rdi
        call    __cxa_throw

That means it will be resolved into an invocation of std::terminate because the stack frame is empty at "main level" regardless of noexcept specification.

nr: #2 dodano: 2017-12-01 19:12

The type of main in int main() noexcept; is "function of () returning int" in C++14 and "noexcept function of () returning int" in C++17.

The former is explicitly required to be supported by [basic.start.main]. The latter isn't.

This looks like a defect in C++17.

Source Show
◀ Wstecz