diff options
Diffstat (limited to 'compiler')
29 files changed, 590 insertions, 468 deletions
diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs index 710a592e258..3a65ffe41ae 100644 --- a/compiler/rustc_ast/src/token.rs +++ b/compiler/rustc_ast/src/token.rs @@ -586,6 +586,13 @@ impl Token { self.is_non_raw_ident_where(|id| id.name.is_bool_lit()) } + pub fn is_numeric_lit(&self) -> bool { + matches!( + self.kind, + Literal(Lit { kind: LitKind::Integer, .. }) | Literal(Lit { kind: LitKind::Float, .. }) + ) + } + /// Returns `true` if the token is a non-raw identifier for which `pred` holds. pub fn is_non_raw_ident_where(&self, pred: impl FnOnce(Ident) -> bool) -> bool { match self.ident() { diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index e0d4095d769..b7497c713f3 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -2,7 +2,6 @@ use super::{AnonymousLifetimeMode, LoweringContext, ParamMode}; use super::{ImplTraitContext, ImplTraitPosition}; use crate::Arena; -use rustc_ast::node_id::NodeMap; use rustc_ast::ptr::P; use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor}; use rustc_ast::*; @@ -1351,8 +1350,11 @@ impl<'hir> LoweringContext<'_, 'hir> { generics: &Generics, itctx: ImplTraitContext<'_, 'hir>, ) -> GenericsCtor<'hir> { - // Collect `?Trait` bounds in where clause and move them to parameter definitions. - let mut add_bounds: NodeMap<Vec<_>> = Default::default(); + // Error if `?Trait` bounds in where clauses don't refer directly to type paramters. + // Note: we used to clone these bounds directly onto the type parameter (and avoid lowering + // these into hir when we lower thee where clauses), but this makes it quite difficult to + // keep track of the Span info. Now, `add_implicitly_sized` in `AstConv` checks both param bounds and + // where clauses for `?Sized`. for pred in &generics.where_clause.predicates { if let WherePredicate::BoundPredicate(ref bound_pred) = *pred { 'next_bound: for bound in &bound_pred.bounds { @@ -1368,7 +1370,6 @@ impl<'hir> LoweringContext<'_, 'hir> { { for param in &generics.params { if def_id == self.resolver.local_def_id(param.id).to_def_id() { - add_bounds.entry(param.id).or_default().push(bound.clone()); continue 'next_bound; } } @@ -1386,7 +1387,7 @@ impl<'hir> LoweringContext<'_, 'hir> { } GenericsCtor { - params: self.lower_generic_params_mut(&generics.params, &add_bounds, itctx).collect(), + params: self.lower_generic_params_mut(&generics.params, itctx).collect(), where_clause: self.lower_where_clause(&generics.where_clause), span: self.lower_span(generics.span), } @@ -1419,32 +1420,17 @@ impl<'hir> LoweringContext<'_, 'hir> { ref bounded_ty, ref bounds, span, - }) => { - self.with_in_scope_lifetime_defs(&bound_generic_params, |this| { - hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate { - bound_generic_params: this.lower_generic_params( - bound_generic_params, - &NodeMap::default(), - ImplTraitContext::disallowed(), - ), - bounded_ty: this.lower_ty(bounded_ty, ImplTraitContext::disallowed()), - bounds: this.arena.alloc_from_iter(bounds.iter().map( - |bound| match bound { - // We used to ignore `?Trait` bounds, as they were copied into type - // parameters already, but we need to keep them around only for - // diagnostics when we suggest removal of `?Sized` bounds. See - // `suggest_constraining_type_param`. This will need to change if - // we ever allow something *other* than `?Sized`. - GenericBound::Trait(p, TraitBoundModifier::Maybe) => { - hir::GenericBound::Unsized(this.lower_span(p.span)) - } - _ => this.lower_param_bound(bound, ImplTraitContext::disallowed()), - }, - )), - span: this.lower_span(span), - }) + }) => self.with_in_scope_lifetime_defs(&bound_generic_params, |this| { + hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate { + bound_generic_params: this + .lower_generic_params(bound_generic_params, ImplTraitContext::disallowed()), + bounded_ty: this.lower_ty(bounded_ty, ImplTraitContext::disallowed()), + bounds: this.arena.alloc_from_iter(bounds.iter().map(|bound| { + this.lower_param_bound(bound, ImplTraitContext::disallowed()) + })), + span: this.lower_span(span), }) - } + }), WherePredicate::RegionPredicate(WhereRegionPredicate { ref lifetime, ref bounds, diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 5391d4b0c93..fa14764c42a 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -1313,7 +1313,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { hir::TyKind::BareFn(this.arena.alloc(hir::BareFnTy { generic_params: this.lower_generic_params( &f.generic_params, - &NodeMap::default(), ImplTraitContext::disallowed(), ), unsafety: this.lower_unsafety(f.unsafety), @@ -1998,30 +1997,25 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { fn lower_generic_params_mut<'s>( &'s mut self, params: &'s [GenericParam], - add_bounds: &'s NodeMap<Vec<GenericBound>>, mut itctx: ImplTraitContext<'s, 'hir>, ) -> impl Iterator<Item = hir::GenericParam<'hir>> + Captures<'a> + Captures<'s> { - params - .iter() - .map(move |param| self.lower_generic_param(param, add_bounds, itctx.reborrow())) + params.iter().map(move |param| self.lower_generic_param(param, itctx.reborrow())) } fn lower_generic_params( &mut self, params: &[GenericParam], - add_bounds: &NodeMap<Vec<GenericBound>>, itctx: ImplTraitContext<'_, 'hir>, ) -> &'hir [hir::GenericParam<'hir>] { - self.arena.alloc_from_iter(self.lower_generic_params_mut(params, add_bounds, itctx)) + self.arena.alloc_from_iter(self.lower_generic_params_mut(params, itctx)) } fn lower_generic_param( &mut self, param: &GenericParam, - add_bounds: &NodeMap<Vec<GenericBound>>, mut itctx: ImplTraitContext<'_, 'hir>, ) -> hir::GenericParam<'hir> { - let mut bounds: Vec<_> = self + let bounds: Vec<_> = self .with_anonymous_lifetime_mode(AnonymousLifetimeMode::ReportError, |this| { this.lower_param_bounds_mut(¶m.bounds, itctx.reborrow()).collect() }); @@ -2057,12 +2051,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { (param_name, kind) } GenericParamKind::Type { ref default, .. } => { - let add_bounds = add_bounds.get(¶m.id).map_or(&[][..], |x| &x); - if !add_bounds.is_empty() { - let params = self.lower_param_bounds_mut(add_bounds, itctx.reborrow()); - bounds.extend(params); - } - let kind = hir::GenericParamKind::Type { default: default.as_ref().map(|x| { self.lower_ty(x, ImplTraitContext::Disallowed(ImplTraitPosition::Other)) @@ -2123,11 +2111,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { p: &PolyTraitRef, mut itctx: ImplTraitContext<'_, 'hir>, ) -> hir::PolyTraitRef<'hir> { - let bound_generic_params = self.lower_generic_params( - &p.bound_generic_params, - &NodeMap::default(), - itctx.reborrow(), - ); + let bound_generic_params = + self.lower_generic_params(&p.bound_generic_params, itctx.reborrow()); let trait_ref = self.with_in_scope_lifetime_defs(&p.bound_generic_params, |this| { // Any impl Trait types defined within this scope can capture diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 903b630bbd6..4fb51ecc1d3 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -36,6 +36,7 @@ use regex::Regex; use tempfile::Builder as TempFileBuilder; use std::ffi::OsString; +use std::lazy::OnceCell; use std::path::{Path, PathBuf}; use std::process::{ExitStatus, Output, Stdio}; use std::{ascii, char, env, fmt, fs, io, mem, str}; @@ -257,6 +258,19 @@ fn link_rlib<'a, B: ArchiveBuilder<'a>>( // metadata of the rlib we're generating somehow. for lib in codegen_results.crate_info.used_libraries.iter() { match lib.kind { + NativeLibKind::Static { bundle: None | Some(true), whole_archive: Some(true) } + if flavor == RlibFlavor::Normal => + { + // Don't allow mixing +bundle with +whole_archive since an rlib may contain + // multiple native libs, some of which are +whole-archive and some of which are + // -whole-archive and it isn't clear how we can currently handle such a + // situation correctly. + // See https://github.com/rust-lang/rust/issues/88085#issuecomment-901050897 + sess.err( + "the linking modifiers `+bundle` and `+whole-archive` are not compatible \ + with each other when generating rlibs", + ); + } NativeLibKind::Static { bundle: None | Some(true), .. } => {} NativeLibKind::Static { bundle: Some(false), .. } | NativeLibKind::Dylib { .. } @@ -1255,6 +1269,7 @@ fn archive_search_paths(sess: &Session) -> Vec<PathBuf> { sess.target_filesearch(PathKind::Native).search_path_dirs() } +#[derive(PartialEq)] enum RlibFlavor { Normal, StaticlibBase, @@ -2034,7 +2049,7 @@ fn add_local_native_libraries( let relevant_libs = codegen_results.crate_info.used_libraries.iter().filter(|l| relevant_lib(sess, l)); - let search_path = archive_search_paths(sess); + let search_path = OnceCell::new(); let mut last = (NativeLibKind::Unspecified, None); for lib in relevant_libs { let name = match lib.name { @@ -2056,7 +2071,11 @@ fn add_local_native_libraries( } NativeLibKind::Static { bundle: None | Some(true), .. } | NativeLibKind::Static { whole_archive: Some(true), .. } => { - cmd.link_whole_staticlib(name, verbatim, &search_path); + cmd.link_whole_staticlib( + name, + verbatim, + &search_path.get_or_init(|| archive_search_paths(sess)), + ); } NativeLibKind::Static { .. } => cmd.link_staticlib(name, verbatim), NativeLibKind::RawDylib => { @@ -2149,6 +2168,7 @@ fn add_upstream_rust_crates<'a, B: ArchiveBuilder<'a>>( } let mut compiler_builtins = None; + let search_path = OnceCell::new(); for &cnum in deps.iter() { if group_start == Some(cnum) { @@ -2182,16 +2202,35 @@ fn add_upstream_rust_crates<'a, B: ArchiveBuilder<'a>>( // external build system already has the native dependencies defined, and it // will provide them to the linker itself. if sess.opts.debugging_opts.link_native_libraries { - // Skip if this library is the same as the last. let mut last = None; for lib in &codegen_results.crate_info.native_libraries[&cnum] { - if lib.name.is_some() - && relevant_lib(sess, lib) - && matches!(lib.kind, NativeLibKind::Static { bundle: Some(false), .. }) - && last != lib.name - { - cmd.link_staticlib(lib.name.unwrap(), lib.verbatim.unwrap_or(false)); - last = lib.name; + if !relevant_lib(sess, lib) { + // Skip libraries if they are disabled by `#[link(cfg=...)]` + continue; + } + + // Skip if this library is the same as the last. + if last == lib.name { + continue; + } + + if let Some(static_lib_name) = lib.name { + if let NativeLibKind::Static { bundle: Some(false), whole_archive } = + lib.kind + { + let verbatim = lib.verbatim.unwrap_or(false); + if whole_archive == Some(true) { + cmd.link_whole_staticlib( + static_lib_name, + verbatim, + search_path.get_or_init(|| archive_search_paths(sess)), + ); + } else { + cmd.link_staticlib(static_lib_name, verbatim); + } + + last = lib.name; + } } } } diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs index b6ee70c419b..634286770d1 100644 --- a/compiler/rustc_codegen_ssa/src/lib.rs +++ b/compiler/rustc_codegen_ssa/src/lib.rs @@ -3,6 +3,7 @@ #![feature(box_patterns)] #![feature(try_blocks)] #![feature(in_band_lifetimes)] +#![feature(once_cell)] #![feature(nll)] #![feature(associated_type_bounds)] #![recursion_limit = "256"] diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 21fe894c6fc..84bc37170c6 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -441,10 +441,12 @@ pub enum GenericBound<'hir> { Trait(PolyTraitRef<'hir>, TraitBoundModifier), // FIXME(davidtwco): Introduce `PolyTraitRef::LangItem` LangItemTrait(LangItem, Span, HirId, &'hir GenericArgs<'hir>), - Unsized(Span), Outlives(Lifetime), } +#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] +rustc_data_structures::static_assert_size!(GenericBound<'_>, 48); + impl GenericBound<'_> { pub fn trait_ref(&self) -> Option<&TraitRef<'_>> { match self { @@ -458,7 +460,6 @@ impl GenericBound<'_> { GenericBound::Trait(t, ..) => t.span, GenericBound::LangItemTrait(_, span, ..) => *span, GenericBound::Outlives(l) => l.span, - GenericBound::Unsized(span) => *span, } } } diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 2dd49eba442..137782a6dc7 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -871,7 +871,6 @@ pub fn walk_param_bound<'v, V: Visitor<'v>>(visitor: &mut V, bound: &'v GenericB visitor.visit_generic_args(span, args); } GenericBound::Outlives(ref lifetime) => visitor.visit_lifetime(lifetime), - GenericBound::Unsized(_) => {} } } diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 42e51f4bb48..36054c04847 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -2232,9 +2232,6 @@ impl<'a> State<'a> { GenericBound::Outlives(lt) => { self.print_lifetime(lt); } - GenericBound::Unsized(_) => { - self.s.word("?Sized"); - } } } } diff --git a/compiler/rustc_incremental/src/persist/file_format.rs b/compiler/rustc_incremental/src/persist/file_format.rs index b821ed6cff9..572a4fc6971 100644 --- a/compiler/rustc_incremental/src/persist/file_format.rs +++ b/compiler/rustc_incremental/src/persist/file_format.rs @@ -12,10 +12,12 @@ use std::env; use std::fs; use std::io::{self, Read}; -use std::path::Path; +use std::path::{Path, PathBuf}; +use rustc_data_structures::memmap::Mmap; use rustc_serialize::opaque::{FileEncodeResult, FileEncoder}; use rustc_serialize::Encoder; +use rustc_session::Session; /// The first few bytes of files generated by incremental compilation. const FILE_MAGIC: &[u8] = b"RSIC"; @@ -28,7 +30,7 @@ const HEADER_FORMAT_VERSION: u16 = 0; /// the Git commit hash. const RUSTC_VERSION: Option<&str> = option_env!("CFG_VERSION"); -pub fn write_file_header(stream: &mut FileEncoder, nightly_build: bool) -> FileEncodeResult { +pub(crate) fn write_file_header(stream: &mut FileEncoder, nightly_build: bool) -> FileEncodeResult { stream.emit_raw_bytes(FILE_MAGIC)?; stream.emit_raw_bytes(&[ (HEADER_FORMAT_VERSION >> 0) as u8, @@ -41,6 +43,61 @@ pub fn write_file_header(stream: &mut FileEncoder, nightly_build: bool) -> FileE stream.emit_raw_bytes(rustc_version.as_bytes()) } +pub(crate) fn save_in<F>(sess: &Session, path_buf: PathBuf, name: &str, encode: F) +where + F: FnOnce(&mut FileEncoder) -> FileEncodeResult, +{ + debug!("save: storing data in {}", path_buf.display()); + + // Delete the old file, if any. + // Note: It's important that we actually delete the old file and not just + // truncate and overwrite it, since it might be a shared hard-link, the + // underlying data of which we don't want to modify. + // + // We have to ensure we have dropped the memory maps to this file + // before performing this removal. + match fs::remove_file(&path_buf) { + Ok(()) => { + debug!("save: remove old file"); + } + Err(err) if err.kind() == io::ErrorKind::NotFound => (), + Err(err) => { + sess.err(&format!( + "unable to delete old {} at `{}`: {}", + name, + path_buf.display(), + err + )); + return; + } + } + + let mut encoder = match FileEncoder::new(&path_buf) { + Ok(encoder) => encoder, + Err(err) => { + sess.err(&format!("failed to create {} at `{}`: {}", name, path_buf.display(), err)); + return; + } + }; + + if let Err(err) = write_file_header(&mut encoder, sess.is_nightly_build()) { + sess.err(&format!("failed to write {} header to `{}`: {}", name, path_buf.display(), err)); + return; + } + + if let Err(err) = encode(&mut encoder) { + sess.err(&format!("failed to write {} to `{}`: {}", name, path_buf.display(), err)); + return; + } + + if let Err(err) = encoder.flush() { + sess.err(&format!("failed to flush {} to `{}`: {}", name, path_buf.display(), err)); + return; + } + + debug!("save: data written to disk successfully"); +} + /// Reads the contents of a file with a file header as defined in this module. /// /// - Returns `Ok(Some(data, pos))` if the file existed and was generated by a @@ -54,14 +111,21 @@ pub fn read_file( report_incremental_info: bool, path: &Path, nightly_build: bool, -) -> io::Result<Option<(Vec<u8>, usize)>> { - let data = match fs::read(path) { - Ok(data) => data, +) -> io::Result<Option<(Mmap, usize)>> { + let file = match fs::File::open(path) { + Ok(file) => file, Err(err) if err.kind() == io::ErrorKind::NotFound => return Ok(None), Err(err) => return Err(err), }; + // SAFETY: This process must not modify nor remove the backing file while the memory map lives. + // For the dep-graph and the work product index, it is as soon as the decoding is done. + // For the query result cache, the memory map is dropped in save_dep_graph before calling + // save_in and trying to remove the backing file. + // + // There is no way to prevent another process from modifying this file. + let mmap = unsafe { Mmap::map(file) }?; - let mut file = io::Cursor::new(data); + let mut file = io::Cursor::new(&*mmap); // Check FILE_MAGIC { @@ -103,7 +167,7 @@ pub fn read_file( } let post_header_start_pos = file.position() as usize; - Ok(Some((file.into_inner(), post_header_start_pos))) + Ok(Some((mmap, post_header_start_pos))) } fn report_format_mismatch(report_incremental_info: bool, file: &Path, message: &str) { diff --git a/compiler/rustc_incremental/src/persist/load.rs b/compiler/rustc_incremental/src/persist/load.rs index 437d5596447..4d38556e5d2 100644 --- a/compiler/rustc_incremental/src/persist/load.rs +++ b/compiler/rustc_incremental/src/persist/load.rs @@ -1,6 +1,7 @@ //! Code to save/load the dep-graph from files. use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::memmap::Mmap; use rustc_middle::dep_graph::{SerializedDepGraph, WorkProduct, WorkProductId}; use rustc_middle::ty::OnDiskCache; use rustc_serialize::opaque::Decoder; @@ -48,7 +49,7 @@ fn load_data( report_incremental_info: bool, path: &Path, nightly_build: bool, -) -> LoadResult<(Vec<u8>, usize)> { +) -> LoadResult<(Mmap, usize)> { match file_format::read_file(report_incremental_info, path, nightly_build) { Ok(Some(data_and_pos)) => LoadResult::Ok { data: data_and_pos }, Ok(None) => { diff --git a/compiler/rustc_incremental/src/persist/save.rs b/compiler/rustc_incremental/src/persist/save.rs index a8455854ebb..6c683058b12 100644 --- a/compiler/rustc_incremental/src/persist/save.rs +++ b/compiler/rustc_incremental/src/persist/save.rs @@ -6,8 +6,6 @@ use rustc_serialize::opaque::{FileEncodeResult, FileEncoder}; use rustc_serialize::Encodable as RustcEncodable; use rustc_session::Session; use std::fs; -use std::io; -use std::path::PathBuf; use super::data::*; use super::dirty_clean; @@ -44,7 +42,14 @@ pub fn save_dep_graph(tcx: TyCtxt<'_>) { join( move || { sess.time("incr_comp_persist_result_cache", || { - save_in(sess, query_cache_path, "query cache", |e| encode_query_cache(tcx, e)); + // Drop the memory map so that we can remove the file and write to it. + if let Some(odc) = &tcx.on_disk_cache { + odc.drop_serialized_data(tcx); + } + + file_format::save_in(sess, query_cache_path, "query cache", |e| { + encode_query_cache(tcx, e) + }); }); }, move || { @@ -86,7 +91,9 @@ pub fn save_work_product_index( debug!("save_work_product_index()"); dep_graph.assert_ignored(); let path = work_products_path(sess); - save_in(sess, path, "work product index", |e| encode_work_product_index(&new_work_products, e)); + file_format::save_in(sess, path, "work product index", |e| { + encode_work_product_index(&new_work_products, e) + }); // We also need to clean out old work-products, as not all of them are // deleted during invalidation. Some object files don't change their @@ -113,58 +120,6 @@ pub fn save_work_product_index( }); } -pub(crate) fn save_in<F>(sess: &Session, path_buf: PathBuf, name: &str, encode: F) -where - F: FnOnce(&mut FileEncoder) -> FileEncodeResult, -{ - debug!("save: storing data in {}", path_buf.display()); - - // Delete the old file, if any. - // Note: It's important that we actually delete the old file and not just - // truncate and overwrite it, since it might be a shared hard-link, the - // underlying data of which we don't want to modify - match fs::remove_file(&path_buf) { - Ok(()) => { - debug!("save: remove old file"); - } - Err(err) if err.kind() == io::ErrorKind::NotFound => (), - Err(err) => { - sess.err(&format!( - "unable to delete old {} at `{}`: {}", - name, - path_buf.display(), - err - )); - return; - } - } - - let mut encoder = match FileEncoder::new(&path_buf) { - Ok(encoder) => encoder, - Err(err) => { - sess.err(&format!("failed to create {} at `{}`: {}", name, path_buf.display(), err)); - return; - } - }; - - if let Err(err) = file_format::write_file_header(&mut encoder, sess.is_nightly_build()) { - sess.err(&format!("failed to write {} header to `{}`: {}", name, path_buf.display(), err)); - return; - } - - if let Err(err) = encode(&mut encoder) { - sess.err(&format!("failed to write {} to `{}`: {}", name, path_buf.display(), err)); - return; - } - - if let Err(err) = encoder.flush() { - sess.err(&format!("failed to flush {} to `{}`: {}", name, path_buf.display(), err)); - return; - } - - debug!("save: data written to disk successfully"); -} - fn encode_work_product_index( work_products: &FxHashMap<WorkProductId, WorkProduct>, encoder: &mut FileEncoder, diff --git a/compiler/rustc_infer/src/infer/fudge.rs b/compiler/rustc_infer/src/infer/fudge.rs index c292b2bdb30..35ebe92c592 100644 --- a/compiler/rustc_infer/src/infer/fudge.rs +++ b/compiler/rustc_infer/src/infer/fudge.rs @@ -187,7 +187,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for InferenceFudger<'a, 'tcx> { if self.type_vars.0.contains(&vid) { // This variable was created during the fudging. // Recreate it with a fresh variable here. - let idx = (vid.index - self.type_vars.0.start.index) as usize; + let idx = (vid.as_usize() - self.type_vars.0.start.as_usize()) as usize; let origin = self.type_vars.1[idx]; self.infcx.next_ty_var(origin) } else { diff --git a/compiler/rustc_infer/src/infer/type_variable.rs b/compiler/rustc_infer/src/infer/type_variable.rs index d2b0bdaf978..f15268f6895 100644 --- a/compiler/rustc_infer/src/infer/type_variable.rs +++ b/compiler/rustc_infer/src/infer/type_variable.rs @@ -196,7 +196,7 @@ impl<'tcx> TypeVariableTable<'_, 'tcx> { /// Note that this function does not return care whether /// `vid` has been unified with something else or not. pub fn var_diverges(&self, vid: ty::TyVid) -> Diverging { - self.storage.values.get(vid.index as usize).diverging + self.storage.values.get(vid.index()).diverging } /// Returns the origin that was given when `vid` was created. @@ -204,7 +204,7 @@ impl<'tcx> TypeVariableTable<'_, 'tcx> { /// Note that this function does not return care whether /// `vid` has been unified with something else or not. pub fn var_origin(&self, vid: ty::TyVid) -> &TypeVariableOrigin { - &self.storage.values.get(vid.index as usize).origin + &self.storage.values.get(vid.as_usize()).origin } /// Records that `a == b`, depending on `dir`. @@ -269,7 +269,7 @@ impl<'tcx> TypeVariableTable<'_, 'tcx> { assert_eq!(eq_key.vid, sub_key); let index = self.values().push(TypeVariableData { origin, diverging }); - assert_eq!(eq_key.vid.index, index as u32); + assert_eq!(eq_key.vid.as_u32(), index as u32); debug!( "new_var(index={:?}, universe={:?}, diverging={:?}, origin={:?}", @@ -357,11 +357,11 @@ impl<'tcx> TypeVariableTable<'_, 'tcx> { &mut self, value_count: usize, ) -> (Range<TyVid>, Vec<TypeVariableOrigin>) { - let range = TyVid { index: value_count as u32 }..TyVid { index: self.num_vars() as u32 }; + let range = TyVid::from_usize(value_count)..TyVid::from_usize(self.num_vars()); ( range.start..range.end, - (range.start.index..range.end.index) - .map(|index| self.storage.values.get(index as usize).origin) + (range.start.as_usize()..range.end.as_usize()) + .map(|index| self.storage.values.get(index).origin) .collect(), ) } @@ -371,7 +371,7 @@ impl<'tcx> TypeVariableTable<'_, 'tcx> { pub fn unsolved_variables(&mut self) -> Vec<ty::TyVid> { (0..self.storage.values.len()) .filter_map(|i| { - let vid = ty::TyVid { index: i as u32 }; + let vid = ty::TyVid::from_usize(i); match self.probe(vid) { TypeVariableValue::Unknown { .. } => Some(vid), TypeVariableValue::Known { .. } => None, @@ -424,10 +424,10 @@ impl<'tcx> ut::UnifyKey for TyVidEqKey<'tcx> { type Value = TypeVariableValue<'tcx>; #[inline(always)] fn index(&self) -> u32 { - self.vid.index + self.vid.as_u32() } fn from_index(i: u32) -> Self { - TyVidEqKey::from(ty::TyVid { index: i }) + TyVidEqKey::from(ty::TyVid::from_u32(i)) } fn tag() -> &'static str { "TyVidEqKey" diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index de7c6d9e095..1f5057d1da2 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -27,6 +27,7 @@ use crate::ty::{ use rustc_ast as ast; use rustc_attr as attr; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::memmap::Mmap; use rustc_data_structures::profiling::SelfProfilerRef; use rustc_data_structures::sharded::{IntoPointer, ShardedHashMap}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; @@ -71,7 +72,7 @@ use std::sync::Arc; pub trait OnDiskCache<'tcx>: rustc_data_structures::sync::Sync { /// Creates a new `OnDiskCache` instance from the serialized data in `data`. - fn new(sess: &'tcx Session, data: Vec<u8>, start_pos: usize) -> Self + fn new(sess: &'tcx Session, data: Mmap, start_pos: usize) -> Self where Self: Sized; @@ -100,6 +101,8 @@ pub trait OnDiskCache<'tcx>: rustc_data_structures::sync::Sync { fn register_reused_dep_node(&self, tcx: TyCtxt<'tcx>, dep_node: &DepNode); fn store_foreign_def_id_hash(&self, def_id: DefId, hash: DefPathHash); + fn drop_serialized_data(&self, tcx: TyCtxt<'tcx>); + fn serialize(&self, tcx: TyCtxt<'tcx>, encoder: &mut FileEncoder) -> FileEncodeResult; } diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs index 4cfb104bee3..092eae0fc5c 100644 --- a/compiler/rustc_middle/src/ty/diagnostics.rs +++ b/compiler/rustc_middle/src/ty/diagnostics.rs @@ -2,7 +2,6 @@ use crate::ty::TyKind::*; use crate::ty::{InferTy, TyCtxt, TyS}; -use rustc_data_structures::fx::FxHashSet; use rustc_errors::{Applicability, DiagnosticBuilder}; use rustc_hir as hir; use rustc_hir::def_id::DefId; @@ -114,10 +113,8 @@ fn suggest_removing_unsized_bound( def_id: Option<DefId>, ) { // See if there's a `?Sized` bound that can be removed to suggest that. - // First look at the `where` clause because we can have `where T: ?Sized`, but that - // `?Sized` bound is *also* included in the `GenericParam` as a bound, which breaks - // the spans. Hence the somewhat involved logic that follows. - let mut where_unsized_bounds = FxHashSet::default(); + // First look at the `where` clause because we can have `where T: ?Sized`, + // then look at params. for (where_pos, predicate) in generics.where_clause.predicates.iter().enumerate() { match predicate { WherePredicate::BoundPredicate(WhereBoundPredicate { @@ -140,7 +137,6 @@ fn suggest_removing_unsized_bound( }) if segment.ident.as_str() == param_name => { for (pos, bound) in bounds.iter().enumerate() { match bound { - hir::GenericBound::Unsized(_) => {} hir::GenericBound::Trait(poly, hir::TraitBoundModifier::Maybe) if poly.trait_ref.trait_def_id() == def_id => {} _ => continue, @@ -173,7 +169,6 @@ fn suggest_removing_unsized_bound( // ^^^^^^^^^ (_, pos, _, _) => bounds[pos - 1].span().shrink_to_hi().to(bound.span()), }; - where_unsized_bounds.insert(bound.span()); err.span_suggestion_verbose( sp, "consider removing the `?Sized` bound to make the \ @@ -189,8 +184,7 @@ fn suggest_removing_unsized_bound( for (pos, bound) in param.bounds.iter().enumerate() { match bound { hir::GenericBound::Trait(poly, hir::TraitBoundModifier::Maybe) - if poly.trait_ref.trait_def_id() == def_id - && !where_unsized_bounds.contains(&bound.span()) => + if poly.trait_ref.trait_def_id() == def_id => { let sp = match (param.bounds.len(), pos) { // T: ?Sized, diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index d01ca27b851..fddfd6e435c 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -137,6 +137,9 @@ pub struct ResolverOutputs { /// A list of proc macro LocalDefIds, written out in the order in which /// they are declared in the static array generated by proc_macro_harness. pub proc_macros: Vec<LocalDefId>, + /// Mapping from ident span to path span for paths that don't exist as written, but that + /// exist under `std`. For example, wrote `str::from_utf8` instead of `std::str::from_utf8`. + pub confused_type_with_std_module: FxHashMap<Span, Span>, } #[derive(Clone, Copy, Debug)] diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index a1d3e9adba0..05156745105 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -516,6 +516,26 @@ impl<'a> Parser<'a> { token::BinOp(token::And) | token::AndAnd => { make_it!(this, attrs, |this, _| this.parse_borrow_expr(lo)) } + token::BinOp(token::Plus) if this.look_ahead(1, |tok| tok.is_numeric_lit()) => { + let mut err = this.struct_span_err(lo, "leading `+` is not supported"); + err.span_label(lo, "unexpected `+`"); + + // a block on the LHS might have been intended to be an expression instead + if let Some(sp) = this.sess.ambiguous_block_expr_parse.borrow().get(&lo) { + this.sess.expr_parentheses_needed(&mut err, *sp); + } else { + err.span_suggestion_verbose( + lo, + "try removing the `+`", + "".to_string(), + Applicability::MachineApplicable, + ); + } + err.emit(); + + this.bump(); + this.parse_prefix_expr(None) + } // `+expr` token::Ident(..) if this.token.is_keyword(kw::Box) => { make_it!(this, attrs, |this, _| this.parse_box_expr(lo)) } diff --git a/compiler/rustc_query_impl/src/on_disk_cache.rs b/compiler/rustc_query_impl/src/on_disk_cache.rs index ee64f22618e..5c2803c67e7 100644 --- a/compiler/rustc_query_impl/src/on_disk_cache.rs +++ b/compiler/rustc_query_impl/src/on_disk_cache.rs @@ -1,6 +1,7 @@ use crate::QueryCtxt; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet}; -use rustc_data_structures::sync::{HashMapExt, Lock, Lrc, OnceCell}; +use rustc_data_structures::memmap::Mmap; +use rustc_data_structures::sync::{HashMapExt, Lock, Lrc, OnceCell, RwLock}; use rustc_data_structures::unhash::UnhashMap; use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, StableCrateId, LOCAL_CRATE}; use rustc_hir::definitions::DefPathHash; @@ -42,7 +43,7 @@ const TAG_EXPN_DATA: u8 = 1; /// any side effects that have been emitted during a query. pub struct OnDiskCache<'sess> { // The complete cache data in serialized form. - serialized_data: Vec<u8>, + serialized_data: RwLock<Option<Mmap>>, // Collects all `QuerySideEffects` created during the current compilation // session. @@ -182,7 +183,8 @@ impl EncodedSourceFileId { } impl<'sess> rustc_middle::ty::OnDiskCache<'sess> for OnDiskCache<'sess> { - fn new(sess: &'sess Session, data: Vec<u8>, start_pos: usize) -> Self { + /// Creates a new `OnDiskCache` instance from the serialized data in `data`. + fn new(sess: &'sess Session, data: Mmap, start_pos: usize) -> Self { debug_assert!(sess.opts.incremental.is_some()); // Wrap in a scope so we can borrow `data`. @@ -204,7 +206,7 @@ impl<'sess> rustc_middle::ty::OnDiskCache<'sess> for OnDiskCache<'sess> { }; Self { - serialized_data: data, + serialized_data: RwLock::new(Some(data)), file_index_to_stable_id: footer.file_index_to_stable_id, file_index_to_file: Default::default(), cnum_map: OnceCell::new(), @@ -225,7 +227,7 @@ impl<'sess> rustc_middle::ty::OnDiskCache<'sess> for OnDiskCache<'sess> { fn new_empty(source_map: &'sess SourceMap) -> Self { Self { - serialized_data: Vec::new(), + serialized_data: RwLock::new(None), file_index_to_stable_id: Default::default(), file_index_to_file: Default::default(), cnum_map: OnceCell::new(), @@ -244,7 +246,31 @@ impl<'sess> rustc_middle::ty::OnDiskCache<'sess> for OnDiskCache<'sess> { } } - fn serialize(&self, tcx: TyCtxt<'sess>, encoder: &mut FileEncoder) -> FileEncodeResult { + /// Execute all cache promotions and release the serialized backing Mmap. + /// + /// Cache promotions require invoking queries, which needs to read the serialized data. + /// In order to serialize the new on-disk cache, the former on-disk cache file needs to be + /// deleted, hence we won't be able to refer to its memmapped data. + fn drop_serialized_data(&self, tcx: TyCtxt<'tcx>) { + // Register any dep nodes that we reused from the previous session, + // but didn't `DepNode::construct` in this session. This ensures + // that their `DefPathHash` to `RawDefId` mappings are registered + // in 'latest_foreign_def_path_hashes' if necessary, since that + // normally happens in `DepNode::construct`. + tcx.dep_graph.register_reused_dep_nodes(tcx); + + // Load everything into memory so we can write it out to the on-disk + // cache. The vast majority of cacheable query results should already + // be in memory, so this should be a cheap operation. + // Do this *before* we clone 'latest_foreign_def_path_hashes', since + // loading existing queries may cause us to create new DepNodes, which + // may in turn end up invoking `store_foreign_def_id_hash` + tcx.dep_graph.exec_cache_promotions(QueryCtxt::from_tcx(tcx)); + + *self.serialized_data.write() = None; + } + + fn serialize<'tcx>(&self, tcx: TyCtxt<'tcx>, encoder: &mut FileEncoder) -> FileEncodeResult { // Serializing the `DepGraph` should not modify it. tcx.dep_graph.with_ignore(|| { // Allocate `SourceFileIndex`es. @@ -266,21 +292,6 @@ impl<'sess> rustc_middle::ty::OnDiskCache<'sess> for OnDiskCache<'sess> { (file_to_file_index, file_index_to_stable_id) }; - // Register any dep nodes that we reused from the previous session, - // but didn't `DepNode::construct` in this session. This ensures - // that their `DefPathHash` to `RawDefId` mappings are registered - // in 'latest_foreign_def_path_hashes' if necessary, since that - // normally happens in `DepNode::construct`. - tcx.dep_graph.register_reused_dep_nodes(tcx); - - // Load everything into memory so we can write it out to the on-disk - // cache. The vast majority of cacheable query results should already - // be in memory, so this should be a cheap operation. - // Do this *before* we clone 'latest_foreign_def_path_hashes', since - // loading existing queries may cause us to create new DepNodes, which - // may in turn end up invoking `store_foreign_def_id_hash` - tcx.dep_graph.exec_cache_promotions(QueryCtxt::from_tcx(tcx)); - let latest_foreign_def_path_hashes = self.latest_foreign_def_path_hashes.lock().clone(); let hygiene_encode_context = HygieneEncodeContext::default(); @@ -564,7 +575,7 @@ impl<'sess> OnDiskCache<'sess> { }) } - fn with_decoder<'a, 'tcx, T, F: FnOnce(&mut CacheDecoder<'sess, 'tcx>) -> T>( + fn with_decoder<'a, 'tcx, T, F: for<'s> FnOnce(&mut CacheDecoder<'s, 'tcx>) -> T>( &'sess self, tcx: TyCtxt<'tcx>, pos: AbsoluteBytePos, @@ -575,9 +586,10 @@ impl<'sess> OnDiskCache<'sess> { { let cnum_map = self.cnum_map.get_or_init(|| Self::compute_cnum_map(tcx)); + let serialized_data = self.serialized_data.read(); let mut decoder = CacheDecoder { tcx, - opaque: opaque::Decoder::new(&self.serialized_data[..], pos.to_usize()), + opaque: opaque::Decoder::new(serialized_data.as_deref().unwrap_or(&[]), pos.to_usize()), source_map: self.source_map, cnum_map, file_index_to_file: &self.file_index_to_file, diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 60573968361..c0b52d21fa6 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -1999,9 +1999,8 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { let item_span = path.iter().last().map_or(span, |segment| segment.ident.span); - let mut hm = self.r.session.confused_type_with_std_module.borrow_mut(); - hm.insert(item_span, span); - hm.insert(span, span); + self.r.confused_type_with_std_module.insert(item_span, span); + self.r.confused_type_with_std_module.insert(span, span); } } diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 152d34fd635..6d2961db9e3 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -1038,6 +1038,7 @@ pub struct Resolver<'a> { /// A list of proc macro LocalDefIds, written out in the order in which /// they are declared in the static array generated by proc_macro_harness. proc_macros: Vec<NodeId>, + confused_type_with_std_module: FxHashMap<Span, Span>, } /// Nothing really interesting here; it just provides memory for the rest of the crate. @@ -1404,6 +1405,7 @@ impl<'a> Resolver<'a> { main_def: Default::default(), trait_impls: Default::default(), proc_macros: Default::default(), + confused_type_with_std_module: Default::default(), }; let root_parent_scope = ParentScope::module(graph_root, &resolver); @@ -1447,6 +1449,7 @@ impl<'a> Resolver<'a> { let maybe_unused_extern_crates = self.maybe_unused_extern_crates; let glob_map = self.glob_map; let main_def = self.main_def; + let confused_type_with_std_module = self.confused_type_with_std_module; ResolverOutputs { definitions, cstore: Box::new(self.crate_loader.into_cstore()), @@ -1464,6 +1467,7 @@ impl<'a> Resolver<'a> { main_def, trait_impls: self.trait_impls, proc_macros, + confused_type_with_std_module, } } @@ -1486,6 +1490,7 @@ impl<'a> Resolver<'a> { main_def: self.main_def.clone(), trait_impls: self.trait_impls.clone(), proc_macros, + confused_type_with_std_module: self.confused_type_with_std_module.clone(), } } diff --git a/compiler/rustc_save_analysis/src/dump_visitor.rs b/compiler/rustc_save_analysis/src/dump_visitor.rs index 08ed9ec73c8..3e99f4e29ef 100644 --- a/compiler/rustc_save_analysis/src/dump_visitor.rs +++ b/compiler/rustc_save_analysis/src/dump_visitor.rs @@ -693,7 +693,6 @@ impl<'tcx> DumpVisitor<'tcx> { (Some(self.tcx.require_lang_item(lang_item, Some(span))), span) } hir::GenericBound::Outlives(..) => continue, - hir::GenericBound::Unsized(_) => continue, }; if let Some(id) = def_id { diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 0f7db69fefe..c71595ab57e 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -183,10 +183,6 @@ pub struct Session { /// Cap lint level specified by a driver specifically. pub driver_lint_caps: FxHashMap<lint::LintId, lint::Level>, - /// Mapping from ident span to path span for paths that don't exist as written, but that - /// exist under `std`. For example, wrote `str::from_utf8` instead of `std::str::from_utf8`. - pub confused_type_with_std_module: Lock<FxHashMap<Span, Span>>, - /// Tracks the current behavior of the CTFE engine when an error occurs. /// Options range from returning the error without a backtrace to returning an error /// and immediately printing the backtrace to stderr. @@ -1313,7 +1309,6 @@ pub fn build_session( print_fuel, jobserver: jobserver::client(), driver_lint_caps, - confused_type_with_std_module: Lock::new(Default::default()), ctfe_backtrace, miri_unleashed_features: Lock::new(Default::default()), asm_arch, diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index db3432b0142..0d3fd748645 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -1244,7 +1244,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { let sig = if let ty::Tuple(inputs) = inputs.kind() { tcx.mk_fn_sig( inputs.iter().map(|k| k.expect_ty()), - tcx.mk_ty_infer(ty::TyVar(ty::TyVid { index: 0 })), + tcx.mk_ty_infer(ty::TyVar(ty::TyVid::from_u32(0))), false, hir::Unsafety::Normal, abi::Abi::Rust, @@ -1252,7 +1252,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { } else { tcx.mk_fn_sig( std::iter::once(inputs), - tcx.mk_ty_infer(ty::TyVar(ty::TyVid { index: 0 })), + tcx.mk_ty_infer(ty::TyVar(ty::TyVid::from_u32(0))), false, hir::Unsafety::Normal, abi::Abi::Rust, diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs index c405bbe2d1f..d9ce169efc1 100644 --- a/compiler/rustc_type_ir/src/lib.rs +++ b/compiler/rustc_type_ir/src/lib.rs @@ -363,10 +363,11 @@ pub enum IntVarValue { #[derive(Clone, Copy, PartialEq, Eq)] pub struct FloatVarValue(pub FloatTy); -/// A **ty**pe **v**ariable **ID**. -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Encodable, Decodable)] -pub struct TyVid { - pub index: u32, +rustc_index::newtype_index! { + /// A **ty**pe **v**ariable **ID**. + pub struct TyVid { + DEBUG_FORMAT = "_#{}t" + } } /// An **int**egral (`u32`, `i32`, `usize`, etc.) type **v**ariable **ID**. @@ -422,10 +423,10 @@ pub enum InferTy { impl UnifyKey for TyVid { type Value = (); fn index(&self) -> u32 { - self.index + self.as_u32() } fn from_index(i: u32) -> TyVid { - TyVid { index: i } + TyVid::from_u32(i) } fn tag() -> &'static str { "TyVid" @@ -558,7 +559,7 @@ impl<CTX> HashStable<CTX> for InferTy { fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { use InferTy::*; match self { - TyVar(v) => v.index.hash_stable(ctx, hasher), + TyVar(v) => v.as_u32().hash_stable(ctx, hasher), IntVar(v) => v.index.hash_stable(ctx, hasher), FloatVar(v) => v.index.hash_stable(ctx, hasher), FreshTy(v) | FreshIntTy(v) | FreshFloatTy(v) => v.hash_stable(ctx, hasher), @@ -587,12 +588,6 @@ impl fmt::Debug for FloatVarValue { } } -impl fmt::Debug for TyVid { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "_#{}t", self.index) - } -} - impl fmt::Debug for IntVid { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "_#{}i", self.index) diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs index 059e0cadd19..51bb09e4c54 100644 --- a/compiler/rustc_typeck/src/astconv/mod.rs +++ b/compiler/rustc_typeck/src/astconv/mod.rs @@ -111,11 +111,6 @@ pub trait AstConv<'tcx> { fn record_ty(&self, hir_id: hir::HirId, ty: Ty<'tcx>, span: Span); } -pub enum SizedByDefault { - Yes, - No, -} - #[derive(Debug)] struct ConvertedBinding<'a, 'tcx> { hir_id: hir::HirId, @@ -698,6 +693,61 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { ) } + fn instantiate_poly_trait_ref_inner( + &self, + hir_id: hir::HirId, + span: Span, + binding_span: Option<Span>, + constness: ty::BoundConstness, + bounds: &mut Bounds<'tcx>, + speculative: bool, + trait_ref_span: Span, + trait_def_id: DefId, + trait_segment: &hir::PathSegment<'_>, + args: &GenericArgs<'_>, + infer_args: bool, + self_ty: Ty<'tcx>, + ) -> GenericArgCountResult { + let (substs, arg_count) = self.create_substs_for_ast_path( + trait_ref_span, + trait_def_id, + &[], + trait_segment, + args, + infer_args, + Some(self_ty), + ); + + let tcx = self.tcx(); + let bound_vars = tcx.late_bound_vars(hir_id); + debug!(?bound_vars); + + let assoc_bindings = self.create_assoc_bindings_for_generic_args(args); + + let poly_trait_ref = + ty::Binder::bind_with_vars(ty::TraitRef::new(trait_def_id, substs), bound_vars); + + debug!(?poly_trait_ref, ?assoc_bindings); + bounds.trait_bounds.push((poly_trait_ref, span, constness)); + + let mut dup_bindings = FxHashMap::default(); + for binding in &assoc_bindings { + // Specify type to assert that error was already reported in `Err` case. + let _: Result<_, ErrorReported> = self.add_predicates_for_ast_type_binding( + hir_id, + poly_trait_ref, + binding, + bounds, + speculative, + &mut dup_bindings, + binding_span.unwrap_or(binding.span), + ); + // Okay to ignore `Err` because of `ErrorReported` (see above). + } + + arg_count + } + /// Given a trait bound like `Debug`, applies that trait bound the given self-type to construct /// a full trait reference. The resulting trait reference is returned. This may also generate /// auxiliary bounds, which are added to `bounds`. @@ -718,7 +768,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { /// `Bar<'a>`. The returned poly-trait-ref will have this binder instantiated explicitly, /// however. #[tracing::instrument(level = "debug", skip(self, span, constness, bounds, speculative))] - pub fn instantiate_poly_trait_ref( + pub(crate) fn instantiate_poly_trait_ref( &self, trait_ref: &hir::TraitRef<'_>, span: Span, @@ -727,48 +777,34 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { bounds: &mut Bounds<'tcx>, speculative: bool, ) -> GenericArgCountResult { + let hir_id = trait_ref.hir_ref_id; + let binding_span = None; + let trait_ref_span = trait_ref.path.span; let trait_def_id = trait_ref.trait_def_id().unwrap_or_else(|| FatalError.raise()); + let trait_segment = trait_ref.path.segments.last().unwrap(); + let args = trait_segment.args(); + let infer_args = trait_segment.infer_args; self.prohibit_generics(trait_ref.path.segments.split_last().unwrap().1); + self.complain_about_internal_fn_trait(span, trait_def_id, trait_segment); - let tcx = self.tcx(); - let bound_vars = tcx.late_bound_vars(trait_ref.hir_ref_id); - debug!(?bound_vars); - - let (substs, arg_count) = self.create_substs_for_ast_trait_ref( - trait_ref.path.span, + self.instantiate_poly_trait_ref_inner( + hir_id, + span, + binding_span, + constness, + bounds, + speculative, + trait_ref_span, trait_def_id, + trait_segment, + args, + infer_args, self_ty, - trait_ref.path.segments.last().unwrap(), - ); - let assoc_bindings = self - .create_assoc_bindings_for_generic_args(trait_ref.path.segments.last().unwrap().args()); - - let poly_trait_ref = - ty::Binder::bind_with_vars(ty::TraitRef::new(trait_def_id, substs), bound_vars); - - debug!(?poly_trait_ref, ?assoc_bindings); - bounds.trait_bounds.push((poly_trait_ref, span, constness)); - - let mut dup_bindings = FxHashMap::default(); - for binding in &assoc_bindings { - // Specify type to assert that error was already reported in `Err` case. - let _: Result<_, ErrorReported> = self.add_predicates_for_ast_type_binding( - trait_ref.hir_ref_id, - poly_trait_ref, - binding, - bounds, - speculative, - &mut dup_bindings, - binding.span, - ); - // Okay to ignore `Err` because of `ErrorReported` (see above). - } - - arg_count + ) } - pub fn instantiate_lang_item_trait_ref( + pub(crate) fn instantiate_lang_item_trait_ref( &self, lang_item: hir::LangItem, span: Span, @@ -777,36 +813,28 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { self_ty: Ty<'tcx>, bounds: &mut Bounds<'tcx>, ) { + let binding_span = Some(span); + let constness = ty::BoundConstness::NotConst; + let speculative = false; + let trait_ref_span = span; let trait_def_id = self.tcx().require_lang_item(lang_item, Some(span)); + let trait_segment = &hir::PathSegment::invalid(); + let infer_args = false; - let (substs, _) = self.create_substs_for_ast_path( + self.instantiate_poly_trait_ref_inner( + hir_id, span, + binding_span, + constness, + bounds, + speculative, + trait_ref_span, trait_def_id, - &[], - &hir::PathSegment::invalid(), + trait_segment, args, - false, - Some(self_ty), + infer_args, + self_ty, ); - let assoc_bindings = self.create_assoc_bindings_for_generic_args(args); - let tcx = self.tcx(); - let bound_vars = tcx.late_bound_vars(hir_id); - let poly_trait_ref = - ty::Binder::bind_with_vars(ty::TraitRef::new(trait_def_id, substs), bound_vars); - bounds.trait_bounds.push((poly_trait_ref, span, ty::BoundConstness::NotConst)); - - let mut dup_bindings = FxHashMap::default(); - for binding in assoc_bindings { - let _: Result<_, ErrorReported> = self.add_predicates_for_ast_type_binding( - hir_id, - poly_trait_ref, - &binding, - bounds, - false, - &mut dup_bindings, - span, - ); - } } fn ast_path_to_mono_trait_ref( @@ -853,46 +881,76 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { .is_some() } - // Returns `true` if a bounds list includes `?Sized`. - pub fn is_unsized(&self, ast_bounds: &[hir::GenericBound<'_>], span: Span) -> bool { + // Sets `implicitly_sized` to true on `Bounds` if necessary + pub(crate) fn add_implicitly_sized<'hir>( + &self, + bounds: &mut Bounds<'hir>, + ast_bounds: &'hir [hir::GenericBound<'hir>], + self_ty_where_predicates: Option<(hir::HirId, &'hir [hir::WherePredicate<'hir>])>, + span: Span, + ) { let tcx = self.tcx(); // Try to find an unbound in bounds. let mut unbound = None; - for ab in ast_bounds { - if let hir::GenericBound::Trait(ptr, hir::TraitBoundModifier::Maybe) = ab { - if unbound.is_none() { - unbound = Some(&ptr.trait_ref); - } else { - tcx.sess.emit_err(MultipleRelaxedDefaultBounds { span }); + let mut search_bounds = |ast_bounds: &'hir [hir::GenericBound<'hir>]| { + for ab in ast_bounds { + if let hir::GenericBound::Trait(ptr, hir::TraitBoundModifier::Maybe) = ab { + if unbound.is_none() { + unbound = Some(&ptr.trait_ref); + } else { + tcx.sess.emit_err(MultipleRelaxedDefaultBounds { span }); + } } } - } - - let kind_id = tcx.lang_items().require(LangItem::Sized); - match unbound { - Some(tpb) => { - // FIXME(#8559) currently requires the unbound to be built-in. - if let Ok(kind_id) = kind_id { - if tpb.path.res != Res::Def(DefKind::Trait, kind_id) { - tcx.sess.span_warn( - span, - "default bound relaxed for a type parameter, but \ - this does nothing because the given bound is not \ - a default; only `?Sized` is supported", - ); - return false; + }; + search_bounds(ast_bounds); + if let Some((self_ty, where_clause)) = self_ty_where_predicates { + let self_ty_def_id = tcx.hir().local_def_id(self_ty).to_def_id(); + for clause in where_clause { + match clause { + hir::WherePredicate::BoundPredicate(pred) => { + match pred.bounded_ty.kind { + hir::TyKind::Path(hir::QPath::Resolved(_, path)) => match path.res { + Res::Def(DefKind::TyParam, def_id) if def_id == self_ty_def_id => {} + _ => continue, + }, + _ => continue, + } + search_bounds(pred.bounds); } + _ => {} } } - _ if kind_id.is_ok() => { - return false; + } + + let sized_def_id = tcx.lang_items().require(LangItem::Sized); + match (&sized_def_id, unbound) { + (Ok(sized_def_id), Some(tpb)) + if tpb.path.res == Res::Def(DefKind::Trait, *sized_def_id) => + { + // There was in fact a `?Sized` bound, return without doing anything + return; + } + (_, Some(_)) => { + // There was a `?Trait` bound, but it was not `?Sized`; warn. + tcx.sess.span_warn( + span, + "default bound relaxed for a type parameter, but \ + this does nothing because the given bound is not \ + a default; only `?Sized` is supported", + ); + // Otherwise, add implicitly sized if `Sized` is available. } + _ => { + // There was no `?Sized` bound; add implicitly sized if `Sized` is available. + } + } + if sized_def_id.is_err() { // No lang item for `Sized`, so we can't add it as a bound. - None => {} + return; } - - true + bounds.implicitly_sized = Some(span); } /// This helper takes a *converted* parameter type (`param_ty`) @@ -910,46 +968,43 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { /// **A note on binders:** there is an implied binder around /// `param_ty` and `ast_bounds`. See `instantiate_poly_trait_ref` /// for more details. - #[tracing::instrument(level = "debug", skip(self, bounds))] - fn add_bounds( + #[tracing::instrument(level = "debug", skip(self, ast_bounds, bounds))] + pub(crate) fn add_bounds<'hir, I: Iterator<Item = &'hir hir::GenericBound<'hir>>>( &self, param_ty: Ty<'tcx>, - ast_bounds: &[hir::GenericBound<'_>], + ast_bounds: I, bounds: &mut Bounds<'tcx>, bound_vars: &'tcx ty::List<ty::BoundVariableKind>, ) { for ast_bound in ast_bounds { - match *ast_bound { - hir::GenericBound::Trait(ref b, hir::TraitBoundModifier::None) => { - self.instantiate_poly_trait_ref( - &b.trait_ref, - b.span, - ty::BoundConstness::NotConst, + match ast_bound { + hir::GenericBound::Trait(poly_trait_ref, modifier) => { + let constness = match modifier { + hir::TraitBoundModifier::MaybeConst => ty::BoundConstness::ConstIfConst, + hir::TraitBoundModifier::None => ty::BoundConstness::NotConst, + hir::TraitBoundModifier::Maybe => continue, + }; + + let _ = self.instantiate_poly_trait_ref( + &poly_trait_ref.trait_ref, + poly_trait_ref.span, + constness, param_ty, bounds, false, ); } - hir::GenericBound::Trait(ref b, hir::TraitBoundModifier::MaybeConst) => { - self.instantiate_poly_trait_ref( - &b.trait_ref, - b.span, - ty::BoundConstness::ConstIfConst, - param_ty, - bounds, - false, + &hir::GenericBound::LangItemTrait(lang_item, span, hir_id, args) => { + self.instantiate_lang_item_trait_ref( + lang_item, span, hir_id, args, param_ty, bounds, ); } - hir::GenericBound::Trait(_, hir::TraitBoundModifier::Maybe) - | hir::GenericBound::Unsized(_) => {} - hir::GenericBound::LangItemTrait(lang_item, span, hir_id, args) => self - .instantiate_lang_item_trait_ref( - lang_item, span, hir_id, args, param_ty, bounds, - ), - hir::GenericBound::Outlives(ref l) => bounds.region_bounds.push(( - ty::Binder::bind_with_vars(self.ast_region_to_region(l, None), bound_vars), - l.span, - )), + hir::GenericBound::Outlives(lifetime) => { + let region = self.ast_region_to_region(lifetime, None); + bounds + .region_bounds + .push((ty::Binder::bind_with_vars(region, bound_vars), lifetime.span)); + } } } } @@ -970,24 +1025,20 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { /// example above, but is not true in supertrait listings like `trait Foo: Bar + Baz`. /// /// `span` should be the declaration size of the parameter. - pub fn compute_bounds( + pub(crate) fn compute_bounds( &self, param_ty: Ty<'tcx>, ast_bounds: &[hir::GenericBound<'_>], - sized_by_default: SizedByDefault, - span: Span, ) -> Bounds<'tcx> { - self.compute_bounds_inner(param_ty, &ast_bounds, sized_by_default, span) + self.compute_bounds_inner(param_ty, &ast_bounds) } /// Convert the bounds in `ast_bounds` that refer to traits which define an associated type /// named `assoc_name` into ty::Bounds. Ignore the rest. - pub fn compute_bounds_that_match_assoc_type( + pub(crate) fn compute_bounds_that_match_assoc_type( &self, param_ty: Ty<'tcx>, ast_bounds: &[hir::GenericBound<'_>], - sized_by_default: SizedByDefault, - span: Span, assoc_name: Ident, ) -> Bounds<'tcx> { let mut result = Vec::new(); @@ -1002,25 +1053,17 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { } } - self.compute_bounds_inner(param_ty, &result, sized_by_default, span) + self.compute_bounds_inner(param_ty, &result) } fn compute_bounds_inner( &self, param_ty: Ty<'tcx>, ast_bounds: &[hir::GenericBound<'_>], - sized_by_default: SizedByDefault, - span: Span, ) -> Bounds<'tcx> { let mut bounds = Bounds::default(); - self.add_bounds(param_ty, ast_bounds, &mut bounds, ty::List::empty()); - - bounds.implicitly_sized = if let SizedByDefault::Yes = sized_by_default { - if !self.is_unsized(ast_bounds, span) { Some(span) } else { None } - } else { - None - }; + self.add_bounds(param_ty, ast_bounds.iter(), &mut bounds, ty::List::empty()); bounds } @@ -1212,7 +1255,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // Calling `skip_binder` is okay, because `add_bounds` expects the `param_ty` // parameter to have a skipped binder. let param_ty = tcx.mk_ty(ty::Projection(projection_ty.skip_binder())); - self.add_bounds(param_ty, ast_bounds, bounds, candidate.bound_vars()); + self.add_bounds(param_ty, ast_bounds.iter(), bounds, candidate.bound_vars()); } } Ok(()) @@ -1495,9 +1538,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let mut err = struct_span_err!(self.tcx().sess, span, E0223, "ambiguous associated type"); if let (true, Ok(snippet)) = ( self.tcx() - .sess + .resolutions(()) .confused_type_with_std_module - .borrow() .keys() .any(|full_span| full_span.contains(span)), self.tcx().sess.source_map().span_to_snippet(span), diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs index c60d82d0cab..a746ad7ad4b 100644 --- a/compiler/rustc_typeck/src/check/method/suggest.rs +++ b/compiler/rustc_typeck/src/check/method/suggest.rs @@ -434,7 +434,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } if let Some(span) = - tcx.sess.confused_type_with_std_module.borrow().get(&span) + tcx.resolutions(()).confused_type_with_std_module.get(&span) { if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(*span) { err.span_suggestion( @@ -742,7 +742,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let projection_ty = pred.skip_binder().projection_ty; let substs_with_infer_self = tcx.mk_substs( - iter::once(tcx.mk_ty_var(ty::TyVid { index: 0 }).into()) + iter::once(tcx.mk_ty_var(ty::TyVid::from_u32(0)).into()) .chain(projection_ty.substs.iter().skip(1)), ); @@ -829,6 +829,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err.note(&format!( "the following trait bounds were not satisfied:\n{bound_list}" )); + self.suggest_derive(&mut err, &unsatisfied_predicates); + unsatisfied_bounds = true; } } @@ -971,6 +973,85 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { None } + fn suggest_derive( + &self, + err: &mut DiagnosticBuilder<'_>, + unsatisfied_predicates: &Vec<(ty::Predicate<'tcx>, Option<ty::Predicate<'tcx>>)>, + ) { + let derivables = [ + sym::Eq, + sym::PartialEq, + sym::Ord, + sym::PartialOrd, + sym::Clone, + sym::Copy, + sym::Hash, + sym::Default, + sym::debug_trait, + ]; + let mut derives = unsatisfied_predicates + .iter() + .filter_map(|(pred, _)| { + let trait_pred = + if let ty::PredicateKind::Trait(trait_pred) = pred.kind().skip_binder() { + trait_pred + } else { + return None; + }; + let trait_ref = trait_pred.trait_ref; + let adt_def = if let ty::Adt(adt_def, _) = trait_ref.self_ty().kind() { + adt_def + } else { + return None; + }; + if adt_def.did.is_local() { + let diagnostic_items = self.tcx.diagnostic_items(trait_ref.def_id.krate); + return derivables.iter().find_map(|trait_derivable| { + let item_def_id = + if let Some(item_def_id) = diagnostic_items.get(trait_derivable) { + item_def_id + } else { + return None; + }; + if item_def_id == &trait_pred.trait_ref.def_id + && !(adt_def.is_enum() && *trait_derivable == sym::Default) + { + return Some(( + format!("{}", trait_ref.self_ty()), + self.tcx.def_span(adt_def.did), + format!("{}", trait_ref.print_only_trait_path()), + )); + } + None + }); + } + None + }) + .collect::<Vec<(String, Span, String)>>(); + derives.sort(); + let derives_grouped = derives.into_iter().fold( + Vec::<(String, Span, String)>::new(), + |mut acc, (self_name, self_span, trait_name)| { + if let Some((acc_self_name, _, ref mut traits)) = acc.last_mut() { + if acc_self_name == &self_name { + traits.push_str(format!(", {}", trait_name).as_str()); + return acc; + } + } + acc.push((self_name, self_span, trait_name)); + acc + }, + ); + for (self_name, self_span, traits) in &derives_grouped { + err.span_suggestion_verbose( + self_span.shrink_to_lo(), + &format!("consider annotating `{}` with `#[derive({})]`", self_name, traits), + format!("#[derive({})]\n", traits), + Applicability::MaybeIncorrect, + ); + } + } + /// Print out the type for use in value namespace. fn ty_to_value_string(&self, ty: Ty<'tcx>) -> String { match ty.kind() { diff --git a/compiler/rustc_typeck/src/check/upvar.rs b/compiler/rustc_typeck/src/check/upvar.rs index 702f69a9fcf..53b99a14f37 100644 --- a/compiler/rustc_typeck/src/check/upvar.rs +++ b/compiler/rustc_typeck/src/check/upvar.rs @@ -399,7 +399,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } }; + // This restriction needs to be applied after we have handled adjustments for `move` + // closures. We want to make sure any adjustment that might make us move the place into + // the closure gets handled. + let (place, capture_kind) = + restrict_precision_for_drop_types(self, place, capture_kind, usage_span); + capture_info.capture_kind = capture_kind; + let capture_info = if let Some(existing) = processed.get(&place) { determine_capture_info(*existing, capture_info) } else { @@ -626,7 +633,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.tcx.struct_span_lint_hir( lint::builtin::RUST_2021_INCOMPATIBLE_CLOSURE_CAPTURES, closure_hir_id, - closure_head_span, + closure_head_span, |lint| { let mut diagnostics_builder = lint.build( format!( @@ -1852,6 +1859,31 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'tcx> { self.borrow(assignee_place, diag_expr_id, ty::BorrowKind::MutBorrow); } } + +/// Rust doesn't permit moving fields out of a type that implements drop +fn restrict_precision_for_drop_types<'a, 'tcx>( + fcx: &'a FnCtxt<'a, 'tcx>, + mut place: Place<'tcx>, + mut curr_mode: ty::UpvarCapture<'tcx>, + span: Span, +) -> (Place<'tcx>, ty::UpvarCapture<'tcx>) { + let is_copy_type = fcx.infcx.type_is_copy_modulo_regions(fcx.param_env, place.ty(), span); + + if let (false, UpvarCapture::ByValue(..)) = (is_copy_type, curr_mode) { + for i in 0..place.projections.len() { + match place.ty_before_projection(i).kind() { + ty::Adt(def, _) if def.destructor(fcx.tcx).is_some() => { + truncate_place_to_len_and_update_capture_kind(&mut place, &mut curr_mode, i); + break; + } + _ => {} + } + } + } + + (place, curr_mode) +} + /// Truncate `place` so that an `unsafe` block isn't required to capture it. /// - No projections are applied to raw pointers, since these require unsafe blocks. We capture /// them completely. diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index 64120510e56..3688fa05e03 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -14,7 +14,7 @@ //! At present, however, we do run collection across all items in the //! crate as a kind of pass. This should eventually be factored away. -use crate::astconv::{AstConv, SizedByDefault}; +use crate::astconv::AstConv; use crate::bounds::Bounds; use crate::check::intrinsic::intrinsic_operation_unsafety; use crate::constrained_generic_params as cgp; @@ -1156,18 +1156,10 @@ fn super_predicates_that_define_assoc_type( &icx, self_param_ty, &bounds, - SizedByDefault::No, - item.span, assoc_name, ) } else { - <dyn AstConv<'_>>::compute_bounds( - &icx, - self_param_ty, - &bounds, - SizedByDefault::No, - item.span, - ) + <dyn AstConv<'_>>::compute_bounds(&icx, self_param_ty, &bounds) }; let superbounds1 = superbounds1.predicates(tcx, self_param_ty); @@ -2176,12 +2168,13 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP let param_ty = ty::ParamTy::new(index, name).to_ty(tcx); index += 1; - let sized = SizedByDefault::Yes; - let bounds = <dyn AstConv<'_>>::compute_bounds( + let mut bounds = <dyn AstConv<'_>>::compute_bounds(&icx, param_ty, ¶m.bounds); + // Params are implicitly sized unless a `?Sized` bound is found + <dyn AstConv<'_>>::add_implicitly_sized( &icx, - param_ty, + &mut bounds, ¶m.bounds, - sized, + Some((param.hir_id, ast_generics.where_clause.predicates)), param.span, ); predicates.extend(bounds.predicates(tcx, param_ty)); @@ -2227,64 +2220,15 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP } } - for bound in bound_pred.bounds.iter() { - match bound { - hir::GenericBound::Trait(poly_trait_ref, modifier) => { - let constness = match modifier { - hir::TraitBoundModifier::None => ty::BoundConstness::NotConst, - hir::TraitBoundModifier::MaybeConst => { - ty::BoundConstness::ConstIfConst - } - // We ignore `where T: ?Sized`, it is already part of - // type parameter `T`. - hir::TraitBoundModifier::Maybe => continue, - }; - - let mut bounds = Bounds::default(); - let _ = <dyn AstConv<'_>>::instantiate_poly_trait_ref( - &icx, - &poly_trait_ref.trait_ref, - poly_trait_ref.span, - constness, - ty, - &mut bounds, - false, - ); - predicates.extend(bounds.predicates(tcx, ty)); - } - - &hir::GenericBound::LangItemTrait(lang_item, span, hir_id, args) => { - let mut bounds = Bounds::default(); - <dyn AstConv<'_>>::instantiate_lang_item_trait_ref( - &icx, - lang_item, - span, - hir_id, - args, - ty, - &mut bounds, - ); - predicates.extend(bounds.predicates(tcx, ty)); - } - - hir::GenericBound::Unsized(_) => {} - - hir::GenericBound::Outlives(lifetime) => { - let region = - <dyn AstConv<'_>>::ast_region_to_region(&icx, lifetime, None); - predicates.insert(( - ty::Binder::bind_with_vars( - ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate( - ty, region, - )), - bound_vars, - ) - .to_predicate(tcx), - lifetime.span, - )); - } - } - } + let mut bounds = Bounds::default(); + <dyn AstConv<'_>>::add_bounds( + &icx, + ty, + bound_pred.bounds.iter(), + &mut bounds, + bound_vars, + ); + predicates.extend(bounds.predicates(tcx, ty)); } hir::WherePredicate::RegionPredicate(region_pred) => { @@ -2498,45 +2442,14 @@ fn predicates_from_bound<'tcx>( param_ty: Ty<'tcx>, bound: &'tcx hir::GenericBound<'tcx>, ) -> Vec<(ty::Predicate<'tcx>, Span)> { - match *bound { - hir::GenericBound::Trait(ref tr, modifier) => { - let constness = match modifier { - hir::TraitBoundModifier::Maybe => return vec![], - hir::TraitBoundModifier::MaybeConst => ty::BoundConstness::ConstIfConst, - hir::TraitBoundModifier::None => ty::BoundConstness::NotConst, - }; - - let mut bounds = Bounds::default(); - let _ = astconv.instantiate_poly_trait_ref( - &tr.trait_ref, - tr.span, - constness, - param_ty, - &mut bounds, - false, - ); - bounds.predicates(astconv.tcx(), param_ty) - } - hir::GenericBound::LangItemTrait(lang_item, span, hir_id, args) => { - let mut bounds = Bounds::default(); - astconv.instantiate_lang_item_trait_ref( - lang_item, - span, - hir_id, - args, - param_ty, - &mut bounds, - ); - bounds.predicates(astconv.tcx(), param_ty) - } - hir::GenericBound::Unsized(_) => vec![], - hir::GenericBound::Outlives(ref lifetime) => { - let region = astconv.ast_region_to_region(lifetime, None); - let pred = ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(param_ty, region)) - .to_predicate(astconv.tcx()); - vec![(pred, lifetime.span)] - } - } + let mut bounds = Bounds::default(); + astconv.add_bounds( + param_ty, + std::array::IntoIter::new([bound]), + &mut bounds, + ty::List::empty(), + ); + bounds.predicates(astconv.tcx(), param_ty) } fn compute_sig_of_foreign_fn_decl<'tcx>( diff --git a/compiler/rustc_typeck/src/collect/item_bounds.rs b/compiler/rustc_typeck/src/collect/item_bounds.rs index 1d08c4450af..2bc048ac8a0 100644 --- a/compiler/rustc_typeck/src/collect/item_bounds.rs +++ b/compiler/rustc_typeck/src/collect/item_bounds.rs @@ -1,5 +1,5 @@ use super::ItemCtxt; -use crate::astconv::{AstConv, SizedByDefault}; +use crate::astconv::AstConv; use rustc_hir as hir; use rustc_infer::traits::util; use rustc_middle::ty::subst::InternalSubsts; @@ -17,7 +17,7 @@ use rustc_span::Span; fn associated_type_bounds<'tcx>( tcx: TyCtxt<'tcx>, assoc_item_def_id: DefId, - bounds: &'tcx [hir::GenericBound<'tcx>], + ast_bounds: &'tcx [hir::GenericBound<'tcx>], span: Span, ) -> &'tcx [(ty::Predicate<'tcx>, Span)] { let item_ty = tcx.mk_projection( @@ -25,13 +25,10 @@ fn associated_type_bounds<'tcx>( InternalSubsts::identity_for_item(tcx, assoc_item_def_id), ); - let bounds = <dyn AstConv<'_>>::compute_bounds( - &ItemCtxt::new(tcx, assoc_item_def_id), - item_ty, - &bounds, - SizedByDefault::Yes, - span, - ); + let icx = ItemCtxt::new(tcx, assoc_item_def_id); + let mut bounds = <dyn AstConv<'_>>::compute_bounds(&icx, item_ty, &ast_bounds); + // Associated types are implicitly sized unless a `?Sized` bound is found + <dyn AstConv<'_>>::add_implicitly_sized(&icx, &mut bounds, &ast_bounds, None, span); let trait_def_id = tcx.associated_item(assoc_item_def_id).container.id(); let trait_predicates = tcx.trait_explicit_predicates_and_bounds(trait_def_id.expect_local()); @@ -59,21 +56,18 @@ fn associated_type_bounds<'tcx>( fn opaque_type_bounds<'tcx>( tcx: TyCtxt<'tcx>, opaque_def_id: DefId, - bounds: &'tcx [hir::GenericBound<'tcx>], + ast_bounds: &'tcx [hir::GenericBound<'tcx>], span: Span, ) -> &'tcx [(ty::Predicate<'tcx>, Span)] { ty::print::with_no_queries(|| { let item_ty = tcx.mk_opaque(opaque_def_id, InternalSubsts::identity_for_item(tcx, opaque_def_id)); - let bounds = <dyn AstConv<'_>>::compute_bounds( - &ItemCtxt::new(tcx, opaque_def_id), - item_ty, - &bounds, - SizedByDefault::Yes, - span, - ) - .predicates(tcx, item_ty); + let icx = ItemCtxt::new(tcx, opaque_def_id); + let mut bounds = <dyn AstConv<'_>>::compute_bounds(&icx, item_ty, &ast_bounds); + // Opaque types are implicitly sized unless a `?Sized` bound is found + <dyn AstConv<'_>>::add_implicitly_sized(&icx, &mut bounds, &ast_bounds, None, span); + let bounds = bounds.predicates(tcx, item_ty); debug!("opaque_type_bounds({}) = {:?}", tcx.def_path_str(opaque_def_id), bounds); |
