diff options
Diffstat (limited to 'compiler/rustc_passes/src')
| -rw-r--r-- | compiler/rustc_passes/src/abi_test.rs | 1 | ||||
| -rw-r--r-- | compiler/rustc_passes/src/check_attr.rs | 180 | ||||
| -rw-r--r-- | compiler/rustc_passes/src/check_const.rs | 11 | ||||
| -rw-r--r-- | compiler/rustc_passes/src/dead.rs | 71 | ||||
| -rw-r--r-- | compiler/rustc_passes/src/diagnostic_items.rs | 2 | ||||
| -rw-r--r-- | compiler/rustc_passes/src/entry.rs | 83 | ||||
| -rw-r--r-- | compiler/rustc_passes/src/errors.rs | 56 | ||||
| -rw-r--r-- | compiler/rustc_passes/src/hir_stats.rs | 7 | ||||
| -rw-r--r-- | compiler/rustc_passes/src/lang_items.rs | 15 | ||||
| -rw-r--r-- | compiler/rustc_passes/src/layout_test.rs | 1 | ||||
| -rw-r--r-- | compiler/rustc_passes/src/lib.rs | 6 | ||||
| -rw-r--r-- | compiler/rustc_passes/src/liveness.rs | 11 | ||||
| -rw-r--r-- | compiler/rustc_passes/src/loops.rs | 210 | ||||
| -rw-r--r-- | compiler/rustc_passes/src/naked_functions.rs | 3 | ||||
| -rw-r--r-- | compiler/rustc_passes/src/reachable.rs | 34 | ||||
| -rw-r--r-- | compiler/rustc_passes/src/stability.rs | 6 | ||||
| -rw-r--r-- | compiler/rustc_passes/src/weak_lang_items.rs | 4 |
17 files changed, 438 insertions, 263 deletions
diff --git a/compiler/rustc_passes/src/abi_test.rs b/compiler/rustc_passes/src/abi_test.rs index 986ef69ad88..0c3dd649997 100644 --- a/compiler/rustc_passes/src/abi_test.rs +++ b/compiler/rustc_passes/src/abi_test.rs @@ -1,6 +1,7 @@ use rustc_ast::Attribute; use rustc_hir::def::DefKind; use rustc_hir::def_id::LocalDefId; +use rustc_middle::span_bug; use rustc_middle::ty::layout::{FnAbiError, LayoutError}; use rustc_middle::ty::{self, GenericArgs, Instance, Ty, TyCtxt}; use rustc_span::source_map::Spanned; diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 1254ae8cfc8..4fe84b91b8b 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -11,14 +11,15 @@ use rustc_data_structures::fx::FxHashMap; use rustc_errors::StashKey; use rustc_errors::{Applicability, DiagCtxt, IntoDiagArg, MultiSpan}; use rustc_feature::{AttributeDuplicates, AttributeType, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP}; -use rustc_hir as hir; use rustc_hir::def_id::LocalModDefId; use rustc_hir::intravisit::{self, Visitor}; +use rustc_hir::{self as hir}; use rustc_hir::{ self, FnSig, ForeignItem, HirId, Item, ItemKind, TraitItem, CRATE_HIR_ID, CRATE_OWNER_ID, }; -use rustc_hir::{MethodKind, Target, Unsafety}; +use rustc_hir::{MethodKind, Safety, Target}; use rustc_macros::LintDiagnostic; +use rustc_middle::bug; use rustc_middle::hir::nested_filter; use rustc_middle::middle::resolve_bound_vars::ObjectLifetimeDefault; use rustc_middle::query::Providers; @@ -38,15 +39,13 @@ use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt; use rustc_trait_selection::traits::ObligationCtxt; use std::cell::Cell; use std::collections::hash_map::Entry; +use tracing::debug; #[derive(LintDiagnostic)] #[diag(passes_diagnostic_diagnostic_on_unimplemented_only_for_traits)] -pub struct DiagnosticOnUnimplementedOnlyForTraits; +struct DiagnosticOnUnimplementedOnlyForTraits; -pub(crate) fn target_from_impl_item<'tcx>( - tcx: TyCtxt<'tcx>, - impl_item: &hir::ImplItem<'_>, -) -> Target { +fn target_from_impl_item<'tcx>(tcx: TyCtxt<'tcx>, impl_item: &hir::ImplItem<'_>) -> Target { match impl_item.kind { hir::ImplItemKind::Const(..) => Target::AssocConst, hir::ImplItemKind::Fn(..) => { @@ -98,7 +97,7 @@ struct CheckAttrVisitor<'tcx> { } impl<'tcx> CheckAttrVisitor<'tcx> { - pub fn dcx(&self) -> &'tcx DiagCtxt { + fn dcx(&self) -> &'tcx DiagCtxt { self.tcx.dcx() } @@ -115,92 +114,96 @@ impl<'tcx> CheckAttrVisitor<'tcx> { let mut seen = FxHashMap::default(); let attrs = self.tcx.hir().attrs(hir_id); for attr in attrs { - if attr.path_matches(&[sym::diagnostic, sym::on_unimplemented]) { - self.check_diagnostic_on_unimplemented(attr.span, hir_id, target); - } - match attr.name_or_empty() { - sym::do_not_recommend => self.check_do_not_recommend(attr.span, target), - sym::inline => self.check_inline(hir_id, attr, span, target), - sym::coverage => self.check_coverage(hir_id, attr, span, target), - sym::non_exhaustive => self.check_non_exhaustive(hir_id, attr, span, target), - sym::marker => self.check_marker(hir_id, attr, span, target), - sym::target_feature => self.check_target_feature(hir_id, attr, span, target, attrs), - sym::thread_local => self.check_thread_local(attr, span, target), - sym::track_caller => { + match attr.path().as_slice() { + [sym::diagnostic, sym::do_not_recommend] => { + self.check_do_not_recommend(attr.span, hir_id, target) + } + [sym::diagnostic, sym::on_unimplemented] => { + self.check_diagnostic_on_unimplemented(attr.span, hir_id, target) + } + [sym::inline] => self.check_inline(hir_id, attr, span, target), + [sym::coverage] => self.check_coverage(hir_id, attr, span, target), + [sym::non_exhaustive] => self.check_non_exhaustive(hir_id, attr, span, target), + [sym::marker] => self.check_marker(hir_id, attr, span, target), + [sym::target_feature] => { + self.check_target_feature(hir_id, attr, span, target, attrs) + } + [sym::thread_local] => self.check_thread_local(attr, span, target), + [sym::track_caller] => { self.check_track_caller(hir_id, attr.span, attrs, span, target) } - sym::doc => self.check_doc_attrs( + [sym::doc] => self.check_doc_attrs( attr, hir_id, target, &mut specified_inline, &mut doc_aliases, ), - sym::no_link => self.check_no_link(hir_id, attr, span, target), - sym::export_name => self.check_export_name(hir_id, attr, span, target), - sym::rustc_layout_scalar_valid_range_start - | sym::rustc_layout_scalar_valid_range_end => { + [sym::no_link] => self.check_no_link(hir_id, attr, span, target), + [sym::export_name] => self.check_export_name(hir_id, attr, span, target), + [sym::rustc_layout_scalar_valid_range_start] + | [sym::rustc_layout_scalar_valid_range_end] => { self.check_rustc_layout_scalar_valid_range(attr, span, target) } - sym::allow_internal_unstable => { + [sym::allow_internal_unstable] => { self.check_allow_internal_unstable(hir_id, attr, span, target, attrs) } - sym::debugger_visualizer => self.check_debugger_visualizer(attr, target), - sym::rustc_allow_const_fn_unstable => { + [sym::debugger_visualizer] => self.check_debugger_visualizer(attr, target), + [sym::rustc_allow_const_fn_unstable] => { self.check_rustc_allow_const_fn_unstable(hir_id, attr, span, target) } - sym::rustc_std_internal_symbol => { + [sym::rustc_std_internal_symbol] => { self.check_rustc_std_internal_symbol(attr, span, target) } - sym::naked => self.check_naked(hir_id, attr, span, target), - sym::rustc_never_returns_null_ptr => { + [sym::naked] => self.check_naked(hir_id, attr, span, target), + [sym::rustc_never_returns_null_ptr] => { self.check_applied_to_fn_or_method(hir_id, attr, span, target) } - sym::rustc_legacy_const_generics => { + [sym::rustc_legacy_const_generics] => { self.check_rustc_legacy_const_generics(hir_id, attr, span, target, item) } - sym::rustc_lint_query_instability => { + [sym::rustc_lint_query_instability] => { self.check_rustc_lint_query_instability(hir_id, attr, span, target) } - sym::rustc_lint_diagnostics => { + [sym::rustc_lint_diagnostics] => { self.check_rustc_lint_diagnostics(hir_id, attr, span, target) } - sym::rustc_lint_opt_ty => self.check_rustc_lint_opt_ty(attr, span, target), - sym::rustc_lint_opt_deny_field_access => { + [sym::rustc_lint_opt_ty] => self.check_rustc_lint_opt_ty(attr, span, target), + [sym::rustc_lint_opt_deny_field_access] => { self.check_rustc_lint_opt_deny_field_access(attr, span, target) } - sym::rustc_clean - | sym::rustc_dirty - | sym::rustc_if_this_changed - | sym::rustc_then_this_would_need => self.check_rustc_dirty_clean(attr), - sym::rustc_coinductive - | sym::rustc_must_implement_one_of - | sym::rustc_deny_explicit_impl - | sym::const_trait => self.check_must_be_applied_to_trait(attr, span, target), - sym::cmse_nonsecure_entry => { + [sym::rustc_clean] + | [sym::rustc_dirty] + | [sym::rustc_if_this_changed] + | [sym::rustc_then_this_would_need] => self.check_rustc_dirty_clean(attr), + [sym::rustc_coinductive] + | [sym::rustc_must_implement_one_of] + | [sym::rustc_deny_explicit_impl] + | [sym::const_trait] => self.check_must_be_applied_to_trait(attr, span, target), + [sym::cmse_nonsecure_entry] => { self.check_cmse_nonsecure_entry(hir_id, attr, span, target) } - sym::collapse_debuginfo => self.check_collapse_debuginfo(attr, span, target), - sym::must_not_suspend => self.check_must_not_suspend(attr, span, target), - sym::must_use => self.check_must_use(hir_id, attr, target), - sym::rustc_pass_by_value => self.check_pass_by_value(attr, span, target), - sym::rustc_allow_incoherent_impl => { + [sym::collapse_debuginfo] => self.check_collapse_debuginfo(attr, span, target), + [sym::must_not_suspend] => self.check_must_not_suspend(attr, span, target), + [sym::must_use] => self.check_must_use(hir_id, attr, target), + [sym::rustc_pass_by_value] => self.check_pass_by_value(attr, span, target), + [sym::rustc_allow_incoherent_impl] => { self.check_allow_incoherent_impl(attr, span, target) } - sym::rustc_has_incoherent_inherent_impls => { + [sym::rustc_has_incoherent_inherent_impls] => { self.check_has_incoherent_inherent_impls(attr, span, target) } - sym::ffi_pure => self.check_ffi_pure(attr.span, attrs, target), - sym::ffi_const => self.check_ffi_const(attr.span, target), - sym::rustc_const_unstable - | sym::rustc_const_stable - | sym::unstable - | sym::stable - | sym::rustc_allowed_through_unstable_modules - | sym::rustc_promotable => self.check_stability_promotable(attr, target), - sym::link_ordinal => self.check_link_ordinal(attr, span, target), - sym::rustc_confusables => self.check_confusables(attr, target), - sym::rustc_safe_intrinsic => { + [sym::ffi_pure] => self.check_ffi_pure(attr.span, attrs, target), + [sym::ffi_const] => self.check_ffi_const(attr.span, target), + [sym::rustc_const_unstable] + | [sym::rustc_const_stable] + | [sym::unstable] + | [sym::stable] + | [sym::rustc_allowed_through_unstable_modules] + | [sym::rustc_promotable] => self.check_stability_promotable(attr, target), + [sym::link_ordinal] => self.check_link_ordinal(attr, span, target), + [sym::rustc_confusables] => self.check_confusables(attr, target), + [sym::rustc_safe_intrinsic] => { self.check_rustc_safe_intrinsic(hir_id, attr, span, target) } _ => true, @@ -292,18 +295,26 @@ impl<'tcx> CheckAttrVisitor<'tcx> { ); } - /// Checks if `#[do_not_recommend]` is applied on a trait impl. - fn check_do_not_recommend(&self, attr_span: Span, target: Target) -> bool { - if let Target::Impl = target { - true - } else { - self.dcx().emit_err(errors::IncorrectDoNotRecommendLocation { span: attr_span }); - false + /// Checks if `#[diagnostic::do_not_recommend]` is applied on a trait impl. + fn check_do_not_recommend(&self, attr_span: Span, hir_id: HirId, target: Target) -> bool { + if !matches!(target, Target::Impl) { + self.tcx.emit_node_span_lint( + UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, + hir_id, + attr_span, + errors::IncorrectDoNotRecommendLocation, + ); } + true } /// Checks if `#[diagnostic::on_unimplemented]` is applied to a trait definition - fn check_diagnostic_on_unimplemented(&self, attr_span: Span, hir_id: HirId, target: Target) { + fn check_diagnostic_on_unimplemented( + &self, + attr_span: Span, + hir_id: HirId, + target: Target, + ) -> bool { if !matches!(target, Target::Trait) { self.tcx.emit_node_span_lint( UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, @@ -312,6 +323,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { DiagnosticOnUnimplementedOnlyForTraits, ); } + true } /// Checks if an `#[inline]` is applied to a function or a closure. Returns `true` if valid. @@ -519,7 +531,26 @@ impl<'tcx> CheckAttrVisitor<'tcx> { self.dcx().emit_err(errors::NakedTrackedCaller { attr_span }); false } - Target::Fn | Target::Method(..) | Target::ForeignFn | Target::Closure => true, + Target::Fn => { + // `#[track_caller]` is not valid on weak lang items because they are called via + // `extern` declarations and `#[track_caller]` would alter their ABI. + if let Some((lang_item, _)) = hir::lang_items::extract(attrs) + && let Some(item) = hir::LangItem::from_name(lang_item) + && item.is_weak() + { + let sig = self.tcx.hir_node(hir_id).fn_sig().unwrap(); + + self.dcx().emit_err(errors::LangItemWithTrackCaller { + attr_span, + name: lang_item, + sig_span: sig.span, + }); + false + } else { + true + } + } + Target::Method(..) | Target::ForeignFn | Target::Closure => true, // FIXME(#80564): We permit struct fields, match arms and macro defs to have an // `#[track_caller]` attribute with just a lint, because we previously // erroneously allowed it and some crates used it accidentally, to be compatible @@ -602,7 +633,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { ) -> bool { match target { Target::Fn => { - // `#[target_feature]` is not allowed in language items. + // `#[target_feature]` is not allowed in lang items. if let Some((lang_item, _)) = hir::lang_items::extract(attrs) // Calling functions with `#[target_feature]` is // not unsafe on WASM, see #84988 @@ -2315,7 +2346,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { }), token_stream, false, - Unsafety::Normal, + Safety::Safe, Abi::Rust, ); @@ -2342,7 +2373,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { cause.span = ty.span; } } - TypeError::UnsafetyMismatch(_) => { + TypeError::SafetyMismatch(_) => { // FIXME: Would be nice if we had a span here.. } TypeError::AbiMismatch(_) => { @@ -2503,7 +2534,6 @@ fn check_invalid_crate_level_attr(tcx: TyCtxt<'_>, attrs: &[Attribute]) { sym::automatically_derived, sym::start, sym::rustc_main, - sym::unix_sigpipe, sym::derive, sym::test, sym::test_case, diff --git a/compiler/rustc_passes/src/check_const.rs b/compiler/rustc_passes/src/check_const.rs index 4a1a2049083..fa2c8f69c71 100644 --- a/compiler/rustc_passes/src/check_const.rs +++ b/compiler/rustc_passes/src/check_const.rs @@ -13,6 +13,7 @@ use rustc_hir::def_id::{LocalDefId, LocalModDefId}; use rustc_hir::intravisit::{self, Visitor}; use rustc_middle::hir::nested_filter; use rustc_middle::query::Providers; +use rustc_middle::span_bug; use rustc_middle::ty::TyCtxt; use rustc_session::parse::feature_err; use rustc_span::{sym, Span, Symbol}; @@ -195,11 +196,6 @@ impl<'tcx> Visitor<'tcx> for CheckConstVisitor<'tcx> { self.recurse_into(kind, None, |this| intravisit::walk_anon_const(this, anon)); } - fn visit_inline_const(&mut self, block: &'tcx hir::ConstBlock) { - let kind = Some(hir::ConstContext::Const { inline: true }); - self.recurse_into(kind, None, |this| intravisit::walk_inline_const(this, block)); - } - fn visit_body(&mut self, body: &'tcx hir::Body<'tcx>) { let owner = self.tcx.hir().body_owner_def_id(body.id()); let kind = self.tcx.hir().body_const_context(owner); @@ -227,6 +223,11 @@ impl<'tcx> Visitor<'tcx> for CheckConstVisitor<'tcx> { self.const_check_violated(expr, e.span); } } + hir::ExprKind::ConstBlock(expr) => { + let kind = Some(hir::ConstContext::Const { inline: true }); + self.recurse_into(kind, None, |this| intravisit::walk_expr(this, expr)); + return; + } _ => {} } diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index 51f288b3c95..0049afff528 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -16,6 +16,7 @@ use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::middle::privacy::Level; use rustc_middle::query::Providers; use rustc_middle::ty::{self, TyCtxt}; +use rustc_middle::{bug, span_bug}; use rustc_session::lint; use rustc_session::lint::builtin::DEAD_CODE; use rustc_span::symbol::{sym, Symbol}; @@ -424,10 +425,11 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { && let ItemKind::Impl(impl_ref) = self.tcx.hir().expect_item(local_impl_id).kind { - if self.tcx.visibility(trait_id).is_public() - && matches!(trait_item.kind, hir::TraitItemKind::Fn(..)) + if matches!(trait_item.kind, hir::TraitItemKind::Fn(..)) && !ty_ref_to_pub_struct(self.tcx, impl_ref.self_ty) { + // skip methods of private ty, + // they would be solved in `solve_rest_impl_items` continue; } @@ -484,32 +486,46 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { fn solve_rest_impl_items(&mut self, mut unsolved_impl_items: Vec<(hir::ItemId, LocalDefId)>) { let mut ready; - (ready, unsolved_impl_items) = unsolved_impl_items - .into_iter() - .partition(|&(impl_id, _)| self.impl_item_with_used_self(impl_id)); + (ready, unsolved_impl_items) = + unsolved_impl_items.into_iter().partition(|&(impl_id, impl_item_id)| { + self.impl_item_with_used_self(impl_id, impl_item_id) + }); while !ready.is_empty() { self.worklist = ready.into_iter().map(|(_, id)| (id, ComesFromAllowExpect::No)).collect(); self.mark_live_symbols(); - (ready, unsolved_impl_items) = unsolved_impl_items - .into_iter() - .partition(|&(impl_id, _)| self.impl_item_with_used_self(impl_id)); + (ready, unsolved_impl_items) = + unsolved_impl_items.into_iter().partition(|&(impl_id, impl_item_id)| { + self.impl_item_with_used_self(impl_id, impl_item_id) + }); } } - fn impl_item_with_used_self(&mut self, impl_id: hir::ItemId) -> bool { + fn impl_item_with_used_self(&mut self, impl_id: hir::ItemId, impl_item_id: LocalDefId) -> bool { if let TyKind::Path(hir::QPath::Resolved(_, path)) = self.tcx.hir().item(impl_id).expect_impl().self_ty.kind && let Res::Def(def_kind, def_id) = path.res && let Some(local_def_id) = def_id.as_local() && matches!(def_kind, DefKind::Struct | DefKind::Enum | DefKind::Union) { - self.live_symbols.contains(&local_def_id) - } else { - false + if self.tcx.visibility(impl_item_id).is_public() { + // for the public method, we don't know the trait item is used or not, + // so we mark the method live if the self is used + return self.live_symbols.contains(&local_def_id); + } + + if let Some(trait_item_id) = self.tcx.associated_item(impl_item_id).trait_item_def_id + && let Some(local_id) = trait_item_id.as_local() + { + // for the private method, we can know the trait item is used or not, + // so we mark the method live if the self is used and the trait item is used + return self.live_symbols.contains(&local_id) + && self.live_symbols.contains(&local_def_id); + } } + false } } @@ -571,6 +587,16 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> { hir::ExprKind::OffsetOf(..) => { self.handle_offset_of(expr); } + hir::ExprKind::ConstBlock(expr) => { + // When inline const blocks are used in pattern position, paths + // referenced by it should be considered as used. + let in_pat = mem::replace(&mut self.in_pat, false); + + intravisit::walk_expr(self, expr); + + self.in_pat = in_pat; + return; + } _ => (), } @@ -632,17 +658,6 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> { self.in_pat = in_pat; } - - fn visit_inline_const(&mut self, c: &'tcx hir::ConstBlock) { - // When inline const blocks are used in pattern position, paths - // referenced by it should be considered as used. - let in_pat = mem::replace(&mut self.in_pat, false); - - self.live_symbols.insert(c.def_id); - intravisit::walk_inline_const(self, c); - - self.in_pat = in_pat; - } } fn has_allow_dead_code_or_lang_attr( @@ -744,20 +759,22 @@ fn check_item<'tcx>( matches!(fn_sig.decl.implicit_self, hir::ImplicitSelfKind::None); } - // for impl trait blocks, mark associate functions live if the trait is public + // for trait impl blocks, + // mark the method live if the self_ty is public, + // or the method is public and may construct self if of_trait && (!matches!(tcx.def_kind(local_def_id), DefKind::AssocFn) || tcx.visibility(local_def_id).is_public() && (ty_is_pub || may_construct_self)) { worklist.push((local_def_id, ComesFromAllowExpect::No)); - } else if of_trait && tcx.visibility(local_def_id).is_public() { - // pub method && private ty & methods not construct self - unsolved_impl_items.push((id, local_def_id)); } else if let Some(comes_from_allow) = has_allow_dead_code_or_lang_attr(tcx, local_def_id) { worklist.push((local_def_id, comes_from_allow)); + } else if of_trait { + // private method || public method not constructs self + unsolved_impl_items.push((id, local_def_id)); } } } diff --git a/compiler/rustc_passes/src/diagnostic_items.rs b/compiler/rustc_passes/src/diagnostic_items.rs index 906ecdfe5ab..78653e5f95a 100644 --- a/compiler/rustc_passes/src/diagnostic_items.rs +++ b/compiler/rustc_passes/src/diagnostic_items.rs @@ -82,7 +82,7 @@ fn all_diagnostic_items(tcx: TyCtxt<'_>, (): ()) -> DiagnosticItems { let mut items = DiagnosticItems::default(); // Collect diagnostic items in other crates. - for &cnum in tcx.crates(()).iter().chain(std::iter::once(&LOCAL_CRATE)) { + for &cnum in tcx.crates_including_speculative(()).iter().chain(std::iter::once(&LOCAL_CRATE)) { for (&name, &def_id) in &tcx.diagnostic_items(cnum).name_to_id { collect_item(tcx, &mut items, name, def_id); } diff --git a/compiler/rustc_passes/src/entry.rs b/compiler/rustc_passes/src/entry.rs index 438c583db49..b43c8282db1 100644 --- a/compiler/rustc_passes/src/entry.rs +++ b/compiler/rustc_passes/src/entry.rs @@ -12,17 +12,16 @@ use rustc_span::symbol::sym; use rustc_span::{Span, Symbol}; use crate::errors::{ - AttrOnlyInFunctions, AttrOnlyOnMain, AttrOnlyOnRootMain, ExternMain, MultipleRustcMain, - MultipleStartFunctions, NoMainErr, UnixSigpipeValues, + AttrOnlyInFunctions, ExternMain, MultipleRustcMain, MultipleStartFunctions, NoMainErr, }; struct EntryContext<'tcx> { tcx: TyCtxt<'tcx>, - /// The function that has attribute named `main`. - attr_main_fn: Option<(LocalDefId, Span)>, + /// The function has the `#[rustc_main]` attribute. + rustc_main_fn: Option<(LocalDefId, Span)>, - /// The function that has the attribute 'start' on it. + /// The function that has the attribute `#[start]` on it. start_fn: Option<(LocalDefId, Span)>, /// The functions that one might think are `main` but aren't, e.g. @@ -43,10 +42,10 @@ fn entry_fn(tcx: TyCtxt<'_>, (): ()) -> Option<(DefId, EntryFnType)> { } let mut ctxt = - EntryContext { tcx, attr_main_fn: None, start_fn: None, non_main_fns: Vec::new() }; + EntryContext { tcx, rustc_main_fn: None, start_fn: None, non_main_fns: Vec::new() }; for id in tcx.hir().items() { - find_item(id, &mut ctxt); + check_and_search_item(id, &mut ctxt); } configure_main(tcx, &ctxt) @@ -57,7 +56,16 @@ fn attr_span_by_symbol(ctxt: &EntryContext<'_>, id: ItemId, sym: Symbol) -> Opti attr::find_by_name(attrs, sym).map(|attr| attr.span) } -fn find_item(id: ItemId, ctxt: &mut EntryContext<'_>) { +fn check_and_search_item(id: ItemId, ctxt: &mut EntryContext<'_>) { + if !matches!(ctxt.tcx.def_kind(id.owner_id), DefKind::Fn) { + for attr in [sym::start, sym::rustc_main] { + if let Some(span) = attr_span_by_symbol(ctxt, id, attr) { + ctxt.tcx.dcx().emit_err(AttrOnlyInFunctions { span, attr }); + } + } + return; + } + let at_root = ctxt.tcx.opt_local_parent(id.owner_id.def_id) == Some(CRATE_DEF_ID); let attrs = ctxt.tcx.hir().attrs(id.hir_id()); @@ -66,41 +74,25 @@ fn find_item(id: ItemId, ctxt: &mut EntryContext<'_>) { at_root, ctxt.tcx.opt_item_name(id.owner_id.to_def_id()), ); + match entry_point_type { - EntryPointType::None => { - if let Some(span) = attr_span_by_symbol(ctxt, id, sym::unix_sigpipe) { - ctxt.tcx.dcx().emit_err(AttrOnlyOnMain { span, attr: sym::unix_sigpipe }); - } - } - _ if !matches!(ctxt.tcx.def_kind(id.owner_id), DefKind::Fn) => { - for attr in [sym::start, sym::rustc_main] { - if let Some(span) = attr_span_by_symbol(ctxt, id, attr) { - ctxt.tcx.dcx().emit_err(AttrOnlyInFunctions { span, attr }); - } - } - } - EntryPointType::MainNamed => (), + EntryPointType::None => {} + EntryPointType::MainNamed => {} EntryPointType::OtherMain => { - if let Some(span) = attr_span_by_symbol(ctxt, id, sym::unix_sigpipe) { - ctxt.tcx.dcx().emit_err(AttrOnlyOnRootMain { span, attr: sym::unix_sigpipe }); - } ctxt.non_main_fns.push(ctxt.tcx.def_span(id.owner_id)); } EntryPointType::RustcMainAttr => { - if ctxt.attr_main_fn.is_none() { - ctxt.attr_main_fn = Some((id.owner_id.def_id, ctxt.tcx.def_span(id.owner_id))); + if ctxt.rustc_main_fn.is_none() { + ctxt.rustc_main_fn = Some((id.owner_id.def_id, ctxt.tcx.def_span(id.owner_id))); } else { ctxt.tcx.dcx().emit_err(MultipleRustcMain { span: ctxt.tcx.def_span(id.owner_id.to_def_id()), - first: ctxt.attr_main_fn.unwrap().1, + first: ctxt.rustc_main_fn.unwrap().1, additional: ctxt.tcx.def_span(id.owner_id.to_def_id()), }); } } EntryPointType::Start => { - if let Some(span) = attr_span_by_symbol(ctxt, id, sym::unix_sigpipe) { - ctxt.tcx.dcx().emit_err(AttrOnlyOnMain { span, attr: sym::unix_sigpipe }); - } if ctxt.start_fn.is_none() { ctxt.start_fn = Some((id.owner_id.def_id, ctxt.tcx.def_span(id.owner_id))); } else { @@ -118,10 +110,11 @@ fn find_item(id: ItemId, ctxt: &mut EntryContext<'_>) { fn configure_main(tcx: TyCtxt<'_>, visitor: &EntryContext<'_>) -> Option<(DefId, EntryFnType)> { if let Some((def_id, _)) = visitor.start_fn { Some((def_id.to_def_id(), EntryFnType::Start)) - } else if let Some((local_def_id, _)) = visitor.attr_main_fn { + } else if let Some((local_def_id, _)) = visitor.rustc_main_fn { let def_id = local_def_id.to_def_id(); - Some((def_id, EntryFnType::Main { sigpipe: sigpipe(tcx, def_id) })) + Some((def_id, EntryFnType::Main { sigpipe: sigpipe(tcx) })) } else { + // The actual resolution of main happens in the resolver, this here if let Some(main_def) = tcx.resolutions(()).main_def && let Some(def_id) = main_def.opt_fn_def_id() { @@ -133,31 +126,19 @@ fn configure_main(tcx: TyCtxt<'_>, visitor: &EntryContext<'_>) -> Option<(DefId, return None; } - return Some((def_id, EntryFnType::Main { sigpipe: sigpipe(tcx, def_id) })); + return Some((def_id, EntryFnType::Main { sigpipe: sigpipe(tcx) })); } no_main_err(tcx, visitor); None } } -fn sigpipe(tcx: TyCtxt<'_>, def_id: DefId) -> u8 { - if let Some(attr) = tcx.get_attr(def_id, sym::unix_sigpipe) { - match (attr.value_str(), attr.meta_item_list()) { - (Some(sym::inherit), None) => sigpipe::INHERIT, - (Some(sym::sig_ign), None) => sigpipe::SIG_IGN, - (Some(sym::sig_dfl), None) => sigpipe::SIG_DFL, - (Some(_), None) => { - tcx.dcx().emit_err(UnixSigpipeValues { span: attr.span }); - sigpipe::DEFAULT - } - _ => { - // Keep going so that `fn emit_malformed_attribute()` can print - // an excellent error message - sigpipe::DEFAULT - } - } - } else { - sigpipe::DEFAULT +fn sigpipe(tcx: TyCtxt<'_>) -> u8 { + match tcx.sess.opts.unstable_opts.on_broken_pipe { + rustc_target::spec::OnBrokenPipe::Default => sigpipe::DEFAULT, + rustc_target::spec::OnBrokenPipe::Kill => sigpipe::SIG_DFL, + rustc_target::spec::OnBrokenPipe::Error => sigpipe::SIG_IGN, + rustc_target::spec::OnBrokenPipe::Inherit => sigpipe::INHERIT, } } diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 3f26ea4507d..7fdd9924b51 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -17,12 +17,9 @@ use rustc_span::{Span, Symbol, DUMMY_SP}; use crate::check_attr::ProcMacroKind; use crate::lang_items::Duplicate; -#[derive(Diagnostic)] +#[derive(LintDiagnostic)] #[diag(passes_incorrect_do_not_recommend_location)] -pub struct IncorrectDoNotRecommendLocation { - #[primary_span] - pub span: Span, -} +pub struct IncorrectDoNotRecommendLocation; #[derive(LintDiagnostic)] #[diag(passes_outer_crate_level_attr)] @@ -820,6 +817,16 @@ pub struct MissingLangItem { } #[derive(Diagnostic)] +#[diag(passes_lang_item_fn_with_track_caller)] +pub struct LangItemWithTrackCaller { + #[primary_span] + pub attr_span: Span, + pub name: Symbol, + #[label] + pub sig_span: Span, +} + +#[derive(Diagnostic)] #[diag(passes_lang_item_fn_with_target_feature)] pub struct LangItemWithTargetFeature { #[primary_span] @@ -1076,14 +1083,16 @@ pub struct BreakInsideClosure<'a> { } #[derive(Diagnostic)] -#[diag(passes_break_inside_async_block, code = E0267)] -pub struct BreakInsideAsyncBlock<'a> { +#[diag(passes_break_inside_coroutine, code = E0267)] +pub struct BreakInsideCoroutine<'a> { #[primary_span] #[label] pub span: Span, - #[label(passes_async_block_label)] - pub closure_span: Span, + #[label(passes_coroutine_label)] + pub coroutine_span: Span, pub name: &'a str, + pub kind: &'a str, + pub source: &'a str, } #[derive(Diagnostic)] @@ -1091,7 +1100,7 @@ pub struct BreakInsideAsyncBlock<'a> { pub struct OutsideLoop<'a> { #[primary_span] #[label] - pub span: Span, + pub spans: Vec<Span>, pub name: &'a str, pub is_break: bool, #[subdiagnostic] @@ -1103,7 +1112,7 @@ pub struct OutsideLoopSuggestion { #[suggestion_part(code = "'block: ")] pub block_span: Span, #[suggestion_part(code = " 'block")] - pub break_span: Span, + pub break_spans: Vec<Span>, } #[derive(Diagnostic)] @@ -1197,22 +1206,6 @@ pub struct NakedFunctionsMustUseNoreturn { } #[derive(Diagnostic)] -#[diag(passes_attr_only_on_main)] -pub struct AttrOnlyOnMain { - #[primary_span] - pub span: Span, - pub attr: Symbol, -} - -#[derive(Diagnostic)] -#[diag(passes_attr_only_on_root_main)] -pub struct AttrOnlyOnRootMain { - #[primary_span] - pub span: Span, - pub attr: Symbol, -} - -#[derive(Diagnostic)] #[diag(passes_attr_only_in_functions)] pub struct AttrOnlyInFunctions { #[primary_span] @@ -1249,13 +1242,6 @@ pub struct ExternMain { pub span: Span, } -#[derive(Diagnostic)] -#[diag(passes_unix_sigpipe_values)] -pub struct UnixSigpipeValues { - #[primary_span] - pub span: Span, -} - pub struct NoMainErr { pub sp: Span, pub crate_name: Symbol, @@ -1755,7 +1741,7 @@ impl Subdiagnostic for UnusedVariableStringInterp { fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>( self, diag: &mut Diag<'_, G>, - _f: F, + _f: &F, ) { diag.span_label(self.lit, crate::fluent_generated::passes_maybe_string_interpolation); diag.multipart_suggestion( diff --git a/compiler/rustc_passes/src/hir_stats.rs b/compiler/rustc_passes/src/hir_stats.rs index 49408c5618b..a980d5dcaba 100644 --- a/compiler/rustc_passes/src/hir_stats.rs +++ b/compiler/rustc_passes/src/hir_stats.rs @@ -498,7 +498,7 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> { (self, i, i.kind, Id::None, ast, ForeignItem, ForeignItemKind), [Static, Fn, TyAlias, MacCall] ); - ast_visit::walk_foreign_item(self, i) + ast_visit::walk_item(self, i) } fn visit_item(&mut self, i: &'v ast::Item) { @@ -522,7 +522,8 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> { Impl, MacCall, MacroDef, - Delegation + Delegation, + DelegationMac ] ); ast_visit::walk_item(self, i) @@ -650,7 +651,7 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> { fn visit_assoc_item(&mut self, i: &'v ast::AssocItem, ctxt: ast_visit::AssocCtxt) { record_variants!( (self, i, i.kind, Id::None, ast, AssocItem, AssocItemKind), - [Const, Fn, Type, MacCall, Delegation] + [Const, Fn, Type, MacCall, Delegation, DelegationMac] ); ast_visit::walk_assoc_item(self, i, ctxt); } diff --git a/compiler/rustc_passes/src/lang_items.rs b/compiler/rustc_passes/src/lang_items.rs index d1368267224..b3722e99e16 100644 --- a/compiler/rustc_passes/src/lang_items.rs +++ b/compiler/rustc_passes/src/lang_items.rs @@ -1,4 +1,4 @@ -//! Detecting language items. +//! Detecting lang items. //! //! Language items are items that represent concepts intrinsic to the language //! itself. Examples are: @@ -149,8 +149,9 @@ impl<'ast, 'tcx> LanguageItemCollector<'ast, 'tcx> { } }; - // When there's a duplicate lang item, something went very wrong and there's no value in recovering or doing anything. - // Give the user the one message to let them debug the mess they created and then wish them farewell. + // When there's a duplicate lang item, something went very wrong and there's no value + // in recovering or doing anything. Give the user the one message to let them debug the + // mess they created and then wish them farewell. self.tcx.dcx().emit_fatal(DuplicateLangItem { local_span: item_span, lang_item_name, @@ -285,7 +286,9 @@ impl<'ast, 'tcx> visit::Visitor<'ast> for LanguageItemCollector<'ast, 'tcx> { ast::ItemKind::TraitAlias(_, _) => Target::TraitAlias, ast::ItemKind::Impl(_) => Target::Impl, ast::ItemKind::MacroDef(_) => Target::MacroDef, - ast::ItemKind::MacCall(_) => unreachable!("macros should have been expanded"), + ast::ItemKind::MacCall(_) | ast::ItemKind::DelegationMac(_) => { + unreachable!("macros should have been expanded") + } }; self.check_for_lang( @@ -340,7 +343,9 @@ impl<'ast, 'tcx> visit::Visitor<'ast> for LanguageItemCollector<'ast, 'tcx> { } ast::AssocItemKind::Const(ct) => (Target::AssocConst, Some(&ct.generics)), ast::AssocItemKind::Type(ty) => (Target::AssocTy, Some(&ty.generics)), - ast::AssocItemKind::MacCall(_) => unreachable!("macros should have been expanded"), + ast::AssocItemKind::MacCall(_) | ast::AssocItemKind::DelegationMac(_) => { + unreachable!("macros should have been expanded") + } }; self.check_for_lang( diff --git a/compiler/rustc_passes/src/layout_test.rs b/compiler/rustc_passes/src/layout_test.rs index 8d223c23363..82d43f078ee 100644 --- a/compiler/rustc_passes/src/layout_test.rs +++ b/compiler/rustc_passes/src/layout_test.rs @@ -1,6 +1,7 @@ use rustc_ast::Attribute; use rustc_hir::def::DefKind; use rustc_hir::def_id::LocalDefId; +use rustc_middle::span_bug; use rustc_middle::ty::layout::{HasParamEnv, HasTyCtxt, LayoutError, LayoutOfHelpers, TyAndLayout}; use rustc_middle::ty::{self, ParamEnv, Ty, TyCtxt}; use rustc_span::source_map::Spanned; diff --git a/compiler/rustc_passes/src/lib.rs b/compiler/rustc_passes/src/lib.rs index e03052bcfed..045a0a1525b 100644 --- a/compiler/rustc_passes/src/lib.rs +++ b/compiler/rustc_passes/src/lib.rs @@ -8,16 +8,10 @@ #![doc(rust_logo)] #![feature(rustdoc_internals)] #![allow(internal_features)] -#![feature(generic_nonzero)] #![feature(let_chains)] #![feature(map_try_insert)] #![feature(try_blocks)] -#[macro_use] -extern crate rustc_middle; -#[macro_use] -extern crate tracing; - use rustc_middle::query::Providers; pub mod abi_test; diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs index c7729302783..1f966be26ff 100644 --- a/compiler/rustc_passes/src/liveness.rs +++ b/compiler/rustc_passes/src/liveness.rs @@ -94,14 +94,15 @@ use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{Expr, HirId, HirIdMap, HirIdSet}; use rustc_index::IndexVec; use rustc_middle::query::Providers; +use rustc_middle::span_bug; use rustc_middle::ty::{self, RootVariableMinCaptureList, Ty, TyCtxt}; use rustc_session::lint; use rustc_span::symbol::{kw, sym, Symbol}; use rustc_span::{BytePos, Span}; - use std::io; use std::io::prelude::*; use std::rc::Rc; +use tracing::{debug, instrument}; mod rwu_table; @@ -146,6 +147,11 @@ fn check_liveness(tcx: TyCtxt<'_>, def_id: LocalDefId) { return; } + // Don't run for inline consts, they are collected together with their parent + if let DefKind::InlineConst = tcx.def_kind(def_id) { + return; + } + // Don't run unused pass for #[naked] if tcx.has_attr(def_id.to_def_id(), sym::naked) { return; @@ -1143,12 +1149,13 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { } hir::ExprKind::Lit(..) - | hir::ExprKind::ConstBlock(..) | hir::ExprKind::Err(_) | hir::ExprKind::Path(hir::QPath::TypeRelative(..)) | hir::ExprKind::Path(hir::QPath::LangItem(..)) | hir::ExprKind::OffsetOf(..) => succ, + hir::ExprKind::ConstBlock(expr) => self.propagate_through_expr(expr, succ), + // Note that labels have been resolved, so we don't need to look // at the label ident hir::ExprKind::Block(ref blk, _) => self.propagate_through_block(blk, succ), diff --git a/compiler/rustc_passes/src/loops.rs b/compiler/rustc_passes/src/loops.rs index e10a22cdf31..737310e5c04 100644 --- a/compiler/rustc_passes/src/loops.rs +++ b/compiler/rustc_passes/src/loops.rs @@ -1,3 +1,5 @@ +use std::collections::BTreeMap; +use std::fmt; use Context::*; use rustc_hir as hir; @@ -6,13 +8,14 @@ use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{Destination, Node}; use rustc_middle::hir::nested_filter; use rustc_middle::query::Providers; +use rustc_middle::span_bug; use rustc_middle::ty::TyCtxt; use rustc_session::Session; use rustc_span::hygiene::DesugaringKind; use rustc_span::{BytePos, Span}; use crate::errors::{ - BreakInsideAsyncBlock, BreakInsideClosure, BreakNonLoop, ContinueLabeledBlock, OutsideLoop, + BreakInsideClosure, BreakInsideCoroutine, BreakNonLoop, ContinueLabeledBlock, OutsideLoop, OutsideLoopSuggestion, UnlabeledCfInWhileCondition, UnlabeledInLabeledBlock, }; @@ -22,24 +25,57 @@ enum Context { Fn, Loop(hir::LoopSource), Closure(Span), - AsyncClosure(Span), + Coroutine { coroutine_span: Span, kind: hir::CoroutineDesugaring, source: hir::CoroutineSource }, UnlabeledBlock(Span), + UnlabeledIfBlock(Span), LabeledBlock, Constant, } -#[derive(Copy, Clone)] +#[derive(Clone)] +struct BlockInfo { + name: String, + spans: Vec<Span>, + suggs: Vec<Span>, +} + +#[derive(PartialEq)] +enum BreakContextKind { + Break, + Continue, +} + +impl fmt::Display for BreakContextKind { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + BreakContextKind::Break => "break", + BreakContextKind::Continue => "continue", + } + .fmt(f) + } +} + +#[derive(Clone)] struct CheckLoopVisitor<'a, 'tcx> { sess: &'a Session, tcx: TyCtxt<'tcx>, - cx: Context, + // Keep track of a stack of contexts, so that suggestions + // are not made for contexts where it would be incorrect, + // such as adding a label for an `if`. + // e.g. `if 'foo: {}` would be incorrect. + cx_stack: Vec<Context>, + block_breaks: BTreeMap<Span, BlockInfo>, } fn check_mod_loops(tcx: TyCtxt<'_>, module_def_id: LocalModDefId) { - tcx.hir().visit_item_likes_in_module( - module_def_id, - &mut CheckLoopVisitor { sess: tcx.sess, tcx, cx: Normal }, - ); + let mut check = CheckLoopVisitor { + sess: tcx.sess, + tcx, + cx_stack: vec![Normal], + block_breaks: Default::default(), + }; + tcx.hir().visit_item_likes_in_module(module_def_id, &mut check); + check.report_outside_loop_error(); } pub(crate) fn provide(providers: &mut Providers) { @@ -57,10 +93,6 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> { self.with_context(Constant, |v| intravisit::walk_anon_const(v, c)); } - fn visit_inline_const(&mut self, c: &'hir hir::ConstBlock) { - self.with_context(Constant, |v| intravisit::walk_inline_const(v, c)); - } - fn visit_fn( &mut self, fk: hir::intravisit::FnKind<'hir>, @@ -82,18 +114,55 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> { fn visit_expr(&mut self, e: &'hir hir::Expr<'hir>) { match e.kind { + hir::ExprKind::If(cond, then, else_opt) => { + self.visit_expr(cond); + + let get_block = |ck_loop: &CheckLoopVisitor<'a, 'hir>, + expr: &hir::Expr<'hir>| + -> Option<&hir::Block<'hir>> { + if let hir::ExprKind::Block(b, None) = expr.kind + && matches!( + ck_loop.cx_stack.last(), + Some(&Normal) + | Some(&Constant) + | Some(&UnlabeledBlock(_)) + | Some(&UnlabeledIfBlock(_)) + ) + { + Some(b) + } else { + None + } + }; + + if let Some(b) = get_block(self, then) { + self.with_context(UnlabeledIfBlock(b.span.shrink_to_lo()), |v| { + v.visit_block(b) + }); + } else { + self.visit_expr(then); + } + + if let Some(else_expr) = else_opt { + if let Some(b) = get_block(self, else_expr) { + self.with_context(UnlabeledIfBlock(b.span.shrink_to_lo()), |v| { + v.visit_block(b) + }); + } else { + self.visit_expr(else_expr); + } + } + } hir::ExprKind::Loop(ref b, _, source, _) => { self.with_context(Loop(source), |v| v.visit_block(b)); } hir::ExprKind::Closure(&hir::Closure { ref fn_decl, body, fn_decl_span, kind, .. }) => { - // FIXME(coroutines): This doesn't handle coroutines correctly let cx = match kind { - hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared( - hir::CoroutineDesugaring::Async, - hir::CoroutineSource::Block, - )) => AsyncClosure(fn_decl_span), + hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(kind, source)) => { + Coroutine { coroutine_span: fn_decl_span, kind, source } + } _ => Closure(fn_decl_span), }; self.visit_fn_decl(fn_decl); @@ -102,11 +171,14 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> { hir::ExprKind::Block(ref b, Some(_label)) => { self.with_context(LabeledBlock, |v| v.visit_block(b)); } - hir::ExprKind::Block(ref b, None) if matches!(self.cx, Fn) => { + hir::ExprKind::Block(ref b, None) if matches!(self.cx_stack.last(), Some(&Fn)) => { self.with_context(Normal, |v| v.visit_block(b)); } hir::ExprKind::Block(ref b, None) - if matches!(self.cx, Normal | Constant | UnlabeledBlock(_)) => + if matches!( + self.cx_stack.last(), + Some(&Normal) | Some(&Constant) | Some(&UnlabeledBlock(_)) + ) => { self.with_context(UnlabeledBlock(b.span.shrink_to_lo()), |v| v.visit_block(b)); } @@ -179,7 +251,12 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> { Some(label) => sp_lo.with_hi(label.ident.span.hi()), None => sp_lo.shrink_to_lo(), }; - self.require_break_cx("break", e.span, label_sp); + self.require_break_cx( + BreakContextKind::Break, + e.span, + label_sp, + self.cx_stack.len() - 1, + ); } hir::ExprKind::Continue(destination) => { self.require_label_in_labeled_block(e.span, &destination, "continue"); @@ -201,7 +278,15 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> { } Err(_) => {} } - self.require_break_cx("continue", e.span, e.span) + self.require_break_cx( + BreakContextKind::Continue, + e.span, + e.span, + self.cx_stack.len() - 1, + ) + } + hir::ExprKind::ConstBlock(expr) => { + self.with_context(Constant, |v| intravisit::walk_expr(v, expr)); } _ => intravisit::walk_expr(self, e), } @@ -213,28 +298,67 @@ impl<'a, 'hir> CheckLoopVisitor<'a, 'hir> { where F: FnOnce(&mut CheckLoopVisitor<'a, 'hir>), { - let old_cx = self.cx; - self.cx = cx; + self.cx_stack.push(cx); f(self); - self.cx = old_cx; + self.cx_stack.pop(); } - fn require_break_cx(&self, name: &str, span: Span, break_span: Span) { - let is_break = name == "break"; - match self.cx { + fn require_break_cx( + &mut self, + br_cx_kind: BreakContextKind, + span: Span, + break_span: Span, + cx_pos: usize, + ) { + match self.cx_stack[cx_pos] { LabeledBlock | Loop(_) => {} Closure(closure_span) => { - self.sess.dcx().emit_err(BreakInsideClosure { span, closure_span, name }); + self.sess.dcx().emit_err(BreakInsideClosure { + span, + closure_span, + name: &br_cx_kind.to_string(), + }); + } + Coroutine { coroutine_span, kind, source } => { + let kind = match kind { + hir::CoroutineDesugaring::Async => "async", + hir::CoroutineDesugaring::Gen => "gen", + hir::CoroutineDesugaring::AsyncGen => "async gen", + }; + let source = match source { + hir::CoroutineSource::Block => "block", + hir::CoroutineSource::Closure => "closure", + hir::CoroutineSource::Fn => "function", + }; + self.sess.dcx().emit_err(BreakInsideCoroutine { + span, + coroutine_span, + name: &br_cx_kind.to_string(), + kind, + source, + }); } - AsyncClosure(closure_span) => { - self.sess.dcx().emit_err(BreakInsideAsyncBlock { span, closure_span, name }); + UnlabeledBlock(block_span) + if br_cx_kind == BreakContextKind::Break && block_span.eq_ctxt(break_span) => + { + let block = self.block_breaks.entry(block_span).or_insert_with(|| BlockInfo { + name: br_cx_kind.to_string(), + spans: vec![], + suggs: vec![], + }); + block.spans.push(span); + block.suggs.push(break_span); } - UnlabeledBlock(block_span) if is_break && block_span.eq_ctxt(break_span) => { - let suggestion = Some(OutsideLoopSuggestion { block_span, break_span }); - self.sess.dcx().emit_err(OutsideLoop { span, name, is_break, suggestion }); + UnlabeledIfBlock(_) if br_cx_kind == BreakContextKind::Break => { + self.require_break_cx(br_cx_kind, span, break_span, cx_pos - 1); } - Normal | Constant | Fn | UnlabeledBlock(_) => { - self.sess.dcx().emit_err(OutsideLoop { span, name, is_break, suggestion: None }); + Normal | Constant | Fn | UnlabeledBlock(_) | UnlabeledIfBlock(_) => { + self.sess.dcx().emit_err(OutsideLoop { + spans: vec![span], + name: &br_cx_kind.to_string(), + is_break: br_cx_kind == BreakContextKind::Break, + suggestion: None, + }); } } } @@ -246,7 +370,7 @@ impl<'a, 'hir> CheckLoopVisitor<'a, 'hir> { cf_type: &str, ) -> bool { if !span.is_desugaring(DesugaringKind::QuestionMark) - && self.cx == LabeledBlock + && self.cx_stack.last() == Some(&LabeledBlock) && label.label.is_none() { self.sess.dcx().emit_err(UnlabeledInLabeledBlock { span, cf_type }); @@ -254,4 +378,18 @@ impl<'a, 'hir> CheckLoopVisitor<'a, 'hir> { } false } + + fn report_outside_loop_error(&mut self) { + for (s, block) in &self.block_breaks { + self.sess.dcx().emit_err(OutsideLoop { + spans: block.spans.clone(), + name: &block.name, + is_break: true, + suggestion: Some(OutsideLoopSuggestion { + block_span: *s, + break_spans: block.suggs.clone(), + }), + }); + } + } } diff --git a/compiler/rustc_passes/src/naked_functions.rs b/compiler/rustc_passes/src/naked_functions.rs index a1f37ee3b83..d45ee32a624 100644 --- a/compiler/rustc_passes/src/naked_functions.rs +++ b/compiler/rustc_passes/src/naked_functions.rs @@ -83,8 +83,7 @@ fn check_abi(tcx: TyCtxt<'_>, def_id: LocalDefId, abi: Abi) { fn check_no_patterns(tcx: TyCtxt<'_>, params: &[hir::Param<'_>]) { for param in params { match param.pat.kind { - hir::PatKind::Wild - | hir::PatKind::Binding(hir::BindingAnnotation::NONE, _, _, None) => {} + hir::PatKind::Wild | hir::PatKind::Binding(hir::BindingMode::NONE, _, _, None) => {} _ => { tcx.dcx().emit_err(NoPatterns { span: param.pat.span }); } diff --git a/compiler/rustc_passes/src/reachable.rs b/compiler/rustc_passes/src/reachable.rs index 869cbebbc0d..ab1dd248556 100644 --- a/compiler/rustc_passes/src/reachable.rs +++ b/compiler/rustc_passes/src/reachable.rs @@ -1,14 +1,26 @@ -//! Finds local items that are externally reachable, which means that other crates need access to -//! their compiled machine code or their MIR. +//! Finds local items that are "reachable", which means that other crates need access to their +//! compiled code or their *runtime* MIR. (Compile-time MIR is always encoded anyway, so we don't +//! worry about that here.) //! -//! An item is "externally reachable" if it is relevant for other crates. This obviously includes -//! all public items. However, some of these items cannot be compiled to machine code (because they -//! are generic), and for some the machine code is not sufficient (because we want to cross-crate -//! inline them). These items "need cross-crate MIR". When a reachable function `f` needs -//! cross-crate MIR, then all the functions it calls also become reachable, as they will be -//! necessary to use the MIR of `f` from another crate. Furthermore, an item can become "externally -//! reachable" by having a `const`/`const fn` return a pointer to that item, so we also need to -//! recurse into reachable `const`/`const fn`. +//! An item is "reachable" if codegen that happens in downstream crates can end up referencing this +//! item. This obviously includes all public items. However, some of these items cannot be codegen'd +//! (because they are generic), and for some the compiled code is not sufficient (because we want to +//! cross-crate inline them). These items "need cross-crate MIR". When a reachable function `f` +//! needs cross-crate MIR, then its MIR may be codegen'd in a downstream crate, and hence items it +//! mentions need to be considered reachable. +//! +//! Furthermore, if a `const`/`const fn` is reachable, then it can return pointers to other items, +//! making those reachable as well. For instance, consider a `const fn` returning a pointer to an +//! otherwise entirely private function: if a downstream crate calls that `const fn` to compute the +//! initial value of a `static`, then it needs to generate a direct reference to this function -- +//! i.e., the function is directly reachable from that downstream crate! Hence we have to recurse +//! into `const` and `const fn`. +//! +//! Conversely, reachability *stops* when it hits a monomorphic non-`const` function that we do not +//! want to cross-crate inline. That function will just be codegen'd in this crate, which means the +//! monomorphization collector will consider it a root and then do another graph traversal to +//! codegen everything called by this function -- but that's a very different graph from what we are +//! considering here as at that point, everything is monomorphic. use hir::def_id::LocalDefIdSet; use rustc_data_structures::stack::ensure_sufficient_stack; @@ -17,6 +29,7 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::Node; +use rustc_middle::bug; use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs}; use rustc_middle::middle::privacy::{self, Level}; use rustc_middle::mir::interpret::{ConstAllocation, GlobalAlloc}; @@ -24,6 +37,7 @@ use rustc_middle::query::Providers; use rustc_middle::ty::{self, ExistentialTraitRef, TyCtxt}; use rustc_privacy::DefIdVisitor; use rustc_session::config::CrateType; +use tracing::debug; /// Determines whether this item is recursive for reachability. See `is_recursively_reachable_local` /// below for details. diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index 05c833cdfb6..31c709f2eb6 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -25,9 +25,9 @@ use rustc_session::lint::builtin::{INEFFECTIVE_UNSTABLE_TRAIT_IMPL, USELESS_DEPR use rustc_span::symbol::{sym, Symbol}; use rustc_span::Span; use rustc_target::spec::abi::Abi; - use std::mem::replace; use std::num::NonZero; +use tracing::{debug, info}; #[derive(PartialEq)] enum AnnotationKind { @@ -1020,7 +1020,7 @@ pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) { // stabilization diagnostic, but it can be avoided when there are no // `remaining_lib_features`. let mut all_implications = remaining_implications.clone(); - for &cnum in tcx.crates(()) { + for &cnum in tcx.used_crates(()) { all_implications .extend_unord(tcx.stability_implications(cnum).items().map(|(k, v)| (*k, *v))); } @@ -1033,7 +1033,7 @@ pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) { &all_implications, ); - for &cnum in tcx.crates(()) { + for &cnum in tcx.used_crates(()) { if remaining_lib_features.is_empty() && remaining_implications.is_empty() { break; } diff --git a/compiler/rustc_passes/src/weak_lang_items.rs b/compiler/rustc_passes/src/weak_lang_items.rs index 4eb0c6c275e..d80addf1236 100644 --- a/compiler/rustc_passes/src/weak_lang_items.rs +++ b/compiler/rustc_passes/src/weak_lang_items.rs @@ -14,7 +14,7 @@ use crate::errors::{ }; /// 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. +/// lang items required by this crate, but not defined yet. pub fn check_crate(tcx: TyCtxt<'_>, items: &mut lang_items::LanguageItems, krate: &ast::Crate) { // These are never called by user code, they're generated by the compiler. // They will never implicitly be added to the `missing` array unless we do @@ -68,7 +68,7 @@ fn verify(tcx: TyCtxt<'_>, items: &lang_items::LanguageItems) { } let mut missing = FxHashSet::default(); - for &cnum in tcx.crates(()).iter() { + for &cnum in tcx.used_crates(()).iter() { for &item in tcx.missing_lang_items(cnum).iter() { missing.insert(item); } |
