diff options
Diffstat (limited to 'compiler')
| -rw-r--r-- | compiler/rustc_hir_typeck/src/expr.rs | 33 | ||||
| -rw-r--r-- | compiler/rustc_hir_typeck/src/lib.rs | 6 | ||||
| -rw-r--r-- | compiler/rustc_interface/src/passes.rs | 22 | ||||
| -rw-r--r-- | compiler/rustc_middle/src/query/mod.rs | 3 | ||||
| -rw-r--r-- | compiler/rustc_mir_build/messages.ftl | 12 | ||||
| -rw-r--r-- | compiler/rustc_mir_build/src/builder/mod.rs | 7 | ||||
| -rw-r--r-- | compiler/rustc_mir_build/src/errors.rs | 22 | ||||
| -rw-r--r-- | compiler/rustc_mir_build/src/lib.rs | 4 | ||||
| -rw-r--r-- | compiler/rustc_mir_transform/messages.ftl | 12 | ||||
| -rw-r--r-- | compiler/rustc_mir_transform/src/check_call_recursion.rs (renamed from compiler/rustc_mir_build/src/lints.rs) | 81 | ||||
| -rw-r--r-- | compiler/rustc_mir_transform/src/check_inline.rs (renamed from compiler/rustc_mir_build/src/check_inline.rs) | 52 | ||||
| -rw-r--r-- | compiler/rustc_mir_transform/src/errors.rs | 22 | ||||
| -rw-r--r-- | compiler/rustc_mir_transform/src/inline.rs | 6 | ||||
| -rw-r--r-- | compiler/rustc_mir_transform/src/lib.rs | 10 |
14 files changed, 161 insertions, 131 deletions
diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 3bb518e7f97..dc6a2adf622 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -1991,18 +1991,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { adt_ty: Ty<'tcx>, expected: Expectation<'tcx>, expr: &hir::Expr<'_>, - span: Span, + path_span: Span, variant: &'tcx ty::VariantDef, hir_fields: &'tcx [hir::ExprField<'tcx>], base_expr: &'tcx hir::StructTailExpr<'tcx>, ) { let tcx = self.tcx; - let adt_ty = self.try_structurally_resolve_type(span, adt_ty); + let adt_ty = self.try_structurally_resolve_type(path_span, adt_ty); let adt_ty_hint = expected.only_has_type(self).and_then(|expected| { self.fudge_inference_if_ok(|| { let ocx = ObligationCtxt::new(self); - ocx.sup(&self.misc(span), self.param_env, expected, adt_ty)?; + ocx.sup(&self.misc(path_span), self.param_env, expected, adt_ty)?; if !ocx.select_where_possible().is_empty() { return Err(TypeError::Mismatch); } @@ -2012,11 +2012,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }); if let Some(adt_ty_hint) = adt_ty_hint { // re-link the variables that the fudging above can create. - self.demand_eqtype(span, adt_ty_hint, adt_ty); + self.demand_eqtype(path_span, adt_ty_hint, adt_ty); } let ty::Adt(adt, args) = adt_ty.kind() else { - span_bug!(span, "non-ADT passed to check_expr_struct_fields"); + span_bug!(path_span, "non-ADT passed to check_expr_struct_fields"); }; let adt_kind = adt.adt_kind(); @@ -2107,7 +2107,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if adt_kind == AdtKind::Union && hir_fields.len() != 1 { struct_span_code_err!( self.dcx(), - span, + path_span, E0784, "union expressions should have exactly one field", ) @@ -2167,6 +2167,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }); return; } + if variant.fields.is_empty() { + let mut err = self.dcx().struct_span_err( + span, + format!( + "`{adt_ty}` has no fields, `..` needs at least one default field in the \ + struct definition", + ), + ); + err.span_label(path_span, "this type has no fields"); + err.emit(); + } if !missing_mandatory_fields.is_empty() { let s = pluralize!(missing_mandatory_fields.len()); let fields: Vec<_> = @@ -2316,11 +2327,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .collect(); if !private_fields.is_empty() { - self.report_private_fields(adt_ty, span, expr.span, private_fields, hir_fields); + self.report_private_fields( + adt_ty, + path_span, + expr.span, + private_fields, + hir_fields, + ); } else { self.report_missing_fields( adt_ty, - span, + path_span, remaining_fields, variant, hir_fields, diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index cb21961f36b..9cd9ca040ce 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -87,7 +87,7 @@ fn used_trait_imports(tcx: TyCtxt<'_>, def_id: LocalDefId) -> &UnordSet<LocalDef } fn typeck<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &'tcx ty::TypeckResults<'tcx> { - typeck_with_fallback(tcx, def_id, None) + typeck_with_inspect(tcx, def_id, None) } /// Same as `typeck` but `inspect` is invoked on evaluation of each root obligation. @@ -99,11 +99,11 @@ pub fn inspect_typeck<'tcx>( def_id: LocalDefId, inspect: ObligationInspector<'tcx>, ) -> &'tcx ty::TypeckResults<'tcx> { - typeck_with_fallback(tcx, def_id, Some(inspect)) + typeck_with_inspect(tcx, def_id, Some(inspect)) } #[instrument(level = "debug", skip(tcx, inspector), ret)] -fn typeck_with_fallback<'tcx>( +fn typeck_with_inspect<'tcx>( tcx: TyCtxt<'tcx>, def_id: LocalDefId, inspector: Option<ObligationInspector<'tcx>>, diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index aff66e48fbb..241bc35857a 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -875,6 +875,8 @@ fn run_required_analyses(tcx: TyCtxt<'_>) { }); // Freeze definitions as we don't add new ones at this point. // We need to wait until now since we synthesize a by-move body + // for all coroutine-closures. + // // This improves performance by allowing lock-free access to them. tcx.untracked().definitions.freeze(); @@ -887,7 +889,7 @@ fn run_required_analyses(tcx: TyCtxt<'_>) { }); }); sess.time("MIR_effect_checking", || { - for def_id in tcx.hir().body_owners() { + tcx.hir().par_body_owners(|def_id| { tcx.ensure().has_ffi_unwind_calls(def_id); // If we need to codegen, ensure that we emit all errors from @@ -898,15 +900,17 @@ fn run_required_analyses(tcx: TyCtxt<'_>) { { tcx.ensure().mir_drops_elaborated_and_const_checked(def_id); } - } + }); }); - tcx.hir().par_body_owners(|def_id| { - if tcx.is_coroutine(def_id.to_def_id()) { - tcx.ensure().mir_coroutine_witnesses(def_id); - tcx.ensure().check_coroutine_obligations( - tcx.typeck_root_def_id(def_id.to_def_id()).expect_local(), - ); - } + sess.time("coroutine_obligations", || { + tcx.hir().par_body_owners(|def_id| { + if tcx.is_coroutine(def_id.to_def_id()) { + tcx.ensure().mir_coroutine_witnesses(def_id); + tcx.ensure().check_coroutine_obligations( + tcx.typeck_root_def_id(def_id.to_def_id()).expect_local(), + ); + } + }); }); sess.time("layout_testing", || layout_test::test_layout(tcx)); diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index bfbcb0532c1..65e93c3a1cc 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1164,8 +1164,7 @@ rustc_queries! { } /// Check whether the function has any recursion that could cause the inliner to trigger - /// a cycle. Returns the call stack causing the cycle. The call stack does not contain the - /// current function, just all intermediate functions. + /// a cycle. query mir_callgraph_reachable(key: (ty::Instance<'tcx>, LocalDefId)) -> bool { fatal_cycle desc { |tcx| diff --git a/compiler/rustc_mir_build/messages.ftl b/compiler/rustc_mir_build/messages.ftl index 5203c33c968..ffdb721fb18 100644 --- a/compiler/rustc_mir_build/messages.ftl +++ b/compiler/rustc_mir_build/messages.ftl @@ -118,12 +118,6 @@ mir_build_extern_static_requires_unsafe_unsafe_op_in_unsafe_fn_allowed = .note = extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior .label = use of extern static -mir_build_force_inline = - `{$callee}` is incompatible with `#[rustc_force_inline]` - .attr = annotation here - .callee = `{$callee}` defined here - .note = incompatible due to: {$reason} - mir_build_inform_irrefutable = `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant mir_build_initializing_type_with_requires_unsafe = @@ -330,12 +324,6 @@ mir_build_type_not_structural_more_info = see https://doc.rust-lang.org/stable/s mir_build_type_not_structural_tip = the `PartialEq` trait must be derived, manual `impl`s are not sufficient; see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details -mir_build_unconditional_recursion = function cannot return without recursing - .label = cannot return without recursing - .help = a `loop` may express intention better if this is on purpose - -mir_build_unconditional_recursion_call_site_label = recursive call site - mir_build_union_field_requires_unsafe = access to union field is unsafe and requires unsafe block .note = the field may not be properly initialized: using uninitialized data will cause undefined behavior diff --git a/compiler/rustc_mir_build/src/builder/mod.rs b/compiler/rustc_mir_build/src/builder/mod.rs index 8b01ec0d06a..9fa431f7d5f 100644 --- a/compiler/rustc_mir_build/src/builder/mod.rs +++ b/compiler/rustc_mir_build/src/builder/mod.rs @@ -26,10 +26,8 @@ use rustc_middle::ty::{self, ScalarInt, Ty, TyCtxt, TypeVisitableExt, TypingMode use rustc_middle::{bug, span_bug}; use rustc_span::{Span, Symbol, sym}; -use super::lints; use crate::builder::expr::as_place::PlaceBuilder; use crate::builder::scope::DropKind; -use crate::check_inline; pub(crate) fn closure_saved_names_of_captured_variables<'tcx>( tcx: TyCtxt<'tcx>, @@ -48,7 +46,7 @@ pub(crate) fn closure_saved_names_of_captured_variables<'tcx>( } /// Construct the MIR for a given `DefId`. -pub(crate) fn mir_build<'tcx>(tcx: TyCtxtAt<'tcx>, def: LocalDefId) -> Body<'tcx> { +pub(crate) fn build_mir<'tcx>(tcx: TyCtxtAt<'tcx>, def: LocalDefId) -> Body<'tcx> { let tcx = tcx.tcx; tcx.ensure_with_value().thir_abstract_const(def); if let Err(e) = tcx.check_match(def) { @@ -80,9 +78,6 @@ pub(crate) fn mir_build<'tcx>(tcx: TyCtxtAt<'tcx>, def: LocalDefId) -> Body<'tcx } }; - lints::check(tcx, &body); - check_inline::check_force_inline(tcx, &body); - // The borrow checker will replace all the regions here with its own // inference variables. There's no point having non-erased regions here. // The exception is `body.user_type_annotations`, which is used unmodified diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs index 90c31a2caa3..83aec9ccdef 100644 --- a/compiler/rustc_mir_build/src/errors.rs +++ b/compiler/rustc_mir_build/src/errors.rs @@ -12,16 +12,6 @@ use rustc_span::{Span, Symbol}; use crate::fluent_generated as fluent; #[derive(LintDiagnostic)] -#[diag(mir_build_unconditional_recursion)] -#[help] -pub(crate) struct UnconditionalRecursion { - #[label] - pub(crate) span: Span, - #[label(mir_build_unconditional_recursion_call_site_label)] - pub(crate) call_sites: Vec<Span>, -} - -#[derive(LintDiagnostic)] #[diag(mir_build_call_to_deprecated_safe_fn_requires_unsafe)] pub(crate) struct CallToDeprecatedSafeFnRequiresUnsafe { #[label] @@ -1107,15 +1097,3 @@ impl<'a> Subdiagnostic for Rust2024IncompatiblePatSugg<'a> { ); } } - -#[derive(Diagnostic)] -#[diag(mir_build_force_inline)] -#[note] -pub(crate) struct InvalidForceInline { - #[primary_span] - pub attr_span: Span, - #[label(mir_build_callee)] - pub callee_span: Span, - pub callee: String, - pub reason: &'static str, -} diff --git a/compiler/rustc_mir_build/src/lib.rs b/compiler/rustc_mir_build/src/lib.rs index 76a35355de7..8e786733ee0 100644 --- a/compiler/rustc_mir_build/src/lib.rs +++ b/compiler/rustc_mir_build/src/lib.rs @@ -15,11 +15,9 @@ // "Go to file" feature to silently ignore all files in the module, probably // because it assumes that "build" is a build-output directory. See #134365. mod builder; -pub mod check_inline; mod check_tail_calls; mod check_unsafety; mod errors; -pub mod lints; mod thir; use rustc_middle::util::Providers; @@ -29,7 +27,7 @@ rustc_fluent_macro::fluent_messages! { "../messages.ftl" } pub fn provide(providers: &mut Providers) { providers.check_match = thir::pattern::check_match; providers.lit_to_const = thir::constant::lit_to_const; - providers.hooks.build_mir = builder::mir_build; + providers.hooks.build_mir = builder::build_mir; providers.closure_saved_names_of_captured_variables = builder::closure_saved_names_of_captured_variables; providers.check_unsafety = check_unsafety::check_unsafety; diff --git a/compiler/rustc_mir_transform/messages.ftl b/compiler/rustc_mir_transform/messages.ftl index b0c023cca82..5628f4c9381 100644 --- a/compiler/rustc_mir_transform/messages.ftl +++ b/compiler/rustc_mir_transform/messages.ftl @@ -27,6 +27,12 @@ mir_transform_force_inline = .callee = `{$callee}` defined here .note = could not be inlined due to: {$reason} +mir_transform_force_inline_attr = + `{$callee}` is incompatible with `#[rustc_force_inline]` + .attr = annotation here + .callee = `{$callee}` defined here + .note = incompatible due to: {$reason} + mir_transform_force_inline_justification = `{$callee}` is required to be inlined to: {$sym} @@ -66,6 +72,12 @@ mir_transform_unaligned_packed_ref = reference to packed field is unaligned .note_ub = creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) .help = copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers) +mir_transform_unconditional_recursion = function cannot return without recursing + .label = cannot return without recursing + .help = a `loop` may express intention better if this is on purpose + +mir_transform_unconditional_recursion_call_site_label = recursive call site + mir_transform_undefined_transmute = pointers cannot be transmuted to integers during const eval .note = at compile-time, pointers do not have an integer value .note2 = avoiding this restriction via `union` or raw pointers leads to compile-time undefined behavior diff --git a/compiler/rustc_mir_build/src/lints.rs b/compiler/rustc_mir_transform/src/check_call_recursion.rs index 5cf33868ade..51fd3c6512e 100644 --- a/compiler/rustc_mir_build/src/lints.rs +++ b/compiler/rustc_mir_transform/src/check_call_recursion.rs @@ -10,25 +10,54 @@ use rustc_session::lint::builtin::UNCONDITIONAL_RECURSION; use rustc_span::Span; use crate::errors::UnconditionalRecursion; +use crate::pass_manager::MirLint; -pub(crate) fn check<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) { - check_call_recursion(tcx, body); +pub(super) struct CheckCallRecursion; + +impl<'tcx> MirLint<'tcx> for CheckCallRecursion { + fn run_lint(&self, tcx: TyCtxt<'tcx>, body: &Body<'tcx>) { + let def_id = body.source.def_id().expect_local(); + + if let DefKind::Fn | DefKind::AssocFn = tcx.def_kind(def_id) { + // If this is trait/impl method, extract the trait's args. + let trait_args = match tcx.trait_of_item(def_id.to_def_id()) { + Some(trait_def_id) => { + let trait_args_count = tcx.generics_of(trait_def_id).count(); + &GenericArgs::identity_for_item(tcx, def_id)[..trait_args_count] + } + _ => &[], + }; + + check_recursion(tcx, body, CallRecursion { trait_args }) + } + } } -fn check_call_recursion<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) { - let def_id = body.source.def_id().expect_local(); +/// Requires drop elaboration to have been performed. +pub(super) struct CheckDropRecursion; - if let DefKind::Fn | DefKind::AssocFn = tcx.def_kind(def_id) { - // If this is trait/impl method, extract the trait's args. - let trait_args = match tcx.trait_of_item(def_id.to_def_id()) { - Some(trait_def_id) => { - let trait_args_count = tcx.generics_of(trait_def_id).count(); - &GenericArgs::identity_for_item(tcx, def_id)[..trait_args_count] - } - _ => &[], - }; +impl<'tcx> MirLint<'tcx> for CheckDropRecursion { + fn run_lint(&self, tcx: TyCtxt<'tcx>, body: &Body<'tcx>) { + let def_id = body.source.def_id().expect_local(); - check_recursion(tcx, body, CallRecursion { trait_args }) + // First check if `body` is an `fn drop()` of `Drop` + if let DefKind::AssocFn = tcx.def_kind(def_id) + && let Some(trait_ref) = + tcx.impl_of_method(def_id.to_def_id()).and_then(|def_id| tcx.impl_trait_ref(def_id)) + && let Some(drop_trait) = tcx.lang_items().drop_trait() + && drop_trait == trait_ref.instantiate_identity().def_id + // avoid erroneous `Drop` impls from causing ICEs below + && let sig = tcx.fn_sig(def_id).instantiate_identity() + && sig.inputs().skip_binder().len() == 1 + { + // It was. Now figure out for what type `Drop` is implemented and then + // check for recursion. + if let ty::Ref(_, dropped_ty, _) = + tcx.liberate_late_bound_regions(def_id.to_def_id(), sig.input(0)).kind() + { + check_recursion(tcx, body, RecursiveDrop { drop_for: *dropped_ty }); + } + } } } @@ -61,30 +90,6 @@ fn check_recursion<'tcx>( } } -/// Requires drop elaboration to have been performed first. -pub fn check_drop_recursion<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) { - let def_id = body.source.def_id().expect_local(); - - // First check if `body` is an `fn drop()` of `Drop` - if let DefKind::AssocFn = tcx.def_kind(def_id) - && let Some(trait_ref) = - tcx.impl_of_method(def_id.to_def_id()).and_then(|def_id| tcx.impl_trait_ref(def_id)) - && let Some(drop_trait) = tcx.lang_items().drop_trait() - && drop_trait == trait_ref.instantiate_identity().def_id - // avoid erroneous `Drop` impls from causing ICEs below - && let sig = tcx.fn_sig(def_id).instantiate_identity() - && sig.inputs().skip_binder().len() == 1 - { - // It was. Now figure out for what type `Drop` is implemented and then - // check for recursion. - if let ty::Ref(_, dropped_ty, _) = - tcx.liberate_late_bound_regions(def_id.to_def_id(), sig.input(0)).kind() - { - check_recursion(tcx, body, RecursiveDrop { drop_for: *dropped_ty }); - } - } -} - trait TerminatorClassifier<'tcx> { fn is_recursive_terminator( &self, diff --git a/compiler/rustc_mir_build/src/check_inline.rs b/compiler/rustc_mir_transform/src/check_inline.rs index 1af3b3e2c13..497f4a660ea 100644 --- a/compiler/rustc_mir_build/src/check_inline.rs +++ b/compiler/rustc_mir_transform/src/check_inline.rs @@ -1,3 +1,6 @@ +//! Check that a body annotated with `#[rustc_force_inline]` will not fail to inline based on its +//! definition alone (irrespective of any specific caller). + use rustc_attr_parsing::InlineAttr; use rustc_hir::def_id::DefId; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; @@ -6,30 +9,37 @@ use rustc_middle::ty; use rustc_middle::ty::TyCtxt; use rustc_span::sym; -/// Check that a body annotated with `#[rustc_force_inline]` will not fail to inline based on its -/// definition alone (irrespective of any specific caller). -pub(crate) fn check_force_inline<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) { - let def_id = body.source.def_id(); - if !tcx.hir().body_owner_kind(def_id).is_fn_or_closure() || !def_id.is_local() { - return; - } - let InlineAttr::Force { attr_span, .. } = tcx.codegen_fn_attrs(def_id).inline else { - return; - }; +use crate::pass_manager::MirLint; - if let Err(reason) = - is_inline_valid_on_fn(tcx, def_id).and_then(|_| is_inline_valid_on_body(tcx, body)) - { - tcx.dcx().emit_err(crate::errors::InvalidForceInline { - attr_span, - callee_span: tcx.def_span(def_id), - callee: tcx.def_path_str(def_id), - reason, - }); +pub(super) struct CheckForceInline; + +impl<'tcx> MirLint<'tcx> for CheckForceInline { + fn run_lint(&self, tcx: TyCtxt<'tcx>, body: &Body<'tcx>) { + let def_id = body.source.def_id(); + if !tcx.hir().body_owner_kind(def_id).is_fn_or_closure() || !def_id.is_local() { + return; + } + let InlineAttr::Force { attr_span, .. } = tcx.codegen_fn_attrs(def_id).inline else { + return; + }; + + if let Err(reason) = + is_inline_valid_on_fn(tcx, def_id).and_then(|_| is_inline_valid_on_body(tcx, body)) + { + tcx.dcx().emit_err(crate::errors::InvalidForceInline { + attr_span, + callee_span: tcx.def_span(def_id), + callee: tcx.def_path_str(def_id), + reason, + }); + } } } -pub fn is_inline_valid_on_fn<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> Result<(), &'static str> { +pub(super) fn is_inline_valid_on_fn<'tcx>( + tcx: TyCtxt<'tcx>, + def_id: DefId, +) -> Result<(), &'static str> { let codegen_attrs = tcx.codegen_fn_attrs(def_id); if tcx.has_attr(def_id, sym::rustc_no_mir_inline) { return Err("#[rustc_no_mir_inline]"); @@ -65,7 +75,7 @@ pub fn is_inline_valid_on_fn<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> Result<( Ok(()) } -pub fn is_inline_valid_on_body<'tcx>( +pub(super) fn is_inline_valid_on_body<'tcx>( _: TyCtxt<'tcx>, body: &Body<'tcx>, ) -> Result<(), &'static str> { diff --git a/compiler/rustc_mir_transform/src/errors.rs b/compiler/rustc_mir_transform/src/errors.rs index 015633d145f..a2fd46043ca 100644 --- a/compiler/rustc_mir_transform/src/errors.rs +++ b/compiler/rustc_mir_transform/src/errors.rs @@ -10,6 +10,28 @@ use rustc_span::{Span, Symbol}; use crate::fluent_generated as fluent; #[derive(LintDiagnostic)] +#[diag(mir_transform_unconditional_recursion)] +#[help] +pub(crate) struct UnconditionalRecursion { + #[label] + pub(crate) span: Span, + #[label(mir_transform_unconditional_recursion_call_site_label)] + pub(crate) call_sites: Vec<Span>, +} + +#[derive(Diagnostic)] +#[diag(mir_transform_force_inline_attr)] +#[note] +pub(crate) struct InvalidForceInline { + #[primary_span] + pub attr_span: Span, + #[label(mir_transform_callee)] + pub callee_span: Span, + pub callee: String, + pub reason: &'static str, +} + +#[derive(LintDiagnostic)] pub(crate) enum ConstMutate { #[diag(mir_transform_const_modify)] #[note] diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs index 470393c9ae1..2052e28325c 100644 --- a/compiler/rustc_mir_transform/src/inline.rs +++ b/compiler/rustc_mir_transform/src/inline.rs @@ -21,8 +21,8 @@ use tracing::{debug, instrument, trace, trace_span}; use crate::cost_checker::CostChecker; use crate::deref_separator::deref_finder; use crate::simplify::simplify_cfg; -use crate::util; use crate::validate::validate_types; +use crate::{check_inline, util}; pub(crate) mod cycle; @@ -575,7 +575,7 @@ fn try_inlining<'tcx, I: Inliner<'tcx>>( check_mir_is_available(inliner, caller_body, callsite.callee)?; let callee_attrs = tcx.codegen_fn_attrs(callsite.callee.def_id()); - rustc_mir_build::check_inline::is_inline_valid_on_fn(tcx, callsite.callee.def_id())?; + check_inline::is_inline_valid_on_fn(tcx, callsite.callee.def_id())?; check_codegen_attributes(inliner, callsite, callee_attrs)?; let terminator = caller_body[callsite.block].terminator.as_ref().unwrap(); @@ -590,7 +590,7 @@ fn try_inlining<'tcx, I: Inliner<'tcx>>( } let callee_body = try_instance_mir(tcx, callsite.callee.def)?; - rustc_mir_build::check_inline::is_inline_valid_on_body(tcx, callee_body)?; + check_inline::is_inline_valid_on_body(tcx, callee_body)?; inliner.check_callee_mir_body(callsite, callee_body, callee_attrs)?; let Ok(callee_body) = callsite.callee.try_instantiate_mir_and_normalize_erasing_regions( diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index db999bea986..d1bacf1f598 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -114,6 +114,8 @@ declare_passes! { mod add_moves_for_packed_drops : AddMovesForPackedDrops; mod add_retag : AddRetag; mod add_subtyping_projections : Subtyper; + mod check_inline : CheckForceInline; + mod check_call_recursion : CheckCallRecursion, CheckDropRecursion; mod check_alignment : CheckAlignment; mod check_const_item_mutation : CheckConstItemMutation; mod check_packed_ref : CheckPackedRef; @@ -375,6 +377,8 @@ fn mir_built(tcx: TyCtxt<'_>, def: LocalDefId) -> &Steal<Body<'_>> { &mut body, &[ // MIR-level lints. + &Lint(check_inline::CheckForceInline), + &Lint(check_call_recursion::CheckCallRecursion), &Lint(check_packed_ref::CheckPackedRef), &Lint(check_const_item_mutation::CheckConstItemMutation), &Lint(function_item_references::FunctionItemReferences), @@ -505,10 +509,6 @@ fn mir_drops_elaborated_and_const_checked(tcx: TyCtxt<'_>, def: LocalDefId) -> & run_analysis_to_runtime_passes(tcx, &mut body); - // Now that drop elaboration has been performed, we can check for - // unconditional drop recursion. - rustc_mir_build::lints::check_drop_recursion(tcx, &body); - tcx.alloc_steal_mir(body) } @@ -570,6 +570,8 @@ fn run_runtime_lowering_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { // Calling this after `PostAnalysisNormalize` ensures that we don't deal with opaque types. &add_subtyping_projections::Subtyper, &elaborate_drops::ElaborateDrops, + // Needs to happen after drop elaboration. + &Lint(check_call_recursion::CheckDropRecursion), // This will remove extraneous landing pads which are no longer // necessary as well as forcing any call in a non-unwinding // function calling a possibly-unwinding function to abort the process. |
