diff options
Diffstat (limited to 'compiler/rustc_passes')
-rw-r--r-- | compiler/rustc_passes/src/check_attr.rs | 277 | ||||
-rw-r--r-- | compiler/rustc_passes/src/check_const.rs | 17 | ||||
-rw-r--r-- | compiler/rustc_passes/src/dead.rs | 136 | ||||
-rw-r--r-- | compiler/rustc_passes/src/debugger_visualizer.rs | 15 | ||||
-rw-r--r-- | compiler/rustc_passes/src/diagnostic_items.rs | 45 | ||||
-rw-r--r-- | compiler/rustc_passes/src/entry.rs | 157 | ||||
-rw-r--r-- | compiler/rustc_passes/src/errors.rs | 1095 | ||||
-rw-r--r-- | compiler/rustc_passes/src/hir_id_validator.rs | 23 | ||||
-rw-r--r-- | compiler/rustc_passes/src/hir_stats.rs | 4 | ||||
-rw-r--r-- | compiler/rustc_passes/src/lang_items.rs | 211 | ||||
-rw-r--r-- | compiler/rustc_passes/src/layout_test.rs | 77 | ||||
-rw-r--r-- | compiler/rustc_passes/src/lib.rs | 3 | ||||
-rw-r--r-- | compiler/rustc_passes/src/lib_features.rs | 34 | ||||
-rw-r--r-- | compiler/rustc_passes/src/liveness.rs | 65 | ||||
-rw-r--r-- | compiler/rustc_passes/src/loops.rs | 161 | ||||
-rw-r--r-- | compiler/rustc_passes/src/naked_functions.rs | 88 | ||||
-rw-r--r-- | compiler/rustc_passes/src/reachable.rs | 53 | ||||
-rw-r--r-- | compiler/rustc_passes/src/stability.rs | 230 | ||||
-rw-r--r-- | compiler/rustc_passes/src/weak_lang_items.rs | 31 |
19 files changed, 1659 insertions, 1063 deletions
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index b3f15ba7c..27a57adf9 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -4,16 +4,21 @@ //! conflicts between multiple such attributes attached to the same //! item. -use crate::errors; +use crate::errors::{ + self, AttrApplication, DebugVisualizerUnreadable, InvalidAttrAtCrateLevel, ObjectLifetimeErr, + OnlyHasEffectOn, TransparentIncompatible, UnrecognizedReprHint, +}; use rustc_ast::{ast, AttrStyle, Attribute, Lit, LitKind, MetaItemKind, NestedMetaItem}; use rustc_data_structures::fx::FxHashMap; -use rustc_errors::{fluent, struct_span_err, Applicability, MultiSpan}; +use rustc_errors::{fluent, Applicability, MultiSpan}; use rustc_expand::base::resolve_path; use rustc_feature::{AttributeDuplicates, AttributeType, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP}; use rustc_hir as hir; -use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID}; +use rustc_hir::def_id::LocalDefId; use rustc_hir::intravisit::{self, Visitor}; -use rustc_hir::{self, FnSig, ForeignItem, HirId, Item, ItemKind, TraitItem, CRATE_HIR_ID}; +use rustc_hir::{ + self, FnSig, ForeignItem, HirId, Item, ItemKind, TraitItem, CRATE_HIR_ID, CRATE_OWNER_ID, +}; use rustc_hir::{MethodKind, Target}; use rustc_middle::hir::nested_filter; use rustc_middle::middle::resolve_lifetime::ObjectLifetimeDefault; @@ -35,8 +40,8 @@ pub(crate) fn target_from_impl_item<'tcx>( match impl_item.kind { hir::ImplItemKind::Const(..) => Target::AssocConst, hir::ImplItemKind::Fn(..) => { - let parent_hir_id = tcx.hir().get_parent_item(impl_item.hir_id()); - let containing_item = tcx.hir().expect_item(parent_hir_id); + let parent_def_id = tcx.hir().get_parent_item(impl_item.hir_id()).def_id; + let containing_item = tcx.hir().expect_item(parent_def_id); let containing_impl_is_for_trait = match &containing_item.kind { hir::ItemKind::Impl(impl_) => impl_.of_trait.is_some(), _ => bug!("parent of an ImplItem must be an Impl"), @@ -47,7 +52,7 @@ pub(crate) fn target_from_impl_item<'tcx>( Target::Method(MethodKind::Inherent) } } - hir::ImplItemKind::TyAlias(..) => Target::AssocTy, + hir::ImplItemKind::Type(..) => Target::AssocTy, } } @@ -162,17 +167,17 @@ impl CheckAttrVisitor<'_> { sym::no_mangle => self.check_no_mangle(hir_id, attr, span, target), 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::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 | sym::proc_macro_derive => { - self.check_generic_attr(hir_id, attr, target, &[Target::Fn]) + self.check_generic_attr(hir_id, attr, target, Target::Fn) } sym::automatically_derived => { - self.check_generic_attr(hir_id, attr, target, &[Target::Impl]) + self.check_generic_attr(hir_id, attr, target, Target::Impl) } sym::no_implicit_prelude => { - self.check_generic_attr(hir_id, attr, target, &[Target::Mod]) + self.check_generic_attr(hir_id, attr, target, Target::Mod) } sym::rustc_object_lifetime_default => self.check_object_lifetime_default(hir_id), _ => {} @@ -263,7 +268,7 @@ impl CheckAttrVisitor<'_> { } // FIXME(#65833): We permit associated consts to have an `#[inline]` attribute with // just a lint, because we previously erroneously allowed it and some crates used it - // accidentally, to to be compatible with crates depending on them, we can't throw an + // accidentally, to be compatible with crates depending on them, we can't throw an // error here. Target::AssocConst => { self.tcx.emit_spanned_lint( @@ -349,29 +354,18 @@ impl CheckAttrVisitor<'_> { hir_id: HirId, attr: &Attribute, target: Target, - allowed_targets: &[Target], + allowed_target: Target, ) { - if !allowed_targets.iter().any(|t| t == &target) { - let name = attr.name_or_empty(); - let mut i = allowed_targets.iter(); - // Pluralize - let b = i.next().map_or_else(String::new, |t| t.to_string() + "s"); - let supported_names = i.enumerate().fold(b, |mut b, (i, allowed_target)| { - if allowed_targets.len() > 2 && i == allowed_targets.len() - 2 { - b.push_str(", and "); - } else if allowed_targets.len() == 2 && i == allowed_targets.len() - 2 { - b.push_str(" and "); - } else { - b.push_str(", "); - } - // Pluralize - b.push_str(&(allowed_target.to_string() + "s")); - b - }); - self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| { - lint.build(&format!("`#[{name}]` only has an effect on {}", supported_names)) - .emit(); - }); + if target != allowed_target { + self.tcx.emit_spanned_lint( + UNUSED_ATTRIBUTES, + hir_id, + attr.span, + OnlyHasEffectOn { + attr_name: attr.name_or_empty(), + target_name: allowed_target.name().replace(" ", "_"), + }, + ); } } @@ -382,7 +376,7 @@ impl CheckAttrVisitor<'_> { | Target::Method(MethodKind::Trait { body: true } | MethodKind::Inherent) => true, // FIXME(#80564): We permit struct fields, match arms and macro defs to have an // `#[allow_internal_unstable]` attribute with just a lint, because we previously - // erroneously allowed it and some crates used it accidentally, to to be compatible + // erroneously allowed it and some crates used it accidentally, to be compatible // with crates depending on them, we can't throw an error here. Target::Field | Target::Arm | Target::MacroDef => { self.inline_attr_str_error_with_macro_def(hir_id, attr, "naked"); @@ -427,7 +421,7 @@ impl CheckAttrVisitor<'_> { ObjectLifetimeDefault::Param(def_id) => tcx.item_name(def_id).to_string(), ObjectLifetimeDefault::Ambiguous => "Ambiguous".to_owned(), }; - tcx.sess.span_err(p.span, &repr); + tcx.sess.emit_err(ObjectLifetimeErr { span: p.span, repr }); } } } @@ -462,7 +456,7 @@ impl CheckAttrVisitor<'_> { Target::Fn | 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 to be compatible + // erroneously allowed it and some crates used it accidentally, to be compatible // with crates depending on them, we can't throw an error here. Target::Field | Target::Arm | Target::MacroDef => { for attr in attrs { @@ -491,7 +485,7 @@ impl CheckAttrVisitor<'_> { Target::Struct | Target::Enum | Target::Variant => true, // FIXME(#80564): We permit struct fields, match arms and macro defs to have an // `#[non_exhaustive]` attribute with just a lint, because we previously - // erroneously allowed it and some crates used it accidentally, to to be compatible + // erroneously allowed it and some crates used it accidentally, to be compatible // with crates depending on them, we can't throw an error here. Target::Field | Target::Arm | Target::MacroDef => { self.inline_attr_str_error_with_macro_def(hir_id, attr, "non_exhaustive"); @@ -513,7 +507,7 @@ impl CheckAttrVisitor<'_> { Target::Trait => true, // FIXME(#80564): We permit struct fields, match arms and macro defs to have an // `#[marker]` attribute with just a lint, because we previously - // erroneously allowed it and some crates used it accidentally, to to be compatible + // erroneously allowed it and some crates used it accidentally, to be compatible // with crates depending on them, we can't throw an error here. Target::Field | Target::Arm | Target::MacroDef => { self.inline_attr_str_error_with_macro_def(hir_id, attr, "marker"); @@ -572,7 +566,7 @@ impl CheckAttrVisitor<'_> { } // FIXME(#80564): We permit struct fields, match arms and macro defs to have an // `#[target_feature]` attribute with just a lint, because we previously - // erroneously allowed it and some crates used it accidentally, to to be compatible + // erroneously allowed it and some crates used it accidentally, to be compatible // with crates depending on them, we can't throw an error here. Target::Field | Target::Arm | Target::MacroDef => { self.inline_attr_str_error_with_macro_def(hir_id, attr, "target_feature"); @@ -640,8 +634,8 @@ impl CheckAttrVisitor<'_> { let span = meta.span(); if let Some(location) = match target { Target::AssocTy => { - let parent_hir_id = self.tcx.hir().get_parent_item(hir_id); - let containing_item = self.tcx.hir().expect_item(parent_hir_id); + let parent_def_id = self.tcx.hir().get_parent_item(hir_id).def_id; + let containing_item = self.tcx.hir().expect_item(parent_def_id); if Target::from_item(containing_item) == Target::Impl { Some("type alias in implementation block") } else { @@ -649,8 +643,8 @@ impl CheckAttrVisitor<'_> { } } Target::AssocConst => { - let parent_hir_id = self.tcx.hir().get_parent_item(hir_id); - let containing_item = self.tcx.hir().expect_item(parent_hir_id); + let parent_def_id = self.tcx.hir().get_parent_item(hir_id).def_id; + let containing_item = self.tcx.hir().expect_item(parent_def_id); // We can't link to trait impl's consts. let err = "associated constant in trait implementation block"; match containing_item.kind { @@ -828,8 +822,8 @@ impl CheckAttrVisitor<'_> { if let Some((prev_inline, prev_span)) = *specified_inline { if do_inline != prev_inline { let mut spans = MultiSpan::from_spans(vec![prev_span, meta.span()]); - spans.push_span_label(prev_span, fluent::passes::doc_inline_conflict_first); - spans.push_span_label(meta.span(), fluent::passes::doc_inline_conflict_second); + spans.push_span_label(prev_span, fluent::passes_doc_inline_conflict_first); + spans.push_span_label(meta.span(), fluent::passes_doc_inline_conflict_second); self.tcx.sess.emit_err(errors::DocKeywordConflict { spans }); return false; } @@ -875,25 +869,31 @@ impl CheckAttrVisitor<'_> { hir_id: HirId, ) -> bool { if hir_id != CRATE_HIR_ID { - self.tcx.struct_span_lint_hir(INVALID_DOC_ATTRIBUTES, hir_id, meta.span(), |lint| { - let mut err = lint.build(fluent::passes::attr_crate_level); - if attr.style == AttrStyle::Outer - && self.tcx.hir().get_parent_item(hir_id) == CRATE_DEF_ID - { - if let Ok(mut src) = self.tcx.sess.source_map().span_to_snippet(attr.span) { - src.insert(1, '!'); - err.span_suggestion_verbose( - attr.span, - fluent::passes::suggestion, - src, - Applicability::MaybeIncorrect, - ); - } else { - err.span_help(attr.span, fluent::passes::help); + self.tcx.struct_span_lint_hir( + INVALID_DOC_ATTRIBUTES, + hir_id, + meta.span(), + fluent::passes_attr_crate_level, + |err| { + if attr.style == AttrStyle::Outer + && self.tcx.hir().get_parent_item(hir_id) == CRATE_OWNER_ID + { + if let Ok(mut src) = self.tcx.sess.source_map().span_to_snippet(attr.span) { + src.insert(1, '!'); + err.span_suggestion_verbose( + attr.span, + fluent::suggestion, + src, + Applicability::MaybeIncorrect, + ); + } else { + err.span_help(attr.span, fluent::help); + } } - } - err.note(fluent::passes::note).emit(); - }); + err.note(fluent::note); + err + }, + ); return false; } true @@ -934,6 +934,22 @@ impl CheckAttrVisitor<'_> { is_valid } + /// Check that the `#![doc(cfg_hide(...))]` attribute only contains a list of attributes. + /// Returns `true` if valid. + fn check_doc_cfg_hide(&self, meta: &NestedMetaItem, hir_id: HirId) -> bool { + if meta.meta_item_list().is_some() { + true + } else { + self.tcx.emit_spanned_lint( + INVALID_DOC_ATTRIBUTES, + hir_id, + meta.span(), + errors::DocCfgHideTakesList, + ); + false + } + } + /// Runs various checks on `#[doc]` attributes. Returns `true` if valid. /// /// `specified_inline` should be initialized to `None` and kept for the scope @@ -987,6 +1003,13 @@ impl CheckAttrVisitor<'_> { is_valid = false; } + sym::cfg_hide + if !self.check_attr_crate_level(attr, meta, hir_id) + || !self.check_doc_cfg_hide(meta, hir_id) => + { + is_valid = false; + } + sym::inline | sym::no_inline if !self.check_doc_inline( attr, @@ -1205,7 +1228,7 @@ impl CheckAttrVisitor<'_> { Target::Fn | Target::Method(..) | Target::ForeignFn | Target::Closure => {} // FIXME(#80564): We permit struct fields, match arms and macro defs to have an // `#[cold]` attribute with just a lint, because we previously - // erroneously allowed it and some crates used it accidentally, to to be compatible + // erroneously allowed it and some crates used it accidentally, to be compatible // with crates depending on them, we can't throw an error here. Target::Field | Target::Arm | Target::MacroDef => { self.inline_attr_str_error_with_macro_def(hir_id, attr, "cold"); @@ -1247,7 +1270,7 @@ impl CheckAttrVisitor<'_> { Target::ForeignFn | Target::ForeignStatic => {} // FIXME(#80564): We permit struct fields, match arms and macro defs to have an // `#[link_name]` attribute with just a lint, because we previously - // erroneously allowed it and some crates used it accidentally, to to be compatible + // erroneously allowed it and some crates used it accidentally, to be compatible // with crates depending on them, we can't throw an error here. Target::Field | Target::Arm | Target::MacroDef => { self.inline_attr_str_error_with_macro_def(hir_id, attr, "link_name"); @@ -1281,7 +1304,7 @@ impl CheckAttrVisitor<'_> { Target::ExternCrate => true, // FIXME(#80564): We permit struct fields, match arms and macro defs to have an // `#[no_link]` attribute with just a lint, because we previously - // erroneously allowed it and some crates used it accidentally, to to be compatible + // erroneously allowed it and some crates used it accidentally, to be compatible // with crates depending on them, we can't throw an error here. Target::Field | Target::Arm | Target::MacroDef => { self.inline_attr_str_error_with_macro_def(hir_id, attr, "no_link"); @@ -1311,7 +1334,7 @@ impl CheckAttrVisitor<'_> { Target::Method(..) if self.is_impl_item(hir_id) => true, // FIXME(#80564): We permit struct fields, match arms and macro defs to have an // `#[export_name]` attribute with just a lint, because we previously - // erroneously allowed it and some crates used it accidentally, to to be compatible + // erroneously allowed it and some crates used it accidentally, to be compatible // with crates depending on them, we can't throw an error here. Target::Field | Target::Arm | Target::MacroDef => { self.inline_attr_str_error_with_macro_def(hir_id, attr, "export_name"); @@ -1503,7 +1526,7 @@ impl CheckAttrVisitor<'_> { Target::Static | Target::Fn | Target::Method(..) => {} // FIXME(#80564): We permit struct fields, match arms and macro defs to have an // `#[link_section]` attribute with just a lint, because we previously - // erroneously allowed it and some crates used it accidentally, to to be compatible + // erroneously allowed it and some crates used it accidentally, to be compatible // with crates depending on them, we can't throw an error here. Target::Field | Target::Arm | Target::MacroDef => { self.inline_attr_str_error_with_macro_def(hir_id, attr, "link_section"); @@ -1528,7 +1551,7 @@ impl CheckAttrVisitor<'_> { Target::Method(..) if self.is_impl_item(hir_id) => {} // FIXME(#80564): We permit struct fields, match arms and macro defs to have an // `#[no_mangle]` attribute with just a lint, because we previously - // erroneously allowed it and some crates used it accidentally, to to be compatible + // erroneously allowed it and some crates used it accidentally, to be compatible // with crates depending on them, we can't throw an error here. Target::Field | Target::Arm | Target::MacroDef => { self.inline_attr_str_error_with_macro_def(hir_id, attr, "no_mangle"); @@ -1594,12 +1617,17 @@ impl CheckAttrVisitor<'_> { continue; } - let (article, allowed_targets) = match hint.name_or_empty() { + match hint.name_or_empty() { sym::C => { is_c = true; match target { Target::Struct | Target::Union | Target::Enum => continue, - _ => ("a", "struct, enum, or union"), + _ => { + self.tcx.sess.emit_err(AttrApplication::StructEnumUnion { + hint_span: hint.span(), + span, + }); + } } } sym::align => { @@ -1615,12 +1643,20 @@ impl CheckAttrVisitor<'_> { match target { Target::Struct | Target::Union | Target::Enum | Target::Fn => continue, - _ => ("a", "struct, enum, function, or union"), + _ => { + self.tcx.sess.emit_err(AttrApplication::StructEnumFunctionUnion { + hint_span: hint.span(), + span, + }); + } } } sym::packed => { if target != Target::Struct && target != Target::Union { - ("a", "struct or union") + self.tcx.sess.emit_err(AttrApplication::StructUnion { + hint_span: hint.span(), + span, + }); } else { continue; } @@ -1628,7 +1664,9 @@ impl CheckAttrVisitor<'_> { sym::simd => { is_simd = true; if target != Target::Struct { - ("a", "struct") + self.tcx + .sess + .emit_err(AttrApplication::Struct { hint_span: hint.span(), span }); } else { continue; } @@ -1637,7 +1675,12 @@ impl CheckAttrVisitor<'_> { is_transparent = true; match target { Target::Struct | Target::Union | Target::Enum => continue, - _ => ("a", "struct, enum, or union"), + _ => { + self.tcx.sess.emit_err(AttrApplication::StructEnumUnion { + hint_span: hint.span(), + span, + }); + } } } sym::i8 @@ -1654,35 +1697,18 @@ impl CheckAttrVisitor<'_> { | sym::usize => { int_reprs += 1; if target != Target::Enum { - ("an", "enum") + self.tcx + .sess + .emit_err(AttrApplication::Enum { hint_span: hint.span(), span }); } else { continue; } } _ => { - struct_span_err!( - self.tcx.sess, - hint.span(), - E0552, - "unrecognized representation hint" - ) - .help("valid reprs are `C`, `align`, `packed`, `transparent`, `simd`, `i8`, `u8`, \ - `i16`, `u16`, `i32`, `u32`, `i64`, `u64`, `i128`, `u128`, `isize`, `usize`") - .emit(); - + self.tcx.sess.emit_err(UnrecognizedReprHint { span: hint.span() }); continue; } }; - - struct_span_err!( - self.tcx.sess, - hint.span(), - E0517, - "{}", - &format!("attribute should be applied to {article} {allowed_targets}") - ) - .span_label(span, &format!("not {article} {allowed_targets}")) - .emit(); } // Just point at all repr hints if there are any incompatibilities. @@ -1692,14 +1718,9 @@ impl CheckAttrVisitor<'_> { // Error on repr(transparent, <anything else>). if is_transparent && hints.len() > 1 { let hint_spans: Vec<_> = hint_spans.clone().collect(); - struct_span_err!( - self.tcx.sess, - hint_spans, - E0692, - "transparent {} cannot have other repr hints", - target - ) - .emit(); + self.tcx + .sess + .emit_err(TransparentIncompatible { hint_spans, target: target.to_string() }); } // Warn on repr(u8, u16), repr(C, simd), and c-like-enum-repr(C, u8) if (int_reprs > 1) @@ -1742,7 +1763,7 @@ impl CheckAttrVisitor<'_> { } } Some(_) => { - // This error case is handled in rustc_typeck::collect. + // This error case is handled in rustc_hir_analysis::collect. } None => { // Default case (compiler) when arg isn't defined. @@ -1784,7 +1805,7 @@ impl CheckAttrVisitor<'_> { Target::MacroDef => true, // FIXME(#80564): We permit struct fields and match arms to have an // `#[allow_internal_unstable]` attribute with just a lint, because we previously - // erroneously allowed it and some crates used it accidentally, to to be compatible + // erroneously allowed it and some crates used it accidentally, to be compatible // with crates depending on them, we can't throw an error here. Target::Field | Target::Arm => { self.inline_attr_str_error_without_macro_def( @@ -1851,14 +1872,12 @@ impl CheckAttrVisitor<'_> { match std::fs::File::open(&file) { Ok(_) => true, - Err(err) => { - self.tcx - .sess - .struct_span_err( - meta_item.span, - &format!("couldn't read {}: {}", file.display(), err), - ) - .emit(); + Err(error) => { + self.tcx.sess.emit_err(DebugVisualizerUnreadable { + span: meta_item.span, + file: &file, + error, + }); false } } @@ -1881,7 +1900,7 @@ impl CheckAttrVisitor<'_> { } // FIXME(#80564): We permit struct fields and match arms to have an // `#[allow_internal_unstable]` attribute with just a lint, because we previously - // erroneously allowed it and some crates used it accidentally, to to be compatible + // erroneously allowed it and some crates used it accidentally, to be compatible // with crates depending on them, we can't throw an error here. Target::Field | Target::Arm | Target::MacroDef => { self.inline_attr_str_error_with_macro_def(hir_id, attr, "allow_internal_unstable"); @@ -2043,7 +2062,7 @@ impl<'tcx> Visitor<'tcx> for CheckAttrVisitor<'tcx> { // so this lets us continue to run them while maintaining backwards compatibility. // In the long run, the checks should be harmonized. if let ItemKind::Macro(ref macro_def, _) = item.kind { - let def_id = item.def_id.to_def_id(); + let def_id = item.owner_id.to_def_id(); if macro_def.macro_rules && !self.tcx.has_attr(def_id, sym::macro_export) { check_non_exported_macro_for_invalid_attrs(self.tcx, item); } @@ -2169,25 +2188,11 @@ 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 mut err = tcx.sess.struct_span_err( - attr.span, - &format!( - "`{}` attribute cannot be used at crate level", - attr_to_check.to_ident_string() - ), - ); - // Only emit an error with a suggestion if we can create a - // string out of the attribute span - if let Ok(src) = tcx.sess.source_map().span_to_snippet(attr.span) { - let replacement = src.replace("#!", "#"); - err.span_suggestion_verbose( - attr.span, - "perhaps you meant to use an outer attribute", - replacement, - rustc_errors::Applicability::MachineApplicable, - ); - } - err.emit(); + tcx.sess.emit_err(InvalidAttrAtCrateLevel { + span: attr.span, + snippet: tcx.sess.source_map().span_to_snippet(attr.span).ok(), + name: *attr_to_check, + }); } } } diff --git a/compiler/rustc_passes/src/check_const.rs b/compiler/rustc_passes/src/check_const.rs index 70518284c..aa726d6cd 100644 --- a/compiler/rustc_passes/src/check_const.rs +++ b/compiler/rustc_passes/src/check_const.rs @@ -8,7 +8,6 @@ //! through, but errors for structured control flow in a `const` should be emitted here. use rustc_attr as attr; -use rustc_errors::struct_span_err; use rustc_hir as hir; use rustc_hir::def_id::LocalDefId; use rustc_hir::intravisit::{self, Visitor}; @@ -18,6 +17,8 @@ use rustc_middle::ty::TyCtxt; use rustc_session::parse::feature_err; use rustc_span::{sym, Span, Symbol}; +use crate::errors::ExprNotAllowedInContext; + /// An expression that is not *always* legal in a const context. #[derive(Clone, Copy)] enum NonConstExpr { @@ -133,18 +134,22 @@ impl<'tcx> CheckConstVisitor<'tcx> { let const_kind = const_kind.expect("`const_check_violated` may only be called inside a const context"); - let msg = format!("{} is not allowed in a `{}`", expr.name(), const_kind.keyword_name()); - let required_gates = required_gates.unwrap_or(&[]); let missing_gates: Vec<_> = required_gates.iter().copied().filter(|&g| !features.enabled(g)).collect(); match missing_gates.as_slice() { [] => { - struct_span_err!(tcx.sess, span, E0744, "{}", msg).emit(); + tcx.sess.emit_err(ExprNotAllowedInContext { + span, + expr: expr.name(), + context: const_kind.keyword_name(), + }); } [missing_primary, ref missing_secondary @ ..] => { + let msg = + format!("{} is not allowed in a `{}`", expr.name(), const_kind.keyword_name()); let mut err = feature_err(&tcx.sess.parse_sess, *missing_primary, span, &msg); // If multiple feature gates would be required to enable this expression, include @@ -191,10 +196,6 @@ impl<'tcx> Visitor<'tcx> for CheckConstVisitor<'tcx> { self.tcx.hir() } - fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) { - intravisit::walk_item(self, item); - } - fn visit_anon_const(&mut self, anon: &'tcx hir::AnonConst) { let kind = Some(hir::ConstContext::Const); self.recurse_into(kind, None, |this| intravisit::walk_anon_const(this, anon)); diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index f141d7bee..753d01f46 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -11,13 +11,15 @@ use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{Node, PatKind, TyKind}; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; -use rustc_middle::middle::privacy; +use rustc_middle::middle::privacy::Level; use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, DefIdTree, TyCtxt}; use rustc_session::lint; use rustc_span::symbol::{sym, Symbol}; use std::mem; +use crate::errors::UselessAssignment; + // Any local node that may call something in its body block should be // explored. For example, if it's a live Node::Item that is a // function, then we should explore its block to check for codes that @@ -102,14 +104,8 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { } } Res::Def(_, def_id) => self.check_def_id(def_id), - Res::SelfTy { trait_: t, alias_to: i } => { - if let Some(t) = t { - self.check_def_id(t); - } - if let Some((i, _)) = i { - self.check_def_id(i); - } - } + Res::SelfTyParam { trait_: t } => self.check_def_id(t), + Res::SelfTyAlias { alias_to: i, .. } => self.check_def_id(i), Res::ToolMod | Res::NonMacroAttr(..) | Res::Err => {} } } @@ -186,18 +182,11 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { && !assign.span.from_expansion() { let is_field_assign = matches!(lhs.kind, hir::ExprKind::Field(..)); - self.tcx.struct_span_lint_hir( + self.tcx.emit_spanned_lint( lint::builtin::DEAD_CODE, assign.hir_id, assign.span, - |lint| { - lint.build(&format!( - "useless assignment of {} of type `{}` to itself", - if is_field_assign { "field" } else { "variable" }, - self.typeck_results().expr_ty(lhs), - )) - .emit(); - }, + UselessAssignment { is_field_assign, ty: self.typeck_results().expr_ty(lhs) } ) } } @@ -291,8 +280,8 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { } fn visit_node(&mut self, node: Node<'tcx>) { - if let Node::ImplItem(hir::ImplItem { def_id, .. }) = node - && self.should_ignore_item(def_id.to_def_id()) + if let Node::ImplItem(hir::ImplItem { owner_id, .. }) = node + && self.should_ignore_item(owner_id.to_def_id()) { return; } @@ -304,7 +293,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { match node { Node::Item(item) => match item.kind { hir::ItemKind::Struct(..) | hir::ItemKind::Union(..) => { - let def = self.tcx.adt_def(item.def_id); + let def = self.tcx.adt_def(item.owner_id); self.repr_has_repr_c = def.repr().c(); self.repr_has_repr_simd = def.repr().simd(); @@ -317,7 +306,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { intravisit::walk_trait_item(self, trait_item); } Node::ImplItem(impl_item) => { - let item = self.tcx.local_parent(impl_item.def_id); + let item = self.tcx.local_parent(impl_item.owner_id.def_id); if self.tcx.impl_trait_ref(item).is_none() { //// If it's a type whose items are live, then it's live, too. //// This is done to handle the case where, for example, the static @@ -374,7 +363,7 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> { if has_repr_c || (f.is_positional() && has_repr_simd) { return Some(def_id); } - if !tcx.visibility(f.hir_id.owner).is_public() { + if !tcx.visibility(f.hir_id.owner.def_id).is_public() { return None; } if tcx.visibility(def_id).is_public() { Some(def_id) } else { None } @@ -528,10 +517,10 @@ fn check_item<'tcx>( ) { let allow_dead_code = has_allow_dead_code_or_lang_attr(tcx, id.hir_id()); if allow_dead_code { - worklist.push(id.def_id); + worklist.push(id.owner_id.def_id); } - match tcx.def_kind(id.def_id) { + match tcx.def_kind(id.owner_id) { DefKind::Enum => { let item = tcx.hir().item(id); if let hir::ItemKind::Enum(ref enum_def, _) = item.kind { @@ -551,15 +540,15 @@ fn check_item<'tcx>( } } DefKind::Impl => { - let of_trait = tcx.impl_trait_ref(id.def_id); + let of_trait = tcx.impl_trait_ref(id.owner_id); if of_trait.is_some() { - worklist.push(id.def_id); + worklist.push(id.owner_id.def_id); } // get DefIds from another query let local_def_ids = tcx - .associated_item_def_ids(id.def_id) + .associated_item_def_ids(id.owner_id) .iter() .filter_map(|def_id| def_id.as_local()); @@ -577,12 +566,12 @@ fn check_item<'tcx>( if let hir::ItemKind::Struct(ref variant_data, _) = item.kind && let Some(ctor_hir_id) = variant_data.ctor_hir_id() { - struct_constructors.insert(tcx.hir().local_def_id(ctor_hir_id), item.def_id); + struct_constructors.insert(tcx.hir().local_def_id(ctor_hir_id), item.owner_id.def_id); } } DefKind::GlobalAsm => { // global_asm! is always live. - worklist.push(id.def_id); + worklist.push(id.owner_id.def_id); } _ => {} } @@ -590,12 +579,12 @@ fn check_item<'tcx>( fn check_trait_item<'tcx>(tcx: TyCtxt<'tcx>, worklist: &mut Vec<LocalDefId>, id: hir::TraitItemId) { use hir::TraitItemKind::{Const, Fn}; - if matches!(tcx.def_kind(id.def_id), DefKind::AssocConst | DefKind::AssocFn) { + 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(_))) && has_allow_dead_code_or_lang_attr(tcx, trait_item.hir_id()) { - worklist.push(trait_item.def_id); + worklist.push(trait_item.owner_id.def_id); } } } @@ -605,27 +594,24 @@ fn check_foreign_item<'tcx>( worklist: &mut Vec<LocalDefId>, id: hir::ForeignItemId, ) { - if matches!(tcx.def_kind(id.def_id), DefKind::Static(_) | DefKind::Fn) + if matches!(tcx.def_kind(id.owner_id), DefKind::Static(_) | DefKind::Fn) && has_allow_dead_code_or_lang_attr(tcx, id.hir_id()) { - worklist.push(id.def_id); + worklist.push(id.owner_id.def_id); } } fn create_and_seed_worklist<'tcx>( tcx: TyCtxt<'tcx>, ) -> (Vec<LocalDefId>, FxHashMap<LocalDefId, LocalDefId>) { - let access_levels = &tcx.privacy_access_levels(()); + let effective_visibilities = &tcx.effective_visibilities(()); // see `MarkSymbolVisitor::struct_constructors` let mut struct_constructors = Default::default(); - let mut worklist = access_levels - .map + let mut worklist = effective_visibilities .iter() - .filter_map( - |(&id, &level)| { - if level >= privacy::AccessLevel::Reachable { Some(id) } else { None } - }, - ) + .filter_map(|(&id, effective_vis)| { + effective_vis.is_public_at_level(Level::Reachable).then_some(id) + }) // Seed entry point .chain(tcx.entry_fn(()).and_then(|(def_id, _)| def_id.as_local())) .collect::<Vec<_>>(); @@ -726,6 +712,26 @@ impl<'tcx> DeadVisitor<'tcx> { }) .collect(); + let descr = tcx.def_kind(first_id).descr(first_id.to_def_id()); + let span_len = dead_codes.len(); + let names = match &names[..] { + _ if span_len > 6 => String::new(), + [name] => format!("`{name}` "), + [names @ .., last] => { + format!( + "{} and `{last}` ", + names.iter().map(|name| format!("`{name}`")).join(", ") + ) + } + [] => unreachable!(), + }; + let msg = format!( + "{these}{descr}{s} {names}{are} never {participle}", + these = if span_len > 6 { "multiple " } else { "" }, + s = pluralize!(span_len), + are = pluralize!("is", span_len), + ); + tcx.struct_span_lint_hir( if is_positional { lint::builtin::UNUSED_TUPLE_STRUCT_FIELDS @@ -734,27 +740,8 @@ impl<'tcx> DeadVisitor<'tcx> { }, tcx.hir().local_def_id_to_hir_id(first_id), MultiSpan::from_spans(spans.clone()), - |lint| { - let descr = tcx.def_kind(first_id).descr(first_id.to_def_id()); - let span_len = dead_codes.len(); - let names = match &names[..] { - _ if span_len > 6 => String::new(), - [name] => format!("`{name}` "), - [names @ .., last] => { - format!( - "{} and `{last}` ", - names.iter().map(|name| format!("`{name}`")).join(", ") - ) - } - [] => unreachable!(), - }; - let mut err = lint.build(&format!( - "{these}{descr}{s} {names}{are} never {participle}", - these = if span_len > 6 { "multiple " } else { "" }, - s = pluralize!(span_len), - are = pluralize!("is", span_len), - )); - + msg, + |err| { if is_positional { err.multipart_suggestion( &format!( @@ -800,7 +787,7 @@ impl<'tcx> DeadVisitor<'tcx> { ); err.note(&msg); } - err.emit(); + err }, ); } @@ -874,19 +861,19 @@ fn check_mod_deathness(tcx: TyCtxt<'_>, module: LocalDefId) { let module_items = tcx.hir_module_items(module); for item in module_items.items() { - if !live_symbols.contains(&item.def_id) { - let parent = tcx.local_parent(item.def_id); + if !live_symbols.contains(&item.owner_id.def_id) { + let parent = tcx.local_parent(item.owner_id.def_id); if parent != module && !live_symbols.contains(&parent) { // We already have diagnosed something. continue; } - visitor.check_definition(item.def_id); + visitor.check_definition(item.owner_id.def_id); continue; } - let def_kind = tcx.def_kind(item.def_id); + let def_kind = tcx.def_kind(item.owner_id); if let DefKind::Struct | DefKind::Union | DefKind::Enum = def_kind { - let adt = tcx.adt_def(item.def_id); + let adt = tcx.adt_def(item.owner_id); let mut dead_variants = Vec::new(); for variant in adt.variants() { @@ -929,16 +916,21 @@ fn check_mod_deathness(tcx: TyCtxt<'_>, module: LocalDefId) { visitor.warn_dead_fields_and_variants(def_id, "read", dead_fields, is_positional) } - visitor.warn_dead_fields_and_variants(item.def_id, "constructed", dead_variants, false); + visitor.warn_dead_fields_and_variants( + item.owner_id.def_id, + "constructed", + dead_variants, + false, + ); } } for impl_item in module_items.impl_items() { - visitor.check_definition(impl_item.def_id); + visitor.check_definition(impl_item.owner_id.def_id); } for foreign_item in module_items.foreign_items() { - visitor.check_definition(foreign_item.def_id); + visitor.check_definition(foreign_item.owner_id.def_id); } // We do not warn trait items. diff --git a/compiler/rustc_passes/src/debugger_visualizer.rs b/compiler/rustc_passes/src/debugger_visualizer.rs index e08683fe2..253b0a88e 100644 --- a/compiler/rustc_passes/src/debugger_visualizer.rs +++ b/compiler/rustc_passes/src/debugger_visualizer.rs @@ -13,6 +13,8 @@ use rustc_span::{sym, DebuggerVisualizerFile, DebuggerVisualizerType}; use std::sync::Arc; +use crate::errors::DebugVisualizerUnreadable; + fn check_for_debugger_visualizer<'tcx>( tcx: TyCtxt<'tcx>, hir_id: HirId, @@ -54,13 +56,12 @@ fn check_for_debugger_visualizer<'tcx>( debugger_visualizers .insert(DebuggerVisualizerFile::new(Arc::from(contents), visualizer_type)); } - Err(err) => { - tcx.sess - .struct_span_err( - meta_item.span, - &format!("couldn't read {}: {}", file.display(), err), - ) - .emit(); + Err(error) => { + tcx.sess.emit_err(DebugVisualizerUnreadable { + span: meta_item.span, + file: &file, + error, + }); } } } diff --git a/compiler/rustc_passes/src/diagnostic_items.rs b/compiler/rustc_passes/src/diagnostic_items.rs index e6b69d898..a72056e00 100644 --- a/compiler/rustc_passes/src/diagnostic_items.rs +++ b/compiler/rustc_passes/src/diagnostic_items.rs @@ -14,7 +14,9 @@ use rustc_hir::diagnostic_items::DiagnosticItems; use rustc_middle::ty::query::Providers; use rustc_middle::ty::TyCtxt; use rustc_span::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE}; -use rustc_span::symbol::{sym, Symbol}; +use rustc_span::symbol::{kw::Empty, sym, Symbol}; + +use crate::errors::{DuplicateDiagnosticItem, DuplicateDiagnosticItemInCrate}; fn observe_item<'tcx>( tcx: TyCtxt<'tcx>, @@ -33,25 +35,22 @@ fn collect_item(tcx: TyCtxt<'_>, items: &mut DiagnosticItems, name: Symbol, item items.id_to_name.insert(item_def_id, name); if let Some(original_def_id) = items.name_to_id.insert(name, item_def_id) { if original_def_id != item_def_id { - let mut err = match tcx.hir().span_if_local(item_def_id) { - Some(span) => tcx - .sess - .struct_span_err(span, &format!("duplicate diagnostic item found: `{name}`.")), - None => tcx.sess.struct_err(&format!( - "duplicate diagnostic item in crate `{}`: `{}`.", - tcx.crate_name(item_def_id.krate), - name - )), - }; - if let Some(span) = tcx.hir().span_if_local(original_def_id) { - err.span_note(span, "the diagnostic item is first defined here"); + let orig_span = tcx.hir().span_if_local(original_def_id); + let orig_crate_name = if orig_span.is_some() { + None } else { - err.note(&format!( - "the diagnostic item is first defined in crate `{}`.", - tcx.crate_name(original_def_id.krate) - )); - } - err.emit(); + Some(tcx.crate_name(original_def_id.krate)) + }; + match tcx.hir().span_if_local(item_def_id) { + Some(span) => tcx.sess.emit_err(DuplicateDiagnosticItem { span, name }), + None => tcx.sess.emit_err(DuplicateDiagnosticItemInCrate { + span: orig_span, + orig_crate_name: orig_crate_name.unwrap_or(Empty), + have_orig_crate_name: orig_crate_name.map(|_| ()), + crate_name: tcx.crate_name(item_def_id.krate), + name, + }), + }; } } } @@ -74,19 +73,19 @@ fn diagnostic_items<'tcx>(tcx: TyCtxt<'tcx>, cnum: CrateNum) -> DiagnosticItems let crate_items = tcx.hir_crate_items(()); for id in crate_items.items() { - observe_item(tcx, &mut diagnostic_items, id.def_id); + observe_item(tcx, &mut diagnostic_items, id.owner_id.def_id); } for id in crate_items.trait_items() { - observe_item(tcx, &mut diagnostic_items, id.def_id); + observe_item(tcx, &mut diagnostic_items, id.owner_id.def_id); } for id in crate_items.impl_items() { - observe_item(tcx, &mut diagnostic_items, id.def_id); + observe_item(tcx, &mut diagnostic_items, id.owner_id.def_id); } for id in crate_items.foreign_items() { - observe_item(tcx, &mut diagnostic_items, id.def_id); + observe_item(tcx, &mut diagnostic_items, id.owner_id.def_id); } diagnostic_items diff --git a/compiler/rustc_passes/src/entry.rs b/compiler/rustc_passes/src/entry.rs index cd10170d3..5885f45ae 100644 --- a/compiler/rustc_passes/src/entry.rs +++ b/compiler/rustc_passes/src/entry.rs @@ -1,5 +1,5 @@ use rustc_ast::entry::EntryPointType; -use rustc_errors::struct_span_err; +use rustc_errors::error_code; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID, LOCAL_CRATE}; use rustc_hir::{ItemId, Node, CRATE_HIR_ID}; @@ -8,7 +8,12 @@ use rustc_middle::ty::{DefIdTree, TyCtxt}; use rustc_session::config::{sigpipe, CrateType, EntryFnType}; use rustc_session::parse::feature_err; use rustc_span::symbol::sym; -use rustc_span::{Span, Symbol, DUMMY_SP}; +use rustc_span::{Span, Symbol}; + +use crate::errors::{ + AttrOnlyInFunctions, AttrOnlyOnMain, AttrOnlyOnRootMain, ExternMain, MultipleRustcMain, + MultipleStartFunctions, NoMainErr, UnixSigpipeValues, +}; struct EntryContext<'tcx> { tcx: TyCtxt<'tcx>, @@ -57,7 +62,7 @@ fn entry_point_type(ctxt: &EntryContext<'_>, id: ItemId, at_root: bool) -> Entry } else if ctxt.tcx.sess.contains_name(attrs, sym::rustc_main) { EntryPointType::RustcMainAttr } else { - if let Some(name) = ctxt.tcx.opt_item_name(id.def_id.to_def_id()) + 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`. @@ -71,64 +76,57 @@ fn entry_point_type(ctxt: &EntryContext<'_>, id: ItemId, at_root: bool) -> Entry } } -fn err_if_attr_found(ctxt: &EntryContext<'_>, id: ItemId, sym: Symbol, details: &str) { +fn attr_span_by_symbol(ctxt: &EntryContext<'_>, id: ItemId, sym: Symbol) -> Option<Span> { let attrs = ctxt.tcx.hir().attrs(id.hir_id()); - if let Some(attr) = ctxt.tcx.sess.find_by_name(attrs, sym) { - ctxt.tcx - .sess - .struct_span_err(attr.span, &format!("`{}` attribute {}", sym, details)) - .emit(); - } + ctxt.tcx.sess.find_by_name(attrs, sym).map(|attr| attr.span) } fn find_item(id: ItemId, ctxt: &mut EntryContext<'_>) { - let at_root = ctxt.tcx.opt_local_parent(id.def_id) == Some(CRATE_DEF_ID); + 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) { EntryPointType::None => { - err_if_attr_found(ctxt, id, sym::unix_sigpipe, "can only be used on `fn main()`"); + if let Some(span) = attr_span_by_symbol(ctxt, id, sym::unix_sigpipe) { + ctxt.tcx.sess.emit_err(AttrOnlyOnMain { span, attr: sym::unix_sigpipe }); + } } - _ if !matches!(ctxt.tcx.def_kind(id.def_id), DefKind::Fn) => { - err_if_attr_found(ctxt, id, sym::start, "can only be used on functions"); - err_if_attr_found(ctxt, id, sym::rustc_main, "can only be used on functions"); + _ 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.sess.emit_err(AttrOnlyInFunctions { span, attr }); + } + } } EntryPointType::MainNamed => (), EntryPointType::OtherMain => { - err_if_attr_found(ctxt, id, sym::unix_sigpipe, "can only be used on root `fn main()`"); - ctxt.non_main_fns.push(ctxt.tcx.def_span(id.def_id)); + if let Some(span) = attr_span_by_symbol(ctxt, id, sym::unix_sigpipe) { + ctxt.tcx.sess.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.def_id, ctxt.tcx.def_span(id.def_id.to_def_id()))); + ctxt.attr_main_fn = Some((id.owner_id.def_id, ctxt.tcx.def_span(id.owner_id))); } else { - struct_span_err!( - ctxt.tcx.sess, - ctxt.tcx.def_span(id.def_id.to_def_id()), - E0137, - "multiple functions with a `#[rustc_main]` attribute" - ) - .span_label( - ctxt.tcx.def_span(id.def_id.to_def_id()), - "additional `#[rustc_main]` function", - ) - .span_label(ctxt.attr_main_fn.unwrap().1, "first `#[rustc_main]` function") - .emit(); + ctxt.tcx.sess.emit_err(MultipleRustcMain { + span: ctxt.tcx.def_span(id.owner_id.to_def_id()), + first: ctxt.attr_main_fn.unwrap().1, + additional: ctxt.tcx.def_span(id.owner_id.to_def_id()), + }); } } EntryPointType::Start => { - err_if_attr_found(ctxt, id, sym::unix_sigpipe, "can only be used on `fn main()`"); + if let Some(span) = attr_span_by_symbol(ctxt, id, sym::unix_sigpipe) { + ctxt.tcx.sess.emit_err(AttrOnlyOnMain { span, attr: sym::unix_sigpipe }); + } if ctxt.start_fn.is_none() { - ctxt.start_fn = Some((id.def_id, ctxt.tcx.def_span(id.def_id.to_def_id()))); + ctxt.start_fn = Some((id.owner_id.def_id, ctxt.tcx.def_span(id.owner_id))); } else { - struct_span_err!( - ctxt.tcx.sess, - ctxt.tcx.def_span(id.def_id.to_def_id()), - E0138, - "multiple `start` functions" - ) - .span_label(ctxt.start_fn.unwrap().1, "previous `#[start]` function here") - .span_label(ctxt.tcx.def_span(id.def_id.to_def_id()), "multiple `start` functions") - .emit(); + ctxt.tcx.sess.emit_err(MultipleStartFunctions { + span: ctxt.tcx.def_span(id.owner_id), + labeled: ctxt.tcx.def_span(id.owner_id.to_def_id()), + previous: ctxt.start_fn.unwrap().1, + }); } } } @@ -144,12 +142,7 @@ fn configure_main(tcx: TyCtxt<'_>, visitor: &EntryContext<'_>) -> Option<(DefId, 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(_))) { - tcx.sess - .struct_span_err( - tcx.def_span(def_id), - "the `main` function cannot be declared in an `extern` block", - ) - .emit(); + tcx.sess.emit_err(ExternMain { span: tcx.def_span(def_id) }); return None; } @@ -182,12 +175,7 @@ fn sigpipe(tcx: TyCtxt<'_>, def_id: DefId) -> u8 { sigpipe::DEFAULT } _ => { - tcx.sess - .struct_span_err( - attr.span, - "valid values for `#[unix_sigpipe = \"...\"]` are `inherit`, `sig_ign`, or `sig_dfl`", - ) - .emit(); + tcx.sess.emit_err(UnixSigpipeValues { span: attr.span }); sigpipe::DEFAULT } } @@ -206,52 +194,29 @@ fn no_main_err(tcx: TyCtxt<'_>, visitor: &EntryContext<'_>) { } // There is no main function. - let mut err = struct_span_err!( - tcx.sess, - DUMMY_SP, - E0601, - "`main` function not found in crate `{}`", - tcx.crate_name(LOCAL_CRATE) - ); - let filename = &tcx.sess.local_crate_source_file; - let note = if !visitor.non_main_fns.is_empty() { - for &span in &visitor.non_main_fns { - err.span_note(span, "here is a function named `main`"); - } - err.note("you have one or more functions named `main` not defined at the crate level"); - err.help("consider moving the `main` function definitions"); - // There were some functions named `main` though. Try to give the user a hint. - format!( - "the main function must be defined at the crate level{}", - filename.as_ref().map(|f| format!(" (in `{}`)", f.display())).unwrap_or_default() - ) - } else if let Some(filename) = filename { - format!("consider adding a `main` function to `{}`", filename.display()) - } else { - String::from("consider adding a `main` function at the crate level") - }; + let mut has_filename = true; + let filename = tcx.sess.local_crate_source_file.clone().unwrap_or_else(|| { + has_filename = false; + Default::default() + }); + let main_def_opt = tcx.resolutions(()).main_def; + let diagnostic_id = error_code!(E0601); + let add_teach_note = tcx.sess.teach(&diagnostic_id); // The file may be empty, which leads to the diagnostic machinery not emitting this // note. This is a relatively simple way to detect that case and emit a span-less // note instead. - if tcx.sess.source_map().lookup_line(sp.hi()).is_ok() { - err.set_span(sp.shrink_to_hi()); - err.span_label(sp.shrink_to_hi(), ¬e); - } else { - err.note(¬e); - } - - if let Some(main_def) = tcx.resolutions(()).main_def && main_def.opt_fn_def_id().is_none(){ - // There is something at `crate::main`, but it is not a function definition. - err.span_label(main_def.span, "non-function item at `crate::main` is found"); - } - - if tcx.sess.teach(&err.get_code().unwrap()) { - err.note( - "If you don't know the basics of Rust, you can go look to the Rust Book \ - to get started: https://doc.rust-lang.org/book/", - ); - } - err.emit(); + let file_empty = !tcx.sess.source_map().lookup_line(sp.hi()).is_ok(); + + tcx.sess.emit_err(NoMainErr { + sp, + crate_name: tcx.crate_name(LOCAL_CRATE), + has_filename, + filename, + file_empty, + non_main_fns: visitor.non_main_fns.clone(), + main_def_opt, + add_teach_note, + }); } pub fn provide(providers: &mut Providers) { diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 96cc8ae98..adaaf5392 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -1,39 +1,49 @@ -use rustc_errors::{Applicability, MultiSpan}; -use rustc_macros::{LintDiagnostic, SessionDiagnostic, SessionSubdiagnostic}; -use rustc_span::{Span, Symbol}; +use std::{ + io::Error, + path::{Path, PathBuf}, +}; + +use rustc_ast::Label; +use rustc_errors::{error_code, Applicability, ErrorGuaranteed, IntoDiagnostic, MultiSpan}; +use rustc_hir::{self as hir, ExprKind, Target}; +use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; +use rustc_middle::ty::{MainDefinition, Ty}; +use rustc_span::{Span, Symbol, DUMMY_SP}; + +use crate::lang_items::Duplicate; #[derive(LintDiagnostic)] -#[diag(passes::outer_crate_level_attr)] +#[diag(passes_outer_crate_level_attr)] pub struct OuterCrateLevelAttr; #[derive(LintDiagnostic)] -#[diag(passes::inner_crate_level_attr)] +#[diag(passes_inner_crate_level_attr)] pub struct InnerCrateLevelAttr; #[derive(LintDiagnostic)] -#[diag(passes::ignored_attr_with_macro)] +#[diag(passes_ignored_attr_with_macro)] pub struct IgnoredAttrWithMacro<'a> { pub sym: &'a str, } #[derive(LintDiagnostic)] -#[diag(passes::ignored_attr)] +#[diag(passes_ignored_attr)] pub struct IgnoredAttr<'a> { pub sym: &'a str, } #[derive(LintDiagnostic)] -#[diag(passes::inline_ignored_function_prototype)] +#[diag(passes_inline_ignored_function_prototype)] pub struct IgnoredInlineAttrFnProto; #[derive(LintDiagnostic)] -#[diag(passes::inline_ignored_constants)] +#[diag(passes_inline_ignored_constants)] #[warning] #[note] pub struct IgnoredInlineAttrConstants; -#[derive(SessionDiagnostic)] -#[diag(passes::inline_not_fn_or_closure, code = "E0518")] +#[derive(Diagnostic)] +#[diag(passes_inline_not_fn_or_closure, code = "E0518")] pub struct InlineNotFnOrClosure { #[primary_span] pub attr_span: Span, @@ -42,19 +52,19 @@ pub struct InlineNotFnOrClosure { } #[derive(LintDiagnostic)] -#[diag(passes::no_coverage_ignored_function_prototype)] +#[diag(passes_no_coverage_ignored_function_prototype)] pub struct IgnoredNoCoverageFnProto; #[derive(LintDiagnostic)] -#[diag(passes::no_coverage_propagate)] +#[diag(passes_no_coverage_propagate)] pub struct IgnoredNoCoveragePropagate; #[derive(LintDiagnostic)] -#[diag(passes::no_coverage_fn_defn)] +#[diag(passes_no_coverage_fn_defn)] pub struct IgnoredNoCoverageFnDefn; -#[derive(SessionDiagnostic)] -#[diag(passes::no_coverage_not_coverable, code = "E0788")] +#[derive(Diagnostic)] +#[diag(passes_no_coverage_not_coverable, code = "E0788")] pub struct IgnoredNoCoverageNotCoverable { #[primary_span] pub attr_span: Span, @@ -62,8 +72,8 @@ pub struct IgnoredNoCoverageNotCoverable { pub defn_span: Span, } -#[derive(SessionDiagnostic)] -#[diag(passes::should_be_applied_to_fn)] +#[derive(Diagnostic)] +#[diag(passes_should_be_applied_to_fn)] pub struct AttrShouldBeAppliedToFn { #[primary_span] pub attr_span: Span, @@ -71,15 +81,15 @@ pub struct AttrShouldBeAppliedToFn { pub defn_span: Span, } -#[derive(SessionDiagnostic)] -#[diag(passes::naked_tracked_caller, code = "E0736")] +#[derive(Diagnostic)] +#[diag(passes_naked_tracked_caller, code = "E0736")] pub struct NakedTrackedCaller { #[primary_span] pub attr_span: Span, } -#[derive(SessionDiagnostic)] -#[diag(passes::should_be_applied_to_fn, code = "E0739")] +#[derive(Diagnostic)] +#[diag(passes_should_be_applied_to_fn, code = "E0739")] pub struct TrackedCallerWrongLocation { #[primary_span] pub attr_span: Span, @@ -87,8 +97,8 @@ pub struct TrackedCallerWrongLocation { pub defn_span: Span, } -#[derive(SessionDiagnostic)] -#[diag(passes::should_be_applied_to_struct_enum, code = "E0701")] +#[derive(Diagnostic)] +#[diag(passes_should_be_applied_to_struct_enum, code = "E0701")] pub struct NonExhaustiveWrongLocation { #[primary_span] pub attr_span: Span, @@ -96,8 +106,8 @@ pub struct NonExhaustiveWrongLocation { pub defn_span: Span, } -#[derive(SessionDiagnostic)] -#[diag(passes::should_be_applied_to_trait)] +#[derive(Diagnostic)] +#[diag(passes_should_be_applied_to_trait)] pub struct AttrShouldBeAppliedToTrait { #[primary_span] pub attr_span: Span, @@ -106,11 +116,11 @@ pub struct AttrShouldBeAppliedToTrait { } #[derive(LintDiagnostic)] -#[diag(passes::target_feature_on_statement)] +#[diag(passes_target_feature_on_statement)] pub struct TargetFeatureOnStatement; -#[derive(SessionDiagnostic)] -#[diag(passes::should_be_applied_to_static)] +#[derive(Diagnostic)] +#[diag(passes_should_be_applied_to_static)] pub struct AttrShouldBeAppliedToStatic { #[primary_span] pub attr_span: Span, @@ -118,24 +128,24 @@ pub struct AttrShouldBeAppliedToStatic { pub defn_span: Span, } -#[derive(SessionDiagnostic)] -#[diag(passes::doc_expect_str)] +#[derive(Diagnostic)] +#[diag(passes_doc_expect_str)] pub struct DocExpectStr<'a> { #[primary_span] pub attr_span: Span, pub attr_name: &'a str, } -#[derive(SessionDiagnostic)] -#[diag(passes::doc_alias_empty)] +#[derive(Diagnostic)] +#[diag(passes_doc_alias_empty)] pub struct DocAliasEmpty<'a> { #[primary_span] pub span: Span, pub attr_str: &'a str, } -#[derive(SessionDiagnostic)] -#[diag(passes::doc_alias_bad_char)] +#[derive(Diagnostic)] +#[diag(passes_doc_alias_bad_char)] pub struct DocAliasBadChar<'a> { #[primary_span] pub span: Span, @@ -143,16 +153,16 @@ pub struct DocAliasBadChar<'a> { pub char_: char, } -#[derive(SessionDiagnostic)] -#[diag(passes::doc_alias_start_end)] +#[derive(Diagnostic)] +#[diag(passes_doc_alias_start_end)] pub struct DocAliasStartEnd<'a> { #[primary_span] pub span: Span, pub attr_str: &'a str, } -#[derive(SessionDiagnostic)] -#[diag(passes::doc_alias_bad_location)] +#[derive(Diagnostic)] +#[diag(passes_doc_alias_bad_location)] pub struct DocAliasBadLocation<'a> { #[primary_span] pub span: Span, @@ -160,8 +170,8 @@ pub struct DocAliasBadLocation<'a> { pub location: &'a str, } -#[derive(SessionDiagnostic)] -#[diag(passes::doc_alias_not_an_alias)] +#[derive(Diagnostic)] +#[diag(passes_doc_alias_not_an_alias)] pub struct DocAliasNotAnAlias<'a> { #[primary_span] pub span: Span, @@ -169,64 +179,64 @@ pub struct DocAliasNotAnAlias<'a> { } #[derive(LintDiagnostic)] -#[diag(passes::doc_alias_duplicated)] +#[diag(passes_doc_alias_duplicated)] pub struct DocAliasDuplicated { #[label] pub first_defn: Span, } -#[derive(SessionDiagnostic)] -#[diag(passes::doc_alias_not_string_literal)] +#[derive(Diagnostic)] +#[diag(passes_doc_alias_not_string_literal)] pub struct DocAliasNotStringLiteral { #[primary_span] pub span: Span, } -#[derive(SessionDiagnostic)] -#[diag(passes::doc_alias_malformed)] +#[derive(Diagnostic)] +#[diag(passes_doc_alias_malformed)] pub struct DocAliasMalformed { #[primary_span] pub span: Span, } -#[derive(SessionDiagnostic)] -#[diag(passes::doc_keyword_empty_mod)] +#[derive(Diagnostic)] +#[diag(passes_doc_keyword_empty_mod)] pub struct DocKeywordEmptyMod { #[primary_span] pub span: Span, } -#[derive(SessionDiagnostic)] -#[diag(passes::doc_keyword_not_mod)] +#[derive(Diagnostic)] +#[diag(passes_doc_keyword_not_mod)] pub struct DocKeywordNotMod { #[primary_span] pub span: Span, } -#[derive(SessionDiagnostic)] -#[diag(passes::doc_keyword_invalid_ident)] +#[derive(Diagnostic)] +#[diag(passes_doc_keyword_invalid_ident)] pub struct DocKeywordInvalidIdent { #[primary_span] pub span: Span, pub doc_keyword: Symbol, } -#[derive(SessionDiagnostic)] -#[diag(passes::doc_fake_variadic_not_valid)] +#[derive(Diagnostic)] +#[diag(passes_doc_fake_variadic_not_valid)] pub struct DocFakeVariadicNotValid { #[primary_span] pub span: Span, } -#[derive(SessionDiagnostic)] -#[diag(passes::doc_keyword_only_impl)] +#[derive(Diagnostic)] +#[diag(passes_doc_keyword_only_impl)] pub struct DocKeywordOnlyImpl { #[primary_span] pub span: Span, } -#[derive(SessionDiagnostic)] -#[diag(passes::doc_inline_conflict)] +#[derive(Diagnostic)] +#[diag(passes_doc_inline_conflict)] #[help] pub struct DocKeywordConflict { #[primary_span] @@ -234,17 +244,17 @@ pub struct DocKeywordConflict { } #[derive(LintDiagnostic)] -#[diag(passes::doc_inline_only_use)] +#[diag(passes_doc_inline_only_use)] #[note] pub struct DocInlineOnlyUse { #[label] pub attr_span: Span, - #[label(passes::not_a_use_item_label)] + #[label(not_a_use_item_label)] pub item_span: Option<Span>, } -#[derive(SessionDiagnostic)] -#[diag(passes::doc_attr_not_crate_level)] +#[derive(Diagnostic)] +#[diag(passes_doc_attr_not_crate_level)] pub struct DocAttrNotCrateLevel<'a> { #[primary_span] pub span: Span, @@ -252,29 +262,33 @@ pub struct DocAttrNotCrateLevel<'a> { } #[derive(LintDiagnostic)] -#[diag(passes::doc_test_unknown)] +#[diag(passes_doc_test_unknown)] pub struct DocTestUnknown { pub path: String, } #[derive(LintDiagnostic)] -#[diag(passes::doc_test_takes_list)] +#[diag(passes_doc_test_takes_list)] pub struct DocTestTakesList; #[derive(LintDiagnostic)] -#[diag(passes::doc_primitive)] +#[diag(passes_doc_cfg_hide_takes_list)] +pub struct DocCfgHideTakesList; + +#[derive(LintDiagnostic)] +#[diag(passes_doc_primitive)] pub struct DocPrimitive; #[derive(LintDiagnostic)] -#[diag(passes::doc_test_unknown_any)] +#[diag(passes_doc_test_unknown_any)] pub struct DocTestUnknownAny { pub path: String, } #[derive(LintDiagnostic)] -#[diag(passes::doc_test_unknown_spotlight)] +#[diag(passes_doc_test_unknown_spotlight)] #[note] -#[note(passes::no_op_note)] +#[note(no_op_note)] pub struct DocTestUnknownSpotlight { pub path: String, #[suggestion_short(applicability = "machine-applicable", code = "notable_trait")] @@ -282,7 +296,7 @@ pub struct DocTestUnknownSpotlight { } #[derive(LintDiagnostic)] -#[diag(passes::doc_test_unknown_include)] +#[diag(passes_doc_test_unknown_include)] pub struct DocTestUnknownInclude { pub path: String, pub value: String, @@ -292,11 +306,11 @@ pub struct DocTestUnknownInclude { } #[derive(LintDiagnostic)] -#[diag(passes::doc_invalid)] +#[diag(passes_doc_invalid)] pub struct DocInvalid; -#[derive(SessionDiagnostic)] -#[diag(passes::pass_by_value)] +#[derive(Diagnostic)] +#[diag(passes_pass_by_value)] pub struct PassByValue { #[primary_span] pub attr_span: Span, @@ -304,8 +318,8 @@ pub struct PassByValue { pub span: Span, } -#[derive(SessionDiagnostic)] -#[diag(passes::allow_incoherent_impl)] +#[derive(Diagnostic)] +#[diag(passes_allow_incoherent_impl)] pub struct AllowIncoherentImpl { #[primary_span] pub attr_span: Span, @@ -313,8 +327,8 @@ pub struct AllowIncoherentImpl { pub span: Span, } -#[derive(SessionDiagnostic)] -#[diag(passes::has_incoherent_inherent_impl)] +#[derive(Diagnostic)] +#[diag(passes_has_incoherent_inherent_impl)] pub struct HasIncoherentInherentImpl { #[primary_span] pub attr_span: Span, @@ -323,21 +337,21 @@ pub struct HasIncoherentInherentImpl { } #[derive(LintDiagnostic)] -#[diag(passes::must_use_async)] +#[diag(passes_must_use_async)] pub struct MustUseAsync { #[label] pub span: Span, } #[derive(LintDiagnostic)] -#[diag(passes::must_use_no_effect)] +#[diag(passes_must_use_no_effect)] pub struct MustUseNoEffect { pub article: &'static str, pub target: rustc_hir::Target, } -#[derive(SessionDiagnostic)] -#[diag(passes::must_not_suspend)] +#[derive(Diagnostic)] +#[diag(passes_must_not_suspend)] pub struct MustNotSuspend { #[primary_span] pub attr_span: Span, @@ -346,7 +360,7 @@ pub struct MustNotSuspend { } #[derive(LintDiagnostic)] -#[diag(passes::cold)] +#[diag(passes_cold)] #[warning] pub struct Cold { #[label] @@ -354,7 +368,7 @@ pub struct Cold { } #[derive(LintDiagnostic)] -#[diag(passes::link)] +#[diag(passes_link)] #[warning] pub struct Link { #[label] @@ -362,7 +376,7 @@ pub struct Link { } #[derive(LintDiagnostic)] -#[diag(passes::link_name)] +#[diag(passes_link_name)] #[warning] pub struct LinkName<'a> { #[help] @@ -372,8 +386,8 @@ pub struct LinkName<'a> { pub value: &'a str, } -#[derive(SessionDiagnostic)] -#[diag(passes::no_link)] +#[derive(Diagnostic)] +#[diag(passes_no_link)] pub struct NoLink { #[primary_span] pub attr_span: Span, @@ -381,8 +395,8 @@ pub struct NoLink { pub span: Span, } -#[derive(SessionDiagnostic)] -#[diag(passes::export_name)] +#[derive(Diagnostic)] +#[diag(passes_export_name)] pub struct ExportName { #[primary_span] pub attr_span: Span, @@ -390,8 +404,8 @@ pub struct ExportName { pub span: Span, } -#[derive(SessionDiagnostic)] -#[diag(passes::rustc_layout_scalar_valid_range_not_struct)] +#[derive(Diagnostic)] +#[diag(passes_rustc_layout_scalar_valid_range_not_struct)] pub struct RustcLayoutScalarValidRangeNotStruct { #[primary_span] pub attr_span: Span, @@ -399,15 +413,15 @@ pub struct RustcLayoutScalarValidRangeNotStruct { pub span: Span, } -#[derive(SessionDiagnostic)] -#[diag(passes::rustc_layout_scalar_valid_range_arg)] +#[derive(Diagnostic)] +#[diag(passes_rustc_layout_scalar_valid_range_arg)] pub struct RustcLayoutScalarValidRangeArg { #[primary_span] pub attr_span: Span, } -#[derive(SessionDiagnostic)] -#[diag(passes::rustc_legacy_const_generics_only)] +#[derive(Diagnostic)] +#[diag(passes_rustc_legacy_const_generics_only)] pub struct RustcLegacyConstGenericsOnly { #[primary_span] pub attr_span: Span, @@ -415,8 +429,8 @@ pub struct RustcLegacyConstGenericsOnly { pub param_span: Span, } -#[derive(SessionDiagnostic)] -#[diag(passes::rustc_legacy_const_generics_index)] +#[derive(Diagnostic)] +#[diag(passes_rustc_legacy_const_generics_index)] pub struct RustcLegacyConstGenericsIndex { #[primary_span] pub attr_span: Span, @@ -424,8 +438,8 @@ pub struct RustcLegacyConstGenericsIndex { pub generics_span: Span, } -#[derive(SessionDiagnostic)] -#[diag(passes::rustc_legacy_const_generics_index_exceed)] +#[derive(Diagnostic)] +#[diag(passes_rustc_legacy_const_generics_index_exceed)] pub struct RustcLegacyConstGenericsIndexExceed { #[primary_span] #[label] @@ -433,22 +447,22 @@ pub struct RustcLegacyConstGenericsIndexExceed { pub arg_count: usize, } -#[derive(SessionDiagnostic)] -#[diag(passes::rustc_legacy_const_generics_index_negative)] +#[derive(Diagnostic)] +#[diag(passes_rustc_legacy_const_generics_index_negative)] pub struct RustcLegacyConstGenericsIndexNegative { #[primary_span] pub invalid_args: Vec<Span>, } -#[derive(SessionDiagnostic)] -#[diag(passes::rustc_dirty_clean)] +#[derive(Diagnostic)] +#[diag(passes_rustc_dirty_clean)] pub struct RustcDirtyClean { #[primary_span] pub span: Span, } #[derive(LintDiagnostic)] -#[diag(passes::link_section)] +#[diag(passes_link_section)] #[warning] pub struct LinkSection { #[label] @@ -456,52 +470,52 @@ pub struct LinkSection { } #[derive(LintDiagnostic)] -#[diag(passes::no_mangle_foreign)] +#[diag(passes_no_mangle_foreign)] #[warning] #[note] pub struct NoMangleForeign { #[label] pub span: Span, - #[suggestion(applicability = "machine-applicable")] + #[suggestion(code = "", applicability = "machine-applicable")] pub attr_span: Span, pub foreign_item_kind: &'static str, } #[derive(LintDiagnostic)] -#[diag(passes::no_mangle)] +#[diag(passes_no_mangle)] #[warning] pub struct NoMangle { #[label] pub span: Span, } -#[derive(SessionDiagnostic)] -#[diag(passes::repr_ident, code = "E0565")] +#[derive(Diagnostic)] +#[diag(passes_repr_ident, code = "E0565")] pub struct ReprIdent { #[primary_span] pub span: Span, } #[derive(LintDiagnostic)] -#[diag(passes::repr_conflicting, code = "E0566")] +#[diag(passes_repr_conflicting, code = "E0566")] pub struct ReprConflicting; -#[derive(SessionDiagnostic)] -#[diag(passes::used_static)] +#[derive(Diagnostic)] +#[diag(passes_used_static)] pub struct UsedStatic { #[primary_span] pub span: Span, } -#[derive(SessionDiagnostic)] -#[diag(passes::used_compiler_linker)] +#[derive(Diagnostic)] +#[diag(passes_used_compiler_linker)] pub struct UsedCompilerLinker { #[primary_span] pub spans: Vec<Span>, } -#[derive(SessionDiagnostic)] -#[diag(passes::allow_internal_unstable)] +#[derive(Diagnostic)] +#[diag(passes_allow_internal_unstable)] pub struct AllowInternalUnstable { #[primary_span] pub attr_span: Span, @@ -509,25 +523,34 @@ pub struct AllowInternalUnstable { pub span: Span, } -#[derive(SessionDiagnostic)] -#[diag(passes::debug_visualizer_placement)] +#[derive(Diagnostic)] +#[diag(passes_debug_visualizer_placement)] pub struct DebugVisualizerPlacement { #[primary_span] pub span: Span, } -#[derive(SessionDiagnostic)] -#[diag(passes::debug_visualizer_invalid)] -#[note(passes::note_1)] -#[note(passes::note_2)] -#[note(passes::note_3)] +#[derive(Diagnostic)] +#[diag(passes_debug_visualizer_invalid)] +#[note(note_1)] +#[note(note_2)] +#[note(note_3)] pub struct DebugVisualizerInvalid { #[primary_span] pub span: Span, } -#[derive(SessionDiagnostic)] -#[diag(passes::rustc_allow_const_fn_unstable)] +#[derive(Diagnostic)] +#[diag(passes_debug_visualizer_unreadable)] +pub struct DebugVisualizerUnreadable<'a> { + #[primary_span] + pub span: Span, + pub file: &'a Path, + pub error: Error, +} + +#[derive(Diagnostic)] +#[diag(passes_rustc_allow_const_fn_unstable)] pub struct RustcAllowConstFnUnstable { #[primary_span] pub attr_span: Span, @@ -535,8 +558,8 @@ pub struct RustcAllowConstFnUnstable { pub span: Span, } -#[derive(SessionDiagnostic)] -#[diag(passes::rustc_std_internal_symbol)] +#[derive(Diagnostic)] +#[diag(passes_rustc_std_internal_symbol)] pub struct RustcStdInternalSymbol { #[primary_span] pub attr_span: Span, @@ -544,66 +567,66 @@ pub struct RustcStdInternalSymbol { pub span: Span, } -#[derive(SessionDiagnostic)] -#[diag(passes::const_trait)] +#[derive(Diagnostic)] +#[diag(passes_const_trait)] pub struct ConstTrait { #[primary_span] pub attr_span: Span, } -#[derive(SessionDiagnostic)] -#[diag(passes::link_ordinal)] +#[derive(Diagnostic)] +#[diag(passes_link_ordinal)] pub struct LinkOrdinal { #[primary_span] pub attr_span: Span, } -#[derive(SessionDiagnostic)] -#[diag(passes::stability_promotable)] +#[derive(Diagnostic)] +#[diag(passes_stability_promotable)] pub struct StabilityPromotable { #[primary_span] pub attr_span: Span, } #[derive(LintDiagnostic)] -#[diag(passes::deprecated)] +#[diag(passes_deprecated)] pub struct Deprecated; #[derive(LintDiagnostic)] -#[diag(passes::macro_use)] +#[diag(passes_macro_use)] pub struct MacroUse { pub name: Symbol, } #[derive(LintDiagnostic)] -#[diag(passes::macro_export)] +#[diag(passes_macro_export)] pub struct MacroExport; #[derive(LintDiagnostic)] -#[diag(passes::plugin_registrar)] +#[diag(passes_plugin_registrar)] pub struct PluginRegistrar; -#[derive(SessionSubdiagnostic)] +#[derive(Subdiagnostic)] pub enum UnusedNote { - #[note(passes::unused_empty_lints_note)] + #[note(passes_unused_empty_lints_note)] EmptyList { name: Symbol }, - #[note(passes::unused_no_lints_note)] + #[note(passes_unused_no_lints_note)] NoLints { name: Symbol }, - #[note(passes::unused_default_method_body_const_note)] + #[note(passes_unused_default_method_body_const_note)] DefaultMethodBodyConst, } #[derive(LintDiagnostic)] -#[diag(passes::unused)] +#[diag(passes_unused)] pub struct Unused { - #[suggestion(applicability = "machine-applicable")] + #[suggestion(code = "", applicability = "machine-applicable")] pub attr_span: Span, #[subdiagnostic] pub note: UnusedNote, } -#[derive(SessionDiagnostic)] -#[diag(passes::non_exported_macro_invalid_attrs, code = "E0518")] +#[derive(Diagnostic)] +#[diag(passes_non_exported_macro_invalid_attrs, code = "E0518")] pub struct NonExportedMacroInvalidAttrs { #[primary_span] #[label] @@ -611,7 +634,7 @@ pub struct NonExportedMacroInvalidAttrs { } #[derive(LintDiagnostic)] -#[diag(passes::unused_duplicate)] +#[diag(passes_unused_duplicate)] pub struct UnusedDuplicate { #[suggestion(code = "", applicability = "machine-applicable")] pub this: Span, @@ -621,8 +644,8 @@ pub struct UnusedDuplicate { pub warning: Option<()>, } -#[derive(SessionDiagnostic)] -#[diag(passes::unused_multiple)] +#[derive(Diagnostic)] +#[diag(passes_unused_multiple)] pub struct UnusedMultiple { #[primary_span] #[suggestion(code = "", applicability = "machine-applicable")] @@ -632,8 +655,8 @@ pub struct UnusedMultiple { pub name: Symbol, } -#[derive(SessionDiagnostic)] -#[diag(passes::rustc_lint_opt_ty)] +#[derive(Diagnostic)] +#[diag(passes_rustc_lint_opt_ty)] pub struct RustcLintOptTy { #[primary_span] pub attr_span: Span, @@ -641,8 +664,8 @@ pub struct RustcLintOptTy { pub span: Span, } -#[derive(SessionDiagnostic)] -#[diag(passes::rustc_lint_opt_deny_field_access)] +#[derive(Diagnostic)] +#[diag(passes_rustc_lint_opt_deny_field_access)] pub struct RustcLintOptDenyFieldAccess { #[primary_span] pub attr_span: Span, @@ -650,11 +673,779 @@ pub struct RustcLintOptDenyFieldAccess { pub span: Span, } -#[derive(SessionDiagnostic)] -#[diag(passes::collapse_debuginfo)] +#[derive(Diagnostic)] +#[diag(passes_collapse_debuginfo)] pub struct CollapseDebuginfo { #[primary_span] pub attr_span: Span, #[label] pub defn_span: Span, } + +#[derive(LintDiagnostic)] +#[diag(passes_deprecated_annotation_has_no_effect)] +pub struct DeprecatedAnnotationHasNoEffect { + #[suggestion(applicability = "machine-applicable", code = "")] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(passes_unknown_external_lang_item, code = "E0264")] +pub struct UnknownExternLangItem { + #[primary_span] + pub span: Span, + pub lang_item: Symbol, +} + +#[derive(Diagnostic)] +#[diag(passes_missing_panic_handler)] +pub struct MissingPanicHandler; + +#[derive(Diagnostic)] +#[diag(passes_alloc_func_required)] +pub struct AllocFuncRequired; + +#[derive(Diagnostic)] +#[diag(passes_missing_alloc_error_handler)] +pub struct MissingAllocErrorHandler; + +#[derive(Diagnostic)] +#[diag(passes_missing_lang_item)] +#[note] +#[help] +pub struct MissingLangItem { + pub name: Symbol, +} + +#[derive(Diagnostic)] +#[diag(passes_lang_item_on_incorrect_target, code = "E0718")] +pub struct LangItemOnIncorrectTarget { + #[primary_span] + #[label] + pub span: Span, + pub name: Symbol, + pub expected_target: Target, + pub actual_target: Target, +} + +#[derive(Diagnostic)] +#[diag(passes_unknown_lang_item, code = "E0522")] +pub struct UnknownLangItem { + #[primary_span] + #[label] + pub span: Span, + pub name: Symbol, +} + +pub struct InvalidAttrAtCrateLevel { + pub span: Span, + pub snippet: Option<String>, + pub name: Symbol, +} + +impl IntoDiagnostic<'_> for InvalidAttrAtCrateLevel { + fn into_diagnostic( + self, + handler: &'_ rustc_errors::Handler, + ) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> { + let mut diag = handler.struct_err(rustc_errors::fluent::passes_invalid_attr_at_crate_level); + diag.set_span(self.span); + 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("#!", "#"); + diag.span_suggestion_verbose( + self.span, + rustc_errors::fluent::suggestion, + replacement, + rustc_errors::Applicability::MachineApplicable, + ); + } + diag + } +} + +#[derive(Diagnostic)] +#[diag(passes_duplicate_diagnostic_item)] +pub struct DuplicateDiagnosticItem { + #[primary_span] + pub span: Span, + pub name: Symbol, +} + +#[derive(Diagnostic)] +#[diag(passes_duplicate_diagnostic_item_in_crate)] +pub struct DuplicateDiagnosticItemInCrate { + #[note(passes_diagnostic_item_first_defined)] + pub span: Option<Span>, + pub orig_crate_name: Symbol, + #[note] + pub have_orig_crate_name: Option<()>, + pub crate_name: Symbol, + pub name: Symbol, +} + +#[derive(Diagnostic)] +#[diag(passes_abi)] +pub struct Abi { + #[primary_span] + pub span: Span, + pub abi: String, +} + +#[derive(Diagnostic)] +#[diag(passes_align)] +pub struct Align { + #[primary_span] + pub span: Span, + pub align: String, +} + +#[derive(Diagnostic)] +#[diag(passes_size)] +pub struct Size { + #[primary_span] + pub span: Span, + pub size: String, +} + +#[derive(Diagnostic)] +#[diag(passes_homogeneous_aggregate)] +pub struct HomogeneousAggregate { + #[primary_span] + pub span: Span, + pub homogeneous_aggregate: String, +} + +#[derive(Diagnostic)] +#[diag(passes_layout_of)] +pub struct LayoutOf { + #[primary_span] + pub span: Span, + pub normalized_ty: String, + pub ty_layout: String, +} + +#[derive(Diagnostic)] +#[diag(passes_unrecognized_field)] +pub struct UnrecognizedField { + #[primary_span] + pub span: Span, + pub name: Symbol, +} + +#[derive(Diagnostic)] +#[diag(passes_feature_stable_twice, code = "E0711")] +pub struct FeatureStableTwice { + #[primary_span] + pub span: Span, + pub feature: Symbol, + pub since: Symbol, + pub prev_since: Symbol, +} + +#[derive(Diagnostic)] +#[diag(passes_feature_previously_declared, code = "E0711")] +pub struct FeaturePreviouslyDeclared<'a, 'b> { + #[primary_span] + pub span: Span, + pub feature: Symbol, + pub declared: &'a str, + pub prev_declared: &'b str, +} + +#[derive(Diagnostic)] +#[diag(passes_expr_not_allowed_in_context, code = "E0744")] +pub struct ExprNotAllowedInContext<'a> { + #[primary_span] + pub span: Span, + pub expr: String, + pub context: &'a str, +} + +pub struct BreakNonLoop<'a> { + pub span: Span, + pub head: Option<Span>, + pub kind: &'a str, + pub suggestion: String, + pub loop_label: Option<Label>, + pub break_label: Option<Label>, + pub break_expr_kind: &'a ExprKind<'a>, + pub break_expr_span: Span, +} + +impl<'a> IntoDiagnostic<'_> for BreakNonLoop<'a> { + fn into_diagnostic( + self, + handler: &rustc_errors::Handler, + ) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> { + let mut diag = handler.struct_span_err_with_code( + self.span, + rustc_errors::fluent::passes_break_non_loop, + error_code!(E0571), + ); + diag.set_arg("kind", self.kind); + diag.span_label(self.span, rustc_errors::fluent::label); + if let Some(head) = self.head { + diag.span_label(head, rustc_errors::fluent::label2); + } + diag.span_suggestion( + self.span, + rustc_errors::fluent::suggestion, + self.suggestion, + Applicability::MaybeIncorrect, + ); + if let (Some(label), None) = (self.loop_label, self.break_label) { + match self.break_expr_kind { + ExprKind::Path(hir::QPath::Resolved( + None, + hir::Path { segments: [segment], res: hir::def::Res::Err, .. }, + )) if label.ident.to_string() == format!("'{}", segment.ident) => { + // This error is redundant, we will have already emitted a + // suggestion to use the label when `segment` wasn't found + // (hence the `Res::Err` check). + diag.delay_as_bug(); + } + _ => { + diag.span_suggestion( + self.break_expr_span, + rustc_errors::fluent::break_expr_suggestion, + label.ident, + Applicability::MaybeIncorrect, + ); + } + } + } + diag + } +} + +#[derive(Diagnostic)] +#[diag(passes_continue_labeled_block, code = "E0696")] +pub struct ContinueLabeledBlock { + #[primary_span] + #[label] + pub span: Span, + #[label(block_label)] + pub block_span: Span, +} + +#[derive(Diagnostic)] +#[diag(passes_break_inside_closure, code = "E0267")] +pub struct BreakInsideClosure<'a> { + #[primary_span] + #[label] + pub span: Span, + #[label(closure_label)] + pub closure_span: Span, + pub name: &'a str, +} + +#[derive(Diagnostic)] +#[diag(passes_break_inside_async_block, code = "E0267")] +pub struct BreakInsideAsyncBlock<'a> { + #[primary_span] + #[label] + pub span: Span, + #[label(async_block_label)] + pub closure_span: Span, + pub name: &'a str, +} + +#[derive(Diagnostic)] +#[diag(passes_outside_loop, code = "E0268")] +pub struct OutsideLoop<'a> { + #[primary_span] + #[label] + pub span: Span, + pub name: &'a str, +} + +#[derive(Diagnostic)] +#[diag(passes_unlabeled_in_labeled_block, code = "E0695")] +pub struct UnlabeledInLabeledBlock<'a> { + #[primary_span] + #[label] + pub span: Span, + pub cf_type: &'a str, +} + +#[derive(Diagnostic)] +#[diag(passes_unlabeled_cf_in_while_condition, code = "E0590")] +pub struct UnlabeledCfInWhileCondition<'a> { + #[primary_span] + #[label] + pub span: Span, + pub cf_type: &'a str, +} + +#[derive(Diagnostic)] +#[diag(passes_cannot_inline_naked_function)] +pub struct CannotInlineNakedFunction { + #[primary_span] + pub span: Span, +} + +#[derive(LintDiagnostic)] +#[diag(passes_undefined_naked_function_abi)] +pub struct UndefinedNakedFunctionAbi; + +#[derive(Diagnostic)] +#[diag(passes_no_patterns)] +pub struct NoPatterns { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(passes_params_not_allowed)] +#[help] +pub struct ParamsNotAllowed { + #[primary_span] + pub span: Span, +} + +pub struct NakedFunctionsAsmBlock { + pub span: Span, + pub multiple_asms: Vec<Span>, + pub non_asms: Vec<Span>, +} + +impl IntoDiagnostic<'_> for NakedFunctionsAsmBlock { + fn into_diagnostic( + self, + handler: &rustc_errors::Handler, + ) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> { + let mut diag = handler.struct_span_err_with_code( + self.span, + rustc_errors::fluent::passes_naked_functions_asm_block, + error_code!(E0787), + ); + for span in self.multiple_asms.iter() { + diag.span_label(*span, rustc_errors::fluent::label_multiple_asm); + } + for span in self.non_asms.iter() { + diag.span_label(*span, rustc_errors::fluent::label_non_asm); + } + diag + } +} + +#[derive(Diagnostic)] +#[diag(passes_naked_functions_operands, code = "E0787")] +pub struct NakedFunctionsOperands { + #[primary_span] + pub unsupported_operands: Vec<Span>, +} + +#[derive(Diagnostic)] +#[diag(passes_naked_functions_asm_options, code = "E0787")] +pub struct NakedFunctionsAsmOptions { + #[primary_span] + pub span: Span, + pub unsupported_options: String, +} + +#[derive(Diagnostic)] +#[diag(passes_naked_functions_must_use_noreturn, code = "E0787")] +pub struct NakedFunctionsMustUseNoreturn { + #[primary_span] + pub span: Span, + #[suggestion(code = ", options(noreturn)", applicability = "machine-applicable")] + pub last_span: Span, +} + +#[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] + pub span: Span, + pub attr: Symbol, +} + +#[derive(Diagnostic)] +#[diag(passes_multiple_rustc_main, code = "E0137")] +pub struct MultipleRustcMain { + #[primary_span] + pub span: Span, + #[label(first)] + pub first: Span, + #[label(additional)] + pub additional: Span, +} + +#[derive(Diagnostic)] +#[diag(passes_multiple_start_functions, code = "E0138")] +pub struct MultipleStartFunctions { + #[primary_span] + pub span: Span, + #[label] + pub labeled: Span, + #[label(previous)] + pub previous: Span, +} + +#[derive(Diagnostic)] +#[diag(passes_extern_main)] +pub struct ExternMain { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(passes_unix_sigpipe_values)] +pub struct UnixSigpipeValues { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(passes_no_main_function, code = "E0601")] +pub struct NoMainFunction { + #[primary_span] + pub span: Span, + pub crate_name: String, +} + +pub struct NoMainErr { + pub sp: Span, + pub crate_name: Symbol, + pub has_filename: bool, + pub filename: PathBuf, + pub file_empty: bool, + pub non_main_fns: Vec<Span>, + pub main_def_opt: Option<MainDefinition>, + pub add_teach_note: bool, +} + +impl<'a> IntoDiagnostic<'a> for NoMainErr { + fn into_diagnostic( + self, + handler: &'a rustc_errors::Handler, + ) -> rustc_errors::DiagnosticBuilder<'a, ErrorGuaranteed> { + let mut diag = handler.struct_span_err_with_code( + DUMMY_SP, + rustc_errors::fluent::passes_no_main_function, + error_code!(E0601), + ); + diag.set_arg("crate_name", self.crate_name); + diag.set_arg("filename", self.filename); + diag.set_arg("has_filename", self.has_filename); + let note = if !self.non_main_fns.is_empty() { + for &span in &self.non_main_fns { + diag.span_note(span, rustc_errors::fluent::here_is_main); + } + diag.note(rustc_errors::fluent::one_or_more_possible_main); + diag.help(rustc_errors::fluent::consider_moving_main); + // There were some functions named `main` though. Try to give the user a hint. + rustc_errors::fluent::main_must_be_defined_at_crate + } else if self.has_filename { + rustc_errors::fluent::consider_adding_main_to_file + } else { + rustc_errors::fluent::consider_adding_main_at_crate + }; + if self.file_empty { + diag.note(note); + } else { + diag.set_span(self.sp.shrink_to_hi()); + 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(){ + // There is something at `crate::main`, but it is not a function definition. + diag.span_label(main_def.span, rustc_errors::fluent::non_function_main); + } + + if self.add_teach_note { + diag.note(rustc_errors::fluent::teach_note); + } + diag + } +} + +pub struct DuplicateLangItem { + pub local_span: Option<Span>, + pub lang_item_name: Symbol, + pub crate_name: Symbol, + pub dependency_of: Symbol, + pub is_local: bool, + pub path: String, + pub first_defined_span: Option<Span>, + pub orig_crate_name: Symbol, + pub orig_dependency_of: Symbol, + pub orig_is_local: bool, + pub orig_path: String, + pub(crate) duplicate: Duplicate, +} + +impl IntoDiagnostic<'_> for DuplicateLangItem { + fn into_diagnostic( + self, + handler: &rustc_errors::Handler, + ) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> { + let mut diag = handler.struct_err_with_code( + match self.duplicate { + Duplicate::Plain => rustc_errors::fluent::passes_duplicate_lang_item, + + Duplicate::Crate => rustc_errors::fluent::passes_duplicate_lang_item_crate, + Duplicate::CrateDepends => { + rustc_errors::fluent::passes_duplicate_lang_item_crate_depends + } + }, + error_code!(E0152), + ); + diag.set_arg("lang_item_name", self.lang_item_name); + diag.set_arg("crate_name", self.crate_name); + diag.set_arg("dependency_of", self.dependency_of); + diag.set_arg("path", self.path); + diag.set_arg("orig_crate_name", self.orig_crate_name); + diag.set_arg("orig_dependency_of", self.orig_dependency_of); + diag.set_arg("orig_path", self.orig_path); + if let Some(span) = self.local_span { + diag.set_span(span); + } + if let Some(span) = self.first_defined_span { + diag.span_note(span, rustc_errors::fluent::first_defined_span); + } else { + if self.orig_dependency_of.is_empty() { + diag.note(rustc_errors::fluent::first_defined_crate); + } else { + diag.note(rustc_errors::fluent::first_defined_crate_depends); + } + + if self.orig_is_local { + diag.note(rustc_errors::fluent::first_definition_local); + } else { + diag.note(rustc_errors::fluent::first_definition_path); + } + + if self.is_local { + diag.note(rustc_errors::fluent::second_definition_local); + } else { + diag.note(rustc_errors::fluent::second_definition_path); + } + } + diag + } +} + +#[derive(Diagnostic)] +#[diag(passes_incorrect_target, code = "E0718")] +pub struct IncorrectTarget<'a> { + #[primary_span] + pub span: Span, + #[label] + pub generics_span: Span, + pub name: &'a str, // cannot be symbol because it renders e.g. `r#fn` instead of `fn` + pub kind: &'static str, + pub num: usize, + pub actual_num: usize, + pub at_least: bool, +} + +#[derive(LintDiagnostic)] +#[diag(passes_useless_assignment)] +pub struct UselessAssignment<'a> { + pub is_field_assign: bool, + pub ty: Ty<'a>, +} + +#[derive(LintDiagnostic)] +#[diag(passes_only_has_effect_on)] +pub struct OnlyHasEffectOn { + pub attr_name: Symbol, + pub target_name: String, +} + +#[derive(Diagnostic)] +#[diag(passes_object_lifetime_err)] +pub struct ObjectLifetimeErr { + #[primary_span] + pub span: Span, + pub repr: String, +} + +#[derive(Diagnostic)] +#[diag(passes_unrecognized_repr_hint, code = "E0552")] +#[help] +pub struct UnrecognizedReprHint { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +pub enum AttrApplication { + #[diag(passes_attr_application_enum, code = "E0517")] + Enum { + #[primary_span] + hint_span: Span, + #[label] + span: Span, + }, + #[diag(passes_attr_application_struct, code = "E0517")] + Struct { + #[primary_span] + hint_span: Span, + #[label] + span: Span, + }, + #[diag(passes_attr_application_struct_union, code = "E0517")] + StructUnion { + #[primary_span] + hint_span: Span, + #[label] + span: Span, + }, + #[diag(passes_attr_application_struct_enum_union, code = "E0517")] + StructEnumUnion { + #[primary_span] + hint_span: Span, + #[label] + span: Span, + }, + #[diag(passes_attr_application_struct_enum_function_union, code = "E0517")] + StructEnumFunctionUnion { + #[primary_span] + hint_span: Span, + #[label] + span: Span, + }, +} + +#[derive(Diagnostic)] +#[diag(passes_transparent_incompatible, code = "E0692")] +pub struct TransparentIncompatible { + #[primary_span] + pub hint_spans: Vec<Span>, + pub target: String, +} + +#[derive(Diagnostic)] +#[diag(passes_deprecated_attribute, code = "E0549")] +pub struct DeprecatedAttribute { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(passes_useless_stability)] +pub struct UselessStability { + #[primary_span] + #[label] + pub span: Span, + #[label(item)] + pub item_sp: Span, +} + +#[derive(Diagnostic)] +#[diag(passes_invalid_stability)] +pub struct InvalidStability { + #[primary_span] + #[label] + pub span: Span, + #[label(item)] + pub item_sp: Span, +} + +#[derive(Diagnostic)] +#[diag(passes_cannot_stabilize_deprecated)] +pub struct CannotStabilizeDeprecated { + #[primary_span] + #[label] + pub span: Span, + #[label(item)] + pub item_sp: Span, +} + +#[derive(Diagnostic)] +#[diag(passes_invalid_deprecation_version)] +pub struct InvalidDeprecationVersion { + #[primary_span] + #[label] + pub span: Span, + #[label(item)] + pub item_sp: Span, +} + +#[derive(Diagnostic)] +#[diag(passes_missing_stability_attr)] +pub struct MissingStabilityAttr<'a> { + #[primary_span] + pub span: Span, + pub descr: &'a str, +} + +#[derive(Diagnostic)] +#[diag(passes_missing_const_stab_attr)] +pub struct MissingConstStabAttr<'a> { + #[primary_span] + pub span: Span, + pub descr: &'a str, +} + +#[derive(Diagnostic)] +#[diag(passes_trait_impl_const_stable)] +#[note] +pub struct TraitImplConstStable { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(passes_feature_only_on_nightly, code = "E0554")] +pub struct FeatureOnlyOnNightly { + #[primary_span] + pub span: Span, + pub release_channel: &'static str, +} + +#[derive(Diagnostic)] +#[diag(passes_unknown_feature, code = "E0635")] +pub struct UnknownFeature { + #[primary_span] + pub span: Span, + pub feature: Symbol, +} + +#[derive(Diagnostic)] +#[diag(passes_implied_feature_not_exist)] +pub struct ImpliedFeatureNotExist { + #[primary_span] + pub span: Span, + pub feature: Symbol, + pub implied_by: Symbol, +} + +#[derive(Diagnostic)] +#[diag(passes_duplicate_feature_err, code = "E0636")] +pub struct DuplicateFeatureErr { + #[primary_span] + pub span: Span, + pub feature: Symbol, +} +#[derive(Diagnostic)] +#[diag(passes_missing_const_err)] +pub struct MissingConstErr { + #[primary_span] + #[help] + pub fn_sig_span: Span, + #[label] + pub const_span: Span, +} diff --git a/compiler/rustc_passes/src/hir_id_validator.rs b/compiler/rustc_passes/src/hir_id_validator.rs index 3bb8c0bb4..88bb39deb 100644 --- a/compiler/rustc_passes/src/hir_id_validator.rs +++ b/compiler/rustc_passes/src/hir_id_validator.rs @@ -1,6 +1,5 @@ use rustc_data_structures::sync::Lock; use rustc_hir as hir; -use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID}; use rustc_hir::intravisit; use rustc_hir::{HirId, ItemLocalId}; use rustc_index::bit_set::GrowableBitSet; @@ -42,7 +41,7 @@ pub fn check_crate(tcx: TyCtxt<'_>) { struct HirIdValidator<'a, 'hir> { hir_map: Map<'hir>, - owner: Option<LocalDefId>, + owner: Option<hir::OwnerId>, hir_ids_seen: GrowableBitSet<ItemLocalId>, errors: &'a Lock<Vec<String>>, } @@ -63,12 +62,12 @@ impl<'a, 'hir> HirIdValidator<'a, 'hir> { self.errors.lock().push(f()); } - fn check<F: FnOnce(&mut HirIdValidator<'a, 'hir>)>(&mut self, owner: LocalDefId, walk: F) { + fn check<F: FnOnce(&mut HirIdValidator<'a, 'hir>)>(&mut self, owner: hir::OwnerId, walk: F) { assert!(self.owner.is_none()); self.owner = Some(owner); walk(self); - if owner == CRATE_DEF_ID { + if owner == hir::CRATE_OWNER_ID { return; } @@ -97,14 +96,14 @@ impl<'a, 'hir> HirIdValidator<'a, 'hir> { missing_items.push(format!( "[local_id: {}, owner: {}]", local_id, - self.hir_map.def_path(owner).to_string_no_crate_verbose() + self.hir_map.def_path(owner.def_id).to_string_no_crate_verbose() )); } self.error(|| { format!( "ItemLocalIds not assigned densely in {}. \ Max ItemLocalId = {}, missing IDs = {:#?}; seens IDs = {:#?}", - self.hir_map.def_path(owner).to_string_no_crate_verbose(), + self.hir_map.def_path(owner.def_id).to_string_no_crate_verbose(), max, missing_items, self.hir_ids_seen @@ -127,7 +126,7 @@ impl<'a, 'hir> intravisit::Visitor<'hir> for HirIdValidator<'a, 'hir> { fn visit_item(&mut self, i: &'hir hir::Item<'hir>) { let mut inner_visitor = self.new_visitor(self.hir_map); - inner_visitor.check(i.def_id, |this| intravisit::walk_item(this, i)); + inner_visitor.check(i.owner_id, |this| intravisit::walk_item(this, i)); } fn visit_id(&mut self, hir_id: HirId) { @@ -138,8 +137,8 @@ impl<'a, 'hir> intravisit::Visitor<'hir> for HirIdValidator<'a, 'hir> { format!( "HirIdValidator: The recorded owner of {} is {} instead of {}", self.hir_map.node_to_string(hir_id), - self.hir_map.def_path(hir_id.owner).to_string_no_crate_verbose(), - self.hir_map.def_path(owner).to_string_no_crate_verbose() + self.hir_map.def_path(hir_id.owner.def_id).to_string_no_crate_verbose(), + self.hir_map.def_path(owner.def_id).to_string_no_crate_verbose() ) }); } @@ -149,16 +148,16 @@ impl<'a, 'hir> intravisit::Visitor<'hir> for HirIdValidator<'a, 'hir> { fn visit_foreign_item(&mut self, i: &'hir hir::ForeignItem<'hir>) { let mut inner_visitor = self.new_visitor(self.hir_map); - inner_visitor.check(i.def_id, |this| intravisit::walk_foreign_item(this, i)); + inner_visitor.check(i.owner_id, |this| intravisit::walk_foreign_item(this, i)); } fn visit_trait_item(&mut self, i: &'hir hir::TraitItem<'hir>) { let mut inner_visitor = self.new_visitor(self.hir_map); - inner_visitor.check(i.def_id, |this| intravisit::walk_trait_item(this, i)); + inner_visitor.check(i.owner_id, |this| intravisit::walk_trait_item(this, i)); } fn visit_impl_item(&mut self, i: &'hir hir::ImplItem<'hir>) { let mut inner_visitor = self.new_visitor(self.hir_map); - inner_visitor.check(i.def_id, |this| intravisit::walk_impl_item(this, i)); + inner_visitor.check(i.owner_id, |this| intravisit::walk_impl_item(this, i)); } } diff --git a/compiler/rustc_passes/src/hir_stats.rs b/compiler/rustc_passes/src/hir_stats.rs index 0be2fc053..33220fd2b 100644 --- a/compiler/rustc_passes/src/hir_stats.rs +++ b/compiler/rustc_passes/src/hir_stats.rs @@ -391,7 +391,7 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> { fn visit_impl_item(&mut self, ii: &'v hir::ImplItem<'v>) { record_variants!( (self, ii, ii.kind, Id::Node(ii.hir_id()), hir, ImplItem, ImplItemKind), - [Const, Fn, TyAlias] + [Const, Fn, Type] ); hir_visit::walk_impl_item(self, ii) } @@ -620,7 +620,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, TyAlias, MacCall] + [Const, Fn, Type, MacCall] ); 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 79900a90a..df811be2a 100644 --- a/compiler/rustc_passes/src/lang_items.rs +++ b/compiler/rustc_passes/src/lang_items.rs @@ -8,9 +8,11 @@ //! * Functions called by the compiler itself. use crate::check_attr::target_from_impl_item; +use crate::errors::{ + DuplicateLangItem, IncorrectTarget, LangItemOnIncorrectTarget, UnknownLangItem, +}; use crate::weak_lang_items; -use rustc_errors::{pluralize, struct_span_err}; use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; @@ -18,10 +20,16 @@ use rustc_hir::lang_items::{extract, GenericRequirement, ITEM_REFS}; use rustc_hir::{HirId, LangItem, LanguageItems, Target}; use rustc_middle::ty::TyCtxt; use rustc_session::cstore::ExternCrate; -use rustc_span::Span; +use rustc_span::{symbol::kw::Empty, Span}; use rustc_middle::ty::query::Providers; +pub(crate) enum Duplicate { + Plain, + Crate, + CrateDepends, +} + struct LanguageItemCollector<'tcx> { items: LanguageItems, tcx: TyCtxt<'tcx>, @@ -34,42 +42,24 @@ impl<'tcx> LanguageItemCollector<'tcx> { fn check_for_lang(&mut self, actual_target: Target, hir_id: HirId) { let attrs = self.tcx.hir().attrs(hir_id); - if let Some((value, span)) = extract(&attrs) { - match ITEM_REFS.get(&value).cloned() { + if let Some((name, span)) = extract(&attrs) { + match ITEM_REFS.get(&name).cloned() { // Known lang item with attribute on correct target. Some((item_index, expected_target)) if actual_target == expected_target => { self.collect_item_extended(item_index, hir_id, span); } // Known lang item with attribute on incorrect target. Some((_, expected_target)) => { - struct_span_err!( - self.tcx.sess, + self.tcx.sess.emit_err(LangItemOnIncorrectTarget { span, - E0718, - "`{}` language item must be applied to a {}", - value, + name, expected_target, - ) - .span_label( - span, - format!( - "attribute should be applied to a {}, not a {}", - expected_target, actual_target, - ), - ) - .emit(); + actual_target, + }); } // Unknown lang item. _ => { - struct_span_err!( - self.tcx.sess, - span, - E0522, - "definition of an unknown language item: `{}`", - value - ) - .span_label(span, format!("definition of unknown language item `{}`", value)) - .emit(); + self.tcx.sess.emit_err(UnknownLangItem { span, name }); } } } @@ -79,74 +69,72 @@ impl<'tcx> LanguageItemCollector<'tcx> { // Check for duplicates. if let Some(original_def_id) = self.items.items[item_index] { if original_def_id != item_def_id { - let lang_item = LangItem::from_u32(item_index as u32).unwrap(); - let name = lang_item.name(); - let mut err = match self.tcx.hir().span_if_local(item_def_id) { - Some(span) => struct_span_err!( - self.tcx.sess, - span, - E0152, - "found duplicate lang item `{}`", - name - ), - None => match self.tcx.extern_crate(item_def_id) { - Some(ExternCrate { dependency_of, .. }) => { - self.tcx.sess.struct_err(&format!( - "duplicate lang item in crate `{}` (which `{}` depends on): `{}`.", - self.tcx.crate_name(item_def_id.krate), - self.tcx.crate_name(*dependency_of), - name - )) - } - _ => self.tcx.sess.struct_err(&format!( - "duplicate lang item in crate `{}`: `{}`.", - self.tcx.crate_name(item_def_id.krate), - name - )), - }, + let local_span = self.tcx.hir().span_if_local(item_def_id); + let lang_item_name = LangItem::from_u32(item_index as u32).unwrap().name(); + let crate_name = self.tcx.crate_name(item_def_id.krate); + let mut dependency_of = Empty; + let is_local = item_def_id.is_local(); + let path = if is_local { + String::new() + } else { + self.tcx + .crate_extern_paths(item_def_id.krate) + .iter() + .map(|p| p.display().to_string()) + .collect::<Vec<_>>() + .join(", ") + .into() }; - if let Some(span) = self.tcx.hir().span_if_local(original_def_id) { - err.span_note(span, "the lang item is first defined here"); + let first_defined_span = self.tcx.hir().span_if_local(original_def_id); + let mut orig_crate_name = Empty; + let mut orig_dependency_of = Empty; + let orig_is_local = original_def_id.is_local(); + let orig_path = if orig_is_local { + String::new() } else { - match self.tcx.extern_crate(original_def_id) { - Some(ExternCrate { dependency_of, .. }) => { - err.note(&format!( - "the lang item is first defined in crate `{}` (which `{}` depends on)", - self.tcx.crate_name(original_def_id.krate), - self.tcx.crate_name(*dependency_of) - )); - } - _ => { - err.note(&format!( - "the lang item is first defined in crate `{}`.", - self.tcx.crate_name(original_def_id.krate) - )); - } + self.tcx + .crate_extern_paths(original_def_id.krate) + .iter() + .map(|p| p.display().to_string()) + .collect::<Vec<_>>() + .join(", ") + .into() + }; + if first_defined_span.is_none() { + orig_crate_name = self.tcx.crate_name(original_def_id.krate); + if let Some(ExternCrate { dependency_of: inner_dependency_of, .. }) = + self.tcx.extern_crate(original_def_id) + { + orig_dependency_of = self.tcx.crate_name(*inner_dependency_of); } - let mut note_def = |which, def_id: DefId| { - let crate_name = self.tcx.crate_name(def_id.krate); - let note = if def_id.is_local() { - format!("{} definition in the local crate (`{}`)", which, crate_name) - } else { - let paths: Vec<_> = self - .tcx - .crate_extern_paths(def_id.krate) - .iter() - .map(|p| p.display().to_string()) - .collect(); - format!( - "{} definition in `{}` loaded from {}", - which, - crate_name, - paths.join(", ") - ) - }; - err.note(¬e); - }; - note_def("first", original_def_id); - note_def("second", item_def_id); } - err.emit(); + + let duplicate = if local_span.is_some() { + Duplicate::Plain + } else { + match self.tcx.extern_crate(item_def_id) { + Some(ExternCrate { dependency_of: inner_dependency_of, .. }) => { + dependency_of = self.tcx.crate_name(*inner_dependency_of); + Duplicate::CrateDepends + } + _ => Duplicate::Crate, + } + }; + + self.tcx.sess.emit_err(DuplicateLangItem { + local_span, + lang_item_name, + crate_name, + dependency_of, + is_local, + path, + first_defined_span, + orig_crate_name, + orig_dependency_of, + orig_is_local, + orig_path, + duplicate, + }); } } @@ -179,41 +167,30 @@ impl<'tcx> LanguageItemCollector<'tcx> { None => (0, *item_span), }; + let mut at_least = false; let required = match lang_item.required_generics() { - GenericRequirement::Exact(num) if num != actual_num => { - Some((format!("{}", num), pluralize!(num))) - } + GenericRequirement::Exact(num) if num != actual_num => Some(num), GenericRequirement::Minimum(num) if actual_num < num => { - Some((format!("at least {}", num), pluralize!(num))) - } + at_least = true; + Some(num)} + , // If the number matches, or there is no requirement, handle it normally _ => None, }; - if let Some((range_str, pluralized)) = required { + if let Some(num) = required { // We are issuing E0718 "incorrect target" here, because while the // item kind of the target is correct, the target is still wrong // because of the wrong number of generic arguments. - struct_span_err!( - self.tcx.sess, + self.tcx.sess.emit_err(IncorrectTarget { span, - E0718, - "`{}` language item must be applied to a {} with {} generic argument{}", - name, - kind.descr(), - range_str, - pluralized, - ) - .span_label( generics_span, - format!( - "this {} has {} generic argument{}", - kind.descr(), - actual_num, - pluralize!(actual_num), - ), - ) - .emit(); + name: name.as_str(), + kind: kind.descr(), + num, + actual_num, + at_least, + }); // return early to not collect the lang item return; @@ -240,9 +217,9 @@ fn get_lang_items(tcx: TyCtxt<'_>, (): ()) -> LanguageItems { let crate_items = tcx.hir_crate_items(()); for id in crate_items.items() { - collector.check_for_lang(Target::from_def_kind(tcx.def_kind(id.def_id)), id.hir_id()); + collector.check_for_lang(Target::from_def_kind(tcx.def_kind(id.owner_id)), id.hir_id()); - if matches!(tcx.def_kind(id.def_id), DefKind::Enum) { + if matches!(tcx.def_kind(id.owner_id), DefKind::Enum) { let item = tcx.hir().item(id); if let hir::ItemKind::Enum(def, ..) = &item.kind { for variant in def.variants { diff --git a/compiler/rustc_passes/src/layout_test.rs b/compiler/rustc_passes/src/layout_test.rs index fd03f6571..5322baee7 100644 --- a/compiler/rustc_passes/src/layout_test.rs +++ b/compiler/rustc_passes/src/layout_test.rs @@ -3,20 +3,23 @@ use rustc_hir::def::DefKind; use rustc_hir::def_id::LocalDefId; use rustc_middle::ty::layout::{HasParamEnv, HasTyCtxt, LayoutError, LayoutOfHelpers, TyAndLayout}; use rustc_middle::ty::{ParamEnv, Ty, TyCtxt}; +use rustc_span::source_map::Spanned; use rustc_span::symbol::sym; use rustc_span::Span; use rustc_target::abi::{HasDataLayout, TargetDataLayout}; +use crate::errors::{Abi, Align, HomogeneousAggregate, LayoutOf, Size, UnrecognizedField}; + pub fn test_layout(tcx: TyCtxt<'_>) { if tcx.features().rustc_attrs { // if the `rustc_attrs` feature is not enabled, don't bother testing layout for id in tcx.hir().items() { if matches!( - tcx.def_kind(id.def_id), + tcx.def_kind(id.owner_id), DefKind::TyAlias | DefKind::Enum | DefKind::Struct | DefKind::Union ) { - for attr in tcx.get_attrs(id.def_id.to_def_id(), sym::rustc_layout) { - dump_layout_of(tcx, id.def_id, attr); + for attr in tcx.get_attrs(id.owner_id.to_def_id(), sym::rustc_layout) { + dump_layout_of(tcx, id.owner_id.def_id, attr); } } } @@ -35,62 +38,64 @@ fn dump_layout_of<'tcx>(tcx: TyCtxt<'tcx>, item_def_id: LocalDefId, attr: &Attri for meta_item in meta_items { match meta_item.name_or_empty() { sym::abi => { - tcx.sess.span_err( - tcx.def_span(item_def_id.to_def_id()), - &format!("abi: {:?}", ty_layout.abi), - ); + tcx.sess.emit_err(Abi { + span: tcx.def_span(item_def_id.to_def_id()), + abi: format!("{:?}", ty_layout.abi), + }); } sym::align => { - tcx.sess.span_err( - tcx.def_span(item_def_id.to_def_id()), - &format!("align: {:?}", ty_layout.align), - ); + tcx.sess.emit_err(Align { + span: tcx.def_span(item_def_id.to_def_id()), + align: format!("{:?}", ty_layout.align), + }); } sym::size => { - tcx.sess.span_err( - tcx.def_span(item_def_id.to_def_id()), - &format!("size: {:?}", ty_layout.size), - ); + tcx.sess.emit_err(Size { + span: tcx.def_span(item_def_id.to_def_id()), + size: format!("{:?}", ty_layout.size), + }); } sym::homogeneous_aggregate => { - tcx.sess.span_err( - tcx.def_span(item_def_id.to_def_id()), - &format!( - "homogeneous_aggregate: {:?}", - ty_layout.homogeneous_aggregate(&UnwrapLayoutCx { tcx, param_env }), + tcx.sess.emit_err(HomogeneousAggregate { + span: tcx.def_span(item_def_id.to_def_id()), + homogeneous_aggregate: format!( + "{:?}", + ty_layout.homogeneous_aggregate(&UnwrapLayoutCx { tcx, param_env }) ), - ); + }); } sym::debug => { - let normalized_ty = tcx.normalize_erasing_regions( - param_env.with_reveal_all_normalized(tcx), - ty, - ); - tcx.sess.span_err( - tcx.def_span(item_def_id.to_def_id()), - &format!("layout_of({:?}) = {:#?}", normalized_ty, *ty_layout), + let normalized_ty = format!( + "{:?}", + tcx.normalize_erasing_regions( + param_env.with_reveal_all_normalized(tcx), + ty, + ) ); + let ty_layout = format!("{:#?}", *ty_layout); + tcx.sess.emit_err(LayoutOf { + span: tcx.def_span(item_def_id.to_def_id()), + normalized_ty, + ty_layout, + }); } name => { - tcx.sess.span_err( - meta_item.span(), - &format!("unrecognized field name `{}`", name), - ); + tcx.sess.emit_err(UnrecognizedField { span: meta_item.span(), name }); } } } } Err(layout_error) => { - tcx.sess.span_err( - tcx.def_span(item_def_id.to_def_id()), - &format!("layout error: {:?}", layout_error), - ); + tcx.sess.emit_fatal(Spanned { + node: layout_error, + span: tcx.def_span(item_def_id.to_def_id()), + }); } } } diff --git a/compiler/rustc_passes/src/lib.rs b/compiler/rustc_passes/src/lib.rs index 39ebb8db2..15f60f626 100644 --- a/compiler/rustc_passes/src/lib.rs +++ b/compiler/rustc_passes/src/lib.rs @@ -5,10 +5,11 @@ //! This API is completely unstable and subject to change. #![allow(rustc::potential_query_instability)] +#![deny(rustc::untranslatable_diagnostic)] +#![deny(rustc::diagnostic_outside_of_impl)] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(iter_intersperse)] #![feature(let_chains)] -#![cfg_attr(bootstrap, feature(let_else))] #![feature(map_try_insert)] #![feature(min_specialization)] #![feature(try_blocks)] diff --git a/compiler/rustc_passes/src/lib_features.rs b/compiler/rustc_passes/src/lib_features.rs index 04173c792..b5843c0ae 100644 --- a/compiler/rustc_passes/src/lib_features.rs +++ b/compiler/rustc_passes/src/lib_features.rs @@ -6,7 +6,6 @@ use rustc_ast::{Attribute, MetaItemKind}; use rustc_attr::{rust_version_symbol, VERSION_PLACEHOLDER}; -use rustc_errors::struct_span_err; use rustc_hir::intravisit::Visitor; use rustc_middle::hir::nested_filter; use rustc_middle::middle::lib_features::LibFeatures; @@ -15,6 +14,8 @@ use rustc_middle::ty::TyCtxt; use rustc_span::symbol::Symbol; use rustc_span::{sym, Span}; +use crate::errors::{FeaturePreviouslyDeclared, FeatureStableTwice}; + fn new_lib_features() -> LibFeatures { LibFeatures { stable: Default::default(), unstable: Default::default() } } @@ -92,14 +93,12 @@ impl<'tcx> LibFeatureCollector<'tcx> { (Some(since), _, false) => { if let Some((prev_since, _)) = self.lib_features.stable.get(&feature) { if *prev_since != since { - self.span_feature_error( + self.tcx.sess.emit_err(FeatureStableTwice { span, - &format!( - "feature `{}` is declared stable since {}, \ - but was previously declared stable since {}", - feature, since, prev_since, - ), - ); + feature, + since, + prev_since: *prev_since, + }); return; } } @@ -110,22 +109,17 @@ impl<'tcx> LibFeatureCollector<'tcx> { self.lib_features.unstable.insert(feature, span); } (Some(_), _, true) | (None, true, _) => { - self.span_feature_error( + let declared = if since.is_some() { "stable" } else { "unstable" }; + let prev_declared = if since.is_none() { "stable" } else { "unstable" }; + self.tcx.sess.emit_err(FeaturePreviouslyDeclared { span, - &format!( - "feature `{}` is declared {}, but was previously declared {}", - feature, - if since.is_some() { "stable" } else { "unstable" }, - if since.is_none() { "stable" } else { "unstable" }, - ), - ); + feature, + declared, + prev_declared, + }); } } } - - fn span_feature_error(&self, span: Span, msg: &str) { - struct_span_err!(self.tcx.sess, span, E0711, "{}", &msg).emit(); - } } impl<'tcx> Visitor<'tcx> for LibFeatureCollector<'tcx> { diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs index 6a4cd79cd..c6fe40f72 100644 --- a/compiler/rustc_passes/src/liveness.rs +++ b/compiler/rustc_passes/src/liveness.rs @@ -1319,14 +1319,14 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { // that we do not emit the same warning twice if the uninhabited type // is indeed `!`. + let msg = format!("unreachable {}", descr); self.ir.tcx.struct_span_lint_hir( lint::builtin::UNREACHABLE_CODE, expr_id, expr_span, - |lint| { - let msg = format!("unreachable {}", descr); - lint.build(&msg) - .span_label(expr_span, &msg) + &msg, + |diag| { + diag.span_label(expr_span, &msg) .span_label(orig_span, "any code following this expression is unreachable") .span_note( orig_span, @@ -1335,7 +1335,6 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { orig_ty ), ) - .emit(); }, ); } @@ -1491,14 +1490,8 @@ impl<'tcx> Liveness<'_, 'tcx> { lint::builtin::UNUSED_ASSIGNMENTS, var_hir_id, vec![span], - |lint| { - lint.build(&format!( - "value captured by `{}` is never read", - name - )) - .help("did you mean to capture by reference instead?") - .emit(); - }, + format!("value captured by `{}` is never read", name), + |lint| lint.help("did you mean to capture by reference instead?"), ); } } @@ -1508,11 +1501,8 @@ impl<'tcx> Liveness<'_, 'tcx> { lint::builtin::UNUSED_VARIABLES, var_hir_id, vec![span], - |lint| { - lint.build(&format!("unused variable: `{}`", name)) - .help("did you mean to capture by reference instead?") - .emit(); - }, + format!("unused variable: `{}`", name), + |lint| lint.help("did you mean to capture by reference instead?"), ); } } @@ -1601,20 +1591,17 @@ impl<'tcx> Liveness<'_, 'tcx> { .into_iter() .map(|(_, _, ident_span)| ident_span) .collect::<Vec<_>>(), - |lint| { - lint.build(&format!("variable `{}` is assigned to, but never used", name)) - .note(&format!("consider using `_{}` instead", name)) - .emit(); - }, + format!("variable `{}` is assigned to, but never used", name), + |lint| lint.note(&format!("consider using `_{}` instead", name)), ) } else if can_remove { self.ir.tcx.struct_span_lint_hir( lint::builtin::UNUSED_VARIABLES, first_hir_id, hir_ids_and_spans.iter().map(|(_, pat_span, _)| *pat_span).collect::<Vec<_>>(), + format!("unused variable: `{}`", name), |lint| { - let mut err = lint.build(&format!("unused variable: `{}`", name)); - err.multipart_suggestion( + lint.multipart_suggestion( "try removing the field", hir_ids_and_spans .iter() @@ -1629,8 +1616,7 @@ impl<'tcx> Liveness<'_, 'tcx> { }) .collect(), Applicability::MachineApplicable, - ); - err.emit(); + ) }, ); } else { @@ -1661,14 +1647,13 @@ impl<'tcx> Liveness<'_, 'tcx> { .iter() .map(|(_, pat_span, _)| *pat_span) .collect::<Vec<_>>(), + format!("unused variable: `{}`", name), |lint| { - let mut err = lint.build(&format!("unused variable: `{}`", name)); - err.multipart_suggestion( + lint.multipart_suggestion( "try ignoring the field", shorthands, Applicability::MachineApplicable, - ); - err.emit(); + ) }, ); } else { @@ -1684,17 +1669,16 @@ impl<'tcx> Liveness<'_, 'tcx> { .iter() .map(|(_, _, ident_span)| *ident_span) .collect::<Vec<_>>(), + format!("unused variable: `{}`", name), |lint| { - let mut err = lint.build(&format!("unused variable: `{}`", name)); - if self.has_added_lit_match_name_span(&name, opt_body, &mut err) { - err.span_label(pat.span, "unused variable"); + if self.has_added_lit_match_name_span(&name, opt_body, lint) { + lint.span_label(pat.span, "unused variable"); } - err.multipart_suggestion( + lint.multipart_suggestion( "if this is intentional, prefix it with an underscore", non_shorthands, Applicability::MachineApplicable, - ); - err.emit(); + ) }, ); } @@ -1758,11 +1742,8 @@ impl<'tcx> Liveness<'_, 'tcx> { lint::builtin::UNUSED_ASSIGNMENTS, hir_id, spans, - |lint| { - lint.build(&message(&name)) - .help("maybe it is overwritten before being read?") - .emit(); - }, + message(&name), + |lint| lint.help("maybe it is overwritten before being read?"), ) } } diff --git a/compiler/rustc_passes/src/loops.rs b/compiler/rustc_passes/src/loops.rs index cdda0e388..077194ec6 100644 --- a/compiler/rustc_passes/src/loops.rs +++ b/compiler/rustc_passes/src/loops.rs @@ -1,6 +1,5 @@ use Context::*; -use rustc_errors::{struct_span_err, Applicability}; use rustc_hir as hir; use rustc_hir::def_id::LocalDefId; use rustc_hir::intravisit::{self, Visitor}; @@ -13,6 +12,11 @@ use rustc_session::Session; use rustc_span::hygiene::DesugaringKind; use rustc_span::Span; +use crate::errors::{ + BreakInsideAsyncBlock, BreakInsideClosure, BreakNonLoop, ContinueLabeledBlock, OutsideLoop, + UnlabeledCfInWhileCondition, UnlabeledInLabeledBlock, +}; + #[derive(Clone, Copy, Debug, PartialEq)] enum Context { Normal, @@ -90,7 +94,10 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> { Ok(loop_id) => Some(loop_id), Err(hir::LoopIdError::OutsideLoopScope) => None, Err(hir::LoopIdError::UnlabeledCfInWhileCondition) => { - self.emit_unlabled_cf_in_while_condition(e.span, "break"); + self.sess.emit_err(UnlabeledCfInWhileCondition { + span: e.span, + cf_type: "break", + }); None } Err(hir::LoopIdError::UnresolvedLabel) => None, @@ -116,69 +123,22 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> { match loop_kind { None | Some(hir::LoopSource::Loop) => (), Some(kind) => { - let mut err = struct_span_err!( - self.sess, - e.span, - E0571, - "`break` with value from a `{}` loop", - kind.name() - ); - err.span_label( - e.span, - "can only break with a value inside `loop` or breakable block", + let suggestion = format!( + "break{}", + break_label + .label + .map_or_else(String::new, |l| format!(" {}", l.ident)) ); - if let Some(head) = head { - err.span_label( - head, - &format!( - "you can't `break` with a value in a `{}` loop", - kind.name() - ), - ); - } - err.span_suggestion( - e.span, - &format!( - "use `break` on its own without a value inside this `{}` loop", - kind.name(), - ), - format!( - "break{}", - break_label - .label - .map_or_else(String::new, |l| format!(" {}", l.ident)) - ), - Applicability::MaybeIncorrect, - ); - if let (Some(label), None) = (loop_label, break_label.label) { - match break_expr.kind { - hir::ExprKind::Path(hir::QPath::Resolved( - None, - hir::Path { - segments: [segment], - res: hir::def::Res::Err, - .. - }, - )) if label.ident.to_string() - == format!("'{}", segment.ident) => - { - // This error is redundant, we will have already emitted a - // suggestion to use the label when `segment` wasn't found - // (hence the `Res::Err` check). - err.delay_as_bug(); - } - _ => { - err.span_suggestion( - break_expr.span, - "alternatively, you might have meant to use the \ - available loop label", - label.ident, - Applicability::MaybeIncorrect, - ); - } - } - } - err.emit(); + self.sess.emit_err(BreakNonLoop { + span: e.span, + head, + kind: kind.name(), + suggestion, + loop_label, + break_label: break_label.label, + break_expr_kind: &break_expr.kind, + break_expr_span: break_expr.span, + }); } } } @@ -191,19 +151,17 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> { match destination.target_id { Ok(loop_id) => { if let Node::Block(block) = self.hir_map.find(loop_id).unwrap() { - struct_span_err!( - self.sess, - e.span, - E0696, - "`continue` pointing to a labeled block" - ) - .span_label(e.span, "labeled blocks cannot be `continue`'d") - .span_label(block.span, "labeled block the `continue` points to") - .emit(); + self.sess.emit_err(ContinueLabeledBlock { + span: e.span, + block_span: block.span, + }); } } Err(hir::LoopIdError::UnlabeledCfInWhileCondition) => { - self.emit_unlabled_cf_in_while_condition(e.span, "continue"); + self.sess.emit_err(UnlabeledCfInWhileCondition { + span: e.span, + cf_type: "continue", + }); } Err(_) => {} } @@ -226,21 +184,16 @@ impl<'a, 'hir> CheckLoopVisitor<'a, 'hir> { } fn require_break_cx(&self, name: &str, span: Span) { - let err_inside_of = |article, ty, closure_span| { - struct_span_err!(self.sess, span, E0267, "`{}` inside of {} {}", name, article, ty) - .span_label(span, format!("cannot `{}` inside of {} {}", name, article, ty)) - .span_label(closure_span, &format!("enclosing {}", ty)) - .emit(); - }; - match self.cx { LabeledBlock | Loop(_) => {} - Closure(closure_span) => err_inside_of("a", "closure", closure_span), - AsyncClosure(closure_span) => err_inside_of("an", "`async` block", closure_span), + Closure(closure_span) => { + self.sess.emit_err(BreakInsideClosure { span, closure_span, name }); + } + AsyncClosure(closure_span) => { + self.sess.emit_err(BreakInsideAsyncBlock { span, closure_span, name }); + } Normal | AnonConst => { - struct_span_err!(self.sess, span, E0268, "`{}` outside of a loop", name) - .span_label(span, format!("cannot `{}` outside of a loop", name)) - .emit(); + self.sess.emit_err(OutsideLoop { span, name }); } } } @@ -251,37 +204,13 @@ impl<'a, 'hir> CheckLoopVisitor<'a, 'hir> { label: &Destination, cf_type: &str, ) -> bool { - if !span.is_desugaring(DesugaringKind::QuestionMark) && self.cx == LabeledBlock { - if label.label.is_none() { - struct_span_err!( - self.sess, - span, - E0695, - "unlabeled `{}` inside of a labeled block", - cf_type - ) - .span_label( - span, - format!( - "`{}` statements that would diverge to or through \ - a labeled block need to bear a label", - cf_type - ), - ) - .emit(); - return true; - } + if !span.is_desugaring(DesugaringKind::QuestionMark) + && self.cx == LabeledBlock + && label.label.is_none() + { + self.sess.emit_err(UnlabeledInLabeledBlock { span, cf_type }); + return true; } false } - fn emit_unlabled_cf_in_while_condition(&mut self, span: Span, cf_type: &str) { - struct_span_err!( - self.sess, - span, - E0590, - "`break` or `continue` with no label in the condition of a `while` loop" - ) - .span_label(span, format!("unlabeled `{}` in the condition of a `while` loop", cf_type)) - .emit(); - } } diff --git a/compiler/rustc_passes/src/naked_functions.rs b/compiler/rustc_passes/src/naked_functions.rs index 607973446..acc54e7e1 100644 --- a/compiler/rustc_passes/src/naked_functions.rs +++ b/compiler/rustc_passes/src/naked_functions.rs @@ -1,7 +1,6 @@ //! Checks validity of naked functions. use rustc_ast::InlineAsmOptions; -use rustc_errors::{struct_span_err, Applicability}; use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::LocalDefId; @@ -14,6 +13,12 @@ use rustc_span::symbol::sym; use rustc_span::Span; use rustc_target::spec::abi::Abi; +use crate::errors::{ + CannotInlineNakedFunction, NakedFunctionsAsmBlock, NakedFunctionsAsmOptions, + NakedFunctionsMustUseNoreturn, NakedFunctionsOperands, NoPatterns, ParamsNotAllowed, + UndefinedNakedFunctionAbi, +}; + pub(crate) fn provide(providers: &mut Providers) { *providers = Providers { check_mod_naked_functions, ..*providers }; } @@ -56,7 +61,7 @@ fn check_mod_naked_functions(tcx: TyCtxt<'_>, module_def_id: LocalDefId) { fn check_inline(tcx: TyCtxt<'_>, def_id: LocalDefId) { let attrs = tcx.get_attrs(def_id.to_def_id(), sym::inline); for attr in attrs { - tcx.sess.struct_span_err(attr.span, "naked functions cannot be inlined").emit(); + tcx.sess.emit_err(CannotInlineNakedFunction { span: attr.span }); } } @@ -65,9 +70,12 @@ fn check_abi(tcx: TyCtxt<'_>, def_id: LocalDefId, abi: Abi) { if abi == Abi::Rust { let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); let span = tcx.def_span(def_id); - tcx.struct_span_lint_hir(UNDEFINED_NAKED_FUNCTION_ABI, hir_id, span, |lint| { - lint.build("Rust ABI is unsupported in naked functions").emit(); - }); + tcx.emit_spanned_lint( + UNDEFINED_NAKED_FUNCTION_ABI, + hir_id, + span, + UndefinedNakedFunctionAbi, + ); } } @@ -78,12 +86,7 @@ fn check_no_patterns(tcx: TyCtxt<'_>, params: &[hir::Param<'_>]) { hir::PatKind::Wild | hir::PatKind::Binding(hir::BindingAnnotation::NONE, _, _, None) => {} _ => { - tcx.sess - .struct_span_err( - param.pat.span, - "patterns not allowed in naked function parameters", - ) - .emit(); + tcx.sess.emit_err(NoPatterns { span: param.pat.span }); } } } @@ -113,14 +116,7 @@ impl<'tcx> Visitor<'tcx> for CheckParameters<'tcx> { )) = expr.kind { if self.params.contains(var_hir_id) { - self.tcx - .sess - .struct_span_err( - expr.span, - "referencing function parameters is not allowed in naked functions", - ) - .help("follow the calling convention in asm block to use parameters") - .emit(); + self.tcx.sess.emit_err(ParamsNotAllowed { span: expr.span }); return; } } @@ -135,26 +131,21 @@ fn check_asm<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId, body: &'tcx hir::Body< if let [(ItemKind::Asm | ItemKind::Err, _)] = this.items[..] { // Ok. } else { - let mut diag = struct_span_err!( - tcx.sess, - tcx.def_span(def_id), - E0787, - "naked functions must contain a single asm block" - ); - let mut must_show_error = false; let mut has_asm = false; let mut has_err = false; + let mut multiple_asms = vec![]; + let mut non_asms = vec![]; for &(kind, span) in &this.items { match kind { ItemKind::Asm if has_asm => { must_show_error = true; - diag.span_label(span, "multiple asm blocks are unsupported in naked functions"); + multiple_asms.push(span); } ItemKind::Asm => has_asm = true, ItemKind::NonAsm => { must_show_error = true; - diag.span_label(span, "non-asm is unsupported in naked functions"); + non_asms.push(span); } ItemKind::Err => has_err = true, } @@ -164,9 +155,11 @@ fn check_asm<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId, body: &'tcx hir::Body< // errors, then don't show an additional error. This allows for appending/prepending // `compile_error!("...")` statements and reduces error noise. if must_show_error || !has_err { - diag.emit(); - } else { - diag.cancel(); + tcx.sess.emit_err(NakedFunctionsAsmBlock { + span: tcx.def_span(def_id), + multiple_asms, + non_asms, + }); } } } @@ -247,13 +240,7 @@ impl<'tcx> CheckInlineAssembly<'tcx> { }) .collect(); if !unsupported_operands.is_empty() { - struct_span_err!( - self.tcx.sess, - unsupported_operands, - E0787, - "only `const` and `sym` operands are supported in naked functions", - ) - .emit(); + self.tcx.sess.emit_err(NakedFunctionsOperands { unsupported_operands }); } let unsupported_options: Vec<&'static str> = [ @@ -269,14 +256,10 @@ impl<'tcx> CheckInlineAssembly<'tcx> { .collect(); if !unsupported_options.is_empty() { - struct_span_err!( - self.tcx.sess, + self.tcx.sess.emit_err(NakedFunctionsAsmOptions { span, - E0787, - "asm options unsupported in naked functions: {}", - unsupported_options.join(", ") - ) - .emit(); + unsupported_options: unsupported_options.join(", "), + }); } if !asm.options.contains(InlineAsmOptions::NORETURN) { @@ -286,20 +269,7 @@ impl<'tcx> CheckInlineAssembly<'tcx> { .map_or_else(|| asm.template_strs.last().unwrap().2, |op| op.1) .shrink_to_hi(); - struct_span_err!( - self.tcx.sess, - span, - E0787, - "asm in naked functions must use `noreturn` option" - ) - .span_suggestion( - last_span, - "consider specifying that the asm block is responsible \ - for returning from the function", - ", options(noreturn)", - Applicability::MachineApplicable, - ) - .emit(); + self.tcx.sess.emit_err(NakedFunctionsMustUseNoreturn { span, last_span }); } } } diff --git a/compiler/rustc_passes/src/reachable.rs b/compiler/rustc_passes/src/reachable.rs index f7e3fac6b..50070869a 100644 --- a/compiler/rustc_passes/src/reachable.rs +++ b/compiler/rustc_passes/src/reachable.rs @@ -12,7 +12,7 @@ use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::Node; use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs}; -use rustc_middle::middle::privacy; +use rustc_middle::middle::privacy::{self, Level}; use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, DefIdTree, TyCtxt}; use rustc_session::config::CrateType; @@ -29,7 +29,7 @@ fn item_might_be_inlined(tcx: TyCtxt<'_>, item: &hir::Item<'_>, attrs: &CodegenF 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.def_id); + let generics = tcx.generics_of(item.owner_id); generics.requires_monomorphization(tcx) } _ => false, @@ -42,7 +42,7 @@ fn method_might_be_inlined( 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.def_id); + let generics = tcx.generics_of(impl_item.owner_id); if codegen_fn_attrs.requests_inline() || generics.requires_monomorphization(tcx) { return true; } @@ -116,6 +116,17 @@ impl<'tcx> Visitor<'tcx> for ReachableContext<'tcx> { intravisit::walk_expr(self, expr) } + + fn visit_inline_asm(&mut self, asm: &'tcx hir::InlineAsm<'tcx>, id: hir::HirId) { + for (op, _) in asm.operands { + if let hir::InlineAsmOperand::SymStatic { def_id, .. } = op { + if let Some(def_id) = def_id.as_local() { + self.reachable_symbols.insert(def_id); + } + } + } + intravisit::walk_inline_asm(self, asm, id); + } } impl<'tcx> ReachableContext<'tcx> { @@ -153,9 +164,9 @@ impl<'tcx> ReachableContext<'tcx> { 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) + method_might_be_inlined(self.tcx, impl_item, impl_did.def_id) } - hir::ImplItemKind::TyAlias(_) => false, + hir::ImplItemKind::Type(_) => false, }, Some(_) => false, None => false, // This will happen for default methods. @@ -216,7 +227,7 @@ impl<'tcx> ReachableContext<'tcx> { if item_might_be_inlined( self.tcx, &item, - self.tcx.codegen_fn_attrs(item.def_id), + self.tcx.codegen_fn_attrs(item.owner_id), ) { self.visit_nested_body(body); } @@ -271,7 +282,7 @@ impl<'tcx> ReachableContext<'tcx> { self.visit_nested_body(body) } } - hir::ImplItemKind::TyAlias(_) => {} + hir::ImplItemKind::Type(_) => {} }, Node::Expr(&hir::Expr { kind: hir::ExprKind::Closure(&hir::Closure { body, .. }), @@ -303,13 +314,13 @@ fn check_item<'tcx>( tcx: TyCtxt<'tcx>, id: hir::ItemId, worklist: &mut Vec<LocalDefId>, - access_levels: &privacy::AccessLevels, + effective_visibilities: &privacy::EffectiveVisibilities, ) { - if has_custom_linkage(tcx, id.def_id) { - worklist.push(id.def_id); + if has_custom_linkage(tcx, id.owner_id.def_id) { + worklist.push(id.owner_id.def_id); } - if !matches!(tcx.def_kind(id.def_id), DefKind::Impl) { + if !matches!(tcx.def_kind(id.owner_id), DefKind::Impl) { return; } @@ -318,8 +329,8 @@ fn check_item<'tcx>( if let hir::ItemKind::Impl(hir::Impl { of_trait: Some(ref trait_ref), ref items, .. }) = item.kind { - if !access_levels.is_reachable(item.def_id) { - worklist.extend(items.iter().map(|ii_ref| ii_ref.id.def_id)); + if !effective_visibilities.is_reachable(item.owner_id.def_id) { + worklist.extend(items.iter().map(|ii_ref| ii_ref.id.owner_id.def_id)); let Res::Def(DefKind::Trait, trait_def_id) = trait_ref.path.res else { unreachable!(); @@ -354,7 +365,7 @@ fn has_custom_linkage<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> bool { } fn reachable_set<'tcx>(tcx: TyCtxt<'tcx>, (): ()) -> FxHashSet<LocalDefId> { - let access_levels = &tcx.privacy_access_levels(()); + let effective_visibilities = &tcx.effective_visibilities(()); let any_library = tcx.sess.crate_types().iter().any(|ty| { @@ -373,7 +384,13 @@ fn reachable_set<'tcx>(tcx: TyCtxt<'tcx>, (): ()) -> FxHashSet<LocalDefId> { // If other crates link to us, they're going to expect to be able to // use the lang items, so we need to be sure to mark them as // exported. - reachable_context.worklist.extend(access_levels.map.keys()); + reachable_context.worklist = effective_visibilities + .iter() + .filter_map(|(&id, effective_vis)| { + effective_vis.is_public_at_level(Level::ReachableThroughImplTrait).then_some(id) + }) + .collect::<Vec<_>>(); + for item in tcx.lang_items().items().iter() { if let Some(def_id) = *item { if let Some(def_id) = def_id.as_local() { @@ -393,12 +410,12 @@ fn reachable_set<'tcx>(tcx: TyCtxt<'tcx>, (): ()) -> FxHashSet<LocalDefId> { let crate_items = tcx.hir_crate_items(()); for id in crate_items.items() { - check_item(tcx, id, &mut reachable_context.worklist, access_levels); + check_item(tcx, id, &mut reachable_context.worklist, effective_visibilities); } for id in crate_items.impl_items() { - if has_custom_linkage(tcx, id.def_id) { - reachable_context.worklist.push(id.def_id); + if has_custom_linkage(tcx, id.owner_id.def_id) { + reachable_context.worklist.push(id.owner_id.def_id); } } } diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index 9ba127609..78afa2f25 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -1,12 +1,18 @@ //! A pass that annotates every item and method with its stability level, //! propagating default levels lexically from parent to children ast nodes. +use crate::errors::{ + self, CannotStabilizeDeprecated, DeprecatedAttribute, DuplicateFeatureErr, + FeatureOnlyOnNightly, ImpliedFeatureNotExist, InvalidDeprecationVersion, InvalidStability, + MissingConstErr, MissingConstStabAttr, MissingStabilityAttr, TraitImplConstStable, + UnknownFeature, UselessStability, +}; use rustc_attr::{ self as attr, rust_version_symbol, ConstStability, Stability, StabilityLevel, Unstable, UnstableReason, VERSION_PLACEHOLDER, }; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap}; -use rustc_errors::{struct_span_err, Applicability}; +use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID}; @@ -14,12 +20,11 @@ use rustc_hir::hir_id::CRATE_HIR_ID; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{FieldDef, Item, ItemKind, TraitRef, Ty, TyKind, Variant}; use rustc_middle::hir::nested_filter; -use rustc_middle::middle::privacy::AccessLevels; +use rustc_middle::middle::privacy::EffectiveVisibilities; use rustc_middle::middle::stability::{AllowUnstable, DeprecationEntry, Index}; use rustc_middle::ty::{query::Providers, TyCtxt}; use rustc_session::lint; use rustc_session::lint::builtin::{INEFFECTIVE_UNSTABLE_TRAIT_IMPL, USELESS_DEPRECATED}; -use rustc_session::Session; use rustc_span::symbol::{sym, Symbol}; use rustc_span::Span; use rustc_target::spec::abi::Abi; @@ -122,16 +127,12 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { if kind == AnnotationKind::Prohibited || kind == AnnotationKind::DeprecationProhibited { let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id); - self.tcx.struct_span_lint_hir(USELESS_DEPRECATED, hir_id, *span, |lint| { - lint.build("this `#[deprecated]` annotation has no effect") - .span_suggestion_short( - *span, - "remove the unnecessary deprecation attribute", - "", - rustc_errors::Applicability::MachineApplicable, - ) - .emit(); - }); + self.tcx.emit_spanned_lint( + USELESS_DEPRECATED, + hir_id, + *span, + errors::DeprecatedAnnotationHasNoEffect { span: *span }, + ); } // `Deprecation` is just two pointers, no need to intern it @@ -182,7 +183,9 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { if !self.in_trait_impl || (self.in_trait_impl && !self.tcx.is_const_fn_raw(def_id.to_def_id())) { - missing_const_err(&self.tcx.sess, fn_sig.span, const_span); + self.tcx + .sess + .emit_err(MissingConstErr { fn_sig_span: fn_sig.span, const_span }); } } } @@ -200,14 +203,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { if let Some((rustc_attr::Deprecation { is_since_rustc_version: true, .. }, span)) = &depr { if stab.is_none() { - struct_span_err!( - self.tcx.sess, - *span, - E0549, - "deprecated attribute must be paired with \ - either stable or unstable attribute" - ) - .emit(); + self.tcx.sess.emit_err(DeprecatedAttribute { span: *span }); } } @@ -223,10 +219,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { if kind == AnnotationKind::Prohibited || (kind == AnnotationKind::Container && stab.level.is_stable() && is_deprecated) { - self.tcx.sess.struct_span_err(span,"this stability annotation is useless") - .span_label(span, "useless stability annotation") - .span_label(item_sp, "the stability attribute annotates this item") - .emit(); + self.tcx.sess.emit_err(UselessStability { span, item_sp }); } debug!("annotate: found {:?}", stab); @@ -242,19 +235,15 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { { match stab_v.parse::<u64>() { Err(_) => { - self.tcx.sess.struct_span_err(span, "invalid stability version found") - .span_label(span, "invalid stability version") - .span_label(item_sp, "the stability attribute annotates this item") - .emit(); + self.tcx.sess.emit_err(InvalidStability { span, item_sp }); break; } Ok(stab_vp) => match dep_v.parse::<u64>() { Ok(dep_vp) => match dep_vp.cmp(&stab_vp) { Ordering::Less => { - self.tcx.sess.struct_span_err(span, "an API can't be stabilized after it is deprecated") - .span_label(span, "invalid version") - .span_label(item_sp, "the stability attribute annotates this item") - .emit(); + self.tcx + .sess + .emit_err(CannotStabilizeDeprecated { span, item_sp }); break; } Ordering::Equal => continue, @@ -262,10 +251,9 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { }, Err(_) => { if dep_v != "TBD" { - self.tcx.sess.struct_span_err(span, "invalid deprecation version found") - .span_label(span, "invalid deprecation version") - .span_label(item_sp, "the stability attribute annotates this item") - .emit(); + self.tcx + .sess + .emit_err(InvalidDeprecationVersion { span, item_sp }); } break; } @@ -274,7 +262,9 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { } } - if let Stability { level: Unstable { implied_by: Some(implied_by), .. }, feature } = stab { + if let Stability { level: Unstable { implied_by: Some(implied_by), .. }, feature } = + stab + { self.index.implications.insert(implied_by, feature); } @@ -388,7 +378,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { } self.annotate( - i.def_id, + i.owner_id.def_id, i.span, fn_sig, kind, @@ -407,7 +397,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { }; self.annotate( - ti.def_id, + ti.owner_id.def_id, ti.span, fn_sig, AnnotationKind::Required, @@ -430,7 +420,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { }; self.annotate( - ii.def_id, + ii.owner_id.def_id, ii.span, fn_sig, kind, @@ -488,7 +478,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { fn visit_foreign_item(&mut self, i: &'tcx hir::ForeignItem<'tcx>) { self.annotate( - i.def_id, + i.owner_id.def_id, i.span, None, AnnotationKind::Required, @@ -526,15 +516,18 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { struct MissingStabilityAnnotations<'tcx> { tcx: TyCtxt<'tcx>, - access_levels: &'tcx AccessLevels, + effective_visibilities: &'tcx EffectiveVisibilities, } impl<'tcx> MissingStabilityAnnotations<'tcx> { fn check_missing_stability(&self, def_id: LocalDefId, span: Span) { let stab = self.tcx.stability().local_stability(def_id); - if !self.tcx.sess.opts.test && stab.is_none() && self.access_levels.is_reachable(def_id) { + if !self.tcx.sess.opts.test + && stab.is_none() + && self.effective_visibilities.is_reachable(def_id) + { let descr = self.tcx.def_kind(def_id).descr(def_id.to_def_id()); - self.tcx.sess.span_err(span, &format!("{} has missing stability attribute", descr)); + self.tcx.sess.emit_err(MissingStabilityAttr { span, descr }); } } @@ -550,11 +543,11 @@ impl<'tcx> MissingStabilityAnnotations<'tcx> { .lookup_stability(def_id) .map_or(false, |stability| stability.level.is_stable()); let missing_const_stability_attribute = self.tcx.lookup_const_stability(def_id).is_none(); - let is_reachable = self.access_levels.is_reachable(def_id); + let is_reachable = self.effective_visibilities.is_reachable(def_id); if is_const && is_stable && missing_const_stability_attribute && is_reachable { let descr = self.tcx.def_kind(def_id).descr(def_id.to_def_id()); - self.tcx.sess.span_err(span, &format!("{descr} has missing const stability attribute")); + self.tcx.sess.emit_err(MissingConstStabAttr { span, descr }); } } } @@ -576,25 +569,25 @@ impl<'tcx> Visitor<'tcx> for MissingStabilityAnnotations<'tcx> { hir::ItemKind::Impl(hir::Impl { of_trait: None, .. }) | hir::ItemKind::ForeignMod { .. } ) { - self.check_missing_stability(i.def_id, i.span); + self.check_missing_stability(i.owner_id.def_id, i.span); } // Ensure stable `const fn` have a const stability attribute. - self.check_missing_const_stability(i.def_id, i.span); + self.check_missing_const_stability(i.owner_id.def_id, i.span); intravisit::walk_item(self, i) } fn visit_trait_item(&mut self, ti: &'tcx hir::TraitItem<'tcx>) { - self.check_missing_stability(ti.def_id, ti.span); + self.check_missing_stability(ti.owner_id.def_id, ti.span); intravisit::walk_trait_item(self, ti); } fn visit_impl_item(&mut self, ii: &'tcx hir::ImplItem<'tcx>) { let impl_def_id = self.tcx.hir().get_parent_item(ii.hir_id()); if self.tcx.impl_trait_ref(impl_def_id).is_none() { - self.check_missing_stability(ii.def_id, ii.span); - self.check_missing_const_stability(ii.def_id, ii.span); + self.check_missing_stability(ii.owner_id.def_id, ii.span); + self.check_missing_const_stability(ii.owner_id.def_id, ii.span); } intravisit::walk_impl_item(self, ii); } @@ -613,7 +606,7 @@ impl<'tcx> Visitor<'tcx> for MissingStabilityAnnotations<'tcx> { } fn visit_foreign_item(&mut self, i: &'tcx hir::ForeignItem<'tcx>) { - self.check_missing_stability(i.def_id, i.span); + self.check_missing_stability(i.owner_id.def_id, i.span); intravisit::walk_foreign_item(self, i); } // Note that we don't need to `check_missing_stability` for default generic parameters, @@ -719,7 +712,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> { return; } - let Some(cnum) = self.tcx.extern_mod_stmt_cnum(item.def_id) else { + let Some(cnum) = self.tcx.extern_mod_stmt_cnum(item.owner_id.def_id) else { return; }; let def_id = cnum.as_def_id(); @@ -755,10 +748,8 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> { INEFFECTIVE_UNSTABLE_TRAIT_IMPL, item.hir_id(), span, - |lint| {lint - .build("an `#[unstable]` annotation here has no effect") - .note("see issue #55436 <https://github.com/rust-lang/rust/issues/55436> for more information") - .emit();} + "an `#[unstable]` annotation here has no effect", + |lint| lint.note("see issue #55436 <https://github.com/rust-lang/rust/issues/55436> for more information") ); } } @@ -769,16 +760,12 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> { && *constness == hir::Constness::Const && const_stab.map_or(false, |(stab, _)| stab.is_const_stable()) { - self.tcx - .sess - .struct_span_err(item.span, "trait implementations cannot be const stable yet") - .note("see issue #67792 <https://github.com/rust-lang/rust/issues/67792> for more information") - .emit(); + self.tcx.sess.emit_err(TraitImplConstStable { span: item.span }); } } for impl_item_ref in *items { - let impl_item = self.tcx.associated_item(impl_item_ref.id.def_id); + let impl_item = self.tcx.associated_item(impl_item_ref.id.owner_id); if let Some(def_id) = impl_item.trait_item_def_id { // Pass `None` to skip deprecation warnings. @@ -872,7 +859,7 @@ fn is_unstable_reexport<'tcx>(tcx: TyCtxt<'tcx>, id: hir::HirId) -> bool { } // If this is a path that isn't a use, we don't need to do anything special - if !matches!(tcx.hir().item(hir::ItemId { def_id }).kind, ItemKind::Use(..)) { + if !matches!(tcx.hir().expect_item(def_id).kind, ItemKind::Use(..)) { return false; } @@ -907,8 +894,25 @@ impl<'tcx> Visitor<'tcx> for CheckTraitImplStable<'tcx> { if let TyKind::Never = t.kind { self.fully_stable = false; } + if let TyKind::BareFn(f) = t.kind { + if rustc_target::spec::abi::is_stable(f.abi.name()).is_err() { + self.fully_stable = false; + } + } intravisit::walk_ty(self, t) } + + fn visit_fn_decl(&mut self, fd: &'tcx hir::FnDecl<'tcx>) { + for ty in fd.inputs { + self.visit_ty(ty) + } + if let hir::FnRetTy::Return(output_ty) = fd.output { + match output_ty.kind { + TyKind::Never => {} // `-> !` is stable + _ => self.visit_ty(output_ty), + } + } + } } /// Given the list of enabled features that were not language features (i.e., that @@ -918,8 +922,8 @@ pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) { let is_staged_api = tcx.sess.opts.unstable_opts.force_unstable_if_unmarked || tcx.features().staged_api; if is_staged_api { - let access_levels = &tcx.privacy_access_levels(()); - let mut missing = MissingStabilityAnnotations { tcx, access_levels }; + let effective_visibilities = &tcx.effective_visibilities(()); + let mut missing = MissingStabilityAnnotations { tcx, effective_visibilities }; missing.check_missing_stability(CRATE_DEF_ID, tcx.hir().span(CRATE_HIR_ID)); tcx.hir().walk_toplevel_module(&mut missing); tcx.hir().visit_all_item_likes_in_crate(&mut missing); @@ -934,7 +938,7 @@ pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) { } if !lang_features.insert(feature) { // Warn if the user enables a lang feature multiple times. - duplicate_feature_err(tcx.sess, span, feature); + tcx.sess.emit_err(DuplicateFeatureErr { span, feature }); } } @@ -942,18 +946,14 @@ pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) { let mut remaining_lib_features = FxIndexMap::default(); for (feature, span) in declared_lib_features { if !tcx.sess.opts.unstable_features.is_nightly_build() { - struct_span_err!( - tcx.sess, - *span, - E0554, - "`#![feature]` may not be used on the {} release channel", - env!("CFG_RELEASE_CHANNEL") - ) - .emit(); + tcx.sess.emit_err(FeatureOnlyOnNightly { + span: *span, + release_channel: env!("CFG_RELEASE_CHANNEL"), + }); } if remaining_lib_features.contains_key(&feature) { // Warn if the user enables a lib feature multiple times. - duplicate_feature_err(tcx.sess, *span, *feature); + tcx.sess.emit_err(DuplicateFeatureErr { span: *span, feature: *feature }); } remaining_lib_features.insert(feature, *span); } @@ -1054,23 +1054,18 @@ pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) { } for (feature, span) in remaining_lib_features { - struct_span_err!(tcx.sess, span, E0635, "unknown feature `{}`", feature).emit(); + tcx.sess.emit_err(UnknownFeature { span, feature: *feature }); } for (implied_by, feature) in remaining_implications { let local_defined_features = tcx.lib_features(()); - let span = local_defined_features + let span = *local_defined_features .stable .get(&feature) .map(|(_, span)| span) .or_else(|| local_defined_features.unstable.get(&feature)) .expect("feature that implied another does not exist"); - tcx.sess - .struct_span_err( - *span, - format!("feature `{implied_by}` implying `{feature}` does not exist"), - ) - .emit(); + tcx.sess.emit_err(ImpliedFeatureNotExist { span, feature, implied_by }); } // FIXME(#44232): the `used_features` table no longer exists, so we @@ -1084,27 +1079,31 @@ fn unnecessary_partially_stable_feature_lint( implies: Symbol, since: Symbol, ) { - tcx.struct_span_lint_hir(lint::builtin::STABLE_FEATURES, hir::CRATE_HIR_ID, span, |lint| { - lint.build(&format!( + tcx.struct_span_lint_hir( + lint::builtin::STABLE_FEATURES, + hir::CRATE_HIR_ID, + span, + format!( "the feature `{feature}` has been partially stabilized since {since} and is succeeded \ by the feature `{implies}`" - )) - .span_suggestion( - span, - &format!( + ), + |lint| { + lint.span_suggestion( + span, + &format!( "if you are using features which are still unstable, change to using `{implies}`" ), - implies, - Applicability::MaybeIncorrect, - ) - .span_suggestion( - tcx.sess.source_map().span_extend_to_line(span), - "if you are using features which are now stable, remove this line", - "", - Applicability::MaybeIncorrect, - ) - .emit(); - }); + implies, + Applicability::MaybeIncorrect, + ) + .span_suggestion( + tcx.sess.source_map().span_extend_to_line(span), + "if you are using features which are now stable, remove this line", + "", + Applicability::MaybeIncorrect, + ) + }, + ); } fn unnecessary_stable_feature_lint( @@ -1116,28 +1115,7 @@ fn unnecessary_stable_feature_lint( if since.as_str() == VERSION_PLACEHOLDER { since = rust_version_symbol(); } - tcx.struct_span_lint_hir(lint::builtin::STABLE_FEATURES, hir::CRATE_HIR_ID, span, |lint| { - lint.build(&format!( - "the feature `{feature}` has been stable since {since} and no longer requires an \ - attribute to enable", - )) - .emit(); + tcx.struct_span_lint_hir(lint::builtin::STABLE_FEATURES, hir::CRATE_HIR_ID, span, format!("the feature `{feature}` has been stable since {since} and no longer requires an attribute to enable"), |lint| { + lint }); } - -fn duplicate_feature_err(sess: &Session, span: Span, feature: Symbol) { - struct_span_err!(sess, span, E0636, "the feature `{}` has already been declared", feature) - .emit(); -} - -fn missing_const_err(session: &Session, fn_sig_span: Span, const_span: Span) { - const ERROR_MSG: &'static str = "attributes `#[rustc_const_unstable]` \ - and `#[rustc_const_stable]` require \ - the function or method to be `const`"; - - session - .struct_span_err(fn_sig_span, ERROR_MSG) - .span_help(fn_sig_span, "make the function or method const") - .span_label(const_span, "attribute specified here") - .emit(); -} diff --git a/compiler/rustc_passes/src/weak_lang_items.rs b/compiler/rustc_passes/src/weak_lang_items.rs index c48b4ecf8..959ee600c 100644 --- a/compiler/rustc_passes/src/weak_lang_items.rs +++ b/compiler/rustc_passes/src/weak_lang_items.rs @@ -1,13 +1,17 @@ //! Validity checking for weak lang items use rustc_data_structures::fx::FxHashSet; -use rustc_errors::struct_span_err; use rustc_hir::lang_items::{self, LangItem}; use rustc_hir::weak_lang_items::WEAK_ITEMS_REFS; use rustc_middle::middle::lang_items::required; use rustc_middle::ty::TyCtxt; use rustc_session::config::CrateType; +use crate::errors::{ + AllocFuncRequired, MissingAllocErrorHandler, MissingLangItem, MissingPanicHandler, + UnknownExternLangItem, +}; + /// 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. pub fn check_crate<'tcx>(tcx: TyCtxt<'tcx>, items: &mut lang_items::LanguageItems) { @@ -30,15 +34,8 @@ pub fn check_crate<'tcx>(tcx: TyCtxt<'tcx>, items: &mut lang_items::LanguageItem items.missing.push(item); } } else { - let span = tcx.def_span(id.def_id); - struct_span_err!( - tcx.sess, - span, - E0264, - "unknown external lang item: `{}`", - lang_item - ) - .emit(); + let span = tcx.def_span(id.owner_id); + tcx.sess.emit_err(UnknownExternLangItem { span, lang_item }); } } } @@ -71,20 +68,14 @@ fn verify<'tcx>(tcx: TyCtxt<'tcx>, items: &lang_items::LanguageItems) { for (name, &item) in WEAK_ITEMS_REFS.iter() { if missing.contains(&item) && required(tcx, item) && items.require(item).is_err() { if item == LangItem::PanicImpl { - tcx.sess.err("`#[panic_handler]` function required, but not found"); + tcx.sess.emit_err(MissingPanicHandler); } else if item == LangItem::Oom { if !tcx.features().default_alloc_error_handler { - tcx.sess.err("`#[alloc_error_handler]` function required, but not found"); - tcx.sess.note_without_error("use `#![feature(default_alloc_error_handler)]` for a default error handler"); + tcx.sess.emit_err(AllocFuncRequired); + tcx.sess.emit_note(MissingAllocErrorHandler); } } else { - tcx - .sess - .diagnostic() - .struct_err(&format!("language item required, but not found: `{}`", name)) - .note(&format!("this can occur when a binary crate with `#![no_std]` is compiled for a target where `{}` is defined in the standard library", name)) - .help(&format!("you may be able to compile for a target that doesn't need `{}`, specify a target with `--target` or in `.cargo/config`", name)) - .emit(); + tcx.sess.emit_err(MissingLangItem { name: *name }); } } } |