https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86286

            Bug ID: 86286
           Summary: Could __attribute__ ((nothrow)) on a noexcept function
                    turn off EH codegen?
           Product: gcc
           Version: 9.0
            Status: UNCONFIRMED
          Severity: enhancement
          Priority: P3
         Component: c++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: redi at gcc dot gnu.org
  Target Milestone: ---

We generate ideal code for a noexcept function calling a noexcept function:

int f (int i) noexcept;
int foo (int i) noexcept { return f (i); }

_Z3fooi:
.LFB1:
        .cfi_startproc
        jmp     _Z1fi
        .cfi_endproc
.LFE0:


But when a noexcept function calls a non-noexcept function there is additional
code needed to call std::terminate if an exception occurs:


_Z3gooi:
.LFB1:
        .cfi_startproc
        .cfi_personality 0x3,__gxx_personality_v0
        .cfi_lsda 0x3,.LLSDA1
        jmp     _Z1gi
        .cfi_endproc
.LFE1:
        .globl  __gxx_personality_v0
        .section        .gcc_except_table,"a",@progbits
.LLSDA1:
        .byte   0xff
        .byte   0xff
        .byte   0x1
        .uleb128 .LLSDACSE1-.LLSDACSB1
.LLSDACSB1:
.LLSDACSE1:
        .text


If we know that the non-noexcept function definitely won't throw (e.g. because
we've explicitly checked its preconditions, or we just have additional
knowledge about the state of the program) we can eliminate that extra code with
a nothrow wrapper:

inline int g2 (int i) __attribute__((always_inline,nothrow));
inline int g2 (int i) { return g(i); }
int good (int i) noexcept { return g2 (i); }

_Z4goodi:
.LFB3:
        .cfi_startproc
        jmp     _Z1gi
        .cfi_endproc
.LFE3:

But this is awkward and doesn't scale. It's possible wrap the call in a lambda
using the attribute, but that's still awkward, and less readable:

int good (int i) noexcept {
  return [&]() __attribute__((nothrow)) { return g (i); }();
}


Would it be possible for the nothrow attribute to do that automatically when
placed on a noexcept function? i.e. instead of the g2 wrapper we'd just do:

int good (int i) noexcept __attribute__((nothrow));
int good (int i) noexcept { return g (i); }

I'd like this to declare a function that never throws (which 'noexcept'
guarantees), but also never needs to deal with exceptions coming from below it.


There could be code today which uses both noexcept and __attribute__
((nothrow)), maybe for pre-C++11 compatibility:

#ifdef __GNUC__
# define NOTHROW __attribute__((nothrow))
#endif
#if __cplusplus >= 201103L
# define NOEXCEPT noexcept
#else
# define NOEXCEPT
#endif

void f() NOEXCEPT NOTHROW;

If we're concerned about changing the behaviour of this code (from guaranteed
termination in C++11 and later if the function exits via an exception, to UB)
then maybe a new attribute would be better.

Reply via email to