diff options
Diffstat (limited to 'compiler')
26 files changed, 284 insertions, 129 deletions
diff --git a/compiler/rustc_builtin_macros/src/alloc_error_handler.rs b/compiler/rustc_builtin_macros/src/alloc_error_handler.rs new file mode 100644 index 00000000000..eaf1b1167cf --- /dev/null +++ b/compiler/rustc_builtin_macros/src/alloc_error_handler.rs @@ -0,0 +1,104 @@ +use crate::util::check_builtin_macro_attribute; + +use rustc_ast::ptr::P; +use rustc_ast::{self as ast, FnHeader, FnSig, Generics, StmtKind}; +use rustc_ast::{Fn, ItemKind, Stmt, TyKind, Unsafe}; +use rustc_expand::base::{Annotatable, ExtCtxt}; +use rustc_span::symbol::{kw, sym, Ident}; +use rustc_span::Span; +use thin_vec::thin_vec; + +pub fn expand( + ecx: &mut ExtCtxt<'_>, + _span: Span, + meta_item: &ast::MetaItem, + item: Annotatable, +) -> Vec<Annotatable> { + check_builtin_macro_attribute(ecx, meta_item, sym::alloc_error_handler); + + let orig_item = item.clone(); + let not_function = || { + ecx.sess + .parse_sess + .span_diagnostic + .span_err(item.span(), "alloc_error_handler must be a function"); + vec![orig_item.clone()] + }; + + // Allow using `#[alloc_error_handler]` on an item statement + // FIXME - if we get deref patterns, use them to reduce duplication here + let (item, is_stmt, sig_span) = match &item { + Annotatable::Item(item) => match item.kind { + ItemKind::Fn(ref fn_kind) => (item, false, ecx.with_def_site_ctxt(fn_kind.sig.span)), + _ => return not_function(), + }, + Annotatable::Stmt(stmt) => match &stmt.kind { + StmtKind::Item(item_) => match item_.kind { + ItemKind::Fn(ref fn_kind) => { + (item_, true, ecx.with_def_site_ctxt(fn_kind.sig.span)) + } + _ => return not_function(), + }, + _ => return not_function(), + }, + _ => return not_function(), + }; + + // Generate a bunch of new items using the AllocFnFactory + let span = ecx.with_def_site_ctxt(item.span); + + // Generate item statements for the allocator methods. + let stmts = vec![generate_handler(ecx, item.ident, span, sig_span)]; + + // Generate anonymous constant serving as container for the allocator methods. + let const_ty = ecx.ty(sig_span, TyKind::Tup(Vec::new())); + let const_body = ecx.expr_block(ecx.block(span, stmts)); + let const_item = ecx.item_const(span, Ident::new(kw::Underscore, span), const_ty, const_body); + let const_item = if is_stmt { + Annotatable::Stmt(P(ecx.stmt_item(span, const_item))) + } else { + Annotatable::Item(const_item) + }; + + // Return the original item and the new methods. + vec![orig_item, const_item] +} + +// #[rustc_std_internal_symbol] +// unsafe fn __rg_oom(size: usize, align: usize) -> ! { +// handler(core::alloc::Layout::from_size_align_unchecked(size, align)) +// } +fn generate_handler(cx: &ExtCtxt<'_>, handler: Ident, span: Span, sig_span: Span) -> Stmt { + let usize = cx.path_ident(span, Ident::new(sym::usize, span)); + let ty_usize = cx.ty_path(usize); + let size = Ident::from_str_and_span("size", span); + let align = Ident::from_str_and_span("align", span); + + let layout_new = cx.std_path(&[sym::alloc, sym::Layout, sym::from_size_align_unchecked]); + let layout_new = cx.expr_path(cx.path(span, layout_new)); + let layout = + cx.expr_call(span, layout_new, vec![cx.expr_ident(span, size), cx.expr_ident(span, align)]); + + let call = cx.expr_call_ident(sig_span, handler, vec![layout]); + + let never = ast::FnRetTy::Ty(cx.ty(span, TyKind::Never)); + let params = vec![cx.param(span, size, ty_usize.clone()), cx.param(span, align, ty_usize)]; + let decl = cx.fn_decl(params, never); + let header = FnHeader { unsafety: Unsafe::Yes(span), ..FnHeader::default() }; + let sig = FnSig { decl, header, span: span }; + + let body = Some(cx.block_expr(call)); + let kind = ItemKind::Fn(Box::new(Fn { + defaultness: ast::Defaultness::Final, + sig, + generics: Generics::default(), + body, + })); + + let special = sym::rustc_std_internal_symbol; + let special = cx.meta_word(span, special); + let attrs = thin_vec![cx.attribute(special)]; + + let item = cx.item(span, Ident::from_str_and_span("__rg_oom", span), attrs, kind); + cx.stmt_item(sig_span, item) +} diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs index c7ea7de8f4e..bde0102186a 100644 --- a/compiler/rustc_builtin_macros/src/lib.rs +++ b/compiler/rustc_builtin_macros/src/lib.rs @@ -25,6 +25,7 @@ use rustc_expand::base::{MacroExpanderFn, ResolverExpand, SyntaxExtensionKind}; use rustc_expand::proc_macro::BangProcMacro; use rustc_span::symbol::sym; +mod alloc_error_handler; mod assert; mod cfg; mod cfg_accessible; @@ -94,6 +95,7 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) { } register_attr! { + alloc_error_handler: alloc_error_handler::expand, bench: test::expand_bench, cfg_accessible: cfg_accessible::Expander, cfg_eval: cfg_eval::expand, diff --git a/compiler/rustc_codegen_cranelift/src/allocator.rs b/compiler/rustc_codegen_cranelift/src/allocator.rs index bad8a87b9be..12bb00d346d 100644 --- a/compiler/rustc_codegen_cranelift/src/allocator.rs +++ b/compiler/rustc_codegen_cranelift/src/allocator.rs @@ -5,6 +5,7 @@ use crate::prelude::*; use rustc_ast::expand::allocator::{AllocatorKind, AllocatorTy, ALLOCATOR_METHODS}; use rustc_session::config::OomStrategy; +use rustc_span::symbol::sym; /// Returns whether an allocator shim was created pub(crate) fn codegen( @@ -23,7 +24,7 @@ pub(crate) fn codegen( module, unwind_context, kind, - tcx.lang_items().oom().is_some(), + tcx.alloc_error_handler_kind(()).unwrap(), tcx.sess.opts.unstable_opts.oom, ); true @@ -36,7 +37,7 @@ fn codegen_inner( module: &mut impl Module, unwind_context: &mut UnwindContext, kind: AllocatorKind, - has_alloc_error_handler: bool, + alloc_error_handler_kind: AllocatorKind, oom_strategy: OomStrategy, ) { let usize_ty = module.target_config().pointer_type(); @@ -108,12 +109,12 @@ fn codegen_inner( returns: vec![], }; - let callee_name = if has_alloc_error_handler { "__rg_oom" } else { "__rdl_oom" }; + let callee_name = alloc_error_handler_kind.fn_name(sym::oom); let func_id = module.declare_function("__rust_alloc_error_handler", Linkage::Export, &sig).unwrap(); - let callee_func_id = module.declare_function(callee_name, Linkage::Import, &sig).unwrap(); + let callee_func_id = module.declare_function(&callee_name, Linkage::Import, &sig).unwrap(); let mut ctx = Context::new(); ctx.func.signature = sig; diff --git a/compiler/rustc_codegen_gcc/src/allocator.rs b/compiler/rustc_codegen_gcc/src/allocator.rs index 58efb81e800..e2c9ffe9c1c 100644 --- a/compiler/rustc_codegen_gcc/src/allocator.rs +++ b/compiler/rustc_codegen_gcc/src/allocator.rs @@ -7,7 +7,7 @@ use rustc_span::symbol::sym; use crate::GccContext; -pub(crate) unsafe fn codegen(tcx: TyCtxt<'_>, mods: &mut GccContext, _module_name: &str, kind: AllocatorKind, has_alloc_error_handler: bool) { +pub(crate) unsafe fn codegen(tcx: TyCtxt<'_>, mods: &mut GccContext, _module_name: &str, kind: AllocatorKind, alloc_error_handler_kind: AllocatorKind) { let context = &mods.context; let usize = match tcx.sess.target.pointer_width { @@ -90,14 +90,7 @@ pub(crate) unsafe fn codegen(tcx: TyCtxt<'_>, mods: &mut GccContext, _module_nam .collect(); let func = context.new_function(None, FunctionType::Exported, void, &args, name, false); - let kind = - if has_alloc_error_handler { - AllocatorKind::Global - } - else { - AllocatorKind::Default - }; - let callee = kind.fn_name(sym::oom); + let callee = alloc_error_handler_kind.fn_name(sym::oom); let args: Vec<_> = types.iter().enumerate() .map(|(index, typ)| context.new_parameter(None, *typ, &format!("param{}", index))) .collect(); diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs index accd02ab002..dd0daf2c38b 100644 --- a/compiler/rustc_codegen_gcc/src/lib.rs +++ b/compiler/rustc_codegen_gcc/src/lib.rs @@ -153,11 +153,11 @@ impl CodegenBackend for GccCodegenBackend { } impl ExtraBackendMethods for GccCodegenBackend { - fn codegen_allocator<'tcx>(&self, tcx: TyCtxt<'tcx>, module_name: &str, kind: AllocatorKind, has_alloc_error_handler: bool) -> Self::Module { + fn codegen_allocator<'tcx>(&self, tcx: TyCtxt<'tcx>, module_name: &str, kind: AllocatorKind, alloc_error_handler_kind: AllocatorKind) -> Self::Module { let mut mods = GccContext { context: Context::default(), }; - unsafe { allocator::codegen(tcx, &mut mods, module_name, kind, has_alloc_error_handler); } + unsafe { allocator::codegen(tcx, &mut mods, module_name, kind, alloc_error_handler_kind); } mods } diff --git a/compiler/rustc_codegen_llvm/src/allocator.rs b/compiler/rustc_codegen_llvm/src/allocator.rs index 72961ae888e..fed56cdd438 100644 --- a/compiler/rustc_codegen_llvm/src/allocator.rs +++ b/compiler/rustc_codegen_llvm/src/allocator.rs @@ -15,7 +15,7 @@ pub(crate) unsafe fn codegen( module_llvm: &mut ModuleLlvm, module_name: &str, kind: AllocatorKind, - has_alloc_error_handler: bool, + alloc_error_handler_kind: AllocatorKind, ) { let llcx = &*module_llvm.llcx; let llmod = module_llvm.llmod(); @@ -117,8 +117,7 @@ pub(crate) unsafe fn codegen( attributes::apply_to_llfn(llfn, llvm::AttributePlace::Function, &[uwtable]); } - let kind = if has_alloc_error_handler { AllocatorKind::Global } else { AllocatorKind::Default }; - let callee = kind.fn_name(sym::oom); + let callee = alloc_error_handler_kind.fn_name(sym::oom); let callee = llvm::LLVMRustGetOrInsertFunction(llmod, callee.as_ptr().cast(), callee.len(), ty); // -> ! DIFlagNoReturn attributes::apply_to_llfn(callee, llvm::AttributePlace::Function, &[no_return]); diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index 89c7e51d09e..d51aced85df 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -108,11 +108,11 @@ impl ExtraBackendMethods for LlvmCodegenBackend { tcx: TyCtxt<'tcx>, module_name: &str, kind: AllocatorKind, - has_alloc_error_handler: bool, + alloc_error_handler_kind: AllocatorKind, ) -> ModuleLlvm { let mut module_llvm = ModuleLlvm::new_metadata(tcx, module_name); unsafe { - allocator::codegen(tcx, &mut module_llvm, module_name, kind, has_alloc_error_handler); + allocator::codegen(tcx, &mut module_llvm, module_name, kind, alloc_error_handler_kind); } module_llvm } diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs index c2ecc41601c..752f6b1ef40 100644 --- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs +++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs @@ -193,8 +193,11 @@ fn exported_symbols_provider_local<'tcx>( } if tcx.allocator_kind(()).is_some() { - for method in ALLOCATOR_METHODS { - let symbol_name = format!("__rust_{}", method.name); + for symbol_name in ALLOCATOR_METHODS + .iter() + .map(|method| format!("__rust_{}", method.name)) + .chain(["__rust_alloc_error_handler".to_string(), OomStrategy::SYMBOL.to_string()]) + { let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(tcx, &symbol_name)); symbols.push(( diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index a92087305b8..c1411690f82 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -638,7 +638,14 @@ pub fn codegen_crate<B: ExtraBackendMethods>( let llmod_id = cgu_name_builder.build_cgu_name(LOCAL_CRATE, &["crate"], Some("allocator")).to_string(); let module_llvm = tcx.sess.time("write_allocator_module", || { - backend.codegen_allocator(tcx, &llmod_id, kind, tcx.lang_items().oom().is_some()) + backend.codegen_allocator( + tcx, + &llmod_id, + kind, + // If allocator_kind is Some then alloc_error_handler_kind must + // also be Some. + tcx.alloc_error_handler_kind(()).unwrap(), + ) }); Some(ModuleCodegen { name: llmod_id, module_llvm, kind: ModuleKind::Allocator }) diff --git a/compiler/rustc_codegen_ssa/src/traits/backend.rs b/compiler/rustc_codegen_ssa/src/traits/backend.rs index 87e347c61e2..5c35070ea66 100644 --- a/compiler/rustc_codegen_ssa/src/traits/backend.rs +++ b/compiler/rustc_codegen_ssa/src/traits/backend.rs @@ -119,7 +119,7 @@ pub trait ExtraBackendMethods: CodegenBackend + WriteBackendMethods + Sized + Se tcx: TyCtxt<'tcx>, module_name: &str, kind: AllocatorKind, - has_alloc_error_handler: bool, + alloc_error_handler_kind: AllocatorKind, ) -> Self::Module; /// This generates the codegen unit and returns it along with /// a `u64` giving an estimate of the unit's processing cost. diff --git a/compiler/rustc_error_messages/locales/en-US/metadata.ftl b/compiler/rustc_error_messages/locales/en-US/metadata.ftl index 08e553d9f15..c292ae9b32a 100644 --- a/compiler/rustc_error_messages/locales/en-US/metadata.ftl +++ b/compiler/rustc_error_messages/locales/en-US/metadata.ftl @@ -150,12 +150,28 @@ metadata_no_multiple_global_alloc = metadata_prev_global_alloc = previous global allocator defined here +metadata_no_multiple_alloc_error_handler = + cannot define multiple allocation error handlers + .label = cannot define a new allocation error handler + +metadata_prev_alloc_error_handler = + previous allocation error handler defined here + metadata_conflicting_global_alloc = the `#[global_allocator]` in {$other_crate_name} conflicts with global allocator in: {$crate_name} +metadata_conflicting_alloc_error_handler = + the `#[alloc_error_handler]` in {$other_crate_name} conflicts with allocation error handler in: {$crate_name} + metadata_global_alloc_required = no global memory allocator found but one is required; link to std or add `#[global_allocator]` to a static item that implements the GlobalAlloc trait +metadata_alloc_func_required = + `#[alloc_error_handler]` function required, but not found + +metadata_missing_alloc_error_handler = + use `#![feature(default_alloc_error_handler)]` for a default error handler + metadata_no_transitive_needs_dep = the crate `{$crate_name}` cannot depend on a crate that needs {$needs_crate_name}, but it depends on `{$deps_crate_name}` diff --git a/compiler/rustc_error_messages/locales/en-US/passes.ftl b/compiler/rustc_error_messages/locales/en-US/passes.ftl index 4bc6bd9fb22..bc5bfe2a244 100644 --- a/compiler/rustc_error_messages/locales/en-US/passes.ftl +++ b/compiler/rustc_error_messages/locales/en-US/passes.ftl @@ -367,12 +367,6 @@ passes_unknown_external_lang_item = passes_missing_panic_handler = `#[panic_handler]` function required, but not found -passes_alloc_func_required = - `#[alloc_error_handler]` function required, but not found - -passes_missing_alloc_error_handler = - use `#![feature(default_alloc_error_handler)]` for a default error handler - passes_missing_lang_item = language item required, but not found: `{$name}` .note = this can occur when a binary crate with `#![no_std]` is compiled for a target where `{$name}` is defined in the standard library diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 2ead3c2c8d4..14c8e3c458c 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -555,10 +555,6 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ rustc_attr!(rustc_deallocator, Normal, template!(Word), WarnFollowing, IMPL_DETAIL), rustc_attr!(rustc_allocator_zeroed, Normal, template!(Word), WarnFollowing, IMPL_DETAIL), gated!( - alloc_error_handler, Normal, template!(Word), WarnFollowing, - experimental!(alloc_error_handler) - ), - gated!( default_lib_allocator, Normal, template!(Word), WarnFollowing, allocator_internals, experimental!(default_lib_allocator), ), diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index 72ed73e81b4..a55224d1097 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -126,14 +126,12 @@ impl<CTX> HashStable<CTX> for LangItem { } /// Extracts the first `lang = "$name"` out of a list of attributes. -/// The attributes `#[panic_handler]` and `#[alloc_error_handler]` -/// are also extracted out when found. +/// The `#[panic_handler]` attribute is also extracted out when found. pub fn extract(attrs: &[ast::Attribute]) -> Option<(Symbol, Span)> { attrs.iter().find_map(|attr| { Some(match attr { _ if attr.has_name(sym::lang) => (attr.value_str()?, attr.span), _ if attr.has_name(sym::panic_handler) => (sym::panic_impl, attr.span), - _ if attr.has_name(sym::alloc_error_handler) => (sym::oom, attr.span), _ => return None, }) }) @@ -240,7 +238,6 @@ language_item_table! { ExchangeMalloc, sym::exchange_malloc, exchange_malloc_fn, Target::Fn, GenericRequirement::None; BoxFree, sym::box_free, box_free_fn, Target::Fn, GenericRequirement::Minimum(1); DropInPlace, sym::drop_in_place, drop_in_place_fn, Target::Fn, GenericRequirement::Minimum(1); - Oom, sym::oom, oom, Target::Fn, GenericRequirement::None; AllocLayout, sym::alloc_layout, alloc_layout, Target::Struct, GenericRequirement::None; Start, sym::start, start_fn, Target::Fn, GenericRequirement::Exact(1); diff --git a/compiler/rustc_hir/src/weak_lang_items.rs b/compiler/rustc_hir/src/weak_lang_items.rs index d8e5dd4ffdc..0cc50c6dd85 100644 --- a/compiler/rustc_hir/src/weak_lang_items.rs +++ b/compiler/rustc_hir/src/weak_lang_items.rs @@ -27,5 +27,4 @@ weak_lang_items! { PanicImpl, rust_begin_unwind; EhPersonality, rust_eh_personality; EhCatchTypeinfo, rust_eh_catch_typeinfo; - Oom, rust_oom; } diff --git a/compiler/rustc_hir_typeck/src/check.rs b/compiler/rustc_hir_typeck/src/check.rs index 7f76364e15a..b706d786b52 100644 --- a/compiler/rustc_hir_typeck/src/check.rs +++ b/compiler/rustc_hir_typeck/src/check.rs @@ -211,13 +211,6 @@ pub(super) fn check_fn<'a, 'tcx>( check_panic_info_fn(tcx, panic_impl_did.expect_local(), fn_sig, decl, declared_ret_ty); } - // Check that a function marked as `#[alloc_error_handler]` has signature `fn(Layout) -> !` - if let Some(alloc_error_handler_did) = tcx.lang_items().oom() - && alloc_error_handler_did == hir.local_def_id(fn_id).to_def_id() - { - check_alloc_error_fn(tcx, alloc_error_handler_did.expect_local(), fn_sig, decl, declared_ret_ty); - } - (fcx, gen_ty) } @@ -273,52 +266,3 @@ fn check_panic_info_fn( tcx.sess.span_err(span, "should have no const parameters"); } } - -fn check_alloc_error_fn( - tcx: TyCtxt<'_>, - fn_id: LocalDefId, - fn_sig: ty::FnSig<'_>, - decl: &hir::FnDecl<'_>, - declared_ret_ty: Ty<'_>, -) { - let Some(alloc_layout_did) = tcx.lang_items().alloc_layout() else { - tcx.sess.err("language item required, but not found: `alloc_layout`"); - return; - }; - - if *declared_ret_ty.kind() != ty::Never { - tcx.sess.span_err(decl.output.span(), "return type should be `!`"); - } - - let inputs = fn_sig.inputs(); - if inputs.len() != 1 { - tcx.sess.span_err(tcx.def_span(fn_id), "function should have one argument"); - return; - } - - let arg_is_alloc_layout = match inputs[0].kind() { - ty::Adt(ref adt, _) => adt.did() == alloc_layout_did, - _ => false, - }; - - if !arg_is_alloc_layout { - tcx.sess.span_err(decl.inputs[0].span, "argument should be `Layout`"); - } - - let DefKind::Fn = tcx.def_kind(fn_id) else { - let span = tcx.def_span(fn_id); - tcx.sess.span_err(span, "`#[alloc_error_handler]` should be a function"); - return; - }; - - let generic_counts = tcx.generics_of(fn_id).own_counts(); - if generic_counts.types != 0 { - let span = tcx.def_span(fn_id); - tcx.sess.span_err(span, "`#[alloc_error_handler]` function should have no type parameters"); - } - if generic_counts.consts != 0 { - let span = tcx.def_span(fn_id); - tcx.sess - .span_err(span, "`#[alloc_error_handler]` function should have no const parameters"); - } -} diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs index cfcceecbef4..d4c457975a8 100644 --- a/compiler/rustc_metadata/src/creader.rs +++ b/compiler/rustc_metadata/src/creader.rs @@ -1,8 +1,10 @@ //! Validates all used crates and extern libraries and loads their metadata use crate::errors::{ - ConflictingGlobalAlloc, CrateNotPanicRuntime, GlobalAllocRequired, NoMultipleGlobalAlloc, - NoPanicStrategy, NoTransitiveNeedsDep, NotProfilerRuntime, ProfilerBuiltinsNeedsCore, + AllocFuncRequired, ConflictingAllocErrorHandler, ConflictingGlobalAlloc, CrateNotPanicRuntime, + GlobalAllocRequired, MissingAllocErrorHandler, NoMultipleAllocErrorHandler, + NoMultipleGlobalAlloc, NoPanicStrategy, NoTransitiveNeedsDep, NotProfilerRuntime, + ProfilerBuiltinsNeedsCore, }; use crate::locator::{CrateError, CrateLocator, CratePaths}; use crate::rmeta::{CrateDep, CrateMetadata, CrateNumMap, CrateRoot, MetadataBlob}; @@ -41,8 +43,13 @@ pub struct CStore { /// This crate needs an allocator and either provides it itself, or finds it in a dependency. /// If the above is true, then this field denotes the kind of the found allocator. allocator_kind: Option<AllocatorKind>, + /// This crate needs an allocation error handler and either provides it itself, or finds it in a dependency. + /// If the above is true, then this field denotes the kind of the found allocator. + alloc_error_handler_kind: Option<AllocatorKind>, /// This crate has a `#[global_allocator]` item. has_global_allocator: bool, + /// This crate has a `#[alloc_error_handler]` item. + has_alloc_error_handler: bool, /// This map is used to verify we get no hash conflicts between /// `StableCrateId` values. @@ -197,10 +204,18 @@ impl CStore { self.allocator_kind } + pub(crate) fn alloc_error_handler_kind(&self) -> Option<AllocatorKind> { + self.alloc_error_handler_kind + } + pub(crate) fn has_global_allocator(&self) -> bool { self.has_global_allocator } + pub(crate) fn has_alloc_error_handler(&self) -> bool { + self.has_alloc_error_handler + } + pub fn report_unused_deps(&self, tcx: TyCtxt<'_>) { let json_unused_externs = tcx.sess.opts.json_unused_externs; @@ -247,7 +262,9 @@ impl<'a> CrateLoader<'a> { metas: IndexVec::from_elem_n(None, 1), injected_panic_runtime: None, allocator_kind: None, + alloc_error_handler_kind: None, has_global_allocator: false, + has_alloc_error_handler: false, stable_crate_ids, unused_externs: Vec::new(), }, @@ -792,6 +809,13 @@ impl<'a> CrateLoader<'a> { } spans => !spans.is_empty(), }; + self.cstore.has_alloc_error_handler = match &*alloc_error_handler_spans(&self.sess, krate) { + [span1, span2, ..] => { + self.sess.emit_err(NoMultipleAllocErrorHandler { span2: *span2, span1: *span1 }); + true + } + spans => !spans.is_empty(), + }; // Check to see if we actually need an allocator. This desire comes // about through the `#![needs_allocator]` attribute and is typically @@ -832,22 +856,48 @@ impl<'a> CrateLoader<'a> { } } } + let mut alloc_error_handler = + self.cstore.has_alloc_error_handler.then(|| Symbol::intern("this crate")); + for (_, data) in self.cstore.iter_crate_data() { + if data.has_alloc_error_handler() { + match alloc_error_handler { + Some(other_crate) => { + self.sess.emit_err(ConflictingAllocErrorHandler { + crate_name: data.name(), + other_crate_name: other_crate, + }); + } + None => alloc_error_handler = Some(data.name()), + } + } + } if global_allocator.is_some() { self.cstore.allocator_kind = Some(AllocatorKind::Global); - return; + } else { + // Ok we haven't found a global allocator but we still need an + // allocator. At this point our allocator request is typically fulfilled + // by the standard library, denoted by the `#![default_lib_allocator]` + // attribute. + if !self.sess.contains_name(&krate.attrs, sym::default_lib_allocator) + && !self.cstore.iter_crate_data().any(|(_, data)| data.has_default_lib_allocator()) + { + self.sess.emit_err(GlobalAllocRequired); + } + self.cstore.allocator_kind = Some(AllocatorKind::Default); } - // Ok we haven't found a global allocator but we still need an - // allocator. At this point our allocator request is typically fulfilled - // by the standard library, denoted by the `#![default_lib_allocator]` - // attribute. - if !self.sess.contains_name(&krate.attrs, sym::default_lib_allocator) - && !self.cstore.iter_crate_data().any(|(_, data)| data.has_default_lib_allocator()) - { - self.sess.emit_err(GlobalAllocRequired); + if alloc_error_handler.is_some() { + self.cstore.alloc_error_handler_kind = Some(AllocatorKind::Global); + } else { + // The alloc crate provides a default allocation error handler if + // one isn't specified. + if !self.sess.features_untracked().default_alloc_error_handler { + self.sess.emit_err(AllocFuncRequired); + self.sess.emit_note(MissingAllocErrorHandler); + } + self.cstore.alloc_error_handler_kind = Some(AllocatorKind::Default); } - self.cstore.allocator_kind = Some(AllocatorKind::Default); } fn inject_dependency_if( @@ -1023,3 +1073,26 @@ fn global_allocator_spans(sess: &Session, krate: &ast::Crate) -> Vec<Span> { visit::walk_crate(&mut f, krate); f.spans } + +fn alloc_error_handler_spans(sess: &Session, krate: &ast::Crate) -> Vec<Span> { + struct Finder<'a> { + sess: &'a Session, + name: Symbol, + spans: Vec<Span>, + } + impl<'ast, 'a> visit::Visitor<'ast> for Finder<'a> { + fn visit_item(&mut self, item: &'ast ast::Item) { + if item.ident.name == self.name + && self.sess.contains_name(&item.attrs, sym::rustc_std_internal_symbol) + { + self.spans.push(item.span); + } + visit::walk_item(self, item) + } + } + + let name = Symbol::intern(&AllocatorKind::Global.fn_name(sym::oom)); + let mut f = Finder { sess, name, spans: Vec::new() }; + visit::walk_crate(&mut f, krate); + f.spans +} diff --git a/compiler/rustc_metadata/src/errors.rs b/compiler/rustc_metadata/src/errors.rs index 7c387b9a9ec..289fa53aa5e 100644 --- a/compiler/rustc_metadata/src/errors.rs +++ b/compiler/rustc_metadata/src/errors.rs @@ -344,6 +344,16 @@ pub struct NoMultipleGlobalAlloc { } #[derive(Diagnostic)] +#[diag(metadata_no_multiple_alloc_error_handler)] +pub struct NoMultipleAllocErrorHandler { + #[primary_span] + #[label] + pub span2: Span, + #[label(metadata_prev_alloc_error_handler)] + pub span1: Span, +} + +#[derive(Diagnostic)] #[diag(metadata_conflicting_global_alloc)] pub struct ConflictingGlobalAlloc { pub crate_name: Symbol, @@ -351,10 +361,25 @@ pub struct ConflictingGlobalAlloc { } #[derive(Diagnostic)] +#[diag(metadata_conflicting_alloc_error_handler)] +pub struct ConflictingAllocErrorHandler { + pub crate_name: Symbol, + pub other_crate_name: Symbol, +} + +#[derive(Diagnostic)] #[diag(metadata_global_alloc_required)] pub struct GlobalAllocRequired; #[derive(Diagnostic)] +#[diag(metadata_alloc_func_required)] +pub struct AllocFuncRequired; + +#[derive(Diagnostic)] +#[diag(metadata_missing_alloc_error_handler)] +pub struct MissingAllocErrorHandler; + +#[derive(Diagnostic)] #[diag(metadata_no_transitive_needs_dep)] pub struct NoTransitiveNeedsDep<'a> { pub crate_name: Symbol, diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index 17a7532044a..8e80d794a13 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -1764,6 +1764,10 @@ impl CrateMetadata { self.root.has_global_allocator } + pub(crate) fn has_alloc_error_handler(&self) -> bool { + self.root.has_alloc_error_handler + } + pub(crate) fn has_default_lib_allocator(&self) -> bool { self.root.has_default_lib_allocator } diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index a0a0855251b..f475b0b3981 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -255,6 +255,7 @@ provide! { tcx, def_id, other, cdata, is_panic_runtime => { cdata.root.panic_runtime } is_compiler_builtins => { cdata.root.compiler_builtins } has_global_allocator => { cdata.root.has_global_allocator } + has_alloc_error_handler => { cdata.root.has_alloc_error_handler } has_panic_handler => { cdata.root.has_panic_handler } is_profiler_runtime => { cdata.root.profiler_runtime } required_panic_strategy => { cdata.root.required_panic_strategy } @@ -339,6 +340,7 @@ pub(in crate::rmeta) fn provide(providers: &mut Providers) { // resolve! Does this work? Unsure! That's what the issue is about *providers = Providers { allocator_kind: |tcx, ()| CStore::from_tcx(tcx).allocator_kind(), + alloc_error_handler_kind: |tcx, ()| CStore::from_tcx(tcx).alloc_error_handler_kind(), is_private_dep: |_tcx, cnum| { assert_eq!(cnum, LOCAL_CRATE); false @@ -464,6 +466,10 @@ pub(in crate::rmeta) fn provide(providers: &mut Providers) { assert_eq!(cnum, LOCAL_CRATE); CStore::from_tcx(tcx).has_global_allocator() }, + has_alloc_error_handler: |tcx, cnum| { + assert_eq!(cnum, LOCAL_CRATE); + CStore::from_tcx(tcx).has_alloc_error_handler() + }, postorder_cnums: |tcx, ()| { tcx.arena .alloc_slice(&CStore::from_tcx(tcx).crate_dependencies_in_postorder(LOCAL_CRATE)) diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 87fa69e1639..c907ee64628 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -670,6 +670,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { panic_in_drop_strategy: tcx.sess.opts.unstable_opts.panic_in_drop, edition: tcx.sess.edition(), has_global_allocator: tcx.has_global_allocator(LOCAL_CRATE), + has_alloc_error_handler: tcx.has_alloc_error_handler(LOCAL_CRATE), has_panic_handler: tcx.has_panic_handler(LOCAL_CRATE), has_default_lib_allocator: tcx .sess diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index 774cff2075d..aa6d378a43a 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -223,6 +223,7 @@ pub(crate) struct CrateRoot { panic_in_drop_strategy: PanicStrategy, edition: Edition, has_global_allocator: bool, + has_alloc_error_handler: bool, has_panic_handler: bool, has_default_lib_allocator: bool, diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index a098e570305..33acaed435b 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1391,6 +1391,13 @@ rustc_queries! { desc { "checking if the crate has_global_allocator" } separate_provide_extern } + query has_alloc_error_handler(_: CrateNum) -> bool { + // This query depends on untracked global state in CStore + eval_always + fatal_cycle + desc { "checking if the crate has_alloc_error_handler" } + separate_provide_extern + } query has_panic_handler(_: CrateNum) -> bool { fatal_cycle desc { "checking if the crate has_panic_handler" } @@ -1761,6 +1768,10 @@ rustc_queries! { eval_always desc { "getting the allocator kind for the current crate" } } + query alloc_error_handler_kind(_: ()) -> Option<AllocatorKind> { + eval_always + desc { "alloc error handler kind for the current crate" } + } query upvars_mentioned(def_id: DefId) -> Option<&'tcx FxIndexMap<hir::HirId, hir::Upvar>> { desc { |tcx| "collecting upvars mentioned in `{}`", tcx.def_path_str(def_id) } diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index 753d01f46ca..b779edbc30f 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -470,11 +470,6 @@ fn has_allow_dead_code_or_lang_attr_helper( return true; } - // (To be) stable attribute for #[lang = "oom"] - if tcx.sess.contains_name(attrs, sym::alloc_error_handler) { - return true; - } - let def_id = tcx.hir().local_def_id(id); if tcx.def_kind(def_id).has_codegen_attrs() { let cg_attrs = tcx.codegen_fn_attrs(def_id); diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index adaaf539242..4a5cfd2d429 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -702,14 +702,6 @@ pub struct UnknownExternLangItem { pub struct MissingPanicHandler; #[derive(Diagnostic)] -#[diag(passes_alloc_func_required)] -pub struct AllocFuncRequired; - -#[derive(Diagnostic)] -#[diag(passes_missing_alloc_error_handler)] -pub struct MissingAllocErrorHandler; - -#[derive(Diagnostic)] #[diag(passes_missing_lang_item)] #[note] #[help] diff --git a/compiler/rustc_passes/src/weak_lang_items.rs b/compiler/rustc_passes/src/weak_lang_items.rs index 94d6a405b53..f0815fcd8db 100644 --- a/compiler/rustc_passes/src/weak_lang_items.rs +++ b/compiler/rustc_passes/src/weak_lang_items.rs @@ -7,10 +7,7 @@ use rustc_middle::middle::lang_items::required; use rustc_middle::ty::TyCtxt; use rustc_session::config::CrateType; -use crate::errors::{ - AllocFuncRequired, MissingAllocErrorHandler, MissingLangItem, MissingPanicHandler, - UnknownExternLangItem, -}; +use crate::errors::{MissingLangItem, MissingPanicHandler, UnknownExternLangItem}; /// Checks the crate for usage of weak lang items, returning a vector of all the /// language items required by this crate, but not defined yet. @@ -69,11 +66,6 @@ fn verify<'tcx>(tcx: TyCtxt<'tcx>, items: &lang_items::LanguageItems) { if missing.contains(&item) && required(tcx, item) && items.get(item).is_none() { if item == LangItem::PanicImpl { tcx.sess.emit_err(MissingPanicHandler); - } else if item == LangItem::Oom { - if !tcx.features().default_alloc_error_handler { - tcx.sess.emit_err(AllocFuncRequired); - tcx.sess.emit_note(MissingAllocErrorHandler); - } } else { tcx.sess.emit_err(MissingLangItem { name: item.name() }); } |
