Repository: rust-lang/rust
File: compiler/rustc_codegen_ssa/src/mir/block.rs (Rust)

Code before:
                // This bitmask is a single `HT_IsStdDotDot` flag, which
                // represents that this is a C++-style `catch (...)` block that
                // only captures programmatic exceptions, not all SEH
                // exceptions. The second `null` points to a non-existent
                // `alloca` instruction, which an LLVM pass would inline into
                // the initial SEH frame allocation.
                let adjectives = bx.const_i32(0x40);
                &[null, adjectives, null] as &[_]
            } else {
                // Specifying more arguments than necessary usually doesn't
                // hurt, but the `WasmEHPrepare` LLVM pass does not recognize
                // anything other than a single `null` as a `catch (...)` block,
                // leading to problems down the line during instruction
                // selection.
                &[null] as &[_]
            };

            let cp = bx.catch_pad(cs, args);

            if base::wants_wasm_eh(self.cx.sess()) {
                // For Wasm, we need to call `@llvm.wasm.get.exception` and
                // `@llvm.wasm.get.ehselector` to tell LLVM's WasmEHPrepare pass
                // to generate a catch that only applies for C++ exceptions, not
                // to convert this to a cleanuppad and generate a `catch_all`
                bx.wasm_get_exception_and_selector(&cp);
            }

            funclet = Some(cp);
        } else {
            llbb = Bx::append_block(self.cx, self.llfn, "terminate");
            bx = Bx::build(self.cx, llbb);

            let llpersonality = self.cx.eh_personality();
            bx.filter_landing_pad(llpersonality);

            funclet = None;
        }

        self.set_debug_loc(&mut bx, mir::SourceInfo::outermost(self.mir.span));

        let (fn_abi, fn_ptr, instance) =
            common::build_langcall(&bx, self.mir.span, reason.lang_item());
        if is_call_from_compiler_builtins_to_upstream_monomorphization(bx.tcx(), instance) {
            bx.abort();
        } else {
            let fn_ty = bx.fn_decl_backend_type(fn_abi);

            let llret = bx.call(fn_ty, None, Some(fn_abi), fn_ptr, &[], funclet.as_ref(), None);
            bx.apply_attrs_to_cleanup_callsite(llret);
        }


Review comment (suggestion):
I think this actually should be a `catch_all`. We should handle all foreign unwinding the same, not just foreign unwinding caused by a C++ exception. On unix `catch_unwind` explicitly aborts on all foreign exceptions and drop impls run on all foreign exceptions. And longjmp through rust frames is UB.

Code after:
            //      try {
            //          foo();
            //      } catch (...) {
            //          bar();
            //      }
            //
            // which creates an IR snippet like
            //
            //      cs_terminate:
            //         %cs = catchswitch within none [%cp_terminate] unwind to caller
            //      cp_terminate:
            //         %cp = catchpad within %cs [null, i32 64, null]
            //         ...
            //
            // By contrast, on WebAssembly targets, we specifically _do_ want to
            // catch foreign exceptions. The situation with MSVC is a
            // regrettable hack which we don't want to extend to other targets
            // unless necessary. For WebAssembly, to generate catch(...) and
            // catch only C++ exception instead of generating a catch_all, we
            // need to call the intrinsics @llvm.wasm.get.exception and
            // @llvm.wasm.get.ehselector in the catch pad. Since we don't do
            // this, we generate a catch_all. We originally got this behavior
            // by accident but it luckily matches our intention.

            llbb = Bx::append_block(self.cx, self.llfn, "cs_terminate");

            let mut cs_bx = Bx::build(self.cx, llbb);

            // For wasm InCleanup blocks, our catch_switch is nested within the
            // outer catchpad, so we need to provide it as the parent value to
            // catch_switch.
            let mut outer_cleanuppad = None;
            if outer_catchpad_bb.is_some() {
                // Get the outer funclet's catchpad
                let outer_funclet = self.funclets[cache_bb]
                    .as_ref()
                    .expect("landing_pad_for didn't create funclet");
                outer_cleanuppad = Some(cs_bx.get_funclet_cleanuppad(outer_funclet));
            }
            let cp_llbb = Bx::append_block(self.cx, self.llfn, "cp_terminate");
            let cs = cs_bx.catch_switch(outer_cleanuppad, None, &[cp_llbb]);
            drop(cs_bx);

            bx = Bx::build(self.cx, cp_llbb);
            let null =
                bx.const_null(bx.type_ptr_ext(bx.cx().data_layout().instruction_address_space));

            // The `null` in first argument here is actually a RTTI type
            // descriptor for the C++ personality function, but `catch (...)`
            // has no type so it's null.
            let args = if base::wants_msvc_seh(self.cx.sess()) {