From 54b5eae39b709d2daca8ee3bfb23febebf5c46b9 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 14 Jul 2023 16:32:10 +1000 Subject: [PATCH 01/45] Introduce `MonoItemData`. It replaces `(Linkage, Visibility)`, making the code nicer. Plus the next commit will add another field. --- .../rustc_codegen_cranelift/src/driver/mod.rs | 10 ++++---- compiler/rustc_codegen_gcc/src/base.rs | 4 +-- compiler/rustc_codegen_llvm/src/base.rs | 4 +-- .../src/back/symbol_export.rs | 6 ++--- compiler/rustc_middle/src/mir/mono.rs | 17 +++++++++---- .../rustc_monomorphize/src/partitioning.rs | 25 +++++++++++-------- 6 files changed, 39 insertions(+), 27 deletions(-) diff --git a/compiler/rustc_codegen_cranelift/src/driver/mod.rs b/compiler/rustc_codegen_cranelift/src/driver/mod.rs index 5c52c9c18adfd..12e90b5841034 100644 --- a/compiler/rustc_codegen_cranelift/src/driver/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/driver/mod.rs @@ -5,7 +5,7 @@ //! [`codegen_static`]: crate::constant::codegen_static use rustc_data_structures::profiling::SelfProfilerRef; -use rustc_middle::mir::mono::{Linkage as RLinkage, MonoItem, Visibility}; +use rustc_middle::mir::mono::{MonoItem, MonoItemData}; use crate::prelude::*; @@ -16,11 +16,11 @@ pub(crate) mod jit; fn predefine_mono_items<'tcx>( tcx: TyCtxt<'tcx>, module: &mut dyn Module, - mono_items: &[(MonoItem<'tcx>, (RLinkage, Visibility))], + mono_items: &[(MonoItem<'tcx>, MonoItemData)], ) { tcx.prof.generic_activity("predefine functions").run(|| { let is_compiler_builtins = tcx.is_compiler_builtins(LOCAL_CRATE); - for &(mono_item, (linkage, visibility)) in mono_items { + for &(mono_item, data) in mono_items { match mono_item { MonoItem::Fn(instance) => { let name = tcx.symbol_name(instance).name; @@ -29,8 +29,8 @@ fn predefine_mono_items<'tcx>( get_function_sig(tcx, module.target_config().default_call_conv, instance); let linkage = crate::linkage::get_clif_linkage( mono_item, - linkage, - visibility, + data.linkage, + data.visibility, is_compiler_builtins, ); module.declare_function(name, linkage, &sig).unwrap(); diff --git a/compiler/rustc_codegen_gcc/src/base.rs b/compiler/rustc_codegen_gcc/src/base.rs index dcd560b3dcd95..9e614ca4ace0b 100644 --- a/compiler/rustc_codegen_gcc/src/base.rs +++ b/compiler/rustc_codegen_gcc/src/base.rs @@ -159,8 +159,8 @@ pub fn compile_codegen_unit(tcx: TyCtxt<'_>, cgu_name: Symbol, supports_128bit_i let cx = CodegenCx::new(&context, cgu, tcx, supports_128bit_integers); let mono_items = cgu.items_in_deterministic_order(tcx); - for &(mono_item, (linkage, visibility)) in &mono_items { - mono_item.predefine::>(&cx, linkage, visibility); + for &(mono_item, data) in &mono_items { + mono_item.predefine::>(&cx, data.linkage, data.visibility); } // ... and now that we have everything pre-defined, fill out those definitions. diff --git a/compiler/rustc_codegen_llvm/src/base.rs b/compiler/rustc_codegen_llvm/src/base.rs index 5b2bbdb4bde1e..5b5f81c032940 100644 --- a/compiler/rustc_codegen_llvm/src/base.rs +++ b/compiler/rustc_codegen_llvm/src/base.rs @@ -86,8 +86,8 @@ pub fn compile_codegen_unit(tcx: TyCtxt<'_>, cgu_name: Symbol) -> (ModuleCodegen { let cx = CodegenCx::new(tcx, cgu, &llvm_module); let mono_items = cx.codegen_unit.items_in_deterministic_order(cx.tcx); - for &(mono_item, (linkage, visibility)) in &mono_items { - mono_item.predefine::>(&cx, linkage, visibility); + for &(mono_item, data) in &mono_items { + mono_item.predefine::>(&cx, data.linkage, data.visibility); } // ... and now that we have everything pre-defined, fill out those definitions. diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs index a8b6030ac85c3..44e0b0d19731f 100644 --- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs +++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs @@ -328,14 +328,14 @@ fn exported_symbols_provider_local( let (_, cgus) = tcx.collect_and_partition_mono_items(()); - for (mono_item, &(linkage, visibility)) in cgus.iter().flat_map(|cgu| cgu.items().iter()) { - if linkage != Linkage::External { + for (mono_item, data) in cgus.iter().flat_map(|cgu| cgu.items().iter()) { + if data.linkage != Linkage::External { // We can only re-use things with external linkage, otherwise // we'll get a linker error continue; } - if need_visibility && visibility == Visibility::Hidden { + if need_visibility && data.visibility == Visibility::Hidden { // If we potentially share things from Rust dylibs, they must // not be hidden continue; diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs index ca735d5231465..6ea71a6fdbf94 100644 --- a/compiler/rustc_middle/src/mir/mono.rs +++ b/compiler/rustc_middle/src/mir/mono.rs @@ -230,7 +230,7 @@ pub struct CodegenUnit<'tcx> { /// contain something unique to this crate (e.g., a module path) /// as well as the crate name and disambiguator. name: Symbol, - items: FxHashMap, (Linkage, Visibility)>, + items: FxHashMap, MonoItemData>, size_estimate: usize, primary: bool, /// True if this is CGU is used to hold code coverage information for dead code, @@ -238,6 +238,13 @@ pub struct CodegenUnit<'tcx> { is_code_coverage_dead_code_cgu: bool, } +/// Auxiliary info about a `MonoItem`. +#[derive(Copy, Clone, PartialEq, Debug, HashStable)] +pub struct MonoItemData { + pub linkage: Linkage, + pub visibility: Visibility, +} + /// Specifies the linkage type for a `MonoItem`. /// /// See for more details about these variants. @@ -292,12 +299,12 @@ impl<'tcx> CodegenUnit<'tcx> { } /// The order of these items is non-determinstic. - pub fn items(&self) -> &FxHashMap, (Linkage, Visibility)> { + pub fn items(&self) -> &FxHashMap, MonoItemData> { &self.items } /// The order of these items is non-determinstic. - pub fn items_mut(&mut self) -> &mut FxHashMap, (Linkage, Visibility)> { + pub fn items_mut(&mut self) -> &mut FxHashMap, MonoItemData> { &mut self.items } @@ -355,7 +362,7 @@ impl<'tcx> CodegenUnit<'tcx> { pub fn items_in_deterministic_order( &self, tcx: TyCtxt<'tcx>, - ) -> Vec<(MonoItem<'tcx>, (Linkage, Visibility))> { + ) -> Vec<(MonoItem<'tcx>, MonoItemData)> { // The codegen tests rely on items being process in the same order as // they appear in the file, so for local items, we sort by node_id first #[derive(PartialEq, Eq, PartialOrd, Ord)] @@ -390,7 +397,7 @@ impl<'tcx> CodegenUnit<'tcx> { ) } - let mut items: Vec<_> = self.items().iter().map(|(&i, &l)| (i, l)).collect(); + let mut items: Vec<_> = self.items().iter().map(|(&i, &data)| (i, data)).collect(); items.sort_by_cached_key(|&(i, _)| item_sort_key(tcx, i)); items } diff --git a/compiler/rustc_monomorphize/src/partitioning.rs b/compiler/rustc_monomorphize/src/partitioning.rs index da76cf2236c70..0cb61b3a2d16a 100644 --- a/compiler/rustc_monomorphize/src/partitioning.rs +++ b/compiler/rustc_monomorphize/src/partitioning.rs @@ -107,7 +107,8 @@ use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::middle::exported_symbols::{SymbolExportInfo, SymbolExportLevel}; use rustc_middle::mir; use rustc_middle::mir::mono::{ - CodegenUnit, CodegenUnitNameBuilder, InstantiationMode, Linkage, MonoItem, Visibility, + CodegenUnit, CodegenUnitNameBuilder, InstantiationMode, Linkage, MonoItem, MonoItemData, + Visibility, }; use rustc_middle::query::Providers; use rustc_middle::ty::print::{characteristic_def_id_of_type, with_no_trimmed_paths}; @@ -257,7 +258,7 @@ where internalization_candidates.insert(mono_item); } - cgu.items_mut().insert(mono_item, (linkage, visibility)); + cgu.items_mut().insert(mono_item, MonoItemData { linkage, visibility }); // Get all inlined items that are reachable from `mono_item` without // going via another root item. This includes drop-glue, functions from @@ -271,7 +272,9 @@ where // the `insert` will be a no-op. for inlined_item in reachable_inlined_items { // This is a CGU-private copy. - cgu.items_mut().insert(inlined_item, (Linkage::Internal, Visibility::Default)); + let linkage = Linkage::Internal; + let visibility = Visibility::Default; + cgu.items_mut().insert(inlined_item, MonoItemData { linkage, visibility }); } } @@ -492,7 +495,7 @@ fn internalize_symbols<'tcx>( for cgu in codegen_units { let home_cgu = MonoItemPlacement::SingleCgu(cgu.name()); - for (item, linkage_and_visibility) in cgu.items_mut() { + for (item, data) in cgu.items_mut() { if !internalization_candidates.contains(item) { // This item is no candidate for internalizing, so skip it. continue; @@ -520,7 +523,8 @@ fn internalize_symbols<'tcx>( // If we got here, we did not find any uses from other CGUs, so // it's fine to make this monomorphization internal. - *linkage_and_visibility = (Linkage::Internal, Visibility::Default); + data.linkage = Linkage::Internal; + data.visibility = Visibility::Default; } } } @@ -537,7 +541,7 @@ fn mark_code_coverage_dead_code_cgu<'tcx>(codegen_units: &mut [CodegenUnit<'tcx> // function symbols to be included via `-u` or `/include` linker args. let dead_code_cgu = codegen_units .iter_mut() - .filter(|cgu| cgu.items().iter().any(|(_, (linkage, _))| *linkage == Linkage::External)) + .filter(|cgu| cgu.items().iter().any(|(_, data)| data.linkage == Linkage::External)) .min_by_key(|cgu| cgu.size_estimate()); // If there are no CGUs that have externally linked items, then we just @@ -937,7 +941,8 @@ fn debug_dump<'a, 'tcx: 'a>( let _ = writeln!(s, " - items: {num_items}, mean size: {mean_size:.1}, sizes: {sizes}",); - for (item, linkage) in cgu.items_in_deterministic_order(tcx) { + for (item, data) in cgu.items_in_deterministic_order(tcx) { + let linkage = data.linkage; let symbol_name = item.symbol_name(tcx).name; let symbol_hash_start = symbol_name.rfind('h'); let symbol_hash = symbol_hash_start.map_or("", |i| &symbol_name[i..]); @@ -1100,8 +1105,8 @@ fn collect_and_partition_mono_items(tcx: TyCtxt<'_>, (): ()) -> (&DefIdSet, &[Co let mut item_to_cgus: FxHashMap<_, Vec<_>> = Default::default(); for cgu in codegen_units { - for (&mono_item, &linkage) in cgu.items() { - item_to_cgus.entry(mono_item).or_default().push((cgu.name(), linkage)); + for (&mono_item, &data) in cgu.items() { + item_to_cgus.entry(mono_item).or_default().push((cgu.name(), data.linkage)); } } @@ -1114,7 +1119,7 @@ fn collect_and_partition_mono_items(tcx: TyCtxt<'_>, (): ()) -> (&DefIdSet, &[Co let cgus = item_to_cgus.get_mut(i).unwrap_or(&mut empty); cgus.sort_by_key(|(name, _)| *name); cgus.dedup(); - for &(ref cgu_name, (linkage, _)) in cgus.iter() { + for &(ref cgu_name, linkage) in cgus.iter() { output.push(' '); output.push_str(cgu_name.as_str()); From 1159f435b5dd6139dcf67ff17e82354ec5704a69 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 14 Jul 2023 16:02:32 +1000 Subject: [PATCH 02/45] Store item size estimate in `MonoItemData`. This means we call `MonoItem::size_estimate` (which involves a query) less often: just once per mono item, and then once more per inline item placement. After that we can reuse the stored value as necessary. This means `CodegenUnit::compute_size_estimate` is cheaper. --- compiler/rustc_middle/src/mir/mono.rs | 11 +++---- .../rustc_monomorphize/src/partitioning.rs | 29 ++++++++++--------- 2 files changed, 22 insertions(+), 18 deletions(-) diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs index 6ea71a6fdbf94..a71c95d30ccbc 100644 --- a/compiler/rustc_middle/src/mir/mono.rs +++ b/compiler/rustc_middle/src/mir/mono.rs @@ -243,6 +243,7 @@ pub struct CodegenUnit<'tcx> { pub struct MonoItemData { pub linkage: Linkage, pub visibility: Visibility, + pub size_estimate: usize, } /// Specifies the linkage type for a `MonoItem`. @@ -327,16 +328,16 @@ impl<'tcx> CodegenUnit<'tcx> { base_n::encode(hash, base_n::CASE_INSENSITIVE) } - pub fn compute_size_estimate(&mut self, tcx: TyCtxt<'tcx>) { - // Estimate the size of a codegen unit as (approximately) the number of MIR - // statements it corresponds to. - self.size_estimate = self.items.keys().map(|mi| mi.size_estimate(tcx)).sum(); + pub fn compute_size_estimate(&mut self) { + // The size of a codegen unit as the sum of the sizes of the items + // within it. + self.size_estimate = self.items.values().map(|data| data.size_estimate).sum(); } - #[inline] /// Should only be called if [`compute_size_estimate`] has previously been called. /// /// [`compute_size_estimate`]: Self::compute_size_estimate + #[inline] pub fn size_estimate(&self) -> usize { // Items are never zero-sized, so if we have items the estimate must be // non-zero, unless we forgot to call `compute_size_estimate` first. diff --git a/compiler/rustc_monomorphize/src/partitioning.rs b/compiler/rustc_monomorphize/src/partitioning.rs index 0cb61b3a2d16a..64cf0c9f7dbb3 100644 --- a/compiler/rustc_monomorphize/src/partitioning.rs +++ b/compiler/rustc_monomorphize/src/partitioning.rs @@ -222,11 +222,12 @@ where for mono_item in mono_items { // Handle only root items directly here. Inlined items are handled at // the bottom of the loop based on reachability. + let size_estimate = mono_item.size_estimate(cx.tcx); match mono_item.instantiation_mode(cx.tcx) { InstantiationMode::GloballyShared { .. } => {} InstantiationMode::LocalCopy => { num_unique_inlined_items += 1; - unique_inlined_items_size += mono_item.size_estimate(cx.tcx); + unique_inlined_items_size += size_estimate; continue; } } @@ -258,7 +259,7 @@ where internalization_candidates.insert(mono_item); } - cgu.items_mut().insert(mono_item, MonoItemData { linkage, visibility }); + cgu.items_mut().insert(mono_item, MonoItemData { linkage, visibility, size_estimate }); // Get all inlined items that are reachable from `mono_item` without // going via another root item. This includes drop-glue, functions from @@ -272,9 +273,11 @@ where // the `insert` will be a no-op. for inlined_item in reachable_inlined_items { // This is a CGU-private copy. - let linkage = Linkage::Internal; - let visibility = Visibility::Default; - cgu.items_mut().insert(inlined_item, MonoItemData { linkage, visibility }); + cgu.items_mut().entry(inlined_item).or_insert_with(|| MonoItemData { + linkage: Linkage::Internal, + visibility: Visibility::Default, + size_estimate: inlined_item.size_estimate(cx.tcx), + }); } } @@ -289,7 +292,7 @@ where codegen_units.sort_by(|a, b| a.name().as_str().cmp(b.name().as_str())); for cgu in codegen_units.iter_mut() { - cgu.compute_size_estimate(cx.tcx); + cgu.compute_size_estimate(); } return PlacedMonoItems { @@ -352,7 +355,7 @@ fn merge_codegen_units<'tcx>( && codegen_units.iter().any(|cgu| cgu.size_estimate() < NON_INCR_MIN_CGU_SIZE)) { // Sort small cgus to the back. - codegen_units.sort_by_cached_key(|cgu| cmp::Reverse(cgu.size_estimate())); + codegen_units.sort_by_key(|cgu| cmp::Reverse(cgu.size_estimate())); let mut smallest = codegen_units.pop().unwrap(); let second_smallest = codegen_units.last_mut().unwrap(); @@ -361,7 +364,7 @@ fn merge_codegen_units<'tcx>( // may be duplicate inlined items, in which case the destination CGU is // unaffected. Recalculate size estimates afterwards. second_smallest.items_mut().extend(smallest.items_mut().drain()); - second_smallest.compute_size_estimate(cx.tcx); + second_smallest.compute_size_estimate(); // Record that `second_smallest` now contains all the stuff that was // in `smallest` before. @@ -882,15 +885,15 @@ fn debug_dump<'a, 'tcx: 'a>( num_cgus += 1; all_cgu_sizes.push(cgu.size_estimate()); - for (item, _) in cgu.items() { + for (item, data) in cgu.items() { match item.instantiation_mode(tcx) { InstantiationMode::GloballyShared { .. } => { root_items += 1; - root_size += item.size_estimate(tcx); + root_size += data.size_estimate; } InstantiationMode::LocalCopy => { placed_inlined_items += 1; - placed_inlined_size += item.size_estimate(tcx); + placed_inlined_size += data.size_estimate; } } } @@ -932,7 +935,7 @@ fn debug_dump<'a, 'tcx: 'a>( let mean_size = size as f64 / num_items as f64; let mut placed_item_sizes: Vec<_> = - cgu.items().iter().map(|(item, _)| item.size_estimate(tcx)).collect(); + cgu.items().values().map(|data| data.size_estimate).collect(); placed_item_sizes.sort_unstable_by_key(|&n| cmp::Reverse(n)); let sizes = list(&placed_item_sizes); @@ -946,11 +949,11 @@ fn debug_dump<'a, 'tcx: 'a>( let symbol_name = item.symbol_name(tcx).name; let symbol_hash_start = symbol_name.rfind('h'); let symbol_hash = symbol_hash_start.map_or("", |i| &symbol_name[i..]); - let size = item.size_estimate(tcx); let kind = match item.instantiation_mode(tcx) { InstantiationMode::GloballyShared { .. } => "root", InstantiationMode::LocalCopy => "inlined", }; + let size = data.size_estimate; let _ = with_no_trimmed_paths!(writeln!( s, " - {item} [{linkage:?}] [{symbol_hash}] ({kind}, size: {size})" From 71bfc5747b2a18392a9093dbfb2e5aecd5425c17 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 14 Jul 2023 21:32:48 +1000 Subject: [PATCH 03/45] Ignore unreachable inlined items in `debug_dump`. They're quite rare, and ignoring them simplifies things quite a bit, and further reduces the number of calls to `MonoItem::size_estimate` to the number of placed items (one per root item, and one or more per reachable inlined item). --- .../rustc_monomorphize/src/partitioning.rs | 48 +++++++------------ 1 file changed, 18 insertions(+), 30 deletions(-) diff --git a/compiler/rustc_monomorphize/src/partitioning.rs b/compiler/rustc_monomorphize/src/partitioning.rs index 64cf0c9f7dbb3..18b51c66b9d7c 100644 --- a/compiler/rustc_monomorphize/src/partitioning.rs +++ b/compiler/rustc_monomorphize/src/partitioning.rs @@ -131,11 +131,6 @@ struct PlacedMonoItems<'tcx> { codegen_units: Vec>, internalization_candidates: FxHashSet>, - - /// These must be obtained when the iterator in `partition` runs. They - /// can't be obtained later because some inlined functions might not be - /// reachable. - unique_inlined_stats: (usize, usize), } // The output CGUs are sorted by name. @@ -153,11 +148,11 @@ where // Place all mono items into a codegen unit. `place_mono_items` is // responsible for initializing the CGU size estimates. - let PlacedMonoItems { mut codegen_units, internalization_candidates, unique_inlined_stats } = { + let PlacedMonoItems { mut codegen_units, internalization_candidates } = { let _prof_timer = tcx.prof.generic_activity("cgu_partitioning_place_items"); let placed = place_mono_items(cx, mono_items); - debug_dump(tcx, "PLACE", &placed.codegen_units, placed.unique_inlined_stats); + debug_dump(tcx, "PLACE", &placed.codegen_units); placed }; @@ -168,7 +163,7 @@ where { let _prof_timer = tcx.prof.generic_activity("cgu_partitioning_merge_cgus"); merge_codegen_units(cx, &mut codegen_units); - debug_dump(tcx, "MERGE", &codegen_units, unique_inlined_stats); + debug_dump(tcx, "MERGE", &codegen_units); } // Make as many symbols "internal" as possible, so LLVM has more freedom to @@ -177,7 +172,7 @@ where let _prof_timer = tcx.prof.generic_activity("cgu_partitioning_internalize_symbols"); internalize_symbols(cx, &mut codegen_units, internalization_candidates); - debug_dump(tcx, "INTERNALIZE", &codegen_units, unique_inlined_stats); + debug_dump(tcx, "INTERNALIZE", &codegen_units); } // Mark one CGU for dead code, if necessary. @@ -217,19 +212,12 @@ where let cgu_name_builder = &mut CodegenUnitNameBuilder::new(cx.tcx); let cgu_name_cache = &mut FxHashMap::default(); - let mut num_unique_inlined_items = 0; - let mut unique_inlined_items_size = 0; for mono_item in mono_items { // Handle only root items directly here. Inlined items are handled at // the bottom of the loop based on reachability. - let size_estimate = mono_item.size_estimate(cx.tcx); match mono_item.instantiation_mode(cx.tcx) { InstantiationMode::GloballyShared { .. } => {} - InstantiationMode::LocalCopy => { - num_unique_inlined_items += 1; - unique_inlined_items_size += size_estimate; - continue; - } + InstantiationMode::LocalCopy => continue, } let characteristic_def_id = characteristic_def_id_of_mono_item(cx.tcx, mono_item); @@ -258,6 +246,7 @@ where if visibility == Visibility::Hidden && can_be_internalized { internalization_candidates.insert(mono_item); } + let size_estimate = mono_item.size_estimate(cx.tcx); cgu.items_mut().insert(mono_item, MonoItemData { linkage, visibility, size_estimate }); @@ -295,11 +284,7 @@ where cgu.compute_size_estimate(); } - return PlacedMonoItems { - codegen_units, - internalization_candidates, - unique_inlined_stats: (num_unique_inlined_items, unique_inlined_items_size), - }; + return PlacedMonoItems { codegen_units, internalization_candidates }; fn get_reachable_inlined_items<'tcx>( tcx: TyCtxt<'tcx>, @@ -858,12 +843,7 @@ fn default_visibility(tcx: TyCtxt<'_>, id: DefId, is_generic: bool) -> Visibilit } } -fn debug_dump<'a, 'tcx: 'a>( - tcx: TyCtxt<'tcx>, - label: &str, - cgus: &[CodegenUnit<'tcx>], - (unique_inlined_items, unique_inlined_size): (usize, usize), -) { +fn debug_dump<'a, 'tcx: 'a>(tcx: TyCtxt<'tcx>, label: &str, cgus: &[CodegenUnit<'tcx>]) { let dump = move || { use std::fmt::Write; @@ -872,13 +852,17 @@ fn debug_dump<'a, 'tcx: 'a>( // Note: every unique root item is placed exactly once, so the number // of unique root items always equals the number of placed root items. + // + // Also, unreached inlined items won't be counted here. This is fine. + + let mut inlined_items = FxHashSet::default(); let mut root_items = 0; - // unique_inlined_items is passed in above. + let mut unique_inlined_items = 0; let mut placed_inlined_items = 0; let mut root_size = 0; - // unique_inlined_size is passed in above. + let mut unique_inlined_size = 0; let mut placed_inlined_size = 0; for cgu in cgus.iter() { @@ -892,6 +876,10 @@ fn debug_dump<'a, 'tcx: 'a>( root_size += data.size_estimate; } InstantiationMode::LocalCopy => { + if inlined_items.insert(item) { + unique_inlined_items += 1; + unique_inlined_size += data.size_estimate; + } placed_inlined_items += 1; placed_inlined_size += data.size_estimate; } From f4c46025646536123f570001cc322549a1623d7f Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 14 Jul 2023 17:38:11 +1000 Subject: [PATCH 04/45] Remove `instance_def_size_estimate` query. It doesn't seem worthwhile now that `MonoItem::size_estimate` is called much less often. --- compiler/rustc_middle/src/mir/mono.rs | 17 ++++++++++++----- compiler/rustc_middle/src/query/mod.rs | 6 ------ compiler/rustc_ty_utils/src/ty.rs | 17 ----------------- 3 files changed, 12 insertions(+), 28 deletions(-) diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs index a71c95d30ccbc..616a23ae6bfcc 100644 --- a/compiler/rustc_middle/src/mir/mono.rs +++ b/compiler/rustc_middle/src/mir/mono.rs @@ -59,12 +59,19 @@ impl<'tcx> MonoItem<'tcx> { pub fn size_estimate(&self, tcx: TyCtxt<'tcx>) -> usize { match *self { MonoItem::Fn(instance) => { - // Estimate the size of a function based on how many statements - // it contains. - tcx.instance_def_size_estimate(instance.def) + match instance.def { + // "Normal" functions size estimate: the number of + // statements, plus one for the terminator. + InstanceDef::Item(..) | InstanceDef::DropGlue(..) => { + let mir = tcx.instance_mir(instance.def); + mir.basic_blocks.iter().map(|bb| bb.statements.len() + 1).sum() + } + // Other compiler-generated shims size estimate: 1 + _ => 1, + } } - // Conservatively estimate the size of a static declaration - // or assembly to be 1. + // Conservatively estimate the size of a static declaration or + // assembly item to be 1. MonoItem::Static(_) | MonoItem::GlobalAsm(_) => 1, } } diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index a059590e6ad23..cf9745844d6df 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -2080,12 +2080,6 @@ rustc_queries! { desc { "looking up supported target features" } } - /// Get an estimate of the size of an InstanceDef based on its MIR for CGU partitioning. - query instance_def_size_estimate(def: ty::InstanceDef<'tcx>) - -> usize { - desc { |tcx| "estimating size for `{}`", tcx.def_path_str(def.def_id()) } - } - query features_query(_: ()) -> &'tcx rustc_feature::Features { feedable desc { "looking up enabled feature gates" } diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs index 6e5c50492c696..6e1b019bb8da2 100644 --- a/compiler/rustc_ty_utils/src/ty.rs +++ b/compiler/rustc_ty_utils/src/ty.rs @@ -317,22 +317,6 @@ fn param_env_reveal_all_normalized(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamE tcx.param_env(def_id).with_reveal_all_normalized(tcx) } -fn instance_def_size_estimate<'tcx>( - tcx: TyCtxt<'tcx>, - instance_def: ty::InstanceDef<'tcx>, -) -> usize { - use ty::InstanceDef; - - match instance_def { - InstanceDef::Item(..) | InstanceDef::DropGlue(..) => { - let mir = tcx.instance_mir(instance_def); - mir.basic_blocks.iter().map(|bb| bb.statements.len() + 1).sum() - } - // Estimate the size of other compiler-generated shims to be 1. - _ => 1, - } -} - /// If `def_id` is an issue 33140 hack impl, returns its self type; otherwise, returns `None`. /// /// See [`ty::ImplOverlapKind::Issue33140`] for more details. @@ -440,7 +424,6 @@ pub fn provide(providers: &mut Providers) { adt_sized_constraint, param_env, param_env_reveal_all_normalized, - instance_def_size_estimate, issue33140_self_ty, defaultness, unsizing_params_for_adt, From 2a30038bf12f923581ca0a878648bc6694d4a36a Mon Sep 17 00:00:00 2001 From: Jacob Pratt Date: Sat, 9 Jul 2022 17:21:26 -0400 Subject: [PATCH 05/45] Introduce restrictions to the AST --- compiler/rustc_ast/src/ast.rs | 31 +++++++++++++++++++ compiler/rustc_ast/src/ast_traits.rs | 18 +++++++++-- compiler/rustc_ast/src/mut_visit.rs | 12 +++++++ compiler/rustc_ast/src/visit.rs | 9 ++++++ compiler/rustc_ast_pretty/src/pprust/state.rs | 4 +++ .../rustc_ast_pretty/src/pprust/state/item.rs | 17 ++++++++++ 6 files changed, 88 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index a7198fbf88768..f3d6ba31f46bf 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -2721,6 +2721,37 @@ impl VisibilityKind { } } +#[derive(Clone, Encodable, Decodable, Debug)] +pub struct Restriction { + pub kind: RestrictionKind, + pub span: Span, +} + +#[derive(Clone, Encodable, Decodable, Debug)] +pub enum RestrictionKind { + Unrestricted, + Restricted { path: P, id: NodeId }, + Implied, +} + +impl Restriction { + pub fn unrestricted() -> Self { + Restriction { kind: RestrictionKind::Unrestricted, span: DUMMY_SP } + } + + pub fn restricted(path: P, id: NodeId) -> Self { + Restriction { kind: RestrictionKind::Restricted { path, id }, span: DUMMY_SP } + } + + pub fn implied() -> Self { + Restriction { kind: RestrictionKind::Implied, span: DUMMY_SP } + } + + pub fn with_span(self, span: Span) -> Self { + Restriction { span, ..self } + } +} + /// Field definition in a struct, variant or union. /// /// E.g., `bar: usize` as in `struct Foo { bar: usize }`. diff --git a/compiler/rustc_ast/src/ast_traits.rs b/compiler/rustc_ast/src/ast_traits.rs index 4dc9c30a2c807..23a5d3a781f81 100644 --- a/compiler/rustc_ast/src/ast_traits.rs +++ b/compiler/rustc_ast/src/ast_traits.rs @@ -7,7 +7,7 @@ use crate::token::Nonterminal; use crate::tokenstream::LazyAttrTokenStream; use crate::{Arm, Crate, ExprField, FieldDef, GenericParam, Param, PatField, Variant}; use crate::{AssocItem, Expr, ForeignItem, Item, NodeId}; -use crate::{AttrItem, AttrKind, Block, Pat, Path, Ty, Visibility}; +use crate::{AttrItem, AttrKind, Block, Pat, Path, Restriction, Ty, Visibility}; use crate::{AttrVec, Attribute, Stmt, StmtKind}; use rustc_span::Span; @@ -108,7 +108,19 @@ macro_rules! impl_has_span { }; } -impl_has_span!(AssocItem, Block, Expr, ForeignItem, Item, Pat, Path, Stmt, Ty, Visibility); +impl_has_span!( + AssocItem, + Block, + Expr, + ForeignItem, + Item, + Pat, + Path, + Stmt, + Ty, + Visibility, + Restriction, +); impl> HasSpan for T { fn span(&self) -> Span { @@ -324,7 +336,7 @@ impl_has_attrs!( PatField, Variant, ); -impl_has_attrs_none!(Attribute, AttrItem, Block, Pat, Path, Ty, Visibility); +impl_has_attrs_none!(Attribute, AttrItem, Block, Pat, Path, Ty, Visibility, Restriction); impl> HasAttrs for T { const SUPPORTS_CUSTOM_INNER_ATTRS: bool = T::Target::SUPPORTS_CUSTOM_INNER_ATTRS; diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 53a9c9a046ea0..0f8f4993bf5c4 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -278,6 +278,10 @@ pub trait MutVisitor: Sized { noop_visit_vis(vis, self); } + fn visit_restriction(&mut self, restriction: &mut Restriction) { + noop_visit_restriction(restriction, self); + } + fn visit_id(&mut self, _id: &mut NodeId) { // Do nothing. } @@ -1554,6 +1558,14 @@ pub fn noop_visit_vis(visibility: &mut Visibility, vis: &mut T) { vis.visit_span(&mut visibility.span); } +pub fn noop_visit_restriction(restriction: &mut Restriction, vis: &mut T) { + if let RestrictionKind::Restricted { path, id } = &mut restriction.kind { + vis.visit_path(path); + vis.visit_id(id); + } + vis.visit_span(&mut restriction.span); +} + /// Some value for the AST node that is valid but possibly meaningless. pub trait DummyAstNode { fn dummy() -> Self; diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index d9de5b8e197db..a404c09d60312 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -227,6 +227,9 @@ pub trait Visitor<'ast>: Sized { fn visit_vis(&mut self, vis: &'ast Visibility) { walk_vis(self, vis) } + fn visit_restriction(&mut self, restriction: &'ast Restriction) { + walk_restriction(self, restriction) + } fn visit_fn_ret_ty(&mut self, ret_ty: &'ast FnRetTy) { walk_fn_ret_ty(self, ret_ty) } @@ -949,6 +952,12 @@ pub fn walk_vis<'a, V: Visitor<'a>>(visitor: &mut V, vis: &'a Visibility) { } } +pub fn walk_restriction<'a, V: Visitor<'a>>(visitor: &mut V, restriction: &'a Restriction) { + if let RestrictionKind::Restricted { ref path, id } = restriction.kind { + visitor.visit_path(path, id); + } +} + pub fn walk_attribute<'a, V: Visitor<'a>>(visitor: &mut V, attr: &'a Attribute) { match &attr.kind { AttrKind::Normal(normal) => walk_attr_args(visitor, &normal.item.args), diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index 59239b49eddd8..e61ea3aa28f87 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -883,6 +883,10 @@ pub trait PrintState<'a>: std::ops::Deref + std::ops::Dere Self::to_string(|s| s.print_visibility(v)) } + fn restriction_to_string(&self, kw: &'static str, restriction: &ast::Restriction) -> String { + Self::to_string(|s| s.print_restriction(kw, restriction)) + } + fn block_to_string(&self, blk: &ast::Block) -> String { Self::to_string(|s| { // Containing cbox, will be closed by `print_block` at `}`. diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs index 5c01b7ea70a13..dd5178f17abaf 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/item.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs @@ -428,6 +428,23 @@ impl<'a> State<'a> { } } + // FIXME(jhpratt) make `kw` into a const generic when #![feature(adt_consts_params)] is no + // longer incomplete + pub(crate) fn print_restriction(&mut self, kw: &'static str, restriction: &ast::Restriction) { + match restriction.kind { + ast::RestrictionKind::Unrestricted => self.word_nbsp(kw), + ast::RestrictionKind::Restricted { ref path, .. } => { + let path = Self::to_string(|s| s.print_path(path, false, 0)); + if path == "crate" || path == "self" || path == "super" { + self.word_nbsp(format!("{kw}({path})")) + } else { + self.word_nbsp(format!("{kw}(in {path})")) + } + } + ast::RestrictionKind::Implied => {} + } + } + fn print_defaultness(&mut self, defaultness: ast::Defaultness) { if let ast::Defaultness::Default(_) = defaultness { self.word_nbsp("default"); From 49cd517ab27e4544280e8778864da7e63bc465ae Mon Sep 17 00:00:00 2001 From: Jacob Pratt Date: Sat, 9 Jul 2022 17:33:17 -0400 Subject: [PATCH 06/45] Parse `impl` restriction on trait definitions --- compiler/rustc_ast/src/ast.rs | 1 + compiler/rustc_ast/src/mut_visit.rs | 10 ++- compiler/rustc_ast/src/visit.rs | 10 ++- compiler/rustc_ast_lowering/src/item.rs | 9 +- .../rustc_ast_pretty/src/pprust/state/item.rs | 2 + compiler/rustc_parse/src/parser/item.rs | 65 ++++++++++++--- compiler/rustc_parse/src/parser/mod.rs | 82 ++++++++++++++++++- .../clippy/clippy_utils/src/ast_utils.rs | 2 + src/tools/rustfmt/src/items.rs | 1 + 9 files changed, 168 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index f3d6ba31f46bf..e23396f26fd20 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -2900,6 +2900,7 @@ impl Default for FnHeader { #[derive(Clone, Encodable, Decodable, Debug)] pub struct Trait { + pub impl_restriction: Restriction, pub unsafety: Unsafe, pub is_auto: IsAuto, pub generics: Generics, diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 0f8f4993bf5c4..3bc9433a0207d 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -1096,7 +1096,15 @@ pub fn noop_visit_item_kind(kind: &mut ItemKind, vis: &mut T) { vis.visit_ty(self_ty); items.flat_map_in_place(|item| vis.flat_map_impl_item(item)); } - ItemKind::Trait(box Trait { unsafety, is_auto: _, generics, bounds, items }) => { + ItemKind::Trait(box Trait { + impl_restriction, + unsafety, + is_auto: _, + generics, + bounds, + items, + }) => { + noop_visit_restriction(impl_restriction, vis); visit_unsafety(unsafety, vis); vis.visit_generics(generics); visit_bounds(bounds, vis); diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index a404c09d60312..27a6c0792e5d7 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -360,10 +360,18 @@ pub fn walk_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a Item) { visitor.visit_generics(generics); visitor.visit_variant_data(struct_definition); } - ItemKind::Trait(box Trait { unsafety: _, is_auto: _, generics, bounds, items }) => { + ItemKind::Trait(box Trait { + impl_restriction, + unsafety: _, + is_auto: _, + generics, + bounds, + items, + }) => { visitor.visit_generics(generics); walk_list!(visitor, visit_param_bound, bounds, BoundKind::SuperTraits); walk_list!(visitor, visit_assoc_item, items, AssocCtxt::Trait); + visitor.visit_restriction(impl_restriction); } ItemKind::TraitAlias(generics, bounds) => { visitor.visit_generics(generics); diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index ab68436c0939d..8263939f1ede5 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -415,7 +415,14 @@ impl<'hir> LoweringContext<'_, 'hir> { items: new_impl_items, })) } - ItemKind::Trait(box Trait { is_auto, unsafety, generics, bounds, items }) => { + ItemKind::Trait(box Trait { + impl_restriction: _, + is_auto, + unsafety, + generics, + bounds, + items, + }) => { // FIXME(const_trait_impl, effects, fee1-dead) this should be simplified if possible let constness = attrs .unwrap_or(&[]) diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs index dd5178f17abaf..fffe4062ace43 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/item.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs @@ -314,6 +314,7 @@ impl<'a> State<'a> { self.bclose(item.span, empty); } ast::ItemKind::Trait(box ast::Trait { + impl_restriction, is_auto, unsafety, generics, @@ -323,6 +324,7 @@ impl<'a> State<'a> { }) => { self.head(""); self.print_visibility(&item.vis); + self.print_restriction("impl", impl_restriction); self.print_unsafety(*unsafety); self.print_is_auto(*is_auto); self.word_nbsp("trait"); diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 1470180dea714..6d388dbc7c704 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -239,7 +239,7 @@ impl<'a> Parser<'a> { let (ident, ty, expr) = self.parse_item_global(None)?; (ident, ItemKind::Const(Box::new(ConstItem { defaultness: def_(), ty, expr }))) } - } else if self.check_keyword(kw::Trait) || self.check_auto_or_unsafe_trait_item() { + } else if self.check_keyword(kw::Trait) || self.is_trait_item_with_modifiers() { // TRAIT ITEM self.parse_item_trait(attrs, lo)? } else if self.check_keyword(kw::Impl) @@ -344,7 +344,7 @@ impl<'a> Parser<'a> { /// When parsing a statement, would the start of a path be an item? pub(super) fn is_path_start_item(&mut self) -> bool { self.is_kw_followed_by_ident(kw::Union) // no: `union::b`, yes: `union U { .. }` - || self.check_auto_or_unsafe_trait_item() // no: `auto::b`, yes: `auto trait X { .. }` + || self.is_trait_item_with_modifiers() // no: `auto::b`, yes: `auto trait X { .. }` || self.is_async_fn() // no(2015): `async::b`, yes: `async fn` || matches!(self.is_macro_rules_item(), IsMacroRulesItem::Yes{..}) // no: `macro_rules::b`, yes: `macro_rules! mac` } @@ -789,16 +789,50 @@ impl<'a> Parser<'a> { } } - /// Is this an `(unsafe auto? | auto) trait` item? - fn check_auto_or_unsafe_trait_item(&mut self) -> bool { - // auto trait - self.check_keyword(kw::Auto) && self.is_keyword_ahead(1, &[kw::Trait]) - // unsafe auto trait - || self.check_keyword(kw::Unsafe) && self.is_keyword_ahead(1, &[kw::Trait, kw::Auto]) + /// Is this item an unsafe trait, an auto trait, have an impl restriction, + /// or any combination thereof? + fn is_trait_item_with_modifiers(&mut self) -> bool { + let current_token = TokenTree::Token(self.token.clone(), self.token_spacing); + let look_ahead = |index| match index { + 0 => Some(¤t_token), + _ => self.token_cursor.tree_cursor.look_ahead(index - 1), + }; + + let mut has_impl_restriction = false; + let mut has_unsafe = false; + let mut has_auto = false; + let mut has_trait = false; + + let mut index = 0; + + if let Some(TokenTree::Token(token, _)) = look_ahead(index) && token.is_keyword(kw::Impl) { + has_impl_restriction = true; + index += 1; + } + if has_impl_restriction + && matches!(look_ahead(index), Some(TokenTree::Delimited(_, Delimiter::Parenthesis, _))) + { + index += 1; + } + if let Some(TokenTree::Token(token, _)) = look_ahead(index) && token.is_keyword(kw::Unsafe) { + has_unsafe = true; + index += 1; + } + if let Some(TokenTree::Token(token, _)) = look_ahead(index) && token.is_keyword(kw::Auto) { + has_auto = true; + index += 1; + } + if let Some(TokenTree::Token(token, _)) = look_ahead(index) && token.is_keyword(kw::Trait) { + has_trait = true; + } + + (has_impl_restriction || has_unsafe || has_auto) && has_trait } - /// Parses `unsafe? auto? trait Foo { ... }` or `trait Foo = Bar;`. + /// Parses `impl(in path)? unsafe? auto? trait Foo { ... }` or `trait Foo = Bar;`. fn parse_item_trait(&mut self, attrs: &mut AttrVec, lo: Span) -> PResult<'a, ItemInfo> { + let impl_restriction = + self.parse_restriction(kw::Impl, "implementable", FollowedByType::No)?; let unsafety = self.parse_unsafety(Case::Sensitive); // Parse optional `auto` prefix. let is_auto = if self.eat_keyword(kw::Auto) { IsAuto::Yes } else { IsAuto::No }; @@ -825,6 +859,10 @@ impl<'a> Parser<'a> { self.expect_semi()?; let whole_span = lo.to(self.prev_token.span); + if !matches!(impl_restriction.kind, RestrictionKind::Implied) { + let msg = "trait aliases cannot be implemented"; + self.struct_span_err(whole_span, msg).span_label(whole_span, msg).emit(); + } if is_auto == IsAuto::Yes { self.sess.emit_err(errors::TraitAliasCannotBeAuto { span: whole_span }); } @@ -841,7 +879,14 @@ impl<'a> Parser<'a> { let items = self.parse_item_list(attrs, |p| p.parse_trait_item(ForceCollect::No))?; Ok(( ident, - ItemKind::Trait(Box::new(Trait { is_auto, unsafety, generics, bounds, items })), + ItemKind::Trait(Box::new(Trait { + impl_restriction, + is_auto, + unsafety, + generics, + bounds, + items, + })), )) } } diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index e4d843b7c8bcc..48d4aa8e49b48 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -16,6 +16,7 @@ pub use diagnostics::AttemptLocalParseRecovery; pub(crate) use item::FnParseMode; pub use pat::{CommaRecoveryMode, RecoverColon, RecoverComma}; pub use path::PathStyle; +use rustc_errors::struct_span_err; use rustc_ast::ptr::P; use rustc_ast::token::{self, Delimiter, Nonterminal, Token, TokenKind}; @@ -26,7 +27,7 @@ use rustc_ast::AttrId; use rustc_ast::DUMMY_NODE_ID; use rustc_ast::{self as ast, AnonConst, AttrStyle, Const, DelimArgs, Extern}; use rustc_ast::{Async, AttrArgs, AttrArgsEq, Expr, ExprKind, MacDelimiter, Mutability, StrLit}; -use rustc_ast::{HasAttrs, HasTokens, Unsafe, Visibility, VisibilityKind}; +use rustc_ast::{HasAttrs, HasTokens, Restriction, Unsafe, Visibility, VisibilityKind}; use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync::Ordering; @@ -1458,6 +1459,85 @@ impl<'a> Parser<'a> { Ok(()) } + /// Parses `kw` and `kw(in path)` plus shortcuts `kw(crate)` for `kw(in crate)`, `kw(self)` for + /// `kw(in self)` and `kw(super)` for `kw(in super)`. + fn parse_restriction( + &mut self, + kw: Symbol, + action: &str, + fbt: FollowedByType, + ) -> PResult<'a, Restriction> { + if !self.eat_keyword(kw) { + // We need a span, but there's inherently no keyword to grab a span from for an implied + // restriction. An empty span at the beginning of the current token is a reasonable + // fallback. + return Ok(Restriction::implied().with_span(self.token.span.shrink_to_lo())); + } + + let lo = self.prev_token.span; + + if self.check(&token::OpenDelim(Delimiter::Parenthesis)) { + // We don't `self.bump()` the `(` yet because this might be a struct definition where + // `()` or a tuple might be allowed. For example, `struct Struct(kw (), kw (usize));`. + // Because of this, we only `bump` the `(` if we're assured it is appropriate to do so + // by the following tokens. + if self.is_keyword_ahead(1, &[kw::In]) { + // Parse `kw(in path)`. + self.bump(); // `(` + self.bump(); // `in` + let path = self.parse_path(PathStyle::Mod)?; // `path` + self.expect(&token::CloseDelim(Delimiter::Parenthesis))?; // `)` + return Ok(Restriction::restricted(P(path), ast::DUMMY_NODE_ID) + .with_span(lo.to(self.prev_token.span))); + } else if self.look_ahead(2, |t| t == &token::CloseDelim(Delimiter::Parenthesis)) + && self.is_keyword_ahead(1, &[kw::Crate, kw::Super, kw::SelfLower]) + { + // Parse `kw(crate)`, `kw(self)`, or `kw(super)`. + self.bump(); // `(` + let path = self.parse_path(PathStyle::Mod)?; // `crate`/`super`/`self` + self.expect(&token::CloseDelim(Delimiter::Parenthesis))?; // `)` + return Ok(Restriction::restricted(P(path), ast::DUMMY_NODE_ID) + .with_span(lo.to(self.prev_token.span))); + } else if let FollowedByType::No = fbt { + // Provide this diagnostic if a type cannot follow; + // in particular, if this is not a tuple struct. + self.recover_incorrect_restriction(kw.as_str(), action)?; + // Emit diagnostic, but continue unrestricted. + } + } + + Ok(Restriction::unrestricted().with_span(lo)) + } + + /// Recovery for e.g. `kw(something) fn ...` or `struct X { kw(something) y: Z }` + fn recover_incorrect_restriction(&mut self, kw: &str, action: &str) -> PResult<'a, ()> { + self.bump(); // `(` + let path = self.parse_path(PathStyle::Mod)?; + self.expect(&token::CloseDelim(Delimiter::Parenthesis))?; // `)` + + let msg = "incorrect restriction"; + let suggestion = format!( + r##"some possible restrictions are:\n\ + `{kw}(crate)`: {action} only on the current crate\n\ + `{kw}(super)`: {action} only in the current module's parent\n\ + `{kw}(in path::to::module)`: {action} only on the specified path"## + ); + + let path_str = pprust::path_to_string(&path); + + struct_span_err!(self.sess.span_diagnostic, path.span, E0704, "{msg}") + .help(suggestion) + .span_suggestion( + path.span, + format!("make this {action} only to module `{path_str}` with `in`"), + format!("in {path_str}"), + Applicability::MachineApplicable, + ) + .emit(); + + Ok(()) + } + /// Parses `extern string_literal?`. fn parse_extern(&mut self, case: Case) -> Extern { if self.eat_keyword_case(kw::Extern, case) { diff --git a/src/tools/clippy/clippy_utils/src/ast_utils.rs b/src/tools/clippy/clippy_utils/src/ast_utils.rs index 8cc01f1ef9740..52549f72c01ed 100644 --- a/src/tools/clippy/clippy_utils/src/ast_utils.rs +++ b/src/tools/clippy/clippy_utils/src/ast_utils.rs @@ -366,6 +366,7 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool { }, ( Trait(box ast::Trait { + impl_restriction: _, // does not affect item kind is_auto: la, unsafety: lu, generics: lg, @@ -373,6 +374,7 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool { items: li, }), Trait(box ast::Trait { + impl_restriction: _, is_auto: ra, unsafety: ru, generics: rg, diff --git a/src/tools/rustfmt/src/items.rs b/src/tools/rustfmt/src/items.rs index d5bc38303e004..f515ccc08ae4c 100644 --- a/src/tools/rustfmt/src/items.rs +++ b/src/tools/rustfmt/src/items.rs @@ -1120,6 +1120,7 @@ pub(crate) fn format_trait( ) -> Option { if let ast::ItemKind::Trait(trait_kind) = &item.kind { let ast::Trait { + impl_restriction: _, is_auto, unsafety, ref generics, From b35b97534568d1a4bd5dfbc45fd1f4a816cefe29 Mon Sep 17 00:00:00 2001 From: Jacob Pratt Date: Sat, 9 Jul 2022 17:36:29 -0400 Subject: [PATCH 07/45] rustfmt `impl` restriction --- src/tools/rustfmt/src/items.rs | 5 ++-- src/tools/rustfmt/src/utils.rs | 30 +++++++++++++++++-- src/tools/rustfmt/tests/source/restriction.rs | 13 ++++++++ src/tools/rustfmt/tests/target/restriction.rs | 5 ++++ 4 files changed, 49 insertions(+), 4 deletions(-) create mode 100644 src/tools/rustfmt/tests/source/restriction.rs create mode 100644 src/tools/rustfmt/tests/target/restriction.rs diff --git a/src/tools/rustfmt/src/items.rs b/src/tools/rustfmt/src/items.rs index f515ccc08ae4c..ce93693e65e6e 100644 --- a/src/tools/rustfmt/src/items.rs +++ b/src/tools/rustfmt/src/items.rs @@ -1120,7 +1120,7 @@ pub(crate) fn format_trait( ) -> Option { if let ast::ItemKind::Trait(trait_kind) = &item.kind { let ast::Trait { - impl_restriction: _, + ref impl_restriction, is_auto, unsafety, ref generics, @@ -1129,8 +1129,9 @@ pub(crate) fn format_trait( } = **trait_kind; let mut result = String::with_capacity(128); let header = format!( - "{}{}{}trait ", + "{}{}{}{}trait ", format_visibility(context, &item.vis), + format_restriction("impl", context, &impl_restriction), format_unsafety(unsafety), format_auto(is_auto), ); diff --git a/src/tools/rustfmt/src/utils.rs b/src/tools/rustfmt/src/utils.rs index 890a05b8c8259..ca08552f0650f 100644 --- a/src/tools/rustfmt/src/utils.rs +++ b/src/tools/rustfmt/src/utils.rs @@ -1,8 +1,8 @@ use std::borrow::Cow; use rustc_ast::ast::{ - self, Attribute, MetaItem, MetaItemKind, NestedMetaItem, NodeId, Path, Visibility, - VisibilityKind, + self, Attribute, MetaItem, MetaItemKind, NestedMetaItem, NodeId, Path, Restriction, + RestrictionKind, Visibility, VisibilityKind, }; use rustc_ast::ptr; use rustc_ast_pretty::pprust; @@ -74,6 +74,32 @@ pub(crate) fn format_visibility( } } +// Does not allocate in the common, implied case. +pub(crate) fn format_restriction( + kw: &'static str, + context: &RewriteContext<'_>, + restriction: &Restriction, +) -> String { + match restriction.kind { + RestrictionKind::Unrestricted => format!("{kw} "), + RestrictionKind::Restricted { ref path, .. } => { + let Path { ref segments, .. } = **path; + let mut segments_iter = segments.iter().map(|seg| rewrite_ident(context, seg.ident)); + if path.is_global() && segments_iter.next().is_none() { + panic!("non-global path in {kw}(restricted)?"); + } + let is_keyword = |s| s == "crate" || s == "self" || s == "super"; + // FIXME use `segments_iter.intersperse("::").collect::()` once + // `#![feature(iter_intersperse)]` is re-stabilized. + let path = itertools::join(segments_iter, "::"); + let in_str = if is_keyword(&path) { "" } else { "in " }; + + format!("{kw}({in_str}{path}) ") + } + RestrictionKind::Implied => String::new(), + } +} + #[inline] pub(crate) fn format_async(is_async: &ast::Async) -> &'static str { match is_async { diff --git a/src/tools/rustfmt/tests/source/restriction.rs b/src/tools/rustfmt/tests/source/restriction.rs new file mode 100644 index 0000000000000..648c2982cb935 --- /dev/null +++ b/src/tools/rustfmt/tests/source/restriction.rs @@ -0,0 +1,13 @@ +pub +impl(crate) +trait Foo {} + +pub +impl +trait Bar {} + +pub +impl ( in foo +:: +bar ) +trait Baz {} diff --git a/src/tools/rustfmt/tests/target/restriction.rs b/src/tools/rustfmt/tests/target/restriction.rs new file mode 100644 index 0000000000000..81dad02a21180 --- /dev/null +++ b/src/tools/rustfmt/tests/target/restriction.rs @@ -0,0 +1,5 @@ +pub impl(crate) trait Foo {} + +pub impl trait Bar {} + +pub impl(in foo::bar) trait Baz {} From a89c30326d13133c8fdb9731b3dea19b7aa19326 Mon Sep 17 00:00:00 2001 From: Jacob Pratt Date: Sat, 9 Jul 2022 18:56:23 -0400 Subject: [PATCH 08/45] Lower `impl` restriction to `rustc_middle` --- compiler/rustc_middle/src/hir/map/mod.rs | 3 +- compiler/rustc_middle/src/ty/mod.rs | 31 ++++++ compiler/rustc_resolve/messages.ftl | 12 +++ .../rustc_resolve/src/build_reduced_graph.rs | 98 ++++++++++++++++++- compiler/rustc_resolve/src/diagnostics.rs | 38 ++++++- compiler/rustc_resolve/src/errors.rs | 22 +++++ compiler/rustc_resolve/src/lib.rs | 13 +++ 7 files changed, 213 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index 1fd68dc5cb28e..1323c972e8c60 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -1220,9 +1220,10 @@ pub(super) fn crate_hash(tcx: TyCtxt<'_>, _: LocalCrate) -> Svh { } tcx.sess.opts.dep_tracking_hash(true).hash_stable(&mut hcx, &mut stable_hasher); tcx.sess.local_stable_crate_id().hash_stable(&mut hcx, &mut stable_hasher); - // Hash visibility information since it does not appear in HIR. + // Hash visibility and restriction information since it does not appear in HIR. resolutions.visibilities.hash_stable(&mut hcx, &mut stable_hasher); resolutions.has_pub_restricted.hash_stable(&mut hcx, &mut stable_hasher); + resolutions.impl_restrictions.hash_stable(&mut hcx, &mut stable_hasher); stable_hasher.finish() }); diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 0411890ab5139..f0ac63b987272 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -162,6 +162,7 @@ pub struct ResolverOutputs { #[derive(Debug)] pub struct ResolverGlobalCtxt { pub visibilities: FxHashMap, + pub impl_restrictions: FxHashMap, /// This field is used to decide whether we should make `PRIVATE_IN_PUBLIC` a hard error. pub has_pub_restricted: bool, /// Item with a given `LocalDefId` was defined during macro expansion with ID `ExpnId`. @@ -290,6 +291,36 @@ pub enum Visibility { Restricted(Id), } +#[derive(Clone, Debug, PartialEq, Eq, Copy, Hash, Encodable, Decodable, HashStable)] +pub enum Restriction { + /// The restriction does not affect the item. + Unrestricted, + /// The restriction only applies outside of this path. + Restricted(DefId, Span), +} + +impl Restriction { + /// Returns `true` if this restriction applies in the given module. This + /// means the behavior is _not_ allowed. + pub fn is_restricted_in(self, module: DefId, tcx: TyCtxt<'_>) -> bool { + let restricted_to = match self { + Restriction::Unrestricted => return false, + Restriction::Restricted(other, _) if other.krate != module.krate => return false, + Restriction::Restricted(module, _) => module, + }; + + !tcx.is_descendant_of(module, restricted_to) + } + + /// Obtain the [`Span`] of the restriction. Panics if the restriction is unrestricted. + pub fn expect_span(&self) -> Span { + match self { + Restriction::Unrestricted => bug!("called `expect_span` on an unrestricted item"), + Restriction::Restricted(_, span) => *span, + } + } +} + #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable, TyEncodable, TyDecodable)] pub enum BoundConstness { /// `T: Trait` diff --git a/compiler/rustc_resolve/messages.ftl b/compiler/rustc_resolve/messages.ftl index f98918cba8800..a076a8f27fec0 100644 --- a/compiler/rustc_resolve/messages.ftl +++ b/compiler/rustc_resolve/messages.ftl @@ -221,6 +221,18 @@ resolve_relative_2018 = resolve_remove_surrounding_derive = remove from the surrounding `derive()` +resolve_restriction_ancestor_only = + restrictions can only be restricted to ancestor modules + +resolve_restriction_indeterminate = + cannot determine resolution for the restriction + +resolve_restriction_module_only = + restriction must resolve to a module +resolve_restriction_relative_2018 = + relative paths are not supported in restrictions in 2018 edition or later + .suggestion = try + resolve_self_import_can_only_appear_once_in_the_list = `self` import can only appear once in an import list .label = can only appear once in an import list diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index ff63e4e33cb9d..8562c458a95e5 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -12,7 +12,8 @@ use crate::Namespace::{self, MacroNS, TypeNS, ValueNS}; use crate::{errors, BindingKey, MacroData, NameBindingData}; use crate::{Determinacy, ExternPreludeEntry, Finalize, Module, ModuleKind, ModuleOrUniformRoot}; use crate::{NameBinding, NameBindingKind, ParentScope, PathResult, PerNS, ResolutionError}; -use crate::{Resolver, ResolverArenas, Segment, ToNameBinding, VisResolutionError}; +use crate::{Resolver, ResolverArenas, Segment, ToNameBinding}; +use crate::{RestrictionResolutionError, VisResolutionError}; use rustc_ast::visit::{self, AssocCtxt, Visitor}; use rustc_ast::{self as ast, AssocItem, AssocItemKind, MetaItemKind, StmtKind}; @@ -324,6 +325,96 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { self.r.field_def_ids.insert(def_id, self.r.tcx.arena.alloc_from_iter(def_ids)); } + fn resolve_restriction(&mut self, restriction: &ast::Restriction) -> ty::Restriction { + self.try_resolve_restriction(restriction, true).unwrap_or_else(|err| { + self.r.report_restriction_error(err); + ty::Restriction::Unrestricted + }) + } + + fn try_resolve_restriction<'ast>( + &mut self, + restriction: &'ast ast::Restriction, + finalize: bool, + ) -> Result> { + let parent_scope = &self.parent_scope; + match restriction.kind { + // If the restriction is implied, it has no effect when the item is otherwise visible. + ast::RestrictionKind::Unrestricted | ast::RestrictionKind::Implied => { + Ok(ty::Restriction::Unrestricted) + } + ast::RestrictionKind::Restricted { ref path, id } => { + // For restrictions we are not ready to provide correct implementation of "uniform + // paths" right now, so on 2018 edition we only allow module-relative paths for now. + // On 2015 edition visibilities are resolved as crate-relative by default, + // so we are prepending a root segment if necessary. + let ident = path.segments.get(0).expect("empty path in restriction").ident; + let crate_root = if ident.is_path_segment_keyword() { + None + } else if ident.span.is_rust_2015() { + Some(Segment::from_ident(Ident::new( + kw::PathRoot, + path.span.shrink_to_lo().with_ctxt(ident.span.ctxt()), + ))) + } else { + return Err(RestrictionResolutionError::Relative2018(ident.span, path)); + }; + + let segments = crate_root + .into_iter() + .chain(path.segments.iter().map(|seg| seg.into())) + .collect::>(); + let expected_found_error = |res| { + Err(RestrictionResolutionError::ExpectedFound( + path.span, + Segment::names_to_string(&segments), + res, + )) + }; + match self.r.resolve_path( + &segments, + Some(TypeNS), + parent_scope, + finalize.then(|| Finalize::new(id, path.span)), + None, + ) { + PathResult::Module(ModuleOrUniformRoot::Module(module)) => { + let res = module.res().expect("restriction resolved to unnamed block"); + if finalize { + self.r.record_partial_res(id, PartialRes::new(res)); + } + if module.is_normal() { + if res == Res::Err { + Ok(ty::Restriction::Unrestricted) + } else { + let vis = ty::Visibility::Restricted(res.def_id()); + if self.r.is_accessible_from(vis, parent_scope.module) { + Ok(ty::Restriction::Restricted(res.def_id(), restriction.span)) + } else { + Err(RestrictionResolutionError::AncestorOnly(path.span)) + } + } + } else { + expected_found_error(res) + } + } + PathResult::Module(..) => { + Err(RestrictionResolutionError::ModuleOnly(path.span)) + } + PathResult::NonModule(partial_res) => { + expected_found_error(partial_res.base_res()) + } + PathResult::Failed { span, label, suggestion, .. } => { + Err(RestrictionResolutionError::FailedToResolve(span, label, suggestion)) + } + PathResult::Indeterminate => { + Err(RestrictionResolutionError::Indeterminate(path.span)) + } + } + } + } + } + fn insert_field_visibilities_local(&mut self, def_id: DefId, vdata: &ast::VariantData) { let field_vis = vdata .fields() @@ -779,7 +870,10 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { self.insert_field_visibilities_local(def_id, vdata); } - ItemKind::Trait(..) => { + ItemKind::Trait(ref trait_def) => { + let impl_restriction = self.resolve_restriction(&trait_def.impl_restriction); + self.r.impl_restrictions.insert(local_def_id, impl_restriction); + // Add all the items within to a new module. let module = self.r.new_module( Some(parent), diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index d3dcdfa427542..d753255a46331 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -38,7 +38,10 @@ use crate::path_names_to_string; use crate::{errors as errs, BindingKey}; use crate::{AmbiguityError, AmbiguityErrorMisc, AmbiguityKind, BindingError, Finalize}; use crate::{HasGenericParams, MacroRulesScope, Module, ModuleKind, ModuleOrUniformRoot}; -use crate::{LexicalScopeBinding, NameBinding, NameBindingKind, PrivacyError, VisResolutionError}; +use crate::{ + LexicalScopeBinding, NameBinding, NameBindingKind, PrivacyError, RestrictionResolutionError, + VisResolutionError, +}; use crate::{ParentScope, PathResult, ResolutionError, Resolver, Scope, ScopeSet}; use crate::{Segment, UseError}; @@ -999,6 +1002,39 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { .emit() } + pub(crate) fn report_restriction_error( + &mut self, + vis_resolution_error: RestrictionResolutionError<'_>, + ) -> ErrorGuaranteed { + match vis_resolution_error { + RestrictionResolutionError::Relative2018(span, path) => { + self.tcx.sess.create_err(errs::RestrictionRelative2018 { + span, + path_span: path.span, + // intentionally converting to String, as the text would also be used as + // in suggestion context + path_str: pprust::path_to_string(&path), + }) + } + RestrictionResolutionError::AncestorOnly(span) => { + self.tcx.sess.create_err(errs::RestrictionAncestorOnly(span)) + } + RestrictionResolutionError::FailedToResolve(span, label, suggestion) => { + self.into_struct_error(span, ResolutionError::FailedToResolve { label, suggestion }) + } + RestrictionResolutionError::ExpectedFound(span, path_str, res) => { + self.tcx.sess.create_err(errs::ExpectedFound { span, res, path_str }) + } + RestrictionResolutionError::Indeterminate(span) => { + self.tcx.sess.create_err(errs::RestrictionIndeterminate(span)) + } + RestrictionResolutionError::ModuleOnly(span) => { + self.tcx.sess.create_err(errs::RestrictionModuleOnly(span)) + } + } + .emit() + } + /// Lookup typo candidate in scope for a macro or import. fn early_lookup_typo_candidate( &mut self, diff --git a/compiler/rustc_resolve/src/errors.rs b/compiler/rustc_resolve/src/errors.rs index e4b89c65853d0..0a2edbf9bcea1 100644 --- a/compiler/rustc_resolve/src/errors.rs +++ b/compiler/rustc_resolve/src/errors.rs @@ -727,3 +727,25 @@ pub(crate) struct IsNotDirectlyImportable { pub(crate) span: Span, pub(crate) target: Ident, } + +#[derive(Diagnostic)] +#[diag(resolve_restriction_relative_2018)] +pub(crate) struct RestrictionRelative2018 { + #[primary_span] + pub(crate) span: Span, + #[suggestion(code = "crate::{path_str}", applicability = "maybe-incorrect")] + pub(crate) path_span: Span, + pub(crate) path_str: String, +} + +#[derive(Diagnostic)] +#[diag(resolve_restriction_ancestor_only, code = "E0742")] +pub(crate) struct RestrictionAncestorOnly(#[primary_span] pub(crate) Span); + +#[derive(Diagnostic)] +#[diag(resolve_restriction_indeterminate, code = "E0578")] +pub(crate) struct RestrictionIndeterminate(#[primary_span] pub(crate) Span); + +#[derive(Diagnostic)] +#[diag(resolve_restriction_module_only)] +pub(crate) struct RestrictionModuleOnly(#[primary_span] pub(crate) Span); diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index faa672db59ccf..ba6494d57e382 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -275,6 +275,15 @@ enum VisResolutionError<'a> { ModuleOnly(Span), } +enum RestrictionResolutionError<'a> { + Relative2018(Span, &'a ast::Path), + AncestorOnly(Span), + FailedToResolve(Span, String, Option), + ExpectedFound(Span, String, Res), + Indeterminate(Span), + ModuleOnly(Span), +} + /// A minimal representation of a path segment. We use this in resolve because we synthesize 'path /// segments' which don't have the rest of an AST or HIR `PathSegment`. #[derive(Clone, Copy, Debug)] @@ -971,6 +980,7 @@ pub struct Resolver<'a, 'tcx> { /// Visibilities in "lowered" form, for all entities that have them. visibilities: FxHashMap, has_pub_restricted: bool, + impl_restrictions: FxHashMap, used_imports: FxHashSet, maybe_unused_trait_imports: FxIndexSet, @@ -1309,6 +1319,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { glob_map: Default::default(), visibilities, + impl_restrictions: FxHashMap::default(), has_pub_restricted: false, used_imports: FxHashSet::default(), maybe_unused_trait_imports: Default::default(), @@ -1424,6 +1435,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { let proc_macros = self.proc_macros.iter().map(|id| self.local_def_id(*id)).collect(); let expn_that_defined = self.expn_that_defined; let visibilities = self.visibilities; + let impl_restrictions = self.impl_restrictions; let has_pub_restricted = self.has_pub_restricted; let extern_crate_map = self.extern_crate_map; let maybe_unused_trait_imports = self.maybe_unused_trait_imports; @@ -1442,6 +1454,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { let global_ctxt = ResolverGlobalCtxt { expn_that_defined, visibilities, + impl_restrictions, has_pub_restricted, effective_visibilities, extern_crate_map, From c938764ba20ab6b1fa229887df0749863ab81633 Mon Sep 17 00:00:00 2001 From: Jacob Pratt Date: Sat, 9 Jul 2022 19:11:43 -0400 Subject: [PATCH 09/45] Error in implementation of restricted trait --- Cargo.lock | 16 +++++ compiler/rustc_driver_impl/Cargo.toml | 1 + compiler/rustc_driver_impl/src/lib.rs | 1 + compiler/rustc_interface/Cargo.toml | 1 + compiler/rustc_interface/src/passes.rs | 4 ++ compiler/rustc_middle/src/query/erase.rs | 1 + compiler/rustc_middle/src/query/mod.rs | 8 +++ compiler/rustc_restrictions/Cargo.toml | 14 ++++ compiler/rustc_restrictions/messages.ftl | 2 + compiler/rustc_restrictions/src/errors.rs | 11 +++ .../src/impl_restriction.rs | 68 +++++++++++++++++++ compiler/rustc_restrictions/src/lib.rs | 16 +++++ tests/ui/restrictions/impl-restriction.rs | 11 +++ tests/ui/restrictions/impl-restriction.stderr | 14 ++++ 14 files changed, 168 insertions(+) create mode 100644 compiler/rustc_restrictions/Cargo.toml create mode 100644 compiler/rustc_restrictions/messages.ftl create mode 100644 compiler/rustc_restrictions/src/errors.rs create mode 100644 compiler/rustc_restrictions/src/impl_restriction.rs create mode 100644 compiler/rustc_restrictions/src/lib.rs create mode 100644 tests/ui/restrictions/impl-restriction.rs create mode 100644 tests/ui/restrictions/impl-restriction.stderr diff --git a/Cargo.lock b/Cargo.lock index 9f1561b503d8e..330791691b219 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3490,6 +3490,7 @@ dependencies = [ "rustc_privacy", "rustc_query_system", "rustc_resolve", + "rustc_restrictions", "rustc_session", "rustc_span", "rustc_symbol_mangling", @@ -3777,6 +3778,7 @@ dependencies = [ "rustc_query_impl", "rustc_query_system", "rustc_resolve", + "rustc_restrictions", "rustc_session", "rustc_span", "rustc_symbol_mangling", @@ -4189,6 +4191,20 @@ dependencies = [ "tracing", ] +[[package]] +name = "rustc_restrictions" +version = "0.0.0" +dependencies = [ + "rustc_errors", + "rustc_fluent_macro", + "rustc_hir", + "rustc_macros", + "rustc_middle", + "rustc_session", + "rustc_span", + "tracing", +] + [[package]] name = "rustc_serialize" version = "0.0.0" diff --git a/compiler/rustc_driver_impl/Cargo.toml b/compiler/rustc_driver_impl/Cargo.toml index 67352c55c9019..e755285ba643f 100644 --- a/compiler/rustc_driver_impl/Cargo.toml +++ b/compiler/rustc_driver_impl/Cargo.toml @@ -28,6 +28,7 @@ rustc_passes = { path = "../rustc_passes" } rustc_privacy = { path = "../rustc_privacy" } rustc_query_system = { path = "../rustc_query_system" } rustc_resolve = { path = "../rustc_resolve" } +rustc_restrictions = { path = "../rustc_restrictions" } rustc_symbol_mangling = { path = "../rustc_symbol_mangling" } rustc_trait_selection = { path = "../rustc_trait_selection" } rustc_ty_utils = { path = "../rustc_ty_utils" } diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 2e26ce111f01d..f3e12be9a8ada 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -117,6 +117,7 @@ pub static DEFAULT_LOCALE_RESOURCES: &[&str] = &[ rustc_privacy::DEFAULT_LOCALE_RESOURCE, rustc_query_system::DEFAULT_LOCALE_RESOURCE, rustc_resolve::DEFAULT_LOCALE_RESOURCE, + rustc_restrictions::DEFAULT_LOCALE_RESOURCE, rustc_session::DEFAULT_LOCALE_RESOURCE, rustc_symbol_mangling::DEFAULT_LOCALE_RESOURCE, rustc_trait_selection::DEFAULT_LOCALE_RESOURCE, diff --git a/compiler/rustc_interface/Cargo.toml b/compiler/rustc_interface/Cargo.toml index 7826d42dcb2d7..a6b307cdf1580 100644 --- a/compiler/rustc_interface/Cargo.toml +++ b/compiler/rustc_interface/Cargo.toml @@ -48,6 +48,7 @@ rustc_privacy = { path = "../rustc_privacy" } rustc_query_system = { path = "../rustc_query_system" } rustc_query_impl = { path = "../rustc_query_impl" } rustc_resolve = { path = "../rustc_resolve" } +rustc_restrictions = { path = "../rustc_restrictions" } rustc_target = { path = "../rustc_target" } rustc_trait_selection = { path = "../rustc_trait_selection" } rustc_ty_utils = { path = "../rustc_ty_utils" } diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 6b3facd041c28..ca894e2674923 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -670,6 +670,7 @@ pub static DEFAULT_QUERY_PROVIDERS: LazyLock = LazyLock::new(|| { rustc_resolve::provide(providers); rustc_hir_analysis::provide(providers); rustc_hir_typeck::provide(providers); + rustc_restrictions::provide(providers); ty::provide(providers); traits::provide(providers); rustc_passes::provide(providers); @@ -859,6 +860,9 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> { tcx.ensure().check_mod_privacy(module); }); }); + }, + { + sess.time("check_impl_restriction", || tcx.check_impl_restriction(())); } ); diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs index 2c481745d987a..604639b3e786c 100644 --- a/compiler/rustc_middle/src/query/erase.rs +++ b/compiler/rustc_middle/src/query/erase.rs @@ -270,6 +270,7 @@ trivial! { rustc_middle::ty::fast_reject::SimplifiedType, rustc_middle::ty::ImplPolarity, rustc_middle::ty::Representability, + rustc_middle::ty::Restriction, rustc_middle::ty::ReprOptions, rustc_middle::ty::UnusedGenericParams, rustc_middle::ty::util::AlwaysRequiresDrop, diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index c304245ca39b6..df55f3ab2f16a 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1695,6 +1695,14 @@ rustc_queries! { feedable } + query impl_restriction(def_id: LocalDefId) -> ty::Restriction { + desc { |tcx| "computing impl restriction for `{}`", tcx.def_path_str(def_id.to_def_id()) } + } + + query check_impl_restriction(_: ()) { + desc { "checking impl restrictions" } + } + query inhabited_predicate_adt(key: DefId) -> ty::inhabitedness::InhabitedPredicate<'tcx> { desc { "computing the uninhabited predicate of `{:?}`", key } } diff --git a/compiler/rustc_restrictions/Cargo.toml b/compiler/rustc_restrictions/Cargo.toml new file mode 100644 index 0000000000000..6bf7445ba7d8e --- /dev/null +++ b/compiler/rustc_restrictions/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "rustc_restrictions" +version = "0.0.0" +edition = "2021" + +[dependencies] +rustc_fluent_macro = { path = "../rustc_fluent_macro" } +rustc_errors = { path = "../rustc_errors" } +rustc_hir = { path = "../rustc_hir" } +rustc_macros = { path = "../rustc_macros" } +rustc_middle = { path = "../rustc_middle" } +rustc_session = { path = "../rustc_session" } +rustc_span = { path = "../rustc_span" } +tracing = "0.1" diff --git a/compiler/rustc_restrictions/messages.ftl b/compiler/rustc_restrictions/messages.ftl new file mode 100644 index 0000000000000..45c50f7765112 --- /dev/null +++ b/compiler/rustc_restrictions/messages.ftl @@ -0,0 +1,2 @@ +restrictions_impl_of_restricted_trait = implementation of restricted trait + .note = trait restricted here diff --git a/compiler/rustc_restrictions/src/errors.rs b/compiler/rustc_restrictions/src/errors.rs new file mode 100644 index 0000000000000..f62307a88d8c3 --- /dev/null +++ b/compiler/rustc_restrictions/src/errors.rs @@ -0,0 +1,11 @@ +use rustc_macros::Diagnostic; +use rustc_span::Span; + +#[derive(Diagnostic)] +#[diag(restrictions_impl_of_restricted_trait)] +pub struct ImplOfRestrictedTrait { + #[primary_span] + pub impl_span: Span, + #[note] + pub restriction_span: Span, +} diff --git a/compiler/rustc_restrictions/src/impl_restriction.rs b/compiler/rustc_restrictions/src/impl_restriction.rs new file mode 100644 index 0000000000000..f802802f6cad1 --- /dev/null +++ b/compiler/rustc_restrictions/src/impl_restriction.rs @@ -0,0 +1,68 @@ +use hir::intravisit::Visitor; +use rustc_hir::def_id::LocalDefId; +use rustc_hir::{self as hir, Node}; +use rustc_middle::query::Providers; +use rustc_middle::span_bug; +use rustc_middle::ty::{self, TyCtxt}; + +use crate::errors; + +pub(crate) fn provide(providers: &mut Providers) { + *providers = Providers { impl_restriction, check_impl_restriction, ..*providers }; +} + +struct ImplOfRestrictedTraitVisitor<'tcx> { + tcx: TyCtxt<'tcx>, +} + +impl<'v> Visitor<'v> for ImplOfRestrictedTraitVisitor<'v> { + type NestedFilter = rustc_middle::hir::nested_filter::All; + + fn nested_visit_map(&mut self) -> Self::Map { + self.tcx.hir() + } + + fn visit_item(&mut self, item: &'v hir::Item<'v>) { + if let hir::ItemKind::Trait(..) = item.kind { + let restriction = self.tcx.impl_restriction(item.owner_id.def_id); + + self.tcx.for_each_impl(item.owner_id.to_def_id(), |impl_| { + if restriction.is_restricted_in(impl_, self.tcx) { + self.tcx.sess.emit_err(errors::ImplOfRestrictedTrait { + impl_span: self.tcx.span_of_impl(impl_).expect("impl should be local"), + restriction_span: restriction.expect_span(), + }); + } + }); + }; + + hir::intravisit::walk_item(self, item) + } +} + +pub(crate) fn impl_restriction(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Restriction { + match tcx.resolutions(()).impl_restrictions.get(&def_id) { + Some(restriction) => *restriction, + None => { + let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); + match tcx.hir().get(hir_id) { + Node::Item(hir::Item { kind: hir::ItemKind::Trait(..), .. }) => { + span_bug!( + tcx.def_span(def_id), + "impl restriction table unexpectedly missing a def-id: {def_id:?}", + ) + } + _ => { + span_bug!( + tcx.def_span(def_id), + "called `impl_restriction` on non-trait: {def_id:?}", + ) + } + } + } + } +} + +pub(crate) fn check_impl_restriction(tcx: TyCtxt<'_>, _: ()) { + tcx.hir().walk_toplevel_module(&mut ImplOfRestrictedTraitVisitor { tcx }); +} diff --git a/compiler/rustc_restrictions/src/lib.rs b/compiler/rustc_restrictions/src/lib.rs new file mode 100644 index 0000000000000..56f64dc3774c1 --- /dev/null +++ b/compiler/rustc_restrictions/src/lib.rs @@ -0,0 +1,16 @@ +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] +#![deny(rustc::untranslatable_diagnostic)] +#![deny(rustc::diagnostic_outside_of_impl)] + +mod errors; +mod impl_restriction; + +use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage}; +use rustc_fluent_macro::fluent_messages; +use rustc_middle::query::Providers; + +fluent_messages! { "../messages.ftl" } + +pub fn provide(providers: &mut Providers) { + impl_restriction::provide(providers); +} diff --git a/tests/ui/restrictions/impl-restriction.rs b/tests/ui/restrictions/impl-restriction.rs new file mode 100644 index 0000000000000..158c36f63ac05 --- /dev/null +++ b/tests/ui/restrictions/impl-restriction.rs @@ -0,0 +1,11 @@ +// compile-flags: --crate-type=lib + +pub mod foo { + pub mod bar { + pub(crate) impl(super) trait Foo {} + } + + impl bar::Foo for i8 {} +} + +impl foo::bar::Foo for u8 {} //~ ERROR implementation of restricted trait diff --git a/tests/ui/restrictions/impl-restriction.stderr b/tests/ui/restrictions/impl-restriction.stderr new file mode 100644 index 0000000000000..76ba1c3e01b53 --- /dev/null +++ b/tests/ui/restrictions/impl-restriction.stderr @@ -0,0 +1,14 @@ +error: implementation of restricted trait + --> $DIR/impl-restriction.rs:11:1 + | +LL | impl foo::bar::Foo for u8 {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: trait restricted here + --> $DIR/impl-restriction.rs:5:20 + | +LL | pub(crate) impl(super) trait Foo {} + | ^^^^^^^^^^^ + +error: aborting due to previous error + From 94bef5ad513888546599910218ff31ae17923860 Mon Sep 17 00:00:00 2001 From: Jacob Pratt Date: Sat, 9 Jul 2022 19:33:17 -0400 Subject: [PATCH 10/45] Place restrictions behind feature gate --- compiler/rustc_ast_passes/src/feature_gate.rs | 1 + compiler/rustc_feature/src/active.rs | 2 ++ compiler/rustc_parse/src/parser/mod.rs | 11 +++++--- compiler/rustc_span/src/symbol.rs | 1 + tests/ui/restrictions/feature-gate.rs | 13 +++++++++ .../feature-gate.without_gate.stderr | 27 +++++++++++++++++++ tests/ui/restrictions/impl-restriction.rs | 2 ++ tests/ui/restrictions/impl-restriction.stderr | 4 +-- 8 files changed, 56 insertions(+), 5 deletions(-) create mode 100644 tests/ui/restrictions/feature-gate.rs create mode 100644 tests/ui/restrictions/feature-gate.without_gate.stderr diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index b0dbc2c23403e..a16f0c16a86af 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -556,6 +556,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session) { gate_all!(const_closures, "const closures are experimental"); gate_all!(builtin_syntax, "`builtin #` syntax is unstable"); gate_all!(explicit_tail_calls, "`become` expression is experimental"); + gate_all!(restrictions, "restrictions are experimental"); if !visitor.features.negative_bounds { for &span in spans.get(&sym::negative_bounds).iter().copied().flatten() { diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index 56a2c5eff3d07..e754086747960 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -505,6 +505,8 @@ declare_features! ( (incomplete, repr128, "1.16.0", Some(56071), None), /// Allows `repr(simd)` and importing the various simd intrinsics. (active, repr_simd, "1.4.0", Some(27731), None), + /// Allows restricting the implementation of traits and mutability of fields. + (active, restrictions, "CURRENT_RUSTC_VERSION", None, None), /// Allows return-position `impl Trait` in traits. (active, return_position_impl_trait_in_trait, "1.65.0", Some(91611), None), /// Allows bounding the return type of AFIT/RPITIT. diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 48d4aa8e49b48..66a70c8147519 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -1474,6 +1474,11 @@ impl<'a> Parser<'a> { return Ok(Restriction::implied().with_span(self.token.span.shrink_to_lo())); } + let gate = |span| { + self.sess.gated_spans.gate(sym::restrictions, span); + span + }; + let lo = self.prev_token.span; if self.check(&token::OpenDelim(Delimiter::Parenthesis)) { @@ -1488,7 +1493,7 @@ impl<'a> Parser<'a> { let path = self.parse_path(PathStyle::Mod)?; // `path` self.expect(&token::CloseDelim(Delimiter::Parenthesis))?; // `)` return Ok(Restriction::restricted(P(path), ast::DUMMY_NODE_ID) - .with_span(lo.to(self.prev_token.span))); + .with_span(lo.to(gate(lo.to(self.prev_token.span))))); } else if self.look_ahead(2, |t| t == &token::CloseDelim(Delimiter::Parenthesis)) && self.is_keyword_ahead(1, &[kw::Crate, kw::Super, kw::SelfLower]) { @@ -1497,7 +1502,7 @@ impl<'a> Parser<'a> { let path = self.parse_path(PathStyle::Mod)?; // `crate`/`super`/`self` self.expect(&token::CloseDelim(Delimiter::Parenthesis))?; // `)` return Ok(Restriction::restricted(P(path), ast::DUMMY_NODE_ID) - .with_span(lo.to(self.prev_token.span))); + .with_span(gate(lo.to(self.prev_token.span)))); } else if let FollowedByType::No = fbt { // Provide this diagnostic if a type cannot follow; // in particular, if this is not a tuple struct. @@ -1506,7 +1511,7 @@ impl<'a> Parser<'a> { } } - Ok(Restriction::unrestricted().with_span(lo)) + Ok(Restriction::unrestricted().with_span(gate(lo))) } /// Recovery for e.g. `kw(something) fn ...` or `struct X { kw(something) y: Z }` diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 4fc440ef94702..3b5fe561f7d52 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1222,6 +1222,7 @@ symbols! { repr_transparent, require, residual, + restrictions, result, resume, return_position_impl_trait_in_trait, diff --git a/tests/ui/restrictions/feature-gate.rs b/tests/ui/restrictions/feature-gate.rs new file mode 100644 index 0000000000000..f5c8c45991d96 --- /dev/null +++ b/tests/ui/restrictions/feature-gate.rs @@ -0,0 +1,13 @@ +// gate-test-restrictions +// compile-flags: --crate-type=lib +// revisions: with_gate without_gate +//[with_gate] check-pass + +#![cfg_attr(with_gate, feature(restrictions))] + +pub impl trait Foo {} //[without_gate]~ ERROR +pub impl(crate) trait Bar {} //[without_gate]~ ERROR + +mod foo { + pub impl(in foo) trait Baz {} //[without_gate]~ ERROR +} diff --git a/tests/ui/restrictions/feature-gate.without_gate.stderr b/tests/ui/restrictions/feature-gate.without_gate.stderr new file mode 100644 index 0000000000000..e1d38263f9727 --- /dev/null +++ b/tests/ui/restrictions/feature-gate.without_gate.stderr @@ -0,0 +1,27 @@ +error[E0658]: restrictions are experimental + --> $DIR/feature-gate.rs:8:5 + | +LL | pub impl trait Foo {} + | ^^^^ + | + = help: add `#![feature(restrictions)]` to the crate attributes to enable + +error[E0658]: restrictions are experimental + --> $DIR/feature-gate.rs:9:5 + | +LL | pub impl(crate) trait Bar {} + | ^^^^^^^^^^^ + | + = help: add `#![feature(restrictions)]` to the crate attributes to enable + +error[E0658]: restrictions are experimental + --> $DIR/feature-gate.rs:12:9 + | +LL | pub impl(in foo) trait Baz {} + | ^^^^^^^^^^^^ + | + = help: add `#![feature(restrictions)]` to the crate attributes to enable + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/restrictions/impl-restriction.rs b/tests/ui/restrictions/impl-restriction.rs index 158c36f63ac05..e4afe0dcd79f7 100644 --- a/tests/ui/restrictions/impl-restriction.rs +++ b/tests/ui/restrictions/impl-restriction.rs @@ -1,5 +1,7 @@ // compile-flags: --crate-type=lib +#![feature(restrictions)] + pub mod foo { pub mod bar { pub(crate) impl(super) trait Foo {} diff --git a/tests/ui/restrictions/impl-restriction.stderr b/tests/ui/restrictions/impl-restriction.stderr index 76ba1c3e01b53..b73d1f29a036d 100644 --- a/tests/ui/restrictions/impl-restriction.stderr +++ b/tests/ui/restrictions/impl-restriction.stderr @@ -1,11 +1,11 @@ error: implementation of restricted trait - --> $DIR/impl-restriction.rs:11:1 + --> $DIR/impl-restriction.rs:13:1 | LL | impl foo::bar::Foo for u8 {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ | note: trait restricted here - --> $DIR/impl-restriction.rs:5:20 + --> $DIR/impl-restriction.rs:7:20 | LL | pub(crate) impl(super) trait Foo {} | ^^^^^^^^^^^ From f5ea0f7226217e5e08f29bf1d37a58cdfeeff058 Mon Sep 17 00:00:00 2001 From: Jacob Pratt Date: Sun, 10 Jul 2022 18:01:48 -0400 Subject: [PATCH 11/45] Update compiler error index --- compiler/rustc_error_codes/src/error_codes/E0577.md | 5 +++-- compiler/rustc_error_codes/src/error_codes/E0578.md | 3 ++- compiler/rustc_error_codes/src/error_codes/E0704.md | 3 ++- compiler/rustc_error_codes/src/error_codes/E0742.md | 4 ++-- 4 files changed, 9 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_error_codes/src/error_codes/E0577.md b/compiler/rustc_error_codes/src/error_codes/E0577.md index eba2d3b14175b..72a0cbdb8cc0c 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0577.md +++ b/compiler/rustc_error_codes/src/error_codes/E0577.md @@ -1,4 +1,4 @@ -Something other than a module was found in visibility scope. +Something other than a module was found in visibility or restriction scope. Erroneous code example: @@ -13,7 +13,8 @@ fn main() {} `Sea` is not a module, therefore it is invalid to use it in a visibility path. To fix this error we need to ensure `sea` is a module. -Please note that the visibility scope can only be applied on ancestors! +Please note that the visibility and restriction scope can only be applied on +ancestors! ```edition2018 pub mod sea { diff --git a/compiler/rustc_error_codes/src/error_codes/E0578.md b/compiler/rustc_error_codes/src/error_codes/E0578.md index fca89757287f5..eff9b61c0905a 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0578.md +++ b/compiler/rustc_error_codes/src/error_codes/E0578.md @@ -1,4 +1,5 @@ -A module cannot be found and therefore, the visibility cannot be determined. +A module cannot be found and therefore, the visibility or restriction cannot be +determined. Erroneous code example: diff --git a/compiler/rustc_error_codes/src/error_codes/E0704.md b/compiler/rustc_error_codes/src/error_codes/E0704.md index c22b274fb223e..a3a5e41430c2f 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0704.md +++ b/compiler/rustc_error_codes/src/error_codes/E0704.md @@ -1,4 +1,4 @@ -An incorrect visibility restriction was specified. +An incorrect restriction was specified. Erroneous code example: @@ -25,3 +25,4 @@ mod foo { For more information see the Rust Reference on [Visibility]. [Visibility]: https://doc.rust-lang.org/reference/visibility-and-privacy.html +[//]: FIXME(jhpratt) add link to Restriction page in reference once it's created diff --git a/compiler/rustc_error_codes/src/error_codes/E0742.md b/compiler/rustc_error_codes/src/error_codes/E0742.md index e10c1639dd38a..1058a9ba792f8 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0742.md +++ b/compiler/rustc_error_codes/src/error_codes/E0742.md @@ -1,5 +1,5 @@ -Visibility is restricted to a module which isn't an ancestor of the current -item. +Visibility or restriction is restricted to a module which isn't an ancestor of +the current item. Erroneous code example: From bb278ab4379afe3f3b47dabf02c29363add05e01 Mon Sep 17 00:00:00 2001 From: Jacob Pratt Date: Sun, 10 Jul 2022 22:17:38 -0400 Subject: [PATCH 12/45] Parse `mut` restriction on fields --- compiler/rustc_ast/src/ast.rs | 1 + compiler/rustc_ast/src/mut_visit.rs | 3 ++- compiler/rustc_ast/src/visit.rs | 1 + .../rustc_ast_pretty/src/pprust/state/item.rs | 1 + compiler/rustc_expand/src/placeholders.rs | 1 + compiler/rustc_middle/src/ty/mod.rs | 16 +++++++++----- compiler/rustc_parse/src/parser/item.rs | 22 +++++++++++++++++-- tests/ui/macros/stringify.rs | 5 +++++ 8 files changed, 42 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index e23396f26fd20..f0e46b4b1a48c 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -2761,6 +2761,7 @@ pub struct FieldDef { pub id: NodeId, pub span: Span, pub vis: Visibility, + pub mut_restriction: Restriction, pub ident: Option, pub ty: P, diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 3bc9433a0207d..76dc149e51741 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -994,9 +994,10 @@ pub fn noop_flat_map_field_def( mut fd: FieldDef, visitor: &mut T, ) -> SmallVec<[FieldDef; 1]> { - let FieldDef { span, ident, vis, id, ty, attrs, is_placeholder: _ } = &mut fd; + let FieldDef { span, ident, vis, mut_restriction, id, ty, attrs, is_placeholder: _ } = &mut fd; visitor.visit_span(span); visit_opt(ident, |ident| visitor.visit_ident(ident)); + visitor.visit_restriction(mut_restriction); visitor.visit_vis(vis); visitor.visit_id(id); visitor.visit_ty(ty); diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index 27a6c0792e5d7..d1cc8b42864c3 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -716,6 +716,7 @@ pub fn walk_field_def<'a, V: Visitor<'a>>(visitor: &mut V, field: &'a FieldDef) if let Some(ident) = field.ident { visitor.visit_ident(ident); } + visitor.visit_restriction(&field.mut_restriction); visitor.visit_ty(&field.ty); walk_list!(visitor, visit_attribute, &field.attrs); } diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs index fffe4062ace43..0ee9ca04ab99d 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/item.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs @@ -466,6 +466,7 @@ impl<'a> State<'a> { self.maybe_print_comment(field.span.lo()); self.print_outer_attributes(&field.attrs); self.print_visibility(&field.vis); + self.print_restriction("mut", &field.mut_restriction); self.print_ident(field.ident.unwrap()); self.word_nbsp(":"); self.print_type(&field.ty); diff --git a/compiler/rustc_expand/src/placeholders.rs b/compiler/rustc_expand/src/placeholders.rs index e9af688ee2b61..83d78535b5d0b 100644 --- a/compiler/rustc_expand/src/placeholders.rs +++ b/compiler/rustc_expand/src/placeholders.rs @@ -169,6 +169,7 @@ pub fn placeholder( span, ty: ty(), vis, + mut_restriction: ast::Restriction::unrestricted(), is_placeholder: true, }]), AstFragmentKind::Variants => AstFragment::Variants(smallvec![ast::Variant { diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index f0ac63b987272..6eb1c8b53234b 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -292,24 +292,23 @@ pub enum Visibility { } #[derive(Clone, Debug, PartialEq, Eq, Copy, Hash, Encodable, Decodable, HashStable)] -pub enum Restriction { +pub enum Restriction { /// The restriction does not affect the item. Unrestricted, /// The restriction only applies outside of this path. - Restricted(DefId, Span), + Restricted(Id, Span), } -impl Restriction { +impl> Restriction { /// Returns `true` if this restriction applies in the given module. This /// means the behavior is _not_ allowed. pub fn is_restricted_in(self, module: DefId, tcx: TyCtxt<'_>) -> bool { let restricted_to = match self { Restriction::Unrestricted => return false, - Restriction::Restricted(other, _) if other.krate != module.krate => return false, Restriction::Restricted(module, _) => module, }; - !tcx.is_descendant_of(module, restricted_to) + !tcx.is_descendant_of(module, restricted_to.into()) } /// Obtain the [`Span`] of the restriction. Panics if the restriction is unrestricted. @@ -319,6 +318,13 @@ impl Restriction { Restriction::Restricted(_, span) => *span, } } + + pub fn map_id(self, f: impl FnOnce(Id) -> OutId) -> Restriction { + match self { + Restriction::Unrestricted => Restriction::Unrestricted, + Restriction::Restricted(id, span) => Restriction::Restricted(f(id), span), + } + } } #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable, TyEncodable, TyDecodable)] diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 6d388dbc7c704..fbc45f5e4bcaa 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -1589,6 +1589,16 @@ impl<'a> Parser<'a> { return Err(err); } }; + let mut_restriction = + match p.parse_restriction(kw::Mut, "mutate", FollowedByType::Yes) { + Ok(mut_restriction) => mut_restriction, + Err(err) => { + if let Some(ref mut snapshot) = snapshot { + snapshot.recover_diff_marker(); + } + return Err(err); + } + }; let ty = match p.parse_ty() { Ok(ty) => ty, Err(err) => { @@ -1603,6 +1613,7 @@ impl<'a> Parser<'a> { FieldDef { span: lo.to(ty.span), vis, + mut_restriction, ident: None, id: DUMMY_NODE_ID, ty, @@ -1624,7 +1635,11 @@ impl<'a> Parser<'a> { self.collect_tokens_trailing_token(attrs, ForceCollect::No, |this, attrs| { let lo = this.token.span; let vis = this.parse_visibility(FollowedByType::No)?; - Ok((this.parse_single_struct_field(adt_ty, lo, vis, attrs)?, TrailingToken::None)) + let mut_restriction = this.parse_restriction(kw::Mut, "mutate", FollowedByType::No)?; + Ok(( + this.parse_single_struct_field(adt_ty, lo, vis, mut_restriction, attrs)?, + TrailingToken::None, + )) }) } @@ -1634,10 +1649,11 @@ impl<'a> Parser<'a> { adt_ty: &str, lo: Span, vis: Visibility, + mut_restriction: Restriction, attrs: AttrVec, ) -> PResult<'a, FieldDef> { let mut seen_comma: bool = false; - let a_var = self.parse_name_and_ty(adt_ty, lo, vis, attrs)?; + let a_var = self.parse_name_and_ty(adt_ty, lo, vis, mut_restriction, attrs)?; if self.token == token::Comma { seen_comma = true; } @@ -1773,6 +1789,7 @@ impl<'a> Parser<'a> { adt_ty: &str, lo: Span, vis: Visibility, + mut_restriction: Restriction, attrs: AttrVec, ) -> PResult<'a, FieldDef> { let name = self.parse_field_ident(adt_ty, lo)?; @@ -1791,6 +1808,7 @@ impl<'a> Parser<'a> { span: lo.to(self.prev_token.span), ident: Some(name), vis, + mut_restriction, id: DUMMY_NODE_ID, ty, attrs, diff --git a/tests/ui/macros/stringify.rs b/tests/ui/macros/stringify.rs index 816f99baa8495..8f940cb675958 100644 --- a/tests/ui/macros/stringify.rs +++ b/tests/ui/macros/stringify.rs @@ -882,3 +882,8 @@ fn test_vis() { } assert_eq!(stringify_inherited_vis!(struct), ""); } + +#[test] +fn test_restriction() { + assert_eq!(stringify!(pub impl(crate) trait Foo {}), "pub impl(crate) trait Foo {}"); +} From f6a6786698b5a433a5b54fd6a4ac9332611ed7df Mon Sep 17 00:00:00 2001 From: Jacob Pratt Date: Mon, 11 Jul 2022 00:43:30 -0400 Subject: [PATCH 13/45] rustfmt `mut` restriction --- src/tools/rustfmt/src/items.rs | 6 +- src/tools/rustfmt/tests/source/restriction.rs | 83 +++++++++++++++++++ src/tools/rustfmt/tests/target/restriction.rs | 33 ++++++++ 3 files changed, 119 insertions(+), 3 deletions(-) diff --git a/src/tools/rustfmt/src/items.rs b/src/tools/rustfmt/src/items.rs index ce93693e65e6e..e6e3364646d5b 100644 --- a/src/tools/rustfmt/src/items.rs +++ b/src/tools/rustfmt/src/items.rs @@ -1828,15 +1828,15 @@ pub(crate) fn rewrite_struct_field_prefix( field: &ast::FieldDef, ) -> Option { let vis = format_visibility(context, &field.vis); + let mut_restriction = format_restriction("mut", context, &field.mut_restriction); let type_annotation_spacing = type_annotation_spacing(context.config); Some(match field.ident { Some(name) => format!( - "{}{}{}:", - vis, + "{vis}{mut_restriction}{}{}:", rewrite_ident(context, name), type_annotation_spacing.0 ), - None => vis.to_string(), + None => format!("{vis}{mut_restriction}"), }) } diff --git a/src/tools/rustfmt/tests/source/restriction.rs b/src/tools/rustfmt/tests/source/restriction.rs index 648c2982cb935..6df58576479d6 100644 --- a/src/tools/rustfmt/tests/source/restriction.rs +++ b/src/tools/rustfmt/tests/source/restriction.rs @@ -11,3 +11,86 @@ impl ( in foo :: bar ) trait Baz {} + +struct FooS { + pub + mut(crate) + field: (), +} + +struct BarS { + pub + mut + field: (), +} + +struct BazS { + pub + mut ( in foo + :: + bar ) + field: (), +} + +struct FooS2( + pub + mut(crate) + (), +); + +struct BarS2( + pub + mut + (), +); + +struct BazS2( + pub + mut ( in foo + :: + bar ) + (), +); + +enum Enum { + Foo { + mut(crate) + field: (), + }, + Bar { + mut + field: (), + }, + Baz { + mut ( in foo + :: + bar ) + field: (), + }, + FooT( + mut(crate) + (), + ), + BarT( + mut + (), + ), + BazT( + mut ( in foo + :: + bar ) + (), + ), + +} + +union Union { + mut(crate) + field1: (), + mut + field2: (), + mut ( in foo + :: + bar ) + field3: (), +} diff --git a/src/tools/rustfmt/tests/target/restriction.rs b/src/tools/rustfmt/tests/target/restriction.rs index 81dad02a21180..a25ea9c161f06 100644 --- a/src/tools/rustfmt/tests/target/restriction.rs +++ b/src/tools/rustfmt/tests/target/restriction.rs @@ -3,3 +3,36 @@ pub impl(crate) trait Foo {} pub impl trait Bar {} pub impl(in foo::bar) trait Baz {} + +struct FooS { + pub mut(crate) field: (), +} + +struct BarS { + pub mut field: (), +} + +struct BazS { + pub mut(in foo::bar) field: (), +} + +struct FooS2(pub mut(crate) ()); + +struct BarS2(pub mut ()); + +struct BazS2(pub mut(in foo::bar) ()); + +enum Enum { + Foo { mut(crate) field: () }, + Bar { mut field: () }, + Baz { mut(in foo::bar) field: () }, + FooT(mut(crate) ()), + BarT(mut ()), + BazT(mut(in foo::bar) ()), +} + +union Union { + mut(crate) field1: (), + mut field2: (), + mut(in foo::bar) field3: (), +} From c1622778b08324538bda4c43a5f38aabec849868 Mon Sep 17 00:00:00 2001 From: Jacob Pratt Date: Mon, 11 Jul 2022 00:59:25 -0400 Subject: [PATCH 14/45] Lower `mut` restriction to `rustc_middle` --- compiler/rustc_middle/src/hir/map/mod.rs | 1 + compiler/rustc_middle/src/ty/mod.rs | 1 + compiler/rustc_resolve/src/build_reduced_graph.rs | 3 +++ compiler/rustc_resolve/src/lib.rs | 4 ++++ 4 files changed, 9 insertions(+) diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index 1323c972e8c60..ffb4a4730f54b 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -1224,6 +1224,7 @@ pub(super) fn crate_hash(tcx: TyCtxt<'_>, _: LocalCrate) -> Svh { resolutions.visibilities.hash_stable(&mut hcx, &mut stable_hasher); resolutions.has_pub_restricted.hash_stable(&mut hcx, &mut stable_hasher); resolutions.impl_restrictions.hash_stable(&mut hcx, &mut stable_hasher); + resolutions.mut_restrictions.hash_stable(&mut hcx, &mut stable_hasher); stable_hasher.finish() }); diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 6eb1c8b53234b..cebc17f09cdbc 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -163,6 +163,7 @@ pub struct ResolverOutputs { pub struct ResolverGlobalCtxt { pub visibilities: FxHashMap, pub impl_restrictions: FxHashMap, + pub mut_restrictions: FxHashMap, /// This field is used to decide whether we should make `PRIVATE_IN_PUBLIC` a hard error. pub has_pub_restricted: bool, /// Item with a given `LocalDefId` was defined during macro expansion with ID `ExpnId`. diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 8562c458a95e5..5da9aa6894240 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -846,6 +846,9 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { ctor_vis = field_vis; } ret_fields.push(field_vis.to_def_id()); + + let mut_restriction = self.resolve_restriction(&field.mut_restriction); + self.r.mut_restrictions.insert(local_def_id, mut_restriction); } let ctor_def_id = self.r.local_def_id(ctor_node_id); let ctor_res = diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index ba6494d57e382..38747b4f0dab9 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -981,6 +981,7 @@ pub struct Resolver<'a, 'tcx> { visibilities: FxHashMap, has_pub_restricted: bool, impl_restrictions: FxHashMap, + mut_restrictions: FxHashMap, used_imports: FxHashSet, maybe_unused_trait_imports: FxIndexSet, @@ -1320,6 +1321,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { glob_map: Default::default(), visibilities, impl_restrictions: FxHashMap::default(), + mut_restrictions: FxHashMap::default(), has_pub_restricted: false, used_imports: FxHashSet::default(), maybe_unused_trait_imports: Default::default(), @@ -1436,6 +1438,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { let expn_that_defined = self.expn_that_defined; let visibilities = self.visibilities; let impl_restrictions = self.impl_restrictions; + let mut_restrictions = self.mut_restrictions; let has_pub_restricted = self.has_pub_restricted; let extern_crate_map = self.extern_crate_map; let maybe_unused_trait_imports = self.maybe_unused_trait_imports; @@ -1455,6 +1458,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { expn_that_defined, visibilities, impl_restrictions, + mut_restrictions, has_pub_restricted, effective_visibilities, extern_crate_map, From ad7f018444f9a7c53f91c9b2f94cf943f481b05f Mon Sep 17 00:00:00 2001 From: Jacob Pratt Date: Sat, 16 Jul 2022 00:25:41 -0400 Subject: [PATCH 15/45] Add query to obtain `mut` restriction --- compiler/rustc_middle/src/query/mod.rs | 4 +++ compiler/rustc_restrictions/src/lib.rs | 2 ++ .../rustc_restrictions/src/mut_restriction.rs | 32 +++++++++++++++++++ 3 files changed, 38 insertions(+) create mode 100644 compiler/rustc_restrictions/src/mut_restriction.rs diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index df55f3ab2f16a..e345ce3a70616 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1712,6 +1712,10 @@ rustc_queries! { desc { "computing the uninhabited predicate of `{}`", key } } + query mut_restriction(def_id: LocalDefId) -> ty::Restriction { + desc { |tcx| "computing mut restriction for `{}`", tcx.def_path_str(def_id.to_def_id()) } + } + query dep_kind(_: CrateNum) -> CrateDepKind { eval_always desc { "fetching what a dependency looks like" } diff --git a/compiler/rustc_restrictions/src/lib.rs b/compiler/rustc_restrictions/src/lib.rs index 56f64dc3774c1..09d2cc8b722ae 100644 --- a/compiler/rustc_restrictions/src/lib.rs +++ b/compiler/rustc_restrictions/src/lib.rs @@ -4,6 +4,7 @@ mod errors; mod impl_restriction; +mod mut_restriction; use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage}; use rustc_fluent_macro::fluent_messages; @@ -13,4 +14,5 @@ fluent_messages! { "../messages.ftl" } pub fn provide(providers: &mut Providers) { impl_restriction::provide(providers); + mut_restriction::provide(providers); } diff --git a/compiler/rustc_restrictions/src/mut_restriction.rs b/compiler/rustc_restrictions/src/mut_restriction.rs new file mode 100644 index 0000000000000..271bd7abf94af --- /dev/null +++ b/compiler/rustc_restrictions/src/mut_restriction.rs @@ -0,0 +1,32 @@ +use rustc_hir::def_id::LocalDefId; +use rustc_hir::{Item, ItemKind, Node}; +use rustc_middle::query::Providers; +use rustc_middle::span_bug; +use rustc_middle::ty::{Restriction, TyCtxt}; + +pub(crate) fn provide(providers: &mut Providers) { + *providers = Providers { mut_restriction, ..*providers }; +} + +fn mut_restriction(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Restriction { + match tcx.resolutions(()).mut_restrictions.get(&def_id) { + Some(restriction) => *restriction, + None => { + let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); + match tcx.hir().get(hir_id) { + Node::Item(Item { kind: ItemKind::Struct(..), .. }) => { + span_bug!( + tcx.def_span(def_id), + "mut restriction table unexpectedly missing a def-id: {def_id:?}", + ) + } + _ => { + span_bug!( + tcx.def_span(def_id), + "called `mut_restriction` on invalid item: {def_id:?}", + ) + } + } + } + } +} From f7ffd594d005a5211794961e1ae804780e7ef051 Mon Sep 17 00:00:00 2001 From: Jacob Pratt Date: Fri, 22 Jul 2022 00:11:31 -0400 Subject: [PATCH 16/45] Lower struct field mut restriction to MIR --- compiler/rustc_hir_analysis/src/collect.rs | 1 + compiler/rustc_metadata/src/rmeta/decoder.rs | 9 +++++++++ compiler/rustc_metadata/src/rmeta/mod.rs | 1 + compiler/rustc_middle/src/ty/mod.rs | 7 ++++--- compiler/rustc_middle/src/ty/parameterized.rs | 1 + .../rustc_resolve/src/build_reduced_graph.rs | 10 ++++++++-- .../rustc_restrictions/src/mut_restriction.rs | 16 ++++++++-------- 7 files changed, 32 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index c160cf2df6e5f..e6d395b3d22b2 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -807,6 +807,7 @@ fn convert_variant( did: f.def_id.to_def_id(), name: f.ident.name, vis: tcx.visibility(f.def_id), + mut_restriction: tcx.mut_restriction(f.def_id), } }) .collect(); diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index 8fa1d365728a2..a7c26ef8e7089 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -903,6 +903,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { did, name: self.item_name(did.index), vis: self.get_visibility(did.index), + mut_restriction: self.get_mut_restriction(index), }) .collect(), adt_kind, @@ -964,6 +965,14 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { .map_id(|index| self.local_def_id(index)) } + fn get_mut_restriction(self, id: DefIndex) -> ty::Restriction { + self.root + .tables + .mut_restriction + .get(self, id) + .map_or(ty::Restriction::Unrestricted, |restriction| restriction.decode(self)) + } + fn get_trait_item_def_id(self, id: DefIndex) -> Option { self.root.tables.trait_item_def_id.get(self, id).map(|d| d.decode_from_cdata(self)) } diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index 9cffd96f4a396..fd026fa5fa20c 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -395,6 +395,7 @@ define_tables! { associated_item_or_field_def_ids: Table>, opt_def_kind: Table, visibility: Table>>, + mut_restriction: Table>, def_span: Table>, def_ident_span: Table>, lookup_stability: Table>, diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index cebc17f09cdbc..05c5651409bc6 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -2155,6 +2155,7 @@ pub struct FieldDef { pub did: DefId, pub name: Symbol, pub vis: Visibility, + pub mut_restriction: Restriction, } impl PartialEq for FieldDef { @@ -2167,9 +2168,9 @@ impl PartialEq for FieldDef { // of `FieldDef` changes, a compile-error will be produced, reminding // us to revisit this assumption. - let Self { did: lhs_did, name: _, vis: _ } = &self; + let Self { did: lhs_did, name: _, vis: _, mut_restriction: _ } = &self; - let Self { did: rhs_did, name: _, vis: _ } = other; + let Self { did: rhs_did, name: _, vis: _, mut_restriction: _ } = other; let res = lhs_did == rhs_did; @@ -2195,7 +2196,7 @@ impl Hash for FieldDef { // of `FieldDef` changes, a compile-error will be produced, reminding // us to revisit this assumption. - let Self { did, name: _, vis: _ } = &self; + let Self { did, name: _, vis: _, mut_restriction: _ } = &self; did.hash(s) } diff --git a/compiler/rustc_middle/src/ty/parameterized.rs b/compiler/rustc_middle/src/ty/parameterized.rs index cc2b26a5e1457..431c8bc1a8892 100644 --- a/compiler/rustc_middle/src/ty/parameterized.rs +++ b/compiler/rustc_middle/src/ty/parameterized.rs @@ -69,6 +69,7 @@ trivially_parameterized_over_tcx! { ty::TraitDef, ty::UnusedGenericParams, ty::Visibility, + ty::Restriction, ty::adjustment::CoerceUnsizedInfo, ty::fast_reject::SimplifiedType, rustc_ast::Attribute, diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 5da9aa6894240..93f0e9def38d7 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -820,6 +820,13 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { self.insert_field_def_ids(local_def_id, vdata); self.insert_field_visibilities_local(def_id, vdata); + for field in vdata.fields() { + if let Some(local_did) = self.r.opt_local_def_id(field.id) { + let mut_restriction = self.resolve_restriction(&field.mut_restriction); + self.r.mut_restrictions.insert(local_did, mut_restriction); + } + } + // If this is a tuple or unit struct, define a name // in the value namespace as well. if let Some((ctor_kind, ctor_node_id)) = CtorKind::from_ast(vdata) { @@ -847,8 +854,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { } ret_fields.push(field_vis.to_def_id()); - let mut_restriction = self.resolve_restriction(&field.mut_restriction); - self.r.mut_restrictions.insert(local_def_id, mut_restriction); + // TODO(jhpratt) add resolutions for enum variant fields } let ctor_def_id = self.r.local_def_id(ctor_node_id); let ctor_res = diff --git a/compiler/rustc_restrictions/src/mut_restriction.rs b/compiler/rustc_restrictions/src/mut_restriction.rs index 271bd7abf94af..c4babdb6d9ca4 100644 --- a/compiler/rustc_restrictions/src/mut_restriction.rs +++ b/compiler/rustc_restrictions/src/mut_restriction.rs @@ -1,5 +1,5 @@ use rustc_hir::def_id::LocalDefId; -use rustc_hir::{Item, ItemKind, Node}; +use rustc_hir::Node; use rustc_middle::query::Providers; use rustc_middle::span_bug; use rustc_middle::ty::{Restriction, TyCtxt}; @@ -9,16 +9,16 @@ pub(crate) fn provide(providers: &mut Providers) { } fn mut_restriction(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Restriction { - match tcx.resolutions(()).mut_restrictions.get(&def_id) { + tracing::debug!("mut_restriction({def_id:?})"); + + match (&tcx.resolutions(()).mut_restrictions).get(&def_id) { Some(restriction) => *restriction, None => { - let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); + let hir_id = tcx.local_def_id_to_hir_id(def_id); match tcx.hir().get(hir_id) { - Node::Item(Item { kind: ItemKind::Struct(..), .. }) => { - span_bug!( - tcx.def_span(def_id), - "mut restriction table unexpectedly missing a def-id: {def_id:?}", - ) + Node::Field(..) => { + tracing::debug!("mut restriction not found; assuming unrestricted"); + Restriction::Unrestricted } _ => { span_bug!( From 75830d49d539312d1ff53c991bcaafd91fb9af67 Mon Sep 17 00:00:00 2001 From: Jacob Pratt Date: Fri, 22 Jul 2022 00:13:28 -0400 Subject: [PATCH 17/45] Get field definition from `TyCtxt` and `Field` --- compiler/rustc_middle/src/mir/tcx.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/compiler/rustc_middle/src/mir/tcx.rs b/compiler/rustc_middle/src/mir/tcx.rs index f79697936d28c..bb359801ed61e 100644 --- a/compiler/rustc_middle/src/mir/tcx.rs +++ b/compiler/rustc_middle/src/mir/tcx.rs @@ -51,6 +51,22 @@ impl<'tcx> PlaceTy<'tcx> { } } + /// `place_ty.field_def(f)` obtains the `FieldDef` of the provided ADT field. + pub fn field_def(self, f: FieldIdx) -> &'tcx ty::FieldDef { + let ty::Adt(adt_def, _) = self.ty.kind() else { + bug!("extracting field def of non-ADT: {self:?}") + }; + + let variant_def = match self.variant_index { + None => adt_def.non_enum_variant(), + Some(variant_index) => { + assert!(adt_def.is_enum()); + &adt_def.variant(variant_index) + } + }; + &variant_def.fields[f] + } + /// Convenience wrapper around `projection_ty_core` for /// `PlaceElem`, where we can just use the `Ty` that is already /// stored inline on field projection elems. From 1d0f756e3349b8a57e5e8a38212607863e11dd0c Mon Sep 17 00:00:00 2001 From: Jacob Pratt Date: Fri, 22 Jul 2022 00:15:22 -0400 Subject: [PATCH 18/45] Validate `mut` restriction on struct fields --- compiler/rustc_middle/src/query/mod.rs | 4 ++ compiler/rustc_mir_transform/src/lib.rs | 2 + compiler/rustc_restrictions/messages.ftl | 3 + compiler/rustc_restrictions/src/errors.rs | 9 +++ .../rustc_restrictions/src/mut_restriction.rs | 68 ++++++++++++++++++- 5 files changed, 85 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index e345ce3a70616..0daad5ea7e48c 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1716,6 +1716,10 @@ rustc_queries! { desc { |tcx| "computing mut restriction for `{}`", tcx.def_path_str(def_id.to_def_id()) } } + query check_mut_restriction(def_id: LocalDefId) { + desc { "checking mut restrictions" } + } + query dep_kind(_: CrateNum) -> CrateDepKind { eval_always desc { "fetching what a dependency looks like" } diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index d419329f2d6bf..a8f9454459fbb 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -265,6 +265,8 @@ fn mir_const(tcx: TyCtxt<'_>, def: LocalDefId) -> &Steal> { tcx.ensure_with_value().unsafety_check_result(def); } + tcx.ensure().check_mut_restriction(def); + // has_ffi_unwind_calls query uses the raw mir, so make sure it is run. tcx.ensure_with_value().has_ffi_unwind_calls(def); diff --git a/compiler/rustc_restrictions/messages.ftl b/compiler/rustc_restrictions/messages.ftl index 45c50f7765112..28b476c947828 100644 --- a/compiler/rustc_restrictions/messages.ftl +++ b/compiler/rustc_restrictions/messages.ftl @@ -1,2 +1,5 @@ restrictions_impl_of_restricted_trait = implementation of restricted trait .note = trait restricted here + +restrictions_mut_of_restricted_field = mutable use of restricted field + .note = mutability restricted here diff --git a/compiler/rustc_restrictions/src/errors.rs b/compiler/rustc_restrictions/src/errors.rs index f62307a88d8c3..36423d2096a7c 100644 --- a/compiler/rustc_restrictions/src/errors.rs +++ b/compiler/rustc_restrictions/src/errors.rs @@ -9,3 +9,12 @@ pub struct ImplOfRestrictedTrait { #[note] pub restriction_span: Span, } + +#[derive(Diagnostic)] +#[diag(restrictions_mut_of_restricted_field)] +pub struct MutOfRestrictedField { + #[primary_span] + pub mut_span: Span, + #[note] + pub restriction_span: Span, +} diff --git a/compiler/rustc_restrictions/src/mut_restriction.rs b/compiler/rustc_restrictions/src/mut_restriction.rs index c4babdb6d9ca4..660af95de83bc 100644 --- a/compiler/rustc_restrictions/src/mut_restriction.rs +++ b/compiler/rustc_restrictions/src/mut_restriction.rs @@ -1,11 +1,16 @@ use rustc_hir::def_id::LocalDefId; use rustc_hir::Node; +use rustc_middle::mir::visit::{PlaceContext, Visitor}; +use rustc_middle::mir::{Body, Location, Place, ProjectionElem, Statement, Terminator}; use rustc_middle::query::Providers; use rustc_middle::span_bug; use rustc_middle::ty::{Restriction, TyCtxt}; +use rustc_span::Span; + +use crate::errors; pub(crate) fn provide(providers: &mut Providers) { - *providers = Providers { mut_restriction, ..*providers }; + *providers = Providers { mut_restriction, check_mut_restriction, ..*providers }; } fn mut_restriction(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Restriction { @@ -30,3 +35,64 @@ fn mut_restriction(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Restriction { } } } + +fn check_mut_restriction(tcx: TyCtxt<'_>, def_id: LocalDefId) { + tracing::debug!("check_mut_restriction({def_id:?})"); + + let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); + + // FIXME(jhpratt) Does this need to be handled somehow? + if matches!(tcx.hir().get(hir_id), Node::AnonConst(_)) { + return; + } + + let body = &tcx.mir_built(def_id).borrow(); + let mut checker = MutRestrictionChecker { tcx, body, span: body.span }; + checker.visit_body(body); +} + +struct MutRestrictionChecker<'a, 'tcx> { + tcx: TyCtxt<'tcx>, + body: &'a Body<'tcx>, + span: Span, +} + +impl<'tcx> Visitor<'tcx> for MutRestrictionChecker<'_, 'tcx> { + fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) { + self.span = terminator.source_info.span; + self.super_terminator(terminator, location); + } + + fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) { + self.span = statement.source_info.span; + self.super_statement(statement, location); + } + + fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, _location: Location) { + if !context.is_mutating_use() { + return; + } + + let body_did = self.body.source.instance.def_id(); + + for (place_base, elem) in place.iter_projections() { + match elem { + ProjectionElem::Field(field, _ty) => { + let field_ty = place_base.ty(self.body, self.tcx); + if !field_ty.ty.is_adt() { + continue; + } + let field_def = field_ty.field_def(field); + + if field_def.mut_restriction.is_restricted_in(body_did, self.tcx) { + self.tcx.sess.emit_err(errors::MutOfRestrictedField { + mut_span: self.span, + restriction_span: field_def.mut_restriction.expect_span(), + }); + } + } + _ => {} + } + } + } +} From 9dfdfeac2d81aabdc541f7cdf677993333b20c11 Mon Sep 17 00:00:00 2001 From: Jacob Pratt Date: Fri, 22 Jul 2022 00:16:39 -0400 Subject: [PATCH 19/45] Test `mut` restriction --- tests/ui/restrictions/mut-restriction.rs | 39 ++++++++++ tests/ui/restrictions/mut-restriction.stderr | 75 ++++++++++++++++++++ 2 files changed, 114 insertions(+) create mode 100644 tests/ui/restrictions/mut-restriction.rs create mode 100644 tests/ui/restrictions/mut-restriction.stderr diff --git a/tests/ui/restrictions/mut-restriction.rs b/tests/ui/restrictions/mut-restriction.rs new file mode 100644 index 0000000000000..47e9b52918715 --- /dev/null +++ b/tests/ui/restrictions/mut-restriction.rs @@ -0,0 +1,39 @@ +#![feature(restrictions)] + +pub mod foo { + #[derive(Default)] + pub struct Foo { + pub mut(self) alpha: u8, + } +} + +fn change_alpha(foo: &mut foo::Foo) { + foo.alpha = 1; //~ ERROR mutable use of restricted field +} + +fn change_alpha_ptr(foo: *mut foo::Foo) { + // unsafe doesn't matter + unsafe { + (*foo).alpha = 1; //~ ERROR mutable use of restricted field + } +} + +fn main() { + let mut foo = foo::Foo::default(); + foo.alpha = 1; //~ ERROR mutable use of restricted field + std::ptr::addr_of_mut!(foo.alpha); //~ ERROR mutable use of restricted field + + let _alpha = &mut foo.alpha; //~ ERROR mutable use of restricted field + + let mut closure = || { + foo.alpha = 1; //~ ERROR mutable use of restricted field + }; + + // okay: the mutation occurs inside the function + closure(); + change_alpha(&mut foo); + change_alpha_ptr(&mut foo as *mut _); + + // okay: this is the same as turning &T into &mut T, which is unsound + unsafe { *(&foo.alpha as *const _ as *mut _) = 1; } +} diff --git a/tests/ui/restrictions/mut-restriction.stderr b/tests/ui/restrictions/mut-restriction.stderr new file mode 100644 index 0000000000000..6fa16f51bd914 --- /dev/null +++ b/tests/ui/restrictions/mut-restriction.stderr @@ -0,0 +1,75 @@ +error: mutable use of restricted field + --> $DIR/mut-restriction.rs:11:5 + | +LL | foo.alpha = 1; + | ^^^^^^^^^^^^^ + | +note: mutability restricted here + --> $DIR/mut-restriction.rs:6:13 + | +LL | pub mut(self) alpha: u8, + | ^^^^^^^^^ + +error: mutable use of restricted field + --> $DIR/mut-restriction.rs:17:9 + | +LL | (*foo).alpha = 1; + | ^^^^^^^^^^^^^^^^ + | +note: mutability restricted here + --> $DIR/mut-restriction.rs:6:13 + | +LL | pub mut(self) alpha: u8, + | ^^^^^^^^^ + +error: mutable use of restricted field + --> $DIR/mut-restriction.rs:23:5 + | +LL | foo.alpha = 1; + | ^^^^^^^^^^^^^ + | +note: mutability restricted here + --> $DIR/mut-restriction.rs:6:13 + | +LL | pub mut(self) alpha: u8, + | ^^^^^^^^^ + +error: mutable use of restricted field + --> $DIR/mut-restriction.rs:24:5 + | +LL | std::ptr::addr_of_mut!(foo.alpha); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: mutability restricted here + --> $DIR/mut-restriction.rs:6:13 + | +LL | pub mut(self) alpha: u8, + | ^^^^^^^^^ + = note: this error originates in the macro `std::ptr::addr_of_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: mutable use of restricted field + --> $DIR/mut-restriction.rs:26:18 + | +LL | let _alpha = &mut foo.alpha; + | ^^^^^^^^^^^^^^ + | +note: mutability restricted here + --> $DIR/mut-restriction.rs:6:13 + | +LL | pub mut(self) alpha: u8, + | ^^^^^^^^^ + +error: mutable use of restricted field + --> $DIR/mut-restriction.rs:29:9 + | +LL | foo.alpha = 1; + | ^^^^^^^^^^^^^ + | +note: mutability restricted here + --> $DIR/mut-restriction.rs:6:13 + | +LL | pub mut(self) alpha: u8, + | ^^^^^^^^^ + +error: aborting due to 6 previous errors + From 4a7aab243ec265634259db33eb27a46e68433ec3 Mon Sep 17 00:00:00 2001 From: Jacob Pratt Date: Fri, 22 Jul 2022 02:16:41 -0400 Subject: [PATCH 20/45] Validate `mut` restriction on enum variant fields --- .../rustc_resolve/src/build_reduced_graph.rs | 10 ++++- tests/ui/restrictions/mut-restriction.rs | 26 +++++++++++-- tests/ui/restrictions/mut-restriction.stderr | 38 +++++++++++++++---- 3 files changed, 62 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 93f0e9def38d7..28d2a02223996 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -793,7 +793,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { self.r.define(parent, ident, TypeNS, (res, vis, sp, expansion)); } - ItemKind::Enum(_, _) => { + ItemKind::Enum(ref enum_def, _) => { let module = self.r.new_module( Some(parent), ModuleKind::Def(DefKind::Enum, def_id, ident.name), @@ -803,6 +803,14 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { ); self.r.define(parent, ident, TypeNS, (module, vis, sp, expansion)); self.parent_scope.module = module; + + for variant in &enum_def.variants { + for field in variant.data.fields() { + let local_did = self.r.local_def_id(field.id); + let mut_restriction = self.resolve_restriction(&field.mut_restriction); + self.r.mut_restrictions.insert(local_did, mut_restriction); + } + } } ItemKind::TraitAlias(..) => { diff --git a/tests/ui/restrictions/mut-restriction.rs b/tests/ui/restrictions/mut-restriction.rs index 47e9b52918715..3b8b4e798ea10 100644 --- a/tests/ui/restrictions/mut-restriction.rs +++ b/tests/ui/restrictions/mut-restriction.rs @@ -5,13 +5,26 @@ pub mod foo { pub struct Foo { pub mut(self) alpha: u8, } + + pub enum Bar { + Beta(mut(self) u8), + } + + impl Default for Bar { + fn default() -> Self { + Bar::Beta(0) + } + } } -fn change_alpha(foo: &mut foo::Foo) { +fn mut_direct(foo: &mut foo::Foo, bar: &mut foo::Bar) { foo.alpha = 1; //~ ERROR mutable use of restricted field + match bar { + foo::Bar::Beta(ref mut beta) => {} //~ ERROR mutable use of restricted field + } } -fn change_alpha_ptr(foo: *mut foo::Foo) { +fn mut_ptr(foo: *mut foo::Foo) { // unsafe doesn't matter unsafe { (*foo).alpha = 1; //~ ERROR mutable use of restricted field @@ -20,7 +33,12 @@ fn change_alpha_ptr(foo: *mut foo::Foo) { fn main() { let mut foo = foo::Foo::default(); + let mut bar = foo::Bar::default(); + foo.alpha = 1; //~ ERROR mutable use of restricted field + match bar { + foo::Bar::Beta(ref mut beta) => {} //~ ERROR mutable use of restricted field + } std::ptr::addr_of_mut!(foo.alpha); //~ ERROR mutable use of restricted field let _alpha = &mut foo.alpha; //~ ERROR mutable use of restricted field @@ -31,8 +49,8 @@ fn main() { // okay: the mutation occurs inside the function closure(); - change_alpha(&mut foo); - change_alpha_ptr(&mut foo as *mut _); + mut_direct(&mut foo, &mut bar); + mut_ptr(&mut foo as *mut _); // okay: this is the same as turning &T into &mut T, which is unsound unsafe { *(&foo.alpha as *const _ as *mut _) = 1; } diff --git a/tests/ui/restrictions/mut-restriction.stderr b/tests/ui/restrictions/mut-restriction.stderr index 6fa16f51bd914..567183b7024d0 100644 --- a/tests/ui/restrictions/mut-restriction.stderr +++ b/tests/ui/restrictions/mut-restriction.stderr @@ -1,5 +1,5 @@ error: mutable use of restricted field - --> $DIR/mut-restriction.rs:11:5 + --> $DIR/mut-restriction.rs:21:5 | LL | foo.alpha = 1; | ^^^^^^^^^^^^^ @@ -11,7 +11,19 @@ LL | pub mut(self) alpha: u8, | ^^^^^^^^^ error: mutable use of restricted field - --> $DIR/mut-restriction.rs:17:9 + --> $DIR/mut-restriction.rs:23:24 + | +LL | foo::Bar::Beta(ref mut beta) => {} + | ^^^^^^^^^^^^ + | +note: mutability restricted here + --> $DIR/mut-restriction.rs:10:14 + | +LL | Beta(mut(self) u8), + | ^^^^^^^^^ + +error: mutable use of restricted field + --> $DIR/mut-restriction.rs:30:9 | LL | (*foo).alpha = 1; | ^^^^^^^^^^^^^^^^ @@ -23,7 +35,7 @@ LL | pub mut(self) alpha: u8, | ^^^^^^^^^ error: mutable use of restricted field - --> $DIR/mut-restriction.rs:23:5 + --> $DIR/mut-restriction.rs:38:5 | LL | foo.alpha = 1; | ^^^^^^^^^^^^^ @@ -35,7 +47,19 @@ LL | pub mut(self) alpha: u8, | ^^^^^^^^^ error: mutable use of restricted field - --> $DIR/mut-restriction.rs:24:5 + --> $DIR/mut-restriction.rs:40:24 + | +LL | foo::Bar::Beta(ref mut beta) => {} + | ^^^^^^^^^^^^ + | +note: mutability restricted here + --> $DIR/mut-restriction.rs:10:14 + | +LL | Beta(mut(self) u8), + | ^^^^^^^^^ + +error: mutable use of restricted field + --> $DIR/mut-restriction.rs:42:5 | LL | std::ptr::addr_of_mut!(foo.alpha); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -48,7 +72,7 @@ LL | pub mut(self) alpha: u8, = note: this error originates in the macro `std::ptr::addr_of_mut` (in Nightly builds, run with -Z macro-backtrace for more info) error: mutable use of restricted field - --> $DIR/mut-restriction.rs:26:18 + --> $DIR/mut-restriction.rs:44:18 | LL | let _alpha = &mut foo.alpha; | ^^^^^^^^^^^^^^ @@ -60,7 +84,7 @@ LL | pub mut(self) alpha: u8, | ^^^^^^^^^ error: mutable use of restricted field - --> $DIR/mut-restriction.rs:29:9 + --> $DIR/mut-restriction.rs:47:9 | LL | foo.alpha = 1; | ^^^^^^^^^^^^^ @@ -71,5 +95,5 @@ note: mutability restricted here LL | pub mut(self) alpha: u8, | ^^^^^^^^^ -error: aborting due to 6 previous errors +error: aborting due to 8 previous errors From 17ef482f31fb29a7fb02a78017b7d8b2e37ed167 Mon Sep 17 00:00:00 2001 From: Jacob Pratt Date: Sun, 24 Jul 2022 02:37:27 -0400 Subject: [PATCH 21/45] Split feature in two --- compiler/rustc_ast_passes/src/feature_gate.rs | 3 +- compiler/rustc_feature/src/active.rs | 6 ++- compiler/rustc_parse/src/parser/item.rs | 37 +++++++++++++------ compiler/rustc_parse/src/parser/mod.rs | 5 ++- compiler/rustc_span/src/symbol.rs | 3 +- .../{feature-gate.rs => impl-feature-gate.rs} | 4 +- ... => impl-feature-gate.without_gate.stderr} | 12 +++--- tests/ui/restrictions/impl-restriction.rs | 2 +- tests/ui/restrictions/mut-feature-gate.rs | 10 +++++ .../mut-feature-gate.without_gate.stderr | 11 ++++++ tests/ui/restrictions/mut-restriction.rs | 2 +- 11 files changed, 68 insertions(+), 27 deletions(-) rename tests/ui/restrictions/{feature-gate.rs => impl-feature-gate.rs} (76%) rename tests/ui/restrictions/{feature-gate.without_gate.stderr => impl-feature-gate.without_gate.stderr} (55%) create mode 100644 tests/ui/restrictions/mut-feature-gate.rs create mode 100644 tests/ui/restrictions/mut-feature-gate.without_gate.stderr diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index a16f0c16a86af..306963887e66e 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -556,7 +556,8 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session) { gate_all!(const_closures, "const closures are experimental"); gate_all!(builtin_syntax, "`builtin #` syntax is unstable"); gate_all!(explicit_tail_calls, "`become` expression is experimental"); - gate_all!(restrictions, "restrictions are experimental"); + gate_all!(impl_restriction, "restrictions are experimental"); + gate_all!(mut_restriction, "restrictions are experimental"); if !visitor.features.negative_bounds { for &span in spans.get(&sym::negative_bounds).iter().copied().flatten() { diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index e754086747960..9d326d21299b2 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -426,6 +426,8 @@ declare_features! ( (active, half_open_range_patterns_in_slices, "1.66.0", Some(67264), None), /// Allows `if let` guard in match arms. (active, if_let_guard, "1.47.0", Some(51114), None), + /// Allows restricting the implementation of traits. + (active, impl_restriction, "CURRENT_RUSTC_VERSION", None, None), /// Allows `impl Trait` to be used inside associated types (RFC 2515). (active, impl_trait_in_assoc_type, "1.70.0", Some(63063), None), /// Allows `impl Trait` as output type in `Fn` traits in return position of functions. @@ -462,6 +464,8 @@ declare_features! ( (active, more_qualified_paths, "1.54.0", Some(86935), None), /// Allows the `#[must_not_suspend]` attribute. (active, must_not_suspend, "1.57.0", Some(83310), None), + /// Allows restricting the mutation of fields. + (active, mut_restriction, "CURRENT_RUSTC_VERSION", None, None), /// Allows using `#[naked]` on functions. (active, naked_functions, "1.9.0", Some(32408), None), /// Allows specifying the as-needed link modifier @@ -505,8 +509,6 @@ declare_features! ( (incomplete, repr128, "1.16.0", Some(56071), None), /// Allows `repr(simd)` and importing the various simd intrinsics. (active, repr_simd, "1.4.0", Some(27731), None), - /// Allows restricting the implementation of traits and mutability of fields. - (active, restrictions, "CURRENT_RUSTC_VERSION", None, None), /// Allows return-position `impl Trait` in traits. (active, return_position_impl_trait_in_trait, "1.65.0", Some(91611), None), /// Allows bounding the return type of AFIT/RPITIT. diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index fbc45f5e4bcaa..2d7c303ecf704 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -831,8 +831,12 @@ impl<'a> Parser<'a> { /// Parses `impl(in path)? unsafe? auto? trait Foo { ... }` or `trait Foo = Bar;`. fn parse_item_trait(&mut self, attrs: &mut AttrVec, lo: Span) -> PResult<'a, ItemInfo> { - let impl_restriction = - self.parse_restriction(kw::Impl, "implementable", FollowedByType::No)?; + let impl_restriction = self.parse_restriction( + kw::Impl, + Some(sym::impl_restriction), + "implementable", + FollowedByType::No, + )?; let unsafety = self.parse_unsafety(Case::Sensitive); // Parse optional `auto` prefix. let is_auto = if self.eat_keyword(kw::Auto) { IsAuto::Yes } else { IsAuto::No }; @@ -1589,16 +1593,20 @@ impl<'a> Parser<'a> { return Err(err); } }; - let mut_restriction = - match p.parse_restriction(kw::Mut, "mutate", FollowedByType::Yes) { - Ok(mut_restriction) => mut_restriction, - Err(err) => { - if let Some(ref mut snapshot) = snapshot { - snapshot.recover_diff_marker(); - } - return Err(err); + let mut_restriction = match p.parse_restriction( + kw::Mut, + Some(sym::mut_restriction), + "mutate", + FollowedByType::Yes, + ) { + Ok(mut_restriction) => mut_restriction, + Err(err) => { + if let Some(ref mut snapshot) = snapshot { + snapshot.recover_diff_marker(); } - }; + return Err(err); + } + }; let ty = match p.parse_ty() { Ok(ty) => ty, Err(err) => { @@ -1635,7 +1643,12 @@ impl<'a> Parser<'a> { self.collect_tokens_trailing_token(attrs, ForceCollect::No, |this, attrs| { let lo = this.token.span; let vis = this.parse_visibility(FollowedByType::No)?; - let mut_restriction = this.parse_restriction(kw::Mut, "mutate", FollowedByType::No)?; + let mut_restriction = this.parse_restriction( + kw::Mut, + Some(sym::mut_restriction), + "mutate", + FollowedByType::No, + )?; Ok(( this.parse_single_struct_field(adt_ty, lo, vis, mut_restriction, attrs)?, TrailingToken::None, diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 66a70c8147519..016e63ea2c6da 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -1464,6 +1464,7 @@ impl<'a> Parser<'a> { fn parse_restriction( &mut self, kw: Symbol, + feature_gate: Option, action: &str, fbt: FollowedByType, ) -> PResult<'a, Restriction> { @@ -1475,7 +1476,9 @@ impl<'a> Parser<'a> { } let gate = |span| { - self.sess.gated_spans.gate(sym::restrictions, span); + if let Some(feature_gate) = feature_gate { + self.sess.gated_spans.gate(feature_gate, span); + } span }; diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 3b5fe561f7d52..c6e2a2541fdc6 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -814,6 +814,7 @@ symbols! { ignore, impl_header_lifetime_elision, impl_lint_pass, + impl_restriction, impl_trait_in_assoc_type, impl_trait_in_bindings, impl_trait_in_fn_trait_return, @@ -978,6 +979,7 @@ symbols! { multiple_supertrait_upcastable, must_not_suspend, must_use, + mut_restriction, naked, naked_functions, name, @@ -1222,7 +1224,6 @@ symbols! { repr_transparent, require, residual, - restrictions, result, resume, return_position_impl_trait_in_trait, diff --git a/tests/ui/restrictions/feature-gate.rs b/tests/ui/restrictions/impl-feature-gate.rs similarity index 76% rename from tests/ui/restrictions/feature-gate.rs rename to tests/ui/restrictions/impl-feature-gate.rs index f5c8c45991d96..0531796ca09a0 100644 --- a/tests/ui/restrictions/feature-gate.rs +++ b/tests/ui/restrictions/impl-feature-gate.rs @@ -1,9 +1,9 @@ -// gate-test-restrictions +// gate-test-impl_restriction // compile-flags: --crate-type=lib // revisions: with_gate without_gate //[with_gate] check-pass -#![cfg_attr(with_gate, feature(restrictions))] +#![cfg_attr(with_gate, feature(impl_restriction))] pub impl trait Foo {} //[without_gate]~ ERROR pub impl(crate) trait Bar {} //[without_gate]~ ERROR diff --git a/tests/ui/restrictions/feature-gate.without_gate.stderr b/tests/ui/restrictions/impl-feature-gate.without_gate.stderr similarity index 55% rename from tests/ui/restrictions/feature-gate.without_gate.stderr rename to tests/ui/restrictions/impl-feature-gate.without_gate.stderr index e1d38263f9727..e26da7a5dc997 100644 --- a/tests/ui/restrictions/feature-gate.without_gate.stderr +++ b/tests/ui/restrictions/impl-feature-gate.without_gate.stderr @@ -1,26 +1,26 @@ error[E0658]: restrictions are experimental - --> $DIR/feature-gate.rs:8:5 + --> $DIR/impl-feature-gate.rs:8:5 | LL | pub impl trait Foo {} | ^^^^ | - = help: add `#![feature(restrictions)]` to the crate attributes to enable + = help: add `#![feature(impl_restriction)]` to the crate attributes to enable error[E0658]: restrictions are experimental - --> $DIR/feature-gate.rs:9:5 + --> $DIR/impl-feature-gate.rs:9:5 | LL | pub impl(crate) trait Bar {} | ^^^^^^^^^^^ | - = help: add `#![feature(restrictions)]` to the crate attributes to enable + = help: add `#![feature(impl_restriction)]` to the crate attributes to enable error[E0658]: restrictions are experimental - --> $DIR/feature-gate.rs:12:9 + --> $DIR/impl-feature-gate.rs:12:9 | LL | pub impl(in foo) trait Baz {} | ^^^^^^^^^^^^ | - = help: add `#![feature(restrictions)]` to the crate attributes to enable + = help: add `#![feature(impl_restriction)]` to the crate attributes to enable error: aborting due to 3 previous errors diff --git a/tests/ui/restrictions/impl-restriction.rs b/tests/ui/restrictions/impl-restriction.rs index e4afe0dcd79f7..bbd2612cd50e5 100644 --- a/tests/ui/restrictions/impl-restriction.rs +++ b/tests/ui/restrictions/impl-restriction.rs @@ -1,6 +1,6 @@ // compile-flags: --crate-type=lib -#![feature(restrictions)] +#![feature(impl_restriction)] pub mod foo { pub mod bar { diff --git a/tests/ui/restrictions/mut-feature-gate.rs b/tests/ui/restrictions/mut-feature-gate.rs new file mode 100644 index 0000000000000..f5f654879df3f --- /dev/null +++ b/tests/ui/restrictions/mut-feature-gate.rs @@ -0,0 +1,10 @@ +// gate-test-mut_restriction +// compile-flags: --crate-type=lib +// revisions: with_gate without_gate +//[with_gate] check-pass + +#![cfg_attr(with_gate, feature(mut_restriction))] + +pub struct Foo { + pub mut(self) alpha: u8, //[without_gate]~ ERROR +} diff --git a/tests/ui/restrictions/mut-feature-gate.without_gate.stderr b/tests/ui/restrictions/mut-feature-gate.without_gate.stderr new file mode 100644 index 0000000000000..abfedbaf60301 --- /dev/null +++ b/tests/ui/restrictions/mut-feature-gate.without_gate.stderr @@ -0,0 +1,11 @@ +error[E0658]: restrictions are experimental + --> $DIR/mut-feature-gate.rs:9:9 + | +LL | pub mut(self) alpha: u8, + | ^^^^^^^^^ + | + = help: add `#![feature(mut_restriction)]` to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/restrictions/mut-restriction.rs b/tests/ui/restrictions/mut-restriction.rs index 3b8b4e798ea10..c894380d46b2c 100644 --- a/tests/ui/restrictions/mut-restriction.rs +++ b/tests/ui/restrictions/mut-restriction.rs @@ -1,4 +1,4 @@ -#![feature(restrictions)] +#![feature(mut_restriction)] pub mod foo { #[derive(Default)] From 0561a0b02e45745c5125f1638ce7ac45b0f87a19 Mon Sep 17 00:00:00 2001 From: Jacob Pratt Date: Wed, 27 Jul 2022 21:34:55 -0400 Subject: [PATCH 22/45] Ban expressions with mut restricted fields --- compiler/rustc_middle/src/ty/mod.rs | 31 +++++++++++++++++++ compiler/rustc_restrictions/messages.ftl | 4 +++ compiler/rustc_restrictions/src/errors.rs | 12 +++++++ compiler/rustc_restrictions/src/lib.rs | 1 + .../rustc_restrictions/src/mut_restriction.rs | 26 ++++++++++++++++ .../mut-restriction-construction.rs | 16 ++++++++++ .../mut-restriction-construction.stderr | 24 ++++++++++++++ 7 files changed, 114 insertions(+) create mode 100644 tests/ui/restrictions/mut-restriction-construction.rs create mode 100644 tests/ui/restrictions/mut-restriction-construction.stderr diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 05c5651409bc6..ec111acdbe6dc 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -319,6 +319,37 @@ impl> Restriction { Restriction::Restricted(_, span) => *span, } } + /// Obtain the stricter of the two restrictions. If the two restrictions are the same, returns + /// `left`. Panics if the restrictions do not reference the same crate. + pub fn stricter_of(left: Self, right: Self, tcx: TyCtxt<'_>) -> Self + where + Id: Copy, + { + match (left, right) { + (Restriction::Unrestricted, Restriction::Unrestricted) => Restriction::Unrestricted, + (Restriction::Unrestricted, Restriction::Restricted(..)) => right, + (Restriction::Restricted(..), Restriction::Unrestricted) => left, + (Restriction::Restricted(left_did, _), Restriction::Restricted(right_did, _)) => { + let left_did = left_did.into(); + let right_did = right_did.into(); + + if left_did.krate != right_did.krate { + bug!("stricter_of: left and right restriction do not reference the same crate"); + } + + if tcx.is_descendant_of(left_did, right_did) { left } else { right } + } + } + } + + /// Obtain the strictest of the provided restrictions. If multiple restrictions are the same, + /// the first is returned. Panics if all restrictions do not reference the same crate. + pub fn strictest_of(iter: impl Iterator, tcx: TyCtxt<'_>) -> Self + where + Id: Copy, + { + iter.fold(Restriction::Unrestricted, |left, right| Self::stricter_of(left, right, tcx)) + } pub fn map_id(self, f: impl FnOnce(Id) -> OutId) -> Restriction { match self { diff --git a/compiler/rustc_restrictions/messages.ftl b/compiler/rustc_restrictions/messages.ftl index 28b476c947828..0de352602e988 100644 --- a/compiler/rustc_restrictions/messages.ftl +++ b/compiler/rustc_restrictions/messages.ftl @@ -3,3 +3,7 @@ restrictions_impl_of_restricted_trait = implementation of restricted trait restrictions_mut_of_restricted_field = mutable use of restricted field .note = mutability restricted here + +restrictions_construction_of_ty_with_mut_restricted_field = construction of {$ty} with mut restricted field + .label = mutability restricted here + .note = {$ty} expressions cannot be used when the {$ty} has a field with a mutability restriction diff --git a/compiler/rustc_restrictions/src/errors.rs b/compiler/rustc_restrictions/src/errors.rs index 36423d2096a7c..0248636828df3 100644 --- a/compiler/rustc_restrictions/src/errors.rs +++ b/compiler/rustc_restrictions/src/errors.rs @@ -18,3 +18,15 @@ pub struct MutOfRestrictedField { #[note] pub restriction_span: Span, } + +#[derive(Diagnostic)] +#[diag(restrictions_construction_of_ty_with_mut_restricted_field)] +pub struct ConstructionOfTyWithMutRestrictedField { + #[primary_span] + pub construction_span: Span, + #[label] + pub restriction_span: Span, + #[note] + pub note: (), + pub ty: &'static str, +} diff --git a/compiler/rustc_restrictions/src/lib.rs b/compiler/rustc_restrictions/src/lib.rs index 09d2cc8b722ae..7f9eb7051471d 100644 --- a/compiler/rustc_restrictions/src/lib.rs +++ b/compiler/rustc_restrictions/src/lib.rs @@ -1,6 +1,7 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::diagnostic_outside_of_impl)] +#![feature(box_patterns)] mod errors; mod impl_restriction; diff --git a/compiler/rustc_restrictions/src/mut_restriction.rs b/compiler/rustc_restrictions/src/mut_restriction.rs index 660af95de83bc..1aa570ef12a74 100644 --- a/compiler/rustc_restrictions/src/mut_restriction.rs +++ b/compiler/rustc_restrictions/src/mut_restriction.rs @@ -1,6 +1,7 @@ use rustc_hir::def_id::LocalDefId; use rustc_hir::Node; use rustc_middle::mir::visit::{PlaceContext, Visitor}; +use rustc_middle::mir::{AggregateKind, Rvalue}; use rustc_middle::mir::{Body, Location, Place, ProjectionElem, Statement, Terminator}; use rustc_middle::query::Providers; use rustc_middle::span_bug; @@ -95,4 +96,29 @@ impl<'tcx> Visitor<'tcx> for MutRestrictionChecker<'_, 'tcx> { } } } + + // TODO(jhpratt) make this into a query to take advantage of caching + fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) { + if let Rvalue::Aggregate(box AggregateKind::Adt(def_id, variant_idx, _, _, _), _) = rvalue { + let adt_def = self.tcx.type_of(def_id).0.ty_adt_def().unwrap(); + let variant = adt_def.variant(*variant_idx); + + let construction_restriction = Restriction::strictest_of( + variant.fields.iter().map(|field| field.mut_restriction), + self.tcx, + ); + + let body_did = self.body.source.instance.def_id(); + if construction_restriction.is_restricted_in(body_did, self.tcx) { + self.tcx.sess.emit_err(errors::ConstructionOfTyWithMutRestrictedField { + construction_span: self.span, + restriction_span: construction_restriction.expect_span(), + note: (), + ty: adt_def.variant_descr(), + }); + } + } + + self.super_rvalue(rvalue, location); + } } diff --git a/tests/ui/restrictions/mut-restriction-construction.rs b/tests/ui/restrictions/mut-restriction-construction.rs new file mode 100644 index 0000000000000..75e64d7ea74f7 --- /dev/null +++ b/tests/ui/restrictions/mut-restriction-construction.rs @@ -0,0 +1,16 @@ +#![feature(mut_restriction)] + +pub mod foo { + pub struct Foo { + pub mut(self) alpha: u8, + } + + pub enum Bar { + Beta(mut(self) u8), + } +} + +fn main() { + let foo = foo::Foo { alpha: 0 }; //~ ERROR + let bar = foo::Bar::Beta(0); //~ ERROR +} diff --git a/tests/ui/restrictions/mut-restriction-construction.stderr b/tests/ui/restrictions/mut-restriction-construction.stderr new file mode 100644 index 0000000000000..a65ca146f96fe --- /dev/null +++ b/tests/ui/restrictions/mut-restriction-construction.stderr @@ -0,0 +1,24 @@ +error: construction of struct with mut restricted field + --> $DIR/mut-restriction-construction.rs:14:15 + | +LL | pub mut(self) alpha: u8, + | --------- mutability restricted here +... +LL | let foo = foo::Foo { alpha: 0 }; + | ^^^^^^^^^^^^^^^^^^^^^ + | + = note: struct expressions cannot be used when the struct has a field with a mutability restriction + +error: construction of variant with mut restricted field + --> $DIR/mut-restriction-construction.rs:15:15 + | +LL | Beta(mut(self) u8), + | --------- mutability restricted here +... +LL | let bar = foo::Bar::Beta(0); + | ^^^^^^^^^^^^^^^^^ + | + = note: variant expressions cannot be used when the variant has a field with a mutability restriction + +error: aborting due to 2 previous errors + From e984d823780308ceaa7dab15551e571c243c2cf9 Mon Sep 17 00:00:00 2001 From: Jacob Pratt Date: Wed, 27 Jul 2022 22:00:56 -0400 Subject: [PATCH 23/45] Improve diagnostics --- compiler/rustc_restrictions/messages.ftl | 4 +- compiler/rustc_restrictions/src/errors.rs | 4 +- tests/ui/restrictions/impl-restriction.stderr | 9 +-- tests/ui/restrictions/mut-restriction.stderr | 71 +++++++------------ 4 files changed, 31 insertions(+), 57 deletions(-) diff --git a/compiler/rustc_restrictions/messages.ftl b/compiler/rustc_restrictions/messages.ftl index 0de352602e988..c7db2e4145810 100644 --- a/compiler/rustc_restrictions/messages.ftl +++ b/compiler/rustc_restrictions/messages.ftl @@ -1,8 +1,8 @@ restrictions_impl_of_restricted_trait = implementation of restricted trait - .note = trait restricted here + .label = trait restricted here restrictions_mut_of_restricted_field = mutable use of restricted field - .note = mutability restricted here + .label = mutability restricted here restrictions_construction_of_ty_with_mut_restricted_field = construction of {$ty} with mut restricted field .label = mutability restricted here diff --git a/compiler/rustc_restrictions/src/errors.rs b/compiler/rustc_restrictions/src/errors.rs index 0248636828df3..c38b9c5ff9edd 100644 --- a/compiler/rustc_restrictions/src/errors.rs +++ b/compiler/rustc_restrictions/src/errors.rs @@ -6,7 +6,7 @@ use rustc_span::Span; pub struct ImplOfRestrictedTrait { #[primary_span] pub impl_span: Span, - #[note] + #[label] pub restriction_span: Span, } @@ -15,7 +15,7 @@ pub struct ImplOfRestrictedTrait { pub struct MutOfRestrictedField { #[primary_span] pub mut_span: Span, - #[note] + #[label] pub restriction_span: Span, } diff --git a/tests/ui/restrictions/impl-restriction.stderr b/tests/ui/restrictions/impl-restriction.stderr index b73d1f29a036d..21b2de3106b81 100644 --- a/tests/ui/restrictions/impl-restriction.stderr +++ b/tests/ui/restrictions/impl-restriction.stderr @@ -1,14 +1,11 @@ error: implementation of restricted trait --> $DIR/impl-restriction.rs:13:1 | +LL | pub(crate) impl(super) trait Foo {} + | ----------- trait restricted here +... LL | impl foo::bar::Foo for u8 {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ - | -note: trait restricted here - --> $DIR/impl-restriction.rs:7:20 - | -LL | pub(crate) impl(super) trait Foo {} - | ^^^^^^^^^^^ error: aborting due to previous error diff --git a/tests/ui/restrictions/mut-restriction.stderr b/tests/ui/restrictions/mut-restriction.stderr index 567183b7024d0..a4fca52cc0e7b 100644 --- a/tests/ui/restrictions/mut-restriction.stderr +++ b/tests/ui/restrictions/mut-restriction.stderr @@ -1,99 +1,76 @@ error: mutable use of restricted field --> $DIR/mut-restriction.rs:21:5 | +LL | pub mut(self) alpha: u8, + | --------- mutability restricted here +... LL | foo.alpha = 1; | ^^^^^^^^^^^^^ - | -note: mutability restricted here - --> $DIR/mut-restriction.rs:6:13 - | -LL | pub mut(self) alpha: u8, - | ^^^^^^^^^ error: mutable use of restricted field --> $DIR/mut-restriction.rs:23:24 | +LL | Beta(mut(self) u8), + | --------- mutability restricted here +... LL | foo::Bar::Beta(ref mut beta) => {} | ^^^^^^^^^^^^ - | -note: mutability restricted here - --> $DIR/mut-restriction.rs:10:14 - | -LL | Beta(mut(self) u8), - | ^^^^^^^^^ error: mutable use of restricted field --> $DIR/mut-restriction.rs:30:9 | +LL | pub mut(self) alpha: u8, + | --------- mutability restricted here +... LL | (*foo).alpha = 1; | ^^^^^^^^^^^^^^^^ - | -note: mutability restricted here - --> $DIR/mut-restriction.rs:6:13 - | -LL | pub mut(self) alpha: u8, - | ^^^^^^^^^ error: mutable use of restricted field --> $DIR/mut-restriction.rs:38:5 | +LL | pub mut(self) alpha: u8, + | --------- mutability restricted here +... LL | foo.alpha = 1; | ^^^^^^^^^^^^^ - | -note: mutability restricted here - --> $DIR/mut-restriction.rs:6:13 - | -LL | pub mut(self) alpha: u8, - | ^^^^^^^^^ error: mutable use of restricted field --> $DIR/mut-restriction.rs:40:24 | +LL | Beta(mut(self) u8), + | --------- mutability restricted here +... LL | foo::Bar::Beta(ref mut beta) => {} | ^^^^^^^^^^^^ - | -note: mutability restricted here - --> $DIR/mut-restriction.rs:10:14 - | -LL | Beta(mut(self) u8), - | ^^^^^^^^^ error: mutable use of restricted field --> $DIR/mut-restriction.rs:42:5 | +LL | pub mut(self) alpha: u8, + | --------- mutability restricted here +... LL | std::ptr::addr_of_mut!(foo.alpha); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: mutability restricted here - --> $DIR/mut-restriction.rs:6:13 - | -LL | pub mut(self) alpha: u8, - | ^^^^^^^^^ = note: this error originates in the macro `std::ptr::addr_of_mut` (in Nightly builds, run with -Z macro-backtrace for more info) error: mutable use of restricted field --> $DIR/mut-restriction.rs:44:18 | +LL | pub mut(self) alpha: u8, + | --------- mutability restricted here +... LL | let _alpha = &mut foo.alpha; | ^^^^^^^^^^^^^^ - | -note: mutability restricted here - --> $DIR/mut-restriction.rs:6:13 - | -LL | pub mut(self) alpha: u8, - | ^^^^^^^^^ error: mutable use of restricted field --> $DIR/mut-restriction.rs:47:9 | +LL | pub mut(self) alpha: u8, + | --------- mutability restricted here +... LL | foo.alpha = 1; | ^^^^^^^^^^^^^ - | -note: mutability restricted here - --> $DIR/mut-restriction.rs:6:13 - | -LL | pub mut(self) alpha: u8, - | ^^^^^^^^^ error: aborting due to 8 previous errors From 3421cb94143c4ad8d1d325e45e52fcdd22b19490 Mon Sep 17 00:00:00 2001 From: Jacob Pratt Date: Tue, 26 Jul 2022 19:34:21 -0400 Subject: [PATCH 24/45] Turn construction restriction into a query This allows the compiler to cache the result. --- compiler/rustc_middle/src/query/mod.rs | 8 ++++++ .../rustc_restrictions/src/mut_restriction.rs | 27 ++++++++++++++----- 2 files changed, 28 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 0daad5ea7e48c..b095781049bda 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1720,6 +1720,14 @@ rustc_queries! { desc { "checking mut restrictions" } } + query adt_expression_restriction(variant_def_id: DefId) -> ty::Restriction { + desc { + "computing where `{}` can be constructed via an ADT expression", + tcx.def_path_str(variant_def_id) + } + cache_on_disk_if { true } + } + query dep_kind(_: CrateNum) -> CrateDepKind { eval_always desc { "fetching what a dependency looks like" } diff --git a/compiler/rustc_restrictions/src/mut_restriction.rs b/compiler/rustc_restrictions/src/mut_restriction.rs index 1aa570ef12a74..5f8300e7b2373 100644 --- a/compiler/rustc_restrictions/src/mut_restriction.rs +++ b/compiler/rustc_restrictions/src/mut_restriction.rs @@ -1,4 +1,5 @@ -use rustc_hir::def_id::LocalDefId; +use rustc_hir::def::Res; +use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::Node; use rustc_middle::mir::visit::{PlaceContext, Visitor}; use rustc_middle::mir::{AggregateKind, Rvalue}; @@ -11,7 +12,12 @@ use rustc_span::Span; use crate::errors; pub(crate) fn provide(providers: &mut Providers) { - *providers = Providers { mut_restriction, check_mut_restriction, ..*providers }; + *providers = Providers { + mut_restriction, + check_mut_restriction, + adt_expression_restriction, + ..*providers + }; } fn mut_restriction(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Restriction { @@ -52,6 +58,17 @@ fn check_mut_restriction(tcx: TyCtxt<'_>, def_id: LocalDefId) { checker.visit_body(body); } +/// Obtain the restriction on ADT expressions. This occurs when an ADT field has its mutability +/// restricted. +// This is a query to allow the compiler to cache the output. This avoids the need to recompute the +// same information for every ADT expression. +fn adt_expression_restriction(tcx: TyCtxt<'_>, variant_def_id: DefId) -> Restriction { + let res = Res::Def(tcx.def_kind(variant_def_id), variant_def_id); + let variant = tcx.expect_variant_res(res); + + Restriction::strictest_of(variant.fields.iter().map(|field| field.mut_restriction), tcx) +} + struct MutRestrictionChecker<'a, 'tcx> { tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, @@ -97,16 +114,12 @@ impl<'tcx> Visitor<'tcx> for MutRestrictionChecker<'_, 'tcx> { } } - // TODO(jhpratt) make this into a query to take advantage of caching fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) { if let Rvalue::Aggregate(box AggregateKind::Adt(def_id, variant_idx, _, _, _), _) = rvalue { let adt_def = self.tcx.type_of(def_id).0.ty_adt_def().unwrap(); let variant = adt_def.variant(*variant_idx); - let construction_restriction = Restriction::strictest_of( - variant.fields.iter().map(|field| field.mut_restriction), - self.tcx, - ); + let construction_restriction = self.tcx.adt_expression_restriction(variant.def_id); let body_did = self.body.source.instance.def_id(); if construction_restriction.is_restricted_in(body_did, self.tcx) { From 400b4d0f574392eb5cc5e7dda570f46c00c09134 Mon Sep 17 00:00:00 2001 From: Jacob Pratt Date: Wed, 10 Aug 2022 18:07:03 -0400 Subject: [PATCH 25/45] Add stringify tests for restrictions --- tests/ui/macros/stringify.rs | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/tests/ui/macros/stringify.rs b/tests/ui/macros/stringify.rs index 8f940cb675958..ef0029d4d2968 100644 --- a/tests/ui/macros/stringify.rs +++ b/tests/ui/macros/stringify.rs @@ -884,6 +884,21 @@ fn test_vis() { } #[test] -fn test_restriction() { +fn test_impl_restriction() { assert_eq!(stringify!(pub impl(crate) trait Foo {}), "pub impl(crate) trait Foo {}"); + assert_eq!(stringify!(pub impl(in crate) trait Foo {}), "pub impl(in crate) trait Foo {}"); + assert_eq!(stringify!(pub impl(super) trait Foo {}), "pub impl(super) trait Foo {}"); + assert_eq!(stringify!(pub impl(in super) trait Foo {}), "pub impl(in super) trait Foo {}"); + assert_eq!(stringify!(pub impl(self) trait Foo {}), "pub impl(self) trait Foo {}"); + assert_eq!(stringify!(pub impl(in self) trait Foo {}), "pub impl(in self) trait Foo {}"); +} + +#[test] +fn test_mut_restriction() { + assert_eq!(stringify!(pub mut(crate) struct Foo {}), "pub mut(crate) struct Foo {}"); + assert_eq!(stringify!(pub mut(in crate) struct Foo {}), "pub mut(in crate) struct Foo {}"); + assert_eq!(stringify!(pub mut(super) struct Foo {}), "pub mut(super) struct Foo {}"); + assert_eq!(stringify!(pub mut(in super) struct Foo {}), "pub mut(in super) struct Foo {}"); + assert_eq!(stringify!(pub mut(self) struct Foo {}), "pub mut(self) struct Foo {}"); + assert_eq!(stringify!(pub mut(in self) struct Foo {}), "pub mut(in self) struct Foo {}"); } From 8a85dc57d2e29420c8302eecf003744ee05238b7 Mon Sep 17 00:00:00 2001 From: Jacob Pratt Date: Wed, 19 Oct 2022 02:29:39 -0400 Subject: [PATCH 26/45] Improve diagnostics --- compiler/rustc_middle/src/ty/mod.rs | 31 +++++++--- compiler/rustc_restrictions/messages.ftl | 11 ++-- compiler/rustc_restrictions/src/errors.rs | 7 ++- .../src/impl_restriction.rs | 2 + .../rustc_restrictions/src/mut_restriction.rs | 9 ++- .../auxiliary/external-impl-restriction.rs | 7 +++ .../auxiliary/external-mut-restriction.rs | 23 ++++++++ tests/ui/restrictions/impl-restriction.rs | 10 +++- tests/ui/restrictions/impl-restriction.stderr | 4 +- .../mut-restriction-construction.rs | 4 +- .../mut-restriction-construction.stderr | 8 +-- tests/ui/restrictions/mut-restriction.rs | 30 +++++++--- tests/ui/restrictions/mut-restriction.stderr | 56 +++++++++++++------ 13 files changed, 152 insertions(+), 50 deletions(-) create mode 100644 tests/ui/restrictions/auxiliary/external-impl-restriction.rs create mode 100644 tests/ui/restrictions/auxiliary/external-mut-restriction.rs diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index ec111acdbe6dc..eb384236c1546 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -300,7 +300,7 @@ pub enum Restriction { Restricted(Id, Span), } -impl> Restriction { +impl + Copy> Restriction { /// Returns `true` if this restriction applies in the given module. This /// means the behavior is _not_ allowed. pub fn is_restricted_in(self, module: DefId, tcx: TyCtxt<'_>) -> bool { @@ -319,12 +319,28 @@ impl> Restriction { Restriction::Restricted(_, span) => *span, } } + + pub fn expect_restriction_path( + &self, + tcx: TyCtxt<'_>, + krate: rustc_span::def_id::CrateNum, + ) -> String { + let Restriction::Restricted(def_id, _) = self else { + bug!("called `expect_restricted_path` on an unrestricted item") + }; + + let def_id: DefId = (*def_id).into(); + + if krate == def_id.krate { + tcx.def_path_str(def_id) + } else { + tcx.crate_name(krate).to_ident_string() + } + } + /// Obtain the stricter of the two restrictions. If the two restrictions are the same, returns /// `left`. Panics if the restrictions do not reference the same crate. - pub fn stricter_of(left: Self, right: Self, tcx: TyCtxt<'_>) -> Self - where - Id: Copy, - { + pub fn stricter_of(left: Self, right: Self, tcx: TyCtxt<'_>) -> Self { match (left, right) { (Restriction::Unrestricted, Restriction::Unrestricted) => Restriction::Unrestricted, (Restriction::Unrestricted, Restriction::Restricted(..)) => right, @@ -344,10 +360,7 @@ impl> Restriction { /// Obtain the strictest of the provided restrictions. If multiple restrictions are the same, /// the first is returned. Panics if all restrictions do not reference the same crate. - pub fn strictest_of(iter: impl Iterator, tcx: TyCtxt<'_>) -> Self - where - Id: Copy, - { + pub fn strictest_of(iter: impl Iterator, tcx: TyCtxt<'_>) -> Self { iter.fold(Restriction::Unrestricted, |left, right| Self::stricter_of(left, right, tcx)) } diff --git a/compiler/rustc_restrictions/messages.ftl b/compiler/rustc_restrictions/messages.ftl index c7db2e4145810..95eef84efb7e1 100644 --- a/compiler/rustc_restrictions/messages.ftl +++ b/compiler/rustc_restrictions/messages.ftl @@ -1,9 +1,12 @@ -restrictions_impl_of_restricted_trait = implementation of restricted trait +restrictions_impl_of_restricted_trait = + trait cannot be implemented outside `{$restriction_path}` .label = trait restricted here -restrictions_mut_of_restricted_field = mutable use of restricted field +restrictions_mut_of_restricted_field = + field cannot be mutated outside `{$restriction_path}` .label = mutability restricted here -restrictions_construction_of_ty_with_mut_restricted_field = construction of {$ty} with mut restricted field +restrictions_construction_of_ty_with_mut_restricted_field = + `{$name}` cannot be constructed using {$article} {$description} expression outside `{$restriction_path}` + .note = {$article} {$description} containing fields with a mutability restriction cannot be constructed using {$article} {$description} expression .label = mutability restricted here - .note = {$ty} expressions cannot be used when the {$ty} has a field with a mutability restriction diff --git a/compiler/rustc_restrictions/src/errors.rs b/compiler/rustc_restrictions/src/errors.rs index c38b9c5ff9edd..24e3a74682c77 100644 --- a/compiler/rustc_restrictions/src/errors.rs +++ b/compiler/rustc_restrictions/src/errors.rs @@ -8,6 +8,7 @@ pub struct ImplOfRestrictedTrait { pub impl_span: Span, #[label] pub restriction_span: Span, + pub restriction_path: String, } #[derive(Diagnostic)] @@ -17,6 +18,7 @@ pub struct MutOfRestrictedField { pub mut_span: Span, #[label] pub restriction_span: Span, + pub restriction_path: String, } #[derive(Diagnostic)] @@ -26,7 +28,10 @@ pub struct ConstructionOfTyWithMutRestrictedField { pub construction_span: Span, #[label] pub restriction_span: Span, + pub restriction_path: String, #[note] pub note: (), - pub ty: &'static str, + pub article: &'static str, + pub description: &'static str, + pub name: String, } diff --git a/compiler/rustc_restrictions/src/impl_restriction.rs b/compiler/rustc_restrictions/src/impl_restriction.rs index f802802f6cad1..3667db64360d2 100644 --- a/compiler/rustc_restrictions/src/impl_restriction.rs +++ b/compiler/rustc_restrictions/src/impl_restriction.rs @@ -31,6 +31,8 @@ impl<'v> Visitor<'v> for ImplOfRestrictedTraitVisitor<'v> { self.tcx.sess.emit_err(errors::ImplOfRestrictedTrait { impl_span: self.tcx.span_of_impl(impl_).expect("impl should be local"), restriction_span: restriction.expect_span(), + restriction_path: restriction + .expect_restriction_path(self.tcx, hir::def_id::LOCAL_CRATE), }); } }); diff --git a/compiler/rustc_restrictions/src/mut_restriction.rs b/compiler/rustc_restrictions/src/mut_restriction.rs index 5f8300e7b2373..cdddd48383b03 100644 --- a/compiler/rustc_restrictions/src/mut_restriction.rs +++ b/compiler/rustc_restrictions/src/mut_restriction.rs @@ -106,6 +106,9 @@ impl<'tcx> Visitor<'tcx> for MutRestrictionChecker<'_, 'tcx> { self.tcx.sess.emit_err(errors::MutOfRestrictedField { mut_span: self.span, restriction_span: field_def.mut_restriction.expect_span(), + restriction_path: field_def + .mut_restriction + .expect_restriction_path(self.tcx, body_did.krate), }); } } @@ -126,8 +129,12 @@ impl<'tcx> Visitor<'tcx> for MutRestrictionChecker<'_, 'tcx> { self.tcx.sess.emit_err(errors::ConstructionOfTyWithMutRestrictedField { construction_span: self.span, restriction_span: construction_restriction.expect_span(), + restriction_path: construction_restriction + .expect_restriction_path(self.tcx, body_did.krate), note: (), - ty: adt_def.variant_descr(), + article: "a", + description: adt_def.variant_descr(), + name: variant.name.to_ident_string(), }); } } diff --git a/tests/ui/restrictions/auxiliary/external-impl-restriction.rs b/tests/ui/restrictions/auxiliary/external-impl-restriction.rs new file mode 100644 index 0000000000000..fa3814add9d38 --- /dev/null +++ b/tests/ui/restrictions/auxiliary/external-impl-restriction.rs @@ -0,0 +1,7 @@ +#![feature(impl_restriction)] + +pub impl(crate) trait TopLevel {} + +pub mod inner { + pub impl(self) trait Inner {} +} diff --git a/tests/ui/restrictions/auxiliary/external-mut-restriction.rs b/tests/ui/restrictions/auxiliary/external-mut-restriction.rs new file mode 100644 index 0000000000000..c4c485f22a046 --- /dev/null +++ b/tests/ui/restrictions/auxiliary/external-mut-restriction.rs @@ -0,0 +1,23 @@ +#![feature(mut_restriction)] + +pub struct TopLevel { + pub mut(self) alpha: u8, +} + +impl TopLevel { + pub fn new() -> Self { + Self { alpha: 0 } + } +} + +pub mod inner { + pub struct Inner { + pub mut(self) beta: u8, + } + + impl Inner { + pub fn new() -> Self { + Self { beta: 0 } + } + } +} diff --git a/tests/ui/restrictions/impl-restriction.rs b/tests/ui/restrictions/impl-restriction.rs index bbd2612cd50e5..752a6f72a8f1d 100644 --- a/tests/ui/restrictions/impl-restriction.rs +++ b/tests/ui/restrictions/impl-restriction.rs @@ -1,7 +1,15 @@ // compile-flags: --crate-type=lib +// aux-build: external-impl-restriction.rs #![feature(impl_restriction)] +extern crate external_impl_restriction; + +struct LocalType; // needed to avoid orphan rule errors + +impl external_impl_restriction::TopLevel for LocalType {} //FIXME~ ERROR trait cannot be implemented outside `external_impl_restriction` +impl external_impl_restriction::inner::Inner for LocalType {} //FIXME~ ERROR trait cannot be implemented outside `external_impl_restriction` + pub mod foo { pub mod bar { pub(crate) impl(super) trait Foo {} @@ -10,4 +18,4 @@ pub mod foo { impl bar::Foo for i8 {} } -impl foo::bar::Foo for u8 {} //~ ERROR implementation of restricted trait +impl foo::bar::Foo for u8 {} //~ ERROR trait cannot be implemented outside `foo` diff --git a/tests/ui/restrictions/impl-restriction.stderr b/tests/ui/restrictions/impl-restriction.stderr index 21b2de3106b81..b94b393a97fa2 100644 --- a/tests/ui/restrictions/impl-restriction.stderr +++ b/tests/ui/restrictions/impl-restriction.stderr @@ -1,5 +1,5 @@ -error: implementation of restricted trait - --> $DIR/impl-restriction.rs:13:1 +error: trait cannot be implemented outside `foo` + --> $DIR/impl-restriction.rs:21:1 | LL | pub(crate) impl(super) trait Foo {} | ----------- trait restricted here diff --git a/tests/ui/restrictions/mut-restriction-construction.rs b/tests/ui/restrictions/mut-restriction-construction.rs index 75e64d7ea74f7..361af0ed87743 100644 --- a/tests/ui/restrictions/mut-restriction-construction.rs +++ b/tests/ui/restrictions/mut-restriction-construction.rs @@ -11,6 +11,6 @@ pub mod foo { } fn main() { - let foo = foo::Foo { alpha: 0 }; //~ ERROR - let bar = foo::Bar::Beta(0); //~ ERROR + let foo = foo::Foo { alpha: 0 }; //~ ERROR cannot be constructed + let bar = foo::Bar::Beta(0); //~ ERROR cannot be constructed } diff --git a/tests/ui/restrictions/mut-restriction-construction.stderr b/tests/ui/restrictions/mut-restriction-construction.stderr index a65ca146f96fe..f09f6b6976ae6 100644 --- a/tests/ui/restrictions/mut-restriction-construction.stderr +++ b/tests/ui/restrictions/mut-restriction-construction.stderr @@ -1,4 +1,4 @@ -error: construction of struct with mut restricted field +error: `Foo` cannot be constructed using a struct expression outside `foo` --> $DIR/mut-restriction-construction.rs:14:15 | LL | pub mut(self) alpha: u8, @@ -7,9 +7,9 @@ LL | pub mut(self) alpha: u8, LL | let foo = foo::Foo { alpha: 0 }; | ^^^^^^^^^^^^^^^^^^^^^ | - = note: struct expressions cannot be used when the struct has a field with a mutability restriction + = note: a struct containing fields with a mutability restriction cannot be constructed using a struct expression -error: construction of variant with mut restricted field +error: `Beta` cannot be constructed using a variant expression outside `foo` --> $DIR/mut-restriction-construction.rs:15:15 | LL | Beta(mut(self) u8), @@ -18,7 +18,7 @@ LL | Beta(mut(self) u8), LL | let bar = foo::Bar::Beta(0); | ^^^^^^^^^^^^^^^^^ | - = note: variant expressions cannot be used when the variant has a field with a mutability restriction + = note: a variant containing fields with a mutability restriction cannot be constructed using a variant expression error: aborting due to 2 previous errors diff --git a/tests/ui/restrictions/mut-restriction.rs b/tests/ui/restrictions/mut-restriction.rs index c894380d46b2c..8a5f0fd884a35 100644 --- a/tests/ui/restrictions/mut-restriction.rs +++ b/tests/ui/restrictions/mut-restriction.rs @@ -1,5 +1,9 @@ +// aux-build: external-mut-restriction.rs + #![feature(mut_restriction)] +extern crate external_mut_restriction; + pub mod foo { #[derive(Default)] pub struct Foo { @@ -18,16 +22,16 @@ pub mod foo { } fn mut_direct(foo: &mut foo::Foo, bar: &mut foo::Bar) { - foo.alpha = 1; //~ ERROR mutable use of restricted field + foo.alpha = 1; //~ ERROR field cannot be mutated outside `foo` match bar { - foo::Bar::Beta(ref mut beta) => {} //~ ERROR mutable use of restricted field + foo::Bar::Beta(ref mut beta) => {} //~ ERROR field cannot be mutated outside `foo` } } fn mut_ptr(foo: *mut foo::Foo) { // unsafe doesn't matter unsafe { - (*foo).alpha = 1; //~ ERROR mutable use of restricted field + (*foo).alpha = 1; //~ ERROR field cannot be mutated outside `foo` } } @@ -35,16 +39,16 @@ fn main() { let mut foo = foo::Foo::default(); let mut bar = foo::Bar::default(); - foo.alpha = 1; //~ ERROR mutable use of restricted field + foo.alpha = 1; //~ ERROR field cannot be mutated outside `foo` match bar { - foo::Bar::Beta(ref mut beta) => {} //~ ERROR mutable use of restricted field + foo::Bar::Beta(ref mut beta) => {} //~ ERROR field cannot be mutated outside `foo` } - std::ptr::addr_of_mut!(foo.alpha); //~ ERROR mutable use of restricted field + std::ptr::addr_of_mut!(foo.alpha); //~ ERROR field cannot be mutated outside `foo` - let _alpha = &mut foo.alpha; //~ ERROR mutable use of restricted field + let _alpha = &mut foo.alpha; //~ ERROR field cannot be mutated outside `foo` let mut closure = || { - foo.alpha = 1; //~ ERROR mutable use of restricted field + foo.alpha = 1; //~ ERROR field cannot be mutated outside `foo` }; // okay: the mutation occurs inside the function @@ -52,6 +56,14 @@ fn main() { mut_direct(&mut foo, &mut bar); mut_ptr(&mut foo as *mut _); - // okay: this is the same as turning &T into &mut T, which is unsound + // undefined behavior, but not a compile error (it is the same as turning &T into &mut T) unsafe { *(&foo.alpha as *const _ as *mut _) = 1; } + + let mut external_top_level = external_mut_restriction::TopLevel::new(); + external_top_level.alpha = 1; //~ ERROR field cannot be mutated outside + //FIXME~^ ERROR field cannot be mutated outside `external_mut_restriction` + + let mut external_inner = external_mut_restriction::inner::Inner::new(); + external_inner.beta = 1; //~ ERROR field cannot be mutated outside + //FIXME~^ ERROR field cannot be mutated outside `external_mut_restriction` } diff --git a/tests/ui/restrictions/mut-restriction.stderr b/tests/ui/restrictions/mut-restriction.stderr index a4fca52cc0e7b..c1d55a58fbf1f 100644 --- a/tests/ui/restrictions/mut-restriction.stderr +++ b/tests/ui/restrictions/mut-restriction.stderr @@ -1,5 +1,5 @@ -error: mutable use of restricted field - --> $DIR/mut-restriction.rs:21:5 +error: field cannot be mutated outside `foo` + --> $DIR/mut-restriction.rs:25:5 | LL | pub mut(self) alpha: u8, | --------- mutability restricted here @@ -7,8 +7,8 @@ LL | pub mut(self) alpha: u8, LL | foo.alpha = 1; | ^^^^^^^^^^^^^ -error: mutable use of restricted field - --> $DIR/mut-restriction.rs:23:24 +error: field cannot be mutated outside `foo` + --> $DIR/mut-restriction.rs:27:24 | LL | Beta(mut(self) u8), | --------- mutability restricted here @@ -16,8 +16,8 @@ LL | Beta(mut(self) u8), LL | foo::Bar::Beta(ref mut beta) => {} | ^^^^^^^^^^^^ -error: mutable use of restricted field - --> $DIR/mut-restriction.rs:30:9 +error: field cannot be mutated outside `foo` + --> $DIR/mut-restriction.rs:34:9 | LL | pub mut(self) alpha: u8, | --------- mutability restricted here @@ -25,8 +25,8 @@ LL | pub mut(self) alpha: u8, LL | (*foo).alpha = 1; | ^^^^^^^^^^^^^^^^ -error: mutable use of restricted field - --> $DIR/mut-restriction.rs:38:5 +error: field cannot be mutated outside `foo` + --> $DIR/mut-restriction.rs:42:5 | LL | pub mut(self) alpha: u8, | --------- mutability restricted here @@ -34,8 +34,8 @@ LL | pub mut(self) alpha: u8, LL | foo.alpha = 1; | ^^^^^^^^^^^^^ -error: mutable use of restricted field - --> $DIR/mut-restriction.rs:40:24 +error: field cannot be mutated outside `foo` + --> $DIR/mut-restriction.rs:44:24 | LL | Beta(mut(self) u8), | --------- mutability restricted here @@ -43,8 +43,8 @@ LL | Beta(mut(self) u8), LL | foo::Bar::Beta(ref mut beta) => {} | ^^^^^^^^^^^^ -error: mutable use of restricted field - --> $DIR/mut-restriction.rs:42:5 +error: field cannot be mutated outside `foo` + --> $DIR/mut-restriction.rs:46:5 | LL | pub mut(self) alpha: u8, | --------- mutability restricted here @@ -54,8 +54,8 @@ LL | std::ptr::addr_of_mut!(foo.alpha); | = note: this error originates in the macro `std::ptr::addr_of_mut` (in Nightly builds, run with -Z macro-backtrace for more info) -error: mutable use of restricted field - --> $DIR/mut-restriction.rs:44:18 +error: field cannot be mutated outside `foo` + --> $DIR/mut-restriction.rs:48:18 | LL | pub mut(self) alpha: u8, | --------- mutability restricted here @@ -63,8 +63,30 @@ LL | pub mut(self) alpha: u8, LL | let _alpha = &mut foo.alpha; | ^^^^^^^^^^^^^^ -error: mutable use of restricted field - --> $DIR/mut-restriction.rs:47:9 +error: field cannot be mutated outside `mut_restriction` + --> $DIR/mut-restriction.rs:63:5 + | +LL | external_top_level.alpha = 1; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + ::: $DIR/auxiliary/external-mut-restriction.rs:4:9 + | +LL | pub mut(self) alpha: u8, + | --------- mutability restricted here + +error: field cannot be mutated outside `mut_restriction` + --> $DIR/mut-restriction.rs:67:5 + | +LL | external_inner.beta = 1; + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + ::: $DIR/auxiliary/external-mut-restriction.rs:15:13 + | +LL | pub mut(self) beta: u8, + | --------- mutability restricted here + +error: field cannot be mutated outside `foo` + --> $DIR/mut-restriction.rs:51:9 | LL | pub mut(self) alpha: u8, | --------- mutability restricted here @@ -72,5 +94,5 @@ LL | pub mut(self) alpha: u8, LL | foo.alpha = 1; | ^^^^^^^^^^^^^ -error: aborting due to 8 previous errors +error: aborting due to 10 previous errors From bd9c2dbc1298d05bb980236ababd528ae70d4ed9 Mon Sep 17 00:00:00 2001 From: Jacob Pratt Date: Thu, 20 Oct 2022 21:08:06 -0400 Subject: [PATCH 27/45] Remove kw-only restriction, use shorthand properly This also moves the field-level mut restriction to a single location. It attempts to resolve the missing errors for when a restricted trait is implemented outside the defining crate, but the compiler does not currently store information for other crates. --- compiler/rustc_ast/src/ast.rs | 13 ++-- compiler/rustc_ast/src/mut_visit.rs | 2 +- compiler/rustc_ast/src/visit.rs | 2 +- .../rustc_ast_pretty/src/pprust/state/item.rs | 5 +- compiler/rustc_expand/src/placeholders.rs | 2 +- compiler/rustc_middle/src/query/mod.rs | 4 +- compiler/rustc_middle/src/ty/mod.rs | 4 +- compiler/rustc_parse/src/parser/mod.rs | 62 +++++++++---------- .../rustc_resolve/src/build_reduced_graph.rs | 27 ++------ compiler/rustc_resolve/src/lib.rs | 3 +- .../src/impl_restriction.rs | 61 +++++++----------- .../rustc_restrictions/src/mut_restriction.rs | 7 ++- src/tools/rustfmt/src/utils.rs | 10 +-- tests/ui/restrictions/impl-feature-gate.rs | 1 - .../impl-feature-gate.without_gate.stderr | 12 +--- tests/ui/restrictions/mut-restriction.stderr | 4 +- .../ui/restrictions/naked-impl-restriction.rs | 4 ++ .../naked-impl-restriction.stderr | 8 +++ .../ui/restrictions/naked-mut-restriction.rs | 6 ++ .../restrictions/naked-mut-restriction.stderr | 10 +++ 20 files changed, 118 insertions(+), 129 deletions(-) create mode 100644 tests/ui/restrictions/naked-impl-restriction.rs create mode 100644 tests/ui/restrictions/naked-impl-restriction.stderr create mode 100644 tests/ui/restrictions/naked-mut-restriction.rs create mode 100644 tests/ui/restrictions/naked-mut-restriction.stderr diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index f0e46b4b1a48c..c9d29adf3cbde 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -2729,18 +2729,15 @@ pub struct Restriction { #[derive(Clone, Encodable, Decodable, Debug)] pub enum RestrictionKind { - Unrestricted, - Restricted { path: P, id: NodeId }, + // kw(path) + Restricted { path: P, id: NodeId, shorthand: bool }, + // nothing Implied, } impl Restriction { - pub fn unrestricted() -> Self { - Restriction { kind: RestrictionKind::Unrestricted, span: DUMMY_SP } - } - - pub fn restricted(path: P, id: NodeId) -> Self { - Restriction { kind: RestrictionKind::Restricted { path, id }, span: DUMMY_SP } + pub fn restricted(path: P, id: NodeId, shorthand: bool) -> Self { + Restriction { kind: RestrictionKind::Restricted { path, id, shorthand }, span: DUMMY_SP } } pub fn implied() -> Self { diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 76dc149e51741..eac9e3bae8b96 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -1568,7 +1568,7 @@ pub fn noop_visit_vis(visibility: &mut Visibility, vis: &mut T) { } pub fn noop_visit_restriction(restriction: &mut Restriction, vis: &mut T) { - if let RestrictionKind::Restricted { path, id } = &mut restriction.kind { + if let RestrictionKind::Restricted { path, id, shorthand: _ } = &mut restriction.kind { vis.visit_path(path); vis.visit_id(id); } diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index d1cc8b42864c3..a17039858be91 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -962,7 +962,7 @@ pub fn walk_vis<'a, V: Visitor<'a>>(visitor: &mut V, vis: &'a Visibility) { } pub fn walk_restriction<'a, V: Visitor<'a>>(visitor: &mut V, restriction: &'a Restriction) { - if let RestrictionKind::Restricted { ref path, id } = restriction.kind { + if let RestrictionKind::Restricted { ref path, id, shorthand: _ } = restriction.kind { visitor.visit_path(path, id); } } diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs index 0ee9ca04ab99d..a04d6ab18e8e0 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/item.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs @@ -434,10 +434,9 @@ impl<'a> State<'a> { // longer incomplete pub(crate) fn print_restriction(&mut self, kw: &'static str, restriction: &ast::Restriction) { match restriction.kind { - ast::RestrictionKind::Unrestricted => self.word_nbsp(kw), - ast::RestrictionKind::Restricted { ref path, .. } => { + ast::RestrictionKind::Restricted { ref path, id: _, shorthand } => { let path = Self::to_string(|s| s.print_path(path, false, 0)); - if path == "crate" || path == "self" || path == "super" { + if shorthand { self.word_nbsp(format!("{kw}({path})")) } else { self.word_nbsp(format!("{kw}(in {path})")) diff --git a/compiler/rustc_expand/src/placeholders.rs b/compiler/rustc_expand/src/placeholders.rs index 83d78535b5d0b..948cf9fb4c243 100644 --- a/compiler/rustc_expand/src/placeholders.rs +++ b/compiler/rustc_expand/src/placeholders.rs @@ -169,7 +169,7 @@ pub fn placeholder( span, ty: ty(), vis, - mut_restriction: ast::Restriction::unrestricted(), + mut_restriction: ast::Restriction::implied(), is_placeholder: true, }]), AstFragmentKind::Variants => AstFragment::Variants(smallvec![ast::Variant { diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index b095781049bda..5ea47488daa04 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1695,8 +1695,8 @@ rustc_queries! { feedable } - query impl_restriction(def_id: LocalDefId) -> ty::Restriction { - desc { |tcx| "computing impl restriction for `{}`", tcx.def_path_str(def_id.to_def_id()) } + query impl_restriction(def_id: DefId) -> ty::Restriction { + desc { |tcx| "computing impl restriction for `{}`", tcx.def_path_str(def_id) } } query check_impl_restriction(_: ()) { diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index eb384236c1546..98a2762477fd9 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -162,7 +162,7 @@ pub struct ResolverOutputs { #[derive(Debug)] pub struct ResolverGlobalCtxt { pub visibilities: FxHashMap, - pub impl_restrictions: FxHashMap, + pub impl_restrictions: FxHashMap, pub mut_restrictions: FxHashMap, /// This field is used to decide whether we should make `PRIVATE_IN_PUBLIC` a hard error. pub has_pub_restricted: bool, @@ -334,7 +334,7 @@ impl + Copy> Restriction { if krate == def_id.krate { tcx.def_path_str(def_id) } else { - tcx.crate_name(krate).to_ident_string() + tcx.crate_name(def_id.krate).to_ident_string() } } diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 016e63ea2c6da..3ff3d7868adc5 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -1459,7 +1459,7 @@ impl<'a> Parser<'a> { Ok(()) } - /// Parses `kw` and `kw(in path)` plus shortcuts `kw(crate)` for `kw(in crate)`, `kw(self)` for + /// Parses `kw(in path)` plus shortcuts `kw(crate)` for `kw(in crate)`, `kw(self)` for /// `kw(in self)` and `kw(super)` for `kw(in super)`. fn parse_restriction( &mut self, @@ -1484,37 +1484,33 @@ impl<'a> Parser<'a> { let lo = self.prev_token.span; - if self.check(&token::OpenDelim(Delimiter::Parenthesis)) { - // We don't `self.bump()` the `(` yet because this might be a struct definition where - // `()` or a tuple might be allowed. For example, `struct Struct(kw (), kw (usize));`. - // Because of this, we only `bump` the `(` if we're assured it is appropriate to do so - // by the following tokens. - if self.is_keyword_ahead(1, &[kw::In]) { - // Parse `kw(in path)`. - self.bump(); // `(` - self.bump(); // `in` - let path = self.parse_path(PathStyle::Mod)?; // `path` - self.expect(&token::CloseDelim(Delimiter::Parenthesis))?; // `)` - return Ok(Restriction::restricted(P(path), ast::DUMMY_NODE_ID) - .with_span(lo.to(gate(lo.to(self.prev_token.span))))); - } else if self.look_ahead(2, |t| t == &token::CloseDelim(Delimiter::Parenthesis)) - && self.is_keyword_ahead(1, &[kw::Crate, kw::Super, kw::SelfLower]) - { - // Parse `kw(crate)`, `kw(self)`, or `kw(super)`. - self.bump(); // `(` - let path = self.parse_path(PathStyle::Mod)?; // `crate`/`super`/`self` - self.expect(&token::CloseDelim(Delimiter::Parenthesis))?; // `)` - return Ok(Restriction::restricted(P(path), ast::DUMMY_NODE_ID) - .with_span(gate(lo.to(self.prev_token.span)))); - } else if let FollowedByType::No = fbt { - // Provide this diagnostic if a type cannot follow; - // in particular, if this is not a tuple struct. - self.recover_incorrect_restriction(kw.as_str(), action)?; - // Emit diagnostic, but continue unrestricted. - } + self.expect(&token::OpenDelim(Delimiter::Parenthesis))?; + + if self.check_keyword(kw::In) { + // Parse `kw(in path)`. + self.bump(); // `in` + let path = self.parse_path(PathStyle::Mod)?; // `path` + self.expect(&token::CloseDelim(Delimiter::Parenthesis))?; // `)` + return Ok(Restriction::restricted(P(path), ast::DUMMY_NODE_ID, false) + .with_span(lo.to(gate(lo.to(self.prev_token.span))))); + } else if self.look_ahead(1, |t| t == &token::CloseDelim(Delimiter::Parenthesis)) + && self.is_keyword_ahead(0, &[kw::Crate, kw::Super, kw::SelfLower]) + { + // Parse `kw(crate)`, `kw(self)`, or `kw(super)`. + let path = self.parse_path(PathStyle::Mod)?; // `crate`/`super`/`self` + self.expect(&token::CloseDelim(Delimiter::Parenthesis))?; // `)` + return Ok(Restriction::restricted(P(path), ast::DUMMY_NODE_ID, true) + .with_span(gate(lo.to(self.prev_token.span)))); + } else if let FollowedByType::No = fbt { + // Provide this diagnostic if a type cannot follow; + // in particular, if this is not a tuple struct. + self.recover_incorrect_restriction(kw.as_str(), action)?; + // Emit diagnostic, but continue unrestricted. + Ok(Restriction::implied()) + } else { + // FIXME(jhpratt) Is this case ever actually encountered? + Ok(Restriction::implied()) } - - Ok(Restriction::unrestricted().with_span(gate(lo))) } /// Recovery for e.g. `kw(something) fn ...` or `struct X { kw(something) y: Z }` @@ -1526,9 +1522,9 @@ impl<'a> Parser<'a> { let msg = "incorrect restriction"; let suggestion = format!( r##"some possible restrictions are:\n\ - `{kw}(crate)`: {action} only on the current crate\n\ + `{kw}(crate)`: {action} only in the current crate\n\ `{kw}(super)`: {action} only in the current module's parent\n\ - `{kw}(in path::to::module)`: {action} only on the specified path"## + `{kw}(in path::to::module)`: {action} only in the specified path"## ); let path_str = pprust::path_to_string(&path); diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 28d2a02223996..2cde452e06e78 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -340,10 +340,8 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { let parent_scope = &self.parent_scope; match restriction.kind { // If the restriction is implied, it has no effect when the item is otherwise visible. - ast::RestrictionKind::Unrestricted | ast::RestrictionKind::Implied => { - Ok(ty::Restriction::Unrestricted) - } - ast::RestrictionKind::Restricted { ref path, id } => { + ast::RestrictionKind::Implied => Ok(ty::Restriction::Unrestricted), + ast::RestrictionKind::Restricted { ref path, id, shorthand: _ } => { // For restrictions we are not ready to provide correct implementation of "uniform // paths" right now, so on 2018 edition we only allow module-relative paths for now. // On 2015 edition visibilities are resolved as crate-relative by default, @@ -793,7 +791,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { self.r.define(parent, ident, TypeNS, (res, vis, sp, expansion)); } - ItemKind::Enum(ref enum_def, _) => { + ItemKind::Enum(..) => { let module = self.r.new_module( Some(parent), ModuleKind::Def(DefKind::Enum, def_id, ident.name), @@ -803,14 +801,6 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { ); self.r.define(parent, ident, TypeNS, (module, vis, sp, expansion)); self.parent_scope.module = module; - - for variant in &enum_def.variants { - for field in variant.data.fields() { - let local_did = self.r.local_def_id(field.id); - let mut_restriction = self.resolve_restriction(&field.mut_restriction); - self.r.mut_restrictions.insert(local_did, mut_restriction); - } - } } ItemKind::TraitAlias(..) => { @@ -828,13 +818,6 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { self.insert_field_def_ids(local_def_id, vdata); self.insert_field_visibilities_local(def_id, vdata); - for field in vdata.fields() { - if let Some(local_did) = self.r.opt_local_def_id(field.id) { - let mut_restriction = self.resolve_restriction(&field.mut_restriction); - self.r.mut_restrictions.insert(local_did, mut_restriction); - } - } - // If this is a tuple or unit struct, define a name // in the value namespace as well. if let Some((ctor_kind, ctor_node_id)) = CtorKind::from_ast(vdata) { @@ -889,7 +872,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { ItemKind::Trait(ref trait_def) => { let impl_restriction = self.resolve_restriction(&trait_def.impl_restriction); - self.r.impl_restrictions.insert(local_def_id, impl_restriction); + self.r.impl_restrictions.insert(def_id, impl_restriction); // Add all the items within to a new module. let module = self.r.new_module( @@ -1563,6 +1546,8 @@ impl<'a, 'b, 'tcx> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b, 'tcx> { } else { let vis = self.resolve_visibility(&sf.vis); self.r.visibilities.insert(self.r.local_def_id(sf.id), vis); + let mut_restriction = self.resolve_restriction(&sf.mut_restriction); + self.r.mut_restrictions.insert(self.r.local_def_id(sf.id), mut_restriction); visit::walk_field_def(self, sf); } } diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 38747b4f0dab9..8bedca45438c8 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -980,7 +980,8 @@ pub struct Resolver<'a, 'tcx> { /// Visibilities in "lowered" form, for all entities that have them. visibilities: FxHashMap, has_pub_restricted: bool, - impl_restrictions: FxHashMap, + // trait def -> restriction scope + impl_restrictions: FxHashMap, mut_restrictions: FxHashMap, used_imports: FxHashSet, maybe_unused_trait_imports: FxIndexSet, diff --git a/compiler/rustc_restrictions/src/impl_restriction.rs b/compiler/rustc_restrictions/src/impl_restriction.rs index 3667db64360d2..a22f23f6ca19e 100644 --- a/compiler/rustc_restrictions/src/impl_restriction.rs +++ b/compiler/rustc_restrictions/src/impl_restriction.rs @@ -1,8 +1,6 @@ -use hir::intravisit::Visitor; -use rustc_hir::def_id::LocalDefId; -use rustc_hir::{self as hir, Node}; +use rustc_hir::def_id::DefId; +use rustc_hir::{self as hir, intravisit::Visitor}; use rustc_middle::query::Providers; -use rustc_middle::span_bug; use rustc_middle::ty::{self, TyCtxt}; use crate::errors; @@ -23,48 +21,37 @@ impl<'v> Visitor<'v> for ImplOfRestrictedTraitVisitor<'v> { } fn visit_item(&mut self, item: &'v hir::Item<'v>) { - if let hir::ItemKind::Trait(..) = item.kind { - let restriction = self.tcx.impl_restriction(item.owner_id.def_id); - - self.tcx.for_each_impl(item.owner_id.to_def_id(), |impl_| { - if restriction.is_restricted_in(impl_, self.tcx) { - self.tcx.sess.emit_err(errors::ImplOfRestrictedTrait { - impl_span: self.tcx.span_of_impl(impl_).expect("impl should be local"), - restriction_span: restriction.expect_span(), - restriction_path: restriction - .expect_restriction_path(self.tcx, hir::def_id::LOCAL_CRATE), - }); - } - }); - }; + if let hir::ItemKind::Impl(hir::Impl { of_trait: Some(trait_ref), .. }) = &item.kind { + let trait_def_id = trait_ref.trait_def_id().expect("item is known to be a trait"); + + let crate_name = self.tcx.crate_name(hir::def_id::LOCAL_CRATE); + tracing::info!(?crate_name); + + let restriction = self.tcx.impl_restriction(trait_def_id); + + if restriction.is_restricted_in(item.owner_id.to_def_id(), self.tcx) { + let impl_span = + self.tcx.span_of_impl(item.owner_id.to_def_id()).expect("impl should be local"); + let restriction_span = restriction.expect_span(); + let restriction_path = + restriction.expect_restriction_path(self.tcx, hir::def_id::LOCAL_CRATE); + let diag = + errors::ImplOfRestrictedTrait { impl_span, restriction_span, restriction_path }; + self.tcx.sess.emit_err(diag); + } + } hir::intravisit::walk_item(self, item) } } -pub(crate) fn impl_restriction(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Restriction { +fn impl_restriction(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Restriction { match tcx.resolutions(()).impl_restrictions.get(&def_id) { Some(restriction) => *restriction, - None => { - let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); - match tcx.hir().get(hir_id) { - Node::Item(hir::Item { kind: hir::ItemKind::Trait(..), .. }) => { - span_bug!( - tcx.def_span(def_id), - "impl restriction table unexpectedly missing a def-id: {def_id:?}", - ) - } - _ => { - span_bug!( - tcx.def_span(def_id), - "called `impl_restriction` on non-trait: {def_id:?}", - ) - } - } - } + None => ty::Restriction::Unrestricted, // FIXME(jhpratt) error here } } -pub(crate) fn check_impl_restriction(tcx: TyCtxt<'_>, _: ()) { +fn check_impl_restriction(tcx: TyCtxt<'_>, _: ()) { tcx.hir().walk_toplevel_module(&mut ImplOfRestrictedTraitVisitor { tcx }); } diff --git a/compiler/rustc_restrictions/src/mut_restriction.rs b/compiler/rustc_restrictions/src/mut_restriction.rs index cdddd48383b03..e1c798c217bb7 100644 --- a/compiler/rustc_restrictions/src/mut_restriction.rs +++ b/compiler/rustc_restrictions/src/mut_restriction.rs @@ -23,7 +23,7 @@ pub(crate) fn provide(providers: &mut Providers) { fn mut_restriction(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Restriction { tracing::debug!("mut_restriction({def_id:?})"); - match (&tcx.resolutions(()).mut_restrictions).get(&def_id) { + match tcx.resolutions(()).mut_restrictions.get(&def_id) { Some(restriction) => *restriction, None => { let hir_id = tcx.local_def_id_to_hir_id(def_id); @@ -86,8 +86,9 @@ impl<'tcx> Visitor<'tcx> for MutRestrictionChecker<'_, 'tcx> { self.super_statement(statement, location); } - fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, _location: Location) { + fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, location: Location) { if !context.is_mutating_use() { + self.super_place(place, context, location); return; } @@ -115,6 +116,8 @@ impl<'tcx> Visitor<'tcx> for MutRestrictionChecker<'_, 'tcx> { _ => {} } } + + self.super_place(place, context, location) } fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) { diff --git a/src/tools/rustfmt/src/utils.rs b/src/tools/rustfmt/src/utils.rs index ca08552f0650f..7b2033fefc0d3 100644 --- a/src/tools/rustfmt/src/utils.rs +++ b/src/tools/rustfmt/src/utils.rs @@ -81,18 +81,20 @@ pub(crate) fn format_restriction( restriction: &Restriction, ) -> String { match restriction.kind { - RestrictionKind::Unrestricted => format!("{kw} "), - RestrictionKind::Restricted { ref path, .. } => { + RestrictionKind::Restricted { + ref path, + id: _, + shorthand, + } => { let Path { ref segments, .. } = **path; let mut segments_iter = segments.iter().map(|seg| rewrite_ident(context, seg.ident)); if path.is_global() && segments_iter.next().is_none() { panic!("non-global path in {kw}(restricted)?"); } - let is_keyword = |s| s == "crate" || s == "self" || s == "super"; // FIXME use `segments_iter.intersperse("::").collect::()` once // `#![feature(iter_intersperse)]` is re-stabilized. let path = itertools::join(segments_iter, "::"); - let in_str = if is_keyword(&path) { "" } else { "in " }; + let in_str = if shorthand { "" } else { "in " }; format!("{kw}({in_str}{path}) ") } diff --git a/tests/ui/restrictions/impl-feature-gate.rs b/tests/ui/restrictions/impl-feature-gate.rs index 0531796ca09a0..d31ecff60e23e 100644 --- a/tests/ui/restrictions/impl-feature-gate.rs +++ b/tests/ui/restrictions/impl-feature-gate.rs @@ -5,7 +5,6 @@ #![cfg_attr(with_gate, feature(impl_restriction))] -pub impl trait Foo {} //[without_gate]~ ERROR pub impl(crate) trait Bar {} //[without_gate]~ ERROR mod foo { diff --git a/tests/ui/restrictions/impl-feature-gate.without_gate.stderr b/tests/ui/restrictions/impl-feature-gate.without_gate.stderr index e26da7a5dc997..cb0385e009837 100644 --- a/tests/ui/restrictions/impl-feature-gate.without_gate.stderr +++ b/tests/ui/restrictions/impl-feature-gate.without_gate.stderr @@ -1,27 +1,19 @@ error[E0658]: restrictions are experimental --> $DIR/impl-feature-gate.rs:8:5 | -LL | pub impl trait Foo {} - | ^^^^ - | - = help: add `#![feature(impl_restriction)]` to the crate attributes to enable - -error[E0658]: restrictions are experimental - --> $DIR/impl-feature-gate.rs:9:5 - | LL | pub impl(crate) trait Bar {} | ^^^^^^^^^^^ | = help: add `#![feature(impl_restriction)]` to the crate attributes to enable error[E0658]: restrictions are experimental - --> $DIR/impl-feature-gate.rs:12:9 + --> $DIR/impl-feature-gate.rs:11:9 | LL | pub impl(in foo) trait Baz {} | ^^^^^^^^^^^^ | = help: add `#![feature(impl_restriction)]` to the crate attributes to enable -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/restrictions/mut-restriction.stderr b/tests/ui/restrictions/mut-restriction.stderr index c1d55a58fbf1f..c5386b675f005 100644 --- a/tests/ui/restrictions/mut-restriction.stderr +++ b/tests/ui/restrictions/mut-restriction.stderr @@ -63,7 +63,7 @@ LL | pub mut(self) alpha: u8, LL | let _alpha = &mut foo.alpha; | ^^^^^^^^^^^^^^ -error: field cannot be mutated outside `mut_restriction` +error: field cannot be mutated outside `external_mut_restriction` --> $DIR/mut-restriction.rs:63:5 | LL | external_top_level.alpha = 1; @@ -74,7 +74,7 @@ LL | external_top_level.alpha = 1; LL | pub mut(self) alpha: u8, | --------- mutability restricted here -error: field cannot be mutated outside `mut_restriction` +error: field cannot be mutated outside `external_mut_restriction` --> $DIR/mut-restriction.rs:67:5 | LL | external_inner.beta = 1; diff --git a/tests/ui/restrictions/naked-impl-restriction.rs b/tests/ui/restrictions/naked-impl-restriction.rs new file mode 100644 index 0000000000000..295dbd721107b --- /dev/null +++ b/tests/ui/restrictions/naked-impl-restriction.rs @@ -0,0 +1,4 @@ +// compile-flags: --crate-type=lib +#![feature(impl_restriction)] + +pub impl trait Foo {} //~ ERROR expected `(` diff --git a/tests/ui/restrictions/naked-impl-restriction.stderr b/tests/ui/restrictions/naked-impl-restriction.stderr new file mode 100644 index 0000000000000..363266b6636a8 --- /dev/null +++ b/tests/ui/restrictions/naked-impl-restriction.stderr @@ -0,0 +1,8 @@ +error: expected `(`, found keyword `trait` + --> $DIR/naked-impl-restriction.rs:4:10 + | +LL | pub impl trait Foo {} + | ^^^^^ expected `(` + +error: aborting due to previous error + diff --git a/tests/ui/restrictions/naked-mut-restriction.rs b/tests/ui/restrictions/naked-mut-restriction.rs new file mode 100644 index 0000000000000..e3deb0ec0fffe --- /dev/null +++ b/tests/ui/restrictions/naked-mut-restriction.rs @@ -0,0 +1,6 @@ +// compile-flags: --crate-type=lib +#![feature(mut_restriction)] + +pub struct Foo { + pub mut x: u32, //~ ERROR expected `(` +} diff --git a/tests/ui/restrictions/naked-mut-restriction.stderr b/tests/ui/restrictions/naked-mut-restriction.stderr new file mode 100644 index 0000000000000..ebd00c7e08b88 --- /dev/null +++ b/tests/ui/restrictions/naked-mut-restriction.stderr @@ -0,0 +1,10 @@ +error: expected `(`, found `x` + --> $DIR/naked-mut-restriction.rs:5:13 + | +LL | pub struct Foo { + | --- while parsing this struct +LL | pub mut x: u32, + | ^ expected `(` + +error: aborting due to previous error + From ae5d13cdba8bf38bbeca2da3ab3a5b3009cb6c62 Mon Sep 17 00:00:00 2001 From: Urgau Date: Thu, 25 May 2023 17:44:58 +0200 Subject: [PATCH 28/45] Fix tidy errors --- compiler/rustc_feature/src/active.rs | 4 ++-- compiler/rustc_resolve/src/build_reduced_graph.rs | 2 +- tests/ui/restrictions/impl-feature-gate.without_gate.stderr | 2 ++ tests/ui/restrictions/mut-feature-gate.without_gate.stderr | 1 + 4 files changed, 6 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index 9d326d21299b2..c2dfea5b05ecd 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -427,7 +427,7 @@ declare_features! ( /// Allows `if let` guard in match arms. (active, if_let_guard, "1.47.0", Some(51114), None), /// Allows restricting the implementation of traits. - (active, impl_restriction, "CURRENT_RUSTC_VERSION", None, None), + (active, impl_restriction, "CURRENT_RUSTC_VERSION", Some(105077), None), /// Allows `impl Trait` to be used inside associated types (RFC 2515). (active, impl_trait_in_assoc_type, "1.70.0", Some(63063), None), /// Allows `impl Trait` as output type in `Fn` traits in return position of functions. @@ -465,7 +465,7 @@ declare_features! ( /// Allows the `#[must_not_suspend]` attribute. (active, must_not_suspend, "1.57.0", Some(83310), None), /// Allows restricting the mutation of fields. - (active, mut_restriction, "CURRENT_RUSTC_VERSION", None, None), + (active, mut_restriction, "CURRENT_RUSTC_VERSION", Some(105077), None), /// Allows using `#[naked]` on functions. (active, naked_functions, "1.9.0", Some(32408), None), /// Allows specifying the as-needed link modifier diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 2cde452e06e78..ccc57e15af3a8 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -845,7 +845,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { } ret_fields.push(field_vis.to_def_id()); - // TODO(jhpratt) add resolutions for enum variant fields + // FIXME(jhpratt) add resolutions for enum variant fields } let ctor_def_id = self.r.local_def_id(ctor_node_id); let ctor_res = diff --git a/tests/ui/restrictions/impl-feature-gate.without_gate.stderr b/tests/ui/restrictions/impl-feature-gate.without_gate.stderr index cb0385e009837..f4924d8c71ba5 100644 --- a/tests/ui/restrictions/impl-feature-gate.without_gate.stderr +++ b/tests/ui/restrictions/impl-feature-gate.without_gate.stderr @@ -4,6 +4,7 @@ error[E0658]: restrictions are experimental LL | pub impl(crate) trait Bar {} | ^^^^^^^^^^^ | + = note: see issue #105077 for more information = help: add `#![feature(impl_restriction)]` to the crate attributes to enable error[E0658]: restrictions are experimental @@ -12,6 +13,7 @@ error[E0658]: restrictions are experimental LL | pub impl(in foo) trait Baz {} | ^^^^^^^^^^^^ | + = note: see issue #105077 for more information = help: add `#![feature(impl_restriction)]` to the crate attributes to enable error: aborting due to 2 previous errors diff --git a/tests/ui/restrictions/mut-feature-gate.without_gate.stderr b/tests/ui/restrictions/mut-feature-gate.without_gate.stderr index abfedbaf60301..b000ba90c843a 100644 --- a/tests/ui/restrictions/mut-feature-gate.without_gate.stderr +++ b/tests/ui/restrictions/mut-feature-gate.without_gate.stderr @@ -4,6 +4,7 @@ error[E0658]: restrictions are experimental LL | pub mut(self) alpha: u8, | ^^^^^^^^^ | + = note: see issue #105077 for more information = help: add `#![feature(mut_restriction)]` to the crate attributes to enable error: aborting due to previous error From cc4d414f3bb996297c0142a2ca86bd7aa95b7d51 Mon Sep 17 00:00:00 2001 From: Jacob Pratt Date: Thu, 5 Jan 2023 10:30:52 +0000 Subject: [PATCH 29/45] Make impl restrictions work cross-crate --- .../src/rmeta/decoder/cstore_impl.rs | 1 + compiler/rustc_metadata/src/rmeta/encoder.rs | 8 +++++++ compiler/rustc_metadata/src/rmeta/mod.rs | 1 + compiler/rustc_middle/src/query/mod.rs | 1 + .../src/impl_restriction.rs | 12 ++++------ tests/ui/restrictions/impl-restriction.rs | 4 ++-- tests/ui/restrictions/impl-restriction.stderr | 24 ++++++++++++++++++- tests/ui/restrictions/mut-restriction.rs | 8 +++---- 8 files changed, 45 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 848535fb39521..0471aaa5b4124 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -271,6 +271,7 @@ provide! { tcx, def_id, other, cdata, associated_types_for_impl_traits_in_associated_fn => { table_defaulted_array } visibility => { cdata.get_visibility(def_id.index) } + impl_restriction => { table } adt_def => { cdata.get_adt_def(def_id.index, tcx) } adt_destructor => { let _ = cdata; diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index b5f955d14fbc8..79a2055ef8f80 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -944,6 +944,10 @@ fn should_encode_visibility(def_kind: DefKind) -> bool { } } +fn should_encode_impl_restriction(def_kind: DefKind) -> bool { + matches!(def_kind, DefKind::Trait) +} + fn should_encode_stability(def_kind: DefKind) -> bool { match def_kind { DefKind::Mod @@ -1336,6 +1340,10 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { self.tcx.local_visibility(local_id).map_id(|def_id| def_id.local_def_index); record!(self.tables.visibility[def_id] <- vis); } + if should_encode_impl_restriction(def_kind) { + let impl_restriction = self.tcx.impl_restriction(def_id); + record!(self.tables.impl_restriction[def_id] <- impl_restriction); + } if should_encode_stability(def_kind) { self.encode_stability(def_id); self.encode_const_stability(def_id); diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index fd026fa5fa20c..1fe04469bc603 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -395,6 +395,7 @@ define_tables! { associated_item_or_field_def_ids: Table>, opt_def_kind: Table, visibility: Table>>, + impl_restriction: Table>, mut_restriction: Table>, def_span: Table>, def_ident_span: Table>, diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 5ea47488daa04..53f3c7bcde2cb 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1697,6 +1697,7 @@ rustc_queries! { query impl_restriction(def_id: DefId) -> ty::Restriction { desc { |tcx| "computing impl restriction for `{}`", tcx.def_path_str(def_id) } + separate_provide_extern } query check_impl_restriction(_: ()) { diff --git a/compiler/rustc_restrictions/src/impl_restriction.rs b/compiler/rustc_restrictions/src/impl_restriction.rs index a22f23f6ca19e..2a13790c5076f 100644 --- a/compiler/rustc_restrictions/src/impl_restriction.rs +++ b/compiler/rustc_restrictions/src/impl_restriction.rs @@ -1,5 +1,6 @@ -use rustc_hir::def_id::DefId; +use rustc_hir::def_id::LocalDefId; use rustc_hir::{self as hir, intravisit::Visitor}; +use rustc_middle::bug; use rustc_middle::query::Providers; use rustc_middle::ty::{self, TyCtxt}; @@ -24,9 +25,6 @@ impl<'v> Visitor<'v> for ImplOfRestrictedTraitVisitor<'v> { if let hir::ItemKind::Impl(hir::Impl { of_trait: Some(trait_ref), .. }) = &item.kind { let trait_def_id = trait_ref.trait_def_id().expect("item is known to be a trait"); - let crate_name = self.tcx.crate_name(hir::def_id::LOCAL_CRATE); - tracing::info!(?crate_name); - let restriction = self.tcx.impl_restriction(trait_def_id); if restriction.is_restricted_in(item.owner_id.to_def_id(), self.tcx) { @@ -45,10 +43,10 @@ impl<'v> Visitor<'v> for ImplOfRestrictedTraitVisitor<'v> { } } -fn impl_restriction(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Restriction { - match tcx.resolutions(()).impl_restrictions.get(&def_id) { +fn impl_restriction(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Restriction { + match tcx.resolutions(()).impl_restrictions.get(&def_id.to_def_id()) { Some(restriction) => *restriction, - None => ty::Restriction::Unrestricted, // FIXME(jhpratt) error here + None => bug!("impl restriction not found for {def_id:?}"), } } diff --git a/tests/ui/restrictions/impl-restriction.rs b/tests/ui/restrictions/impl-restriction.rs index 752a6f72a8f1d..73ac935bf0f6b 100644 --- a/tests/ui/restrictions/impl-restriction.rs +++ b/tests/ui/restrictions/impl-restriction.rs @@ -7,8 +7,8 @@ extern crate external_impl_restriction; struct LocalType; // needed to avoid orphan rule errors -impl external_impl_restriction::TopLevel for LocalType {} //FIXME~ ERROR trait cannot be implemented outside `external_impl_restriction` -impl external_impl_restriction::inner::Inner for LocalType {} //FIXME~ ERROR trait cannot be implemented outside `external_impl_restriction` +impl external_impl_restriction::TopLevel for LocalType {} //~ ERROR trait cannot be implemented outside `external_impl_restriction` +impl external_impl_restriction::inner::Inner for LocalType {} //~ ERROR trait cannot be implemented outside `external_impl_restriction` pub mod foo { pub mod bar { diff --git a/tests/ui/restrictions/impl-restriction.stderr b/tests/ui/restrictions/impl-restriction.stderr index b94b393a97fa2..daa6c66be7fc3 100644 --- a/tests/ui/restrictions/impl-restriction.stderr +++ b/tests/ui/restrictions/impl-restriction.stderr @@ -1,3 +1,25 @@ +error: trait cannot be implemented outside `external_impl_restriction` + --> $DIR/impl-restriction.rs:10:1 + | +LL | impl external_impl_restriction::TopLevel for LocalType {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + ::: $DIR/auxiliary/external-impl-restriction.rs:3:5 + | +LL | pub impl(crate) trait TopLevel {} + | ----------- trait restricted here + +error: trait cannot be implemented outside `external_impl_restriction` + --> $DIR/impl-restriction.rs:11:1 + | +LL | impl external_impl_restriction::inner::Inner for LocalType {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + ::: $DIR/auxiliary/external-impl-restriction.rs:6:9 + | +LL | pub impl(self) trait Inner {} + | ---------- trait restricted here + error: trait cannot be implemented outside `foo` --> $DIR/impl-restriction.rs:21:1 | @@ -7,5 +29,5 @@ LL | pub(crate) impl(super) trait Foo {} LL | impl foo::bar::Foo for u8 {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to previous error +error: aborting due to 3 previous errors diff --git a/tests/ui/restrictions/mut-restriction.rs b/tests/ui/restrictions/mut-restriction.rs index 8a5f0fd884a35..5d6b1057b5833 100644 --- a/tests/ui/restrictions/mut-restriction.rs +++ b/tests/ui/restrictions/mut-restriction.rs @@ -60,10 +60,10 @@ fn main() { unsafe { *(&foo.alpha as *const _ as *mut _) = 1; } let mut external_top_level = external_mut_restriction::TopLevel::new(); - external_top_level.alpha = 1; //~ ERROR field cannot be mutated outside - //FIXME~^ ERROR field cannot be mutated outside `external_mut_restriction` + external_top_level.alpha = 1; + //~^ ERROR field cannot be mutated outside `external_mut_restriction` let mut external_inner = external_mut_restriction::inner::Inner::new(); - external_inner.beta = 1; //~ ERROR field cannot be mutated outside - //FIXME~^ ERROR field cannot be mutated outside `external_mut_restriction` + external_inner.beta = 1; + //~^ ERROR field cannot be mutated outside `external_mut_restriction` } From 7e22f74c52e18a3e88a74cf22d48fdd86bbd923f Mon Sep 17 00:00:00 2001 From: Jacob Pratt Date: Sat, 7 Jan 2023 10:50:06 +0000 Subject: [PATCH 30/45] Store mut restriction data in a table --- compiler/rustc_hir_analysis/src/collect.rs | 1 - compiler/rustc_metadata/src/rmeta/decoder.rs | 9 ------ .../src/rmeta/decoder/cstore_impl.rs | 1 + compiler/rustc_metadata/src/rmeta/encoder.rs | 10 +++--- compiler/rustc_middle/src/query/mod.rs | 5 +-- compiler/rustc_middle/src/ty/mod.rs | 9 +++--- .../rustc_resolve/src/build_reduced_graph.rs | 2 +- compiler/rustc_resolve/src/lib.rs | 3 +- .../rustc_restrictions/src/mut_restriction.rs | 31 ++++++------------- 9 files changed, 26 insertions(+), 45 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index e6d395b3d22b2..c160cf2df6e5f 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -807,7 +807,6 @@ fn convert_variant( did: f.def_id.to_def_id(), name: f.ident.name, vis: tcx.visibility(f.def_id), - mut_restriction: tcx.mut_restriction(f.def_id), } }) .collect(); diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index a7c26ef8e7089..8fa1d365728a2 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -903,7 +903,6 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { did, name: self.item_name(did.index), vis: self.get_visibility(did.index), - mut_restriction: self.get_mut_restriction(index), }) .collect(), adt_kind, @@ -965,14 +964,6 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { .map_id(|index| self.local_def_id(index)) } - fn get_mut_restriction(self, id: DefIndex) -> ty::Restriction { - self.root - .tables - .mut_restriction - .get(self, id) - .map_or(ty::Restriction::Unrestricted, |restriction| restriction.decode(self)) - } - fn get_trait_item_def_id(self, id: DefIndex) -> Option { self.root.tables.trait_item_def_id.get(self, id).map(|d| d.decode_from_cdata(self)) } diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 0471aaa5b4124..678a09d69ea92 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -272,6 +272,7 @@ provide! { tcx, def_id, other, cdata, visibility => { cdata.get_visibility(def_id.index) } impl_restriction => { table } + mut_restriction => { table } adt_def => { cdata.get_adt_def(def_id.index, tcx) } adt_destructor => { let _ = cdata; diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 79a2055ef8f80..4bc85fe61a8bc 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -944,10 +944,6 @@ fn should_encode_visibility(def_kind: DefKind) -> bool { } } -fn should_encode_impl_restriction(def_kind: DefKind) -> bool { - matches!(def_kind, DefKind::Trait) -} - fn should_encode_stability(def_kind: DefKind) -> bool { match def_kind { DefKind::Mod @@ -1340,10 +1336,14 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { self.tcx.local_visibility(local_id).map_id(|def_id| def_id.local_def_index); record!(self.tables.visibility[def_id] <- vis); } - if should_encode_impl_restriction(def_kind) { + if let DefKind::Trait = def_kind { let impl_restriction = self.tcx.impl_restriction(def_id); record!(self.tables.impl_restriction[def_id] <- impl_restriction); } + if let DefKind::Field = def_kind { + let mut_restriction = self.tcx.mut_restriction(def_id); + record!(self.tables.mut_restriction[def_id] <- mut_restriction); + } if should_encode_stability(def_kind) { self.encode_stability(def_id); self.encode_const_stability(def_id); diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 53f3c7bcde2cb..d51c9ae05375b 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1713,8 +1713,9 @@ rustc_queries! { desc { "computing the uninhabited predicate of `{}`", key } } - query mut_restriction(def_id: LocalDefId) -> ty::Restriction { - desc { |tcx| "computing mut restriction for `{}`", tcx.def_path_str(def_id.to_def_id()) } + query mut_restriction(def_id: DefId) -> ty::Restriction { + desc { |tcx| "computing mut restriction for `{}`", tcx.def_path_str(def_id) } + separate_provide_extern } query check_mut_restriction(def_id: LocalDefId) { diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 98a2762477fd9..0b23162dbeee7 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -163,7 +163,7 @@ pub struct ResolverOutputs { pub struct ResolverGlobalCtxt { pub visibilities: FxHashMap, pub impl_restrictions: FxHashMap, - pub mut_restrictions: FxHashMap, + pub mut_restrictions: FxHashMap, /// This field is used to decide whether we should make `PRIVATE_IN_PUBLIC` a hard error. pub has_pub_restricted: bool, /// Item with a given `LocalDefId` was defined during macro expansion with ID `ExpnId`. @@ -2199,7 +2199,6 @@ pub struct FieldDef { pub did: DefId, pub name: Symbol, pub vis: Visibility, - pub mut_restriction: Restriction, } impl PartialEq for FieldDef { @@ -2212,9 +2211,9 @@ impl PartialEq for FieldDef { // of `FieldDef` changes, a compile-error will be produced, reminding // us to revisit this assumption. - let Self { did: lhs_did, name: _, vis: _, mut_restriction: _ } = &self; + let Self { did: lhs_did, name: _, vis: _ } = &self; - let Self { did: rhs_did, name: _, vis: _, mut_restriction: _ } = other; + let Self { did: rhs_did, name: _, vis: _ } = other; let res = lhs_did == rhs_did; @@ -2240,7 +2239,7 @@ impl Hash for FieldDef { // of `FieldDef` changes, a compile-error will be produced, reminding // us to revisit this assumption. - let Self { did, name: _, vis: _, mut_restriction: _ } = &self; + let Self { did, name: _, vis: _ } = &self; did.hash(s) } diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index ccc57e15af3a8..c96ec9021e6ed 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -1547,7 +1547,7 @@ impl<'a, 'b, 'tcx> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b, 'tcx> { let vis = self.resolve_visibility(&sf.vis); self.r.visibilities.insert(self.r.local_def_id(sf.id), vis); let mut_restriction = self.resolve_restriction(&sf.mut_restriction); - self.r.mut_restrictions.insert(self.r.local_def_id(sf.id), mut_restriction); + self.r.mut_restrictions.insert(self.r.local_def_id(sf.id).to_def_id(), mut_restriction); visit::walk_field_def(self, sf); } } diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 8bedca45438c8..bdc9c17d8f403 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -982,7 +982,8 @@ pub struct Resolver<'a, 'tcx> { has_pub_restricted: bool, // trait def -> restriction scope impl_restrictions: FxHashMap, - mut_restrictions: FxHashMap, + // field def -> restriction scope + mut_restrictions: FxHashMap, used_imports: FxHashSet, maybe_unused_trait_imports: FxIndexSet, diff --git a/compiler/rustc_restrictions/src/mut_restriction.rs b/compiler/rustc_restrictions/src/mut_restriction.rs index e1c798c217bb7..a0764aabefd3a 100644 --- a/compiler/rustc_restrictions/src/mut_restriction.rs +++ b/compiler/rustc_restrictions/src/mut_restriction.rs @@ -23,23 +23,9 @@ pub(crate) fn provide(providers: &mut Providers) { fn mut_restriction(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Restriction { tracing::debug!("mut_restriction({def_id:?})"); - match tcx.resolutions(()).mut_restrictions.get(&def_id) { + match tcx.resolutions(()).mut_restrictions.get(&def_id.to_def_id()) { Some(restriction) => *restriction, - None => { - let hir_id = tcx.local_def_id_to_hir_id(def_id); - match tcx.hir().get(hir_id) { - Node::Field(..) => { - tracing::debug!("mut restriction not found; assuming unrestricted"); - Restriction::Unrestricted - } - _ => { - span_bug!( - tcx.def_span(def_id), - "called `mut_restriction` on invalid item: {def_id:?}", - ) - } - } - } + None => span_bug!(tcx.def_span(def_id), "mut restriction not found for {def_id:?}"), } } @@ -66,7 +52,10 @@ fn adt_expression_restriction(tcx: TyCtxt<'_>, variant_def_id: DefId) -> Restric let res = Res::Def(tcx.def_kind(variant_def_id), variant_def_id); let variant = tcx.expect_variant_res(res); - Restriction::strictest_of(variant.fields.iter().map(|field| field.mut_restriction), tcx) + Restriction::strictest_of( + variant.fields.iter().map(|field| tcx.mut_restriction(field.did)), + tcx, + ) } struct MutRestrictionChecker<'a, 'tcx> { @@ -102,13 +91,13 @@ impl<'tcx> Visitor<'tcx> for MutRestrictionChecker<'_, 'tcx> { continue; } let field_def = field_ty.field_def(field); + let field_mut_restriction = self.tcx.mut_restriction(field_def.did); - if field_def.mut_restriction.is_restricted_in(body_did, self.tcx) { + if field_mut_restriction.is_restricted_in(body_did, self.tcx) { self.tcx.sess.emit_err(errors::MutOfRestrictedField { mut_span: self.span, - restriction_span: field_def.mut_restriction.expect_span(), - restriction_path: field_def - .mut_restriction + restriction_span: field_mut_restriction.expect_span(), + restriction_path: field_mut_restriction .expect_restriction_path(self.tcx, body_did.krate), }); } From ae7a6a28c39f096e28bb5abd9e17ff6e3083f6b9 Mon Sep 17 00:00:00 2001 From: Jacob Pratt Date: Sun, 8 Jan 2023 07:21:37 +0000 Subject: [PATCH 31/45] Remove outdated syntax --- src/tools/rustfmt/tests/source/restriction.rs | 26 ------------------- src/tools/rustfmt/tests/target/restriction.rs | 11 -------- 2 files changed, 37 deletions(-) diff --git a/src/tools/rustfmt/tests/source/restriction.rs b/src/tools/rustfmt/tests/source/restriction.rs index 6df58576479d6..58d266a425291 100644 --- a/src/tools/rustfmt/tests/source/restriction.rs +++ b/src/tools/rustfmt/tests/source/restriction.rs @@ -2,10 +2,6 @@ pub impl(crate) trait Foo {} -pub -impl -trait Bar {} - pub impl ( in foo :: @@ -18,12 +14,6 @@ struct FooS { field: (), } -struct BarS { - pub - mut - field: (), -} - struct BazS { pub mut ( in foo @@ -38,12 +28,6 @@ struct FooS2( (), ); -struct BarS2( - pub - mut - (), -); - struct BazS2( pub mut ( in foo @@ -57,10 +41,6 @@ enum Enum { mut(crate) field: (), }, - Bar { - mut - field: (), - }, Baz { mut ( in foo :: @@ -71,10 +51,6 @@ enum Enum { mut(crate) (), ), - BarT( - mut - (), - ), BazT( mut ( in foo :: @@ -87,8 +63,6 @@ enum Enum { union Union { mut(crate) field1: (), - mut - field2: (), mut ( in foo :: bar ) diff --git a/src/tools/rustfmt/tests/target/restriction.rs b/src/tools/rustfmt/tests/target/restriction.rs index a25ea9c161f06..a64a9b5bbef6e 100644 --- a/src/tools/rustfmt/tests/target/restriction.rs +++ b/src/tools/rustfmt/tests/target/restriction.rs @@ -1,38 +1,27 @@ pub impl(crate) trait Foo {} -pub impl trait Bar {} - pub impl(in foo::bar) trait Baz {} struct FooS { pub mut(crate) field: (), } -struct BarS { - pub mut field: (), -} - struct BazS { pub mut(in foo::bar) field: (), } struct FooS2(pub mut(crate) ()); -struct BarS2(pub mut ()); - struct BazS2(pub mut(in foo::bar) ()); enum Enum { Foo { mut(crate) field: () }, - Bar { mut field: () }, Baz { mut(in foo::bar) field: () }, FooT(mut(crate) ()), - BarT(mut ()), BazT(mut(in foo::bar) ()), } union Union { mut(crate) field1: (), - mut field2: (), mut(in foo::bar) field3: (), } From 716ecbddc5192d70db5ffab128f96d055cc7c8bc Mon Sep 17 00:00:00 2001 From: Jacob Pratt Date: Mon, 9 Jan 2023 01:41:45 +0000 Subject: [PATCH 32/45] Explicitly test tuple structs --- .../auxiliary/external-mut-restriction.rs | 30 ++- tests/ui/restrictions/mut-restriction.rs | 101 +++++--- tests/ui/restrictions/mut-restriction.stderr | 224 +++++++++++++----- 3 files changed, 256 insertions(+), 99 deletions(-) diff --git a/tests/ui/restrictions/auxiliary/external-mut-restriction.rs b/tests/ui/restrictions/auxiliary/external-mut-restriction.rs index c4c485f22a046..43406810352ac 100644 --- a/tests/ui/restrictions/auxiliary/external-mut-restriction.rs +++ b/tests/ui/restrictions/auxiliary/external-mut-restriction.rs @@ -1,23 +1,29 @@ #![feature(mut_restriction)] -pub struct TopLevel { - pub mut(self) alpha: u8, +#[derive(Default)] +pub struct TopLevelStruct { + pub mut(self) field: u8, } -impl TopLevel { - pub fn new() -> Self { - Self { alpha: 0 } - } +#[derive(Default)] +pub enum TopLevelEnum { + #[default] + Default, + A(mut(self) u8), + B { mut(self) field: u8 }, } pub mod inner { - pub struct Inner { - pub mut(self) beta: u8, + #[derive(Default)] + pub struct InnerStruct { + pub mut(self) field: u8, } - impl Inner { - pub fn new() -> Self { - Self { beta: 0 } - } + #[derive(Default)] + pub enum InnerEnum { + #[default] + Default, + A(mut(self) u8), + B { mut(self) field: u8 }, } } diff --git a/tests/ui/restrictions/mut-restriction.rs b/tests/ui/restrictions/mut-restriction.rs index 5d6b1057b5833..ce2a00952b164 100644 --- a/tests/ui/restrictions/mut-restriction.rs +++ b/tests/ui/restrictions/mut-restriction.rs @@ -2,68 +2,101 @@ #![feature(mut_restriction)] -extern crate external_mut_restriction; +extern crate external_mut_restriction as external; -pub mod foo { +pub mod local { #[derive(Default)] - pub struct Foo { - pub mut(self) alpha: u8, - } + pub struct TupleStruct(pub mut(self) u8); - pub enum Bar { - Beta(mut(self) u8), + #[derive(Default)] + pub struct FieldStruct { + pub mut(self) field: u8, } - impl Default for Bar { - fn default() -> Self { - Bar::Beta(0) - } + #[derive(Default)] + pub enum Enum { + #[default] + Default, + Tuple(mut(self) u8), + Field { mut(self) field: u8 }, } } -fn mut_direct(foo: &mut foo::Foo, bar: &mut foo::Bar) { - foo.alpha = 1; //~ ERROR field cannot be mutated outside `foo` - match bar { - foo::Bar::Beta(ref mut beta) => {} //~ ERROR field cannot be mutated outside `foo` +fn mut_ref( + local_tuple_struct: &mut local::TupleStruct, + local_field_struct: &mut local::FieldStruct, + local_enum: &mut local::Enum +) { + local_tuple_struct.0 = 1; //~ ERROR field cannot be mutated outside `local` + local_field_struct.field = 1; //~ ERROR field cannot be mutated outside `local` + match local_enum { + local::Enum::Default => {} + local::Enum::Tuple(ref mut a) => {} //~ ERROR field cannot be mutated outside `local` + local::Enum::Field { ref mut field } => {} //~ ERROR field cannot be mutated outside `local` } } -fn mut_ptr(foo: *mut foo::Foo) { +fn mut_ptr(a: *mut local::TupleStruct, b: *mut local::FieldStruct) { // unsafe doesn't matter unsafe { - (*foo).alpha = 1; //~ ERROR field cannot be mutated outside `foo` + (*a).0 = 1; //~ ERROR field cannot be mutated outside `local` + (*b).field = 1; //~ ERROR field cannot be mutated outside `local` } } fn main() { - let mut foo = foo::Foo::default(); - let mut bar = foo::Bar::default(); + let mut local_tuple_struct = local::TupleStruct::default(); + let mut local_field_struct = local::FieldStruct::default(); + let mut local_enum = local::Enum::default(); - foo.alpha = 1; //~ ERROR field cannot be mutated outside `foo` - match bar { - foo::Bar::Beta(ref mut beta) => {} //~ ERROR field cannot be mutated outside `foo` + local_tuple_struct.0 = 1; //~ ERROR field cannot be mutated outside `local` + local_field_struct.field = 1; //~ ERROR field cannot be mutated outside `local` + match local_enum { + local::Enum::Default => {} + local::Enum::Tuple(ref mut a) => {} //~ ERROR field cannot be mutated outside `local` + local::Enum::Field { ref mut field } => {} //~ ERROR field cannot be mutated outside `local` } - std::ptr::addr_of_mut!(foo.alpha); //~ ERROR field cannot be mutated outside `foo` + std::ptr::addr_of_mut!(local_tuple_struct.0); //~ ERROR field cannot be mutated outside `local` + std::ptr::addr_of_mut!(local_field_struct.field); //~ ERROR field cannot be mutated outside `local` - let _alpha = &mut foo.alpha; //~ ERROR field cannot be mutated outside `foo` + &mut local_tuple_struct.0; //~ ERROR field cannot be mutated outside `local` + &mut local_field_struct.field; //~ ERROR field cannot be mutated outside `local` let mut closure = || { - foo.alpha = 1; //~ ERROR field cannot be mutated outside `foo` + local_tuple_struct.0 = 1; //~ ERROR field cannot be mutated outside `local` + local_field_struct.field = 1; //~ ERROR field cannot be mutated outside `local` }; // okay: the mutation occurs inside the function closure(); - mut_direct(&mut foo, &mut bar); - mut_ptr(&mut foo as *mut _); + mut_ref(&mut local_tuple_struct, &mut local_field_struct, &mut local_enum); + mut_ptr(&mut local_tuple_struct as *mut _, &mut local_field_struct as *mut _); // undefined behavior, but not a compile error (it is the same as turning &T into &mut T) - unsafe { *(&foo.alpha as *const _ as *mut _) = 1; } + unsafe { *(&local_tuple_struct.0 as *const _ as *mut _) = 1; } + unsafe { *(&local_field_struct.field as *const _ as *mut _) = 1; } + + // Check that external items have mut restrictions enforced. We are also checking that the + // name of the internal module is not present in the error message, as it is not relevant to the + // user. - let mut external_top_level = external_mut_restriction::TopLevel::new(); - external_top_level.alpha = 1; - //~^ ERROR field cannot be mutated outside `external_mut_restriction` + let mut external_top_level_struct = external::TopLevelStruct::default(); + external_top_level_struct.field = 1; //~ ERROR field cannot be mutated outside `external_mut_restriction` - let mut external_inner = external_mut_restriction::inner::Inner::new(); - external_inner.beta = 1; - //~^ ERROR field cannot be mutated outside `external_mut_restriction` + let mut external_top_level_enum = external::TopLevelEnum::default(); + match external_top_level_enum { + external::TopLevelEnum::Default => {} + external::TopLevelEnum::A(ref mut a) => {} //~ ERROR field cannot be mutated outside `external_mut_restriction` + external::TopLevelEnum::B { ref mut field } => {} //~ ERROR field cannot be mutated outside `external_mut_restriction` + } + + let mut external_inner_struct = external::inner::InnerStruct::default(); + external_inner_struct.field = 1; //~ ERROR field cannot be mutated outside `external_mut_restriction` + + let mut external_inner_enum = external::inner::InnerEnum::default(); + match external_inner_enum { + external::inner::InnerEnum::Default => {} + external::inner::InnerEnum::A(ref mut a) => {} //~ ERROR field cannot be mutated outside `external_mut_restriction` + external::inner::InnerEnum::B { ref mut field } => {} //~ ERROR field cannot be mutated outside `external_mut_restriction` + } } diff --git a/tests/ui/restrictions/mut-restriction.stderr b/tests/ui/restrictions/mut-restriction.stderr index c5386b675f005..95f8c01182f5a 100644 --- a/tests/ui/restrictions/mut-restriction.stderr +++ b/tests/ui/restrictions/mut-restriction.stderr @@ -1,98 +1,216 @@ -error: field cannot be mutated outside `foo` - --> $DIR/mut-restriction.rs:25:5 +error: field cannot be mutated outside `local` + --> $DIR/mut-restriction.rs:30:5 | -LL | pub mut(self) alpha: u8, +LL | pub struct TupleStruct(pub mut(self) u8); + | --------- mutability restricted here +... +LL | local_tuple_struct.0 = 1; + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error: field cannot be mutated outside `local` + --> $DIR/mut-restriction.rs:31:5 + | +LL | pub mut(self) field: u8, | --------- mutability restricted here ... -LL | foo.alpha = 1; - | ^^^^^^^^^^^^^ +LL | local_field_struct.field = 1; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: field cannot be mutated outside `local` + --> $DIR/mut-restriction.rs:35:30 + | +LL | Field { mut(self) field: u8 }, + | --------- mutability restricted here +... +LL | local::Enum::Field { ref mut field } => {} + | ^^^^^^^^^^^^^ -error: field cannot be mutated outside `foo` - --> $DIR/mut-restriction.rs:27:24 +error: field cannot be mutated outside `local` + --> $DIR/mut-restriction.rs:34:28 | -LL | Beta(mut(self) u8), - | --------- mutability restricted here +LL | Tuple(mut(self) u8), + | --------- mutability restricted here ... -LL | foo::Bar::Beta(ref mut beta) => {} - | ^^^^^^^^^^^^ +LL | local::Enum::Tuple(ref mut a) => {} + | ^^^^^^^^^ -error: field cannot be mutated outside `foo` - --> $DIR/mut-restriction.rs:34:9 +error: field cannot be mutated outside `local` + --> $DIR/mut-restriction.rs:42:9 | -LL | pub mut(self) alpha: u8, +LL | pub struct TupleStruct(pub mut(self) u8); + | --------- mutability restricted here +... +LL | (*a).0 = 1; + | ^^^^^^^^^^ + +error: field cannot be mutated outside `local` + --> $DIR/mut-restriction.rs:43:9 + | +LL | pub mut(self) field: u8, | --------- mutability restricted here ... -LL | (*foo).alpha = 1; - | ^^^^^^^^^^^^^^^^ +LL | (*b).field = 1; + | ^^^^^^^^^^^^^^ -error: field cannot be mutated outside `foo` - --> $DIR/mut-restriction.rs:42:5 +error: field cannot be mutated outside `local` + --> $DIR/mut-restriction.rs:52:5 | -LL | pub mut(self) alpha: u8, +LL | pub struct TupleStruct(pub mut(self) u8); + | --------- mutability restricted here +... +LL | local_tuple_struct.0 = 1; + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error: field cannot be mutated outside `local` + --> $DIR/mut-restriction.rs:53:5 + | +LL | pub mut(self) field: u8, | --------- mutability restricted here ... -LL | foo.alpha = 1; - | ^^^^^^^^^^^^^ +LL | local_field_struct.field = 1; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: field cannot be mutated outside `foo` - --> $DIR/mut-restriction.rs:44:24 +error: field cannot be mutated outside `local` + --> $DIR/mut-restriction.rs:57:30 | -LL | Beta(mut(self) u8), - | --------- mutability restricted here +LL | Field { mut(self) field: u8 }, + | --------- mutability restricted here ... -LL | foo::Bar::Beta(ref mut beta) => {} - | ^^^^^^^^^^^^ +LL | local::Enum::Field { ref mut field } => {} + | ^^^^^^^^^^^^^ -error: field cannot be mutated outside `foo` - --> $DIR/mut-restriction.rs:46:5 +error: field cannot be mutated outside `local` + --> $DIR/mut-restriction.rs:56:28 | -LL | pub mut(self) alpha: u8, +LL | Tuple(mut(self) u8), + | --------- mutability restricted here +... +LL | local::Enum::Tuple(ref mut a) => {} + | ^^^^^^^^^ + +error: field cannot be mutated outside `local` + --> $DIR/mut-restriction.rs:59:5 + | +LL | pub struct TupleStruct(pub mut(self) u8); + | --------- mutability restricted here +... +LL | std::ptr::addr_of_mut!(local_tuple_struct.0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this error originates in the macro `std::ptr::addr_of_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: field cannot be mutated outside `local` + --> $DIR/mut-restriction.rs:60:5 + | +LL | pub mut(self) field: u8, | --------- mutability restricted here ... -LL | std::ptr::addr_of_mut!(foo.alpha); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | std::ptr::addr_of_mut!(local_field_struct.field); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: this error originates in the macro `std::ptr::addr_of_mut` (in Nightly builds, run with -Z macro-backtrace for more info) -error: field cannot be mutated outside `foo` - --> $DIR/mut-restriction.rs:48:18 +error: field cannot be mutated outside `local` + --> $DIR/mut-restriction.rs:62:5 + | +LL | pub struct TupleStruct(pub mut(self) u8); + | --------- mutability restricted here +... +LL | &mut local_tuple_struct.0; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: field cannot be mutated outside `local` + --> $DIR/mut-restriction.rs:63:5 | -LL | pub mut(self) alpha: u8, +LL | pub mut(self) field: u8, | --------- mutability restricted here ... -LL | let _alpha = &mut foo.alpha; - | ^^^^^^^^^^^^^^ +LL | &mut local_field_struct.field; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: field cannot be mutated outside `external_mut_restriction` - --> $DIR/mut-restriction.rs:63:5 + --> $DIR/mut-restriction.rs:84:5 | -LL | external_top_level.alpha = 1; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | external_top_level_struct.field = 1; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + ::: $DIR/auxiliary/external-mut-restriction.rs:5:9 + | +LL | pub mut(self) field: u8, + | --------- mutability restricted here + +error: field cannot be mutated outside `external_mut_restriction` + --> $DIR/mut-restriction.rs:90:37 + | +LL | external::TopLevelEnum::B { ref mut field } => {} + | ^^^^^^^^^^^^^ | - ::: $DIR/auxiliary/external-mut-restriction.rs:4:9 + ::: $DIR/auxiliary/external-mut-restriction.rs:13:9 | -LL | pub mut(self) alpha: u8, +LL | B { mut(self) field: u8 }, | --------- mutability restricted here error: field cannot be mutated outside `external_mut_restriction` - --> $DIR/mut-restriction.rs:67:5 + --> $DIR/mut-restriction.rs:89:35 + | +LL | external::TopLevelEnum::A(ref mut a) => {} + | ^^^^^^^^^ + | + ::: $DIR/auxiliary/external-mut-restriction.rs:12:7 + | +LL | A(mut(self) u8), + | --------- mutability restricted here + +error: field cannot be mutated outside `external_mut_restriction` + --> $DIR/mut-restriction.rs:94:5 + | +LL | external_inner_struct.field = 1; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + ::: $DIR/auxiliary/external-mut-restriction.rs:19:13 + | +LL | pub mut(self) field: u8, + | --------- mutability restricted here + +error: field cannot be mutated outside `external_mut_restriction` + --> $DIR/mut-restriction.rs:100:41 | -LL | external_inner.beta = 1; - | ^^^^^^^^^^^^^^^^^^^^^^^ +LL | external::inner::InnerEnum::B { ref mut field } => {} + | ^^^^^^^^^^^^^ | - ::: $DIR/auxiliary/external-mut-restriction.rs:15:13 + ::: $DIR/auxiliary/external-mut-restriction.rs:27:13 | -LL | pub mut(self) beta: u8, +LL | B { mut(self) field: u8 }, | --------- mutability restricted here -error: field cannot be mutated outside `foo` - --> $DIR/mut-restriction.rs:51:9 +error: field cannot be mutated outside `external_mut_restriction` + --> $DIR/mut-restriction.rs:99:39 + | +LL | external::inner::InnerEnum::A(ref mut a) => {} + | ^^^^^^^^^ + | + ::: $DIR/auxiliary/external-mut-restriction.rs:26:11 + | +LL | A(mut(self) u8), + | --------- mutability restricted here + +error: field cannot be mutated outside `local` + --> $DIR/mut-restriction.rs:66:9 + | +LL | pub struct TupleStruct(pub mut(self) u8); + | --------- mutability restricted here +... +LL | local_tuple_struct.0 = 1; + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error: field cannot be mutated outside `local` + --> $DIR/mut-restriction.rs:67:9 | -LL | pub mut(self) alpha: u8, +LL | pub mut(self) field: u8, | --------- mutability restricted here ... -LL | foo.alpha = 1; - | ^^^^^^^^^^^^^ +LL | local_field_struct.field = 1; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 10 previous errors +error: aborting due to 22 previous errors From 011e7c6f7a572cf4edc851d55c6253f296b22fdb Mon Sep 17 00:00:00 2001 From: Jacob Pratt Date: Mon, 9 Jan 2023 01:51:23 +0000 Subject: [PATCH 33/45] Simplify naming in impl restriction test --- tests/ui/restrictions/impl-restriction.rs | 6 +++--- tests/ui/restrictions/impl-restriction.stderr | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/ui/restrictions/impl-restriction.rs b/tests/ui/restrictions/impl-restriction.rs index 73ac935bf0f6b..7f4fc496cbd6a 100644 --- a/tests/ui/restrictions/impl-restriction.rs +++ b/tests/ui/restrictions/impl-restriction.rs @@ -3,12 +3,12 @@ #![feature(impl_restriction)] -extern crate external_impl_restriction; +extern crate external_impl_restriction as external; struct LocalType; // needed to avoid orphan rule errors -impl external_impl_restriction::TopLevel for LocalType {} //~ ERROR trait cannot be implemented outside `external_impl_restriction` -impl external_impl_restriction::inner::Inner for LocalType {} //~ ERROR trait cannot be implemented outside `external_impl_restriction` +impl external::TopLevel for LocalType {} //~ ERROR trait cannot be implemented outside `external_impl_restriction` +impl external::inner::Inner for LocalType {} //~ ERROR trait cannot be implemented outside `external_impl_restriction` pub mod foo { pub mod bar { diff --git a/tests/ui/restrictions/impl-restriction.stderr b/tests/ui/restrictions/impl-restriction.stderr index daa6c66be7fc3..a09d4d23e55a1 100644 --- a/tests/ui/restrictions/impl-restriction.stderr +++ b/tests/ui/restrictions/impl-restriction.stderr @@ -1,8 +1,8 @@ error: trait cannot be implemented outside `external_impl_restriction` --> $DIR/impl-restriction.rs:10:1 | -LL | impl external_impl_restriction::TopLevel for LocalType {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | impl external::TopLevel for LocalType {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ::: $DIR/auxiliary/external-impl-restriction.rs:3:5 | @@ -12,8 +12,8 @@ LL | pub impl(crate) trait TopLevel {} error: trait cannot be implemented outside `external_impl_restriction` --> $DIR/impl-restriction.rs:11:1 | -LL | impl external_impl_restriction::inner::Inner for LocalType {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | impl external::inner::Inner for LocalType {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ::: $DIR/auxiliary/external-impl-restriction.rs:6:9 | From bafce512755208b6b8aef6fe0364795aa4bc7511 Mon Sep 17 00:00:00 2001 From: Jacob Pratt Date: Mon, 9 Jan 2023 01:56:23 +0000 Subject: [PATCH 34/45] Remove unnecessary FIXME --- compiler/rustc_resolve/src/build_reduced_graph.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index c96ec9021e6ed..f3fba84f1b09f 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -844,8 +844,6 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { ctor_vis = field_vis; } ret_fields.push(field_vis.to_def_id()); - - // FIXME(jhpratt) add resolutions for enum variant fields } let ctor_def_id = self.r.local_def_id(ctor_node_id); let ctor_res = From 23f53bf43f8f16dfea8effb29743016dec56a553 Mon Sep 17 00:00:00 2001 From: Jacob Pratt Date: Mon, 9 Jan 2023 09:15:31 +0000 Subject: [PATCH 35/45] Change restriction kind into const generic This allows for static verification that the wrong restriction is never provided. --- compiler/rustc_ast/src/ast.rs | 117 ++++++++++++++++-- compiler/rustc_ast/src/ast_traits.rs | 30 ++--- compiler/rustc_ast/src/mut_visit.rs | 12 +- compiler/rustc_ast/src/visit.rs | 12 +- compiler/rustc_ast_pretty/src/pprust/state.rs | 7 +- .../rustc_ast_pretty/src/pprust/state/item.rs | 19 +-- compiler/rustc_parse/messages.ftl | 14 +++ compiler/rustc_parse/src/errors.rs | 25 ++++ compiler/rustc_parse/src/parser/item.rs | 27 +--- compiler/rustc_parse/src/parser/mod.rs | 116 +++++++++-------- .../rustc_resolve/src/build_reduced_graph.rs | 18 ++- src/tools/rustfmt/src/items.rs | 4 +- src/tools/rustfmt/src/utils.rs | 19 +-- tests/ui/restrictions/in-path-rustfix.fixed | 10 ++ tests/ui/restrictions/in-path-rustfix.rs | 10 ++ tests/ui/restrictions/in-path-rustfix.stderr | 14 +++ .../ui/restrictions/naked-impl-restriction.rs | 2 +- .../naked-impl-restriction.stderr | 12 +- .../ui/restrictions/naked-mut-restriction.rs | 2 +- .../restrictions/naked-mut-restriction.stderr | 14 ++- 20 files changed, 342 insertions(+), 142 deletions(-) create mode 100644 tests/ui/restrictions/in-path-rustfix.fixed create mode 100644 tests/ui/restrictions/in-path-rustfix.rs create mode 100644 tests/ui/restrictions/in-path-rustfix.stderr diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index c9d29adf3cbde..5636410ecdda4 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -35,6 +35,7 @@ use rustc_span::source_map::{respan, Spanned}; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{Span, DUMMY_SP}; use std::fmt; +use std::marker::PhantomData; use std::mem; use thin_vec::{thin_vec, ThinVec}; @@ -2721,31 +2722,129 @@ impl VisibilityKind { } } +pub mod restriction_kind { + use super::*; + + /// Helper macro to generate the type, derive the relevant bounds, and implement the sealed + /// trait. + macro_rules! restriction { + ( + name: $name:ident, + allows_kw_only: $allows_kw_only:literal, + kw_sym: $kw_sym:path, + kw_str: $kw_str:literal, + action: $action:literal, + description: $description:literal, + feature_gate: $feature_gate:expr $(,)? + ) => { + #[derive(Debug, Clone, Copy, Encodable, Decodable)] + pub enum $name {} + + impl RestrictionKind for $name { + const ALLOWS_KW_ONLY: bool = $allows_kw_only; + const KW_SYM: Symbol = $kw_sym; + const KW_STR: &'static str = $kw_str; + const ACTION: &'static str = $action; + const DESCRIPTION: &'static str = $description; + const FEATURE_GATE: Option = $feature_gate; + } + + impl sealed::Sealed for $name {} + }; + } + + // FIXME(jhpratt) After a bootstrap, replace this with the now-implemented native syntax. + mod sealed { + pub trait Sealed {} + } + + pub trait RestrictionKind: sealed::Sealed { + const ALLOWS_KW_ONLY: bool; + const KW_SYM: Symbol; + const KW_STR: &'static str; + const ACTION: &'static str; + const DESCRIPTION: &'static str; + const FEATURE_GATE: Option; + } + + restriction! { + name: Visibility, + allows_kw_only: true, + kw_sym: kw::Pub, + kw_str: "pub", + action: "visible", + description: "visibility", + feature_gate: None, + } + restriction! { + name: Impl, + allows_kw_only: false, + kw_sym: kw::Impl, + kw_str: "impl", + action: "implementable", + description: "impl", + feature_gate: Some(sym::impl_restriction), + } + restriction! { + name: Mut, + allows_kw_only: false, + kw_sym: kw::Mut, + kw_str: "mut", + action: "mutable", + description: "mut", + feature_gate: Some(sym::mut_restriction), + } +} +pub use restriction_kind::RestrictionKind; + +// FIXME(jhpratt) Replace the generic with an enum once ADT const generics are not incomplete. #[derive(Clone, Encodable, Decodable, Debug)] -pub struct Restriction { - pub kind: RestrictionKind, +pub struct Restriction { + pub level: RestrictionLevel, pub span: Span, + pub kind: PhantomData, + pub tokens: Option, } #[derive(Clone, Encodable, Decodable, Debug)] -pub enum RestrictionKind { +pub enum RestrictionLevel { + // kw + Unrestricted, // kw(path) Restricted { path: P, id: NodeId, shorthand: bool }, // nothing Implied, } -impl Restriction { +impl Restriction { + pub fn unrestricted() -> Self { + Self { + level: RestrictionLevel::Unrestricted, + span: DUMMY_SP, + tokens: None, + kind: PhantomData, + } + } + pub fn restricted(path: P, id: NodeId, shorthand: bool) -> Self { - Restriction { kind: RestrictionKind::Restricted { path, id, shorthand }, span: DUMMY_SP } + Self { + level: RestrictionLevel::Restricted { path, id, shorthand }, + span: DUMMY_SP, + tokens: None, + kind: PhantomData, + } } pub fn implied() -> Self { - Restriction { kind: RestrictionKind::Implied, span: DUMMY_SP } + Self { level: RestrictionLevel::Implied, span: DUMMY_SP, tokens: None, kind: PhantomData } } pub fn with_span(self, span: Span) -> Self { - Restriction { span, ..self } + Self { span, ..self } + } + + pub fn with_tokens(self, tokens: LazyAttrTokenStream) -> Self { + Self { tokens: Some(tokens), ..self } } } @@ -2758,7 +2857,7 @@ pub struct FieldDef { pub id: NodeId, pub span: Span, pub vis: Visibility, - pub mut_restriction: Restriction, + pub mut_restriction: Restriction, pub ident: Option, pub ty: P, @@ -2898,7 +2997,7 @@ impl Default for FnHeader { #[derive(Clone, Encodable, Decodable, Debug)] pub struct Trait { - pub impl_restriction: Restriction, + pub impl_restriction: Restriction, pub unsafety: Unsafe, pub is_auto: IsAuto, pub generics: Generics, diff --git a/compiler/rustc_ast/src/ast_traits.rs b/compiler/rustc_ast/src/ast_traits.rs index 23a5d3a781f81..fc7cbf79ea08f 100644 --- a/compiler/rustc_ast/src/ast_traits.rs +++ b/compiler/rustc_ast/src/ast_traits.rs @@ -108,19 +108,13 @@ macro_rules! impl_has_span { }; } -impl_has_span!( - AssocItem, - Block, - Expr, - ForeignItem, - Item, - Pat, - Path, - Stmt, - Ty, - Visibility, - Restriction, -); +impl_has_span!(AssocItem, Block, Expr, ForeignItem, Item, Pat, Path, Stmt, Ty, Visibility); + +impl HasSpan for Restriction { + fn span(&self) -> Span { + self.span + } +} impl> HasSpan for T { fn span(&self) -> Span { @@ -336,7 +330,15 @@ impl_has_attrs!( PatField, Variant, ); -impl_has_attrs_none!(Attribute, AttrItem, Block, Pat, Path, Ty, Visibility, Restriction); +impl_has_attrs_none!(Attribute, AttrItem, Block, Pat, Path, Ty, Visibility); + +impl HasAttrs for Restriction { + const SUPPORTS_CUSTOM_INNER_ATTRS: bool = false; + fn attrs(&self) -> &[Attribute] { + &[] + } + fn visit_attrs(&mut self, _f: impl FnOnce(&mut AttrVec)) {} +} impl> HasAttrs for T { const SUPPORTS_CUSTOM_INNER_ATTRS: bool = T::Target::SUPPORTS_CUSTOM_INNER_ATTRS; diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index eac9e3bae8b96..e77cdb3aea7b0 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -278,7 +278,10 @@ pub trait MutVisitor: Sized { noop_visit_vis(vis, self); } - fn visit_restriction(&mut self, restriction: &mut Restriction) { + fn visit_restriction( + &mut self, + restriction: &mut Restriction, + ) { noop_visit_restriction(restriction, self); } @@ -1567,8 +1570,11 @@ pub fn noop_visit_vis(visibility: &mut Visibility, vis: &mut T) { vis.visit_span(&mut visibility.span); } -pub fn noop_visit_restriction(restriction: &mut Restriction, vis: &mut T) { - if let RestrictionKind::Restricted { path, id, shorthand: _ } = &mut restriction.kind { +pub fn noop_visit_restriction( + restriction: &mut Restriction, + vis: &mut T, +) { + if let RestrictionLevel::Restricted { path, id, shorthand: _ } = &mut restriction.level { vis.visit_path(path); vis.visit_id(id); } diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index a17039858be91..93e7896abfc7f 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -227,7 +227,10 @@ pub trait Visitor<'ast>: Sized { fn visit_vis(&mut self, vis: &'ast Visibility) { walk_vis(self, vis) } - fn visit_restriction(&mut self, restriction: &'ast Restriction) { + fn visit_restriction( + &mut self, + restriction: &'ast Restriction, + ) { walk_restriction(self, restriction) } fn visit_fn_ret_ty(&mut self, ret_ty: &'ast FnRetTy) { @@ -961,8 +964,11 @@ pub fn walk_vis<'a, V: Visitor<'a>>(visitor: &mut V, vis: &'a Visibility) { } } -pub fn walk_restriction<'a, V: Visitor<'a>>(visitor: &mut V, restriction: &'a Restriction) { - if let RestrictionKind::Restricted { ref path, id, shorthand: _ } = restriction.kind { +pub fn walk_restriction<'a, V: Visitor<'a>, Kind: crate::RestrictionKind>( + visitor: &mut V, + restriction: &'a Restriction, +) { + if let RestrictionLevel::Restricted { ref path, id, shorthand: _ } = restriction.level { visitor.visit_path(path, id); } } diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index e61ea3aa28f87..66d83a1d63274 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -883,8 +883,11 @@ pub trait PrintState<'a>: std::ops::Deref + std::ops::Dere Self::to_string(|s| s.print_visibility(v)) } - fn restriction_to_string(&self, kw: &'static str, restriction: &ast::Restriction) -> String { - Self::to_string(|s| s.print_restriction(kw, restriction)) + fn restriction_to_string( + &self, + restriction: &ast::Restriction, + ) -> String { + Self::to_string(|s| s.print_restriction(restriction)) } fn block_to_string(&self, blk: &ast::Block) -> String { diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs index a04d6ab18e8e0..16e6ce7bc9f93 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/item.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs @@ -324,7 +324,7 @@ impl<'a> State<'a> { }) => { self.head(""); self.print_visibility(&item.vis); - self.print_restriction("impl", impl_restriction); + self.print_restriction(impl_restriction); self.print_unsafety(*unsafety); self.print_is_auto(*is_auto); self.word_nbsp("trait"); @@ -430,11 +430,14 @@ impl<'a> State<'a> { } } - // FIXME(jhpratt) make `kw` into a const generic when #![feature(adt_consts_params)] is no - // longer incomplete - pub(crate) fn print_restriction(&mut self, kw: &'static str, restriction: &ast::Restriction) { - match restriction.kind { - ast::RestrictionKind::Restricted { ref path, id: _, shorthand } => { + pub(crate) fn print_restriction( + &mut self, + restriction: &ast::Restriction, + ) { + match restriction.level { + ast::RestrictionLevel::Unrestricted => self.word_nbsp(Kind::KW_STR), + ast::RestrictionLevel::Restricted { ref path, id: _, shorthand } => { + let kw = Kind::KW_STR; let path = Self::to_string(|s| s.print_path(path, false, 0)); if shorthand { self.word_nbsp(format!("{kw}({path})")) @@ -442,7 +445,7 @@ impl<'a> State<'a> { self.word_nbsp(format!("{kw}(in {path})")) } } - ast::RestrictionKind::Implied => {} + ast::RestrictionLevel::Implied => {} } } @@ -465,7 +468,7 @@ impl<'a> State<'a> { self.maybe_print_comment(field.span.lo()); self.print_outer_attributes(&field.attrs); self.print_visibility(&field.vis); - self.print_restriction("mut", &field.mut_restriction); + self.print_restriction(&field.mut_restriction); self.print_ident(field.ident.unwrap()); self.word_nbsp(":"); self.print_type(&field.ty); diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index 9787d98c1a49a..f92aaf3da120f 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -519,6 +519,20 @@ parse_missing_comma_after_match_arm = expected `,` following `match` arm parse_missing_const_type = missing type for `{$kind}` item .suggestion = provide a type for the item +parse_incorrect_restriction = incorrect {$kind} restriction + .help = some possible {$kind} restrictions are: + `{$kw}(crate)`: {$action} only in the current crate + `{$kw}(super)`: {$action} only in the current module's parent + `{$kw}(in path::to::module)`: {$action} only in the specified path + .suggestion = make this {$action} only to module `{$path}` with `in` + +parse_naked_restriction = incorrect {$kind} restriction + .help = some possible {$kind} restrictions are: + `{$kw}(crate)`: {$action} only in the current crate + `{$kw}(super)`: {$action} only in the current module's parent + `{$kw}(in path::to::module)`: {$action} only in the specified path + .suggestion = make this {$action} only in the current crate + parse_missing_expression_in_for_loop = missing expression to iterate on in `for` loop .suggestion = try adding an expression to the `for` loop diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 96e1c0e3c6d9e..a5d7db450e457 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -821,6 +821,31 @@ pub(crate) struct IncorrectVisibilityRestriction { pub inner_str: String, } +#[derive(Diagnostic)] +#[diag(parse_incorrect_restriction, code = "E0704")] +#[help] +pub(crate) struct IncorrectRestriction { + #[primary_span] + #[suggestion(code = "in {path}", applicability = "machine-applicable")] + pub span: Span, + pub path: String, + pub kind: &'static str, + pub action: &'static str, + pub kw: &'static str, +} + +#[derive(Diagnostic)] +#[diag(parse_naked_restriction, code = "E0704")] +#[help] +pub(crate) struct NakedRestriction { + #[primary_span] + #[suggestion(code = "{kw}(crate)", applicability = "machine-applicable")] + pub span: Span, + pub kind: &'static str, + pub action: &'static str, + pub kw: &'static str, +} + #[derive(Diagnostic)] #[diag(parse_assignment_else_not_allowed)] pub(crate) struct AssignmentElseNotAllowed { diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 2d7c303ecf704..2e5b0c029f910 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -831,12 +831,7 @@ impl<'a> Parser<'a> { /// Parses `impl(in path)? unsafe? auto? trait Foo { ... }` or `trait Foo = Bar;`. fn parse_item_trait(&mut self, attrs: &mut AttrVec, lo: Span) -> PResult<'a, ItemInfo> { - let impl_restriction = self.parse_restriction( - kw::Impl, - Some(sym::impl_restriction), - "implementable", - FollowedByType::No, - )?; + let impl_restriction = self.parse_restriction(FollowedByType::No)?; let unsafety = self.parse_unsafety(Case::Sensitive); // Parse optional `auto` prefix. let is_auto = if self.eat_keyword(kw::Auto) { IsAuto::Yes } else { IsAuto::No }; @@ -863,7 +858,7 @@ impl<'a> Parser<'a> { self.expect_semi()?; let whole_span = lo.to(self.prev_token.span); - if !matches!(impl_restriction.kind, RestrictionKind::Implied) { + if !matches!(impl_restriction.level, RestrictionLevel::Implied) { let msg = "trait aliases cannot be implemented"; self.struct_span_err(whole_span, msg).span_label(whole_span, msg).emit(); } @@ -1593,12 +1588,7 @@ impl<'a> Parser<'a> { return Err(err); } }; - let mut_restriction = match p.parse_restriction( - kw::Mut, - Some(sym::mut_restriction), - "mutate", - FollowedByType::Yes, - ) { + let mut_restriction = match p.parse_restriction(FollowedByType::Yes) { Ok(mut_restriction) => mut_restriction, Err(err) => { if let Some(ref mut snapshot) = snapshot { @@ -1643,12 +1633,7 @@ impl<'a> Parser<'a> { self.collect_tokens_trailing_token(attrs, ForceCollect::No, |this, attrs| { let lo = this.token.span; let vis = this.parse_visibility(FollowedByType::No)?; - let mut_restriction = this.parse_restriction( - kw::Mut, - Some(sym::mut_restriction), - "mutate", - FollowedByType::No, - )?; + let mut_restriction = this.parse_restriction(FollowedByType::No)?; Ok(( this.parse_single_struct_field(adt_ty, lo, vis, mut_restriction, attrs)?, TrailingToken::None, @@ -1662,7 +1647,7 @@ impl<'a> Parser<'a> { adt_ty: &str, lo: Span, vis: Visibility, - mut_restriction: Restriction, + mut_restriction: Restriction, attrs: AttrVec, ) -> PResult<'a, FieldDef> { let mut seen_comma: bool = false; @@ -1802,7 +1787,7 @@ impl<'a> Parser<'a> { adt_ty: &str, lo: Span, vis: Visibility, - mut_restriction: Restriction, + mut_restriction: Restriction, attrs: AttrVec, ) -> PResult<'a, FieldDef> { let name = self.parse_field_ident(adt_ty, lo)?; diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 3ff3d7868adc5..bf7c3d31d126d 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -16,7 +16,6 @@ pub use diagnostics::AttemptLocalParseRecovery; pub(crate) use item::FnParseMode; pub use pat::{CommaRecoveryMode, RecoverColon, RecoverComma}; pub use path::PathStyle; -use rustc_errors::struct_span_err; use rustc_ast::ptr::P; use rustc_ast::token::{self, Delimiter, Nonterminal, Token, TokenKind}; @@ -27,7 +26,8 @@ use rustc_ast::AttrId; use rustc_ast::DUMMY_NODE_ID; use rustc_ast::{self as ast, AnonConst, AttrStyle, Const, DelimArgs, Extern}; use rustc_ast::{Async, AttrArgs, AttrArgsEq, Expr, ExprKind, MacDelimiter, Mutability, StrLit}; -use rustc_ast::{HasAttrs, HasTokens, Restriction, Unsafe, Visibility, VisibilityKind}; +use rustc_ast::{HasAttrs, HasTokens, Unsafe}; +use rustc_ast::{Restriction, RestrictionKind, Visibility, VisibilityKind}; use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync::Ordering; @@ -44,7 +44,8 @@ use thin_vec::ThinVec; use tracing::debug; use crate::errors::{ - self, IncorrectVisibilityRestriction, MismatchedClosingDelimiter, NonStringAbiLiteral, + self, IncorrectRestriction, IncorrectVisibilityRestriction, MismatchedClosingDelimiter, + NakedRestriction, NonStringAbiLiteral, }; bitflags::bitflags! { @@ -1459,16 +1460,13 @@ impl<'a> Parser<'a> { Ok(()) } - /// Parses `kw(in path)` plus shortcuts `kw(crate)` for `kw(in crate)`, `kw(self)` for + /// Parses `kw`, `kw(in path)`, and shortcuts `kw(crate)` for `kw(in crate)`, `kw(self)` for /// `kw(in self)` and `kw(super)` for `kw(in super)`. - fn parse_restriction( + fn parse_restriction( &mut self, - kw: Symbol, - feature_gate: Option, - action: &str, fbt: FollowedByType, - ) -> PResult<'a, Restriction> { - if !self.eat_keyword(kw) { + ) -> PResult<'a, Restriction> { + if !self.eat_keyword(Kind::KW_SYM) { // We need a span, but there's inherently no keyword to grab a span from for an implied // restriction. An empty span at the beginning of the current token is a reasonable // fallback. @@ -1476,68 +1474,76 @@ impl<'a> Parser<'a> { } let gate = |span| { - if let Some(feature_gate) = feature_gate { + if let Some(feature_gate) = Kind::FEATURE_GATE { self.sess.gated_spans.gate(feature_gate, span); } span }; - let lo = self.prev_token.span; + let kw_span = self.prev_token.span; - self.expect(&token::OpenDelim(Delimiter::Parenthesis))?; - - if self.check_keyword(kw::In) { - // Parse `kw(in path)`. - self.bump(); // `in` - let path = self.parse_path(PathStyle::Mod)?; // `path` - self.expect(&token::CloseDelim(Delimiter::Parenthesis))?; // `)` - return Ok(Restriction::restricted(P(path), ast::DUMMY_NODE_ID, false) - .with_span(lo.to(gate(lo.to(self.prev_token.span))))); - } else if self.look_ahead(1, |t| t == &token::CloseDelim(Delimiter::Parenthesis)) - && self.is_keyword_ahead(0, &[kw::Crate, kw::Super, kw::SelfLower]) - { - // Parse `kw(crate)`, `kw(self)`, or `kw(super)`. - let path = self.parse_path(PathStyle::Mod)?; // `crate`/`super`/`self` - self.expect(&token::CloseDelim(Delimiter::Parenthesis))?; // `)` - return Ok(Restriction::restricted(P(path), ast::DUMMY_NODE_ID, true) - .with_span(gate(lo.to(self.prev_token.span)))); - } else if let FollowedByType::No = fbt { - // Provide this diagnostic if a type cannot follow; - // in particular, if this is not a tuple struct. - self.recover_incorrect_restriction(kw.as_str(), action)?; - // Emit diagnostic, but continue unrestricted. - Ok(Restriction::implied()) + if self.check(&token::OpenDelim(Delimiter::Parenthesis)) { + if self.is_keyword_ahead(1, &[kw::In]) { + // Parse `kw(in path)`. + self.bump(); // `(` + self.bump(); // `in` + let path = self.parse_path(PathStyle::Mod)?; // `path` + self.expect(&token::CloseDelim(Delimiter::Parenthesis))?; // `)` + return Ok(Restriction::restricted(P(path), ast::DUMMY_NODE_ID, false) + .with_span(gate(kw_span.to(kw_span.to(self.prev_token.span))))); + } else if self.look_ahead(2, |t| t == &token::CloseDelim(Delimiter::Parenthesis)) + && self.is_keyword_ahead(1, &[kw::Crate, kw::Super, kw::SelfLower]) + { + // Parse `kw(crate)`, `kw(self)`, or `kw(super)`. + self.bump(); // `(` + let path = self.parse_path(PathStyle::Mod)?; // `crate`/`super`/`self` + self.expect(&token::CloseDelim(Delimiter::Parenthesis))?; // `)` + return Ok(Restriction::restricted(P(path), ast::DUMMY_NODE_ID, true) + .with_span(gate(kw_span.to(self.prev_token.span)))); + } else { + if let FollowedByType::No = fbt { + // Provide this diagnostic if a type cannot follow; + // in particular, if this is not a tuple struct. + self.recover_incorrect_restriction::()?; + } + Ok(Restriction::implied()) + } } else { - // FIXME(jhpratt) Is this case ever actually encountered? - Ok(Restriction::implied()) + if !Kind::ALLOWS_KW_ONLY { + self.recover_naked_restriction::(kw_span)?; + } + Ok(Restriction::unrestricted()) } } /// Recovery for e.g. `kw(something) fn ...` or `struct X { kw(something) y: Z }` - fn recover_incorrect_restriction(&mut self, kw: &str, action: &str) -> PResult<'a, ()> { + fn recover_incorrect_restriction(&mut self) -> PResult<'a, ()> { self.bump(); // `(` let path = self.parse_path(PathStyle::Mod)?; self.expect(&token::CloseDelim(Delimiter::Parenthesis))?; // `)` - let msg = "incorrect restriction"; - let suggestion = format!( - r##"some possible restrictions are:\n\ - `{kw}(crate)`: {action} only in the current crate\n\ - `{kw}(super)`: {action} only in the current module's parent\n\ - `{kw}(in path::to::module)`: {action} only in the specified path"## - ); + self.sess.emit_err(IncorrectRestriction { + span: path.span, + path: pprust::path_to_string(&path), + kind: Kind::DESCRIPTION, + action: Kind::ACTION, + kw: Kind::KW_STR, + }); - let path_str = pprust::path_to_string(&path); + Ok(()) + } - struct_span_err!(self.sess.span_diagnostic, path.span, E0704, "{msg}") - .help(suggestion) - .span_suggestion( - path.span, - format!("make this {action} only to module `{path_str}` with `in`"), - format!("in {path_str}"), - Applicability::MachineApplicable, - ) - .emit(); + /// Recovery for `kw` when `kw(path)` is required. + fn recover_naked_restriction( + &mut self, + kw_span: Span, + ) -> PResult<'a, ()> { + self.sess.emit_err(NakedRestriction { + span: kw_span, + kind: Kind::DESCRIPTION, + action: Kind::ACTION, + kw: Kind::KW_STR, + }); Ok(()) } diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index f3fba84f1b09f..36c39cae13ef3 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -325,23 +325,29 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { self.r.field_def_ids.insert(def_id, self.r.tcx.arena.alloc_from_iter(def_ids)); } - fn resolve_restriction(&mut self, restriction: &ast::Restriction) -> ty::Restriction { + fn resolve_restriction( + &mut self, + restriction: &ast::Restriction, + ) -> ty::Restriction { self.try_resolve_restriction(restriction, true).unwrap_or_else(|err| { self.r.report_restriction_error(err); ty::Restriction::Unrestricted }) } - fn try_resolve_restriction<'ast>( + fn try_resolve_restriction<'ast, Kind: ast::RestrictionKind>( &mut self, - restriction: &'ast ast::Restriction, + restriction: &'ast ast::Restriction, finalize: bool, ) -> Result> { let parent_scope = &self.parent_scope; - match restriction.kind { + match restriction.level { + ast::RestrictionLevel::Unrestricted => Ok(ty::Restriction::Unrestricted), + // FIXME(jhpratt) create an "implied" level in rustc_middle. This will be useful for + // lints in addition to conversion to visibility. // If the restriction is implied, it has no effect when the item is otherwise visible. - ast::RestrictionKind::Implied => Ok(ty::Restriction::Unrestricted), - ast::RestrictionKind::Restricted { ref path, id, shorthand: _ } => { + ast::RestrictionLevel::Implied => Ok(ty::Restriction::Unrestricted), + ast::RestrictionLevel::Restricted { ref path, id, shorthand: _ } => { // For restrictions we are not ready to provide correct implementation of "uniform // paths" right now, so on 2018 edition we only allow module-relative paths for now. // On 2015 edition visibilities are resolved as crate-relative by default, diff --git a/src/tools/rustfmt/src/items.rs b/src/tools/rustfmt/src/items.rs index e6e3364646d5b..84f89210e9a0e 100644 --- a/src/tools/rustfmt/src/items.rs +++ b/src/tools/rustfmt/src/items.rs @@ -1131,7 +1131,7 @@ pub(crate) fn format_trait( let header = format!( "{}{}{}{}trait ", format_visibility(context, &item.vis), - format_restriction("impl", context, &impl_restriction), + format_restriction(context, &impl_restriction), format_unsafety(unsafety), format_auto(is_auto), ); @@ -1828,7 +1828,7 @@ pub(crate) fn rewrite_struct_field_prefix( field: &ast::FieldDef, ) -> Option { let vis = format_visibility(context, &field.vis); - let mut_restriction = format_restriction("mut", context, &field.mut_restriction); + let mut_restriction = format_restriction(context, &field.mut_restriction); let type_annotation_spacing = type_annotation_spacing(context.config); Some(match field.ident { Some(name) => format!( diff --git a/src/tools/rustfmt/src/utils.rs b/src/tools/rustfmt/src/utils.rs index 7b2033fefc0d3..680febb65f5ac 100644 --- a/src/tools/rustfmt/src/utils.rs +++ b/src/tools/rustfmt/src/utils.rs @@ -2,7 +2,7 @@ use std::borrow::Cow; use rustc_ast::ast::{ self, Attribute, MetaItem, MetaItemKind, NestedMetaItem, NodeId, Path, Restriction, - RestrictionKind, Visibility, VisibilityKind, + RestrictionLevel, Visibility, VisibilityKind, }; use rustc_ast::ptr; use rustc_ast_pretty::pprust; @@ -75,17 +75,18 @@ pub(crate) fn format_visibility( } // Does not allocate in the common, implied case. -pub(crate) fn format_restriction( - kw: &'static str, +pub(crate) fn format_restriction( context: &RewriteContext<'_>, - restriction: &Restriction, -) -> String { - match restriction.kind { - RestrictionKind::Restricted { + restriction: &Restriction, +) -> Cow<'static, str> { + match restriction.level { + RestrictionLevel::Unrestricted => Kind::KW_STR.into(), + RestrictionLevel::Restricted { ref path, id: _, shorthand, } => { + let kw = Kind::KW_STR; let Path { ref segments, .. } = **path; let mut segments_iter = segments.iter().map(|seg| rewrite_ident(context, seg.ident)); if path.is_global() && segments_iter.next().is_none() { @@ -96,9 +97,9 @@ pub(crate) fn format_restriction( let path = itertools::join(segments_iter, "::"); let in_str = if shorthand { "" } else { "in " }; - format!("{kw}({in_str}{path}) ") + format!("{kw}({in_str}{path}) ").into() } - RestrictionKind::Implied => String::new(), + RestrictionLevel::Implied => "".into(), } } diff --git a/tests/ui/restrictions/in-path-rustfix.fixed b/tests/ui/restrictions/in-path-rustfix.fixed new file mode 100644 index 0000000000000..c5c0b4845bb90 --- /dev/null +++ b/tests/ui/restrictions/in-path-rustfix.fixed @@ -0,0 +1,10 @@ +// run-rustfix +// compile-flags: --crate-type=lib + +#![feature(mut_restriction)] + +pub mod a { + pub struct Foo { + mut(in crate::a) _foo: u8, //~ ERROR incorrect mut restriction + } +} diff --git a/tests/ui/restrictions/in-path-rustfix.rs b/tests/ui/restrictions/in-path-rustfix.rs new file mode 100644 index 0000000000000..c4ed040987e10 --- /dev/null +++ b/tests/ui/restrictions/in-path-rustfix.rs @@ -0,0 +1,10 @@ +// run-rustfix +// compile-flags: --crate-type=lib + +#![feature(mut_restriction)] + +pub mod a { + pub struct Foo { + mut(crate::a) _foo: u8, //~ ERROR incorrect mut restriction + } +} diff --git a/tests/ui/restrictions/in-path-rustfix.stderr b/tests/ui/restrictions/in-path-rustfix.stderr new file mode 100644 index 0000000000000..5140922d493fb --- /dev/null +++ b/tests/ui/restrictions/in-path-rustfix.stderr @@ -0,0 +1,14 @@ +error[E0704]: incorrect mut restriction + --> $DIR/in-path-rustfix.rs:8:13 + | +LL | mut(crate::a) _foo: u8, + | ^^^^^^^^ help: make this mutable only to module `crate::a` with `in`: `in crate::a` + | + = help: some possible mut restrictions are: + `mut(crate)`: mutable only in the current crate + `mut(super)`: mutable only in the current module's parent + `mut(in path::to::module)`: mutable only in the specified path + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0704`. diff --git a/tests/ui/restrictions/naked-impl-restriction.rs b/tests/ui/restrictions/naked-impl-restriction.rs index 295dbd721107b..ab0b1f52f4f52 100644 --- a/tests/ui/restrictions/naked-impl-restriction.rs +++ b/tests/ui/restrictions/naked-impl-restriction.rs @@ -1,4 +1,4 @@ // compile-flags: --crate-type=lib #![feature(impl_restriction)] -pub impl trait Foo {} //~ ERROR expected `(` +pub impl trait Foo {} //~ ERROR incorrect impl restriction diff --git a/tests/ui/restrictions/naked-impl-restriction.stderr b/tests/ui/restrictions/naked-impl-restriction.stderr index 363266b6636a8..ff872b44d26d4 100644 --- a/tests/ui/restrictions/naked-impl-restriction.stderr +++ b/tests/ui/restrictions/naked-impl-restriction.stderr @@ -1,8 +1,14 @@ -error: expected `(`, found keyword `trait` - --> $DIR/naked-impl-restriction.rs:4:10 +error[E0704]: incorrect impl restriction + --> $DIR/naked-impl-restriction.rs:4:5 | LL | pub impl trait Foo {} - | ^^^^^ expected `(` + | ^^^^ help: make this implementable only in the current crate: `impl(crate)` + | + = help: some possible impl restrictions are: + `impl(crate)`: implementable only in the current crate + `impl(super)`: implementable only in the current module's parent + `impl(in path::to::module)`: implementable only in the specified path error: aborting due to previous error +For more information about this error, try `rustc --explain E0704`. diff --git a/tests/ui/restrictions/naked-mut-restriction.rs b/tests/ui/restrictions/naked-mut-restriction.rs index e3deb0ec0fffe..f92a7761b746f 100644 --- a/tests/ui/restrictions/naked-mut-restriction.rs +++ b/tests/ui/restrictions/naked-mut-restriction.rs @@ -2,5 +2,5 @@ #![feature(mut_restriction)] pub struct Foo { - pub mut x: u32, //~ ERROR expected `(` + pub mut x: u32, //~ ERROR incorrect mut restriction } diff --git a/tests/ui/restrictions/naked-mut-restriction.stderr b/tests/ui/restrictions/naked-mut-restriction.stderr index ebd00c7e08b88..a0478a884c868 100644 --- a/tests/ui/restrictions/naked-mut-restriction.stderr +++ b/tests/ui/restrictions/naked-mut-restriction.stderr @@ -1,10 +1,14 @@ -error: expected `(`, found `x` - --> $DIR/naked-mut-restriction.rs:5:13 +error[E0704]: incorrect mut restriction + --> $DIR/naked-mut-restriction.rs:5:9 | -LL | pub struct Foo { - | --- while parsing this struct LL | pub mut x: u32, - | ^ expected `(` + | ^^^ help: make this mutable only in the current crate: `mut(crate)` + | + = help: some possible mut restrictions are: + `mut(crate)`: mutable only in the current crate + `mut(super)`: mutable only in the current module's parent + `mut(in path::to::module)`: mutable only in the specified path error: aborting due to previous error +For more information about this error, try `rustc --explain E0704`. From 2f7037c007748b92d027aee8f5f1bd67cd5c7361 Mon Sep 17 00:00:00 2001 From: Jacob Pratt Date: Wed, 11 Jan 2023 08:51:16 +0000 Subject: [PATCH 36/45] Parse visibility as a restriction --- compiler/rustc_ast/src/ast.rs | 78 ++++++----- .../rustc_ast_pretty/src/pprust/state/item.rs | 4 +- compiler/rustc_parse/messages.ftl | 26 ++-- compiler/rustc_parse/src/errors.rs | 28 ++-- compiler/rustc_parse/src/parser/mod.rs | 122 ++++-------------- src/tools/rustfmt/src/utils.rs | 4 +- tests/ui/pub/pub-restricted.stderr | 20 +-- .../naked-impl-restriction.stderr | 2 +- .../restrictions/naked-mut-restriction.stderr | 2 +- 9 files changed, 109 insertions(+), 177 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 5636410ecdda4..fe36e9f217ebe 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -2729,23 +2729,22 @@ pub mod restriction_kind { /// trait. macro_rules! restriction { ( + requires_explicit_path: $requires_explicit_path:ident, name: $name:ident, - allows_kw_only: $allows_kw_only:literal, - kw_sym: $kw_sym:path, - kw_str: $kw_str:literal, - action: $action:literal, - description: $description:literal, + keyword: $keyword_sym:path => $keyword_str:literal, + adjective: $adjective:literal, + noun: $noun:literal, feature_gate: $feature_gate:expr $(,)? ) => { #[derive(Debug, Clone, Copy, Encodable, Decodable)] pub enum $name {} impl RestrictionKind for $name { - const ALLOWS_KW_ONLY: bool = $allows_kw_only; - const KW_SYM: Symbol = $kw_sym; - const KW_STR: &'static str = $kw_str; - const ACTION: &'static str = $action; - const DESCRIPTION: &'static str = $description; + const REQUIRES_EXPLICIT_PATH: bool = $requires_explicit_path; + const KEYWORD_SYM: Symbol = $keyword_sym; + const KEYWORD_STR: &'static str = $keyword_str; + const ADJECTIVE: &'static str = $adjective; + const NOUN: &'static str = $noun; const FEATURE_GATE: Option = $feature_gate; } @@ -2759,39 +2758,36 @@ pub mod restriction_kind { } pub trait RestrictionKind: sealed::Sealed { - const ALLOWS_KW_ONLY: bool; - const KW_SYM: Symbol; - const KW_STR: &'static str; - const ACTION: &'static str; - const DESCRIPTION: &'static str; + const REQUIRES_EXPLICIT_PATH: bool; + const KEYWORD_SYM: Symbol; + const KEYWORD_STR: &'static str; + const ADJECTIVE: &'static str; + const NOUN: &'static str; const FEATURE_GATE: Option; } restriction! { + requires_explicit_path: false, name: Visibility, - allows_kw_only: true, - kw_sym: kw::Pub, - kw_str: "pub", - action: "visible", - description: "visibility", + keyword: kw::Pub => "pub", + adjective: "visible", + noun: "visibility", feature_gate: None, } restriction! { + requires_explicit_path: true, name: Impl, - allows_kw_only: false, - kw_sym: kw::Impl, - kw_str: "impl", - action: "implementable", - description: "impl", + keyword: kw::Impl => "impl", + adjective: "implementable", + noun: "impl", feature_gate: Some(sym::impl_restriction), } restriction! { + requires_explicit_path: true, name: Mut, - allows_kw_only: false, - kw_sym: kw::Mut, - kw_str: "mut", - action: "mutable", - description: "mut", + keyword: kw::Mut => "mut", + adjective: "mutable", + noun: "mut", feature_gate: Some(sym::mut_restriction), } } @@ -2816,6 +2812,28 @@ pub enum RestrictionLevel { Implied, } +impl From> for Visibility { + fn from(restriction: Restriction) -> Self { + match restriction.level { + RestrictionLevel::Unrestricted => Self { + kind: VisibilityKind::Public, + span: restriction.span, + tokens: restriction.tokens, + }, + RestrictionLevel::Restricted { path, id, shorthand } => Self { + kind: VisibilityKind::Restricted { path, id, shorthand }, + span: restriction.span, + tokens: restriction.tokens, + }, + RestrictionLevel::Implied => Self { + kind: VisibilityKind::Inherited, + span: restriction.span, + tokens: restriction.tokens, + }, + } + } +} + impl Restriction { pub fn unrestricted() -> Self { Self { diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs index 16e6ce7bc9f93..e28da52b7cf0a 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/item.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs @@ -435,9 +435,9 @@ impl<'a> State<'a> { restriction: &ast::Restriction, ) { match restriction.level { - ast::RestrictionLevel::Unrestricted => self.word_nbsp(Kind::KW_STR), + ast::RestrictionLevel::Unrestricted => self.word_nbsp(Kind::KEYWORD_STR), ast::RestrictionLevel::Restricted { ref path, id: _, shorthand } => { - let kw = Kind::KW_STR; + let kw = Kind::KEYWORD_STR; let path = Self::to_string(|s| s.print_path(path, false, 0)); if shorthand { self.word_nbsp(format!("{kw}({path})")) diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index f92aaf3da120f..f163cb529be34 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -519,19 +519,19 @@ parse_missing_comma_after_match_arm = expected `,` following `match` arm parse_missing_const_type = missing type for `{$kind}` item .suggestion = provide a type for the item -parse_incorrect_restriction = incorrect {$kind} restriction - .help = some possible {$kind} restrictions are: - `{$kw}(crate)`: {$action} only in the current crate - `{$kw}(super)`: {$action} only in the current module's parent - `{$kw}(in path::to::module)`: {$action} only in the specified path - .suggestion = make this {$action} only to module `{$path}` with `in` - -parse_naked_restriction = incorrect {$kind} restriction - .help = some possible {$kind} restrictions are: - `{$kw}(crate)`: {$action} only in the current crate - `{$kw}(super)`: {$action} only in the current module's parent - `{$kw}(in path::to::module)`: {$action} only in the specified path - .suggestion = make this {$action} only in the current crate +parse_incorrect_restriction = incorrect {$noun} restriction + .help = some possible {$noun} restrictions are: + `{$keyword}(crate)`: {$adjective} only in the current crate + `{$keyword}(super)`: {$adjective} only in the current module's parent + `{$keyword}(in path::to::module)`: {$adjective} only in the specified path + .suggestion = make this {$adjective} only to module `{$path}` with `in` + +parse_restriction_missing_path = incorrect {$noun} restriction + .help = some possible {$noun} restrictions are: + `{$keyword}(crate)`: {$adjective} only in the current crate + `{$keyword}(super)`: {$adjective} only in the current module's parent + `{$keyword}(in path::to::module)`: {$adjective} only in the specified path + .suggestion = make this {$adjective} only to the current crate parse_missing_expression_in_for_loop = missing expression to iterate on in `for` loop .suggestion = try adding an expression to the `for` loop diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index a5d7db450e457..342ab971be1db 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -811,16 +811,6 @@ pub(crate) struct MismatchedClosingDelimiter { pub unclosed: Option, } -#[derive(Diagnostic)] -#[diag(parse_incorrect_visibility_restriction, code = "E0704")] -#[help] -pub(crate) struct IncorrectVisibilityRestriction { - #[primary_span] - #[suggestion(code = "in {inner_str}", applicability = "machine-applicable")] - pub span: Span, - pub inner_str: String, -} - #[derive(Diagnostic)] #[diag(parse_incorrect_restriction, code = "E0704")] #[help] @@ -829,21 +819,21 @@ pub(crate) struct IncorrectRestriction { #[suggestion(code = "in {path}", applicability = "machine-applicable")] pub span: Span, pub path: String, - pub kind: &'static str, - pub action: &'static str, - pub kw: &'static str, + pub noun: &'static str, + pub adjective: &'static str, + pub keyword: &'static str, } #[derive(Diagnostic)] -#[diag(parse_naked_restriction, code = "E0704")] +#[diag(parse_restriction_missing_path, code = "E0704")] #[help] -pub(crate) struct NakedRestriction { +pub(crate) struct RestrictionMissingPath { #[primary_span] - #[suggestion(code = "{kw}(crate)", applicability = "machine-applicable")] + #[suggestion(code = "{keyword}(crate)", applicability = "maybe-incorrect")] pub span: Span, - pub kind: &'static str, - pub action: &'static str, - pub kw: &'static str, + pub noun: &'static str, + pub adjective: &'static str, + pub keyword: &'static str, } #[derive(Diagnostic)] diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index bf7c3d31d126d..f22ae09ecbe05 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -27,7 +27,7 @@ use rustc_ast::DUMMY_NODE_ID; use rustc_ast::{self as ast, AnonConst, AttrStyle, Const, DelimArgs, Extern}; use rustc_ast::{Async, AttrArgs, AttrArgsEq, Expr, ExprKind, MacDelimiter, Mutability, StrLit}; use rustc_ast::{HasAttrs, HasTokens, Unsafe}; -use rustc_ast::{Restriction, RestrictionKind, Visibility, VisibilityKind}; +use rustc_ast::{Restriction, RestrictionKind, Visibility}; use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync::Ordering; @@ -44,8 +44,8 @@ use thin_vec::ThinVec; use tracing::debug; use crate::errors::{ - self, IncorrectRestriction, IncorrectVisibilityRestriction, MismatchedClosingDelimiter, - NakedRestriction, NonStringAbiLiteral, + self, IncorrectRestriction, MismatchedClosingDelimiter, NonStringAbiLiteral, + RestrictionMissingPath, }; bitflags::bitflags! { @@ -1386,78 +1386,7 @@ impl<'a> Parser<'a> { // Public for rustfmt usage. pub fn parse_visibility(&mut self, fbt: FollowedByType) -> PResult<'a, Visibility> { maybe_whole!(self, NtVis, |x| x.into_inner()); - - if !self.eat_keyword(kw::Pub) { - // We need a span for our `Spanned`, but there's inherently no - // keyword to grab a span from for inherited visibility; an empty span at the - // beginning of the current token would seem to be the "Schelling span". - return Ok(Visibility { - span: self.token.span.shrink_to_lo(), - kind: VisibilityKind::Inherited, - tokens: None, - }); - } - let lo = self.prev_token.span; - - if self.check(&token::OpenDelim(Delimiter::Parenthesis)) { - // We don't `self.bump()` the `(` yet because this might be a struct definition where - // `()` or a tuple might be allowed. For example, `struct Struct(pub (), pub (usize));`. - // Because of this, we only `bump` the `(` if we're assured it is appropriate to do so - // by the following tokens. - if self.is_keyword_ahead(1, &[kw::In]) { - // Parse `pub(in path)`. - self.bump(); // `(` - self.bump(); // `in` - let path = self.parse_path(PathStyle::Mod)?; // `path` - self.expect(&token::CloseDelim(Delimiter::Parenthesis))?; // `)` - let vis = VisibilityKind::Restricted { - path: P(path), - id: ast::DUMMY_NODE_ID, - shorthand: false, - }; - return Ok(Visibility { - span: lo.to(self.prev_token.span), - kind: vis, - tokens: None, - }); - } else if self.look_ahead(2, |t| t == &token::CloseDelim(Delimiter::Parenthesis)) - && self.is_keyword_ahead(1, &[kw::Crate, kw::Super, kw::SelfLower]) - { - // Parse `pub(crate)`, `pub(self)`, or `pub(super)`. - self.bump(); // `(` - let path = self.parse_path(PathStyle::Mod)?; // `crate`/`super`/`self` - self.expect(&token::CloseDelim(Delimiter::Parenthesis))?; // `)` - let vis = VisibilityKind::Restricted { - path: P(path), - id: ast::DUMMY_NODE_ID, - shorthand: true, - }; - return Ok(Visibility { - span: lo.to(self.prev_token.span), - kind: vis, - tokens: None, - }); - } else if let FollowedByType::No = fbt { - // Provide this diagnostic if a type cannot follow; - // in particular, if this is not a tuple struct. - self.recover_incorrect_vis_restriction()?; - // Emit diagnostic, but continue with public visibility. - } - } - - Ok(Visibility { span: lo, kind: VisibilityKind::Public, tokens: None }) - } - - /// Recovery for e.g. `pub(something) fn ...` or `struct X { pub(something) y: Z }` - fn recover_incorrect_vis_restriction(&mut self) -> PResult<'a, ()> { - self.bump(); // `(` - let path = self.parse_path(PathStyle::Mod)?; - self.expect(&token::CloseDelim(Delimiter::Parenthesis))?; // `)` - - let path_str = pprust::path_to_string(&path); - self.sess.emit_err(IncorrectVisibilityRestriction { span: path.span, inner_str: path_str }); - - Ok(()) + self.parse_restriction(fbt).map(Into::into) } /// Parses `kw`, `kw(in path)`, and shortcuts `kw(crate)` for `kw(in crate)`, `kw(self)` for @@ -1466,7 +1395,7 @@ impl<'a> Parser<'a> { &mut self, fbt: FollowedByType, ) -> PResult<'a, Restriction> { - if !self.eat_keyword(Kind::KW_SYM) { + if !self.eat_keyword(Kind::KEYWORD_SYM) { // We need a span, but there's inherently no keyword to grab a span from for an implied // restriction. An empty span at the beginning of the current token is a reasonable // fallback. @@ -1483,6 +1412,10 @@ impl<'a> Parser<'a> { let kw_span = self.prev_token.span; if self.check(&token::OpenDelim(Delimiter::Parenthesis)) { + // We don't `self.bump()` the `(` yet because this might be a struct definition where + // `()` or a tuple might be allowed. For example, `struct Struct(pub (), pub (usize));`. + // Because of this, we only bump the `(` if we're assured it is appropriate to do so + // by the following tokens. if self.is_keyword_ahead(1, &[kw::In]) { // Parse `kw(in path)`. self.bump(); // `(` @@ -1490,7 +1423,7 @@ impl<'a> Parser<'a> { let path = self.parse_path(PathStyle::Mod)?; // `path` self.expect(&token::CloseDelim(Delimiter::Parenthesis))?; // `)` return Ok(Restriction::restricted(P(path), ast::DUMMY_NODE_ID, false) - .with_span(gate(kw_span.to(kw_span.to(self.prev_token.span))))); + .with_span(gate(kw_span.to(self.prev_token.span)))); } else if self.look_ahead(2, |t| t == &token::CloseDelim(Delimiter::Parenthesis)) && self.is_keyword_ahead(1, &[kw::Crate, kw::Super, kw::SelfLower]) { @@ -1505,14 +1438,20 @@ impl<'a> Parser<'a> { // Provide this diagnostic if a type cannot follow; // in particular, if this is not a tuple struct. self.recover_incorrect_restriction::()?; + // Emit diagnostic, but continue with no restriction. } - Ok(Restriction::implied()) + Ok(Restriction::unrestricted().with_span(gate(kw_span))) } } else { - if !Kind::ALLOWS_KW_ONLY { - self.recover_naked_restriction::(kw_span)?; + if Kind::REQUIRES_EXPLICIT_PATH { + self.sess.emit_err(RestrictionMissingPath { + span: kw_span, + noun: Kind::NOUN, + adjective: Kind::ADJECTIVE, + keyword: Kind::KEYWORD_STR, + }); } - Ok(Restriction::unrestricted()) + Ok(Restriction::unrestricted().with_span(gate(kw_span))) } } @@ -1525,24 +1464,9 @@ impl<'a> Parser<'a> { self.sess.emit_err(IncorrectRestriction { span: path.span, path: pprust::path_to_string(&path), - kind: Kind::DESCRIPTION, - action: Kind::ACTION, - kw: Kind::KW_STR, - }); - - Ok(()) - } - - /// Recovery for `kw` when `kw(path)` is required. - fn recover_naked_restriction( - &mut self, - kw_span: Span, - ) -> PResult<'a, ()> { - self.sess.emit_err(NakedRestriction { - span: kw_span, - kind: Kind::DESCRIPTION, - action: Kind::ACTION, - kw: Kind::KW_STR, + adjective: Kind::ADJECTIVE, + noun: Kind::NOUN, + keyword: Kind::KEYWORD_STR, }); Ok(()) diff --git a/src/tools/rustfmt/src/utils.rs b/src/tools/rustfmt/src/utils.rs index 680febb65f5ac..d4c461a1748ce 100644 --- a/src/tools/rustfmt/src/utils.rs +++ b/src/tools/rustfmt/src/utils.rs @@ -80,13 +80,13 @@ pub(crate) fn format_restriction( restriction: &Restriction, ) -> Cow<'static, str> { match restriction.level { - RestrictionLevel::Unrestricted => Kind::KW_STR.into(), + RestrictionLevel::Unrestricted => Kind::KEYWORD_STR.into(), RestrictionLevel::Restricted { ref path, id: _, shorthand, } => { - let kw = Kind::KW_STR; + let kw = Kind::KEYWORD_STR; let Path { ref segments, .. } = **path; let mut segments_iter = segments.iter().map(|seg| rewrite_ident(context, seg.ident)); if path.is_global() && segments_iter.next().is_none() { diff --git a/tests/ui/pub/pub-restricted.stderr b/tests/ui/pub/pub-restricted.stderr index 4694530e54863..390b0d593455a 100644 --- a/tests/ui/pub/pub-restricted.stderr +++ b/tests/ui/pub/pub-restricted.stderr @@ -5,9 +5,9 @@ LL | pub (a) fn afn() {} | ^ help: make this visible only to module `a` with `in`: `in a` | = help: some possible visibility restrictions are: - `pub(crate)`: visible only on the current crate + `pub(crate)`: visible only in the current crate `pub(super)`: visible only in the current module's parent - `pub(in path::to::module)`: visible only on the specified path + `pub(in path::to::module)`: visible only in the specified path error[E0704]: incorrect visibility restriction --> $DIR/pub-restricted.rs:4:6 @@ -16,9 +16,9 @@ LL | pub (b) fn bfn() {} | ^ help: make this visible only to module `b` with `in`: `in b` | = help: some possible visibility restrictions are: - `pub(crate)`: visible only on the current crate + `pub(crate)`: visible only in the current crate `pub(super)`: visible only in the current module's parent - `pub(in path::to::module)`: visible only on the specified path + `pub(in path::to::module)`: visible only in the specified path error[E0704]: incorrect visibility restriction --> $DIR/pub-restricted.rs:5:6 @@ -27,9 +27,9 @@ LL | pub (crate::a) fn cfn() {} | ^^^^^^^^ help: make this visible only to module `crate::a` with `in`: `in crate::a` | = help: some possible visibility restrictions are: - `pub(crate)`: visible only on the current crate + `pub(crate)`: visible only in the current crate `pub(super)`: visible only in the current module's parent - `pub(in path::to::module)`: visible only on the specified path + `pub(in path::to::module)`: visible only in the specified path error[E0704]: incorrect visibility restriction --> $DIR/pub-restricted.rs:22:14 @@ -38,9 +38,9 @@ LL | pub (a) invalid: usize, | ^ help: make this visible only to module `a` with `in`: `in a` | = help: some possible visibility restrictions are: - `pub(crate)`: visible only on the current crate + `pub(crate)`: visible only in the current crate `pub(super)`: visible only in the current module's parent - `pub(in path::to::module)`: visible only on the specified path + `pub(in path::to::module)`: visible only in the specified path error[E0704]: incorrect visibility restriction --> $DIR/pub-restricted.rs:31:6 @@ -49,9 +49,9 @@ LL | pub (xyz) fn xyz() {} | ^^^ help: make this visible only to module `xyz` with `in`: `in xyz` | = help: some possible visibility restrictions are: - `pub(crate)`: visible only on the current crate + `pub(crate)`: visible only in the current crate `pub(super)`: visible only in the current module's parent - `pub(in path::to::module)`: visible only on the specified path + `pub(in path::to::module)`: visible only in the specified path error[E0742]: visibilities can only be restricted to ancestor modules --> $DIR/pub-restricted.rs:23:17 diff --git a/tests/ui/restrictions/naked-impl-restriction.stderr b/tests/ui/restrictions/naked-impl-restriction.stderr index ff872b44d26d4..f99d097353ea6 100644 --- a/tests/ui/restrictions/naked-impl-restriction.stderr +++ b/tests/ui/restrictions/naked-impl-restriction.stderr @@ -2,7 +2,7 @@ error[E0704]: incorrect impl restriction --> $DIR/naked-impl-restriction.rs:4:5 | LL | pub impl trait Foo {} - | ^^^^ help: make this implementable only in the current crate: `impl(crate)` + | ^^^^ help: make this implementable only to the current crate: `impl(crate)` | = help: some possible impl restrictions are: `impl(crate)`: implementable only in the current crate diff --git a/tests/ui/restrictions/naked-mut-restriction.stderr b/tests/ui/restrictions/naked-mut-restriction.stderr index a0478a884c868..a1e7c54312123 100644 --- a/tests/ui/restrictions/naked-mut-restriction.stderr +++ b/tests/ui/restrictions/naked-mut-restriction.stderr @@ -2,7 +2,7 @@ error[E0704]: incorrect mut restriction --> $DIR/naked-mut-restriction.rs:5:9 | LL | pub mut x: u32, - | ^^^ help: make this mutable only in the current crate: `mut(crate)` + | ^^^ help: make this mutable only to the current crate: `mut(crate)` | = help: some possible mut restrictions are: `mut(crate)`: mutable only in the current crate From 497f535e4b5068043bf852671124603a1ece744a Mon Sep 17 00:00:00 2001 From: Urgau Date: Thu, 25 May 2023 18:53:16 +0200 Subject: [PATCH 37/45] Bless HIR stats --- tests/ui/stats/hir-stats.stderr | 76 ++++++++++++++++----------------- 1 file changed, 38 insertions(+), 38 deletions(-) diff --git a/tests/ui/stats/hir-stats.stderr b/tests/ui/stats/hir-stats.stderr index d723ff538a886..a40d3168abc71 100644 --- a/tests/ui/stats/hir-stats.stderr +++ b/tests/ui/stats/hir-stats.stderr @@ -15,45 +15,45 @@ ast-stats-1 Arm 96 ( 1.5%) 2 48 ast-stats-1 ForeignItem 96 ( 1.5%) 1 96 ast-stats-1 - Fn 96 ( 1.5%) 1 ast-stats-1 FnDecl 120 ( 1.8%) 5 24 -ast-stats-1 FieldDef 160 ( 2.5%) 2 80 -ast-stats-1 Stmt 160 ( 2.5%) 5 32 +ast-stats-1 Stmt 160 ( 2.4%) 5 32 ast-stats-1 - Local 32 ( 0.5%) 1 ast-stats-1 - MacCall 32 ( 0.5%) 1 ast-stats-1 - Expr 96 ( 1.5%) 3 -ast-stats-1 Param 160 ( 2.5%) 4 40 -ast-stats-1 Block 192 ( 3.0%) 6 32 +ast-stats-1 Param 160 ( 2.4%) 4 40 +ast-stats-1 Block 192 ( 2.9%) 6 32 ast-stats-1 Variant 208 ( 3.2%) 2 104 -ast-stats-1 GenericBound 224 ( 3.5%) 4 56 -ast-stats-1 - Trait 224 ( 3.5%) 4 +ast-stats-1 GenericBound 224 ( 3.4%) 4 56 +ast-stats-1 - Trait 224 ( 3.4%) 4 +ast-stats-1 FieldDef 224 ( 3.4%) 2 112 ast-stats-1 AssocItem 352 ( 5.4%) 4 88 ast-stats-1 - Type 176 ( 2.7%) 2 ast-stats-1 - Fn 176 ( 2.7%) 2 -ast-stats-1 GenericParam 480 ( 7.4%) 5 96 -ast-stats-1 Pat 504 ( 7.8%) 7 72 +ast-stats-1 GenericParam 480 ( 7.3%) 5 96 +ast-stats-1 Pat 504 ( 7.7%) 7 72 ast-stats-1 - Struct 72 ( 1.1%) 1 ast-stats-1 - Wild 72 ( 1.1%) 1 ast-stats-1 - Ident 360 ( 5.5%) 5 -ast-stats-1 Expr 576 ( 8.9%) 8 72 +ast-stats-1 Expr 576 ( 8.8%) 8 72 ast-stats-1 - Path 72 ( 1.1%) 1 ast-stats-1 - Match 72 ( 1.1%) 1 ast-stats-1 - Struct 72 ( 1.1%) 1 ast-stats-1 - Lit 144 ( 2.2%) 2 ast-stats-1 - Block 216 ( 3.3%) 3 -ast-stats-1 PathSegment 720 (11.1%) 30 24 -ast-stats-1 Ty 896 (13.8%) 14 64 +ast-stats-1 PathSegment 720 (11.0%) 30 24 +ast-stats-1 Ty 896 (13.7%) 14 64 ast-stats-1 - Ptr 64 ( 1.0%) 1 ast-stats-1 - Ref 64 ( 1.0%) 1 ast-stats-1 - ImplicitSelf 128 ( 2.0%) 2 -ast-stats-1 - Path 640 ( 9.9%) 10 -ast-stats-1 Item 1_224 (18.9%) 9 136 +ast-stats-1 - Path 640 ( 9.8%) 10 +ast-stats-1 Item 1_224 (18.7%) 9 136 ast-stats-1 - Trait 136 ( 2.1%) 1 ast-stats-1 - Enum 136 ( 2.1%) 1 ast-stats-1 - ForeignMod 136 ( 2.1%) 1 ast-stats-1 - Impl 136 ( 2.1%) 1 ast-stats-1 - Fn 272 ( 4.2%) 2 -ast-stats-1 - Use 408 ( 6.3%) 3 +ast-stats-1 - Use 408 ( 6.2%) 3 ast-stats-1 ---------------------------------------------------------------- -ast-stats-1 Total 6_488 +ast-stats-1 Total 6_552 ast-stats-1 ast-stats-2 POST EXPANSION AST STATS ast-stats-2 Name Accumulated Size Count Item Size @@ -65,32 +65,32 @@ ast-stats-2 ExprField 48 ( 0.7%) 1 48 ast-stats-2 WherePredicate 56 ( 0.8%) 1 56 ast-stats-2 - BoundPredicate 56 ( 0.8%) 1 ast-stats-2 Local 72 ( 1.0%) 1 72 -ast-stats-2 Arm 96 ( 1.4%) 2 48 -ast-stats-2 ForeignItem 96 ( 1.4%) 1 96 -ast-stats-2 - Fn 96 ( 1.4%) 1 +ast-stats-2 Arm 96 ( 1.3%) 2 48 +ast-stats-2 ForeignItem 96 ( 1.3%) 1 96 +ast-stats-2 - Fn 96 ( 1.3%) 1 ast-stats-2 InlineAsm 120 ( 1.7%) 1 120 ast-stats-2 FnDecl 120 ( 1.7%) 5 24 ast-stats-2 Attribute 128 ( 1.8%) 4 32 -ast-stats-2 - DocComment 32 ( 0.5%) 1 -ast-stats-2 - Normal 96 ( 1.4%) 3 -ast-stats-2 FieldDef 160 ( 2.3%) 2 80 -ast-stats-2 Stmt 160 ( 2.3%) 5 32 -ast-stats-2 - Local 32 ( 0.5%) 1 -ast-stats-2 - Semi 32 ( 0.5%) 1 -ast-stats-2 - Expr 96 ( 1.4%) 3 -ast-stats-2 Param 160 ( 2.3%) 4 40 +ast-stats-2 - DocComment 32 ( 0.4%) 1 +ast-stats-2 - Normal 96 ( 1.3%) 3 +ast-stats-2 Stmt 160 ( 2.2%) 5 32 +ast-stats-2 - Local 32 ( 0.4%) 1 +ast-stats-2 - Semi 32 ( 0.4%) 1 +ast-stats-2 - Expr 96 ( 1.3%) 3 +ast-stats-2 Param 160 ( 2.2%) 4 40 ast-stats-2 Block 192 ( 2.7%) 6 32 ast-stats-2 Variant 208 ( 2.9%) 2 104 -ast-stats-2 GenericBound 224 ( 3.2%) 4 56 -ast-stats-2 - Trait 224 ( 3.2%) 4 -ast-stats-2 AssocItem 352 ( 5.0%) 4 88 +ast-stats-2 GenericBound 224 ( 3.1%) 4 56 +ast-stats-2 - Trait 224 ( 3.1%) 4 +ast-stats-2 FieldDef 224 ( 3.1%) 2 112 +ast-stats-2 AssocItem 352 ( 4.9%) 4 88 ast-stats-2 - Type 176 ( 2.5%) 2 ast-stats-2 - Fn 176 ( 2.5%) 2 -ast-stats-2 GenericParam 480 ( 6.8%) 5 96 -ast-stats-2 Pat 504 ( 7.1%) 7 72 +ast-stats-2 GenericParam 480 ( 6.7%) 5 96 +ast-stats-2 Pat 504 ( 7.0%) 7 72 ast-stats-2 - Struct 72 ( 1.0%) 1 ast-stats-2 - Wild 72 ( 1.0%) 1 -ast-stats-2 - Ident 360 ( 5.1%) 5 +ast-stats-2 - Ident 360 ( 5.0%) 5 ast-stats-2 Expr 648 ( 9.1%) 9 72 ast-stats-2 - Path 72 ( 1.0%) 1 ast-stats-2 - Match 72 ( 1.0%) 1 @@ -98,22 +98,22 @@ ast-stats-2 - Struct 72 ( 1.0%) 1 ast-stats-2 - InlineAsm 72 ( 1.0%) 1 ast-stats-2 - Lit 144 ( 2.0%) 2 ast-stats-2 - Block 216 ( 3.0%) 3 -ast-stats-2 PathSegment 792 (11.2%) 33 24 -ast-stats-2 Ty 896 (12.6%) 14 64 +ast-stats-2 PathSegment 792 (11.1%) 33 24 +ast-stats-2 Ty 896 (12.5%) 14 64 ast-stats-2 - Ptr 64 ( 0.9%) 1 ast-stats-2 - Ref 64 ( 0.9%) 1 ast-stats-2 - ImplicitSelf 128 ( 1.8%) 2 -ast-stats-2 - Path 640 ( 9.0%) 10 -ast-stats-2 Item 1_496 (21.1%) 11 136 +ast-stats-2 - Path 640 ( 8.9%) 10 +ast-stats-2 Item 1_496 (20.9%) 11 136 ast-stats-2 - Trait 136 ( 1.9%) 1 ast-stats-2 - Enum 136 ( 1.9%) 1 ast-stats-2 - ExternCrate 136 ( 1.9%) 1 ast-stats-2 - ForeignMod 136 ( 1.9%) 1 ast-stats-2 - Impl 136 ( 1.9%) 1 ast-stats-2 - Fn 272 ( 3.8%) 2 -ast-stats-2 - Use 544 ( 7.7%) 4 +ast-stats-2 - Use 544 ( 7.6%) 4 ast-stats-2 ---------------------------------------------------------------- -ast-stats-2 Total 7_088 +ast-stats-2 Total 7_152 ast-stats-2 hir-stats HIR STATS hir-stats Name Accumulated Size Count Item Size From 7801c8fe7cab09a71bce74aac97ff4774595c189 Mon Sep 17 00:00:00 2001 From: Urgau Date: Thu, 25 May 2023 19:10:32 +0200 Subject: [PATCH 38/45] Increase root limit path for newly added restrictions tests --- compiler/rustc_parse/messages.ftl | 28 ++++++++++++------------ compiler/rustc_restrictions/messages.ftl | 9 ++++---- src/tools/tidy/src/ui_tests.rs | 3 +-- 3 files changed, 19 insertions(+), 21 deletions(-) diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index f163cb529be34..e26539614cbe8 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -309,6 +309,13 @@ parse_inclusive_range_no_end = inclusive range with no end parse_incorrect_braces_trait_bounds = incorrect braces around trait bounds .suggestion = remove the parentheses +parse_incorrect_restriction = incorrect {$noun} restriction + .help = some possible {$noun} restrictions are: + `{$keyword}(crate)`: {$adjective} only in the current crate + `{$keyword}(super)`: {$adjective} only in the current module's parent + `{$keyword}(in path::to::module)`: {$adjective} only in the specified path + .suggestion = make this {$adjective} only to module `{$path}` with `in` + parse_incorrect_semicolon = expected item, found `;` .suggestion = remove this semicolon @@ -519,20 +526,6 @@ parse_missing_comma_after_match_arm = expected `,` following `match` arm parse_missing_const_type = missing type for `{$kind}` item .suggestion = provide a type for the item -parse_incorrect_restriction = incorrect {$noun} restriction - .help = some possible {$noun} restrictions are: - `{$keyword}(crate)`: {$adjective} only in the current crate - `{$keyword}(super)`: {$adjective} only in the current module's parent - `{$keyword}(in path::to::module)`: {$adjective} only in the specified path - .suggestion = make this {$adjective} only to module `{$path}` with `in` - -parse_restriction_missing_path = incorrect {$noun} restriction - .help = some possible {$noun} restrictions are: - `{$keyword}(crate)`: {$adjective} only in the current crate - `{$keyword}(super)`: {$adjective} only in the current module's parent - `{$keyword}(in path::to::module)`: {$adjective} only in the specified path - .suggestion = make this {$adjective} only to the current crate - parse_missing_expression_in_for_loop = missing expression to iterate on in `for` loop .suggestion = try adding an expression to the `for` loop @@ -682,6 +675,13 @@ parse_require_colon_after_labeled_expression = labeled expression must be follow .label = the label .suggestion = add `:` after the label +parse_restriction_missing_path = incorrect {$noun} restriction + .help = some possible {$noun} restrictions are: + `{$keyword}(crate)`: {$adjective} only in the current crate + `{$keyword}(super)`: {$adjective} only in the current module's parent + `{$keyword}(in path::to::module)`: {$adjective} only in the specified path + .suggestion = make this {$adjective} only to the current crate + parse_return_types_use_thin_arrow = return types are denoted using `->` .suggestion = use `->` instead diff --git a/compiler/rustc_restrictions/messages.ftl b/compiler/rustc_restrictions/messages.ftl index 95eef84efb7e1..eb54df1cec093 100644 --- a/compiler/rustc_restrictions/messages.ftl +++ b/compiler/rustc_restrictions/messages.ftl @@ -1,3 +1,7 @@ +restrictions_construction_of_ty_with_mut_restricted_field = + `{$name}` cannot be constructed using {$article} {$description} expression outside `{$restriction_path}` + .note = {$article} {$description} containing fields with a mutability restriction cannot be constructed using {$article} {$description} expression + .label = mutability restricted here restrictions_impl_of_restricted_trait = trait cannot be implemented outside `{$restriction_path}` .label = trait restricted here @@ -5,8 +9,3 @@ restrictions_impl_of_restricted_trait = restrictions_mut_of_restricted_field = field cannot be mutated outside `{$restriction_path}` .label = mutability restricted here - -restrictions_construction_of_ty_with_mut_restricted_field = - `{$name}` cannot be constructed using {$article} {$description} expression outside `{$restriction_path}` - .note = {$article} {$description} containing fields with a mutability restriction cannot be constructed using {$article} {$description} expression - .label = mutability restricted here diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs index c3a639528413b..a8bf097751636 100644 --- a/src/tools/tidy/src/ui_tests.rs +++ b/src/tools/tidy/src/ui_tests.rs @@ -9,9 +9,8 @@ use std::fs; use std::path::{Path, PathBuf}; const ENTRY_LIMIT: usize = 900; -// FIXME: The following limits should be reduced eventually. const ISSUES_ENTRY_LIMIT: usize = 1894; -const ROOT_ENTRY_LIMIT: usize = 870; +const ROOT_ENTRY_LIMIT: usize = 871; const EXPECTED_TEST_FILE_EXTENSIONS: &[&str] = &[ "rs", // test source files From eea7a353dedf539e431984aa541e85abfef67b33 Mon Sep 17 00:00:00 2001 From: Jacob Pratt Date: Thu, 15 Jun 2023 00:12:53 -0400 Subject: [PATCH 39/45] Address review items --- compiler/rustc_ast/src/mut_visit.rs | 2 +- compiler/rustc_ast/src/visit.rs | 6 ++- compiler/rustc_resolve/src/lib.rs | 4 +- .../rustc_restrictions/src/mut_restriction.rs | 45 +++++++++---------- 4 files changed, 28 insertions(+), 29 deletions(-) diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index e77cdb3aea7b0..7f7c2a0bc6b77 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -1108,7 +1108,7 @@ pub fn noop_visit_item_kind(kind: &mut ItemKind, vis: &mut T) { bounds, items, }) => { - noop_visit_restriction(impl_restriction, vis); + vis.visit_restriction(impl_restriction); visit_unsafety(unsafety, vis); vis.visit_generics(generics); visit_bounds(bounds, vis); diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index 93e7896abfc7f..8136aea01f988 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -968,8 +968,10 @@ pub fn walk_restriction<'a, V: Visitor<'a>, Kind: crate::RestrictionKind>( visitor: &mut V, restriction: &'a Restriction, ) { - if let RestrictionLevel::Restricted { ref path, id, shorthand: _ } = restriction.level { - visitor.visit_path(path, id); + match restriction.level { + RestrictionLevel::Unrestricted => {} + RestrictionLevel::Restricted { ref path, id, shorthand: _ } => visitor.visit_path(path, id), + RestrictionLevel::Implied => {} } } diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index bdc9c17d8f403..b1634d03e7b0b 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -980,9 +980,9 @@ pub struct Resolver<'a, 'tcx> { /// Visibilities in "lowered" form, for all entities that have them. visibilities: FxHashMap, has_pub_restricted: bool, - // trait def -> restriction scope + /// trait def -> restriction scope impl_restrictions: FxHashMap, - // field def -> restriction scope + /// field def -> restriction scope mut_restrictions: FxHashMap, used_imports: FxHashSet, maybe_unused_trait_imports: FxIndexSet, diff --git a/compiler/rustc_restrictions/src/mut_restriction.rs b/compiler/rustc_restrictions/src/mut_restriction.rs index a0764aabefd3a..baa84aa2c229f 100644 --- a/compiler/rustc_restrictions/src/mut_restriction.rs +++ b/compiler/rustc_restrictions/src/mut_restriction.rs @@ -76,33 +76,30 @@ impl<'tcx> Visitor<'tcx> for MutRestrictionChecker<'_, 'tcx> { } fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, location: Location) { - if !context.is_mutating_use() { - self.super_place(place, context, location); - return; - } - - let body_did = self.body.source.instance.def_id(); + if context.is_mutating_use() { + let body_did = self.body.source.instance.def_id(); - for (place_base, elem) in place.iter_projections() { - match elem { - ProjectionElem::Field(field, _ty) => { - let field_ty = place_base.ty(self.body, self.tcx); - if !field_ty.ty.is_adt() { - continue; - } - let field_def = field_ty.field_def(field); - let field_mut_restriction = self.tcx.mut_restriction(field_def.did); - - if field_mut_restriction.is_restricted_in(body_did, self.tcx) { - self.tcx.sess.emit_err(errors::MutOfRestrictedField { - mut_span: self.span, - restriction_span: field_mut_restriction.expect_span(), - restriction_path: field_mut_restriction - .expect_restriction_path(self.tcx, body_did.krate), - }); + for (place_base, elem) in place.iter_projections() { + match elem { + ProjectionElem::Field(field, _ty) => { + let field_ty = place_base.ty(self.body, self.tcx); + if !field_ty.ty.is_adt() { + continue; + } + let field_def = field_ty.field_def(field); + let field_mut_restriction = self.tcx.mut_restriction(field_def.did); + + if field_mut_restriction.is_restricted_in(body_did, self.tcx) { + self.tcx.sess.emit_err(errors::MutOfRestrictedField { + mut_span: self.span, + restriction_span: field_mut_restriction.expect_span(), + restriction_path: field_mut_restriction + .expect_restriction_path(self.tcx, body_did.krate), + }); + } } + _ => {} } - _ => {} } } From 5370b54494969f330d0560e92d6cc92eb1ad7b1a Mon Sep 17 00:00:00 2001 From: Jacob Pratt Date: Thu, 15 Jun 2023 00:45:49 -0400 Subject: [PATCH 40/45] Fix build errors --- compiler/rustc_resolve/src/diagnostics.rs | 13 ++++++++++--- compiler/rustc_restrictions/src/mut_restriction.rs | 2 +- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index d753255a46331..39639b966bd7c 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -1019,9 +1019,16 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { RestrictionResolutionError::AncestorOnly(span) => { self.tcx.sess.create_err(errs::RestrictionAncestorOnly(span)) } - RestrictionResolutionError::FailedToResolve(span, label, suggestion) => { - self.into_struct_error(span, ResolutionError::FailedToResolve { label, suggestion }) - } + RestrictionResolutionError::FailedToResolve(span, label, suggestion) => self + .into_struct_error( + span, + ResolutionError::FailedToResolve { + last_segment: None, + label, + suggestion, + module: None, + }, + ), RestrictionResolutionError::ExpectedFound(span, path_str, res) => { self.tcx.sess.create_err(errs::ExpectedFound { span, res, path_str }) } diff --git a/compiler/rustc_restrictions/src/mut_restriction.rs b/compiler/rustc_restrictions/src/mut_restriction.rs index baa84aa2c229f..f2f0515adafc8 100644 --- a/compiler/rustc_restrictions/src/mut_restriction.rs +++ b/compiler/rustc_restrictions/src/mut_restriction.rs @@ -108,7 +108,7 @@ impl<'tcx> Visitor<'tcx> for MutRestrictionChecker<'_, 'tcx> { fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) { if let Rvalue::Aggregate(box AggregateKind::Adt(def_id, variant_idx, _, _, _), _) = rvalue { - let adt_def = self.tcx.type_of(def_id).0.ty_adt_def().unwrap(); + let adt_def = self.tcx.type_of(def_id).skip_binder().ty_adt_def().unwrap(); let variant = adt_def.variant(*variant_idx); let construction_restriction = self.tcx.adt_expression_restriction(variant.def_id); From fb12bf1c30701c407ca3858cbdb9ea3f6f17fa2d Mon Sep 17 00:00:00 2001 From: Jacob Pratt Date: Tue, 11 Jul 2023 03:58:35 -0400 Subject: [PATCH 41/45] Address some review items - Make diagnostics more translatable - Avoid ICE on potential future bug - Use `#![crate_type = lib]` --- compiler/rustc_ast/src/ast.rs | 12 ----- compiler/rustc_middle/src/ty/mod.rs | 15 +++--- compiler/rustc_parse/messages.ftl | 49 ++++++++++++------- compiler/rustc_parse/src/errors.rs | 11 +++-- compiler/rustc_parse/src/parser/item.rs | 3 +- compiler/rustc_parse/src/parser/mod.rs | 10 +--- .../src/impl_restriction.rs | 4 +- .../rustc_restrictions/src/mut_restriction.rs | 8 +-- tests/ui/restrictions/impl-feature-gate.rs | 2 +- tests/ui/restrictions/impl-restriction.rs | 2 +- tests/ui/restrictions/in-path-rustfix.fixed | 2 +- tests/ui/restrictions/in-path-rustfix.rs | 2 +- tests/ui/restrictions/mut-feature-gate.rs | 2 +- .../ui/restrictions/naked-impl-restriction.rs | 2 +- .../ui/restrictions/naked-mut-restriction.rs | 2 +- 15 files changed, 59 insertions(+), 67 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index fe36e9f217ebe..3a12b5341826d 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -2732,8 +2732,6 @@ pub mod restriction_kind { requires_explicit_path: $requires_explicit_path:ident, name: $name:ident, keyword: $keyword_sym:path => $keyword_str:literal, - adjective: $adjective:literal, - noun: $noun:literal, feature_gate: $feature_gate:expr $(,)? ) => { #[derive(Debug, Clone, Copy, Encodable, Decodable)] @@ -2743,8 +2741,6 @@ pub mod restriction_kind { const REQUIRES_EXPLICIT_PATH: bool = $requires_explicit_path; const KEYWORD_SYM: Symbol = $keyword_sym; const KEYWORD_STR: &'static str = $keyword_str; - const ADJECTIVE: &'static str = $adjective; - const NOUN: &'static str = $noun; const FEATURE_GATE: Option = $feature_gate; } @@ -2761,8 +2757,6 @@ pub mod restriction_kind { const REQUIRES_EXPLICIT_PATH: bool; const KEYWORD_SYM: Symbol; const KEYWORD_STR: &'static str; - const ADJECTIVE: &'static str; - const NOUN: &'static str; const FEATURE_GATE: Option; } @@ -2770,24 +2764,18 @@ pub mod restriction_kind { requires_explicit_path: false, name: Visibility, keyword: kw::Pub => "pub", - adjective: "visible", - noun: "visibility", feature_gate: None, } restriction! { requires_explicit_path: true, name: Impl, keyword: kw::Impl => "impl", - adjective: "implementable", - noun: "impl", feature_gate: Some(sym::impl_restriction), } restriction! { requires_explicit_path: true, name: Mut, keyword: kw::Mut => "mut", - adjective: "mutable", - noun: "mut", feature_gate: Some(sym::mut_restriction), } } diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 0b23162dbeee7..0235656edfbe8 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -312,21 +312,18 @@ impl + Copy> Restriction { !tcx.is_descendant_of(module, restricted_to.into()) } - /// Obtain the [`Span`] of the restriction. Panics if the restriction is unrestricted. - pub fn expect_span(&self) -> Span { + /// Obtain the [`Span`] of the restriction. If unrestricted, an empty span is returned. + pub fn span(&self) -> Span { match self { - Restriction::Unrestricted => bug!("called `expect_span` on an unrestricted item"), + Restriction::Unrestricted => rustc_span::DUMMY_SP, Restriction::Restricted(_, span) => *span, } } - pub fn expect_restriction_path( - &self, - tcx: TyCtxt<'_>, - krate: rustc_span::def_id::CrateNum, - ) -> String { + /// Obtain the path of the restriction. If unrestricted, an empty string is returned. + pub fn restriction_path(&self, tcx: TyCtxt<'_>, krate: rustc_span::def_id::CrateNum) -> String { let Restriction::Restricted(def_id, _) = self else { - bug!("called `expect_restricted_path` on an unrestricted item") + return String::new(); }; let def_id: DefId = (*def_id).into(); diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index e26539614cbe8..7e1d24817db20 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -286,6 +286,8 @@ parse_if_expression_missing_then_block = this `if` expression is missing a block .add_then_block = add a block here .condition_possibly_unfinished = this binary operation is possibly unfinished +parse_impl_restriction_on_trait_alias = trait aliases cannot be implemented + parse_in_in_typo = expected iterable, found keyword `in` .suggestion = remove the duplicated `in` @@ -309,12 +311,12 @@ parse_inclusive_range_no_end = inclusive range with no end parse_incorrect_braces_trait_bounds = incorrect braces around trait bounds .suggestion = remove the parentheses -parse_incorrect_restriction = incorrect {$noun} restriction - .help = some possible {$noun} restrictions are: - `{$keyword}(crate)`: {$adjective} only in the current crate - `{$keyword}(super)`: {$adjective} only in the current module's parent - `{$keyword}(in path::to::module)`: {$adjective} only in the specified path - .suggestion = make this {$adjective} only to module `{$path}` with `in` +parse_incorrect_restriction = incorrect {parse_restriction_noun} restriction + .help = some possible {parse_restriction_noun} restrictions are: + `{$keyword}(crate)`: {parse_restriction_adjective} only in the current crate + `{$keyword}(super)`: {parse_restriction_adjective} only in the current module's parent + `{$keyword}(in path::to::module)`: {parse_restriction_adjective} only in the specified path + .suggestion = make this {parse_restriction_adjective} only to module `{$path}` with `in` parse_incorrect_semicolon = expected item, found `;` @@ -326,13 +328,6 @@ parse_incorrect_use_of_await = .parentheses_suggestion = `await` is not a method call, remove the parentheses .postfix_suggestion = `await` is a postfix operation -parse_incorrect_visibility_restriction = incorrect visibility restriction - .help = some possible visibility restrictions are: - `pub(crate)`: visible only on the current crate - `pub(super)`: visible only in the current module's parent - `pub(in path::to::module)`: visible only on the specified path - .suggestion = make this visible only to module `{$inner_str}` with `in` - parse_inner_attr_explanation = inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files parse_inner_attr_not_permitted = an inner attribute is not permitted in this context .label_does_not_annotate_this = {parse_label_inner_attr_does_not_annotate_this} @@ -675,12 +670,28 @@ parse_require_colon_after_labeled_expression = labeled expression must be follow .label = the label .suggestion = add `:` after the label -parse_restriction_missing_path = incorrect {$noun} restriction - .help = some possible {$noun} restrictions are: - `{$keyword}(crate)`: {$adjective} only in the current crate - `{$keyword}(super)`: {$adjective} only in the current module's parent - `{$keyword}(in path::to::module)`: {$adjective} only in the specified path - .suggestion = make this {$adjective} only to the current crate +# internal use only +parse_restriction_adjective = { $keyword -> + [impl] implementable + [mut] mutable + [pub] visible + *[DEFAULT_IS_BUG] BUG +} + +parse_restriction_missing_path = incorrect {parse_restriction_noun} restriction + .help = some possible {parse_restriction_noun} restrictions are: + `{$keyword}(crate)`: {parse_restriction_adjective} only in the current crate + `{$keyword}(super)`: {parse_restriction_adjective} only in the current module's parent + `{$keyword}(in path::to::module)`: {parse_restriction_adjective} only in the specified path + .suggestion = make this {parse_restriction_adjective} only to the current crate + +# internal use only +parse_restriction_noun = { $keyword -> + [impl] impl + [mut] mut + [pub] visibility + *[DEFAULT_IS_BUG] BUG +} parse_return_types_use_thin_arrow = return types are denoted using `->` .suggestion = use `->` instead diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 342ab971be1db..70743cb1ad37b 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -819,8 +819,6 @@ pub(crate) struct IncorrectRestriction { #[suggestion(code = "in {path}", applicability = "machine-applicable")] pub span: Span, pub path: String, - pub noun: &'static str, - pub adjective: &'static str, pub keyword: &'static str, } @@ -831,11 +829,16 @@ pub(crate) struct RestrictionMissingPath { #[primary_span] #[suggestion(code = "{keyword}(crate)", applicability = "maybe-incorrect")] pub span: Span, - pub noun: &'static str, - pub adjective: &'static str, pub keyword: &'static str, } +#[derive(Diagnostic)] +#[diag(parse_impl_restriction_on_trait_alias)] +pub(crate) struct ImplRestrictionOnTraitAlias { + #[primary_span] + pub span: Span, +} + #[derive(Diagnostic)] #[diag(parse_assignment_else_not_allowed)] pub(crate) struct AssignmentElseNotAllowed { diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 2e5b0c029f910..2623bc3df0fd9 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -859,8 +859,7 @@ impl<'a> Parser<'a> { let whole_span = lo.to(self.prev_token.span); if !matches!(impl_restriction.level, RestrictionLevel::Implied) { - let msg = "trait aliases cannot be implemented"; - self.struct_span_err(whole_span, msg).span_label(whole_span, msg).emit(); + self.sess.emit_err(errors::ImplRestrictionOnTraitAlias { span: whole_span }); } if is_auto == IsAuto::Yes { self.sess.emit_err(errors::TraitAliasCannotBeAuto { span: whole_span }); diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index f22ae09ecbe05..51e60fe0e34c2 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -1444,12 +1444,8 @@ impl<'a> Parser<'a> { } } else { if Kind::REQUIRES_EXPLICIT_PATH { - self.sess.emit_err(RestrictionMissingPath { - span: kw_span, - noun: Kind::NOUN, - adjective: Kind::ADJECTIVE, - keyword: Kind::KEYWORD_STR, - }); + self.sess + .emit_err(RestrictionMissingPath { span: kw_span, keyword: Kind::KEYWORD_STR }); } Ok(Restriction::unrestricted().with_span(gate(kw_span))) } @@ -1464,8 +1460,6 @@ impl<'a> Parser<'a> { self.sess.emit_err(IncorrectRestriction { span: path.span, path: pprust::path_to_string(&path), - adjective: Kind::ADJECTIVE, - noun: Kind::NOUN, keyword: Kind::KEYWORD_STR, }); diff --git a/compiler/rustc_restrictions/src/impl_restriction.rs b/compiler/rustc_restrictions/src/impl_restriction.rs index 2a13790c5076f..9be057a7a63a8 100644 --- a/compiler/rustc_restrictions/src/impl_restriction.rs +++ b/compiler/rustc_restrictions/src/impl_restriction.rs @@ -30,9 +30,9 @@ impl<'v> Visitor<'v> for ImplOfRestrictedTraitVisitor<'v> { if restriction.is_restricted_in(item.owner_id.to_def_id(), self.tcx) { let impl_span = self.tcx.span_of_impl(item.owner_id.to_def_id()).expect("impl should be local"); - let restriction_span = restriction.expect_span(); + let restriction_span = restriction.span(); let restriction_path = - restriction.expect_restriction_path(self.tcx, hir::def_id::LOCAL_CRATE); + restriction.restriction_path(self.tcx, hir::def_id::LOCAL_CRATE); let diag = errors::ImplOfRestrictedTrait { impl_span, restriction_span, restriction_path }; self.tcx.sess.emit_err(diag); diff --git a/compiler/rustc_restrictions/src/mut_restriction.rs b/compiler/rustc_restrictions/src/mut_restriction.rs index f2f0515adafc8..72f2c9397c8a0 100644 --- a/compiler/rustc_restrictions/src/mut_restriction.rs +++ b/compiler/rustc_restrictions/src/mut_restriction.rs @@ -92,9 +92,9 @@ impl<'tcx> Visitor<'tcx> for MutRestrictionChecker<'_, 'tcx> { if field_mut_restriction.is_restricted_in(body_did, self.tcx) { self.tcx.sess.emit_err(errors::MutOfRestrictedField { mut_span: self.span, - restriction_span: field_mut_restriction.expect_span(), + restriction_span: field_mut_restriction.span(), restriction_path: field_mut_restriction - .expect_restriction_path(self.tcx, body_did.krate), + .restriction_path(self.tcx, body_did.krate), }); } } @@ -117,9 +117,9 @@ impl<'tcx> Visitor<'tcx> for MutRestrictionChecker<'_, 'tcx> { if construction_restriction.is_restricted_in(body_did, self.tcx) { self.tcx.sess.emit_err(errors::ConstructionOfTyWithMutRestrictedField { construction_span: self.span, - restriction_span: construction_restriction.expect_span(), + restriction_span: construction_restriction.span(), restriction_path: construction_restriction - .expect_restriction_path(self.tcx, body_did.krate), + .restriction_path(self.tcx, body_did.krate), note: (), article: "a", description: adt_def.variant_descr(), diff --git a/tests/ui/restrictions/impl-feature-gate.rs b/tests/ui/restrictions/impl-feature-gate.rs index d31ecff60e23e..439d754b7d41e 100644 --- a/tests/ui/restrictions/impl-feature-gate.rs +++ b/tests/ui/restrictions/impl-feature-gate.rs @@ -1,8 +1,8 @@ // gate-test-impl_restriction -// compile-flags: --crate-type=lib // revisions: with_gate without_gate //[with_gate] check-pass +#![crate_type = "lib"] #![cfg_attr(with_gate, feature(impl_restriction))] pub impl(crate) trait Bar {} //[without_gate]~ ERROR diff --git a/tests/ui/restrictions/impl-restriction.rs b/tests/ui/restrictions/impl-restriction.rs index 7f4fc496cbd6a..391dcf627d87d 100644 --- a/tests/ui/restrictions/impl-restriction.rs +++ b/tests/ui/restrictions/impl-restriction.rs @@ -1,6 +1,6 @@ -// compile-flags: --crate-type=lib // aux-build: external-impl-restriction.rs +#![crate_type = "lib"] #![feature(impl_restriction)] extern crate external_impl_restriction as external; diff --git a/tests/ui/restrictions/in-path-rustfix.fixed b/tests/ui/restrictions/in-path-rustfix.fixed index c5c0b4845bb90..7a664376c107f 100644 --- a/tests/ui/restrictions/in-path-rustfix.fixed +++ b/tests/ui/restrictions/in-path-rustfix.fixed @@ -1,6 +1,6 @@ // run-rustfix -// compile-flags: --crate-type=lib +#![crate_type = "lib"] #![feature(mut_restriction)] pub mod a { diff --git a/tests/ui/restrictions/in-path-rustfix.rs b/tests/ui/restrictions/in-path-rustfix.rs index c4ed040987e10..3f127e371e529 100644 --- a/tests/ui/restrictions/in-path-rustfix.rs +++ b/tests/ui/restrictions/in-path-rustfix.rs @@ -1,6 +1,6 @@ // run-rustfix -// compile-flags: --crate-type=lib +#![crate_type = "lib"] #![feature(mut_restriction)] pub mod a { diff --git a/tests/ui/restrictions/mut-feature-gate.rs b/tests/ui/restrictions/mut-feature-gate.rs index f5f654879df3f..5ec3b39ea6b29 100644 --- a/tests/ui/restrictions/mut-feature-gate.rs +++ b/tests/ui/restrictions/mut-feature-gate.rs @@ -1,8 +1,8 @@ // gate-test-mut_restriction -// compile-flags: --crate-type=lib // revisions: with_gate without_gate //[with_gate] check-pass +#![crate_type = "lib"] #![cfg_attr(with_gate, feature(mut_restriction))] pub struct Foo { diff --git a/tests/ui/restrictions/naked-impl-restriction.rs b/tests/ui/restrictions/naked-impl-restriction.rs index ab0b1f52f4f52..a29913389a95b 100644 --- a/tests/ui/restrictions/naked-impl-restriction.rs +++ b/tests/ui/restrictions/naked-impl-restriction.rs @@ -1,4 +1,4 @@ -// compile-flags: --crate-type=lib +#![crate_type = "lib"] #![feature(impl_restriction)] pub impl trait Foo {} //~ ERROR incorrect impl restriction diff --git a/tests/ui/restrictions/naked-mut-restriction.rs b/tests/ui/restrictions/naked-mut-restriction.rs index f92a7761b746f..200fd0380cffe 100644 --- a/tests/ui/restrictions/naked-mut-restriction.rs +++ b/tests/ui/restrictions/naked-mut-restriction.rs @@ -1,4 +1,4 @@ -// compile-flags: --crate-type=lib +#![crate_type = "lib"] #![feature(mut_restriction)] pub struct Foo { From 731bbd80024a050ce266e70e5702db97d6dbfe3c Mon Sep 17 00:00:00 2001 From: Jacob Pratt Date: Tue, 11 Jul 2023 04:06:54 -0400 Subject: [PATCH 42/45] Invert `Restriction::is_restricted_in` --- compiler/rustc_middle/src/ty/mod.rs | 10 +++++----- compiler/rustc_restrictions/src/impl_restriction.rs | 2 +- compiler/rustc_restrictions/src/mut_restriction.rs | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 0235656edfbe8..c2d2d0dbf5609 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -301,15 +301,15 @@ pub enum Restriction { } impl + Copy> Restriction { - /// Returns `true` if this restriction applies in the given module. This - /// means the behavior is _not_ allowed. - pub fn is_restricted_in(self, module: DefId, tcx: TyCtxt<'_>) -> bool { + /// Returns `true` if the behavior is allowed/unrestricted in the given module. A value of + /// `false` indicates that the behavior is prohibited. + pub fn is_allowed_in(self, module: DefId, tcx: TyCtxt<'_>) -> bool { let restricted_to = match self { - Restriction::Unrestricted => return false, + Restriction::Unrestricted => return true, Restriction::Restricted(module, _) => module, }; - !tcx.is_descendant_of(module, restricted_to.into()) + tcx.is_descendant_of(module, restricted_to.into()) } /// Obtain the [`Span`] of the restriction. If unrestricted, an empty span is returned. diff --git a/compiler/rustc_restrictions/src/impl_restriction.rs b/compiler/rustc_restrictions/src/impl_restriction.rs index 9be057a7a63a8..b887b56ad1f93 100644 --- a/compiler/rustc_restrictions/src/impl_restriction.rs +++ b/compiler/rustc_restrictions/src/impl_restriction.rs @@ -27,7 +27,7 @@ impl<'v> Visitor<'v> for ImplOfRestrictedTraitVisitor<'v> { let restriction = self.tcx.impl_restriction(trait_def_id); - if restriction.is_restricted_in(item.owner_id.to_def_id(), self.tcx) { + if !restriction.is_allowed_in(item.owner_id.to_def_id(), self.tcx) { let impl_span = self.tcx.span_of_impl(item.owner_id.to_def_id()).expect("impl should be local"); let restriction_span = restriction.span(); diff --git a/compiler/rustc_restrictions/src/mut_restriction.rs b/compiler/rustc_restrictions/src/mut_restriction.rs index 72f2c9397c8a0..8579f9f9e60b7 100644 --- a/compiler/rustc_restrictions/src/mut_restriction.rs +++ b/compiler/rustc_restrictions/src/mut_restriction.rs @@ -89,7 +89,7 @@ impl<'tcx> Visitor<'tcx> for MutRestrictionChecker<'_, 'tcx> { let field_def = field_ty.field_def(field); let field_mut_restriction = self.tcx.mut_restriction(field_def.did); - if field_mut_restriction.is_restricted_in(body_did, self.tcx) { + if !field_mut_restriction.is_allowed_in(body_did, self.tcx) { self.tcx.sess.emit_err(errors::MutOfRestrictedField { mut_span: self.span, restriction_span: field_mut_restriction.span(), @@ -114,7 +114,7 @@ impl<'tcx> Visitor<'tcx> for MutRestrictionChecker<'_, 'tcx> { let construction_restriction = self.tcx.adt_expression_restriction(variant.def_id); let body_did = self.body.source.instance.def_id(); - if construction_restriction.is_restricted_in(body_did, self.tcx) { + if !construction_restriction.is_allowed_in(body_did, self.tcx) { self.tcx.sess.emit_err(errors::ConstructionOfTyWithMutRestrictedField { construction_span: self.span, restriction_span: construction_restriction.span(), From f4a661f273b1714ff192d4b3b605a73bbdf6902d Mon Sep 17 00:00:00 2001 From: Jacob Pratt Date: Tue, 11 Jul 2023 04:16:56 -0400 Subject: [PATCH 43/45] Add type aliases for each restriction --- compiler/rustc_ast/src/ast.rs | 12 ++++++++---- compiler/rustc_parse/src/parser/item.rs | 4 ++-- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 3a12b5341826d..480092d36e368 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -2800,8 +2800,12 @@ pub enum RestrictionLevel { Implied, } -impl From> for Visibility { - fn from(restriction: Restriction) -> Self { +pub type VisibilityRestriction = Restriction; +pub type ImplRestriction = Restriction; +pub type MutRestriction = Restriction; + +impl From for Visibility { + fn from(restriction: VisibilityRestriction) -> Self { match restriction.level { RestrictionLevel::Unrestricted => Self { kind: VisibilityKind::Public, @@ -2863,7 +2867,7 @@ pub struct FieldDef { pub id: NodeId, pub span: Span, pub vis: Visibility, - pub mut_restriction: Restriction, + pub mut_restriction: MutRestriction, pub ident: Option, pub ty: P, @@ -3003,7 +3007,7 @@ impl Default for FnHeader { #[derive(Clone, Encodable, Decodable, Debug)] pub struct Trait { - pub impl_restriction: Restriction, + pub impl_restriction: ImplRestriction, pub unsafety: Unsafe, pub is_auto: IsAuto, pub generics: Generics, diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 2623bc3df0fd9..d321bbaa75d36 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -1646,7 +1646,7 @@ impl<'a> Parser<'a> { adt_ty: &str, lo: Span, vis: Visibility, - mut_restriction: Restriction, + mut_restriction: MutRestriction, attrs: AttrVec, ) -> PResult<'a, FieldDef> { let mut seen_comma: bool = false; @@ -1786,7 +1786,7 @@ impl<'a> Parser<'a> { adt_ty: &str, lo: Span, vis: Visibility, - mut_restriction: Restriction, + mut_restriction: MutRestriction, attrs: AttrVec, ) -> PResult<'a, FieldDef> { let name = self.parse_field_ident(adt_ty, lo)?; From c4c73cd4b50c8ce557dbe945064c0a5f65f30ff0 Mon Sep 17 00:00:00 2001 From: Jacob Pratt Date: Wed, 12 Jul 2023 03:40:22 -0400 Subject: [PATCH 44/45] Enforce using correct restriction in rustc_middle --- compiler/rustc_ast/src/ast.rs | 52 +++++++++++-------- compiler/rustc_ast/src/lib.rs | 1 + compiler/rustc_metadata/src/rmeta/mod.rs | 4 +- compiler/rustc_middle/src/query/erase.rs | 5 +- compiler/rustc_middle/src/query/mod.rs | 6 +-- compiler/rustc_middle/src/ty/mod.rs | 18 +++++-- compiler/rustc_middle/src/ty/parameterized.rs | 5 +- .../rustc_resolve/src/build_reduced_graph.rs | 23 +++++--- compiler/rustc_resolve/src/lib.rs | 5 +- .../src/impl_restriction.rs | 5 +- .../rustc_restrictions/src/mut_restriction.rs | 6 +-- 11 files changed, 83 insertions(+), 47 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 480092d36e368..f83ee8d007a29 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -2727,13 +2727,13 @@ pub mod restriction_kind { /// Helper macro to generate the type, derive the relevant bounds, and implement the sealed /// trait. - macro_rules! restriction { - ( + macro_rules! define_restrictions { + ($(Restriction { requires_explicit_path: $requires_explicit_path:ident, name: $name:ident, keyword: $keyword_sym:path => $keyword_str:literal, feature_gate: $feature_gate:expr $(,)? - ) => { + }),* $(,)?) => {$( #[derive(Debug, Clone, Copy, Encodable, Decodable)] pub enum $name {} @@ -2742,10 +2742,12 @@ pub mod restriction_kind { const KEYWORD_SYM: Symbol = $keyword_sym; const KEYWORD_STR: &'static str = $keyword_str; const FEATURE_GATE: Option = $feature_gate; + + const MIDDLE_KIND: u8 = ${index()}; } impl sealed::Sealed for $name {} - }; + )*}; } // FIXME(jhpratt) After a bootstrap, replace this with the now-implemented native syntax. @@ -2758,26 +2760,30 @@ pub mod restriction_kind { const KEYWORD_SYM: Symbol; const KEYWORD_STR: &'static str; const FEATURE_GATE: Option; - } - restriction! { - requires_explicit_path: false, - name: Visibility, - keyword: kw::Pub => "pub", - feature_gate: None, - } - restriction! { - requires_explicit_path: true, - name: Impl, - keyword: kw::Impl => "impl", - feature_gate: Some(sym::impl_restriction), - } - restriction! { - requires_explicit_path: true, - name: Mut, - keyword: kw::Mut => "mut", - feature_gate: Some(sym::mut_restriction), - } + const MIDDLE_KIND: u8; + } + + define_restrictions![ + Restriction { + requires_explicit_path: false, + name: Visibility, + keyword: kw::Pub => "pub", + feature_gate: None, + }, + Restriction { + requires_explicit_path: true, + name: Impl, + keyword: kw::Impl => "impl", + feature_gate: Some(sym::impl_restriction), + }, + Restriction { + requires_explicit_path: true, + name: Mut, + keyword: kw::Mut => "mut", + feature_gate: Some(sym::mut_restriction), + }, + ]; } pub use restriction_kind::RestrictionKind; diff --git a/compiler/rustc_ast/src/lib.rs b/compiler/rustc_ast/src/lib.rs index b07ed1d1c741e..40a03d3e1c1fb 100644 --- a/compiler/rustc_ast/src/lib.rs +++ b/compiler/rustc_ast/src/lib.rs @@ -13,6 +13,7 @@ #![feature(const_trait_impl)] #![feature(if_let_guard)] #![feature(let_chains)] +#![feature(macro_metavar_expr)] #![feature(min_specialization)] #![feature(negative_impls)] #![feature(stmt_expr_attributes)] diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index 1fe04469bc603..e9b35deb45f76 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -395,8 +395,8 @@ define_tables! { associated_item_or_field_def_ids: Table>, opt_def_kind: Table, visibility: Table>>, - impl_restriction: Table>, - mut_restriction: Table>, + impl_restriction: Table>, + mut_restriction: Table>, def_span: Table>, def_ident_span: Table>, lookup_stability: Table>, diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs index 604639b3e786c..88bb1ab0639bb 100644 --- a/compiler/rustc_middle/src/query/erase.rs +++ b/compiler/rustc_middle/src/query/erase.rs @@ -270,11 +270,14 @@ trivial! { rustc_middle::ty::fast_reject::SimplifiedType, rustc_middle::ty::ImplPolarity, rustc_middle::ty::Representability, - rustc_middle::ty::Restriction, rustc_middle::ty::ReprOptions, rustc_middle::ty::UnusedGenericParams, rustc_middle::ty::util::AlwaysRequiresDrop, rustc_middle::ty::Visibility, + // FIXME(jhpratt) replace with a generic impl over ty::RestrictionKind when + // #![feature(generic_const_exprs)] is no longer incomplete. + rustc_middle::ty::ImplRestriction, + rustc_middle::ty::MutRestriction, rustc_session::config::CrateType, rustc_session::config::EntryFnType, rustc_session::config::OptLevel, diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index d51c9ae05375b..fe1bea4f1edd2 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1695,7 +1695,7 @@ rustc_queries! { feedable } - query impl_restriction(def_id: DefId) -> ty::Restriction { + query impl_restriction(def_id: DefId) -> ty::ImplRestriction { desc { |tcx| "computing impl restriction for `{}`", tcx.def_path_str(def_id) } separate_provide_extern } @@ -1713,7 +1713,7 @@ rustc_queries! { desc { "computing the uninhabited predicate of `{}`", key } } - query mut_restriction(def_id: DefId) -> ty::Restriction { + query mut_restriction(def_id: DefId) -> ty::MutRestriction { desc { |tcx| "computing mut restriction for `{}`", tcx.def_path_str(def_id) } separate_provide_extern } @@ -1722,7 +1722,7 @@ rustc_queries! { desc { "checking mut restrictions" } } - query adt_expression_restriction(variant_def_id: DefId) -> ty::Restriction { + query adt_expression_restriction(variant_def_id: DefId) -> ty::MutRestriction { desc { "computing where `{}` can be constructed via an ADT expression", tcx.def_path_str(variant_def_id) diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index c2d2d0dbf5609..e83c1540b2331 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -162,8 +162,8 @@ pub struct ResolverOutputs { #[derive(Debug)] pub struct ResolverGlobalCtxt { pub visibilities: FxHashMap, - pub impl_restrictions: FxHashMap, - pub mut_restrictions: FxHashMap, + pub impl_restrictions: FxHashMap, + pub mut_restrictions: FxHashMap, /// This field is used to decide whether we should make `PRIVATE_IN_PUBLIC` a hard error. pub has_pub_restricted: bool, /// Item with a given `LocalDefId` was defined during macro expansion with ID `ExpnId`. @@ -292,15 +292,23 @@ pub enum Visibility { Restricted(Id), } +// FIXME(jhpratt) Once #![feature(adt_const_params)] is no longer incomplete, replace this with an +// enum of the various kinds of restrictions. +pub type RestrictionKind = u8; +pub type MutRestriction = + Restriction<{ ::MIDDLE_KIND }>; +pub type ImplRestriction = + Restriction<{ ::MIDDLE_KIND }>; + #[derive(Clone, Debug, PartialEq, Eq, Copy, Hash, Encodable, Decodable, HashStable)] -pub enum Restriction { +pub enum Restriction { /// The restriction does not affect the item. Unrestricted, /// The restriction only applies outside of this path. Restricted(Id, Span), } -impl + Copy> Restriction { +impl + Copy> Restriction { /// Returns `true` if the behavior is allowed/unrestricted in the given module. A value of /// `false` indicates that the behavior is prohibited. pub fn is_allowed_in(self, module: DefId, tcx: TyCtxt<'_>) -> bool { @@ -361,7 +369,7 @@ impl + Copy> Restriction { iter.fold(Restriction::Unrestricted, |left, right| Self::stricter_of(left, right, tcx)) } - pub fn map_id(self, f: impl FnOnce(Id) -> OutId) -> Restriction { + pub fn map_id(self, f: impl FnOnce(Id) -> OutId) -> Restriction { match self { Restriction::Unrestricted => Restriction::Unrestricted, Restriction::Restricted(id, span) => Restriction::Restricted(f(id), span), diff --git a/compiler/rustc_middle/src/ty/parameterized.rs b/compiler/rustc_middle/src/ty/parameterized.rs index 431c8bc1a8892..1214844087965 100644 --- a/compiler/rustc_middle/src/ty/parameterized.rs +++ b/compiler/rustc_middle/src/ty/parameterized.rs @@ -69,7 +69,6 @@ trivially_parameterized_over_tcx! { ty::TraitDef, ty::UnusedGenericParams, ty::Visibility, - ty::Restriction, ty::adjustment::CoerceUnsizedInfo, ty::fast_reject::SimplifiedType, rustc_ast::Attribute, @@ -106,6 +105,10 @@ trivially_parameterized_over_tcx! { rustc_type_ir::Variance, } +impl ty::ParameterizedOverTcx for ty::Restriction { + type Value<'tcx> = Self; +} + // HACK(compiler-errors): This macro rule can only take a fake path, // not a real, due to parsing ambiguity reasons. #[macro_export] diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 36c39cae13ef3..ae8916d1347ff 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -325,21 +325,32 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { self.r.field_def_ids.insert(def_id, self.r.tcx.arena.alloc_from_iter(def_ids)); } - fn resolve_restriction( + fn resolve_restriction< + AstKind: ast::RestrictionKind, + const MIDDLE_KIND: ty::RestrictionKind, + >( &mut self, - restriction: &ast::Restriction, - ) -> ty::Restriction { + restriction: &ast::Restriction, + ) -> ty::Restriction<{ MIDDLE_KIND }> { + const { assert!(AstKind::MIDDLE_KIND == MIDDLE_KIND) }; + self.try_resolve_restriction(restriction, true).unwrap_or_else(|err| { self.r.report_restriction_error(err); ty::Restriction::Unrestricted }) } - fn try_resolve_restriction<'ast, Kind: ast::RestrictionKind>( + fn try_resolve_restriction< + 'ast, + AstKind: ast::RestrictionKind, + const MIDDLE_KIND: ty::RestrictionKind, + >( &mut self, - restriction: &'ast ast::Restriction, + restriction: &'ast ast::Restriction, finalize: bool, - ) -> Result> { + ) -> Result, RestrictionResolutionError<'ast>> { + const { assert!(AstKind::MIDDLE_KIND == MIDDLE_KIND) }; + let parent_scope = &self.parent_scope; match restriction.level { ast::RestrictionLevel::Unrestricted => Ok(ty::Restriction::Unrestricted), diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index b1634d03e7b0b..d02627fb2fa09 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -11,6 +11,7 @@ #![feature(box_patterns)] #![feature(extract_if)] #![feature(if_let_guard)] +#![feature(inline_const)] #![feature(iter_intersperse)] #![feature(let_chains)] #![feature(never_type)] @@ -981,9 +982,9 @@ pub struct Resolver<'a, 'tcx> { visibilities: FxHashMap, has_pub_restricted: bool, /// trait def -> restriction scope - impl_restrictions: FxHashMap, + impl_restrictions: FxHashMap, /// field def -> restriction scope - mut_restrictions: FxHashMap, + mut_restrictions: FxHashMap, used_imports: FxHashSet, maybe_unused_trait_imports: FxIndexSet, diff --git a/compiler/rustc_restrictions/src/impl_restriction.rs b/compiler/rustc_restrictions/src/impl_restriction.rs index b887b56ad1f93..a2a5934211e96 100644 --- a/compiler/rustc_restrictions/src/impl_restriction.rs +++ b/compiler/rustc_restrictions/src/impl_restriction.rs @@ -43,7 +43,10 @@ impl<'v> Visitor<'v> for ImplOfRestrictedTraitVisitor<'v> { } } -fn impl_restriction(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Restriction { +fn impl_restriction( + tcx: TyCtxt<'_>, + def_id: LocalDefId, +) -> ty::ImplRestriction { match tcx.resolutions(()).impl_restrictions.get(&def_id.to_def_id()) { Some(restriction) => *restriction, None => bug!("impl restriction not found for {def_id:?}"), diff --git a/compiler/rustc_restrictions/src/mut_restriction.rs b/compiler/rustc_restrictions/src/mut_restriction.rs index 8579f9f9e60b7..14681e1b4b45e 100644 --- a/compiler/rustc_restrictions/src/mut_restriction.rs +++ b/compiler/rustc_restrictions/src/mut_restriction.rs @@ -6,7 +6,7 @@ use rustc_middle::mir::{AggregateKind, Rvalue}; use rustc_middle::mir::{Body, Location, Place, ProjectionElem, Statement, Terminator}; use rustc_middle::query::Providers; use rustc_middle::span_bug; -use rustc_middle::ty::{Restriction, TyCtxt}; +use rustc_middle::ty::{MutRestriction, Restriction, TyCtxt}; use rustc_span::Span; use crate::errors; @@ -20,7 +20,7 @@ pub(crate) fn provide(providers: &mut Providers) { }; } -fn mut_restriction(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Restriction { +fn mut_restriction(tcx: TyCtxt<'_>, def_id: LocalDefId) -> MutRestriction { tracing::debug!("mut_restriction({def_id:?})"); match tcx.resolutions(()).mut_restrictions.get(&def_id.to_def_id()) { @@ -48,7 +48,7 @@ fn check_mut_restriction(tcx: TyCtxt<'_>, def_id: LocalDefId) { /// restricted. // This is a query to allow the compiler to cache the output. This avoids the need to recompute the // same information for every ADT expression. -fn adt_expression_restriction(tcx: TyCtxt<'_>, variant_def_id: DefId) -> Restriction { +fn adt_expression_restriction(tcx: TyCtxt<'_>, variant_def_id: DefId) -> MutRestriction { let res = Res::Def(tcx.def_kind(variant_def_id), variant_def_id); let variant = tcx.expect_variant_res(res); From 076a838cb097b68ffb8060c72c1e15eba76d0771 Mon Sep 17 00:00:00 2001 From: Jacob Pratt Date: Wed, 12 Jul 2023 04:05:49 -0400 Subject: [PATCH 45/45] Use `LocalDefId` instead of `DefId` --- compiler/rustc_middle/src/ty/mod.rs | 4 ++-- compiler/rustc_resolve/src/build_reduced_graph.rs | 4 ++-- compiler/rustc_resolve/src/lib.rs | 4 ++-- compiler/rustc_restrictions/src/impl_restriction.rs | 7 ++----- compiler/rustc_restrictions/src/mut_restriction.rs | 2 +- 5 files changed, 9 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index e83c1540b2331..1bbaf0810091b 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -162,8 +162,8 @@ pub struct ResolverOutputs { #[derive(Debug)] pub struct ResolverGlobalCtxt { pub visibilities: FxHashMap, - pub impl_restrictions: FxHashMap, - pub mut_restrictions: FxHashMap, + pub impl_restrictions: FxHashMap, + pub mut_restrictions: FxHashMap, /// This field is used to decide whether we should make `PRIVATE_IN_PUBLIC` a hard error. pub has_pub_restricted: bool, /// Item with a given `LocalDefId` was defined during macro expansion with ID `ExpnId`. diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index ae8916d1347ff..45fc23828cd5a 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -887,7 +887,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { ItemKind::Trait(ref trait_def) => { let impl_restriction = self.resolve_restriction(&trait_def.impl_restriction); - self.r.impl_restrictions.insert(def_id, impl_restriction); + self.r.impl_restrictions.insert(local_def_id, impl_restriction); // Add all the items within to a new module. let module = self.r.new_module( @@ -1562,7 +1562,7 @@ impl<'a, 'b, 'tcx> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b, 'tcx> { let vis = self.resolve_visibility(&sf.vis); self.r.visibilities.insert(self.r.local_def_id(sf.id), vis); let mut_restriction = self.resolve_restriction(&sf.mut_restriction); - self.r.mut_restrictions.insert(self.r.local_def_id(sf.id).to_def_id(), mut_restriction); + self.r.mut_restrictions.insert(self.r.local_def_id(sf.id), mut_restriction); visit::walk_field_def(self, sf); } } diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index d02627fb2fa09..8865ca5e1cd12 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -982,9 +982,9 @@ pub struct Resolver<'a, 'tcx> { visibilities: FxHashMap, has_pub_restricted: bool, /// trait def -> restriction scope - impl_restrictions: FxHashMap, + impl_restrictions: FxHashMap, /// field def -> restriction scope - mut_restrictions: FxHashMap, + mut_restrictions: FxHashMap, used_imports: FxHashSet, maybe_unused_trait_imports: FxIndexSet, diff --git a/compiler/rustc_restrictions/src/impl_restriction.rs b/compiler/rustc_restrictions/src/impl_restriction.rs index a2a5934211e96..7bd4bf3502f6f 100644 --- a/compiler/rustc_restrictions/src/impl_restriction.rs +++ b/compiler/rustc_restrictions/src/impl_restriction.rs @@ -43,11 +43,8 @@ impl<'v> Visitor<'v> for ImplOfRestrictedTraitVisitor<'v> { } } -fn impl_restriction( - tcx: TyCtxt<'_>, - def_id: LocalDefId, -) -> ty::ImplRestriction { - match tcx.resolutions(()).impl_restrictions.get(&def_id.to_def_id()) { +fn impl_restriction(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::ImplRestriction { + match tcx.resolutions(()).impl_restrictions.get(&def_id) { Some(restriction) => *restriction, None => bug!("impl restriction not found for {def_id:?}"), } diff --git a/compiler/rustc_restrictions/src/mut_restriction.rs b/compiler/rustc_restrictions/src/mut_restriction.rs index 14681e1b4b45e..661feef4099f3 100644 --- a/compiler/rustc_restrictions/src/mut_restriction.rs +++ b/compiler/rustc_restrictions/src/mut_restriction.rs @@ -23,7 +23,7 @@ pub(crate) fn provide(providers: &mut Providers) { fn mut_restriction(tcx: TyCtxt<'_>, def_id: LocalDefId) -> MutRestriction { tracing::debug!("mut_restriction({def_id:?})"); - match tcx.resolutions(()).mut_restrictions.get(&def_id.to_def_id()) { + match tcx.resolutions(()).mut_restrictions.get(&def_id) { Some(restriction) => *restriction, None => span_bug!(tcx.def_span(def_id), "mut restriction not found for {def_id:?}"), }