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

            Bug ID: 109267
           Summary: -Og generates empty functions with
                    .cfi_startproc/.cfi_endproc that conflict with other
                    functions
           Product: gcc
           Version: unknown
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: i at maskray dot me
  Target Milestone: ---

cat > lib.cpp <<'eof'
#include "lib.h"
#include <stdexcept>

void test(const T_value& entry_value) {
    boost::apply_visitor([](const auto& value) { test(value); },
                         entry_value);
}
void test(const Obj_1& ) {
    throw std::runtime_error("Obj_1");
}
void test(const Obj_2& ) {
    throw std::runtime_error("Obj_2");
}
eof
cat > lib.h <<'eof'
#pragma once

#include <boost/variant.hpp>

struct Obj_1 {
  int i;
};
struct Obj_2 {
  int i;
};

using T_value = boost::make_recursive_variant<
        Obj_1,
        Obj_2>::type;
void test(const T_value&);
void test(const Obj_2&);
void test(const Obj_1&);
eof
cat > main.cpp <<'eof'
#include "lib.h"
#include <stdexcept>

int main() {
    try {
        test(Obj_2{2});

    } catch (const std::runtime_error& e) {
    }
    try {
        test(Obj_1{1});

    } catch (const std::runtime_error& e) {
    }
} 
eof

g++ -isystem /usr/include/boost -Og -g -DNDEBUG -S lib.cpp main.cpp
g++ -isystem /usr/include/boost -Og -g -DNDEBUG -fuse-ld=lld lib.cpp main.cpp
return

lib.s has unusual empty functions with .cfi_startproc/.cfi_endproc . I think
this behavior is incorrect since CFI FDE associated to the empty functions may
conflict with FDE of another function.
When linking with GNU ld, GNU ld drops FDE associated to the empty functions,
and therefore the output executable will be correct.
However, I think linkers are not obliged to behave like GNU ld. ld.lld doesn't
discard FDE associated to the empty functions, and the output executable will
call std::terminate.

```
% ./a.out
terminate called after throwing an instance of 'std::runtime_error'
  what():  Obj_1
[1]    2826366 IOT instruction  ./a.out
```

-O1/-O2/-O3 discard such empty functions to avoid the problem. In -O0 codegen,
the function becomes non-empty, avoiding the problem as well.

```
% g++ -isystem /usr/include/boost -Og -g -DNDEBUG -S lib.cpp -o - | grep
11result_typeEiRSD_T0_PNS1_22apply_visitor_unrolledET1_l
        .type  
_ZN5boost6detail7variant22visitation_impl_invokeINS1_14invoke_visitorINS1_15result_wrapper1IZ4testRKNS_7variantINS1_14recursive_flagI5Obj_1EEJ5Obj_2EEEEUlRKT_E_SC_EELb0EEEPKvNSA_18has_fallback_type_EEENSD_11result_typeEiRSD_T0_PNS1_22apply_visitor_unrolledET1_l,
@function
_ZN5boost6detail7variant22visitation_impl_invokeINS1_14invoke_visitorINS1_15result_wrapper1IZ4testRKNS_7variantINS1_14recursive_flagI5Obj_1EEJ5Obj_2EEEEUlRKT_E_SC_EELb0EEEPKvNSA_18has_fallback_type_EEENSD_11result_typeEiRSD_T0_PNS1_22apply_visitor_unrolledET1_l:
        .size  
_ZN5boost6detail7variant22visitation_impl_invokeINS1_14invoke_visitorINS1_15result_wrapper1IZ4testRKNS_7variantINS1_14recursive_flagI5Obj_1EEJ5Obj_2EEEEUlRKT_E_SC_EELb0EEEPKvNSA_18has_fallback_type_EEENSD_11result_typeEiRSD_T0_PNS1_22apply_visitor_unrolledET1_l,
.-_ZN5boost6detail7variant22visitation_impl_invokeINS1_14invoke_visitorINS1_15result_wrapper1IZ4testRKNS_7variantINS1_14recursive_flagI5Obj_1EEJ5Obj_2EEEEUlRKT_E_SC_EELb0EEEPKvNSA_18has_fallback_type_EEENSD_11result_typeEiRSD_T0_PNS1_22apply_visitor_unrolledET1_l
% g++ -isystem /usr/include/boost -O1 -g -DNDEBUG -S lib.cpp -o - | grep
11result_typeEiRSD_T0_PNS1_22apply_visitor_unrolledET1_l
% g++ -isystem /usr/include/boost -O2 -g -DNDEBUG -S lib.cpp -o - | grep
11result_typeEiRSD_T0_PNS1_22apply_visitor_unrolledET1_l
% g++ -isystem /usr/include/boost -O3 -g -DNDEBUG -S lib.cpp -o - | grep
11result_typeEiRSD_T0_PNS1_22apply_visitor_unrolledET1_l
```

Link: https://github.com/llvm/llvm-project/issues/61434

Reply via email to