From bef59cd1388b05c11433d61e6634a0bf1fac6132 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Thu, 28 May 2026 13:46:59 +0200 Subject: [PATCH 1/6] Use weak linkage (otherwise we can't compile .so files with eiis in them) --- compiler/rustc_codegen_llvm/src/mono_item.rs | 5 ++++- compiler/rustc_codegen_ssa/src/codegen_attrs.rs | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/mono_item.rs b/compiler/rustc_codegen_llvm/src/mono_item.rs index 2c0a6ff01018c..b746bab643a34 100644 --- a/compiler/rustc_codegen_llvm/src/mono_item.rs +++ b/compiler/rustc_codegen_llvm/src/mono_item.rs @@ -169,7 +169,10 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { ) { for (alias, linkage, visibility) in aliases { let symbol_name = self.tcx.symbol_name(Instance::mono(self.tcx, *alias)); - tracing::debug!("FUNCTION ALIAS: {alias:?} {linkage:?} {visibility:?}"); + tracing::debug!( + "FUNCTION ALIAS: generating fn {} that calls {aliasee_instance:?} ({alias:?} {linkage:?} {visibility:?})", + symbol_name.name + ); // predefine another copy of the original instance // with a new symbol name diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index b4626724fd803..d1d6499ac2d45 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -259,7 +259,7 @@ fn process_builtin_attrs( codegen_fn_attrs.foreign_item_symbol_aliases.push(( foreign_item, - if i.is_default { Linkage::LinkOnceAny } else { Linkage::External }, + if i.is_default { Linkage::WeakAny } else { Linkage::External }, Visibility::Default, )); codegen_fn_attrs.flags |= CodegenFnAttrFlags::EXTERNALLY_IMPLEMENTABLE_ITEM; From 125149453ce0beef86d1fa856abc6a45475f22f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Mon, 1 Jun 2026 14:09:30 +0200 Subject: [PATCH 2/6] disallow most attrs on eiis --- compiler/rustc_builtin_macros/src/eii.rs | 75 ++++++++++++++----- compiler/rustc_builtin_macros/src/errors.rs | 9 +++ ...ice_contract_attr_on_eii_generated_item.rs | 11 --- ...contract_attr_on_eii_generated_item.stderr | 14 ---- 4 files changed, 66 insertions(+), 43 deletions(-) delete mode 100644 tests/ui/eii/ice_contract_attr_on_eii_generated_item.rs delete mode 100644 tests/ui/eii/ice_contract_attr_on_eii_generated_item.stderr diff --git a/compiler/rustc_builtin_macros/src/eii.rs b/compiler/rustc_builtin_macros/src/eii.rs index fd0ef8500c6c3..d8d749cd35c4b 100644 --- a/compiler/rustc_builtin_macros/src/eii.rs +++ b/compiler/rustc_builtin_macros/src/eii.rs @@ -10,10 +10,10 @@ use rustc_span::{ErrorGuaranteed, Ident, Span, kw, sym}; use thin_vec::{ThinVec, thin_vec}; use crate::errors::{ - EiiExternTargetExpectedList, EiiExternTargetExpectedMacro, EiiExternTargetExpectedUnsafe, - EiiMacroExpectedMaxOneArgument, EiiOnlyOnce, EiiSharedMacroInStatementPosition, - EiiSharedMacroTarget, EiiStaticArgumentRequired, EiiStaticDefault, - EiiStaticMultipleImplementations, EiiStaticMutable, + EiiAttributeNotSupported, EiiExternTargetExpectedList, EiiExternTargetExpectedMacro, + EiiExternTargetExpectedUnsafe, EiiMacroExpectedMaxOneArgument, EiiOnlyOnce, + EiiSharedMacroInStatementPosition, EiiSharedMacroTarget, EiiStaticArgumentRequired, + EiiStaticDefault, EiiStaticMultipleImplementations, EiiStaticMutable, }; /// ```rust @@ -128,6 +128,8 @@ fn eii_( let attrs_from_decl = filter_attrs_for_multiple_eii_attr(ecx, attrs, eii_attr_span, &meta_item.path); + let (macro_attrs, foreign_item_attrs, default_func_attrs) = + split_attrs(ecx, item_span, attrs_from_decl); let Ok(macro_name) = name_for_impl_macro(ecx, foreign_item_name, &meta_item) else { // we don't need to wrap in Annotatable::Stmt conditionally since @@ -148,6 +150,7 @@ fn eii_( eii_attr_span, item_span, foreign_item_name, + default_func_attrs, )) } @@ -157,7 +160,7 @@ fn eii_( item_span, kind, vis, - &attrs_from_decl, + foreign_item_attrs, )); module_items.push(generate_attribute_macro_to_implement( ecx, @@ -165,7 +168,7 @@ fn eii_( macro_name, foreign_item_name, impl_unsafe, - &attrs_from_decl, + macro_attrs, )); // we don't need to wrap in Annotatable::Stmt conditionally since @@ -173,6 +176,49 @@ fn eii_( module_items.into_iter().map(Annotatable::Item).collect() } +fn split_attrs( + ecx: &mut ExtCtxt<'_>, + span: Span, + attrs: ThinVec, +) -> (ThinVec, ThinVec, ThinVec) { + let mut macro_attributes = ThinVec::new(); + let mut foreign_item_attributes = ThinVec::new(); + let mut default_attributes = ThinVec::new(); + + for attr in attrs { + match attr.name() { + // Inline only matters for the default function being inlined into callsites + Some(sym::inline) => default_attributes.push(attr), + // If an eii is marked a lang item, that's because we want to call its declaration, so + // mark the foreign item as the lang item + Some(sym::lang) => foreign_item_attributes.push(attr), + // Deprecating an eii means deprecating the macro and the foreign item + Some(sym::deprecated) => { + foreign_item_attributes.push(attr.clone()); + macro_attributes.push(attr); + } + // The stability of an EII affects the usage of the macro and calling the foreign item + Some(sym::stable) | Some(sym::unstable) => { + foreign_item_attributes.push(attr.clone()); + macro_attributes.push(attr); + } + // Doc attributes should be forwarded to the macro and the foreign item, since those are + // the two items you interact with as a user. + // FIXME: idk yet how EIIs show up in docs, might want to customize + _ if attr.is_doc_comment() => { + foreign_item_attributes.push(attr.clone()); + macro_attributes.push(attr); + } + Some(sym::eii) => unreachable!("should already be filtered out"), + _ => { + ecx.dcx().emit_err(EiiAttributeNotSupported { span, attr_span: attr.span() }); + } + } + } + + (macro_attributes, foreign_item_attributes, default_attributes) +} + /// Decide on the name of the macro that can be used to implement the EII. /// This is either an explicitly given name, or the name of the item in the /// declaration of the EII. @@ -228,10 +274,8 @@ fn generate_default_func_impl( eii_attr_span: Span, item_span: Span, foreign_item_name: Ident, + attrs: ThinVec, ) -> Box { - // FIXME: re-add some original attrs - let attrs = ThinVec::new(); - let mut default_func = func.clone(); default_func.eii_impls.push(EiiImpl { node_id: DUMMY_NODE_ID, @@ -289,10 +333,9 @@ fn generate_foreign_item( item_span: Span, item_kind: &ItemKind, vis: Visibility, - attrs_from_decl: &[Attribute], + attrs_from_decl: ThinVec, ) -> Box { - let mut foreign_item_attrs = ThinVec::new(); - foreign_item_attrs.extend_from_slice(attrs_from_decl); + let mut foreign_item_attrs = attrs_from_decl; // Add the rustc_eii_foreign_item on the foreign item. Usually, foreign items are mangled. // This attribute makes sure that we later know that this foreign item's symbol should not be. @@ -381,13 +424,9 @@ fn generate_attribute_macro_to_implement( macro_name: Ident, foreign_item_name: Ident, impl_unsafe: bool, - attrs_from_decl: &[Attribute], + attrs_from_decl: ThinVec, ) -> Box { - let mut macro_attrs = ThinVec::new(); - - // To avoid e.g. `error: attribute macro has missing stability attribute` - // errors for eii's in std. - macro_attrs.extend_from_slice(attrs_from_decl); + let mut macro_attrs = attrs_from_decl; // Avoid "missing stability attribute" errors for eiis in std. See #146993. macro_attrs.push(ecx.attr_name_value_str(sym::rustc_macro_transparency, sym::semiopaque, span)); diff --git a/compiler/rustc_builtin_macros/src/errors.rs b/compiler/rustc_builtin_macros/src/errors.rs index c64d6871269a6..929c88402b1aa 100644 --- a/compiler/rustc_builtin_macros/src/errors.rs +++ b/compiler/rustc_builtin_macros/src/errors.rs @@ -1186,6 +1186,15 @@ pub(crate) struct EiiMacroExpectedMaxOneArgument { pub name: String, } +#[derive(Diagnostic)] +#[diag("only a small subset of attributes are supported on externally implementable items")] +pub(crate) struct EiiAttributeNotSupported { + #[primary_span] + pub span: Span, + #[note("this attribute is not supported")] + pub attr_span: Span, +} + #[derive(Diagnostic)] #[diag("named argument `{$named_arg_name}` is not used by name")] pub(crate) struct NamedArgumentUsedPositionally { diff --git a/tests/ui/eii/ice_contract_attr_on_eii_generated_item.rs b/tests/ui/eii/ice_contract_attr_on_eii_generated_item.rs deleted file mode 100644 index fce142f6dc08b..0000000000000 --- a/tests/ui/eii/ice_contract_attr_on_eii_generated_item.rs +++ /dev/null @@ -1,11 +0,0 @@ -//@ compile-flags: --crate-type rlib - -#![feature(extern_item_impls)] -#![feature(contracts)] -#![allow(incomplete_features)] - -#[eii] -#[core::contracts::ensures] -//~^ ERROR contract annotations is only supported in functions with bodies -//~| ERROR contract annotations can only be used on functions -fn implementation(); diff --git a/tests/ui/eii/ice_contract_attr_on_eii_generated_item.stderr b/tests/ui/eii/ice_contract_attr_on_eii_generated_item.stderr deleted file mode 100644 index 3335346e55eec..0000000000000 --- a/tests/ui/eii/ice_contract_attr_on_eii_generated_item.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error: contract annotations is only supported in functions with bodies - --> $DIR/ice_contract_attr_on_eii_generated_item.rs:8:1 - | -LL | #[core::contracts::ensures] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: contract annotations can only be used on functions - --> $DIR/ice_contract_attr_on_eii_generated_item.rs:8:1 - | -LL | #[core::contracts::ensures] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 2 previous errors - From a492d4f8e2f10e19b4af2fb75d4c3059e06d0630 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Tue, 2 Jun 2026 16:25:33 +0200 Subject: [PATCH 3/6] add test for attrs on eiis --- tests/ui/eii/attrs.rs | 22 ++++++++++++++++++++++ tests/ui/eii/attrs.stderr | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+) create mode 100644 tests/ui/eii/attrs.rs create mode 100644 tests/ui/eii/attrs.stderr diff --git a/tests/ui/eii/attrs.rs b/tests/ui/eii/attrs.rs new file mode 100644 index 0000000000000..ec6259863e9b0 --- /dev/null +++ b/tests/ui/eii/attrs.rs @@ -0,0 +1,22 @@ +#![feature(extern_item_impls)] +#![deny(deprecated)] //~ NOTE: + +// makes no sense on functions, nor on the macro generated (it's a macrov2). +#[macro_export] //~ NOTE: this attribute is not supported +// makes sense, as long as we only forward it onto the function, +// so we allow and this shouln't cause errors for being on a "wrong target". +#[inline] +// makes sense, should be allowed, and forwarded on both the function and the macro +#[deprecated = "foo"] +#[eii] +fn example() {} +//~^ ERROR only a small subset of attributes are supported on externally implementable items + +// check that both are deprecated vvvv +#[example] +//~^ ERROR use of deprecated macro +fn explicit_impl() {} +fn main() { + example() + //~^ ERROR use of deprecated function +} diff --git a/tests/ui/eii/attrs.stderr b/tests/ui/eii/attrs.stderr new file mode 100644 index 0000000000000..a8d7cbbee1828 --- /dev/null +++ b/tests/ui/eii/attrs.stderr @@ -0,0 +1,32 @@ +error: only a small subset of attributes are supported on externally implementable items + --> $DIR/attrs.rs:12:1 + | +LL | fn example() {} + | ^^^^^^^^^^^^ + | +note: this attribute is not supported + --> $DIR/attrs.rs:5:1 + | +LL | #[macro_export] + | ^^^^^^^^^^^^^^^ + +error: use of deprecated macro `example`: foo + --> $DIR/attrs.rs:16:3 + | +LL | #[example] + | ^^^^^^^ + | +note: the lint level is defined here + --> $DIR/attrs.rs:2:9 + | +LL | #![deny(deprecated)] + | ^^^^^^^^^^ + +error: use of deprecated function `example`: foo + --> $DIR/attrs.rs:20:5 + | +LL | example() + | ^^^^^^^ + +error: aborting due to 3 previous errors + From c5676dc0b6819cc61a26e8633373d8ce5b5f44ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Sat, 30 May 2026 18:32:05 +0200 Subject: [PATCH 4/6] introduce eii into std --- library/core/src/lib.rs | 1 + library/core/src/panic.rs | 33 ++++++++++++++++++++++++++++++++- 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index acc758a75e77b..c7876d32c85a4 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -172,6 +172,7 @@ #![feature(uint_carryless_mul)] #![feature(unboxed_closures)] #![feature(unsized_fn_params)] +#![feature(extern_item_impls)] #![feature(with_negative_coherence)] // tidy-alphabetical-end // diff --git a/library/core/src/panic.rs b/library/core/src/panic.rs index cf07504466808..f5cabebd2de1d 100644 --- a/library/core/src/panic.rs +++ b/library/core/src/panic.rs @@ -14,7 +14,7 @@ pub use self::panic_info::PanicInfo; pub use self::panic_info::PanicMessage; #[stable(feature = "catch_unwind", since = "1.9.0")] pub use self::unwind_safe::{AssertUnwindSafe, RefUnwindSafe, UnwindSafe}; -use crate::any::Any; +use crate::{any::Any, fmt}; #[doc(hidden)] #[unstable(feature = "edition_panic", issue = "none", reason = "use panic!() instead")] @@ -199,3 +199,34 @@ pub macro const_assert { } }} } + +// HACK: currently it's hard to make foreign items lang items, +// this lang item is a function instead that serves as a proxy for the foreign item. +#[lang = "recover_overflow"] +#[doc(hidden)] +#[unstable(feature = "recoverable_integer_overflow_internals", issue = "none")] +pub fn call_recover_overflow_handler() { + recoverable_integer_overflow_handler(); +} + +/// Called on overflow when `-Coverflow-checks=recoverable` is set. +/// +/// Panics by default, mirroring `-Coverflow-checks=checked`, but can be overridden not to panic: +/// +/// ``` +/// #![feature(recoverable_integer_overflow)] +/// +/// use core::sync::atomic::{AtomicUsize, Ordering}; +/// +/// static COUNT_OVERFLOWS: AtomicUsize = AtomicUsize::new(0); +/// +/// #[core::panic::integer_overflow_action] +/// fn count_integer_overflows(_fmt: fmt::Arguments<'_>) { +/// COUNT_OVERFLOWS.fetch_add(1, Ordering::Relaxed); +/// } +/// ``` +#[eii(integer_overflow_action)] +#[unstable(feature = "recoverable_integer_overflow", issue = "none")] +fn recoverable_integer_overflow_handler() { + crate::panicking::panic_fmt(format_args!("integer overflow")); +} From 12f61bae9d9adb6406bb85826f666f95ddb80872 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Thu, 28 May 2026 13:46:59 +0200 Subject: [PATCH 5/6] codegen a call to the recovery eii --- compiler/rustc_hir/src/lang_items.rs | 2 + compiler/rustc_mir_build/src/builder/scope.rs | 52 ++++++++++++++++++- .../src/unstable/convert/stable/mir.rs | 4 +- compiler/rustc_span/src/symbol.rs | 1 + library/core/src/panic.rs | 2 +- 5 files changed, 56 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index 4a3615e5421fe..cbc8913b6d67e 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -448,6 +448,8 @@ language_item_table! { // Used to fallback `{float}` to `f32` when `f32: From<{float}>` From, sym::From, from_trait, Target::Trait, GenericRequirement::Exact(1); + + RecoverOverflow, sym::recover_overflow, recover_integer_overflow, Target::Fn, GenericRequirement::Exact(0); } /// The requirement imposed on the generics of a lang item diff --git a/compiler/rustc_mir_build/src/builder/scope.rs b/compiler/rustc_mir_build/src/builder/scope.rs index ff26b434db5cc..89fd0e5967a2d 100644 --- a/compiler/rustc_mir_build/src/builder/scope.rs +++ b/compiler/rustc_mir_build/src/builder/scope.rs @@ -85,7 +85,7 @@ use std::mem; use interpret::ErrorHandled; use rustc_data_structures::fx::FxHashMap; -use rustc_hir::HirId; +use rustc_hir::{HirId, LangItem}; use rustc_index::{IndexSlice, IndexVec}; use rustc_middle::middle::region; use rustc_middle::mir::{self, *}; @@ -1794,11 +1794,59 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ) -> BasicBlock { match self.check_overflow { CheckOverflow::Checked => self.assert(block, cond, expected, msg, span), - CheckOverflow::Recoverable => todo!(), + CheckOverflow::Recoverable => { + self.recoverable_overflow_check(block, cond, expected, msg, span) + } CheckOverflow::Ignore => unreachable!(), } } + pub(crate) fn recoverable_overflow_check( + &mut self, + block: BasicBlock, + cond: Operand<'tcx>, + expected: bool, + msg: AssertMessage<'tcx>, + span: Span, + ) -> BasicBlock { + assert!( + msg.is_optional_overflow_check(), + "recoverable_overflow_check should only be called with an overflow-related assertion" + ); + + let source_info = self.source_info(span); + + let no_overflow_block = self.cfg.start_new_block(); + let overflow_block = self.cfg.start_new_block(); + + self.cfg.terminate( + block, + source_info, + TerminatorKind::if_(cond, overflow_block, no_overflow_block), + ); + + let recovery_lang_item_def_id = self.tcx.require_lang_item(LangItem::RecoverOverflow, span); + let func = Operand::function_handle(self.tcx, recovery_lang_item_def_id, [], span); + let destination = self.get_unit_temp(); + + self.cfg.terminate( + overflow_block, + source_info, + TerminatorKind::Call { + func, + args: Box::new([]), + destination, + // if this function returns, continue as if no overflow happend! + target: Some(no_overflow_block), + unwind: UnwindAction::Continue, + call_source: CallSource::Misc, + fn_span: span, + }, + ); + + no_overflow_block + } + /// Unschedules any drops in the top two scopes. /// /// This is only needed for pattern-matches combining guards and or-patterns: or-patterns lead diff --git a/compiler/rustc_public/src/unstable/convert/stable/mir.rs b/compiler/rustc_public/src/unstable/convert/stable/mir.rs index 7e76d5a91ac66..17086fe9d7314 100644 --- a/compiler/rustc_public/src/unstable/convert/stable/mir.rs +++ b/compiler/rustc_public/src/unstable/convert/stable/mir.rs @@ -3,14 +3,14 @@ use rustc_middle::mono::MonoItem; use rustc_middle::{bug, mir}; use rustc_public_bridge::context::CompilerCtxt; -use rustc_public_bridge::{Tables, bridge}; +use rustc_public_bridge::{bridge, Tables}; use crate::compiler_interface::BridgeTys; use crate::mir::alloc::GlobalAlloc; use crate::mir::{ConstOperand, Statement, UserTypeProjection, VarDebugInfoFragment}; use crate::ty::{Allocation, ConstantKind, MirConst}; use crate::unstable::Stable; -use crate::{Error, alloc, opaque}; +use crate::{alloc, opaque, Error}; impl<'tcx> Stable<'tcx> for mir::Body<'tcx> { type T = crate::mir::Body; diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index d220651fc9404..8e6ede6cd3f6e 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1627,6 +1627,7 @@ symbols! { reborrow, receiver, receiver_target, + recover_overflow, recursion_limit, reexport_test_harness_main, ref_pat_eat_one_layer_2024, diff --git a/library/core/src/panic.rs b/library/core/src/panic.rs index f5cabebd2de1d..842d2e4302498 100644 --- a/library/core/src/panic.rs +++ b/library/core/src/panic.rs @@ -14,7 +14,7 @@ pub use self::panic_info::PanicInfo; pub use self::panic_info::PanicMessage; #[stable(feature = "catch_unwind", since = "1.9.0")] pub use self::unwind_safe::{AssertUnwindSafe, RefUnwindSafe, UnwindSafe}; -use crate::{any::Any, fmt}; +use crate::any::Any; #[doc(hidden)] #[unstable(feature = "edition_panic", issue = "none", reason = "use panic!() instead")] From a89ba7d49ba98784166727cf3a501c0e9463518c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Mon, 1 Jun 2026 19:55:35 +0200 Subject: [PATCH 6/6] add test --- .../src/unstable/convert/stable/mir.rs | 4 ++-- library/core/src/lib.rs | 2 +- tests/ui/codegen/recoverable_overflow.rs | 16 ++++++++++++++++ tests/ui/codegen/recoverable_overflow.run.stdout | 1 + 4 files changed, 20 insertions(+), 3 deletions(-) create mode 100644 tests/ui/codegen/recoverable_overflow.rs create mode 100644 tests/ui/codegen/recoverable_overflow.run.stdout diff --git a/compiler/rustc_public/src/unstable/convert/stable/mir.rs b/compiler/rustc_public/src/unstable/convert/stable/mir.rs index 17086fe9d7314..7e76d5a91ac66 100644 --- a/compiler/rustc_public/src/unstable/convert/stable/mir.rs +++ b/compiler/rustc_public/src/unstable/convert/stable/mir.rs @@ -3,14 +3,14 @@ use rustc_middle::mono::MonoItem; use rustc_middle::{bug, mir}; use rustc_public_bridge::context::CompilerCtxt; -use rustc_public_bridge::{bridge, Tables}; +use rustc_public_bridge::{Tables, bridge}; use crate::compiler_interface::BridgeTys; use crate::mir::alloc::GlobalAlloc; use crate::mir::{ConstOperand, Statement, UserTypeProjection, VarDebugInfoFragment}; use crate::ty::{Allocation, ConstantKind, MirConst}; use crate::unstable::Stable; -use crate::{alloc, opaque, Error}; +use crate::{Error, alloc, opaque}; impl<'tcx> Stable<'tcx> for mir::Body<'tcx> { type T = crate::mir::Body; diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index c7876d32c85a4..e29a132017685 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -134,6 +134,7 @@ #![feature(diagnostic_on_unmatch_args)] #![feature(doc_cfg)] #![feature(doc_notable_trait)] +#![feature(extern_item_impls)] #![feature(extern_types)] #![feature(f16)] #![feature(f128)] @@ -172,7 +173,6 @@ #![feature(uint_carryless_mul)] #![feature(unboxed_closures)] #![feature(unsized_fn_params)] -#![feature(extern_item_impls)] #![feature(with_negative_coherence)] // tidy-alphabetical-end // diff --git a/tests/ui/codegen/recoverable_overflow.rs b/tests/ui/codegen/recoverable_overflow.rs new file mode 100644 index 0000000000000..c22cdc9bbe7c2 --- /dev/null +++ b/tests/ui/codegen/recoverable_overflow.rs @@ -0,0 +1,16 @@ +//@ no-prefer-dynamic +//@ compile-flags: -Coverflow-checks=recoverable +//@ run-pass +//@ check-run-results +#![feature(recoverable_integer_overflow)] +#![allow(arithmetic_overflow, unused)] + +#[core::panic::integer_overflow_action] +fn overflow() { + println!("overflow happened") +} + +fn main() { + let mut x = 255u8; + x += 1; +} diff --git a/tests/ui/codegen/recoverable_overflow.run.stdout b/tests/ui/codegen/recoverable_overflow.run.stdout new file mode 100644 index 0000000000000..b883b5c9f2780 --- /dev/null +++ b/tests/ui/codegen/recoverable_overflow.run.stdout @@ -0,0 +1 @@ +overflow happened