From 9e13cd3e24086b9e4ebe1b96a2005ccd928c7b56 Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Mon, 24 Oct 2022 20:23:25 -0500 Subject: [PATCH 1/7] Resolve lang items in ast --- Cargo.lock | 1 + compiler/rustc_ast/src/ast.rs | 11 +- .../locales/en-US/passes.ftl | 24 -- .../locales/en-US/resolve.ftl | 23 ++ compiler/rustc_error_messages/src/lib.rs | 1 + compiler/rustc_hir/src/target.rs | 40 +++ compiler/rustc_metadata/src/rmeta/decoder.rs | 1 + compiler/rustc_metadata/src/rmeta/encoder.rs | 6 +- compiler/rustc_middle/src/ty/mod.rs | 4 +- compiler/rustc_passes/src/errors.rs | 44 +-- compiler/rustc_passes/src/lang_items.rs | 274 +++++------------- compiler/rustc_passes/src/weak_lang_items.rs | 17 +- compiler/rustc_resolve/Cargo.toml | 1 + compiler/rustc_resolve/src/errors.rs | 45 +++ compiler/rustc_resolve/src/lang_items.rs | 126 ++++++++ compiler/rustc_resolve/src/lib.rs | 13 +- .../feature-gate-lang-items.stderr | 12 +- src/test/ui/lang-items/issue-83471.stderr | 18 +- 18 files changed, 362 insertions(+), 299 deletions(-) create mode 100644 compiler/rustc_error_messages/locales/en-US/resolve.ftl create mode 100644 compiler/rustc_resolve/src/errors.rs create mode 100644 compiler/rustc_resolve/src/lang_items.rs diff --git a/Cargo.lock b/Cargo.lock index dab693419a95d..9014b12e7d601 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4064,6 +4064,7 @@ dependencies = [ "rustc_feature", "rustc_hir", "rustc_index", + "rustc_macros", "rustc_metadata", "rustc_middle", "rustc_query_system", diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 4ef43735a62c8..b36bbe66e79bb 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -2882,7 +2882,7 @@ impl ItemKind { } } - pub fn descr(&self) -> &str { + pub fn descr(&self) -> &'static str { match self { ItemKind::ExternCrate(..) => "extern crate", ItemKind::Use(..) => "`use` import", @@ -2952,6 +2952,15 @@ impl AssocItemKind { Self::MacCall(..) => Defaultness::Final, } } + + pub fn generics(&self) -> Option<&Generics> { + match self { + Self::Const(..) => None, + Self::Fn(f) => Some(&f.generics), + Self::Type(t) => Some(&t.generics), + Self::MacCall(_) => None, + } + } } impl From for ItemKind { diff --git a/compiler/rustc_error_messages/locales/en-US/passes.ftl b/compiler/rustc_error_messages/locales/en-US/passes.ftl index bc5bfe2a24448..a2c1641b78e19 100644 --- a/compiler/rustc_error_messages/locales/en-US/passes.ftl +++ b/compiler/rustc_error_messages/locales/en-US/passes.ftl @@ -361,9 +361,6 @@ passes_deprecated_annotation_has_no_effect = this `#[deprecated]` annotation has no effect .suggestion = remove the unnecessary deprecation attribute -passes_unknown_external_lang_item = - unknown external lang item: `{$lang_item}` - passes_missing_panic_handler = `#[panic_handler]` function required, but not found @@ -372,14 +369,6 @@ passes_missing_lang_item = .note = this can occur when a binary crate with `#![no_std]` is compiled for a target where `{$name}` is defined in the standard library .help = you may be able to compile for a target that doesn't need `{$name}`, specify a target with `--target` or in `.cargo/config` -passes_lang_item_on_incorrect_target = - `{$name}` language item must be applied to a {$expected_target} - .label = attribute should be applied to a {$expected_target}, not a {$actual_target} - -passes_unknown_lang_item = - definition of an unknown language item: `{$name}` - .label = definition of unknown language item `{$name}` - passes_invalid_attr_at_crate_level = `{$name}` attribute cannot be used at crate level .suggestion = perhaps you meant to use an outer attribute @@ -559,19 +548,6 @@ passes_duplicate_lang_item_crate_depends = .first_definition_path = first definition in `{$orig_crate_name}` loaded from {$orig_path} .second_definition_path = second definition in `{$crate_name}` loaded from {$path} -passes_incorrect_target = - `{$name}` language item must be applied to a {$kind} with {$at_least -> - [true] at least {$num} - *[false] {$num} - } generic {$num -> - [one] argument - *[other] arguments - } - .label = this {$kind} has {$actual_num} generic {$actual_num -> - [one] argument - *[other] arguments - } - passes_useless_assignment = useless assignment of {$is_field_assign -> [true] field diff --git a/compiler/rustc_error_messages/locales/en-US/resolve.ftl b/compiler/rustc_error_messages/locales/en-US/resolve.ftl new file mode 100644 index 0000000000000..16e6c87b2759b --- /dev/null +++ b/compiler/rustc_error_messages/locales/en-US/resolve.ftl @@ -0,0 +1,23 @@ +resolve_lang_item_on_incorrect_target = + `{$name}` language item must be applied to a {$expected_target} + .label = attribute should be applied to a {$expected_target}, not a {$actual_target} + +resolve_unknown_external_lang_item = + unknown external lang item: `{$lang_item}` + +resolve_unknown_lang_item = + definition of an unknown language item: `{$name}` + .label = definition of unknown language item `{$name}` + +resolve_incorrect_target = + `{$name}` language item must be applied to a {$kind} with {$at_least -> + [true] at least {$num} + *[false] {$num} + } generic {$num -> + [one] argument + *[other] arguments + } + .label = this {$kind} has {$actual_num} generic {$actual_num -> + [one] argument + *[other] arguments + } diff --git a/compiler/rustc_error_messages/src/lib.rs b/compiler/rustc_error_messages/src/lib.rs index 9465051dd103f..71de4ef99e2e4 100644 --- a/compiler/rustc_error_messages/src/lib.rs +++ b/compiler/rustc_error_messages/src/lib.rs @@ -61,6 +61,7 @@ fluent_messages! { plugin_impl => "../locales/en-US/plugin_impl.ftl", privacy => "../locales/en-US/privacy.ftl", query_system => "../locales/en-US/query_system.ftl", + resolve => "../locales/en-US/resolve.ftl", save_analysis => "../locales/en-US/save_analysis.ftl", session => "../locales/en-US/session.ftl", symbol_mangling => "../locales/en-US/symbol_mangling.ftl", diff --git a/compiler/rustc_hir/src/target.rs b/compiler/rustc_hir/src/target.rs index 5917d5e346e37..2f629d10d0ba6 100644 --- a/compiler/rustc_hir/src/target.rs +++ b/compiler/rustc_hir/src/target.rs @@ -4,6 +4,9 @@ //! conflicts between multiple such attributes attached to the same //! item. +use rustc_ast as ast; +use rustc_ast::visit as ast_visit; + use crate::hir; use crate::{Item, ItemKind, TraitItem, TraitItemKind}; @@ -198,4 +201,41 @@ impl Target { Target::ExprField => "struct field", } } + + pub fn from_ast_item(item: &ast::Item) -> Target { + match item.kind { + ast::ItemKind::ExternCrate(_) => Target::ExternCrate, + ast::ItemKind::Use(_) => Target::Use, + ast::ItemKind::Static(..) => Target::Static, + ast::ItemKind::Const(..) => Target::Const, + ast::ItemKind::Fn(_) => Target::Fn, + ast::ItemKind::Mod(..) => Target::Mod, + ast::ItemKind::ForeignMod(_) => Target::ForeignMod, + ast::ItemKind::GlobalAsm(_) => Target::GlobalAsm, + ast::ItemKind::TyAlias(_) => Target::TyAlias, + ast::ItemKind::Enum(..) => Target::Enum, + ast::ItemKind::Struct(..) => Target::Struct, + ast::ItemKind::Union(..) => Target::Union, + ast::ItemKind::Trait(_) => Target::Trait, + ast::ItemKind::TraitAlias(..) => Target::TraitAlias, + ast::ItemKind::Impl(_) => Target::Impl, + ast::ItemKind::MacroDef(_) => Target::MacroDef, + ast::ItemKind::MacCall(_) => panic!("unexpected MacCall"), + } + } + + pub fn from_ast_assoc_item(kind: &ast::AssocItemKind, ctxt: ast_visit::AssocCtxt) -> Target { + match kind { + ast::AssocItemKind::Const(..) => Target::AssocConst, + ast::AssocItemKind::Fn(f) => { + let kind = match ctxt { + ast_visit::AssocCtxt::Impl => MethodKind::Inherent, + ast_visit::AssocCtxt::Trait => MethodKind::Trait { body: f.body.is_some() }, + }; + Target::Method(kind) + } + ast::AssocItemKind::Type(_) => Target::AssocTy, + ast::AssocItemKind::MacCall(_) => panic!("unexpected MacCall"), + } + } } diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index 8e80d794a1368..db73da0fcf67f 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -15,6 +15,7 @@ use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res}; use rustc_hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX, LOCAL_CRATE}; use rustc_hir::definitions::{DefKey, DefPath, DefPathData, DefPathHash}; use rustc_hir::diagnostic_items::DiagnosticItems; +use rustc_hir::LangItem; use rustc_index::vec::{Idx, IndexVec}; use rustc_middle::metadata::ModChild; use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo}; diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index c907ee6462870..37e90f725dde0 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1908,10 +1908,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { fn encode_lang_items(&mut self) -> LazyArray<(DefIndex, LangItem)> { empty_proc_macro!(self); - let lang_items = self.tcx.lang_items().iter(); - self.lazy_array(lang_items.filter_map(|(lang_item, def_id)| { - def_id.as_local().map(|id| (id.local_def_index, lang_item)) - })) + let lang_items = self.tcx.resolutions(()).lang_items.iter(); + self.lazy_array(lang_items.map(|&(def_id, lang_item)| (def_id.local_def_index, lang_item))) } fn encode_lang_items_missing(&mut self) -> LazyArray { diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index a42d05706137c..b4aff23aba32c 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -39,7 +39,7 @@ use rustc_hir as hir; use rustc_hir::def::{CtorKind, CtorOf, DefKind, LifetimeRes, Res}; use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LocalDefIdMap}; use rustc_hir::definitions::Definitions; -use rustc_hir::Node; +use rustc_hir::{LangItem, Node}; use rustc_index::vec::IndexVec; use rustc_macros::HashStable; use rustc_query_system::ich::StableHashingContext; @@ -178,6 +178,8 @@ pub struct ResolverGlobalCtxt { /// exist under `std`. For example, wrote `str::from_utf8` instead of `std::str::from_utf8`. pub confused_type_with_std_module: FxHashMap, pub registered_tools: RegisteredTools, + pub lang_items: Vec<(LocalDefId, LangItem)>, + pub missing_lang_items: Vec, } /// Resolutions that should only be used for lowering. diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 4a5cfd2d429cd..84efcfa6a1333 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -5,7 +5,7 @@ use std::{ use rustc_ast::Label; use rustc_errors::{error_code, Applicability, ErrorGuaranteed, IntoDiagnostic, MultiSpan}; -use rustc_hir::{self as hir, ExprKind, Target}; +use rustc_hir::{self as hir, ExprKind}; use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; use rustc_middle::ty::{MainDefinition, Ty}; use rustc_span::{Span, Symbol, DUMMY_SP}; @@ -689,14 +689,6 @@ pub struct DeprecatedAnnotationHasNoEffect { 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; @@ -709,26 +701,6 @@ 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, @@ -1238,20 +1210,6 @@ impl IntoDiagnostic<'_> for DuplicateLangItem { } } -#[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> { diff --git a/compiler/rustc_passes/src/lang_items.rs b/compiler/rustc_passes/src/lang_items.rs index 188efc528ef82..4ab106c5d65e7 100644 --- a/compiler/rustc_passes/src/lang_items.rs +++ b/compiler/rustc_passes/src/lang_items.rs @@ -7,20 +7,14 @@ //! * Traits that represent operators; e.g., `Add`, `Sub`, `Index`. //! * Functions called by the compiler itself. -use crate::check_attr::target_from_impl_item; -use crate::errors::{ - DuplicateLangItem, IncorrectTarget, LangItemOnIncorrectTarget, UnknownLangItem, -}; +use crate::errors::DuplicateLangItem; use crate::weak_lang_items; -use rustc_hir as hir; -use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; -use rustc_hir::lang_items::{extract, GenericRequirement}; -use rustc_hir::{HirId, LangItem, LanguageItems, Target}; +use rustc_hir::{LangItem, LanguageItems}; use rustc_middle::ty::TyCtxt; use rustc_session::cstore::ExternCrate; -use rustc_span::{symbol::kw::Empty, Span}; +use rustc_span::symbol::kw::Empty; use rustc_middle::ty::query::Providers; @@ -30,216 +24,102 @@ pub(crate) enum Duplicate { CrateDepends, } -struct LanguageItemCollector<'tcx> { - items: LanguageItems, - tcx: TyCtxt<'tcx>, -} - -impl<'tcx> LanguageItemCollector<'tcx> { - fn new(tcx: TyCtxt<'tcx>) -> LanguageItemCollector<'tcx> { - LanguageItemCollector { tcx, items: LanguageItems::new() } - } - - fn check_for_lang(&mut self, actual_target: Target, hir_id: HirId) { - let attrs = self.tcx.hir().attrs(hir_id); - if let Some((name, span)) = extract(&attrs) { - match LangItem::from_name(name) { - // Known lang item with attribute on correct target. - Some(lang_item) if actual_target == lang_item.target() => { - self.collect_item_extended(lang_item, hir_id, span); - } - // Known lang item with attribute on incorrect target. - Some(lang_item) => { - self.tcx.sess.emit_err(LangItemOnIncorrectTarget { - span, - name, - expected_target: lang_item.target(), - actual_target, - }); - } - // Unknown lang item. - _ => { - self.tcx.sess.emit_err(UnknownLangItem { span, name }); +fn collect_item( + tcx: TyCtxt<'_>, + items: &mut LanguageItems, + lang_item: LangItem, + item_def_id: DefId, +) { + // Check for duplicates. + if let Some(original_def_id) = items.get(lang_item) { + if original_def_id != item_def_id { + let local_span = item_def_id.as_local().map(|id| tcx.source_span(id)); + let lang_item_name = lang_item.name(); + let crate_name = 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 { + tcx.crate_extern_paths(item_def_id.krate) + .iter() + .map(|p| p.display().to_string()) + .collect::>() + .join(", ") + .into() + }; + let first_defined_span = original_def_id.as_local().map(|id| tcx.source_span(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 { + tcx.crate_extern_paths(original_def_id.krate) + .iter() + .map(|p| p.display().to_string()) + .collect::>() + .join(", ") + .into() + }; + if first_defined_span.is_none() { + orig_crate_name = tcx.crate_name(original_def_id.krate); + if let Some(ExternCrate { dependency_of: inner_dependency_of, .. }) = + tcx.extern_crate(original_def_id) + { + orig_dependency_of = tcx.crate_name(*inner_dependency_of); } } - } - } - fn collect_item(&mut self, lang_item: LangItem, item_def_id: DefId) { - // Check for duplicates. - if let Some(original_def_id) = self.items.get(lang_item) { - if original_def_id != item_def_id { - let local_span = self.tcx.hir().span_if_local(item_def_id); - let lang_item_name = lang_item.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::>() - .join(", ") - .into() - }; - 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 { - self.tcx - .crate_extern_paths(original_def_id.krate) - .iter() - .map(|p| p.display().to_string()) - .collect::>() - .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 duplicate = if local_span.is_some() { + Duplicate::Plain + } else { + match tcx.extern_crate(item_def_id) { + Some(ExternCrate { dependency_of: inner_dependency_of, .. }) => { + dependency_of = tcx.crate_name(*inner_dependency_of); + Duplicate::CrateDepends } + _ => Duplicate::Crate, } - - 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, - }); - } - } - - // Matched. - self.items.set(lang_item, item_def_id); - } - - // Like collect_item() above, but also checks whether the lang item is declared - // with the right number of generic arguments. - fn collect_item_extended(&mut self, lang_item: LangItem, hir_id: HirId, span: Span) { - let item_def_id = self.tcx.hir().local_def_id(hir_id).to_def_id(); - let name = lang_item.name(); - - // Now check whether the lang_item has the expected number of generic - // arguments. Generally speaking, binary and indexing operations have - // one (for the RHS/index), unary operations have none, the closure - // traits have one for the argument list, generators have one for the - // resume argument, and ordering/equality relations have one for the RHS - // Some other types like Box and various functions like drop_in_place - // have minimum requirements. - - if let hir::Node::Item(hir::Item { kind, span: item_span, .. }) = self.tcx.hir().get(hir_id) - { - let (actual_num, generics_span) = match kind.generics() { - Some(generics) => (generics.params.len(), generics.span), - None => (0, *item_span), }; - let mut at_least = false; - let required = match lang_item.required_generics() { - GenericRequirement::Exact(num) if num != actual_num => Some(num), - GenericRequirement::Minimum(num) if actual_num < num => { - at_least = true; - Some(num)} - , - // If the number matches, or there is no requirement, handle it normally - _ => None, - }; - - 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. - self.tcx.sess.emit_err(IncorrectTarget { - span, - generics_span, - name: name.as_str(), - kind: kind.descr(), - num, - actual_num, - at_least, - }); - - // return early to not collect the lang item - return; - } + 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, + }); } - - self.collect_item(lang_item, item_def_id); } + + // Matched. + items.set(lang_item, item_def_id); } /// Traverses and collects all the lang items in all crates. fn get_lang_items(tcx: TyCtxt<'_>, (): ()) -> LanguageItems { - // Initialize the collector. - let mut collector = LanguageItemCollector::new(tcx); + let mut items = LanguageItems::new(); // Collect lang items in other crates. for &cnum in tcx.crates(()).iter() { for &(def_id, lang_item) in tcx.defined_lang_items(cnum).iter() { - collector.collect_item(lang_item, def_id); - } - } - - // Collect lang items in this crate. - 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.owner_id)), id.hir_id()); - - 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 { - collector.check_for_lang(Target::Variant, variant.id); - } - } + collect_item(tcx, &mut items, lang_item, def_id); } } - // FIXME: avoid calling trait_item() when possible - for id in crate_items.trait_items() { - let item = tcx.hir().trait_item(id); - collector.check_for_lang(Target::from_trait_item(item), item.hir_id()) - } - - // FIXME: avoid calling impl_item() when possible - for id in crate_items.impl_items() { - let item = tcx.hir().impl_item(id); - collector.check_for_lang(target_from_impl_item(tcx, item), item.hir_id()) + // Collect lang items from this crate + for &(def_id, lang_item) in &tcx.resolutions(()).lang_items { + collect_item(tcx, &mut items, lang_item, def_id.to_def_id()); } - // Extract out the found lang items. - let LanguageItemCollector { mut items, .. } = collector; - // Find all required but not-yet-defined lang items. weak_lang_items::check_crate(tcx, &mut items); diff --git a/compiler/rustc_passes/src/weak_lang_items.rs b/compiler/rustc_passes/src/weak_lang_items.rs index f0815fcd8db9a..10f1126450159 100644 --- a/compiler/rustc_passes/src/weak_lang_items.rs +++ b/compiler/rustc_passes/src/weak_lang_items.rs @@ -7,7 +7,7 @@ use rustc_middle::middle::lang_items::required; use rustc_middle::ty::TyCtxt; use rustc_session::config::CrateType; -use crate::errors::{MissingLangItem, MissingPanicHandler, UnknownExternLangItem}; +use crate::errors::{MissingLangItem, MissingPanicHandler}; /// 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. @@ -22,18 +22,9 @@ pub fn check_crate<'tcx>(tcx: TyCtxt<'tcx>, items: &mut lang_items::LanguageItem items.missing.push(LangItem::EhCatchTypeinfo); } - let crate_items = tcx.hir_crate_items(()); - for id in crate_items.foreign_items() { - let attrs = tcx.hir().attrs(id.hir_id()); - if let Some((lang_item, _)) = lang_items::extract(attrs) { - if let Some(item) = LangItem::from_name(lang_item) && item.is_weak() { - if items.get(item).is_none() { - items.missing.push(item); - } - } else { - let span = tcx.def_span(id.owner_id); - tcx.sess.emit_err(UnknownExternLangItem { span, lang_item }); - } + for &item in &tcx.resolutions(()).missing_lang_items { + if items.get(item).is_none() { + items.missing.push(item); } } diff --git a/compiler/rustc_resolve/Cargo.toml b/compiler/rustc_resolve/Cargo.toml index d66db1d7a0dd5..f1418536387de 100644 --- a/compiler/rustc_resolve/Cargo.toml +++ b/compiler/rustc_resolve/Cargo.toml @@ -10,6 +10,7 @@ bitflags = "1.2.1" tracing = "0.1" rustc_ast = { path = "../rustc_ast" } rustc_arena = { path = "../rustc_arena" } +rustc_macros = { path = "../rustc_macros" } rustc_middle = { path = "../rustc_middle" } rustc_ast_pretty = { path = "../rustc_ast_pretty" } rustc_attr = { path = "../rustc_attr" } diff --git a/compiler/rustc_resolve/src/errors.rs b/compiler/rustc_resolve/src/errors.rs new file mode 100644 index 0000000000000..c58316c5261de --- /dev/null +++ b/compiler/rustc_resolve/src/errors.rs @@ -0,0 +1,45 @@ +use rustc_hir::Target; +use rustc_macros::Diagnostic; +use rustc_span::{Span, Symbol}; + +#[derive(Diagnostic)] +#[diag(resolve_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(resolve_incorrect_target, code = "E0718")] +pub struct IncorrectTarget<'a> { + #[primary_span] + pub span: Span, + #[label] + pub generics_span: Span, + pub name: &'a str, + pub kind: &'static str, + pub num: usize, + pub actual_num: usize, + pub at_least: bool, +} + +#[derive(Diagnostic)] +#[diag(resolve_unknown_external_lang_item, code = "E0264")] +pub struct UnknownExternLangItem { + #[primary_span] + pub span: Span, + pub lang_item: Symbol, +} + +#[derive(Diagnostic)] +#[diag(resolve_unknown_lang_item, code = "E0522")] +pub struct UnknownLangItem { + #[primary_span] + #[label] + pub span: Span, + pub name: Symbol, +} diff --git a/compiler/rustc_resolve/src/lang_items.rs b/compiler/rustc_resolve/src/lang_items.rs new file mode 100644 index 0000000000000..63c159f0b5bd7 --- /dev/null +++ b/compiler/rustc_resolve/src/lang_items.rs @@ -0,0 +1,126 @@ +use crate::errors::{ + IncorrectTarget, LangItemOnIncorrectTarget, UnknownExternLangItem, UnknownLangItem, +}; +use crate::Resolver; + +use rustc_ast::visit; +use rustc_ast::visit::{AssocCtxt, Visitor}; +use rustc_ast::*; +use rustc_hir::def_id::LocalDefId; +use rustc_hir::lang_items::{extract, GenericRequirement}; +use rustc_hir::{LangItem, Target}; + +impl<'a> Resolver<'a> { + pub(crate) fn resolve_lang_items(&mut self, krate: &Crate) { + let mut collector = + LanguageItemCollector { resolver: self, items: Vec::new(), missing: Vec::new() }; + visit::walk_crate(&mut collector, krate); + let LanguageItemCollector { items, missing, .. } = collector; + self.lang_items = items; + self.missing_lang_items = missing; + } +} +struct LanguageItemCollector<'a, 'b> { + resolver: &'b Resolver<'a>, + items: Vec<(LocalDefId, LangItem)>, + missing: Vec, +} + +impl<'ast> Visitor<'ast> for LanguageItemCollector<'_, '_> { + fn visit_item(&mut self, item: &'ast Item) { + self.check_for_lang( + Target::from_ast_item(item), + &item.attrs, + item.id, + item.kind.generics(), + item.kind.descr(), + ); + visit::walk_item(self, item); + } + + fn visit_assoc_item(&mut self, item: &'ast AssocItem, ctxt: AssocCtxt) { + let target = Target::from_ast_assoc_item(&item.kind, ctxt); + self.check_for_lang(target, &item.attrs, item.id, item.kind.generics(), target.name()); + visit::walk_assoc_item(self, item, ctxt); + } + + fn visit_variant(&mut self, variant: &'ast Variant) { + self.check_for_lang(Target::Variant, &variant.attrs, variant.id, None, "variant"); + visit::walk_variant(self, variant); + } + + fn visit_foreign_item(&mut self, item: &'ast ForeignItem) { + let Some((lang_item, _)) = extract(&item.attrs) else { return }; + if let Some(item) = LangItem::from_name(lang_item) && item.is_weak() { + self.missing.push(item); + } else { + self.resolver.session.emit_err(UnknownExternLangItem { span: item.span, lang_item }); + } + visit::walk_foreign_item(self, item); + } +} + +impl LanguageItemCollector<'_, '_> { + fn check_for_lang( + &mut self, + actual_target: Target, + attrs: &[Attribute], + id: NodeId, + generics: Option<&Generics>, + descr: &'static str, + ) { + let Some((name, span)) = extract(attrs) else { return }; + let Some(lang_item) = LangItem::from_name(name) else { + self.resolver.session.emit_err(UnknownLangItem { span, name }); + return; + }; + if actual_target != lang_item.target() { + self.resolver.session.emit_err(LangItemOnIncorrectTarget { + span, + name, + expected_target: lang_item.target(), + actual_target, + }); + return; + } + // Now check whether the lang_item has the expected number of generic + // arguments. Generally speaking, binary and indexing operations have + // one (for the RHS/index), unary operations have none, the closure + // traits have one for the argument list, generators have one for the + // resume argument, and ordering/equality relations have one for the RHS + // Some other types like Box and various functions like drop_in_place + // have minimum requirements. + if let Some(generics) = generics { + let actual_num = generics.params.len(); + let mut at_least = false; + let required = match lang_item.required_generics() { + GenericRequirement::Exact(num) if num != actual_num => Some(num), + GenericRequirement::Minimum(num) if actual_num < num => { + at_least = true; + Some(num)} + , + // If the number matches, or there is no requirement, handle it normally + _ => None, + }; + + 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. + self.resolver.session.emit_err(IncorrectTarget { + span, + generics_span: generics.span, + name: lang_item.name().as_str(), + kind: descr, + num, + actual_num, + at_least, + }); + return; + } + } + + let item_def_id = self.resolver.local_def_id(id); + self.items.push((item_def_id, lang_item)); + } +} diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 11b70a38da58d..3afbf196aa554 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -37,7 +37,7 @@ use rustc_hir::def::{self, CtorOf, DefKind, LifetimeRes, PartialRes}; use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId}; use rustc_hir::def_id::{CRATE_DEF_ID, LOCAL_CRATE}; use rustc_hir::definitions::{DefPathData, Definitions}; -use rustc_hir::TraitCandidate; +use rustc_hir::{LangItem, TraitCandidate}; use rustc_index::vec::IndexVec; use rustc_metadata::creader::{CStore, CrateLoader}; use rustc_middle::metadata::ModChild; @@ -73,8 +73,10 @@ mod check_unused; mod def_collector; mod diagnostics; mod effective_visibilities; +mod errors; mod ident; mod imports; +mod lang_items; mod late; mod macros; @@ -955,6 +957,8 @@ pub struct Resolver<'a> { /// the surface (`macro` items in libcore), but are actually attributes or derives. builtin_macro_kinds: FxHashMap, registered_tools: RegisteredTools, + lang_items: Vec<(LocalDefId, LangItem)>, + missing_lang_items: Vec, macro_use_prelude: FxHashMap>, macro_map: FxHashMap, dummy_ext_bang: Lrc, @@ -1295,6 +1299,8 @@ impl<'a> Resolver<'a> { builtin_macros: Default::default(), builtin_macro_kinds: Default::default(), registered_tools, + lang_items: Vec::new(), + missing_lang_items: Vec::new(), macro_use_prelude: FxHashMap::default(), macro_map: FxHashMap::default(), dummy_ext_bang: Lrc::new(SyntaxExtension::dummy_bang(session.edition())), @@ -1416,6 +1422,8 @@ impl<'a> Resolver<'a> { proc_macros, confused_type_with_std_module, registered_tools: self.registered_tools, + lang_items: self.lang_items, + missing_lang_items: self.missing_lang_items, }; let ast_lowering = ty::ResolverAstLowering { legacy_const_generic_args: self.legacy_const_generic_args, @@ -1458,6 +1466,8 @@ impl<'a> Resolver<'a> { proc_macros, confused_type_with_std_module: self.confused_type_with_std_module.clone(), registered_tools: self.registered_tools.clone(), + lang_items: self.lang_items.clone(), + missing_lang_items: self.missing_lang_items.clone(), effective_visibilities: self.effective_visibilities.clone(), }; let ast_lowering = ty::ResolverAstLowering { @@ -1527,6 +1537,7 @@ impl<'a> Resolver<'a> { self.session.time("finalize_macro_resolutions", || self.finalize_macro_resolutions()); self.session.time("late_resolve_crate", || self.late_resolve_crate(krate)); self.session.time("resolve_main", || self.resolve_main()); + self.session.time("resolve_lang_items", || self.resolve_lang_items(krate)); self.session.time("resolve_check_unused", || self.check_unused(krate)); self.session.time("resolve_report_errors", || self.report_errors(krate)); self.session.time("resolve_postprocess", || self.crate_loader.postprocess(krate)); diff --git a/src/test/ui/feature-gates/feature-gate-lang-items.stderr b/src/test/ui/feature-gates/feature-gate-lang-items.stderr index c2496863fea44..96994c75161fb 100644 --- a/src/test/ui/feature-gates/feature-gate-lang-items.stderr +++ b/src/test/ui/feature-gates/feature-gate-lang-items.stderr @@ -1,16 +1,16 @@ -error[E0658]: language items are subject to change +error[E0522]: definition of an unknown language item: `foo` --> $DIR/feature-gate-lang-items.rs:1:1 | LL | #[lang = "foo"] - | ^^^^^^^^^^^^^^^ - | - = help: add `#![feature(lang_items)]` to the crate attributes to enable + | ^^^^^^^^^^^^^^^ definition of unknown language item `foo` -error[E0522]: definition of an unknown language item: `foo` +error[E0658]: language items are subject to change --> $DIR/feature-gate-lang-items.rs:1:1 | LL | #[lang = "foo"] - | ^^^^^^^^^^^^^^^ definition of unknown language item `foo` + | ^^^^^^^^^^^^^^^ + | + = help: add `#![feature(lang_items)]` to the crate attributes to enable error: aborting due to 2 previous errors diff --git a/src/test/ui/lang-items/issue-83471.stderr b/src/test/ui/lang-items/issue-83471.stderr index b315df179d01c..75488c21f7db4 100644 --- a/src/test/ui/lang-items/issue-83471.stderr +++ b/src/test/ui/lang-items/issue-83471.stderr @@ -1,3 +1,12 @@ +error[E0718]: `fn` language item must be applied to a trait with 1 generic argument + --> $DIR/issue-83471.rs:11:1 + | +LL | #[lang = "fn"] + | ^^^^^^^^^^^^^^ +... +LL | trait Fn { + | - this trait has 0 generic arguments + error[E0573]: expected type, found built-in attribute `export_name` --> $DIR/issue-83471.rs:15:13 | @@ -30,15 +39,6 @@ LL | fn call(export_name); = note: for more information, see issue #41686 = note: `#[warn(anonymous_parameters)]` on by default -error[E0718]: `fn` language item must be applied to a trait with 1 generic argument - --> $DIR/issue-83471.rs:11:1 - | -LL | #[lang = "fn"] - | ^^^^^^^^^^^^^^ -... -LL | trait Fn { - | - this trait has 0 generic arguments - error[E0425]: cannot find function `a` in this scope --> $DIR/issue-83471.rs:21:5 | From 5438f581f66cfc046cb3d7563800b51bff881fa9 Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Wed, 26 Oct 2022 09:47:57 -0500 Subject: [PATCH 2/7] Use inner ctxt when lowering ExprKind::Paren --- compiler/rustc_ast_lowering/src/expr.rs | 3 ++- src/test/ui/iterators/collect-into-array.stderr | 8 ++++---- src/test/ui/iterators/collect-into-slice.stderr | 8 ++++---- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index ec9c393502056..c82a720b32209 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -272,8 +272,9 @@ impl<'hir> LoweringContext<'_, 'hir> { ExprKind::Paren(ref ex) => { let mut ex = self.lower_expr_mut(ex); // Include parens in span, but only if it is a super-span. + // Use the inner ctxt to maintain desugaring marker for `(a..b)` if e.span.contains(ex.span) { - ex.span = self.lower_span(e.span); + ex.span = self.lower_span(e.span.with_ctxt(ex.span.ctxt())); } // Merge attributes into the inner expression. if !e.attrs.is_empty() { diff --git a/src/test/ui/iterators/collect-into-array.stderr b/src/test/ui/iterators/collect-into-array.stderr index 7fe9707e6d232..2ee100efd12ac 100644 --- a/src/test/ui/iterators/collect-into-array.stderr +++ b/src/test/ui/iterators/collect-into-array.stderr @@ -1,10 +1,10 @@ error[E0277]: an array of type `[u32; 10]` cannot be built directly from an iterator - --> $DIR/collect-into-array.rs:3:31 + --> $DIR/collect-into-array.rs:3:32 | LL | let whatever: [u32; 10] = (0..10).collect(); - | ^^^^^^^ ------- required by a bound introduced by this call - | | - | try collecting into a `Vec<{integer}>`, then using `.try_into()` + | ^^^^^ ------- required by a bound introduced by this call + | | + | try collecting into a `Vec<{integer}>`, then using `.try_into()` | = help: the trait `FromIterator<{integer}>` is not implemented for `[u32; 10]` note: required by a bound in `collect` diff --git a/src/test/ui/iterators/collect-into-slice.stderr b/src/test/ui/iterators/collect-into-slice.stderr index bce40118bdfa0..6e22e78ab4efc 100644 --- a/src/test/ui/iterators/collect-into-slice.stderr +++ b/src/test/ui/iterators/collect-into-slice.stderr @@ -22,12 +22,12 @@ LL | fn collect>(self) -> B | ^ required by this bound in `collect` error[E0277]: a slice of type `[i32]` cannot be built since `[i32]` has no definite size - --> $DIR/collect-into-slice.rs:8:30 + --> $DIR/collect-into-slice.rs:8:31 | LL | let some_generated_vec = (0..10).collect(); - | ^^^^^^^ ------- required by a bound introduced by this call - | | - | try explicitly collecting into a `Vec<{integer}>` + | ^^^^^ ------- required by a bound introduced by this call + | | + | try explicitly collecting into a `Vec<{integer}>` | = help: the trait `FromIterator<{integer}>` is not implemented for `[i32]` note: required by a bound in `collect` From 58b5e22fe91272c18340aa825764b25dafd77858 Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Sun, 9 Oct 2022 20:52:14 -0500 Subject: [PATCH 3/7] Factor out QPath::LangItem --- compiler/rustc_ast_lowering/src/expr.rs | 101 ++++++--------- compiler/rustc_ast_lowering/src/lib.rs | 32 ++++- compiler/rustc_hir/src/hir.rs | 35 +---- compiler/rustc_hir/src/intravisit.rs | 1 - compiler/rustc_hir/src/target.rs | 44 +++---- .../rustc_hir_analysis/src/astconv/mod.rs | 15 --- compiler/rustc_hir_pretty/src/lib.rs | 5 - compiler/rustc_hir_typeck/src/callee.rs | 11 +- compiler/rustc_hir_typeck/src/expr.rs | 73 ++++++++--- .../rustc_hir_typeck/src/fn_ctxt/_impl.rs | 58 ++------- .../rustc_hir_typeck/src/fn_ctxt/checks.rs | 4 - compiler/rustc_hir_typeck/src/lib.rs | 1 + .../rustc_hir_typeck/src/method/suggest.rs | 122 +++++++++--------- compiler/rustc_hir_typeck/src/pat.rs | 4 +- .../infer/error_reporting/need_type_info.rs | 1 - compiler/rustc_lint/src/array_into_iter.rs | 18 ++- compiler/rustc_lint/src/builtin.rs | 2 +- compiler/rustc_lint/src/context.rs | 2 +- compiler/rustc_middle/src/lint.rs | 5 +- compiler/rustc_middle/src/traits/mod.rs | 2 +- compiler/rustc_middle/src/ty/context.rs | 2 +- compiler/rustc_passes/src/liveness.rs | 6 +- compiler/rustc_privacy/src/lib.rs | 6 +- .../rustc_save_analysis/src/dump_visitor.rs | 1 - compiler/rustc_save_analysis/src/lib.rs | 13 +- compiler/rustc_save_analysis/src/sig.rs | 3 - compiler/rustc_span/src/hygiene.rs | 2 + compiler/rustc_span/src/lib.rs | 1 + .../src/traits/error_reporting/mod.rs | 2 + .../src/traits/error_reporting/suggestions.rs | 7 +- src/librustdoc/clean/mod.rs | 1 - src/librustdoc/clean/utils.rs | 3 - .../hashes/indexing_expressions.rs | 4 +- src/test/ui/error-codes/E0264.stderr | 2 +- 34 files changed, 260 insertions(+), 329 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index c82a720b32209..90318f35ef976 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -30,6 +30,7 @@ impl<'hir> LoweringContext<'_, 'hir> { pub(super) fn lower_expr_mut(&mut self, e: &Expr) -> hir::Expr<'hir> { ensure_sufficient_stack(|| { + let mut span = None; let kind = match e.kind { ExprKind::Box(ref inner) => hir::ExprKind::Box(self.lower_expr(inner)), ExprKind::Array(ref exprs) => hir::ExprKind::Array(self.lower_exprs(exprs)), @@ -210,10 +211,15 @@ impl<'hir> LoweringContext<'_, 'hir> { hir::ExprKind::Index(self.lower_expr(el), self.lower_expr(er)) } ExprKind::Range(Some(ref e1), Some(ref e2), RangeLimits::Closed) => { - self.lower_expr_range_closed(e.span, e1, e2) + let (kind, s) = self.lower_expr_range_closed(e.span, e1, e2); + span = Some(s); + kind } ExprKind::Range(ref e1, ref e2, lims) => { - self.lower_expr_range(e.span, e1.as_deref(), e2.as_deref(), lims) + let (kind, s) = + self.lower_expr_range(e.span, e1.as_deref(), e2.as_deref(), lims); + span = Some(s); + kind } ExprKind::Underscore => { self.tcx.sess.emit_err(UnderscoreExprLhsAssign { span: e.span }); @@ -303,7 +309,8 @@ impl<'hir> LoweringContext<'_, 'hir> { let hir_id = self.lower_node_id(e.id); self.lower_attrs(hir_id, &e.attrs); - hir::Expr { hir_id, kind, span: self.lower_span(e.span) } + let span = span.unwrap_or_else(|| self.lower_span(e.span)); + hir::Expr { hir_id, kind, span } }) } @@ -529,12 +536,7 @@ impl<'hir> LoweringContext<'_, 'hir> { expr: &'hir hir::Expr<'hir>, overall_span: Span, ) -> &'hir hir::Expr<'hir> { - let constructor = self.arena.alloc(self.expr_lang_item_path( - method_span, - lang_item, - AttrVec::new(), - None, - )); + let constructor = self.expr_lang_item_path(method_span, lang_item); self.expr_call(overall_span, constructor, std::slice::from_ref(expr)) } @@ -652,15 +654,10 @@ impl<'hir> LoweringContext<'_, 'hir> { // `future::from_generator`: let unstable_span = self.mark_span_with_reason(DesugaringKind::Async, span, self.allow_gen_future.clone()); - let gen_future = self.expr_lang_item_path( - unstable_span, - hir::LangItem::FromGenerator, - AttrVec::new(), - None, - ); + let gen_future = self.expr_lang_item_path(unstable_span, hir::LangItem::FromGenerator); // `future::from_generator(generator)`: - hir::ExprKind::Call(self.arena.alloc(gen_future), arena_vec![self; generator]) + hir::ExprKind::Call(gen_future, arena_vec![self; generator]) } /// Desugar `.await` into: @@ -726,19 +723,16 @@ impl<'hir> LoweringContext<'_, 'hir> { span, hir::LangItem::PinNewUnchecked, arena_vec![self; ref_mut_awaitee], - Some(expr_hir_id), ); let get_context = self.expr_call_lang_item_fn_mut( gen_future_span, hir::LangItem::GetContext, arena_vec![self; task_context], - Some(expr_hir_id), ); let call = self.expr_call_lang_item_fn( span, hir::LangItem::FuturePoll, arena_vec![self; new_unchecked, get_context], - Some(expr_hir_id), ); self.arena.alloc(self.expr_unsafe(call)) }; @@ -751,12 +745,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let (x_pat, x_pat_hid) = self.pat_ident(gen_future_span, x_ident); let x_expr = self.expr_ident(gen_future_span, x_ident, x_pat_hid); let ready_field = self.single_pat_field(gen_future_span, x_pat); - let ready_pat = self.pat_lang_item_variant( - span, - hir::LangItem::PollReady, - ready_field, - Some(expr_hir_id), - ); + let ready_pat = self.pat_lang_item_variant(span, hir::LangItem::PollReady, ready_field); let break_x = self.with_loop_scope(loop_node_id, move |this| { let expr_break = hir::ExprKind::Break(this.lower_loop_destination(None), Some(x_expr)); @@ -767,12 +756,7 @@ impl<'hir> LoweringContext<'_, 'hir> { // `::std::task::Poll::Pending => {}` let pending_arm = { - let pending_pat = self.pat_lang_item_variant( - span, - hir::LangItem::PollPending, - &[], - Some(expr_hir_id), - ); + let pending_pat = self.pat_lang_item_variant(span, hir::LangItem::PollPending, &[]); let empty_block = self.expr_block_empty(span); self.arm(pending_pat, empty_block) }; @@ -839,7 +823,6 @@ impl<'hir> LoweringContext<'_, 'hir> { into_future_span, hir::LangItem::IntoFutureIntoFuture, arena_vec![self; expr], - Some(expr_hir_id), ); // match { @@ -1269,14 +1252,19 @@ impl<'hir> LoweringContext<'_, 'hir> { } /// Desugar `..=` into `std::ops::RangeInclusive::new(, )`. - fn lower_expr_range_closed(&mut self, span: Span, e1: &Expr, e2: &Expr) -> hir::ExprKind<'hir> { + fn lower_expr_range_closed( + &mut self, + span: Span, + e1: &Expr, + e2: &Expr, + ) -> (hir::ExprKind<'hir>, Span) { let e1 = self.lower_expr_mut(e1); let e2 = self.lower_expr_mut(e2); - let fn_path = - hir::QPath::LangItem(hir::LangItem::RangeInclusiveNew, self.lower_span(span), None); - let fn_expr = - self.arena.alloc(self.expr(span, hir::ExprKind::Path(fn_path), AttrVec::new())); - hir::ExprKind::Call(fn_expr, arena_vec![self; e1, e2]) + let span = + self.mark_span_with_reason(DesugaringKind::RangeLiteral, self.lower_span(span), None); + let fn_expr = self.expr_lang_item_path(span, hir::LangItem::RangeInclusiveNew); + let kind = hir::ExprKind::Call(fn_expr, arena_vec![self; e1, e2]); + (kind, span) } fn lower_expr_range( @@ -1285,7 +1273,7 @@ impl<'hir> LoweringContext<'_, 'hir> { e1: Option<&Expr>, e2: Option<&Expr>, lims: RangeLimits, - ) -> hir::ExprKind<'hir> { + ) -> (hir::ExprKind<'hir>, Span) { use rustc_ast::RangeLimits::*; let lang_item = match (e1, e2, lims) { @@ -1308,17 +1296,18 @@ impl<'hir> LoweringContext<'_, 'hir> { e1.iter().map(|e| (sym::start, e)).chain(e2.iter().map(|e| (sym::end, e))).map( |(s, e)| { let expr = self.lower_expr(&e); - let ident = Ident::new(s, self.lower_span(e.span)); + let ident_span = + self.mark_span_with_reason(DesugaringKind::RangeLiteral, expr.span, None); + let ident = Ident::new(s, ident_span); self.expr_field(ident, expr, e.span) }, ), ); - hir::ExprKind::Struct( - self.arena.alloc(hir::QPath::LangItem(lang_item, self.lower_span(span), None)), - fields, - None, - ) + let span = + self.mark_span_with_reason(DesugaringKind::RangeLiteral, self.lower_span(span), None); + let qpath = self.lang_item_qpath(lang_item, span); + (hir::ExprKind::Struct(self.arena.alloc(qpath), fields, None), span) } fn lower_label(&self, opt_label: Option