diff options
Diffstat (limited to 'compiler/rustc_passes')
-rw-r--r-- | compiler/rustc_passes/Cargo.toml | 20 | ||||
-rw-r--r-- | compiler/rustc_passes/messages.ftl | 19 | ||||
-rw-r--r-- | compiler/rustc_passes/src/check_attr.rs | 92 | ||||
-rw-r--r-- | compiler/rustc_passes/src/check_const.rs | 4 | ||||
-rw-r--r-- | compiler/rustc_passes/src/dead.rs | 98 | ||||
-rw-r--r-- | compiler/rustc_passes/src/entry.rs | 41 | ||||
-rw-r--r-- | compiler/rustc_passes/src/errors.rs | 79 | ||||
-rw-r--r-- | compiler/rustc_passes/src/hir_stats.rs | 4 | ||||
-rw-r--r-- | compiler/rustc_passes/src/lang_items.rs | 2 | ||||
-rw-r--r-- | compiler/rustc_passes/src/layout_test.rs | 2 | ||||
-rw-r--r-- | compiler/rustc_passes/src/lib.rs | 3 | ||||
-rw-r--r-- | compiler/rustc_passes/src/lib_features.rs | 8 | ||||
-rw-r--r-- | compiler/rustc_passes/src/liveness.rs | 62 | ||||
-rw-r--r-- | compiler/rustc_passes/src/loops.rs | 55 | ||||
-rw-r--r-- | compiler/rustc_passes/src/reachable.rs | 62 | ||||
-rw-r--r-- | compiler/rustc_passes/src/stability.rs | 72 | ||||
-rw-r--r-- | compiler/rustc_passes/src/weak_lang_items.rs | 4 |
17 files changed, 324 insertions, 303 deletions
diff --git a/compiler/rustc_passes/Cargo.toml b/compiler/rustc_passes/Cargo.toml index 0413b5b4f..40c3811e0 100644 --- a/compiler/rustc_passes/Cargo.toml +++ b/compiler/rustc_passes/Cargo.toml @@ -4,23 +4,25 @@ version = "0.0.0" edition = "2021" [dependencies] -tracing = "0.1" +# tidy-alphabetical-start itertools = "0.10.1" -rustc_middle = { path = "../rustc_middle" } +rustc_ast = { path = "../rustc_ast" } +rustc_ast_pretty = { path = "../rustc_ast_pretty" } rustc_attr = { path = "../rustc_attr" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } rustc_expand = { path = "../rustc_expand" } -rustc_hir = { path = "../rustc_hir" } +rustc_feature = { path = "../rustc_feature" } rustc_fluent_macro = { path = "../rustc_fluent_macro" } +rustc_hir = { path = "../rustc_hir" } rustc_index = { path = "../rustc_index" } -rustc_session = { path = "../rustc_session" } -rustc_target = { path = "../rustc_target" } +rustc_lexer = { path = "../rustc_lexer" } rustc_macros = { path = "../rustc_macros" } -rustc_ast = { path = "../rustc_ast" } +rustc_middle = { path = "../rustc_middle" } rustc_serialize = { path = "../rustc_serialize" } +rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } -rustc_lexer = { path = "../rustc_lexer" } -rustc_ast_pretty = { path = "../rustc_ast_pretty" } -rustc_feature = { path = "../rustc_feature" } +rustc_target = { path = "../rustc_target" } rustc_trait_selection = { path = "../rustc_trait_selection" } +tracing = "0.1" +# tidy-alphabetical-end diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index 214c6d709..be50aad13 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -393,20 +393,13 @@ passes_invalid_attr_at_crate_level = `{$name}` attribute cannot be used at crate level .suggestion = perhaps you meant to use an outer attribute -passes_invalid_deprecation_version = - invalid deprecation version found - .label = invalid deprecation version - .item = the stability attribute annotates this item +passes_invalid_attr_at_crate_level_item = + the inner attribute doesn't annotate this {$kind} passes_invalid_macro_export_arguments = `{$name}` isn't a valid `#[macro_export]` argument passes_invalid_macro_export_arguments_too_many_items = `#[macro_export]` can only take 1 or 0 arguments -passes_invalid_stability = - invalid stability version found - .label = invalid stability version - .item = the stability attribute annotates this item - passes_lang_item_fn_with_target_feature = `{$name}` language item function is not allowed to have `#[target_feature]` .label = `{$name}` language item function is not allowed to have `#[target_feature]` @@ -580,6 +573,8 @@ passes_outside_loop = *[false] {""} } +passes_outside_loop_suggestion = consider labeling this block to be able to break within it + passes_params_not_allowed = referencing function parameters is not allowed in naked functions .help = follow the calling convention in asm block to use parameters @@ -594,9 +589,6 @@ passes_pass_by_value = `pass_by_value` attribute should be applied to a struct, enum or type alias .label = is not a struct, enum or type alias -passes_plugin_registrar = - `#[plugin_registrar]` only has an effect on functions - passes_proc_macro_bad_sig = {$kind} has incorrect signature passes_repr_conflicting = @@ -778,6 +770,8 @@ passes_unused_var_maybe_capture_ref = unused variable: `{$name}` passes_unused_var_remove_field = unused variable: `{$name}` passes_unused_var_remove_field_suggestion = try removing the field +passes_unused_variable_args_in_macro = `{$name}` is captured in macro and introduced a unused variable + passes_unused_variable_try_ignore = unused variable: `{$name}` .suggestion = try ignoring the field @@ -785,6 +779,7 @@ passes_unused_variable_try_prefix = unused variable: `{$name}` .label = unused variable .suggestion = if this is intentional, prefix it with an underscore + passes_used_compiler_linker = `used(compiler)` and `used(linker)` can't be used together diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index d92923e78..c5767fd90 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -211,7 +211,6 @@ impl CheckAttrVisitor<'_> { sym::deprecated => self.check_deprecated(hir_id, attr, span, target), sym::macro_use | sym::macro_escape => self.check_macro_use(hir_id, attr, target), sym::path => self.check_generic_attr(hir_id, attr, target, Target::Mod), - sym::plugin_registrar => self.check_plugin_registrar(hir_id, attr, target), sym::macro_export => self.check_macro_export(hir_id, attr, target), sym::ignore | sym::should_panic => { self.check_generic_attr(hir_id, attr, target, Target::Fn) @@ -1076,7 +1075,9 @@ impl CheckAttrVisitor<'_> { ) -> bool { let mut is_valid = true; - if let Some(mi) = attr.meta() && let Some(list) = mi.meta_item_list() { + if let Some(mi) = attr.meta() + && let Some(list) = mi.meta_item_list() + { for meta in list { if let Some(i_meta) = meta.meta_item() { match i_meta.name_or_empty() { @@ -1108,6 +1109,7 @@ impl CheckAttrVisitor<'_> { | sym::html_root_url | sym::html_no_source | sym::test + | sym::rust_logo if !self.check_attr_crate_level(attr, meta, hir_id) => { is_valid = false; @@ -1132,14 +1134,7 @@ impl CheckAttrVisitor<'_> { is_valid = false; } - sym::masked - if !self.check_doc_masked( - attr, - meta, - hir_id, - target, - ) => - { + sym::masked if !self.check_doc_masked(attr, meta, hir_id, target) => { is_valid = false; } @@ -1166,6 +1161,18 @@ impl CheckAttrVisitor<'_> { | sym::plugins | sym::fake_variadic => {} + sym::rust_logo => { + if !self.tcx.features().rustdoc_internals { + feature_err( + &self.tcx.sess.parse_sess, + sym::rustdoc_internals, + meta.span(), + "the `#[doc(rust_logo)]` attribute is used for Rust branding", + ) + .emit(); + } + } + sym::test => { if !self.check_test_attr(meta, hir_id) { is_valid = false; @@ -1179,13 +1186,11 @@ impl CheckAttrVisitor<'_> { INVALID_DOC_ATTRIBUTES, hir_id, i_meta.span, - errors::DocTestUnknownSpotlight { - path, - span: i_meta.span - } + errors::DocTestUnknownSpotlight { path, span: i_meta.span }, ); - } else if i_meta.has_name(sym::include) && - let Some(value) = i_meta.value_str() { + } else if i_meta.has_name(sym::include) + && let Some(value) = i_meta.value_str() + { let applicability = if list.len() == 1 { Applicability::MachineApplicable } else { @@ -1200,16 +1205,19 @@ impl CheckAttrVisitor<'_> { errors::DocTestUnknownInclude { path, value: value.to_string(), - inner: match attr.style { AttrStyle::Inner=> "!" , AttrStyle::Outer => "" }, + inner: match attr.style { + AttrStyle::Inner => "!", + AttrStyle::Outer => "", + }, sugg: (attr.meta().unwrap().span, applicability), - } + }, ); } else { self.tcx.emit_spanned_lint( INVALID_DOC_ATTRIBUTES, hir_id, i_meta.span, - errors::DocTestUnknownAny { path } + errors::DocTestUnknownAny { path }, ); } is_valid = false; @@ -2189,8 +2197,9 @@ impl CheckAttrVisitor<'_> { attr.span, errors::MacroExport::Normal, ); - } else if let Some(meta_item_list) = attr.meta_item_list() && - !meta_item_list.is_empty() { + } else if let Some(meta_item_list) = attr.meta_item_list() + && !meta_item_list.is_empty() + { if meta_item_list.len() > 1 { self.tcx.emit_spanned_lint( INVALID_MACRO_EXPORT_ARGUMENTS, @@ -2227,17 +2236,6 @@ impl CheckAttrVisitor<'_> { } } - fn check_plugin_registrar(&self, hir_id: HirId, attr: &Attribute, target: Target) { - if target != Target::Fn { - self.tcx.emit_spanned_lint( - UNUSED_ATTRIBUTES, - hir_id, - attr.span, - errors::PluginRegistrar, - ); - } - } - fn check_unused_attribute(&self, hir_id: HirId, attr: &Attribute) { // Warn on useless empty attributes. let note = if matches!( @@ -2255,9 +2253,9 @@ impl CheckAttrVisitor<'_> { { errors::UnusedNote::EmptyList { name: attr.name_or_empty() } } else if matches!( - attr.name_or_empty(), - sym::allow | sym::warn | sym::deny | sym::forbid | sym::expect - ) && let Some(meta) = attr.meta_item_list() + attr.name_or_empty(), + sym::allow | sym::warn | sym::deny | sym::forbid | sym::expect + ) && let Some(meta) = attr.meta_item_list() && meta.len() == 1 && let Some(item) = meta[0].meta_item() && let MetaItemKind::NameValue(_) = &item.kind @@ -2380,7 +2378,7 @@ impl CheckAttrVisitor<'_> { let errors = ocx.select_all_or_error(); if !errors.is_empty() { - infcx.err_ctxt().report_fulfillment_errors(&errors); + infcx.err_ctxt().report_fulfillment_errors(errors); self.abort.set(true); } } @@ -2524,10 +2522,30 @@ fn check_invalid_crate_level_attr(tcx: TyCtxt<'_>, attrs: &[Attribute]) { if attr.style == AttrStyle::Inner { for attr_to_check in ATTRS_TO_CHECK { if attr.has_name(*attr_to_check) { + let item = tcx + .hir() + .items() + .map(|id| tcx.hir().item(id)) + .find(|item| !item.span.is_dummy()) // Skip prelude `use`s + .map(|item| errors::ItemFollowingInnerAttr { + span: item.ident.span, + kind: item.kind.descr(), + }); tcx.sess.emit_err(errors::InvalidAttrAtCrateLevel { span: attr.span, - snippet: tcx.sess.source_map().span_to_snippet(attr.span).ok(), + sugg_span: tcx + .sess + .source_map() + .span_to_snippet(attr.span) + .ok() + .filter(|src| src.starts_with("#![")) + .map(|_| { + attr.span + .with_lo(attr.span.lo() + BytePos(1)) + .with_hi(attr.span.lo() + BytePos(2)) + }), name: *attr_to_check, + item, }); } } diff --git a/compiler/rustc_passes/src/check_const.rs b/compiler/rustc_passes/src/check_const.rs index 6d176af80..7188c177f 100644 --- a/compiler/rustc_passes/src/check_const.rs +++ b/compiler/rustc_passes/src/check_const.rs @@ -86,7 +86,7 @@ impl<'tcx> CheckConstVisitor<'tcx> { let is_feature_allowed = |feature_gate| { // All features require that the corresponding gate be enabled, // even if the function has `#[rustc_allow_const_fn_unstable(the_gate)]`. - if !tcx.features().enabled(feature_gate) { + if !tcx.features().active(feature_gate) { return false; } @@ -134,7 +134,7 @@ impl<'tcx> CheckConstVisitor<'tcx> { let required_gates = required_gates.unwrap_or(&[]); let missing_gates: Vec<_> = - required_gates.iter().copied().filter(|&g| !features.enabled(g)).collect(); + required_gates.iter().copied().filter(|&g| !features.active(g)).collect(); match missing_gates.as_slice() { [] => { diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index 493daf314..2e8c58b02 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -1,6 +1,7 @@ -// This implements the dead-code warning pass. It follows middle::reachable -// closely. The idea is that all reachable symbols are live, codes called -// from live codes are live, and everything else is dead. +// This implements the dead-code warning pass. +// All reachable symbols are live, code called from live code is live, code with certain lint +// expectations such as `#[expect(unused)]` and `#[expect(dead_code)]` is live, and everything else +// is dead. use hir::def_id::{LocalDefIdMap, LocalDefIdSet}; use itertools::Itertools; @@ -192,15 +193,15 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { if let hir::ExprKind::Assign(lhs, rhs, _) = assign.kind && check_for_self_assign_helper(self.typeck_results(), lhs, rhs) - && !assign.span.from_expansion() + && !assign.span.from_expansion() { - let is_field_assign = matches!(lhs.kind, hir::ExprKind::Field(..)); - self.tcx.emit_spanned_lint( - lint::builtin::DEAD_CODE, - assign.hir_id, - assign.span, - UselessAssignment { is_field_assign, ty: self.typeck_results().expr_ty(lhs) } - ) + let is_field_assign = matches!(lhs.kind, hir::ExprKind::Field(..)); + self.tcx.emit_spanned_lint( + lint::builtin::DEAD_CODE, + assign.hir_id, + assign.span, + UselessAssignment { is_field_assign, ty: self.typeck_results().expr_ty(lhs) }, + ) } } @@ -256,10 +257,10 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { let mut current_ty = container; - for &index in indices { + for &(variant, field) in indices { match current_ty.kind() { ty::Adt(def, subst) => { - let field = &def.non_enum_variant().fields[index]; + let field = &def.variant(variant).fields[field]; self.insert_def_id(field.did); let field_ty = field.ty(self.tcx, subst); @@ -270,7 +271,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { // but we may need to mark subfields ty::Tuple(tys) => { current_ty = - self.tcx.normalize_erasing_regions(param_env, tys[index.as_usize()]); + self.tcx.normalize_erasing_regions(param_env, tys[field.as_usize()]); } _ => span_bug!(expr.span, "named field access on non-ADT"), } @@ -670,7 +671,8 @@ fn check_trait_item( if matches!(tcx.def_kind(id.owner_id), DefKind::AssocConst | DefKind::AssocFn) { let trait_item = tcx.hir().trait_item(id); if matches!(trait_item.kind, Const(_, Some(_)) | Fn(_, hir::TraitFn::Provided(_))) - && let Some(comes_from_allow) = has_allow_dead_code_or_lang_attr(tcx, trait_item.owner_id.def_id) + && let Some(comes_from_allow) = + has_allow_dead_code_or_lang_attr(tcx, trait_item.owner_id.def_id) { worklist.push((trait_item.owner_id.def_id, comes_from_allow)); } @@ -747,7 +749,7 @@ fn live_symbols_and_ignored_derived_traits( (symbol_visitor.live_symbols, symbol_visitor.ignored_derived_traits) } -struct DeadVariant { +struct DeadItem { def_id: LocalDefId, name: Symbol, level: lint::Level, @@ -785,7 +787,13 @@ impl<'tcx> DeadVisitor<'tcx> { ShouldWarnAboutField::Yes(is_positional) } - fn warn_multiple_dead_codes( + // # Panics + // All `dead_codes` must have the same lint level, otherwise we will intentionally ICE. + // This is because we emit a multi-spanned lint using the lint level of the `dead_codes`'s + // first local def id. + // Prefer calling `Self.warn_dead_code` or `Self.warn_dead_code_grouped_by_lint_level` + // since those methods group by lint level before calling this method. + fn lint_at_single_level( &self, dead_codes: &[LocalDefId], participle: &str, @@ -796,6 +804,15 @@ impl<'tcx> DeadVisitor<'tcx> { return; }; let tcx = self.tcx; + + let first_hir_id = tcx.hir().local_def_id_to_hir_id(first_id); + let first_lint_level = tcx.lint_level_at_node(lint::builtin::DEAD_CODE, first_hir_id).0; + assert!(dead_codes.iter().skip(1).all(|id| { + let hir_id = tcx.hir().local_def_id_to_hir_id(*id); + let level = tcx.lint_level_at_node(lint::builtin::DEAD_CODE, hir_id).0; + level == first_lint_level + })); + let names: Vec<_> = dead_codes.iter().map(|&def_id| tcx.item_name(def_id.to_def_id())).collect(); let spans: Vec<_> = dead_codes @@ -876,31 +893,26 @@ impl<'tcx> DeadVisitor<'tcx> { } }; - self.tcx.emit_spanned_lint( - lint, - tcx.hir().local_def_id_to_hir_id(first_id), - MultiSpan::from_spans(spans), - diag, - ); + self.tcx.emit_spanned_lint(lint, first_hir_id, MultiSpan::from_spans(spans), diag); } - fn warn_dead_fields_and_variants( + fn warn_multiple( &self, def_id: LocalDefId, participle: &str, - dead_codes: Vec<DeadVariant>, + dead_codes: Vec<DeadItem>, is_positional: bool, ) { let mut dead_codes = dead_codes .iter() .filter(|v| !v.name.as_str().starts_with('_')) - .collect::<Vec<&DeadVariant>>(); + .collect::<Vec<&DeadItem>>(); if dead_codes.is_empty() { return; } dead_codes.sort_by_key(|v| v.level); for (_, group) in &dead_codes.into_iter().group_by(|v| v.level) { - self.warn_multiple_dead_codes( + self.lint_at_single_level( &group.map(|v| v.def_id).collect::<Vec<_>>(), participle, Some(def_id), @@ -910,7 +922,7 @@ impl<'tcx> DeadVisitor<'tcx> { } fn warn_dead_code(&mut self, id: LocalDefId, participle: &str) { - self.warn_multiple_dead_codes(&[id], participle, None, false); + self.lint_at_single_level(&[id], participle, None, false); } fn check_definition(&mut self, def_id: LocalDefId) { @@ -954,17 +966,16 @@ fn check_mod_deathness(tcx: TyCtxt<'_>, module: LocalModDefId) { if let hir::ItemKind::Impl(impl_item) = tcx.hir().item(item).kind { let mut dead_items = Vec::new(); for item in impl_item.items { - let did = item.id.owner_id.def_id; - if !visitor.is_live_code(did) { - dead_items.push(did) + let def_id = item.id.owner_id.def_id; + if !visitor.is_live_code(def_id) { + let name = tcx.item_name(def_id.to_def_id()); + let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); + let level = tcx.lint_level_at_node(lint::builtin::DEAD_CODE, hir_id).0; + + dead_items.push(DeadItem { def_id, name, level }) } } - visitor.warn_multiple_dead_codes( - &dead_items, - "used", - Some(item.owner_id.def_id), - false, - ); + visitor.warn_multiple(item.owner_id.def_id, "used", dead_items, false); } if !live_symbols.contains(&item.owner_id.def_id) { @@ -988,7 +999,7 @@ fn check_mod_deathness(tcx: TyCtxt<'_>, module: LocalModDefId) { // Record to group diagnostics. let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); let level = tcx.lint_level_at_node(lint::builtin::DEAD_CODE, hir_id).0; - dead_variants.push(DeadVariant { def_id, name: variant.name, level }); + dead_variants.push(DeadItem { def_id, name: variant.name, level }); continue; } @@ -1013,21 +1024,16 @@ fn check_mod_deathness(tcx: TyCtxt<'_>, module: LocalModDefId) { hir_id, ) .0; - Some(DeadVariant { def_id, name: field.name, level }) + Some(DeadItem { def_id, name: field.name, level }) } else { None } }) .collect(); - visitor.warn_dead_fields_and_variants(def_id, "read", dead_fields, is_positional) + visitor.warn_multiple(def_id, "read", dead_fields, is_positional); } - visitor.warn_dead_fields_and_variants( - item.owner_id.def_id, - "constructed", - dead_variants, - false, - ); + visitor.warn_multiple(item.owner_id.def_id, "constructed", dead_variants, false); } } diff --git a/compiler/rustc_passes/src/entry.rs b/compiler/rustc_passes/src/entry.rs index 4f71704b8..51a64b385 100644 --- a/compiler/rustc_passes/src/entry.rs +++ b/compiler/rustc_passes/src/entry.rs @@ -52,31 +52,6 @@ fn entry_fn(tcx: TyCtxt<'_>, (): ()) -> Option<(DefId, EntryFnType)> { configure_main(tcx, &ctxt) } -// Beware, this is duplicated in `librustc_builtin_macros/test_harness.rs` -// (with `ast::Item`), so make sure to keep them in sync. -// A small optimization was added so that hir::Item is fetched only when needed. -// An equivalent optimization was not applied to the duplicated code in test_harness.rs. -fn entry_point_type(ctxt: &EntryContext<'_>, id: ItemId, at_root: bool) -> EntryPointType { - let attrs = ctxt.tcx.hir().attrs(id.hir_id()); - if attr::contains_name(attrs, sym::start) { - EntryPointType::Start - } else if attr::contains_name(attrs, sym::rustc_main) { - EntryPointType::RustcMainAttr - } else { - if let Some(name) = ctxt.tcx.opt_item_name(id.owner_id.to_def_id()) - && name == sym::main { - if at_root { - // This is a top-level function so can be `main`. - EntryPointType::MainNamed - } else { - EntryPointType::OtherMain - } - } else { - EntryPointType::None - } - } -} - fn attr_span_by_symbol(ctxt: &EntryContext<'_>, id: ItemId, sym: Symbol) -> Option<Span> { let attrs = ctxt.tcx.hir().attrs(id.hir_id()); attr::find_by_name(attrs, sym).map(|attr| attr.span) @@ -85,7 +60,13 @@ fn attr_span_by_symbol(ctxt: &EntryContext<'_>, id: ItemId, sym: Symbol) -> Opti fn find_item(id: ItemId, ctxt: &mut EntryContext<'_>) { let at_root = ctxt.tcx.opt_local_parent(id.owner_id.def_id) == Some(CRATE_DEF_ID); - match entry_point_type(ctxt, id, at_root) { + let attrs = ctxt.tcx.hir().attrs(id.hir_id()); + let entry_point_type = rustc_ast::entry::entry_point_type( + attrs, + 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.sess.emit_err(AttrOnlyOnMain { span, attr: sym::unix_sigpipe }); @@ -140,9 +121,13 @@ fn configure_main(tcx: TyCtxt<'_>, visitor: &EntryContext<'_>) -> Option<(DefId, let def_id = local_def_id.to_def_id(); Some((def_id, EntryFnType::Main { sigpipe: sigpipe(tcx, def_id) })) } else { - if let Some(main_def) = tcx.resolutions(()).main_def && let Some(def_id) = main_def.opt_fn_def_id() { + if let Some(main_def) = tcx.resolutions(()).main_def + && let Some(def_id) = main_def.opt_fn_def_id() + { // non-local main imports are handled below - if let Some(def_id) = def_id.as_local() && matches!(tcx.hir().find_by_def_id(def_id), Some(Node::ForeignItem(_))) { + if let Some(def_id) = def_id.as_local() + && matches!(tcx.hir().find_by_def_id(def_id), Some(Node::ForeignItem(_))) + { tcx.sess.emit_err(ExternMain { span: tcx.def_span(def_id) }); return None; } diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index f4a6bf017..411c94101 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -717,10 +717,6 @@ pub enum MacroExport { TooManyItems, } -#[derive(LintDiagnostic)] -#[diag(passes_plugin_registrar)] -pub struct PluginRegistrar; - #[derive(Subdiagnostic)] pub enum UnusedNote { #[note(passes_unused_empty_lints_note)] @@ -856,8 +852,15 @@ pub struct UnknownLangItem { pub struct InvalidAttrAtCrateLevel { pub span: Span, - pub snippet: Option<String>, + pub sugg_span: Option<Span>, pub name: Symbol, + pub item: Option<ItemFollowingInnerAttr>, +} + +#[derive(Clone, Copy)] +pub struct ItemFollowingInnerAttr { + pub span: Span, + pub kind: &'static str, } impl IntoDiagnostic<'_> for InvalidAttrAtCrateLevel { @@ -871,15 +874,18 @@ impl IntoDiagnostic<'_> for InvalidAttrAtCrateLevel { diag.set_arg("name", self.name); // Only emit an error with a suggestion if we can create a string out // of the attribute span - if let Some(src) = self.snippet { - let replacement = src.replace("#!", "#"); + if let Some(span) = self.sugg_span { diag.span_suggestion_verbose( - self.span, + span, fluent::passes_suggestion, - replacement, + String::new(), rustc_errors::Applicability::MachineApplicable, ); } + if let Some(item) = self.item { + diag.set_arg("kind", item.kind); + diag.span_label(item.span, fluent::passes_invalid_attr_at_crate_level_item); + } diag } } @@ -1106,6 +1112,16 @@ pub struct OutsideLoop<'a> { pub span: Span, pub name: &'a str, pub is_break: bool, + #[subdiagnostic] + pub suggestion: Option<OutsideLoopSuggestion>, +} +#[derive(Subdiagnostic)] +#[multipart_suggestion(passes_outside_loop_suggestion, applicability = "maybe-incorrect")] +pub struct OutsideLoopSuggestion { + #[suggestion_part(code = "'block: ")] + pub block_span: Span, + #[suggestion_part(code = " 'block")] + pub break_span: Span, } #[derive(Diagnostic)] @@ -1308,7 +1324,9 @@ impl<'a> IntoDiagnostic<'a> for NoMainErr { diag.span_label(self.sp.shrink_to_hi(), note); } - if let Some(main_def) = self.main_def_opt && main_def.opt_fn_def_id().is_none(){ + if let Some(main_def) = self.main_def_opt + && main_def.opt_fn_def_id().is_none() + { // There is something at `crate::main`, but it is not a function definition. diag.span_label(main_def.span, fluent::passes_non_function_main); } @@ -1493,16 +1511,6 @@ pub struct UselessStability { } #[derive(Diagnostic)] -#[diag(passes_invalid_stability)] -pub struct InvalidStability { - #[primary_span] - #[label] - pub span: Span, - #[label(passes_item)] - pub item_sp: Span, -} - -#[derive(Diagnostic)] #[diag(passes_cannot_stabilize_deprecated)] pub struct CannotStabilizeDeprecated { #[primary_span] @@ -1513,16 +1521,6 @@ pub struct CannotStabilizeDeprecated { } #[derive(Diagnostic)] -#[diag(passes_invalid_deprecation_version)] -pub struct InvalidDeprecationVersion { - #[primary_span] - #[label] - pub span: Span, - #[label(passes_item)] - pub item_sp: Span, -} - -#[derive(Diagnostic)] #[diag(passes_missing_stability_attr)] pub struct MissingStabilityAttr<'a> { #[primary_span] @@ -1756,15 +1754,24 @@ pub struct UnusedVariableTryPrefix { #[subdiagnostic] pub string_interp: Vec<UnusedVariableStringInterp>, #[subdiagnostic] - pub sugg: UnusedVariableTryPrefixSugg, + pub sugg: UnusedVariableSugg, + pub name: String, } #[derive(Subdiagnostic)] -#[multipart_suggestion(passes_suggestion, applicability = "machine-applicable")] -pub struct UnusedVariableTryPrefixSugg { - #[suggestion_part(code = "_{name}")] - pub spans: Vec<Span>, - pub name: String, +pub enum UnusedVariableSugg { + #[multipart_suggestion(passes_suggestion, applicability = "machine-applicable")] + TryPrefixSugg { + #[suggestion_part(code = "_{name}")] + spans: Vec<Span>, + name: String, + }, + #[help(passes_unused_variable_args_in_macro)] + NoSugg { + #[primary_span] + span: Span, + name: String, + }, } pub struct UnusedVariableStringInterp { diff --git a/compiler/rustc_passes/src/hir_stats.rs b/compiler/rustc_passes/src/hir_stats.rs index 24087a4ea..f915c1057 100644 --- a/compiler/rustc_passes/src/hir_stats.rs +++ b/compiler/rustc_passes/src/hir_stats.rs @@ -567,10 +567,10 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> { (self, e, e.kind, Id::None, ast, Expr, ExprKind), [ Array, ConstBlock, Call, MethodCall, Tup, Binary, Unary, Lit, Cast, Type, Let, - If, While, ForLoop, Loop, Match, Closure, Block, Async, Await, TryBlock, Assign, + If, While, ForLoop, Loop, Match, Closure, Block, Await, TryBlock, Assign, AssignOp, Field, Index, Range, Underscore, Path, AddrOf, Break, Continue, Ret, InlineAsm, FormatArgs, OffsetOf, MacCall, Struct, Repeat, Paren, Try, Yield, Yeet, - Become, IncludedBytes, Err + Become, IncludedBytes, Gen, Err ] ); ast_visit::walk_expr(self, e) diff --git a/compiler/rustc_passes/src/lang_items.rs b/compiler/rustc_passes/src/lang_items.rs index 7e8372439..2aec4ea7e 100644 --- a/compiler/rustc_passes/src/lang_items.rs +++ b/compiler/rustc_passes/src/lang_items.rs @@ -149,7 +149,7 @@ impl<'tcx> LanguageItemCollector<'tcx> { // Now check whether the lang_item has the expected number of generic // arguments. Generally speaking, binary and indexing operations have // one (for the RHS/index), unary operations have none, the closure - // traits have one for the argument list, generators have one for the + // traits have one for the argument list, coroutines have one for the // resume argument, and ordering/equality relations have one for the RHS // Some other types like Box and various functions like drop_in_place // have minimum requirements. diff --git a/compiler/rustc_passes/src/layout_test.rs b/compiler/rustc_passes/src/layout_test.rs index e195f9ab6..2129a98cd 100644 --- a/compiler/rustc_passes/src/layout_test.rs +++ b/compiler/rustc_passes/src/layout_test.rs @@ -57,7 +57,7 @@ pub fn ensure_wf<'tcx>( ocx.register_obligation(obligation); let errors = ocx.select_all_or_error(); if !errors.is_empty() { - infcx.err_ctxt().report_fulfillment_errors(&errors); + infcx.err_ctxt().report_fulfillment_errors(errors); false } else { // looks WF! diff --git a/compiler/rustc_passes/src/lib.rs b/compiler/rustc_passes/src/lib.rs index 51f3c9ad7..946a9e68d 100644 --- a/compiler/rustc_passes/src/lib.rs +++ b/compiler/rustc_passes/src/lib.rs @@ -6,6 +6,9 @@ #![allow(rustc::potential_query_instability)] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] +#![cfg_attr(not(bootstrap), doc(rust_logo))] +#![cfg_attr(not(bootstrap), feature(rustdoc_internals))] +#![cfg_attr(not(bootstrap), allow(internal_features))] #![feature(iter_intersperse)] #![feature(let_chains)] #![feature(map_try_insert)] diff --git a/compiler/rustc_passes/src/lib_features.rs b/compiler/rustc_passes/src/lib_features.rs index 44174b1b8..0daa273db 100644 --- a/compiler/rustc_passes/src/lib_features.rs +++ b/compiler/rustc_passes/src/lib_features.rs @@ -5,7 +5,7 @@ //! collect them instead. use rustc_ast::Attribute; -use rustc_attr::{rust_version_symbol, VERSION_PLACEHOLDER}; +use rustc_attr::VERSION_PLACEHOLDER; use rustc_hir::intravisit::Visitor; use rustc_middle::hir::nested_filter; use rustc_middle::middle::lib_features::LibFeatures; @@ -56,8 +56,10 @@ impl<'tcx> LibFeatureCollector<'tcx> { } } - if let Some(s) = since && s.as_str() == VERSION_PLACEHOLDER { - since = Some(rust_version_symbol()); + if let Some(s) = since + && s.as_str() == VERSION_PLACEHOLDER + { + since = Some(sym::env_CFG_RELEASE); } if let Some(feature) = feature { diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs index 20e996eae..b73fb984c 100644 --- a/compiler/rustc_passes/src/liveness.rs +++ b/compiler/rustc_passes/src/liveness.rs @@ -706,7 +706,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { // // When computing the liveness for captured variables we take into // account how variable is captured (ByRef vs ByValue) and what is the - // closure kind (Generator / FnOnce vs Fn / FnMut). + // closure kind (Coroutine / FnOnce vs Fn / FnMut). // // Variables captured by reference are assumed to be used on the exit // from the closure. @@ -752,7 +752,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { ty::ClosureKind::FnMut => {} ty::ClosureKind::FnOnce => return succ, }, - ty::Generator(..) => return succ, + ty::Coroutine(..) => return succ, _ => { span_bug!( body.value.span, @@ -1512,13 +1512,15 @@ impl<'tcx> Liveness<'_, 'tcx> { Some(body), |spans, hir_id, ln, var| { if !self.live_on_entry(ln, var) - && let Some(name) = self.should_warn(var) { - self.ir.tcx.emit_spanned_lint( - lint::builtin::UNUSED_ASSIGNMENTS, - hir_id, - spans, - errors::UnusedAssignPassed { name }, - ); } + && let Some(name) = self.should_warn(var) + { + self.ir.tcx.emit_spanned_lint( + lint::builtin::UNUSED_ASSIGNMENTS, + hir_id, + spans, + errors::UnusedAssignPassed { name }, + ); + } }, ); } @@ -1578,7 +1580,6 @@ impl<'tcx> Liveness<'_, 'tcx> { opt_body: Option<&hir::Body<'_>>, ) { let first_hir_id = hir_ids_and_spans[0].0; - if let Some(name) = self.should_warn(var).filter(|name| name != "self") { // annoying: for parameters in funcs like `fn(x: i32) // {ret}`, there is only one node, so asking about @@ -1650,11 +1651,29 @@ impl<'tcx> Liveness<'_, 'tcx> { }, ); } else { + // #117284, when `pat_span` and `ident_span` have different contexts + // we can't provide a good suggestion, instead we pointed out the spans from macro + let from_macro = non_shorthands + .iter() + .find(|(_, pat_span, ident_span)| { + pat_span.ctxt() != ident_span.ctxt() && pat_span.from_expansion() + }) + .map(|(_, pat_span, _)| *pat_span); let non_shorthands = non_shorthands .into_iter() .map(|(_, _, ident_span)| ident_span) .collect::<Vec<_>>(); + let suggestions = self.string_interp_suggestions(&name, opt_body); + let sugg = if let Some(span) = from_macro { + errors::UnusedVariableSugg::NoSugg { span, name: name.clone() } + } else { + errors::UnusedVariableSugg::TryPrefixSugg { + spans: non_shorthands, + name: name.clone(), + } + }; + self.ir.tcx.emit_spanned_lint( lint::builtin::UNUSED_VARIABLES, first_hir_id, @@ -1664,10 +1683,8 @@ impl<'tcx> Liveness<'_, 'tcx> { .collect::<Vec<_>>(), errors::UnusedVariableTryPrefix { label: if !suggestions.is_empty() { Some(pat.span) } else { None }, - sugg: errors::UnusedVariableTryPrefixSugg { - spans: non_shorthands, - name, - }, + name, + sugg, string_interp: suggestions, }, ); @@ -1707,13 +1724,14 @@ impl<'tcx> Liveness<'_, 'tcx> { fn warn_about_dead_assign(&self, spans: Vec<Span>, hir_id: HirId, ln: LiveNode, var: Variable) { if !self.live_on_exit(ln, var) - && let Some(name) = self.should_warn(var) { - self.ir.tcx.emit_spanned_lint( - lint::builtin::UNUSED_ASSIGNMENTS, - hir_id, - spans, - errors::UnusedAssign { name }, - ); - } + && let Some(name) = self.should_warn(var) + { + self.ir.tcx.emit_spanned_lint( + lint::builtin::UNUSED_ASSIGNMENTS, + hir_id, + spans, + errors::UnusedAssign { name }, + ); + } } } diff --git a/compiler/rustc_passes/src/loops.rs b/compiler/rustc_passes/src/loops.rs index 0aaf85086..25e131d74 100644 --- a/compiler/rustc_passes/src/loops.rs +++ b/compiler/rustc_passes/src/loops.rs @@ -1,7 +1,7 @@ use Context::*; use rustc_hir as hir; -use rustc_hir::def_id::LocalModDefId; +use rustc_hir::def_id::{LocalDefId, LocalModDefId}; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{Destination, Movability, Node}; use rustc_middle::hir::map::Map; @@ -10,19 +10,21 @@ use rustc_middle::query::Providers; use rustc_middle::ty::TyCtxt; use rustc_session::Session; use rustc_span::hygiene::DesugaringKind; -use rustc_span::Span; +use rustc_span::{BytePos, Span}; use crate::errors::{ BreakInsideAsyncBlock, BreakInsideClosure, BreakNonLoop, ContinueLabeledBlock, OutsideLoop, - UnlabeledCfInWhileCondition, UnlabeledInLabeledBlock, + OutsideLoopSuggestion, UnlabeledCfInWhileCondition, UnlabeledInLabeledBlock, }; #[derive(Clone, Copy, Debug, PartialEq)] enum Context { Normal, + Fn, Loop(hir::LoopSource), Closure(Span), AsyncClosure(Span), + UnlabeledBlock(Span), LabeledBlock, Constant, } @@ -60,6 +62,25 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> { self.with_context(Constant, |v| intravisit::walk_inline_const(v, c)); } + fn visit_fn( + &mut self, + fk: hir::intravisit::FnKind<'hir>, + fd: &'hir hir::FnDecl<'hir>, + b: hir::BodyId, + _: Span, + id: LocalDefId, + ) { + self.with_context(Fn, |v| intravisit::walk_fn(v, fk, fd, b, id)); + } + + fn visit_trait_item(&mut self, trait_item: &'hir hir::TraitItem<'hir>) { + self.with_context(Fn, |v| intravisit::walk_trait_item(v, trait_item)); + } + + fn visit_impl_item(&mut self, impl_item: &'hir hir::ImplItem<'hir>) { + self.with_context(Fn, |v| intravisit::walk_impl_item(v, impl_item)); + } + fn visit_expr(&mut self, e: &'hir hir::Expr<'hir>) { match e.kind { hir::ExprKind::Loop(ref b, _, source, _) => { @@ -83,6 +104,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) => { + self.with_context(Normal, |v| v.visit_block(&b)); + } + hir::ExprKind::Block(ref b, None) + if matches!(self.cx, Normal | Constant | UnlabeledBlock(_)) => + { + self.with_context(UnlabeledBlock(b.span.shrink_to_lo()), |v| v.visit_block(&b)); + } hir::ExprKind::Break(break_label, ref opt_expr) => { if let Some(e) = opt_expr { self.visit_expr(e); @@ -147,7 +176,12 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> { } } - self.require_break_cx("break", e.span); + let sp_lo = e.span.with_lo(e.span.lo() + BytePos("break".len() as u32)); + let label_sp = match break_label.label { + 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); } hir::ExprKind::Continue(destination) => { self.require_label_in_labeled_block(e.span, &destination, "continue"); @@ -169,7 +203,7 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> { } Err(_) => {} } - self.require_break_cx("continue", e.span) + self.require_break_cx("continue", e.span, e.span) } _ => intravisit::walk_expr(self, e), } @@ -187,7 +221,8 @@ impl<'a, 'hir> CheckLoopVisitor<'a, 'hir> { self.cx = old_cx; } - fn require_break_cx(&self, name: &str, span: Span) { + fn require_break_cx(&self, name: &str, span: Span, break_span: Span) { + let is_break = name == "break"; match self.cx { LabeledBlock | Loop(_) => {} Closure(closure_span) => { @@ -196,8 +231,12 @@ impl<'a, 'hir> CheckLoopVisitor<'a, 'hir> { AsyncClosure(closure_span) => { self.sess.emit_err(BreakInsideAsyncBlock { span, closure_span, name }); } - Normal | Constant => { - self.sess.emit_err(OutsideLoop { span, name, is_break: name == "break" }); + UnlabeledBlock(block_span) if is_break && block_span.eq_ctxt(break_span) => { + let suggestion = Some(OutsideLoopSuggestion { block_span, break_span }); + self.sess.emit_err(OutsideLoop { span, name, is_break, suggestion }); + } + Normal | Constant | Fn | UnlabeledBlock(_) => { + self.sess.emit_err(OutsideLoop { span, name, is_break, suggestion: None }); } } } diff --git a/compiler/rustc_passes/src/reachable.rs b/compiler/rustc_passes/src/reachable.rs index 1239d6d91..650bb97c4 100644 --- a/compiler/rustc_passes/src/reachable.rs +++ b/compiler/rustc_passes/src/reachable.rs @@ -18,43 +18,10 @@ use rustc_middle::ty::{self, TyCtxt}; use rustc_session::config::CrateType; use rustc_target::spec::abi::Abi; -// Returns true if the given item must be inlined because it may be -// monomorphized or it was marked with `#[inline]`. This will only return -// true for functions. -fn item_might_be_inlined(tcx: TyCtxt<'_>, item: &hir::Item<'_>, attrs: &CodegenFnAttrs) -> bool { - if attrs.requests_inline() { - return true; - } - - match item.kind { - hir::ItemKind::Fn(ref sig, ..) if sig.header.is_const() => true, - hir::ItemKind::Impl { .. } | hir::ItemKind::Fn(..) => { - let generics = tcx.generics_of(item.owner_id); - generics.requires_monomorphization(tcx) - } - _ => false, - } -} - -fn method_might_be_inlined( - tcx: TyCtxt<'_>, - impl_item: &hir::ImplItem<'_>, - impl_src: LocalDefId, -) -> bool { - let codegen_fn_attrs = tcx.codegen_fn_attrs(impl_item.hir_id().owner.to_def_id()); - let generics = tcx.generics_of(impl_item.owner_id); - if codegen_fn_attrs.requests_inline() || generics.requires_monomorphization(tcx) { - return true; - } - if let hir::ImplItemKind::Fn(method_sig, _) = &impl_item.kind { - if method_sig.header.is_const() { - return true; - } - } - match tcx.hir().find_by_def_id(impl_src) { - Some(Node::Item(item)) => item_might_be_inlined(tcx, &item, codegen_fn_attrs), - Some(..) | None => span_bug!(impl_item.span, "impl did is not an item"), - } +fn item_might_be_inlined(tcx: TyCtxt<'_>, def_id: DefId) -> bool { + tcx.generics_of(def_id).requires_monomorphization(tcx) + || tcx.cross_crate_inlinable(def_id) + || tcx.is_const_fn(def_id) } // Information needed while computing reachability. @@ -97,7 +64,9 @@ impl<'tcx> Visitor<'tcx> for ReachableContext<'tcx> { _ => None, }; - if let Some(res) = res && let Some(def_id) = res.opt_def_id().and_then(|el| el.as_local()) { + if let Some(res) = res + && let Some(def_id) = res.opt_def_id().and_then(|el| el.as_local()) + { if self.def_id_represents_local_inlined_item(def_id.to_def_id()) { self.worklist.push(def_id); } else { @@ -148,9 +117,7 @@ impl<'tcx> ReachableContext<'tcx> { match self.tcx.hir().find_by_def_id(def_id) { Some(Node::Item(item)) => match item.kind { - hir::ItemKind::Fn(..) => { - item_might_be_inlined(self.tcx, &item, self.tcx.codegen_fn_attrs(def_id)) - } + hir::ItemKind::Fn(..) => item_might_be_inlined(self.tcx, def_id.into()), _ => false, }, Some(Node::TraitItem(trait_method)) => match trait_method.kind { @@ -162,9 +129,7 @@ impl<'tcx> ReachableContext<'tcx> { Some(Node::ImplItem(impl_item)) => match impl_item.kind { hir::ImplItemKind::Const(..) => true, hir::ImplItemKind::Fn(..) => { - let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id); - let impl_did = self.tcx.hir().get_parent_item(hir_id); - method_might_be_inlined(self.tcx, impl_item, impl_did.def_id) + item_might_be_inlined(self.tcx, impl_item.hir_id().owner.to_def_id()) } hir::ImplItemKind::Type(_) => false, }, @@ -224,11 +189,7 @@ impl<'tcx> ReachableContext<'tcx> { Node::Item(item) => { match item.kind { hir::ItemKind::Fn(.., body) => { - if item_might_be_inlined( - self.tcx, - &item, - self.tcx.codegen_fn_attrs(item.owner_id), - ) { + if item_might_be_inlined(self.tcx, item.owner_id.into()) { self.visit_nested_body(body); } } @@ -277,8 +238,7 @@ impl<'tcx> ReachableContext<'tcx> { self.visit_nested_body(body); } hir::ImplItemKind::Fn(_, body) => { - let impl_def_id = self.tcx.local_parent(search_item); - if method_might_be_inlined(self.tcx, impl_item, impl_def_id) { + if item_might_be_inlined(self.tcx, impl_item.hir_id().owner.to_def_id()) { self.visit_nested_body(body) } } diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index 9c265e8ec..6a2498f3f 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -3,8 +3,8 @@ use crate::errors; use rustc_attr::{ - self as attr, rust_version_symbol, ConstStability, Stability, StabilityLevel, Unstable, - UnstableReason, VERSION_PLACEHOLDER, + self as attr, ConstStability, DeprecatedSince, Stability, StabilityLevel, StableSince, + Unstable, UnstableReason, VERSION_PLACEHOLDER, }; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap}; use rustc_hir as hir; @@ -24,8 +24,6 @@ use rustc_span::symbol::{sym, Symbol}; use rustc_span::Span; use rustc_target::spec::abi::Abi; -use std::cmp::Ordering; -use std::iter; use std::mem::replace; use std::num::NonZeroU32; @@ -198,10 +196,8 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { } } - if let Some((rustc_attr::Deprecation { is_since_rustc_version: true, .. }, span)) = &depr { - if stab.is_none() { - self.tcx.sess.emit_err(errors::DeprecatedAttribute { span: *span }); - } + if let Some((depr, span)) = &depr && depr.is_since_rustc_version() && stab.is_none() { + self.tcx.sess.emit_err(errors::DeprecatedAttribute { span: *span }); } if let Some((body_stab, _span)) = body_stab { @@ -223,40 +219,25 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { // Check if deprecated_since < stable_since. If it is, // this is *almost surely* an accident. - if let (&Some(dep_since), &attr::Stable { since: stab_since, .. }) = - (&depr.as_ref().and_then(|(d, _)| d.since), &stab.level) + if let ( + &Some(DeprecatedSince::RustcVersion(dep_since)), + &attr::Stable { since: stab_since, .. }, + ) = (&depr.as_ref().map(|(d, _)| d.since), &stab.level) { - // Explicit version of iter::order::lt to handle parse errors properly - for (dep_v, stab_v) in - iter::zip(dep_since.as_str().split('.'), stab_since.as_str().split('.')) - { - match stab_v.parse::<u64>() { - Err(_) => { - self.tcx.sess.emit_err(errors::InvalidStability { span, item_sp }); - break; + match stab_since { + StableSince::Current => { + self.tcx.sess.emit_err(errors::CannotStabilizeDeprecated { span, item_sp }); + } + StableSince::Version(stab_since) => { + if dep_since < stab_since { + self.tcx + .sess + .emit_err(errors::CannotStabilizeDeprecated { span, item_sp }); } - Ok(stab_vp) => match dep_v.parse::<u64>() { - Ok(dep_vp) => match dep_vp.cmp(&stab_vp) { - Ordering::Less => { - self.tcx.sess.emit_err(errors::CannotStabilizeDeprecated { - span, - item_sp, - }); - break; - } - Ordering::Equal => continue, - Ordering::Greater => break, - }, - Err(_) => { - if dep_v != "TBD" { - self.tcx.sess.emit_err(errors::InvalidDeprecationVersion { - span, - item_sp, - }); - } - break; - } - }, + } + StableSince::Err => { + // An error already reported. Assume the unparseable stabilization + // version is older than the deprecation version. } } } @@ -998,14 +979,17 @@ pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) { all_implications: &FxHashMap<Symbol, Symbol>, ) { for (feature, since) in defined_features { - if let Some(since) = since && let Some(span) = remaining_lib_features.get(&feature) { + if let Some(since) = since + && let Some(span) = remaining_lib_features.get(&feature) + { // Warn if the user has enabled an already-stable lib feature. if let Some(implies) = all_implications.get(&feature) { - unnecessary_partially_stable_feature_lint(tcx, *span, *feature, *implies, *since); + unnecessary_partially_stable_feature_lint( + tcx, *span, *feature, *implies, *since, + ); } else { unnecessary_stable_feature_lint(tcx, *span, *feature, *since); } - } remaining_lib_features.remove(feature); @@ -1106,7 +1090,7 @@ fn unnecessary_stable_feature_lint( mut since: Symbol, ) { if since.as_str() == VERSION_PLACEHOLDER { - since = rust_version_symbol(); + since = sym::env_CFG_RELEASE; } tcx.emit_spanned_lint( lint::builtin::STABLE_FEATURES, diff --git a/compiler/rustc_passes/src/weak_lang_items.rs b/compiler/rustc_passes/src/weak_lang_items.rs index 75e071f1f..9a6fb88c2 100644 --- a/compiler/rustc_passes/src/weak_lang_items.rs +++ b/compiler/rustc_passes/src/weak_lang_items.rs @@ -26,7 +26,9 @@ pub fn check_crate(tcx: TyCtxt<'_>, items: &mut lang_items::LanguageItems) { for id in crate_items.foreign_items() { let attrs = tcx.hir().attrs(id.hir_id()); if let Some((lang_item, _)) = lang_items::extract(attrs) { - if let Some(item) = LangItem::from_name(lang_item) && item.is_weak() { + if let Some(item) = LangItem::from_name(lang_item) + && item.is_weak() + { if items.get(item).is_none() { items.missing.push(item); } |