From 99c1bcfac500bc5bf1cc5992dca4f918540de556 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Rakic?= Date: Thu, 10 Aug 2023 20:35:48 +0000 Subject: [PATCH 01/13] Revert "make MCP510 behavior explicitly opt-in" This reverts commit 2b61a5e17a6bcb552889966f8f932aa680826ab6. --- compiler/rustc_codegen_ssa/src/back/link.rs | 19 ++----------------- 1 file changed, 2 insertions(+), 17 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index cd6201648ee9b..53c56ee782e5d 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -2991,25 +2991,10 @@ fn add_lld_args(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) { return; } - let self_contained_linker = sess.opts.cg.link_self_contained.linker(); - - // FIXME: some targets default to using `lld`, but users can only override the linker on the CLI - // and cannot yet select the precise linker flavor to opt out of that. See for example issue - // #113597 for the `thumbv6m-none-eabi` target: a driver is used, and its default linker - // conflicts with the target's flavor, causing unexpected arguments being passed. - // - // Until the new `LinkerFlavor`-like CLI options are stabilized, we only adopt MCP510's behavior - // if its dedicated unstable CLI flags are used, to keep the current sub-optimal stable - // behavior. - let using_mcp510 = - self_contained_linker || sess.opts.cg.linker_flavor.is_some_and(|f| f.is_unstable()); - if !using_mcp510 && !unstable_use_lld { - return; - } - // 1. Implement the "self-contained" part of this feature by adding rustc distribution // directories to the tool's search path. - if self_contained_linker || unstable_use_lld { + let self_contained_linker = sess.opts.cg.link_self_contained.linker() || unstable_use_lld; + if self_contained_linker { for path in sess.get_tools_search_paths(false) { cmd.arg({ let mut arg = OsString::from("-B"); From 498d6562c3fc4e9261efe2e8188fb45c64532eef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Rakic?= Date: Thu, 10 Aug 2023 20:36:25 +0000 Subject: [PATCH 02/13] infer no use of lld when using a generic linker driver --- compiler/rustc_target/src/spec/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 1871239d7de70..4aa6f1f98a2ca 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -338,7 +338,7 @@ impl LinkerFlavor { || stem == "clang++" || stem.ends_with("-clang++") { - (Some(Cc::Yes), None) + (Some(Cc::Yes), Some(Lld::No)) } else if stem == "wasm-ld" || stem.ends_with("-wasm-ld") || stem == "ld.lld" From 40de40e0941c3c7dde0cb5dd8e116d0051481543 Mon Sep 17 00:00:00 2001 From: Nilstrieb <48135649+Nilstrieb@users.noreply.github.com> Date: Wed, 26 Apr 2023 20:53:05 +0200 Subject: [PATCH 03/13] Add typed `{Local}DefId` for modules This allows for better type safety in the compiler and also improves the documentation for many things, making it clear that they expect modules. --- .../rustc_hir_analysis/src/check/check.rs | 2 +- .../rustc_middle/src/dep_graph/dep_node.rs | 52 +++++++++- compiler/rustc_privacy/src/lib.rs | 2 +- compiler/rustc_span/src/def_id.rs | 95 +++++++++++++++++++ 4 files changed, 148 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 8a5099804ed26..e453fadf4b2de 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -1448,7 +1448,7 @@ pub(super) fn check_mod_item_types(tcx: TyCtxt<'_>, module_def_id: LocalDefId) { for id in module.items() { check_item_type(tcx, id); } - if module_def_id == CRATE_DEF_ID { + if module_def_id == LocalModDefId::CRATE_DEF_ID { super::entry::check_for_entry_fn(tcx); } } diff --git a/compiler/rustc_middle/src/dep_graph/dep_node.rs b/compiler/rustc_middle/src/dep_graph/dep_node.rs index 06251bccc9856..04c09d334001b 100644 --- a/compiler/rustc_middle/src/dep_graph/dep_node.rs +++ b/compiler/rustc_middle/src/dep_graph/dep_node.rs @@ -60,7 +60,7 @@ use crate::mir::mono::MonoItem; use crate::ty::TyCtxt; use rustc_data_structures::fingerprint::Fingerprint; -use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE}; +use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LocalModDefId, ModDefId, LOCAL_CRATE}; use rustc_hir::definitions::DefPathHash; use rustc_hir::{HirId, ItemLocalId, OwnerId}; use rustc_query_system::dep_graph::FingerprintStyle; @@ -387,3 +387,53 @@ impl<'tcx> DepNodeParams> for HirId { } } } + +macro_rules! impl_for_typed_def_id { + ($Name:ident, $LocalName:ident) => { + impl<'tcx> DepNodeParams> for $Name { + #[inline(always)] + fn fingerprint_style() -> FingerprintStyle { + FingerprintStyle::DefPathHash + } + + #[inline(always)] + fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint { + self.to_def_id().to_fingerprint(tcx) + } + + #[inline(always)] + fn to_debug_str(&self, tcx: TyCtxt<'tcx>) -> String { + self.to_def_id().to_debug_str(tcx) + } + + #[inline(always)] + fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option { + DefId::recover(tcx, dep_node).map($Name::new_unchecked) + } + } + + impl<'tcx> DepNodeParams> for $LocalName { + #[inline(always)] + fn fingerprint_style() -> FingerprintStyle { + FingerprintStyle::DefPathHash + } + + #[inline(always)] + fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint { + self.to_def_id().to_fingerprint(tcx) + } + + #[inline(always)] + fn to_debug_str(&self, tcx: TyCtxt<'tcx>) -> String { + self.to_def_id().to_debug_str(tcx) + } + + #[inline(always)] + fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option { + LocalDefId::recover(tcx, dep_node).map($LocalName::new_unchecked) + } + } + }; +} + +impl_for_typed_def_id! { ModDefId, LocalModDefId } diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 30a4235d37145..bf40b43b3bc88 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -519,7 +519,7 @@ impl<'tcx> EmbargoVisitor<'tcx> { loop { let changed_reachability = self.update_macro_reachable(module_def_id, macro_module_def_id, macro_ev); - if changed_reachability || module_def_id == CRATE_DEF_ID { + if changed_reachability || module_def_id == LocalModDefId::CRATE_DEF_ID { break; } module_def_id = self.tcx.local_parent(module_def_id); diff --git a/compiler/rustc_span/src/def_id.rs b/compiler/rustc_span/src/def_id.rs index f65a6aa4fb21a..c03487fd3cade 100644 --- a/compiler/rustc_span/src/def_id.rs +++ b/compiler/rustc_span/src/def_id.rs @@ -28,10 +28,16 @@ impl CrateNum { CrateNum::from_usize(x) } + // FIXME(Nilstrieb): Replace this with `as_mod_def_id`. #[inline] pub fn as_def_id(self) -> DefId { DefId { krate: self, index: CRATE_DEF_INDEX } } + + #[inline] + pub fn as_mod_def_id(self) -> ModDefId { + ModDefId::new_unchecked(DefId { krate: self, index: CRATE_DEF_INDEX }) + } } impl fmt::Display for CrateNum { @@ -485,3 +491,92 @@ impl ToStableHashKey for CrateNum { self.as_def_id().to_stable_hash_key(hcx) } } + +macro_rules! typed_def_id { + ($Name:ident, $LocalName:ident) => { + #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Encodable, Decodable, HashStable_Generic)] + pub struct $Name(DefId); + + impl $Name { + pub const fn new_unchecked(def_id: DefId) -> Self { + Self(def_id) + } + + pub fn to_def_id(self) -> DefId { + self.into() + } + + pub fn is_local(self) -> bool { + self.0.is_local() + } + + pub fn as_local(self) -> Option<$LocalName> { + self.0.as_local().map($LocalName::new_unchecked) + } + } + + impl From<$LocalName> for $Name { + fn from(local: $LocalName) -> Self { + Self(local.0.to_def_id()) + } + } + + impl From<$Name> for DefId { + fn from(typed: $Name) -> Self { + typed.0 + } + } + + #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Encodable, Decodable, HashStable_Generic)] + pub struct $LocalName(LocalDefId); + + impl !Ord for $LocalName {} + impl !PartialOrd for $LocalName {} + + impl $LocalName { + pub const fn new_unchecked(def_id: LocalDefId) -> Self { + Self(def_id) + } + + pub fn to_def_id(self) -> DefId { + self.0.into() + } + + pub fn to_local_def_id(self) -> LocalDefId { + self.0 + } + } + + impl From<$LocalName> for LocalDefId { + fn from(typed: $LocalName) -> Self { + typed.0 + } + } + + impl From<$LocalName> for DefId { + fn from(typed: $LocalName) -> Self { + typed.0.into() + } + } + }; +} + +// N.B.: when adding new typed `DefId`s update the corresponding trait impls in +// `rustc_middle::dep_graph::def_node` for `DepNodeParams`. +typed_def_id! { ModDefId, LocalModDefId } + +impl LocalModDefId { + pub const CRATE_DEF_ID: Self = Self::new_unchecked(CRATE_DEF_ID); +} + +impl ModDefId { + pub fn is_top_level_module(self) -> bool { + self.0.is_top_level_module() + } +} + +impl LocalModDefId { + pub fn is_top_level_module(self) -> bool { + self.0.is_top_level_module() + } +} From c75fc573aac1312ecd53096662f093b630d504f3 Mon Sep 17 00:00:00 2001 From: Nilstrieb <48135649+Nilstrieb@users.noreply.github.com> Date: Wed, 26 Apr 2023 20:53:51 +0200 Subject: [PATCH 04/13] Use `{Local}ModDefId` in many queries --- .../rustc_hir_analysis/src/check/check.rs | 4 +- .../rustc_hir_analysis/src/check/wfcheck.rs | 4 +- compiler/rustc_hir_analysis/src/collect.rs | 4 +- .../rustc_hir_analysis/src/impl_wf_check.rs | 4 +- compiler/rustc_lint/src/late.rs | 6 +- compiler/rustc_lint/src/lib.rs | 4 +- compiler/rustc_middle/src/hir/map/mod.rs | 28 ++++----- compiler/rustc_middle/src/hir/mod.rs | 10 ++-- compiler/rustc_middle/src/query/erase.rs | 1 + compiler/rustc_middle/src/query/keys.rs | 37 +++++++++++- compiler/rustc_middle/src/query/mod.rs | 30 +++++----- compiler/rustc_middle/src/query/plumbing.rs | 22 +++++++ compiler/rustc_middle/src/ty/mod.rs | 4 +- compiler/rustc_middle/src/ty/print/mod.rs | 3 +- compiler/rustc_middle/src/ty/print/pretty.rs | 8 ++- compiler/rustc_passes/src/check_attr.rs | 6 +- compiler/rustc_passes/src/check_const.rs | 4 +- compiler/rustc_passes/src/dead.rs | 6 +- compiler/rustc_passes/src/loops.rs | 4 +- compiler/rustc_passes/src/naked_functions.rs | 4 +- compiler/rustc_passes/src/stability.rs | 4 +- compiler/rustc_privacy/src/lib.rs | 58 ++++++++++++------- compiler/rustc_span/src/def_id.rs | 2 +- src/librustdoc/clean/inline.rs | 6 +- src/librustdoc/clean/mod.rs | 4 +- src/tools/clippy/clippy_utils/src/lib.rs | 8 +-- 26 files changed, 177 insertions(+), 98 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index e453fadf4b2de..46e8cf81bc1f7 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -8,7 +8,7 @@ use rustc_attr as attr; use rustc_errors::{Applicability, ErrorGuaranteed, MultiSpan}; use rustc_hir as hir; use rustc_hir::def::{CtorKind, DefKind, Res}; -use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID}; +use rustc_hir::def_id::{DefId, LocalDefId, LocalModDefId}; use rustc_hir::intravisit::Visitor; use rustc_hir::{ItemKind, Node, PathSegment}; use rustc_infer::infer::opaque_types::ConstrainOpaqueTypeRegionVisitor; @@ -1443,7 +1443,7 @@ pub(super) fn check_type_params_are_used<'tcx>( } } -pub(super) fn check_mod_item_types(tcx: TyCtxt<'_>, module_def_id: LocalDefId) { +pub(super) fn check_mod_item_types(tcx: TyCtxt<'_>, module_def_id: LocalModDefId) { let module = tcx.hir_module_items(module_def_id); for id in module.items() { check_item_type(tcx, id); diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 16d4d099c7e5e..f5beefc47f374 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -5,7 +5,7 @@ use rustc_ast as ast; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet}; use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed}; use rustc_hir as hir; -use rustc_hir::def_id::{DefId, LocalDefId}; +use rustc_hir::def_id::{DefId, LocalDefId, LocalModDefId}; use rustc_hir::lang_items::LangItem; use rustc_hir::ItemKind; use rustc_infer::infer::outlives::env::{OutlivesEnvironment, RegionBoundPairs}; @@ -1854,7 +1854,7 @@ impl<'tcx> WfCheckingCtxt<'_, 'tcx> { } } -fn check_mod_type_wf(tcx: TyCtxt<'_>, module: LocalDefId) { +fn check_mod_type_wf(tcx: TyCtxt<'_>, module: LocalModDefId) { let items = tcx.hir_module_items(module); items.par_items(|item| tcx.ensure().check_well_formed(item.owner_id)); items.par_impl_items(|item| tcx.ensure().check_well_formed(item.owner_id)); diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 02a5d28b1e233..7b9f61d7ab213 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -22,7 +22,7 @@ use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::{Applicability, DiagnosticBuilder, ErrorGuaranteed, StashKey}; use rustc_hir as hir; -use rustc_hir::def_id::{DefId, LocalDefId}; +use rustc_hir::def_id::{DefId, LocalDefId, LocalModDefId}; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{GenericParamKind, Node}; use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; @@ -48,7 +48,7 @@ mod type_of; /////////////////////////////////////////////////////////////////////////// // Main entry point -fn collect_mod_item_types(tcx: TyCtxt<'_>, module_def_id: LocalDefId) { +fn collect_mod_item_types(tcx: TyCtxt<'_>, module_def_id: LocalModDefId) { tcx.hir().visit_item_likes_in_module(module_def_id, &mut CollectItemTypesVisitor { tcx }); } diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check.rs b/compiler/rustc_hir_analysis/src/impl_wf_check.rs index 4f705eaf10aac..788121f7a304f 100644 --- a/compiler/rustc_hir_analysis/src/impl_wf_check.rs +++ b/compiler/rustc_hir_analysis/src/impl_wf_check.rs @@ -14,7 +14,7 @@ use min_specialization::check_min_specialization; use rustc_data_structures::fx::FxHashSet; use rustc_errors::struct_span_err; use rustc_hir::def::DefKind; -use rustc_hir::def_id::LocalDefId; +use rustc_hir::def_id::{LocalDefId, LocalModDefId}; use rustc_middle::query::Providers; use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt}; use rustc_span::{Span, Symbol}; @@ -51,7 +51,7 @@ mod min_specialization; /// impl<'a> Trait for Bar { type X = &'a i32; } /// // ^ 'a is unused and appears in assoc type, error /// ``` -fn check_mod_impl_wf(tcx: TyCtxt<'_>, module_def_id: LocalDefId) { +fn check_mod_impl_wf(tcx: TyCtxt<'_>, module_def_id: LocalModDefId) { let min_specialization = tcx.features().min_specialization; let module = tcx.hir_module_items(module_def_id); for id in module.items() { diff --git a/compiler/rustc_lint/src/late.rs b/compiler/rustc_lint/src/late.rs index 3331dbad4a90e..73af51d9e9061 100644 --- a/compiler/rustc_lint/src/late.rs +++ b/compiler/rustc_lint/src/late.rs @@ -19,7 +19,7 @@ use rustc_ast as ast; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_data_structures::sync::join; use rustc_hir as hir; -use rustc_hir::def_id::LocalDefId; +use rustc_hir::def_id::{LocalDefId, LocalModDefId}; use rustc_hir::intravisit as hir_visit; use rustc_hir::intravisit::Visitor; use rustc_middle::hir::nested_filter; @@ -338,7 +338,7 @@ crate::late_lint_methods!(impl_late_lint_pass, []); pub fn late_lint_mod<'tcx, T: LateLintPass<'tcx> + 'tcx>( tcx: TyCtxt<'tcx>, - module_def_id: LocalDefId, + module_def_id: LocalModDefId, builtin_lints: T, ) { let context = LateContext { @@ -369,7 +369,7 @@ pub fn late_lint_mod<'tcx, T: LateLintPass<'tcx> + 'tcx>( fn late_lint_mod_inner<'tcx, T: LateLintPass<'tcx>>( tcx: TyCtxt<'tcx>, - module_def_id: LocalDefId, + module_def_id: LocalModDefId, context: LateContext<'tcx>, pass: T, ) { diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 42378951af36a..585b10e79e484 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -90,7 +90,7 @@ use rustc_ast as ast; use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage}; use rustc_fluent_macro::fluent_messages; use rustc_hir as hir; -use rustc_hir::def_id::LocalDefId; +use rustc_hir::def_id::{LocalDefId, LocalModDefId}; use rustc_middle::query::Providers; use rustc_middle::ty::TyCtxt; use rustc_session::lint::builtin::{ @@ -145,7 +145,7 @@ pub fn provide(providers: &mut Providers) { *providers = Providers { lint_mod, ..*providers }; } -fn lint_mod(tcx: TyCtxt<'_>, module_def_id: LocalDefId) { +fn lint_mod(tcx: TyCtxt<'_>, module_def_id: LocalModDefId) { late_lint_mod(tcx, module_def_id, BuiltinCombinedModuleLateLintPass::new()); } diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index 224f897492bbe..467962b39bb1b 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -8,7 +8,7 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::svh::Svh; use rustc_data_structures::sync::{par_for_each_in, DynSend, DynSync}; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID, LOCAL_CRATE}; +use rustc_hir::def_id::{DefId, LocalDefId, LocalModDefId, LOCAL_CRATE}; use rustc_hir::definitions::{DefKey, DefPath, DefPathData, DefPathHash}; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::*; @@ -148,7 +148,7 @@ impl<'hir> Map<'hir> { } #[inline] - pub fn module_items(self, module: LocalDefId) -> impl Iterator + 'hir { + pub fn module_items(self, module: LocalModDefId) -> impl Iterator + 'hir { self.tcx.hir_module_items(module).items() } @@ -169,8 +169,8 @@ impl<'hir> Map<'hir> { } #[inline] - pub fn local_def_id_to_hir_id(self, def_id: LocalDefId) -> HirId { - self.tcx.local_def_id_to_hir_id(def_id) + pub fn local_def_id_to_hir_id(self, def_id: impl Into) -> HirId { + self.tcx.local_def_id_to_hir_id(def_id.into()) } /// Do not call this function directly. The query should be called. @@ -529,8 +529,8 @@ impl<'hir> Map<'hir> { self.krate_attrs().iter().any(|attr| attr.has_name(sym::rustc_coherence_is_core)) } - pub fn get_module(self, module: LocalDefId) -> (&'hir Mod<'hir>, Span, HirId) { - let hir_id = HirId::make_owner(module); + pub fn get_module(self, module: LocalModDefId) -> (&'hir Mod<'hir>, Span, HirId) { + let hir_id = HirId::make_owner(module.to_local_def_id()); match self.tcx.hir_owner(hir_id.owner).map(|o| o.node) { Some(OwnerNode::Item(&Item { span, kind: ItemKind::Mod(ref m), .. })) => { (m, span, hir_id) @@ -542,7 +542,7 @@ impl<'hir> Map<'hir> { /// Walks the contents of the local crate. See also `visit_all_item_likes_in_crate`. pub fn walk_toplevel_module(self, visitor: &mut impl Visitor<'hir>) { - let (top_mod, span, hir_id) = self.get_module(CRATE_DEF_ID); + let (top_mod, span, hir_id) = self.get_module(LocalModDefId::CRATE_DEF_ID); visitor.visit_mod(top_mod, span, hir_id); } @@ -595,7 +595,7 @@ impl<'hir> Map<'hir> { /// This method is the equivalent of `visit_all_item_likes_in_crate` but restricted to /// item-likes in a single module. - pub fn visit_item_likes_in_module(self, module: LocalDefId, visitor: &mut V) + pub fn visit_item_likes_in_module(self, module: LocalModDefId, visitor: &mut V) where V: Visitor<'hir>, { @@ -618,17 +618,19 @@ impl<'hir> Map<'hir> { } } - pub fn for_each_module(self, mut f: impl FnMut(LocalDefId)) { + pub fn for_each_module(self, mut f: impl FnMut(LocalModDefId)) { let crate_items = self.tcx.hir_crate_items(()); for module in crate_items.submodules.iter() { - f(module.def_id) + f(LocalModDefId::new_unchecked(module.def_id)) } } #[inline] - pub fn par_for_each_module(self, f: impl Fn(LocalDefId) + DynSend + DynSync) { + pub fn par_for_each_module(self, f: impl Fn(LocalModDefId) + DynSend + DynSync) { let crate_items = self.tcx.hir_crate_items(()); - par_for_each_in(&crate_items.submodules[..], |module| f(module.def_id)) + par_for_each_in(&crate_items.submodules[..], |module| { + f(LocalModDefId::new_unchecked(module.def_id)) + }) } /// Returns an iterator for the nodes in the ancestor tree of the `current_id` @@ -1324,7 +1326,7 @@ fn hir_id_to_string(map: Map<'_>, id: HirId) -> String { } } -pub(super) fn hir_module_items(tcx: TyCtxt<'_>, module_id: LocalDefId) -> ModuleItems { +pub(super) fn hir_module_items(tcx: TyCtxt<'_>, module_id: LocalModDefId) -> ModuleItems { let mut collector = ItemCollector::new(tcx, false); let (hir_mod, span, hir_id) = tcx.hir().get_module(module_id); diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs index 06b25556c82a4..e8fd469e1fb8f 100644 --- a/compiler/rustc_middle/src/hir/mod.rs +++ b/compiler/rustc_middle/src/hir/mod.rs @@ -11,7 +11,7 @@ use crate::ty::{EarlyBinder, ImplSubject, TyCtxt}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::sync::{par_for_each_in, DynSend, DynSync}; use rustc_hir::def::DefKind; -use rustc_hir::def_id::{DefId, LocalDefId}; +use rustc_hir::def_id::{DefId, LocalDefId, LocalModDefId}; use rustc_hir::*; use rustc_query_system::ich::StableHashingContext; use rustc_span::{ExpnId, DUMMY_SP}; @@ -101,22 +101,22 @@ impl<'tcx> TyCtxt<'tcx> { map::Map { tcx: self } } - pub fn parent_module(self, id: HirId) -> LocalDefId { + pub fn parent_module(self, id: HirId) -> LocalModDefId { if !id.is_owner() && self.def_kind(id.owner) == DefKind::Mod { - id.owner.def_id + LocalModDefId::new_unchecked(id.owner.def_id) } else { self.parent_module_from_def_id(id.owner.def_id) } } - pub fn parent_module_from_def_id(self, mut id: LocalDefId) -> LocalDefId { + pub fn parent_module_from_def_id(self, mut id: LocalDefId) -> LocalModDefId { while let Some(parent) = self.opt_local_parent(id) { id = parent; if self.def_kind(id) == DefKind::Mod { break; } } - id + LocalModDefId::new_unchecked(id) } pub fn impl_subject(self, def_id: DefId) -> EarlyBinder> { diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs index 2c481745d987a..348f79ed6a800 100644 --- a/compiler/rustc_middle/src/query/erase.rs +++ b/compiler/rustc_middle/src/query/erase.rs @@ -235,6 +235,7 @@ trivial! { rustc_hir::def_id::DefId, rustc_hir::def_id::DefIndex, rustc_hir::def_id::LocalDefId, + rustc_hir::def_id::LocalModDefId, rustc_hir::def::DefKind, rustc_hir::Defaultness, rustc_hir::definitions::DefKey, diff --git a/compiler/rustc_middle/src/query/keys.rs b/compiler/rustc_middle/src/query/keys.rs index a8aec3096d5de..01bdc4c9904e5 100644 --- a/compiler/rustc_middle/src/query/keys.rs +++ b/compiler/rustc_middle/src/query/keys.rs @@ -8,7 +8,7 @@ use crate::ty::fast_reject::SimplifiedType; use crate::ty::layout::{TyAndLayout, ValidityRequirement}; use crate::ty::{self, Ty, TyCtxt}; use crate::ty::{GenericArg, GenericArgsRef}; -use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE}; +use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LocalModDefId, ModDefId, LOCAL_CRATE}; use rustc_hir::hir_id::{HirId, OwnerId}; use rustc_query_system::query::{DefaultCacheSelector, SingleCacheSelector, VecCacheSelector}; use rustc_span::symbol::{Ident, Symbol}; @@ -175,6 +175,41 @@ impl AsLocalKey for DefId { } } +impl Key for LocalModDefId { + type CacheSelector = DefaultCacheSelector; + + fn default_span(&self, tcx: TyCtxt<'_>) -> Span { + tcx.def_span(*self) + } + + #[inline(always)] + fn key_as_def_id(&self) -> Option { + Some(self.to_def_id()) + } +} + +impl Key for ModDefId { + type CacheSelector = DefaultCacheSelector; + + fn default_span(&self, tcx: TyCtxt<'_>) -> Span { + tcx.def_span(*self) + } + + #[inline(always)] + fn key_as_def_id(&self) -> Option { + Some(self.to_def_id()) + } +} + +impl AsLocalKey for ModDefId { + type LocalKey = LocalModDefId; + + #[inline(always)] + fn as_local_key(&self) -> Option { + self.as_local() + } +} + impl Key for SimplifiedType { type CacheSelector = DefaultCacheSelector; diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 52a18c99edb53..29b1c039de2ea 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -67,7 +67,7 @@ use rustc_errors::ErrorGuaranteed; use rustc_hir as hir; use rustc_hir::def::{DefKind, DocLinkResMap}; use rustc_hir::def_id::{ - CrateNum, DefId, DefIdMap, DefIdSet, LocalDefId, LocalDefIdMap, LocalDefIdSet, + CrateNum, DefId, DefIdMap, DefIdSet, LocalDefId, LocalDefIdMap, LocalDefIdSet, LocalModDefId, }; use rustc_hir::lang_items::{LangItem, LanguageItems}; use rustc_hir::{Crate, ItemLocalId, TraitCandidate}; @@ -167,7 +167,7 @@ rustc_queries! { /// /// This can be conveniently accessed by `tcx.hir().visit_item_likes_in_module`. /// Avoid calling this query directly. - query hir_module_items(key: LocalDefId) -> &'tcx rustc_middle::hir::ModuleItems { + query hir_module_items(key: LocalModDefId) -> &'tcx rustc_middle::hir::ModuleItems { arena_cache desc { |tcx| "getting HIR module items in `{}`", tcx.def_path_str(key) } cache_on_disk_if { true } @@ -896,7 +896,7 @@ rustc_queries! { } /// Performs lint checking for the module. - query lint_mod(key: LocalDefId) -> () { + query lint_mod(key: LocalModDefId) -> () { desc { |tcx| "linting {}", describe_as_module(key, tcx) } } @@ -905,35 +905,35 @@ rustc_queries! { } /// Checks the attributes in the module. - query check_mod_attrs(key: LocalDefId) -> () { + query check_mod_attrs(key: LocalModDefId) -> () { desc { |tcx| "checking attributes in {}", describe_as_module(key, tcx) } } /// Checks for uses of unstable APIs in the module. - query check_mod_unstable_api_usage(key: LocalDefId) -> () { + query check_mod_unstable_api_usage(key: LocalModDefId) -> () { desc { |tcx| "checking for unstable API usage in {}", describe_as_module(key, tcx) } } /// Checks the const bodies in the module for illegal operations (e.g. `if` or `loop`). - query check_mod_const_bodies(key: LocalDefId) -> () { + query check_mod_const_bodies(key: LocalModDefId) -> () { desc { |tcx| "checking consts in {}", describe_as_module(key, tcx) } } /// Checks the loops in the module. - query check_mod_loops(key: LocalDefId) -> () { + query check_mod_loops(key: LocalModDefId) -> () { desc { |tcx| "checking loops in {}", describe_as_module(key, tcx) } } - query check_mod_naked_functions(key: LocalDefId) -> () { + query check_mod_naked_functions(key: LocalModDefId) -> () { desc { |tcx| "checking naked functions in {}", describe_as_module(key, tcx) } } - query check_mod_item_types(key: LocalDefId) -> () { + query check_mod_item_types(key: LocalModDefId) -> () { desc { |tcx| "checking item types in {}", describe_as_module(key, tcx) } } - query check_mod_privacy(key: LocalDefId) -> () { - desc { |tcx| "checking privacy in {}", describe_as_module(key, tcx) } + query check_mod_privacy(key: LocalModDefId) -> () { + desc { |tcx| "checking privacy in {}", describe_as_module(key.to_local_def_id(), tcx) } } query check_liveness(key: LocalDefId) { @@ -952,19 +952,19 @@ rustc_queries! { desc { "finding live symbols in crate" } } - query check_mod_deathness(key: LocalDefId) -> () { + query check_mod_deathness(key: LocalModDefId) -> () { desc { |tcx| "checking deathness of variables in {}", describe_as_module(key, tcx) } } - query check_mod_impl_wf(key: LocalDefId) -> () { + query check_mod_impl_wf(key: LocalModDefId) -> () { desc { |tcx| "checking that impls are well-formed in {}", describe_as_module(key, tcx) } } - query check_mod_type_wf(key: LocalDefId) -> () { + query check_mod_type_wf(key: LocalModDefId) -> () { desc { |tcx| "checking that types are well-formed in {}", describe_as_module(key, tcx) } } - query collect_mod_item_types(key: LocalDefId) -> () { + query collect_mod_item_types(key: LocalModDefId) -> () { desc { |tcx| "collecting item types in {}", describe_as_module(key, tcx) } } diff --git a/compiler/rustc_middle/src/query/plumbing.rs b/compiler/rustc_middle/src/query/plumbing.rs index 97edfc2fca27d..a1aac2846210d 100644 --- a/compiler/rustc_middle/src/query/plumbing.rs +++ b/compiler/rustc_middle/src/query/plumbing.rs @@ -545,6 +545,7 @@ macro_rules! define_feedable { mod sealed { use super::{DefId, LocalDefId, OwnerId}; + use rustc_hir::def_id::{LocalModDefId, ModDefId}; /// An analogue of the `Into` trait that's intended only for query parameters. /// @@ -588,6 +589,27 @@ mod sealed { self.to_def_id() } } + + impl IntoQueryParam for ModDefId { + #[inline(always)] + fn into_query_param(self) -> DefId { + self.to_def_id() + } + } + + impl IntoQueryParam for LocalModDefId { + #[inline(always)] + fn into_query_param(self) -> DefId { + self.to_def_id() + } + } + + impl IntoQueryParam for LocalModDefId { + #[inline(always)] + fn into_query_param(self) -> LocalDefId { + self.into() + } + } } pub use sealed::IntoQueryParam; diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 48aa25dba6dc7..d8ac37c6ebd19 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -355,8 +355,8 @@ impl TyCtxt<'_> { #[inline] #[track_caller] - pub fn local_parent(self, id: LocalDefId) -> LocalDefId { - self.parent(id.to_def_id()).expect_local() + pub fn local_parent(self, id: impl Into) -> LocalDefId { + self.parent(id.into().to_def_id()).expect_local() } pub fn is_descendant_of(self, mut descendant: DefId, ancestor: DefId) -> bool { diff --git a/compiler/rustc_middle/src/ty/print/mod.rs b/compiler/rustc_middle/src/ty/print/mod.rs index 83a75d0c6b987..05871d0bc39d1 100644 --- a/compiler/rustc_middle/src/ty/print/mod.rs +++ b/compiler/rustc_middle/src/ty/print/mod.rs @@ -329,7 +329,8 @@ impl<'tcx, P: Printer<'tcx>> Print<'tcx, P> for ty::Const<'tcx> { } // This is only used by query descriptions -pub fn describe_as_module(def_id: LocalDefId, tcx: TyCtxt<'_>) -> String { +pub fn describe_as_module(def_id: impl Into, tcx: TyCtxt<'_>) -> String { + let def_id = def_id.into(); if def_id.is_top_level_module() { "top-level module".to_string() } else { diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index bb6513363c93f..ac0c88468faa5 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -11,7 +11,7 @@ use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; use rustc_data_structures::sso::SsoHashSet; use rustc_hir as hir; use rustc_hir::def::{self, CtorKind, DefKind, Namespace}; -use rustc_hir::def_id::{DefId, DefIdSet, CRATE_DEF_ID, LOCAL_CRATE}; +use rustc_hir::def_id::{DefId, DefIdSet, ModDefId, CRATE_DEF_ID, LOCAL_CRATE}; use rustc_hir::definitions::{DefKey, DefPathData, DefPathDataName, DisambiguatedDefPathData}; use rustc_hir::LangItem; use rustc_session::config::TrimmedDefPaths; @@ -326,7 +326,8 @@ pub trait PrettyPrinter<'tcx>: { this .tcx() - .module_children(visible_parent) + // FIXME(typed_def_id): Further propagate ModDefId + .module_children(ModDefId::new_unchecked(*visible_parent)) .iter() .filter(|child| child.res.opt_def_id() == Some(def_id)) .find(|child| child.vis.is_public() && child.ident.name != kw::Underscore) @@ -551,7 +552,8 @@ pub trait PrettyPrinter<'tcx>: // that's public and whose identifier isn't `_`. let reexport = self .tcx() - .module_children(visible_parent) + // FIXME(typed_def_id): Further propagate ModDefId + .module_children(ModDefId::new_unchecked(visible_parent)) .iter() .filter(|child| child.res.opt_def_id() == Some(def_id)) .find(|child| child.vis.is_public() && child.ident.name != kw::Underscore) diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 4f9b362e23796..197b335bdec9b 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -10,7 +10,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_errors::{Applicability, IntoDiagnosticArg, MultiSpan}; use rustc_feature::{AttributeDuplicates, AttributeType, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP}; use rustc_hir as hir; -use rustc_hir::def_id::LocalDefId; +use rustc_hir::def_id::LocalModDefId; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{ self, FnSig, ForeignItem, HirId, Item, ItemKind, TraitItem, CRATE_HIR_ID, CRATE_OWNER_ID, @@ -2465,10 +2465,10 @@ fn check_non_exported_macro_for_invalid_attrs(tcx: TyCtxt<'_>, item: &Item<'_>) } } -fn check_mod_attrs(tcx: TyCtxt<'_>, module_def_id: LocalDefId) { +fn check_mod_attrs(tcx: TyCtxt<'_>, module_def_id: LocalModDefId) { let check_attr_visitor = &mut CheckAttrVisitor { tcx, abort: Cell::new(false) }; tcx.hir().visit_item_likes_in_module(module_def_id, check_attr_visitor); - if module_def_id.is_top_level_module() { + if module_def_id.to_local_def_id().is_top_level_module() { check_attr_visitor.check_attributes(CRATE_HIR_ID, DUMMY_SP, Target::Mod, None); check_invalid_crate_level_attr(tcx, tcx.hir().krate_attrs()); } diff --git a/compiler/rustc_passes/src/check_const.rs b/compiler/rustc_passes/src/check_const.rs index e70817d7b7c55..495eb615ed889 100644 --- a/compiler/rustc_passes/src/check_const.rs +++ b/compiler/rustc_passes/src/check_const.rs @@ -9,7 +9,7 @@ use rustc_attr as attr; use rustc_hir as hir; -use rustc_hir::def_id::LocalDefId; +use rustc_hir::def_id::{LocalDefId, LocalModDefId}; use rustc_hir::intravisit::{self, Visitor}; use rustc_middle::hir::nested_filter; use rustc_middle::query::Providers; @@ -55,7 +55,7 @@ impl NonConstExpr { } } -fn check_mod_const_bodies(tcx: TyCtxt<'_>, module_def_id: LocalDefId) { +fn check_mod_const_bodies(tcx: TyCtxt<'_>, module_def_id: LocalModDefId) { let mut vis = CheckConstVisitor::new(tcx); tcx.hir().visit_item_likes_in_module(module_def_id, &mut vis); } diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index 2936c8fac7d91..d1c3bcf3839d5 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -8,7 +8,7 @@ use rustc_data_structures::unord::UnordSet; use rustc_errors::MultiSpan; use rustc_hir as hir; use rustc_hir::def::{CtorOf, DefKind, Res}; -use rustc_hir::def_id::{DefId, LocalDefId}; +use rustc_hir::def_id::{DefId, LocalDefId, LocalModDefId}; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{Node, PatKind, TyKind}; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; @@ -944,7 +944,7 @@ impl<'tcx> DeadVisitor<'tcx> { } } -fn check_mod_deathness(tcx: TyCtxt<'_>, module: LocalDefId) { +fn check_mod_deathness(tcx: TyCtxt<'_>, module: LocalModDefId) { let (live_symbols, ignored_derived_traits) = tcx.live_symbols_and_ignored_derived_traits(()); let mut visitor = DeadVisitor { tcx, live_symbols, ignored_derived_traits }; @@ -969,7 +969,7 @@ fn check_mod_deathness(tcx: TyCtxt<'_>, module: LocalDefId) { 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) { + if parent != module.to_local_def_id() && !live_symbols.contains(&parent) { // We already have diagnosed something. continue; } diff --git a/compiler/rustc_passes/src/loops.rs b/compiler/rustc_passes/src/loops.rs index 7c64df6a50ecf..0aaf85086e455 100644 --- a/compiler/rustc_passes/src/loops.rs +++ b/compiler/rustc_passes/src/loops.rs @@ -1,7 +1,7 @@ use Context::*; use rustc_hir as hir; -use rustc_hir::def_id::LocalDefId; +use rustc_hir::def_id::LocalModDefId; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{Destination, Movability, Node}; use rustc_middle::hir::map::Map; @@ -34,7 +34,7 @@ struct CheckLoopVisitor<'a, 'hir> { cx: Context, } -fn check_mod_loops(tcx: TyCtxt<'_>, module_def_id: LocalDefId) { +fn check_mod_loops(tcx: TyCtxt<'_>, module_def_id: LocalModDefId) { tcx.hir().visit_item_likes_in_module( module_def_id, &mut CheckLoopVisitor { sess: &tcx.sess, hir_map: tcx.hir(), cx: Normal }, diff --git a/compiler/rustc_passes/src/naked_functions.rs b/compiler/rustc_passes/src/naked_functions.rs index 769b389009b7e..7f36c59ad98d9 100644 --- a/compiler/rustc_passes/src/naked_functions.rs +++ b/compiler/rustc_passes/src/naked_functions.rs @@ -3,7 +3,7 @@ use rustc_ast::InlineAsmOptions; use rustc_hir as hir; use rustc_hir::def::DefKind; -use rustc_hir::def_id::LocalDefId; +use rustc_hir::def_id::{LocalDefId, LocalModDefId}; use rustc_hir::intravisit::Visitor; use rustc_hir::{ExprKind, InlineAsmOperand, StmtKind}; use rustc_middle::query::Providers; @@ -23,7 +23,7 @@ pub(crate) fn provide(providers: &mut Providers) { *providers = Providers { check_mod_naked_functions, ..*providers }; } -fn check_mod_naked_functions(tcx: TyCtxt<'_>, module_def_id: LocalDefId) { +fn check_mod_naked_functions(tcx: TyCtxt<'_>, module_def_id: LocalModDefId) { let items = tcx.hir_module_items(module_def_id); for def_id in items.definitions() { if !matches!(tcx.def_kind(def_id), DefKind::Fn | DefKind::AssocFn) { diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index 3950ac9dd31c9..2f07e91005d19 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -9,7 +9,7 @@ use rustc_attr::{ use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID}; +use rustc_hir::def_id::{LocalDefId, LocalModDefId, CRATE_DEF_ID}; use rustc_hir::hir_id::CRATE_HIR_ID; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{FieldDef, Item, ItemKind, TraitRef, Ty, TyKind, Variant}; @@ -682,7 +682,7 @@ fn stability_index(tcx: TyCtxt<'_>, (): ()) -> Index { /// Cross-references the feature names of unstable APIs with enabled /// features and possibly prints errors. -fn check_mod_unstable_api_usage(tcx: TyCtxt<'_>, module_def_id: LocalDefId) { +fn check_mod_unstable_api_usage(tcx: TyCtxt<'_>, module_def_id: LocalModDefId) { tcx.hir().visit_item_likes_in_module(module_def_id, &mut Checker { tcx }); } diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index bf40b43b3bc88..0eb344ba69065 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -20,7 +20,7 @@ use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage}; use rustc_fluent_macro::fluent_messages; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID}; +use rustc_hir::def_id::{DefId, LocalDefId, LocalModDefId, CRATE_DEF_ID}; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{AssocItemKind, ForeignItemKind, HirIdSet, ItemId, Node, PatKind}; use rustc_middle::bug; @@ -382,8 +382,9 @@ impl VisibilityLike for EffectiveVisibility { ) -> Self { let effective_vis = find.effective_visibilities.effective_vis(def_id).copied().unwrap_or_else(|| { - let private_vis = - ty::Visibility::Restricted(find.tcx.parent_module_from_def_id(def_id)); + let private_vis = ty::Visibility::Restricted( + find.tcx.parent_module_from_def_id(def_id).to_local_def_id(), + ); EffectiveVisibility::from_vis(private_vis) }); @@ -412,7 +413,7 @@ struct EmbargoVisitor<'tcx> { /// pub macro m() { /// n::p::f() /// } - macro_reachable: FxHashSet<(LocalDefId, LocalDefId)>, + macro_reachable: FxHashSet<(LocalModDefId, LocalModDefId)>, /// Preliminary pass for marking all underlying types of `impl Trait`s as reachable. impl_trait_pass: bool, /// Has something changed in the level map? @@ -449,7 +450,9 @@ impl<'tcx> EmbargoVisitor<'tcx> { max_vis: Option, level: Level, ) { - let private_vis = ty::Visibility::Restricted(self.tcx.parent_module_from_def_id(def_id)); + // FIXME(typed_def_id): Make `Visibility::Restricted` use a `LocalModDefId` by default. + let private_vis = + ty::Visibility::Restricted(self.tcx.parent_module_from_def_id(def_id).into()); if max_vis != Some(private_vis) { self.changed |= self.effective_visibilities.update( def_id, @@ -508,6 +511,8 @@ impl<'tcx> EmbargoVisitor<'tcx> { // The macro's parent doesn't correspond to a `mod`, return early (#63164, #65252). return; } + // FIXME(typed_def_id): Introduce checked constructors that check def_kind. + let macro_module_def_id = LocalModDefId::new_unchecked(macro_module_def_id); if self.effective_visibilities.public_at_level(local_def_id).is_none() { return; @@ -522,7 +527,7 @@ impl<'tcx> EmbargoVisitor<'tcx> { if changed_reachability || module_def_id == LocalModDefId::CRATE_DEF_ID { break; } - module_def_id = self.tcx.local_parent(module_def_id); + module_def_id = LocalModDefId::new_unchecked(self.tcx.local_parent(module_def_id)); } } @@ -530,8 +535,8 @@ impl<'tcx> EmbargoVisitor<'tcx> { /// module. Returns `true` if the level has changed. fn update_macro_reachable( &mut self, - module_def_id: LocalDefId, - defining_mod: LocalDefId, + module_def_id: LocalModDefId, + defining_mod: LocalModDefId, macro_ev: EffectiveVisibility, ) -> bool { if self.macro_reachable.insert((module_def_id, defining_mod)) { @@ -544,8 +549,8 @@ impl<'tcx> EmbargoVisitor<'tcx> { fn update_macro_reachable_mod( &mut self, - module_def_id: LocalDefId, - defining_mod: LocalDefId, + module_def_id: LocalModDefId, + defining_mod: LocalModDefId, macro_ev: EffectiveVisibility, ) { let module = self.tcx.hir().get_module(module_def_id).0; @@ -560,7 +565,7 @@ impl<'tcx> EmbargoVisitor<'tcx> { macro_ev, ); } - for child in self.tcx.module_children_local(module_def_id) { + for child in self.tcx.module_children_local(module_def_id.to_local_def_id()) { // FIXME: Use module children for the logic above too. if !child.reexport_chain.is_empty() && child.vis.is_accessible_from(defining_mod, self.tcx) @@ -577,7 +582,7 @@ impl<'tcx> EmbargoVisitor<'tcx> { def_id: LocalDefId, def_kind: DefKind, vis: ty::Visibility, - module: LocalDefId, + module: LocalModDefId, macro_ev: EffectiveVisibility, ) { self.update(def_id, macro_ev, Level::Reachable); @@ -608,7 +613,11 @@ impl<'tcx> EmbargoVisitor<'tcx> { // the module, however may be reachable. DefKind::Mod => { if vis.is_accessible_from(module, self.tcx) { - self.update_macro_reachable(def_id, module, macro_ev); + self.update_macro_reachable( + LocalModDefId::new_unchecked(def_id), + module, + macro_ev, + ); } } @@ -892,7 +901,7 @@ fn vis_to_string<'tcx>(def_id: LocalDefId, vis: ty::Visibility, tcx: TyCtxt<'tcx ty::Visibility::Restricted(restricted_id) => { if restricted_id.is_top_level_module() { "pub(crate)".to_string() - } else if restricted_id == tcx.parent_module_from_def_id(def_id) { + } else if restricted_id == tcx.parent_module_from_def_id(def_id).to_local_def_id() { "pub(self)".to_string() } else { format!("pub({})", tcx.item_name(restricted_id.to_def_id())) @@ -1800,7 +1809,7 @@ impl SearchInterfaceForPrivateItemsVisitor<'_> { let vis_descr = match vis { ty::Visibility::Public => "public", ty::Visibility::Restricted(vis_def_id) => { - if vis_def_id == self.tcx.parent_module(hir_id) { + if vis_def_id == self.tcx.parent_module(hir_id).to_local_def_id() { "private" } else if vis_def_id.is_top_level_module() { "crate-private" @@ -2196,7 +2205,7 @@ fn local_visibility(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Visibility { kind: hir::ItemKind::Use(_, hir::UseKind::ListStem) | hir::ItemKind::OpaqueTy(..), .. - }) => ty::Visibility::Restricted(tcx.parent_module(hir_id)), + }) => ty::Visibility::Restricted(tcx.parent_module(hir_id).to_local_def_id()), // Visibilities of trait impl items are inherited from their traits // and are not filled in resolve. Node::ImplItem(impl_item) => { @@ -2224,18 +2233,25 @@ fn local_visibility(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Visibility { } } -fn check_mod_privacy(tcx: TyCtxt<'_>, module_def_id: LocalDefId) { +fn check_mod_privacy(tcx: TyCtxt<'_>, module_def_id: LocalModDefId) { // Check privacy of names not checked in previous compilation stages. - let mut visitor = - NamePrivacyVisitor { tcx, maybe_typeck_results: None, current_item: module_def_id }; + let mut visitor = NamePrivacyVisitor { + tcx, + maybe_typeck_results: None, + current_item: module_def_id.to_local_def_id(), + }; let (module, span, hir_id) = tcx.hir().get_module(module_def_id); intravisit::walk_mod(&mut visitor, module, hir_id); // Check privacy of explicitly written types and traits as well as // inferred types of expressions and patterns. - let mut visitor = - TypePrivacyVisitor { tcx, maybe_typeck_results: None, current_item: module_def_id, span }; + let mut visitor = TypePrivacyVisitor { + tcx, + maybe_typeck_results: None, + current_item: module_def_id.to_local_def_id(), + span, + }; intravisit::walk_mod(&mut visitor, module, hir_id); } diff --git a/compiler/rustc_span/src/def_id.rs b/compiler/rustc_span/src/def_id.rs index c03487fd3cade..595babc26ae68 100644 --- a/compiler/rustc_span/src/def_id.rs +++ b/compiler/rustc_span/src/def_id.rs @@ -28,7 +28,7 @@ impl CrateNum { CrateNum::from_usize(x) } - // FIXME(Nilstrieb): Replace this with `as_mod_def_id`. + // FIXME(typed_def_id): Replace this with `as_mod_def_id`. #[inline] pub fn as_def_id(self) -> DefId { DefId { krate: self, index: CRATE_DEF_INDEX } diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 384010034e621..71f0e9dac55b1 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -9,7 +9,7 @@ use rustc_ast as ast; use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::def_id::{DefId, DefIdSet, LocalDefId}; +use rustc_hir::def_id::{DefId, DefIdSet, LocalModDefId}; use rustc_hir::Mutability; use rustc_metadata::creader::{CStore, LoadedMacro}; use rustc_middle::ty::fast_reject::SimplifiedType; @@ -138,7 +138,7 @@ pub(crate) fn try_inline( pub(crate) fn try_inline_glob( cx: &mut DocContext<'_>, res: Res, - current_mod: LocalDefId, + current_mod: LocalModDefId, visited: &mut DefIdSet, inlined_names: &mut FxHashSet<(ItemType, Symbol)>, import: &hir::Item<'_>, @@ -154,7 +154,7 @@ pub(crate) fn try_inline_glob( // reexported by the glob, e.g. because they are shadowed by something else. let reexports = cx .tcx - .module_children_local(current_mod) + .module_children_local(current_mod.to_local_def_id()) .iter() .filter(|child| !child.reexport_chain.is_empty()) .filter_map(|child| child.res.opt_def_id()) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index b6ba4c853d4cd..624f1620f2cb8 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1551,7 +1551,7 @@ fn first_non_private<'tcx>( } [parent, leaf] if parent.ident.name == kw::Super => { let parent_mod = cx.tcx.parent_module(hir_id); - if let Some(super_parent) = cx.tcx.opt_local_parent(parent_mod) { + if let Some(super_parent) = cx.tcx.opt_local_parent(parent_mod.to_local_def_id()) { (super_parent, leaf.ident) } else { // If we can't find the parent of the parent, then the parent is already the crate. @@ -2828,7 +2828,7 @@ fn clean_use_statement_inner<'tcx>( // The parent of the module in which this import resides. This // is the same as `current_mod` if that's already the top // level module. - let parent_mod = cx.tcx.parent_module_from_def_id(current_mod); + let parent_mod = cx.tcx.parent_module_from_def_id(current_mod.to_local_def_id()); // This checks if the import can be seen from a higher level module. // In other words, it checks if the visibility is the equivalent of diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index 171b7faf21960..b77a2f1d0cd05 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -83,7 +83,7 @@ use rustc_ast::Attribute; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::unhash::UnhashMap; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE}; +use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LocalModDefId, LOCAL_CRATE}; use rustc_hir::hir_id::{HirIdMap, HirIdSet}; use rustc_hir::intravisit::{walk_expr, FnKind, Visitor}; use rustc_hir::LangItem::{OptionNone, OptionSome, ResultErr, ResultOk}; @@ -2370,11 +2370,11 @@ pub fn is_hir_ty_cfg_dependant(cx: &LateContext<'_>, ty: &hir::Ty<'_>) -> bool { false } -static TEST_ITEM_NAMES_CACHE: OnceLock>>> = OnceLock::new(); +static TEST_ITEM_NAMES_CACHE: OnceLock>>> = OnceLock::new(); -fn with_test_item_names(tcx: TyCtxt<'_>, module: LocalDefId, f: impl Fn(&[Symbol]) -> bool) -> bool { +fn with_test_item_names(tcx: TyCtxt<'_>, module: LocalModDefId, f: impl Fn(&[Symbol]) -> bool) -> bool { let cache = TEST_ITEM_NAMES_CACHE.get_or_init(|| Mutex::new(FxHashMap::default())); - let mut map: MutexGuard<'_, FxHashMap>> = cache.lock().unwrap(); + let mut map: MutexGuard<'_, FxHashMap>> = cache.lock().unwrap(); let value = map.entry(module); match value { Entry::Occupied(entry) => f(entry.get()), From f887f5a9c6393d1f3eef98cdf13b4491e27b22e4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 14 Aug 2023 10:38:46 +0200 Subject: [PATCH 05/13] std: add some missing repr(transparent) --- library/core/src/ffi/c_str.rs | 3 +++ library/std/src/ffi/os_str.rs | 3 +++ library/std/src/path.rs | 6 ++++++ library/std/src/sys/wasi/fd.rs | 10 ++++++++-- library/std/src/sys_common/wtf8.rs | 2 ++ 5 files changed, 22 insertions(+), 2 deletions(-) diff --git a/library/core/src/ffi/c_str.rs b/library/core/src/ffi/c_str.rs index b59ec12790d24..aa34569023eb8 100644 --- a/library/core/src/ffi/c_str.rs +++ b/library/core/src/ffi/c_str.rs @@ -88,6 +88,9 @@ use crate::str; // When attribute privacy is implemented, `CStr` should be annotated as `#[repr(transparent)]`. // Anyway, `CStr` representation and layout are considered implementation detail, are // not documented and must not be relied upon. +// For now we just hide this from rustdoc, technically making our doc test builds rely on +// unspecified layout assumptions. We are std, so we can get away with that. +#[cfg_attr(not(doc), repr(transparent))] pub struct CStr { // FIXME: this should not be represented with a DST slice but rather with // just a raw `c_char` along with some form of marker to make diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs index 67e58fd1b8613..a9907ae10342d 100644 --- a/library/std/src/ffi/os_str.rs +++ b/library/std/src/ffi/os_str.rs @@ -116,6 +116,9 @@ impl crate::sealed::Sealed for OsString {} // When attribute privacy is implemented, `OsStr` should be annotated as `#[repr(transparent)]`. // Anyway, `OsStr` representation and layout are considered implementation details, are // not documented and must not be relied upon. +// For now we just hide this from rustdoc, technically making our doc test builds rely on +// unspecified layout assumptions. We are std, so we can get away with that. +#[cfg_attr(not(doc), repr(transparent))] pub struct OsStr { inner: Slice, } diff --git a/library/std/src/path.rs b/library/std/src/path.rs index 99f7a60f8ab01..ef5fc669037ab 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -1164,6 +1164,9 @@ impl FusedIterator for Ancestors<'_> {} // When attribute privacy is implemented, `PathBuf` should be annotated as `#[repr(transparent)]`. // Anyway, `PathBuf` representation and layout are considered implementation detail, are // not documented and must not be relied upon. +// For now we just hide this from rustdoc, technically making our doc test builds rely on +// unspecified layout assumptions. We are std, so we can get away with that. +#[cfg_attr(not(doc), repr(transparent))] pub struct PathBuf { inner: OsString, } @@ -1989,6 +1992,9 @@ impl AsRef for PathBuf { // When attribute privacy is implemented, `Path` should be annotated as `#[repr(transparent)]`. // Anyway, `Path` representation and layout are considered implementation detail, are // not documented and must not be relied upon. +// For now we just hide this from rustdoc, technically making our doc test builds rely on +// unspecified layout assumptions. We are std, so we can get away with that. +#[cfg_attr(not(doc), repr(transparent))] pub struct Path { inner: OsStr, } diff --git a/library/std/src/sys/wasi/fd.rs b/library/std/src/sys/wasi/fd.rs index 1b50c2ea6dd57..d7295a799daab 100644 --- a/library/std/src/sys/wasi/fd.rs +++ b/library/std/src/sys/wasi/fd.rs @@ -16,14 +16,20 @@ pub struct WasiFd { fn iovec<'a>(a: &'a mut [IoSliceMut<'_>]) -> &'a [wasi::Iovec] { assert_eq!(mem::size_of::>(), mem::size_of::()); assert_eq!(mem::align_of::>(), mem::align_of::()); - // SAFETY: `IoSliceMut` and `IoVec` have exactly the same memory layout + // SAFETY: `IoSliceMut` and `IoVec` have exactly the same memory layout. + // We decorate our `IoSliceMut` with `repr(transparent)` (see `io.rs`), and + // `crate::io::IoSliceMut` is a `repr(transparent)` wrapper around our type, so this is + // guaranteed. unsafe { mem::transmute(a) } } fn ciovec<'a>(a: &'a [IoSlice<'_>]) -> &'a [wasi::Ciovec] { assert_eq!(mem::size_of::>(), mem::size_of::()); assert_eq!(mem::align_of::>(), mem::align_of::()); - // SAFETY: `IoSlice` and `CIoVec` have exactly the same memory layout + // SAFETY: `IoSlice` and `CIoVec` have exactly the same memory layout. + // We decorate our `IoSlice` with `repr(transparent)` (see `io.rs`), and + // `crate::io::IoSlice` is a `repr(transparent)` wrapper around our type, so this is + // guaranteed. unsafe { mem::transmute(a) } } diff --git a/library/std/src/sys_common/wtf8.rs b/library/std/src/sys_common/wtf8.rs index 195d175cc9bde..67db5ebd89cfc 100644 --- a/library/std/src/sys_common/wtf8.rs +++ b/library/std/src/sys_common/wtf8.rs @@ -459,6 +459,7 @@ impl Wtf8Buf { /// Converts this `Wtf8Buf` into a boxed `Wtf8`. #[inline] pub fn into_box(self) -> Box { + // SAFETY: relies on `Wtf8` being `repr(transparent)`. unsafe { mem::transmute(self.bytes.into_boxed_slice()) } } @@ -511,6 +512,7 @@ impl Extend for Wtf8Buf { /// Similar to `&str`, but can additionally contain surrogate code points /// if they’re not in a surrogate pair. #[derive(Eq, Ord, PartialEq, PartialOrd)] +#[repr(transparent)] pub struct Wtf8 { bytes: [u8], } From 9dda6b5d35e6e8a1e405fa9b156dfaec67aef02d Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Mon, 14 Aug 2023 12:05:53 -0700 Subject: [PATCH 06/13] Add test for unknown_lints from another file. --- .../unknown-lints/allow-in-other-module.rs | 26 +++++++++++++++++++ tests/ui/lint/unknown-lints/other.rs | 10 +++++++ 2 files changed, 36 insertions(+) create mode 100644 tests/ui/lint/unknown-lints/allow-in-other-module.rs create mode 100644 tests/ui/lint/unknown-lints/other.rs diff --git a/tests/ui/lint/unknown-lints/allow-in-other-module.rs b/tests/ui/lint/unknown-lints/allow-in-other-module.rs new file mode 100644 index 0000000000000..20bf0d7af03cb --- /dev/null +++ b/tests/ui/lint/unknown-lints/allow-in-other-module.rs @@ -0,0 +1,26 @@ +// check-pass + +// Tests that the unknown_lints lint doesn't fire for an unknown lint loaded from a separate file. +// The key part is that the stderr output should be empty. +// Reported in https://github.com/rust-lang/rust/issues/84936 +// Fixed incidentally by https://github.com/rust-lang/rust/pull/97266 + +// This `allow` should apply to submodules, whether they are inline or loaded from a file. +#![allow(unknown_lints)] +#![allow(dead_code)] +// no warning +#![allow(not_a_real_lint)] + +mod other; + +// no warning +#[allow(not_a_real_lint)] +fn m() {} + +mod mm { + // no warning + #[allow(not_a_real_lint)] + fn m() {} +} + +fn main() {} diff --git a/tests/ui/lint/unknown-lints/other.rs b/tests/ui/lint/unknown-lints/other.rs new file mode 100644 index 0000000000000..a5111c00a3ecf --- /dev/null +++ b/tests/ui/lint/unknown-lints/other.rs @@ -0,0 +1,10 @@ +// ignore-test + +// Companion to allow-in-other-module.rs + +// This should not warn. +#![allow(not_a_real_lint)] + +// This should not warn, either. +#[allow(not_a_real_lint)] +fn m() {} From fe1a034f16adbed4302e4d27be96a7ec6fb27177 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 14 Aug 2023 22:55:29 +0200 Subject: [PATCH 07/13] actually this doesn't even affect doctests. nice. --- library/core/src/ffi/c_str.rs | 9 +++------ library/std/src/ffi/os_str.rs | 9 +++------ library/std/src/path.rs | 18 ++++++------------ 3 files changed, 12 insertions(+), 24 deletions(-) diff --git a/library/core/src/ffi/c_str.rs b/library/core/src/ffi/c_str.rs index aa34569023eb8..4082b208c1263 100644 --- a/library/core/src/ffi/c_str.rs +++ b/library/core/src/ffi/c_str.rs @@ -82,14 +82,11 @@ use crate::str; #[stable(feature = "core_c_str", since = "1.64.0")] #[rustc_has_incoherent_inherent_impls] #[lang = "CStr"] -// FIXME: // `fn from` in `impl From<&CStr> for Box` current implementation relies // on `CStr` being layout-compatible with `[u8]`. -// When attribute privacy is implemented, `CStr` should be annotated as `#[repr(transparent)]`. -// Anyway, `CStr` representation and layout are considered implementation detail, are -// not documented and must not be relied upon. -// For now we just hide this from rustdoc, technically making our doc test builds rely on -// unspecified layout assumptions. We are std, so we can get away with that. +// However, `CStr` layout is considered an implementation detail and must not be relied upon. We +// want `repr(transparent)` but we don't want it to show up in rustdoc, so we hide it under +// `cfg(doc)`. This is an ad-hoc implementation of attribute privacy. #[cfg_attr(not(doc), repr(transparent))] pub struct CStr { // FIXME: this should not be represented with a DST slice but rather with diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs index a9907ae10342d..43cecb19b148e 100644 --- a/library/std/src/ffi/os_str.rs +++ b/library/std/src/ffi/os_str.rs @@ -110,14 +110,11 @@ impl crate::sealed::Sealed for OsString {} /// [conversions]: super#conversions #[cfg_attr(not(test), rustc_diagnostic_item = "OsStr")] #[stable(feature = "rust1", since = "1.0.0")] -// FIXME: // `OsStr::from_inner` current implementation relies // on `OsStr` being layout-compatible with `Slice`. -// When attribute privacy is implemented, `OsStr` should be annotated as `#[repr(transparent)]`. -// Anyway, `OsStr` representation and layout are considered implementation details, are -// not documented and must not be relied upon. -// For now we just hide this from rustdoc, technically making our doc test builds rely on -// unspecified layout assumptions. We are std, so we can get away with that. +// However, `OsStr` layout is considered an implementation detail and must not be relied upon. We +// want `repr(transparent)` but we don't want it to show up in rustdoc, so we hide it under +// `cfg(doc)`. This is an ad-hoc implementation of attribute privacy. #[cfg_attr(not(doc), repr(transparent))] pub struct OsStr { inner: Slice, diff --git a/library/std/src/path.rs b/library/std/src/path.rs index ef5fc669037ab..5842c096f1ab7 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -1158,14 +1158,11 @@ impl FusedIterator for Ancestors<'_> {} /// Which method works best depends on what kind of situation you're in. #[cfg_attr(not(test), rustc_diagnostic_item = "PathBuf")] #[stable(feature = "rust1", since = "1.0.0")] -// FIXME: // `PathBuf::as_mut_vec` current implementation relies // on `PathBuf` being layout-compatible with `Vec`. -// When attribute privacy is implemented, `PathBuf` should be annotated as `#[repr(transparent)]`. -// Anyway, `PathBuf` representation and layout are considered implementation detail, are -// not documented and must not be relied upon. -// For now we just hide this from rustdoc, technically making our doc test builds rely on -// unspecified layout assumptions. We are std, so we can get away with that. +// However, `PathBuf` layout is considered an implementation detail and must not be relied upon. We +// want `repr(transparent)` but we don't want it to show up in rustdoc, so we hide it under +// `cfg(doc)`. This is an ad-hoc implementation of attribute privacy. #[cfg_attr(not(doc), repr(transparent))] pub struct PathBuf { inner: OsString, @@ -1986,14 +1983,11 @@ impl AsRef for PathBuf { /// ``` #[cfg_attr(not(test), rustc_diagnostic_item = "Path")] #[stable(feature = "rust1", since = "1.0.0")] -// FIXME: // `Path::new` current implementation relies // on `Path` being layout-compatible with `OsStr`. -// When attribute privacy is implemented, `Path` should be annotated as `#[repr(transparent)]`. -// Anyway, `Path` representation and layout are considered implementation detail, are -// not documented and must not be relied upon. -// For now we just hide this from rustdoc, technically making our doc test builds rely on -// unspecified layout assumptions. We are std, so we can get away with that. +// However, `Path` layout is considered an implementation detail and must not be relied upon. We +// want `repr(transparent)` but we don't want it to show up in rustdoc, so we hide it under +// `cfg(doc)`. This is an ad-hoc implementation of attribute privacy. #[cfg_attr(not(doc), repr(transparent))] pub struct Path { inner: OsStr, From 677afb4b4571cc32154f340c26908baa9e1a2540 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Mon, 14 Aug 2023 16:48:39 -0700 Subject: [PATCH 08/13] Add a regression test for #113238 --- tests/ui/std/slice-from-array-issue-113238.rs | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 tests/ui/std/slice-from-array-issue-113238.rs diff --git a/tests/ui/std/slice-from-array-issue-113238.rs b/tests/ui/std/slice-from-array-issue-113238.rs new file mode 100644 index 0000000000000..e9e1bfb8db308 --- /dev/null +++ b/tests/ui/std/slice-from-array-issue-113238.rs @@ -0,0 +1,9 @@ +// check-pass + +// This intends to use the unsizing coercion from array to slice, but it only +// works if we resolve `<&[u8]>::from` as the reflexive `From for T`. In +// #113238, we found that gimli had added its own `From for &[u8]` +// that affected all `std/backtrace` users. +fn main() { + let _ = <&[u8]>::from(&[]); +} From e8ab56fbb4be702e3f31afb257ace2498434c30b Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 15 Aug 2023 00:05:15 +0000 Subject: [PATCH 09/13] Only consider object candidates for object-safe dyn types --- compiler/rustc_trait_selection/src/solve/assembly/mod.rs | 5 +++++ .../manual-self-impl-for-unsafe-obj.rs | 2 ++ 2 files changed, 7 insertions(+) diff --git a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs index 3750b3750bff1..5bfa8348600ee 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs @@ -826,6 +826,11 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { ty::Dynamic(bounds, ..) => bounds, }; + // Do not consider built-in object impls for non-object-safe types. + if bounds.principal_def_id().is_some_and(|def_id| !tcx.check_is_object_safe(def_id)) { + return; + } + // Consider all of the auto-trait and projection bounds, which don't // need to be recorded as a `BuiltinImplSource::Object` since they don't // really have a vtable base... diff --git a/tests/ui/rfcs/rfc-2027-object-safe-for-dispatch/manual-self-impl-for-unsafe-obj.rs b/tests/ui/rfcs/rfc-2027-object-safe-for-dispatch/manual-self-impl-for-unsafe-obj.rs index 721890db4fbd7..c27e8c4b01972 100644 --- a/tests/ui/rfcs/rfc-2027-object-safe-for-dispatch/manual-self-impl-for-unsafe-obj.rs +++ b/tests/ui/rfcs/rfc-2027-object-safe-for-dispatch/manual-self-impl-for-unsafe-obj.rs @@ -1,5 +1,7 @@ // Check that we can manually implement an object-unsafe trait for its trait object. +// revisions: current next +//[next] compile-flags: -Ztrait-solver=next // run-pass #![feature(object_safe_for_dispatch)] From ab126c2a4e6b6835073949da4ab913d85989db09 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 15 Aug 2023 00:48:09 +0000 Subject: [PATCH 10/13] Probe when assembling upcast candidates so they don't step on eachother's toes --- .../src/solve/trait_goals.rs | 22 ++++++++++--------- ...rr => type-checking-test-1.current.stderr} | 4 ++-- .../type-checking-test-1.next.stderr | 9 ++++++++ .../trait-upcasting/type-checking-test-1.rs | 5 ++++- 4 files changed, 27 insertions(+), 13 deletions(-) rename tests/ui/traits/trait-upcasting/{type-checking-test-1.stderr => type-checking-test-1.current.stderr} (89%) create mode 100644 tests/ui/traits/trait-upcasting/type-checking-test-1.next.stderr diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs index ee6f1686b8238..8bab20e19421d 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs @@ -552,16 +552,18 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { self.walk_vtable( a_principal.with_self_ty(tcx, a_ty), |ecx, new_a_principal, _, vtable_vptr_slot| { - if let Ok(resp) = ecx.consider_builtin_upcast_to_principal( - goal, - a_data, - a_region, - b_data, - b_region, - Some(new_a_principal.map_bound(|trait_ref| { - ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref) - })), - ) { + if let Ok(resp) = ecx.probe_candidate("dyn upcast").enter(|ecx| { + ecx.consider_builtin_upcast_to_principal( + goal, + a_data, + a_region, + b_data, + b_region, + Some(new_a_principal.map_bound(|trait_ref| { + ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref) + })), + ) + }) { responses .push((resp, BuiltinImplSource::TraitUpcasting { vtable_vptr_slot })); } diff --git a/tests/ui/traits/trait-upcasting/type-checking-test-1.stderr b/tests/ui/traits/trait-upcasting/type-checking-test-1.current.stderr similarity index 89% rename from tests/ui/traits/trait-upcasting/type-checking-test-1.stderr rename to tests/ui/traits/trait-upcasting/type-checking-test-1.current.stderr index 82b4e9bd72aec..d48d9b89d1dac 100644 --- a/tests/ui/traits/trait-upcasting/type-checking-test-1.stderr +++ b/tests/ui/traits/trait-upcasting/type-checking-test-1.current.stderr @@ -1,5 +1,5 @@ error[E0605]: non-primitive cast: `&dyn Foo` as `&dyn Bar<_>` - --> $DIR/type-checking-test-1.rs:16:13 + --> $DIR/type-checking-test-1.rs:19:13 | LL | let _ = x as &dyn Bar<_>; // Ambiguous | ^^^^^^^^^^^^^^^^ invalid cast @@ -10,7 +10,7 @@ LL | let _ = &x as &dyn Bar<_>; // Ambiguous | + error[E0277]: the trait bound `&dyn Foo: Bar<_>` is not satisfied - --> $DIR/type-checking-test-1.rs:16:13 + --> $DIR/type-checking-test-1.rs:19:13 | LL | let _ = x as &dyn Bar<_>; // Ambiguous | ^ the trait `Bar<_>` is not implemented for `&dyn Foo` diff --git a/tests/ui/traits/trait-upcasting/type-checking-test-1.next.stderr b/tests/ui/traits/trait-upcasting/type-checking-test-1.next.stderr new file mode 100644 index 0000000000000..b612005fcb051 --- /dev/null +++ b/tests/ui/traits/trait-upcasting/type-checking-test-1.next.stderr @@ -0,0 +1,9 @@ +error[E0605]: non-primitive cast: `&dyn Foo` as `&dyn Bar<_>` + --> $DIR/type-checking-test-1.rs:19:13 + | +LL | let _ = x as &dyn Bar<_>; // Ambiguous + | ^^^^^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0605`. diff --git a/tests/ui/traits/trait-upcasting/type-checking-test-1.rs b/tests/ui/traits/trait-upcasting/type-checking-test-1.rs index 6bc9f4a75d333..7c7beec0809d7 100644 --- a/tests/ui/traits/trait-upcasting/type-checking-test-1.rs +++ b/tests/ui/traits/trait-upcasting/type-checking-test-1.rs @@ -1,3 +1,6 @@ +// revisions: current next +//[next] compile-flags: -Ztrait-solver=next + #![feature(trait_upcasting)] trait Foo: Bar + Bar {} @@ -15,7 +18,7 @@ fn test_specific(x: &dyn Foo) { fn test_unknown_version(x: &dyn Foo) { let _ = x as &dyn Bar<_>; // Ambiguous //~^ ERROR non-primitive cast - //~^^ ERROR the trait bound `&dyn Foo: Bar<_>` is not satisfied + //[current]~^^ ERROR the trait bound `&dyn Foo: Bar<_>` is not satisfied } fn test_infer_version(x: &dyn Foo) { From 7d8563c60277bc8ad07de76c7dc51c5eb4118bb7 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 14 Aug 2023 23:37:06 +0000 Subject: [PATCH 11/13] Separate consider_unsize_to_dyn_candidate from other unsize candidates --- .../src/solve/assembly/mod.rs | 43 +++++++-- .../src/solve/project_goals.rs | 9 +- .../src/solve/trait_goals.rs | 94 ++++++++++--------- tests/ui/unsized/issue-75899.rs | 2 + 4 files changed, 94 insertions(+), 54 deletions(-) diff --git a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs index 3750b3750bff1..44c50b086bd0f 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs @@ -281,23 +281,27 @@ pub(super) trait GoalKind<'tcx>: ) -> QueryResult<'tcx>; /// Consider (possibly several) candidates to upcast or unsize a type to another - /// type. - /// - /// The most common forms of unsizing are array to slice, and concrete (Sized) - /// type into a `dyn Trait`. ADTs and Tuples can also have their final field - /// unsized if it's generic. - /// - /// `dyn Trait1` can be unsized to `dyn Trait2` if they are the same trait, or - /// if `Trait2` is a (transitive) supertrait of `Trait2`. + /// type, excluding the coercion of a sized type into a `dyn Trait`. /// /// We return the `BuiltinImplSource` for each candidate as it is needed /// for unsize coercion in hir typeck and because it is difficult to /// otherwise recompute this for codegen. This is a bit of a mess but the /// easiest way to maintain the existing behavior for now. - fn consider_builtin_unsize_candidates( + fn consider_structural_builtin_unsize_candidates( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, ) -> Vec<(CanonicalResponse<'tcx>, BuiltinImplSource)>; + + /// Consider the `Unsize` candidate corresponding to coercing a sized type + /// into a `dyn Trait`. + /// + /// This is computed separately from the rest of the `Unsize` candidates + /// since it is only done once per self type, and not once per + /// *normalization step* (in `assemble_candidates_via_self_ty`). + fn consider_unsize_to_dyn_candidate( + ecx: &mut EvalCtxt<'_, 'tcx>, + goal: Goal<'tcx, Self>, + ) -> QueryResult<'tcx>; } impl<'tcx> EvalCtxt<'_, 'tcx> { @@ -312,6 +316,8 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { let mut candidates = self.assemble_candidates_via_self_ty(goal, 0); + self.assemble_unsize_to_dyn_candidate(goal, &mut candidates); + self.assemble_blanket_impl_candidates(goal, &mut candidates); self.assemble_param_env_candidates(goal, &mut candidates); @@ -530,6 +536,23 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { } } + fn assemble_unsize_to_dyn_candidate>( + &mut self, + goal: Goal<'tcx, G>, + candidates: &mut Vec>, + ) { + let tcx = self.tcx(); + if tcx.lang_items().unsize_trait() == Some(goal.predicate.trait_def_id(tcx)) { + match G::consider_unsize_to_dyn_candidate(self, goal) { + Ok(result) => candidates.push(Candidate { + source: CandidateSource::BuiltinImpl(BuiltinImplSource::Misc), + result, + }), + Err(NoSolution) => (), + } + } + } + fn assemble_blanket_impl_candidates>( &mut self, goal: Goal<'tcx, G>, @@ -610,7 +633,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { // There may be multiple unsize candidates for a trait with several supertraits: // `trait Foo: Bar + Bar` and `dyn Foo: Unsize>` if lang_items.unsize_trait() == Some(trait_def_id) { - for (result, source) in G::consider_builtin_unsize_candidates(self, goal) { + for (result, source) in G::consider_structural_builtin_unsize_candidates(self, goal) { candidates.push(Candidate { source: CandidateSource::BuiltinImpl(source), result }); } } diff --git a/compiler/rustc_trait_selection/src/solve/project_goals.rs b/compiler/rustc_trait_selection/src/solve/project_goals.rs index e1980f4d7bb0e..6117f51a37885 100644 --- a/compiler/rustc_trait_selection/src/solve/project_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/project_goals.rs @@ -497,7 +497,14 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { ) } - fn consider_builtin_unsize_candidates( + fn consider_unsize_to_dyn_candidate( + _ecx: &mut EvalCtxt<'_, 'tcx>, + goal: Goal<'tcx, Self>, + ) -> QueryResult<'tcx> { + bug!("`Unsize` does not have an associated type: {:?}", goal) + } + + fn consider_structural_builtin_unsize_candidates( _ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, ) -> Vec<(CanonicalResponse<'tcx>, BuiltinImplSource)> { diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs index ee6f1686b8238..639400f09276f 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs @@ -423,7 +423,55 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { ecx.evaluate_added_goals_and_make_canonical_response(certainty) } - fn consider_builtin_unsize_candidates( + fn consider_unsize_to_dyn_candidate( + ecx: &mut EvalCtxt<'_, 'tcx>, + goal: Goal<'tcx, Self>, + ) -> QueryResult<'tcx> { + ecx.probe(|_| CandidateKind::UnsizeAssembly).enter(|ecx| { + let a_ty = goal.predicate.self_ty(); + // We need to normalize the b_ty since it's destructured as a `dyn Trait`. + let Some(b_ty) = + ecx.try_normalize_ty(goal.param_env, goal.predicate.trait_ref.args.type_at(1))? + else { + return ecx.evaluate_added_goals_and_make_canonical_response(Certainty::OVERFLOW); + }; + + let ty::Dynamic(b_data, b_region, ty::Dyn) = *b_ty.kind() else { + return Err(NoSolution); + }; + + let tcx = ecx.tcx(); + + // Can only unsize to an object-safe trait. + if b_data.principal_def_id().is_some_and(|def_id| !tcx.check_is_object_safe(def_id)) { + return Err(NoSolution); + } + + // Check that the type implements all of the predicates of the trait object. + // (i.e. the principal, all of the associated types match, and any auto traits) + ecx.add_goals(b_data.iter().map(|pred| goal.with(tcx, pred.with_self_ty(tcx, a_ty)))); + + // The type must be `Sized` to be unsized. + if let Some(sized_def_id) = tcx.lang_items().sized_trait() { + ecx.add_goal(goal.with(tcx, ty::TraitRef::new(tcx, sized_def_id, [a_ty]))); + } else { + return Err(NoSolution); + } + + // The type must outlive the lifetime of the `dyn` we're unsizing into. + ecx.add_goal(goal.with(tcx, ty::OutlivesPredicate(a_ty, b_region))); + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + }) + } + + /// ```ignore (builtin impl example) + /// trait Trait { + /// fn foo(&self); + /// } + /// // results in the following builtin impl + /// impl<'a, T: Trait + 'a> Unsize for T {} + /// ``` + fn consider_structural_builtin_unsize_candidates( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, ) -> Vec<(CanonicalResponse<'tcx>, BuiltinImplSource)> { @@ -468,11 +516,8 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { goal, a_data, a_region, b_data, b_region, ), - // `T` -> `dyn Trait` unsizing - (_, &ty::Dynamic(b_data, b_region, ty::Dyn)) => result_to_single( - ecx.consider_builtin_unsize_to_dyn(goal, b_data, b_region), - BuiltinImplSource::Misc, - ), + // `T` -> `dyn Trait` unsizing is handled separately in `consider_unsize_to_dyn_candidate` + (_, &ty::Dynamic(..)) => vec![], // `[T; N]` -> `[T]` unsizing (&ty::Array(a_elem_ty, ..), &ty::Slice(b_elem_ty)) => result_to_single( @@ -572,43 +617,6 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { responses } - /// ```ignore (builtin impl example) - /// trait Trait { - /// fn foo(&self); - /// } - /// // results in the following builtin impl - /// impl<'a, T: Trait + 'a> Unsize for T {} - /// ``` - fn consider_builtin_unsize_to_dyn( - &mut self, - goal: Goal<'tcx, (Ty<'tcx>, Ty<'tcx>)>, - b_data: &'tcx ty::List>, - b_region: ty::Region<'tcx>, - ) -> QueryResult<'tcx> { - let tcx = self.tcx(); - let Goal { predicate: (a_ty, _b_ty), .. } = goal; - - // Can only unsize to an object-safe trait - if b_data.principal_def_id().is_some_and(|def_id| !tcx.check_is_object_safe(def_id)) { - return Err(NoSolution); - } - - // Check that the type implements all of the predicates of the trait object. - // (i.e. the principal, all of the associated types match, and any auto traits) - self.add_goals(b_data.iter().map(|pred| goal.with(tcx, pred.with_self_ty(tcx, a_ty)))); - - // The type must be `Sized` to be unsized. - if let Some(sized_def_id) = tcx.lang_items().sized_trait() { - self.add_goal(goal.with(tcx, ty::TraitRef::new(tcx, sized_def_id, [a_ty]))); - } else { - return Err(NoSolution); - } - - // The type must outlive the lifetime of the `dyn` we're unsizing into. - self.add_goal(goal.with(tcx, ty::OutlivesPredicate(a_ty, b_region))); - self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) - } - fn consider_builtin_upcast_to_principal( &mut self, goal: Goal<'tcx, (Ty<'tcx>, Ty<'tcx>)>, diff --git a/tests/ui/unsized/issue-75899.rs b/tests/ui/unsized/issue-75899.rs index abff17e11b54a..7194310329157 100644 --- a/tests/ui/unsized/issue-75899.rs +++ b/tests/ui/unsized/issue-75899.rs @@ -1,3 +1,5 @@ +// revisions: current next +//[next] compile-flags: -Ztrait-solver=next // check-pass trait Trait {} From dc946649f5a813bc29e76f3879f4fc4f02cc3bab Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 14 Aug 2023 21:47:23 +0000 Subject: [PATCH 12/13] Clean up some bad ui testing annotations --- tests/ui/generic-associated-types/issue-86218.rs | 1 - tests/ui/generic-associated-types/issue-90014-tait.rs | 1 - .../generic-associated-types/issue-90014-tait.stderr | 8 ++++---- tests/ui/internal/internal-unstable.rs | 2 -- tests/ui/internal/internal-unstable.stderr | 10 +++++----- tests/ui/parser/issues/issue-70583-block-is-empty-2.rs | 8 ++++++-- .../parser/issues/issue-70583-block-is-empty-2.stderr | 3 ++- .../where-clauses/where-clause-bounds-inconsistency.rs | 1 - 8 files changed, 17 insertions(+), 17 deletions(-) diff --git a/tests/ui/generic-associated-types/issue-86218.rs b/tests/ui/generic-associated-types/issue-86218.rs index 61cfdd35a8926..397a0f2c64903 100644 --- a/tests/ui/generic-associated-types/issue-86218.rs +++ b/tests/ui/generic-associated-types/issue-86218.rs @@ -17,7 +17,6 @@ trait Yay { impl<'a> Yay<&'a ()> for () { type InnerStream<'s> = impl Stream + 's; - //^ ERROR does not fulfill the required lifetime fn foo<'s>() -> Self::InnerStream<'s> { () } diff --git a/tests/ui/generic-associated-types/issue-90014-tait.rs b/tests/ui/generic-associated-types/issue-90014-tait.rs index bc3a4e1296513..1ce5cd3198767 100644 --- a/tests/ui/generic-associated-types/issue-90014-tait.rs +++ b/tests/ui/generic-associated-types/issue-90014-tait.rs @@ -13,7 +13,6 @@ struct Foo<'a>(&'a mut ()); impl Foo<'_> { type Fut<'a> = impl Future; - //^ ERROR: the type `&mut ()` does not fulfill the required lifetime fn make_fut<'a>(&'a self) -> Self::Fut<'a> { async { () } diff --git a/tests/ui/generic-associated-types/issue-90014-tait.stderr b/tests/ui/generic-associated-types/issue-90014-tait.stderr index 8330a387ecd55..1dec7edce508c 100644 --- a/tests/ui/generic-associated-types/issue-90014-tait.stderr +++ b/tests/ui/generic-associated-types/issue-90014-tait.stderr @@ -1,18 +1,18 @@ error[E0308]: mismatched types - --> $DIR/issue-90014-tait.rs:19:9 + --> $DIR/issue-90014-tait.rs:18:9 | LL | type Fut<'a> = impl Future; | ------------------------ the expected future -... +LL | LL | fn make_fut<'a>(&'a self) -> Self::Fut<'a> { | ------------- expected `Foo<'_>::Fut<'a>` because of return type LL | async { () } | ^^^^^^^^^^^^ expected future, found `async` block | = note: expected opaque type `Foo<'_>::Fut<'a>` - found `async` block `[async block@$DIR/issue-90014-tait.rs:19:9: 19:21]` + found `async` block `[async block@$DIR/issue-90014-tait.rs:18:9: 18:21]` note: this item must have the opaque type in its signature in order to be able to register hidden types - --> $DIR/issue-90014-tait.rs:18:8 + --> $DIR/issue-90014-tait.rs:17:8 | LL | fn make_fut<'a>(&'a self) -> Self::Fut<'a> { | ^^^^^^^^ diff --git a/tests/ui/internal/internal-unstable.rs b/tests/ui/internal/internal-unstable.rs index b8987d3e13c65..1eb27fbdc3a63 100644 --- a/tests/ui/internal/internal-unstable.rs +++ b/tests/ui/internal/internal-unstable.rs @@ -8,7 +8,6 @@ extern crate internal_unstable; struct Baz { #[allow_internal_unstable] - //^ WARN `#[allow_internal_unstable]` is ignored on struct fields and match arms baz: u8, } @@ -50,7 +49,6 @@ fn main() { match true { #[allow_internal_unstable] - //^ WARN `#[allow_internal_unstable]` is ignored on struct fields and match arms _ => {} } } diff --git a/tests/ui/internal/internal-unstable.stderr b/tests/ui/internal/internal-unstable.stderr index f0f9bfb8d234f..b7c47365c2d27 100644 --- a/tests/ui/internal/internal-unstable.stderr +++ b/tests/ui/internal/internal-unstable.stderr @@ -1,5 +1,5 @@ error[E0658]: use of unstable library feature 'function' - --> $DIR/internal-unstable.rs:41:25 + --> $DIR/internal-unstable.rs:40:25 | LL | pass_through_allow!(internal_unstable::unstable()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -7,7 +7,7 @@ LL | pass_through_allow!(internal_unstable::unstable()); = help: add `#![feature(function)]` to the crate attributes to enable error[E0658]: use of unstable library feature 'function' - --> $DIR/internal-unstable.rs:43:27 + --> $DIR/internal-unstable.rs:42:27 | LL | pass_through_noallow!(internal_unstable::unstable()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -15,7 +15,7 @@ LL | pass_through_noallow!(internal_unstable::unstable()); = help: add `#![feature(function)]` to the crate attributes to enable error[E0658]: use of unstable library feature 'function' - --> $DIR/internal-unstable.rs:47:22 + --> $DIR/internal-unstable.rs:46:22 | LL | println!("{:?}", internal_unstable::unstable()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -23,7 +23,7 @@ LL | println!("{:?}", internal_unstable::unstable()); = help: add `#![feature(function)]` to the crate attributes to enable error[E0658]: use of unstable library feature 'function' - --> $DIR/internal-unstable.rs:49:10 + --> $DIR/internal-unstable.rs:48:10 | LL | bar!(internal_unstable::unstable()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -31,7 +31,7 @@ LL | bar!(internal_unstable::unstable()); = help: add `#![feature(function)]` to the crate attributes to enable error[E0658]: use of unstable library feature 'function' - --> $DIR/internal-unstable.rs:19:9 + --> $DIR/internal-unstable.rs:18:9 | LL | internal_unstable::unstable(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/parser/issues/issue-70583-block-is-empty-2.rs b/tests/ui/parser/issues/issue-70583-block-is-empty-2.rs index 80f53338a689e..92ff0ef643e34 100644 --- a/tests/ui/parser/issues/issue-70583-block-is-empty-2.rs +++ b/tests/ui/parser/issues/issue-70583-block-is-empty-2.rs @@ -6,9 +6,13 @@ pub enum ErrorHandled { impl ErrorHandled { pub fn assert_reported(self) { match self { + //~^ NOTE this delimiter might not be properly closed... ErrorHandled::Reported => {}} - //^~ ERROR block is empty, you might have not meant to close it + //~^ NOTE block is empty, you might have not meant to close it + //~| NOTE as it matches this but it has different indentation ErrorHandled::TooGeneric => panic!(), } } -} //~ ERROR unexpected closing delimiter: `}` +} +//~^ ERROR unexpected closing delimiter: `}` +//~| NOTE unexpected closing delimiter diff --git a/tests/ui/parser/issues/issue-70583-block-is-empty-2.stderr b/tests/ui/parser/issues/issue-70583-block-is-empty-2.stderr index 9ae94c701869b..c590e04bb3ded 100644 --- a/tests/ui/parser/issues/issue-70583-block-is-empty-2.stderr +++ b/tests/ui/parser/issues/issue-70583-block-is-empty-2.stderr @@ -1,8 +1,9 @@ error: unexpected closing delimiter: `}` - --> $DIR/issue-70583-block-is-empty-2.rs:14:1 + --> $DIR/issue-70583-block-is-empty-2.rs:16:1 | LL | match self { | - this delimiter might not be properly closed... +LL | LL | ErrorHandled::Reported => {}} | --- ...as it matches this but it has different indentation | | diff --git a/tests/ui/where-clauses/where-clause-bounds-inconsistency.rs b/tests/ui/where-clauses/where-clause-bounds-inconsistency.rs index cf7d06b6179b0..ea60fa708764f 100644 --- a/tests/ui/where-clauses/where-clause-bounds-inconsistency.rs +++ b/tests/ui/where-clauses/where-clause-bounds-inconsistency.rs @@ -14,7 +14,6 @@ trait Trait { impl Trait for bool { fn a(&self, _: T) {} - //^~ This gets rejected but should be accepted fn b(&self, _: T) where T: Bound {} fn c(&self, _: T) {} fn d(&self, _: T) where T: Bound {} From 77c6c38add04f74542c37c4fb2299309e3e2101d Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 14 Aug 2023 20:49:08 +0000 Subject: [PATCH 13/13] Check projection arguments before substitution --- .../src/solve/project_goals.rs | 22 +++++++++++++------ ...114.stderr => issue-102114.current.stderr} | 2 +- .../issue-102114.next.stderr | 12 ++++++++++ .../generic-associated-types/issue-102114.rs | 3 +++ 4 files changed, 31 insertions(+), 8 deletions(-) rename tests/ui/generic-associated-types/{issue-102114.stderr => issue-102114.current.stderr} (91%) create mode 100644 tests/ui/generic-associated-types/issue-102114.next.stderr diff --git a/compiler/rustc_trait_selection/src/solve/project_goals.rs b/compiler/rustc_trait_selection/src/solve/project_goals.rs index e1980f4d7bb0e..9ce640ea0f902 100644 --- a/compiler/rustc_trait_selection/src/solve/project_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/project_goals.rs @@ -1,4 +1,4 @@ -use crate::traits::specialization_graph; +use crate::traits::{check_args_compatible, specialization_graph}; use super::assembly::{self, structural_traits}; use super::EvalCtxt; @@ -190,11 +190,8 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { return ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS); }; - if !assoc_def.item.defaultness(tcx).has_value() { - let guar = tcx.sess.delay_span_bug( - tcx.def_span(assoc_def.item.def_id), - "missing value for assoc item in impl", - ); + let error_response = |ecx: &mut EvalCtxt<'_, 'tcx>, reason| { + let guar = tcx.sess.delay_span_bug(tcx.def_span(assoc_def.item.def_id), reason); let error_term = match assoc_def.item.kind { ty::AssocKind::Const => ty::Const::new_error( tcx, @@ -208,7 +205,11 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { }; ecx.eq(goal.param_env, goal.predicate.term, error_term) .expect("expected goal term to be fully unconstrained"); - return ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes); + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + }; + + if !assoc_def.item.defaultness(tcx).has_value() { + return error_response(ecx, "missing value for assoc item in impl"); } // Getting the right args here is complex, e.g. given: @@ -233,6 +234,13 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { assoc_def.defining_node, ); + if !check_args_compatible(tcx, assoc_def.item, args) { + return error_response( + ecx, + "associated item has mismatched generic item arguments", + ); + } + // Finally we construct the actual value of the associated type. let term = match assoc_def.item.kind { ty::AssocKind::Type => tcx.type_of(assoc_def.item.def_id).map_bound(|ty| ty.into()), diff --git a/tests/ui/generic-associated-types/issue-102114.stderr b/tests/ui/generic-associated-types/issue-102114.current.stderr similarity index 91% rename from tests/ui/generic-associated-types/issue-102114.stderr rename to tests/ui/generic-associated-types/issue-102114.current.stderr index 8e41dee54d7e4..6e7a0b1f67f71 100644 --- a/tests/ui/generic-associated-types/issue-102114.stderr +++ b/tests/ui/generic-associated-types/issue-102114.current.stderr @@ -1,5 +1,5 @@ error[E0049]: type `B` has 1 type parameter but its trait declaration has 0 type parameters - --> $DIR/issue-102114.rs:11:12 + --> $DIR/issue-102114.rs:14:12 | LL | type B<'b>; | -- expected 0 type parameters diff --git a/tests/ui/generic-associated-types/issue-102114.next.stderr b/tests/ui/generic-associated-types/issue-102114.next.stderr new file mode 100644 index 0000000000000..6e7a0b1f67f71 --- /dev/null +++ b/tests/ui/generic-associated-types/issue-102114.next.stderr @@ -0,0 +1,12 @@ +error[E0049]: type `B` has 1 type parameter but its trait declaration has 0 type parameters + --> $DIR/issue-102114.rs:14:12 + | +LL | type B<'b>; + | -- expected 0 type parameters +... +LL | type B = Wrapper; + | ^ found 1 type parameter + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0049`. diff --git a/tests/ui/generic-associated-types/issue-102114.rs b/tests/ui/generic-associated-types/issue-102114.rs index de31737efef52..bb6622c0a5fb7 100644 --- a/tests/ui/generic-associated-types/issue-102114.rs +++ b/tests/ui/generic-associated-types/issue-102114.rs @@ -1,3 +1,6 @@ +// revisions: current next +//[next] compile-flags: -Ztrait-solver=next + trait A { type B<'b>; fn a() -> Self::B<'static>;