diff --git a/Cargo.lock b/Cargo.lock index b261a00f4f3ab..753853e6acde4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4242,12 +4242,16 @@ version = "0.0.0" dependencies = [ "measureme", "rustc-rayon-core", + "rustc_ast", "rustc_data_structures", "rustc_errors", "rustc_hir", + "rustc_index", + "rustc_macros", "rustc_middle", "rustc_query_system", "rustc_serialize", + "rustc_session", "rustc_span", "tracing", ] diff --git a/compiler/rustc_ast/src/node_id.rs b/compiler/rustc_ast/src/node_id.rs index d20bace608882..7f928cb576180 100644 --- a/compiler/rustc_ast/src/node_id.rs +++ b/compiler/rustc_ast/src/node_id.rs @@ -1,4 +1,4 @@ -use rustc_span::ExpnId; +use rustc_span::LocalExpnId; use std::fmt; rustc_index::newtype_index! { @@ -24,12 +24,12 @@ pub const CRATE_NODE_ID: NodeId = NodeId::from_u32(0); pub const DUMMY_NODE_ID: NodeId = NodeId::MAX; impl NodeId { - pub fn placeholder_from_expn_id(expn_id: ExpnId) -> Self { + pub fn placeholder_from_expn_id(expn_id: LocalExpnId) -> Self { NodeId::from_u32(expn_id.as_u32()) } - pub fn placeholder_to_expn_id(self) -> ExpnId { - ExpnId::from_u32(self.as_u32()) + pub fn placeholder_to_expn_id(self) -> LocalExpnId { + LocalExpnId::from_u32(self.as_u32()) } } diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs index 97e07d52cc31a..ff13f0d4e4207 100644 --- a/compiler/rustc_builtin_macros/src/asm.rs +++ b/compiler/rustc_builtin_macros/src/asm.rs @@ -455,7 +455,7 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option, args: AsmArgs) -> Option match annitem.kind { ItemKind::Struct(_, Generics { ref params, .. }) | ItemKind::Enum(_, Generics { ref params, .. }) => { - let container_id = cx.current_expansion.id.expn_data().parent; - if cx.resolver.has_derive_copy(container_id) + let container_id = cx.current_expansion.id.expn_data().parent.expect_local(); + let has_derive_copy = cx.resolver.has_derive_copy(container_id); + if has_derive_copy && !params .iter() .any(|param| matches!(param.kind, ast::GenericParamKind::Type { .. })) diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index a3decff3ae7e1..417dedab60d08 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -410,7 +410,7 @@ impl<'a> TraitDef<'a> { .any(|param| matches!(param.kind, ast::GenericParamKind::Type { .. })), _ => unreachable!(), }; - let container_id = cx.current_expansion.id.expn_data().parent; + let container_id = cx.current_expansion.id.expn_data().parent.expect_local(); let always_copy = has_no_type_params && cx.resolver.has_derive_copy(container_id); let use_temporaries = is_packed && always_copy; diff --git a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs index a8c61d53346de..f83329ecba824 100644 --- a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs +++ b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs @@ -304,7 +304,7 @@ fn mk_decls( &[sym::rustc_attrs, sym::proc_macro_internals], None, ); - let span = DUMMY_SP.with_def_site_ctxt(expn_id); + let span = DUMMY_SP.with_def_site_ctxt(expn_id.to_expn_id()); let proc_macro = Ident::new(sym::proc_macro, span); let krate = cx.item(span, proc_macro, Vec::new(), ast::ItemKind::ExternCrate(None)); diff --git a/compiler/rustc_builtin_macros/src/source_util.rs b/compiler/rustc_builtin_macros/src/source_util.rs index ccb9f15b0f505..1ea2c8843d6d7 100644 --- a/compiler/rustc_builtin_macros/src/source_util.rs +++ b/compiler/rustc_builtin_macros/src/source_util.rs @@ -159,7 +159,7 @@ pub fn expand_include<'cx>( } } - Box::new(ExpandResult { p, node_id: cx.resolver.lint_node_id(cx.current_expansion.id) }) + Box::new(ExpandResult { p, node_id: cx.current_expansion.lint_node_id }) } // include_str! : read the given file, insert it as a literal string expr diff --git a/compiler/rustc_builtin_macros/src/standard_library_imports.rs b/compiler/rustc_builtin_macros/src/standard_library_imports.rs index fbd8be22a9de2..e0d57267525d9 100644 --- a/compiler/rustc_builtin_macros/src/standard_library_imports.rs +++ b/compiler/rustc_builtin_macros/src/standard_library_imports.rs @@ -34,8 +34,8 @@ pub fn inject( &[sym::prelude_import], None, ); - let span = DUMMY_SP.with_def_site_ctxt(expn_id); - let call_site = DUMMY_SP.with_call_site_ctxt(expn_id); + let span = DUMMY_SP.with_def_site_ctxt(expn_id.to_expn_id()); + let call_site = DUMMY_SP.with_call_site_ctxt(expn_id.to_expn_id()); let ecfg = ExpansionConfig::default("std_lib_injection".to_string()); let cx = ExtCtxt::new(sess, ecfg, resolver, None); diff --git a/compiler/rustc_builtin_macros/src/test_harness.rs b/compiler/rustc_builtin_macros/src/test_harness.rs index c8a7ff67b4d50..74a97a4058fac 100644 --- a/compiler/rustc_builtin_macros/src/test_harness.rs +++ b/compiler/rustc_builtin_macros/src/test_harness.rs @@ -126,7 +126,8 @@ impl<'a> MutVisitor for TestHarnessGenerator<'a> { for test in &mut tests { // See the comment on `mk_main` for why we're using // `apply_mark` directly. - test.ident.span = test.ident.span.apply_mark(expn_id, Transparency::Opaque); + test.ident.span = + test.ident.span.apply_mark(expn_id.to_expn_id(), Transparency::Opaque); } self.cx.test_cases.extend(tests); } @@ -223,7 +224,7 @@ fn generate_test_harness( &[sym::test, sym::rustc_attrs], None, ); - let def_site = DUMMY_SP.with_def_site_ctxt(expn_id); + let def_site = DUMMY_SP.with_def_site_ctxt(expn_id.to_expn_id()); // Remove the entry points let mut cleaner = EntryPointCleaner { sess, depth: 0, def_site }; diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs index c87309e22224f..424a0d742d12b 100644 --- a/compiler/rustc_codegen_cranelift/src/constant.rs +++ b/compiler/rustc_codegen_cranelift/src/constant.rs @@ -129,13 +129,13 @@ pub(crate) fn codegen_constant<'tcx>( }; let const_val = match const_.val { ConstKind::Value(const_val) => const_val, - ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted }) - if fx.tcx.is_static(def.did) => + ConstKind::Unevaluated(uv) + if fx.tcx.is_static(uv.def.did) => { - assert!(substs.is_empty()); - assert!(promoted.is_none()); + assert!(uv.substs(fx.tcx).is_empty()); + assert!(uv.promoted.is_none()); - return codegen_static_ref(fx, def.did, fx.layout_of(const_.ty)).to_cvalue(fx); + return codegen_static_ref(fx, uv.def.did, fx.layout_of(const_.ty)).to_cvalue(fx); } ConstKind::Unevaluated(unevaluated) => { match fx.tcx.const_eval_resolve(ParamEnv::reveal_all(), unevaluated, None) { diff --git a/compiler/rustc_codegen_cranelift/src/lib.rs b/compiler/rustc_codegen_cranelift/src/lib.rs index cb1cb3c74dbb5..e32dae49131ab 100644 --- a/compiler/rustc_codegen_cranelift/src/lib.rs +++ b/compiler/rustc_codegen_cranelift/src/lib.rs @@ -221,9 +221,7 @@ impl CodegenBackend for CraneliftCodegenBackend { sess, &codegen_results, outputs, - ); - - Ok(()) + ) } } diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index 2bb0ce68b171e..5675a5d981241 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -928,8 +928,12 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { pers_fn: &'ll Value, num_clauses: usize, ) -> &'ll Value { + // Use LLVMSetPersonalityFn to set the personality. It supports arbitrary Consts while, + // LLVMBuildLandingPad requires the argument to be a Function (as of LLVM 12). The + // personality lives on the parent function anyway. + self.set_personality_fn(pers_fn); unsafe { - llvm::LLVMBuildLandingPad(self.llbuilder, ty, pers_fn, num_clauses as c_uint, UNNAMED) + llvm::LLVMBuildLandingPad(self.llbuilder, ty, None, num_clauses as c_uint, UNNAMED) } } diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index d6a6095655595..59259857b4b0d 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -386,11 +386,16 @@ impl MiscMethods<'tcx> for CodegenCx<'ll, 'tcx> { } else { "rust_eh_personality" }; - let fty = self.type_variadic_func(&[], self.type_i32()); - self.declare_cfn(name, llvm::UnnamedAddr::Global, fty) + if let Some(llfn) = self.get_declared_value(name) { + llfn + } else { + let fty = self.type_variadic_func(&[], self.type_i32()); + let llfn = self.declare_cfn(name, llvm::UnnamedAddr::Global, fty); + attributes::apply_target_cpu_attr(self, llfn); + llfn + } } }; - attributes::apply_target_cpu_attr(self, llfn); self.eh_personality.set(Some(llfn)); llfn } diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs index 8375d4c7ca561..2e8a960401724 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs @@ -499,7 +499,7 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { ty::Adt(def, ..) if !def.is_box() => { // Again, only create type information if full debuginfo is enabled if cx.sess().opts.debuginfo == DebugInfo::Full - && !impl_self_ty.needs_subst() + && !impl_self_ty.needs_subst(cx.tcx) { Some(type_metadata(cx, impl_self_ty, rustc_span::DUMMY_SP)) } else { diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index 26fd1cfbcd08e..aa4db1622b233 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -292,9 +292,7 @@ impl CodegenBackend for LlvmCodegenBackend { // Run the linker on any artifacts that resulted from the LLVM run. // This should produce either a finished executable or library. - link_binary::>(sess, &codegen_results, outputs); - - Ok(()) + link_binary::>(sess, &codegen_results, outputs) } } diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 2ade66ac41eda..68d566cca095c 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -1165,7 +1165,7 @@ extern "C" { pub fn LLVMBuildLandingPad( B: &Builder<'a>, Ty: &'a Type, - PersFn: &'a Value, + PersFn: Option<&'a Value>, NumClauses: c_uint, Name: *const c_char, ) -> &'a Value; diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index f9efa448c93fa..ab211e9daff3e 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -1,9 +1,9 @@ -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; use rustc_data_structures::temp_dir::MaybeTempDir; -use rustc_errors::Handler; +use rustc_errors::{ErrorReported, Handler}; use rustc_fs_util::fix_windows_verbatim_for_gcc; use rustc_hir::def_id::CrateNum; -use rustc_middle::middle::cstore::{DllCallingConvention, DllImport}; +use rustc_middle::middle::cstore::DllImport; use rustc_middle::middle::dependency_format::Linkage; use rustc_session::config::{self, CFGuard, CrateType, DebugInfo, LdImpl, Strip}; use rustc_session::config::{OutputFilenames, OutputType, PrintRequest}; @@ -35,7 +35,6 @@ use object::{Architecture, BinaryFormat, Endianness, FileFlags, SectionFlags, Se use tempfile::Builder as TempFileBuilder; use std::ffi::OsString; -use std::iter::FromIterator; use std::path::{Path, PathBuf}; use std::process::{ExitStatus, Output, Stdio}; use std::{ascii, char, env, fmt, fs, io, mem, str}; @@ -54,7 +53,7 @@ pub fn link_binary<'a, B: ArchiveBuilder<'a>>( sess: &'a Session, codegen_results: &CodegenResults, outputs: &OutputFilenames, -) { +) -> Result<(), ErrorReported> { let _timer = sess.timer("link_binary"); let output_metadata = sess.opts.output_types.contains_key(&OutputType::Metadata); for &crate_type in sess.crate_types().iter() { @@ -95,11 +94,17 @@ pub fn link_binary<'a, B: ArchiveBuilder<'a>>( match crate_type { CrateType::Rlib => { let _timer = sess.timer("link_rlib"); - link_rlib::(sess, codegen_results, RlibFlavor::Normal, &out_filename, &path) - .build(); + link_rlib::( + sess, + codegen_results, + RlibFlavor::Normal, + &out_filename, + &path, + )? + .build(); } CrateType::Staticlib => { - link_staticlib::(sess, codegen_results, &out_filename, &path); + link_staticlib::(sess, codegen_results, &out_filename, &path)?; } _ => { link_natively::( @@ -145,6 +150,8 @@ pub fn link_binary<'a, B: ArchiveBuilder<'a>>( } } }); + + Ok(()) } pub fn each_linked_rlib( @@ -220,7 +227,7 @@ fn link_rlib<'a, B: ArchiveBuilder<'a>>( flavor: RlibFlavor, out_filename: &Path, tmpdir: &MaybeTempDir, -) -> B { +) -> Result { info!("preparing rlib to {:?}", out_filename); let mut ab = ::new(sess, out_filename, None); @@ -259,7 +266,7 @@ fn link_rlib<'a, B: ArchiveBuilder<'a>>( } for (raw_dylib_name, raw_dylib_imports) in - collate_raw_dylibs(sess, &codegen_results.crate_info.used_libraries) + collate_raw_dylibs(sess, &codegen_results.crate_info.used_libraries)? { ab.inject_dll_import_lib(&raw_dylib_name, &raw_dylib_imports, tmpdir); } @@ -312,7 +319,7 @@ fn link_rlib<'a, B: ArchiveBuilder<'a>>( } } } - return ab; + return Ok(ab); // For rlibs we "pack" rustc metadata into a dummy object file. When rustc // creates a dylib crate type it will pass `--whole-archive` (or the @@ -454,65 +461,40 @@ fn link_rlib<'a, B: ArchiveBuilder<'a>>( fn collate_raw_dylibs( sess: &Session, used_libraries: &[NativeLib], -) -> Vec<(String, Vec)> { - let mut dylib_table: FxHashMap> = FxHashMap::default(); +) -> Result)>, ErrorReported> { + // Use index maps to preserve original order of imports and libraries. + let mut dylib_table = FxIndexMap::>::default(); for lib in used_libraries { if lib.kind == NativeLibKind::RawDylib { - let name = lib.name.unwrap_or_else(|| - bug!("`link` attribute with kind = \"raw-dylib\" and no name should have caused error earlier") - ); - let name = if matches!(lib.verbatim, Some(true)) { - name.to_string() - } else { - format!("{}.dll", name) - }; - dylib_table.entry(name).or_default().extend(lib.dll_imports.iter().cloned()); - } - } - - // Rustc already signals an error if we have two imports with the same name but different - // calling conventions (or function signatures), so we don't have pay attention to those - // when ordering. - // FIXME: when we add support for ordinals, figure out if we need to do anything if we - // have two DllImport values with the same name but different ordinals. - let mut result: Vec<(String, Vec)> = dylib_table - .into_iter() - .map(|(lib_name, import_table)| { - let mut imports = Vec::from_iter(import_table.into_iter()); - imports.sort_unstable_by_key(|x: &DllImport| x.name.as_str()); - (lib_name, imports) - }) - .collect::>(); - result.sort_unstable_by(|a: &(String, Vec), b: &(String, Vec)| { - a.0.cmp(&b.0) - }); - let result = result; - - // Check for multiple imports with the same name but different calling conventions or - // (when relevant) argument list sizes. Rustc only signals an error for this if the - // declarations are at the same scope level; if one shadows the other, we only get a lint - // warning. - for (library, imports) in &result { - let mut import_table: FxHashMap = FxHashMap::default(); - for import in imports { - if let Some(old_convention) = - import_table.insert(import.name, import.calling_convention) - { - if import.calling_convention != old_convention { - sess.span_fatal( - import.span, - &format!( - "multiple definitions of external function `{}` from library `{}` have different calling conventions", - import.name, - library, - )); + let ext = if matches!(lib.verbatim, Some(true)) { "" } else { ".dll" }; + let name = format!("{}{}", lib.name.expect("unnamed raw-dylib library"), ext); + let imports = dylib_table.entry(name.clone()).or_default(); + for import in &lib.dll_imports { + if let Some(old_import) = imports.insert(import.name, import) { + // FIXME: when we add support for ordinals, figure out if we need to do anything + // if we have two DllImport values with the same name but different ordinals. + if import.calling_convention != old_import.calling_convention { + sess.span_err( + import.span, + &format!( + "multiple declarations of external function `{}` from \ + library `{}` have different calling conventions", + import.name, name, + ), + ); + } } } } } - - result + sess.compile_status()?; + Ok(dylib_table + .into_iter() + .map(|(name, imports)| { + (name, imports.into_iter().map(|(_, import)| import.clone()).collect()) + }) + .collect()) } /// Create a static archive. @@ -531,9 +513,9 @@ fn link_staticlib<'a, B: ArchiveBuilder<'a>>( codegen_results: &CodegenResults, out_filename: &Path, tempdir: &MaybeTempDir, -) { +) -> Result<(), ErrorReported> { let mut ab = - link_rlib::(sess, codegen_results, RlibFlavor::StaticlibBase, out_filename, tempdir); + link_rlib::(sess, codegen_results, RlibFlavor::StaticlibBase, out_filename, tempdir)?; let mut all_native_libs = vec![]; let res = each_linked_rlib(&codegen_results.crate_info, &mut |cnum, path| { @@ -581,6 +563,8 @@ fn link_staticlib<'a, B: ArchiveBuilder<'a>>( print_native_static_libs(sess, &all_native_libs); } } + + Ok(()) } fn escape_stdout_stderr_string(s: &[u8]) -> String { @@ -1950,7 +1934,12 @@ fn add_order_independent_options( // Try to strip as much out of the generated object by removing unused // sections if possible. See more comments in linker.rs if !sess.link_dead_code() { - let keep_metadata = crate_type == CrateType::Dylib; + // If PGO is enabled sometimes gc_sections will remove the profile data section + // as it appears to be unused. This can then cause the PGO profile file to lose + // some functions. If we are generating a profile we shouldn't strip those metadata + // sections to ensure we have all the data for PGO. + let keep_metadata = + crate_type == CrateType::Dylib || sess.opts.cg.profile_generate.enabled(); cmd.gc_sections(keep_metadata); } diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index b584801a62de2..b8eefd6890307 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -1391,7 +1391,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { LocalRef::UnsizedPlace(_) => bug!("transmute must not involve unsized locals"), LocalRef::Operand(None) => { let dst_layout = bx.layout_of(self.monomorphized_place_ty(dst.as_ref())); - assert!(!dst_layout.ty.has_erasable_regions()); + assert!(!dst_layout.ty.has_erasable_regions(self.cx.tcx())); let place = PlaceRef::alloca(bx, dst_layout); place.storage_live(bx); self.codegen_transmute_into(bx, src, place); diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs index 3bbc481b61093..e2edd44826717 100644 --- a/compiler/rustc_codegen_ssa/src/mir/mod.rs +++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs @@ -216,7 +216,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( let mut allocate_local = |local| { let decl = &mir.local_decls[local]; let layout = bx.layout_of(fx.monomorphize(decl.ty)); - assert!(!layout.ty.has_erasable_regions()); + assert!(!layout.ty.has_erasable_regions(cx.tcx())); if local == mir::RETURN_PLACE && fx.fn_abi.ret.is_indirect() { debug!("alloc: {:?} (return place) -> place", local); diff --git a/compiler/rustc_data_structures/src/obligation_forest/mod.rs b/compiler/rustc_data_structures/src/obligation_forest/mod.rs index 05b1a85381f45..25b7a84b3a069 100644 --- a/compiler/rustc_data_structures/src/obligation_forest/mod.rs +++ b/compiler/rustc_data_structures/src/obligation_forest/mod.rs @@ -418,6 +418,7 @@ impl ObligationForest { /// be called in a loop until `outcome.stalled` is false. /// /// This _cannot_ be unrolled (presently, at least). + #[inline(never)] pub fn process_obligations(&mut self, processor: &mut P) -> OUT where P: ObligationProcessor, @@ -671,6 +672,7 @@ impl ObligationForest { self.reused_node_vec = node_rewrites; } + #[inline(never)] fn apply_rewrites(&mut self, node_rewrites: &[usize]) { let orig_nodes_len = node_rewrites.len(); diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index 0183add495777..8c6aef80635cf 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -16,7 +16,7 @@ use rustc_parse::{self, nt_to_tokenstream, parser, MACRO_ARGUMENTS}; use rustc_session::{parse::ParseSess, Limit, Session}; use rustc_span::def_id::{CrateNum, DefId}; use rustc_span::edition::Edition; -use rustc_span::hygiene::{AstPass, ExpnData, ExpnId, ExpnKind}; +use rustc_span::hygiene::{AstPass, ExpnData, ExpnKind, LocalExpnId}; use rustc_span::source_map::SourceMap; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{FileName, MultiSpan, Span, DUMMY_SP}; @@ -29,6 +29,9 @@ use std::rc::Rc; crate use rustc_span::hygiene::MacroKind; +// When adding new variants, make sure to +// adjust the `visit_*` / `flat_map_*` calls in `InvocationCollector` +// to use `assign_id!` #[derive(Debug, Clone)] pub enum Annotatable { Item(P), @@ -813,7 +816,7 @@ impl SyntaxExtension { pub fn expn_data( &self, - parent: ExpnId, + parent: LocalExpnId, call_site: Span, descr: Symbol, macro_def_id: Option, @@ -821,7 +824,7 @@ impl SyntaxExtension { ) -> ExpnData { ExpnData::new( ExpnKind::Macro(self.macro_kind(), descr), - parent, + parent.to_expn_id(), call_site, self.span, self.allow_internal_unstable.clone(), @@ -843,7 +846,11 @@ pub trait ResolverExpand { fn next_node_id(&mut self) -> NodeId; fn resolve_dollar_crates(&mut self); - fn visit_ast_fragment_with_placeholders(&mut self, expn_id: ExpnId, fragment: &AstFragment); + fn visit_ast_fragment_with_placeholders( + &mut self, + expn_id: LocalExpnId, + fragment: &AstFragment, + ); fn register_builtin_macro(&mut self, name: Symbol, ext: SyntaxExtensionKind); fn expansion_for_ast_pass( @@ -852,37 +859,38 @@ pub trait ResolverExpand { pass: AstPass, features: &[Symbol], parent_module_id: Option, - ) -> ExpnId; + ) -> LocalExpnId; fn resolve_imports(&mut self); fn resolve_macro_invocation( &mut self, invoc: &Invocation, - eager_expansion_root: ExpnId, + eager_expansion_root: LocalExpnId, force: bool, ) -> Result, Indeterminate>; fn check_unused_macros(&mut self); - /// Some parent node that is close enough to the given macro call. - fn lint_node_id(&self, expn_id: ExpnId) -> NodeId; - // Resolver interfaces for specific built-in macros. /// Does `#[derive(...)]` attribute with the given `ExpnId` have built-in `Copy` inside it? - fn has_derive_copy(&self, expn_id: ExpnId) -> bool; + fn has_derive_copy(&self, expn_id: LocalExpnId) -> bool; /// Resolve paths inside the `#[derive(...)]` attribute with the given `ExpnId`. fn resolve_derives( &mut self, - expn_id: ExpnId, + expn_id: LocalExpnId, force: bool, derive_paths: &dyn Fn() -> DeriveResolutions, ) -> Result<(), Indeterminate>; /// Take resolutions for paths inside the `#[derive(...)]` attribute with the given `ExpnId` /// back from resolver. - fn take_derive_resolutions(&mut self, expn_id: ExpnId) -> Option; + fn take_derive_resolutions(&mut self, expn_id: LocalExpnId) -> Option; /// Path resolution logic for `#[cfg_accessible(path)]`. - fn cfg_accessible(&mut self, expn_id: ExpnId, path: &ast::Path) -> Result; + fn cfg_accessible( + &mut self, + expn_id: LocalExpnId, + path: &ast::Path, + ) -> Result; /// Decodes the proc-macro quoted span in the specified crate, with the specified id. /// No caching is performed. @@ -913,11 +921,13 @@ impl ModuleData { #[derive(Clone)] pub struct ExpansionData { - pub id: ExpnId, + pub id: LocalExpnId, pub depth: usize, pub module: Rc, pub dir_ownership: DirOwnership, pub prior_type_ascription: Option<(Span, bool)>, + /// Some parent node that is close to this macro call + pub lint_node_id: NodeId, } type OnExternModLoaded<'a> = @@ -958,11 +968,12 @@ impl<'a> ExtCtxt<'a> { extern_mod_loaded, root_path: PathBuf::new(), current_expansion: ExpansionData { - id: ExpnId::root(), + id: LocalExpnId::ROOT, depth: 0, module: Default::default(), dir_ownership: DirOwnership::Owned { relative: None }, prior_type_ascription: None, + lint_node_id: ast::CRATE_NODE_ID, }, force_mode: false, expansions: FxHashMap::default(), @@ -995,19 +1006,19 @@ impl<'a> ExtCtxt<'a> { /// Equivalent of `Span::def_site` from the proc macro API, /// except that the location is taken from the span passed as an argument. pub fn with_def_site_ctxt(&self, span: Span) -> Span { - span.with_def_site_ctxt(self.current_expansion.id) + span.with_def_site_ctxt(self.current_expansion.id.to_expn_id()) } /// Equivalent of `Span::call_site` from the proc macro API, /// except that the location is taken from the span passed as an argument. pub fn with_call_site_ctxt(&self, span: Span) -> Span { - span.with_call_site_ctxt(self.current_expansion.id) + span.with_call_site_ctxt(self.current_expansion.id.to_expn_id()) } /// Equivalent of `Span::mixed_site` from the proc macro API, /// except that the location is taken from the span passed as an argument. pub fn with_mixed_site_ctxt(&self, span: Span) -> Span { - span.with_mixed_site_ctxt(self.current_expansion.id) + span.with_mixed_site_ctxt(self.current_expansion.id.to_expn_id()) } /// Returns span for the macro which originally caused the current expansion to happen. diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 1ab7e15019eff..dcd871c9d2050 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -12,7 +12,7 @@ use rustc_ast::ptr::P; use rustc_ast::token; use rustc_ast::tokenstream::TokenStream; use rustc_ast::visit::{self, AssocCtxt, Visitor}; -use rustc_ast::{AstLike, Block, Inline, ItemKind, MacArgs}; +use rustc_ast::{AstLike, Block, Inline, ItemKind, Local, MacArgs}; use rustc_ast::{MacCallStmt, MacStmtStyle, MetaItemKind, ModKind, NestedMetaItem}; use rustc_ast::{NodeId, PatKind, Path, StmtKind, Unsafe}; use rustc_ast_pretty::pprust; @@ -31,7 +31,7 @@ use rustc_session::lint::BuiltinLintDiagnostics; use rustc_session::parse::{feature_err, ParseSess}; use rustc_session::Limit; use rustc_span::symbol::{sym, Ident}; -use rustc_span::{ExpnId, FileName, Span}; +use rustc_span::{FileName, LocalExpnId, Span}; use smallvec::{smallvec, SmallVec}; use std::ops::DerefMut; @@ -508,7 +508,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { .map(|(path, item, _exts)| { // FIXME: Consider using the derive resolutions (`_exts`) // instead of enqueuing the derives to be resolved again later. - let expn_id = ExpnId::fresh_empty(); + let expn_id = LocalExpnId::fresh_empty(); derive_invocations.push(( Invocation { kind: InvocationKind::Derive { path, item }, @@ -993,7 +993,7 @@ struct InvocationCollector<'a, 'b> { impl<'a, 'b> InvocationCollector<'a, 'b> { fn collect(&mut self, fragment_kind: AstFragmentKind, kind: InvocationKind) -> AstFragment { - let expn_id = ExpnId::fresh_empty(); + let expn_id = LocalExpnId::fresh_empty(); let vis = kind.placeholder_visibility(); self.invocations.push(( Invocation { @@ -1098,6 +1098,43 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { } } +/// Wraps a call to `noop_visit_*` / `noop_flat_map_*` +/// for an AST node that supports attributes +/// (see the `Annotatable` enum) +/// This method assigns a `NodeId`, and sets that `NodeId` +/// as our current 'lint node id'. If a macro call is found +/// inside this AST node, we will use this AST node's `NodeId` +/// to emit lints associated with that macro (allowing +/// `#[allow]` / `#[deny]` to be applied close to +/// the macro invocation). +/// +/// Do *not* call this for a macro AST node +/// (e.g. `ExprKind::MacCall`) - we cannot emit lints +/// at these AST nodes, since they are removed and +/// replaced with the result of macro expansion. +/// +/// All other `NodeId`s are assigned by `visit_id`. +/// * `self` is the 'self' parameter for the current method, +/// * `id` is a mutable reference to the `NodeId` field +/// of the current AST node. +/// * `closure` is a closure that executes the +/// `noop_visit_*` / `noop_flat_map_*` method +/// for the current AST node. +macro_rules! assign_id { + ($self:ident, $id:expr, $closure:expr) => {{ + let old_id = $self.cx.current_expansion.lint_node_id; + if $self.monotonic { + debug_assert_eq!(*$id, ast::DUMMY_NODE_ID); + let new_id = $self.cx.resolver.next_node_id(); + *$id = new_id; + $self.cx.current_expansion.lint_node_id = new_id; + } + let ret = ($closure)(); + $self.cx.current_expansion.lint_node_id = old_id; + ret + }}; +} + impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { fn visit_expr(&mut self, expr: &mut P) { self.cfg.configure_expr(expr); @@ -1118,12 +1155,19 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { self.check_attributes(&expr.attrs); self.collect_bang(mac, expr.span, AstFragmentKind::Expr).make_expr().into_inner() } else { - ensure_sufficient_stack(|| noop_visit_expr(&mut expr, self)); + assign_id!(self, &mut expr.id, || { + ensure_sufficient_stack(|| noop_visit_expr(&mut expr, self)); + }); expr } }); } + // This is needed in order to set `lint_node_id` for `let` statements + fn visit_local(&mut self, local: &mut P) { + assign_id!(self, &mut local.id, || noop_visit_local(local, self)); + } + fn flat_map_arm(&mut self, arm: ast::Arm) -> SmallVec<[ast::Arm; 1]> { let mut arm = configure!(self, arm); @@ -1133,7 +1177,7 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { .make_arms(); } - noop_flat_map_arm(arm, self) + assign_id!(self, &mut arm.id, || noop_flat_map_arm(arm, self)) } fn flat_map_expr_field(&mut self, field: ast::ExprField) -> SmallVec<[ast::ExprField; 1]> { @@ -1145,7 +1189,7 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { .make_expr_fields(); } - noop_flat_map_expr_field(field, self) + assign_id!(self, &mut field.id, || noop_flat_map_expr_field(field, self)) } fn flat_map_pat_field(&mut self, fp: ast::PatField) -> SmallVec<[ast::PatField; 1]> { @@ -1157,7 +1201,7 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { .make_pat_fields(); } - noop_flat_map_pat_field(fp, self) + assign_id!(self, &mut fp.id, || noop_flat_map_pat_field(fp, self)) } fn flat_map_param(&mut self, p: ast::Param) -> SmallVec<[ast::Param; 1]> { @@ -1169,7 +1213,7 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { .make_params(); } - noop_flat_map_param(p, self) + assign_id!(self, &mut p.id, || noop_flat_map_param(p, self)) } fn flat_map_field_def(&mut self, sf: ast::FieldDef) -> SmallVec<[ast::FieldDef; 1]> { @@ -1181,7 +1225,7 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { .make_field_defs(); } - noop_flat_map_field_def(sf, self) + assign_id!(self, &mut sf.id, || noop_flat_map_field_def(sf, self)) } fn flat_map_variant(&mut self, variant: ast::Variant) -> SmallVec<[ast::Variant; 1]> { @@ -1193,7 +1237,7 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { .make_variants(); } - noop_flat_map_variant(variant, self) + assign_id!(self, &mut variant.id, || noop_flat_map_variant(variant, self)) } fn filter_map_expr(&mut self, expr: P) -> Option> { @@ -1214,9 +1258,11 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { .make_opt_expr() .map(|expr| expr.into_inner()) } else { - Some({ - noop_visit_expr(&mut expr, self); - expr + assign_id!(self, &mut expr.id, || { + Some({ + noop_visit_expr(&mut expr, self); + expr + }) }) } }) @@ -1266,6 +1312,8 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { } // The placeholder expander gives ids to statements, so we avoid folding the id here. + // We don't use `assign_id!` - it will be called when we visit statement's contents + // (e.g. an expression, item, or local) let ast::Stmt { id, kind, span } = stmt; noop_flat_map_stmt_kind(kind, self) .into_iter() @@ -1377,7 +1425,7 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { let orig_dir_ownership = mem::replace(&mut self.cx.current_expansion.dir_ownership, dir_ownership); - let result = noop_flat_map_item(item, self); + let result = assign_id!(self, &mut item.id, || noop_flat_map_item(item, self)); // Restore the module info. self.cx.current_expansion.dir_ownership = orig_dir_ownership; @@ -1387,7 +1435,12 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { } _ => { item.attrs = attrs; - noop_flat_map_item(item, self) + // The crate root is special - don't assign an ID to it. + if !(matches!(item.kind, ast::ItemKind::Mod(..)) && ident == Ident::invalid()) { + assign_id!(self, &mut item.id, || noop_flat_map_item(item, self)) + } else { + noop_flat_map_item(item, self) + } } } } @@ -1411,7 +1464,9 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { _ => unreachable!(), }) } - _ => noop_flat_map_assoc_item(item, self), + _ => { + assign_id!(self, &mut item.id, || noop_flat_map_assoc_item(item, self)) + } } } @@ -1434,7 +1489,9 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { _ => unreachable!(), }) } - _ => noop_flat_map_assoc_item(item, self), + _ => { + assign_id!(self, &mut item.id, || noop_flat_map_assoc_item(item, self)) + } } } @@ -1478,7 +1535,12 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { _ => unreachable!(), }) } - _ => noop_flat_map_foreign_item(foreign_item, self), + _ => { + assign_id!(self, &mut foreign_item.id, || noop_flat_map_foreign_item( + foreign_item, + self + )) + } } } @@ -1498,13 +1560,14 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { .make_generic_params(); } - noop_flat_map_generic_param(param, self) + assign_id!(self, &mut param.id, || noop_flat_map_generic_param(param, self)) } fn visit_id(&mut self, id: &mut ast::NodeId) { - if self.monotonic { - debug_assert_eq!(*id, ast::DUMMY_NODE_ID); - *id = self.cx.resolver.next_node_id() + // We may have already assigned a `NodeId` + // by calling `assign_id` + if self.monotonic && *id == ast::DUMMY_NODE_ID { + *id = self.cx.resolver.next_node_id(); } } } diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs index 8b68c94e61a38..7f985af364d7d 100644 --- a/compiler/rustc_expand/src/mbe/macro_rules.rs +++ b/compiler/rustc_expand/src/mbe/macro_rules.rs @@ -289,7 +289,6 @@ fn generic_extension<'cx>( let mut p = Parser::new(sess, tts, false, None); p.last_type_ascription = cx.current_expansion.prior_type_ascription; - let lint_node_id = cx.resolver.lint_node_id(cx.current_expansion.id); // Let the context choose how to interpret the result. // Weird, but useful for X-macros. @@ -301,7 +300,7 @@ fn generic_extension<'cx>( // macro leaves unparsed tokens. site_span: sp, macro_ident: name, - lint_node_id, + lint_node_id: cx.current_expansion.lint_node_id, arm_span, }); } diff --git a/compiler/rustc_expand/src/mbe/transcribe.rs b/compiler/rustc_expand/src/mbe/transcribe.rs index f9e7c4254bc49..9ed5c8b8ffba5 100644 --- a/compiler/rustc_expand/src/mbe/transcribe.rs +++ b/compiler/rustc_expand/src/mbe/transcribe.rs @@ -8,7 +8,7 @@ use rustc_ast::tokenstream::{DelimSpan, TokenStream, TokenTree, TreeAndSpacing}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync::Lrc; use rustc_errors::{pluralize, PResult}; -use rustc_span::hygiene::{ExpnId, Transparency}; +use rustc_span::hygiene::{LocalExpnId, Transparency}; use rustc_span::symbol::MacroRulesNormalizedIdent; use rustc_span::Span; @@ -16,7 +16,7 @@ use smallvec::{smallvec, SmallVec}; use std::mem; // A Marker adds the given mark to the syntax context. -struct Marker(ExpnId, Transparency); +struct Marker(LocalExpnId, Transparency); impl MutVisitor for Marker { fn token_visiting_enabled(&self) -> bool { @@ -24,7 +24,7 @@ impl MutVisitor for Marker { } fn visit_span(&mut self, span: &mut Span) { - *span = span.apply_mark(self.0, self.1) + *span = span.apply_mark(self.0.to_expn_id(), self.1) } } diff --git a/compiler/rustc_incremental/src/persist/load.rs b/compiler/rustc_incremental/src/persist/load.rs index ee62089b23760..437d5596447d7 100644 --- a/compiler/rustc_incremental/src/persist/load.rs +++ b/compiler/rustc_incremental/src/persist/load.rs @@ -2,7 +2,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_middle::dep_graph::{SerializedDepGraph, WorkProduct, WorkProductId}; -use rustc_middle::ty::query::OnDiskCache; +use rustc_middle::ty::OnDiskCache; use rustc_serialize::opaque::Decoder; use rustc_serialize::Decodable; use rustc_session::Session; @@ -198,7 +198,7 @@ pub fn load_dep_graph(sess: &Session) -> DepGraphFuture { /// If we are not in incremental compilation mode, returns `None`. /// Otherwise, tries to load the query result cache from disk, /// creating an empty cache if it could not be loaded. -pub fn load_query_result_cache<'a>(sess: &'a Session) -> Option> { +pub fn load_query_result_cache<'a, C: OnDiskCache<'a>>(sess: &'a Session) -> Option { if sess.opts.incremental.is_none() { return None; } @@ -210,9 +210,7 @@ pub fn load_query_result_cache<'a>(sess: &'a Session) -> Option> &query_cache_path(sess), sess.is_nightly_build(), ) { - LoadResult::Ok { data: (bytes, start_pos) } => { - Some(OnDiskCache::new(sess, bytes, start_pos)) - } - _ => Some(OnDiskCache::new_empty(sess.source_map())), + LoadResult::Ok { data: (bytes, start_pos) } => Some(C::new(sess, bytes, start_pos)), + _ => Some(C::new_empty(sess.source_map())), } } diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs index ac953f4305c31..914b1c97c4797 100644 --- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs +++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs @@ -479,7 +479,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> { { let needs_canonical_flags = if canonicalize_region_mode.any() { TypeFlags::NEEDS_INFER | - TypeFlags::HAS_FREE_REGIONS | // `HAS_RE_PLACEHOLDER` implies `HAS_FREE_REGIONS` + TypeFlags::HAS_POTENTIAL_FREE_REGIONS | // `HAS_RE_PLACEHOLDER` implies `HAS_xxx_FREE_REGIONS` TypeFlags::HAS_TY_PLACEHOLDER | TypeFlags::HAS_CT_PLACEHOLDER } else { diff --git a/compiler/rustc_infer/src/infer/combine.rs b/compiler/rustc_infer/src/infer/combine.rs index 3a11b5a214490..79e885546c331 100644 --- a/compiler/rustc_infer/src/infer/combine.rs +++ b/compiler/rustc_infer/src/infer/combine.rs @@ -129,6 +129,8 @@ impl<'infcx, 'tcx> InferCtxt<'infcx, 'tcx> { where R: ConstEquateRelation<'tcx>, { + let a = self.tcx.expose_default_const_substs(a); + let b = self.tcx.expose_default_const_substs(b); debug!("{}.consts({:?}, {:?})", relation.tag(), a, b); if a == b { return Ok(a); @@ -737,10 +739,9 @@ impl TypeRelation<'tcx> for Generalizer<'_, 'tcx> { } } } - ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted }) - if self.tcx().lazy_normalization() => - { - assert_eq!(promoted, None); + ty::ConstKind::Unevaluated(uv) if self.tcx().lazy_normalization() => { + assert_eq!(uv.promoted, None); + let substs = uv.substs(self.tcx()); let substs = self.relate_with_variance( ty::Variance::Invariant, ty::VarianceDiagInfo::default(), @@ -749,7 +750,7 @@ impl TypeRelation<'tcx> for Generalizer<'_, 'tcx> { )?; Ok(self.tcx().mk_const(ty::Const { ty: c.ty, - val: ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted }), + val: ty::ConstKind::Unevaluated(ty::Unevaluated::new(uv.def, substs)), })) } _ => relate::super_relate_consts(self, c, c), @@ -971,10 +972,9 @@ impl TypeRelation<'tcx> for ConstInferUnifier<'_, 'tcx> { } } } - ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted }) - if self.tcx().lazy_normalization() => - { - assert_eq!(promoted, None); + ty::ConstKind::Unevaluated(uv) if self.tcx().lazy_normalization() => { + assert_eq!(uv.promoted, None); + let substs = uv.substs(self.tcx()); let substs = self.relate_with_variance( ty::Variance::Invariant, ty::VarianceDiagInfo::default(), @@ -983,7 +983,7 @@ impl TypeRelation<'tcx> for ConstInferUnifier<'_, 'tcx> { )?; Ok(self.tcx().mk_const(ty::Const { ty: c.ty, - val: ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted }), + val: ty::ConstKind::Unevaluated(ty::Unevaluated::new(uv.def, substs)), })) } _ => relate::super_relate_consts(self, c, c), diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index e3a79fe265330..de78f49007f3f 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -1517,6 +1517,10 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } impl<'tcx> ty::fold::TypeVisitor<'tcx> for OpaqueTypesVisitor<'tcx> { + fn tcx_for_anon_const_substs(&self) -> Option> { + Some(self.tcx) + } + fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { if let Some((kind, def_id)) = TyCategory::from_ty(self.tcx, t) { let span = self.tcx.def_span(def_id); diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs index d9a1193aac4ba..389b6700f2ec3 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs @@ -51,7 +51,7 @@ impl<'a, 'tcx> FindHirNodeVisitor<'a, 'tcx> { fn node_ty_contains_target(&self, hir_id: HirId) -> Option> { self.node_type_opt(hir_id).map(|ty| self.infcx.resolve_vars_if_possible(ty)).filter(|ty| { - ty.walk().any(|inner| { + ty.walk(self.infcx.tcx).any(|inner| { inner == self.target || match (inner.unpack(), self.target.unpack()) { (GenericArgKind::Type(inner_ty), GenericArgKind::Type(target_ty)) => { diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs index 1e926989263c9..0f02b841d23e3 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs @@ -8,7 +8,9 @@ use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorRepor use rustc_hir::def_id::DefId; use rustc_hir::intravisit::{walk_ty, ErasedMap, NestedVisitorMap, Visitor}; use rustc_hir::{self as hir, GenericBound, Item, ItemKind, Lifetime, LifetimeName, Node, TyKind}; -use rustc_middle::ty::{self, AssocItemContainer, RegionKind, Ty, TypeFoldable, TypeVisitor}; +use rustc_middle::ty::{ + self, AssocItemContainer, RegionKind, Ty, TyCtxt, TypeFoldable, TypeVisitor, +}; use rustc_span::symbol::Ident; use rustc_span::{MultiSpan, Span}; @@ -470,8 +472,14 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { /// Collect all the trait objects in a type that could have received an implicit `'static` lifetime. struct TraitObjectVisitor(Vec); -impl TypeVisitor<'_> for TraitObjectVisitor { - fn visit_ty(&mut self, t: Ty<'_>) -> ControlFlow { +impl<'tcx> TypeVisitor<'tcx> for TraitObjectVisitor { + fn tcx_for_anon_const_substs(&self) -> Option> { + // The default anon const substs cannot include + // trait objects, so we don't have to bother looking. + None + } + + fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { match t.kind() { ty::Dynamic(preds, RegionKind::ReStatic) => { if let Some(def_id) = preds.principal_def_id() { diff --git a/compiler/rustc_infer/src/infer/freshen.rs b/compiler/rustc_infer/src/infer/freshen.rs index b3d7876c6e819..10d7cfbbd1207 100644 --- a/compiler/rustc_infer/src/infer/freshen.rs +++ b/compiler/rustc_infer/src/infer/freshen.rs @@ -138,7 +138,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for TypeFreshener<'a, 'tcx> { } fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { - if !t.needs_infer() && !t.has_erasable_regions() { + if !t.needs_infer() && !t.has_erasable_regions(self.tcx()) { return t; } diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index f39431f2494b1..b1522dc7da4b3 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -1487,16 +1487,16 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { pub fn const_eval_resolve( &self, param_env: ty::ParamEnv<'tcx>, - ty::Unevaluated { def, substs, promoted }: ty::Unevaluated<'tcx>, + unevaluated: ty::Unevaluated<'tcx>, span: Option, ) -> EvalToConstValueResult<'tcx> { let mut original_values = OriginalQueryValues::default(); - let canonical = self.canonicalize_query((param_env, substs), &mut original_values); + let canonical = self.canonicalize_query((param_env, unevaluated), &mut original_values); - let (param_env, substs) = canonical.value; + let (param_env, unevaluated) = canonical.value; // The return value is the evaluated value which doesn't contain any reference to inference // variables, thus we don't need to substitute back the original values. - self.tcx.const_eval_resolve(param_env, ty::Unevaluated { def, substs, promoted }, span) + self.tcx.const_eval_resolve(param_env, unevaluated, span) } /// If `typ` is a type variable of some kind, resolve it one level diff --git a/compiler/rustc_infer/src/infer/nll_relate/mod.rs b/compiler/rustc_infer/src/infer/nll_relate/mod.rs index 20be06adfd09e..9417731872ce0 100644 --- a/compiler/rustc_infer/src/infer/nll_relate/mod.rs +++ b/compiler/rustc_infer/src/infer/nll_relate/mod.rs @@ -201,6 +201,7 @@ where }; value.skip_binder().visit_with(&mut ScopeInstantiator { + tcx: self.infcx.tcx, next_region: &mut next_region, target_index: ty::INNERMOST, bound_region_scope: &mut scope, @@ -756,6 +757,7 @@ where /// `for<..`>. For each of those, it creates an entry in /// `bound_region_scope`. struct ScopeInstantiator<'me, 'tcx> { + tcx: TyCtxt<'tcx>, next_region: &'me mut dyn FnMut(ty::BoundRegion) -> ty::Region<'tcx>, // The debruijn index of the scope we are instantiating. target_index: ty::DebruijnIndex, @@ -763,6 +765,10 @@ struct ScopeInstantiator<'me, 'tcx> { } impl<'me, 'tcx> TypeVisitor<'tcx> for ScopeInstantiator<'me, 'tcx> { + fn tcx_for_anon_const_substs(&self) -> Option> { + Some(self.tcx) + } + fn visit_binder>( &mut self, t: &ty::Binder<'tcx, T>, diff --git a/compiler/rustc_infer/src/infer/outlives/verify.rs b/compiler/rustc_infer/src/infer/outlives/verify.rs index f69212c599b62..dba73251b4f0d 100644 --- a/compiler/rustc_infer/src/infer/outlives/verify.rs +++ b/compiler/rustc_infer/src/infer/outlives/verify.rs @@ -189,7 +189,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { visited: &mut SsoHashSet>, ) -> VerifyBound<'tcx> { let mut bounds = parent - .walk_shallow(visited) + .walk_shallow(self.tcx, visited) .filter_map(|child| match child.unpack() { GenericArgKind::Type(ty) => Some(self.type_bound(ty, visited)), GenericArgKind::Lifetime(lt) => { diff --git a/compiler/rustc_infer/src/infer/resolve.rs b/compiler/rustc_infer/src/infer/resolve.rs index 48b8ee17594e3..4b08c2eb9c19e 100644 --- a/compiler/rustc_infer/src/infer/resolve.rs +++ b/compiler/rustc_infer/src/infer/resolve.rs @@ -126,6 +126,11 @@ impl<'a, 'tcx> UnresolvedTypeFinder<'a, 'tcx> { impl<'a, 'tcx> TypeVisitor<'tcx> for UnresolvedTypeFinder<'a, 'tcx> { type BreakTy = (Ty<'tcx>, Option); + + fn tcx_for_anon_const_substs(&self) -> Option> { + Some(self.infcx.tcx) + } + fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { let t = self.infcx.shallow_resolve(t); if t.has_infer_types() { diff --git a/compiler/rustc_infer/src/infer/type_variable.rs b/compiler/rustc_infer/src/infer/type_variable.rs index 683c1df783e63..13b78b26af424 100644 --- a/compiler/rustc_infer/src/infer/type_variable.rs +++ b/compiler/rustc_infer/src/infer/type_variable.rs @@ -400,6 +400,7 @@ impl<'tcx> From for TyVidEqKey<'tcx> { impl<'tcx> ut::UnifyKey for TyVidEqKey<'tcx> { type Value = TypeVariableValue<'tcx>; + #[inline(always)] fn index(&self) -> u32 { self.vid.index } diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs index 086c49c73972f..8393826aa1285 100644 --- a/compiler/rustc_interface/src/interface.rs +++ b/compiler/rustc_interface/src/interface.rs @@ -12,6 +12,7 @@ use rustc_errors::{ErrorReported, Handler}; use rustc_lint::LintStore; use rustc_middle::ty; use rustc_parse::new_parser_from_source_str; +use rustc_query_impl::QueryCtxt; use rustc_session::config::{self, ErrorOutputType, Input, OutputFilenames}; use rustc_session::early_error; use rustc_session::lint; @@ -233,7 +234,7 @@ pub fn try_print_query_stack(handler: &Handler, num_frames: Option) { // state if it was responsible for triggering the panic. let i = ty::tls::with_context_opt(|icx| { if let Some(icx) = icx { - icx.tcx.queries.try_print_query_stack(icx.tcx, icx.query, handler, num_frames) + QueryCtxt::from_tcx(icx.tcx).try_print_query_stack(icx.query, handler, num_frames) } else { 0 } diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 958a4ab68020a..5db027fb5b473 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -26,7 +26,7 @@ use rustc_mir_build as mir_build; use rustc_parse::{parse_crate_from_file, parse_crate_from_source_str}; use rustc_passes::{self, hir_stats, layout_test}; use rustc_plugin_impl as plugin; -use rustc_query_impl::Queries as TcxQueries; +use rustc_query_impl::{OnDiskCache, Queries as TcxQueries}; use rustc_resolve::{Resolver, ResolverArenas}; use rustc_serialize::json; use rustc_session::config::{CrateType, Input, OutputFilenames, OutputType, PpMode, PpSourceMode}; @@ -819,7 +819,9 @@ pub fn create_global_ctxt<'tcx>( callback(sess, &mut local_providers, &mut extern_providers); } - let queries = queries.get_or_init(|| TcxQueries::new(local_providers, extern_providers)); + let queries = queries.get_or_init(|| { + TcxQueries::new(local_providers, extern_providers, query_result_on_disk_cache) + }); let gcx = sess.time("setup_global_ctxt", || { global_ctxt.get_or_init(move || { @@ -830,7 +832,7 @@ pub fn create_global_ctxt<'tcx>( resolver_outputs, krate, dep_graph, - query_result_on_disk_cache, + queries.on_disk_cache.as_ref().map(OnDiskCache::as_dyn), queries.as_dyn(), &crate_name, outputs, diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs index 4f51ce620427b..8b41a0ff17693 100644 --- a/compiler/rustc_interface/src/util.rs +++ b/compiler/rustc_interface/src/util.rs @@ -10,6 +10,8 @@ use rustc_errors::registry::Registry; use rustc_metadata::dynamic_lib::DynamicLibrary; #[cfg(parallel_compiler)] use rustc_middle::ty::tls; +#[cfg(parallel_compiler)] +use rustc_query_impl::QueryCtxt; use rustc_resolve::{self, Resolver}; use rustc_session as session; use rustc_session::config::{self, CrateType}; @@ -176,7 +178,7 @@ unsafe fn handle_deadlock() { thread::spawn(move || { tls::enter_context(icx, |_| { rustc_span::set_session_globals_then(session_globals, || { - tls::with(|tcx| tcx.queries.deadlock(tcx, ®istry)) + tls::with(|tcx| QueryCtxt::from_tcx(tcx).deadlock(®istry)) }) }); }); diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index ccdbccae156c3..a955ed4ea64f0 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -155,8 +155,8 @@ declare_lint! { declare_lint_pass!(BoxPointers => [BOX_POINTERS]); impl BoxPointers { - fn check_heap_type(&self, cx: &LateContext<'_>, span: Span, ty: Ty<'_>) { - for leaf in ty.walk() { + fn check_heap_type<'tcx>(&self, cx: &LateContext<'tcx>, span: Span, ty: Ty<'tcx>) { + for leaf in ty.walk(cx.tcx) { if let GenericArgKind::Type(leaf_ty) = leaf.unpack() { if leaf_ty.is_box() { cx.struct_span_lint(BOX_POINTERS, span, |lint| { @@ -1614,7 +1614,7 @@ impl<'tcx> LateLintPass<'tcx> for TrivialConstraints { ConstEquate(..) | TypeWellFormedFromEnv(..) => continue, }; - if predicate.is_global() { + if predicate.is_global(cx.tcx) { cx.struct_span_lint(TRIVIAL_BOUNDS, span, |lint| { lint.build(&format!( "{} bound {} does not depend on any type \ diff --git a/compiler/rustc_lint/src/early.rs b/compiler/rustc_lint/src/early.rs index eb2e495f73d3c..7a8b731da5c2e 100644 --- a/compiler/rustc_lint/src/early.rs +++ b/compiler/rustc_lint/src/early.rs @@ -120,6 +120,12 @@ impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T> }) } + fn visit_expr_field(&mut self, f: &'a ast::ExprField) { + self.with_lint_attrs(f.id, &f.attrs, |cx| { + ast_visit::walk_expr_field(cx, f); + }) + } + fn visit_stmt(&mut self, s: &'a ast::Stmt) { // Add the statement's lint attributes to our // current state when checking the statement itself. @@ -204,8 +210,10 @@ impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T> } fn visit_arm(&mut self, a: &'a ast::Arm) { - run_early_pass!(self, check_arm, a); - ast_visit::walk_arm(self, a); + self.with_lint_attrs(a.id, &a.attrs, |cx| { + run_early_pass!(cx, check_arm, a); + ast_visit::walk_arm(cx, a); + }) } fn visit_expr_post(&mut self, e: &'a ast::Expr) { @@ -389,9 +397,15 @@ pub fn check_ast_crate( // All of the buffered lints should have been emitted at this point. // If not, that means that we somehow buffered a lint for a node id // that was not lint-checked (perhaps it doesn't exist?). This is a bug. - for (_id, lints) in buffered.map { + for (id, lints) in buffered.map { for early_lint in lints { - sess.delay_span_bug(early_lint.span, "failed to process buffered lint here"); + sess.delay_span_bug( + early_lint.span, + &format!( + "failed to process buffered lint here (dummy = {})", + id == ast::DUMMY_NODE_ID + ), + ); } } } diff --git a/compiler/rustc_lint/src/noop_method_call.rs b/compiler/rustc_lint/src/noop_method_call.rs index 479cc00199f6a..908d847915f88 100644 --- a/compiler/rustc_lint/src/noop_method_call.rs +++ b/compiler/rustc_lint/src/noop_method_call.rs @@ -62,7 +62,7 @@ impl<'tcx> LateLintPass<'tcx> for NoopMethodCall { _ => return, }; let substs = cx.typeck_results().node_substs(expr.hir_id); - if substs.needs_subst() { + if substs.needs_subst(cx.tcx) { // We can't resolve on types that require monomorphization, so we don't handle them if // we need to perfom substitution. return; diff --git a/compiler/rustc_lint/src/traits.rs b/compiler/rustc_lint/src/traits.rs index e632f29e672c0..e713ce7c71bec 100644 --- a/compiler/rustc_lint/src/traits.rs +++ b/compiler/rustc_lint/src/traits.rs @@ -37,10 +37,47 @@ declare_lint! { "bounds of the form `T: Drop` are useless" } +declare_lint! { + /// The `dyn_drop` lint checks for trait objects with `std::ops::Drop`. + /// + /// ### Example + /// + /// ```rust + /// fn foo(_x: Box) {} + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// A trait object bound of the form `dyn Drop` is most likely misleading + /// and not what the programmer intended. + /// + /// `Drop` bounds do not actually indicate whether a type can be trivially + /// dropped or not, because a composite type containing `Drop` types does + /// not necessarily implement `Drop` itself. Naïvely, one might be tempted + /// to write a deferred drop system, to pull cleaning up memory out of a + /// latency-sensitive code path, using `dyn Drop` trait objects. However, + /// this breaks down e.g. when `T` is `String`, which does not implement + /// `Drop`, but should probably be accepted. + /// + /// To write a trait object bound that accepts anything, use a placeholder + /// trait with a blanket implementation. + /// + /// ```rust + /// trait Placeholder {} + /// impl Placeholder for T {} + /// fn foo(_x: Box) {} + /// ``` + pub DYN_DROP, + Warn, + "trait objects of the form `dyn Drop` are useless" +} + declare_lint_pass!( /// Lint for bounds of the form `T: Drop`, which usually /// indicate an attempt to emulate `std::mem::needs_drop`. - DropTraitConstraints => [DROP_BOUNDS] + DropTraitConstraints => [DROP_BOUNDS, DYN_DROP] ); impl<'tcx> LateLintPass<'tcx> for DropTraitConstraints { @@ -75,4 +112,28 @@ impl<'tcx> LateLintPass<'tcx> for DropTraitConstraints { } } } + + fn check_ty(&mut self, cx: &LateContext<'_>, ty: &'tcx hir::Ty<'tcx>) { + let bounds = match &ty.kind { + hir::TyKind::TraitObject(bounds, _lifetime, _syntax) => bounds, + _ => return, + }; + for bound in &bounds[..] { + let def_id = bound.trait_ref.trait_def_id(); + if cx.tcx.lang_items().drop_trait() == def_id { + cx.struct_span_lint(DYN_DROP, bound.span, |lint| { + let needs_drop = match cx.tcx.get_diagnostic_item(sym::needs_drop) { + Some(needs_drop) => needs_drop, + None => return, + }; + let msg = format!( + "types that do not implement `Drop` can still have drop glue, consider \ + instead using `{}` to detect whether a type is trivially dropped", + cx.tcx.def_path_str(needs_drop) + ); + lint.build(&msg).emit() + }); + } + } + } } diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index a3a87a48768dc..794e6cb0ba3e1 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -1160,6 +1160,9 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { impl<'a, 'tcx> ty::fold::TypeVisitor<'tcx> for ProhibitOpaqueTypes<'a, 'tcx> { type BreakTy = Ty<'tcx>; + fn tcx_for_anon_const_substs(&self) -> Option> { + Some(self.cx.tcx) + } fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow { match ty.kind() { diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index 001198226d9a3..4d85bf6b499d9 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -274,7 +274,7 @@ impl ToStableHashKey for LintId { } // Duplicated from rustc_session::config::ExternDepSpec to avoid cyclic dependency -#[derive(PartialEq)] +#[derive(PartialEq, Debug)] pub enum ExternDepSpec { Json(Json), Raw(String), @@ -282,7 +282,7 @@ pub enum ExternDepSpec { // This could be a closure, but then implementing derive trait // becomes hacky (and it gets allocated). -#[derive(PartialEq)] +#[derive(PartialEq, Debug)] pub enum BuiltinLintDiagnostics { Normal, BareTraitObject(Span, /* is_global */ bool), diff --git a/compiler/rustc_macros/src/query.rs b/compiler/rustc_macros/src/query.rs index 291e7ef045e4f..dcd36d61bc6a0 100644 --- a/compiler/rustc_macros/src/query.rs +++ b/compiler/rustc_macros/src/query.rs @@ -367,7 +367,7 @@ fn add_query_description_impl( tcx: QueryCtxt<'tcx>, id: SerializedDepNodeIndex ) -> Option { - tcx.on_disk_cache.as_ref()?.try_load_query_result(*tcx, id) + tcx.on_disk_cache().as_ref()?.try_load_query_result(*tcx, id) } } }; diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs index 70b3efa1d1690..5373169bda7ab 100644 --- a/compiler/rustc_metadata/src/creader.rs +++ b/compiler/rustc_metadata/src/creader.rs @@ -131,7 +131,10 @@ impl<'a> std::fmt::Debug for CrateDump<'a> { impl CStore { pub fn from_tcx(tcx: TyCtxt<'_>) -> &CStore { - tcx.cstore_as_any().downcast_ref::().expect("`tcx.cstore` is not a `CStore`") + tcx.cstore_untracked() + .as_any() + .downcast_ref::() + .expect("`tcx.cstore` is not a `CStore`") } fn alloc_new_crate_num(&mut self) -> CrateNum { diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index d28ebfe107cdd..8bdd4313de4c3 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -30,13 +30,12 @@ use rustc_middle::ty::codec::TyDecoder; use rustc_middle::ty::{self, Ty, TyCtxt, Visibility}; use rustc_serialize::{opaque, Decodable, Decoder}; use rustc_session::Session; -use rustc_span::hygiene::ExpnDataDecodeMode; +use rustc_span::hygiene::{ExpnIndex, MacroKind}; use rustc_span::source_map::{respan, Spanned}; use rustc_span::symbol::{sym, Ident, Symbol}; -use rustc_span::{self, hygiene::MacroKind, BytePos, ExpnId, Pos, Span, SyntaxContext, DUMMY_SP}; +use rustc_span::{self, BytePos, ExpnId, Pos, Span, SyntaxContext, DUMMY_SP}; use proc_macro::bridge::client::ProcMacro; -use std::cell::Cell; use std::io; use std::mem; use std::num::NonZeroUsize; @@ -80,6 +79,8 @@ crate struct CrateMetadata { /// `DefIndex`. See `raw_def_id_to_def_id` for more details about how /// this is used. def_path_hash_map: OnceCell>, + /// Likewise for ExpnHash. + expn_hash_map: OnceCell>, /// Used for decoding interpret::AllocIds in a cached & thread-safe manner. alloc_decoding_state: AllocDecodingState, /// Caches decoded `DefKey`s. @@ -350,6 +351,12 @@ impl<'a, 'tcx> Decodable> for DefIndex { } } +impl<'a, 'tcx> Decodable> for ExpnIndex { + fn decode(d: &mut DecodeContext<'a, 'tcx>) -> Result { + Ok(ExpnIndex::from_u32(d.read_u32()?)) + } +} + impl<'a, 'tcx> Decodable> for SyntaxContext { fn decode(decoder: &mut DecodeContext<'a, 'tcx>) -> Result { let cdata = decoder.cdata(); @@ -371,43 +378,35 @@ impl<'a, 'tcx> Decodable> for ExpnId { fn decode(decoder: &mut DecodeContext<'a, 'tcx>) -> Result { let local_cdata = decoder.cdata(); let sess = decoder.sess.unwrap(); - let expn_cnum = Cell::new(None); - let get_ctxt = |cnum| { - expn_cnum.set(Some(cnum)); - if cnum == LOCAL_CRATE { - &local_cdata.hygiene_context - } else { - &local_cdata.cstore.get_crate_data(cnum).cdata.hygiene_context - } - }; - rustc_span::hygiene::decode_expn_id( - decoder, - ExpnDataDecodeMode::Metadata(get_ctxt), - |_this, index| { - let cnum = expn_cnum.get().unwrap(); - // Lookup local `ExpnData`s in our own crate data. Foreign `ExpnData`s - // are stored in the owning crate, to avoid duplication. - let crate_data = if cnum == LOCAL_CRATE { - local_cdata - } else { - local_cdata.cstore.get_crate_data(cnum) - }; - let expn_data = crate_data - .root - .expn_data - .get(&crate_data, index) - .unwrap() - .decode((&crate_data, sess)); - let expn_hash = crate_data - .root - .expn_hashes - .get(&crate_data, index) - .unwrap() - .decode((&crate_data, sess)); - Ok((expn_data, expn_hash)) - }, - ) + let cnum = CrateNum::decode(decoder)?; + let index = u32::decode(decoder)?; + + let expn_id = rustc_span::hygiene::decode_expn_id(cnum, index, |expn_id| { + let ExpnId { krate: cnum, local_id: index } = expn_id; + // Lookup local `ExpnData`s in our own crate data. Foreign `ExpnData`s + // are stored in the owning crate, to avoid duplication. + debug_assert_ne!(cnum, LOCAL_CRATE); + let crate_data = if cnum == local_cdata.cnum { + local_cdata + } else { + local_cdata.cstore.get_crate_data(cnum) + }; + let expn_data = crate_data + .root + .expn_data + .get(&crate_data, index) + .unwrap() + .decode((&crate_data, sess)); + let expn_hash = crate_data + .root + .expn_hashes + .get(&crate_data, index) + .unwrap() + .decode((&crate_data, sess)); + (expn_data, expn_hash) + }); + Ok(expn_id) } } @@ -1622,6 +1621,41 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { self.def_path_hash_unlocked(index, &mut def_path_hashes) } + fn expn_hash_to_expn_id(&self, index_guess: u32, hash: ExpnHash) -> ExpnId { + debug_assert_eq!(ExpnId::from_hash(hash), None); + let index_guess = ExpnIndex::from_u32(index_guess); + let old_hash = self.root.expn_hashes.get(self, index_guess).map(|lazy| lazy.decode(self)); + + let index = if old_hash == Some(hash) { + // Fast path: the expn and its index is unchanged from the + // previous compilation session. There is no need to decode anything + // else. + index_guess + } else { + // Slow path: We need to find out the new `DefIndex` of the provided + // `DefPathHash`, if its still exists. This requires decoding every `DefPathHash` + // stored in this crate. + let map = self.cdata.expn_hash_map.get_or_init(|| { + let end_id = self.root.expn_hashes.size() as u32; + let mut map = + UnhashMap::with_capacity_and_hasher(end_id as usize, Default::default()); + for i in 0..end_id { + let i = ExpnIndex::from_u32(i); + if let Some(hash) = self.root.expn_hashes.get(self, i) { + map.insert(hash.decode(self), i); + } else { + panic!("Missing expn_hash entry for {:?}", i); + } + } + map + }); + map[&hash] + }; + + let data = self.root.expn_data.get(self, index).unwrap().decode(self); + rustc_span::hygiene::register_expn_id(self.cnum, index, data, hash) + } + /// Imports the source_map from an external crate into the source_map of the crate /// currently being compiled (the "local crate"). /// @@ -1860,6 +1894,7 @@ impl CrateMetadata { raw_proc_macros, source_map_import_info: OnceCell::new(), def_path_hash_map: Default::default(), + expn_hash_map: Default::default(), alloc_decoding_state, cnum, cnum_map, diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index ce8dfeae076e6..41839c58021ab 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -18,11 +18,11 @@ use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, TyCtxt, Visibility}; use rustc_session::utils::NativeLibKind; use rustc_session::{Session, StableCrateId}; +use rustc_span::hygiene::{ExpnHash, ExpnId}; use rustc_span::source_map::{Span, Spanned}; use rustc_span::symbol::Symbol; use rustc_data_structures::sync::Lrc; -use rustc_span::ExpnId; use smallvec::SmallVec; use std::any::Any; @@ -528,6 +528,10 @@ impl CrateStore for CStore { self.get_crate_data(cnum).def_path_hash_to_def_id(cnum, index_guess, hash) } + fn expn_hash_to_expn_id(&self, cnum: CrateNum, index_guess: u32, hash: ExpnHash) -> ExpnId { + self.get_crate_data(cnum).expn_hash_to_expn_id(index_guess, hash) + } + fn encode_metadata(&self, tcx: TyCtxt<'_>) -> EncodedMetadata { encoder::encode_metadata(tcx) } diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 5c7d84e2bc97f..a4913a32e81ef 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -31,7 +31,7 @@ use rustc_session::config::CrateType; use rustc_span::symbol::{sym, Ident, Symbol}; use rustc_span::{self, ExternalSource, FileName, SourceFile, Span, SyntaxContext}; use rustc_span::{ - hygiene::{ExpnDataEncodeMode, HygieneEncodeContext, MacroKind}, + hygiene::{ExpnIndex, HygieneEncodeContext, MacroKind}, RealFileName, }; use rustc_target::abi::VariantIdx; @@ -168,6 +168,12 @@ impl<'a, 'tcx> Encodable> for DefIndex { } } +impl<'a, 'tcx> Encodable> for ExpnIndex { + fn encode(&self, s: &mut EncodeContext<'a, 'tcx>) -> opaque::EncodeResult { + s.emit_u32(self.as_u32()) + } +} + impl<'a, 'tcx> Encodable> for SyntaxContext { fn encode(&self, s: &mut EncodeContext<'a, 'tcx>) -> opaque::EncodeResult { rustc_span::hygiene::raw_encode_syntax_context(*self, &s.hygiene_ctxt, s) @@ -176,12 +182,15 @@ impl<'a, 'tcx> Encodable> for SyntaxContext { impl<'a, 'tcx> Encodable> for ExpnId { fn encode(&self, s: &mut EncodeContext<'a, 'tcx>) -> opaque::EncodeResult { - rustc_span::hygiene::raw_encode_expn_id( - *self, - &s.hygiene_ctxt, - ExpnDataEncodeMode::Metadata, - s, - ) + if self.krate == LOCAL_CRATE { + // We will only write details for local expansions. Non-local expansions will fetch + // data from the corresponding crate's metadata. + // FIXME(#43047) FIXME(#74731) We may eventually want to avoid relying on external + // metadata from proc-macro crates. + s.hygiene_ctxt.schedule_expn_data_for_encoding(*self); + } + self.krate.encode(s)?; + self.local_id.encode(s) } } @@ -1572,7 +1581,7 @@ impl EncodeContext<'a, 'tcx> { fn encode_native_libraries(&mut self) -> Lazy<[NativeLib]> { empty_proc_macro!(self); let used_libraries = self.tcx.native_libraries(LOCAL_CRATE); - self.lazy(used_libraries.iter().cloned()) + self.lazy(used_libraries.iter()) } fn encode_foreign_modules(&mut self) -> Lazy<[ForeignModule]> { @@ -1593,8 +1602,10 @@ impl EncodeContext<'a, 'tcx> { Ok(()) }, |(this, _, expn_data_table, expn_hash_table), index, expn_data, hash| { - expn_data_table.set(index, this.lazy(expn_data)); - expn_hash_table.set(index, this.lazy(hash)); + if let Some(index) = index.as_local() { + expn_data_table.set(index.as_raw(), this.lazy(expn_data)); + expn_hash_table.set(index.as_raw(), this.lazy(hash)); + } Ok(()) }, ); diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index f2ebfb9b725ba..a487753f4628a 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -19,7 +19,7 @@ use rustc_middle::ty::{self, ReprOptions, Ty}; use rustc_serialize::opaque::Encoder; use rustc_session::config::SymbolManglingVersion; use rustc_span::edition::Edition; -use rustc_span::hygiene::MacroKind; +use rustc_span::hygiene::{ExpnIndex, MacroKind}; use rustc_span::symbol::{Ident, Symbol}; use rustc_span::{self, ExpnData, ExpnHash, ExpnId, Span}; use rustc_target::spec::{PanicStrategy, TargetTriple}; @@ -170,8 +170,8 @@ macro_rules! Lazy { } type SyntaxContextTable = Lazy>>; -type ExpnDataTable = Lazy>>; -type ExpnHashTable = Lazy>>; +type ExpnDataTable = Lazy>>; +type ExpnHashTable = Lazy>>; #[derive(MetadataEncodable, MetadataDecodable)] crate struct ProcMacroData { diff --git a/compiler/rustc_middle/src/middle/cstore.rs b/compiler/rustc_middle/src/middle/cstore.rs index 7efe8e061e885..8150e67929509 100644 --- a/compiler/rustc_middle/src/middle/cstore.rs +++ b/compiler/rustc_middle/src/middle/cstore.rs @@ -6,12 +6,12 @@ use crate::ty::TyCtxt; use rustc_ast as ast; use rustc_data_structures::sync::{self, MetadataRef}; -use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; +use rustc_hir::def_id::{CrateNum, DefId, StableCrateId, LOCAL_CRATE}; use rustc_hir::definitions::{DefKey, DefPath, DefPathHash}; use rustc_macros::HashStable; use rustc_session::search_paths::PathKind; use rustc_session::utils::NativeLibKind; -use rustc_session::StableCrateId; +use rustc_span::hygiene::{ExpnHash, ExpnId}; use rustc_span::symbol::Symbol; use rustc_span::Span; use rustc_target::spec::Target; @@ -64,7 +64,7 @@ pub enum LinkagePreference { RequireStatic, } -#[derive(Clone, Debug, Encodable, Decodable, HashStable)] +#[derive(Debug, Encodable, Decodable, HashStable)] pub struct NativeLib { pub kind: NativeLibKind, pub name: Option, @@ -75,7 +75,7 @@ pub struct NativeLib { pub dll_imports: Vec, } -#[derive(Clone, Debug, PartialEq, Eq, Encodable, Decodable, Hash, HashStable)] +#[derive(Clone, Debug, Encodable, Decodable, HashStable)] pub struct DllImport { pub name: Symbol, pub ordinal: Option, @@ -92,7 +92,7 @@ pub struct DllImport { /// /// The usize value, where present, indicates the size of the function's argument list /// in bytes. -#[derive(Copy, Clone, Debug, PartialEq, Eq, Encodable, Decodable, Hash, HashStable)] +#[derive(Clone, PartialEq, Debug, Encodable, Decodable, HashStable)] pub enum DllCallingConvention { C, Stdcall(usize), @@ -207,6 +207,7 @@ pub trait CrateStore: std::fmt::Debug { index_guess: u32, hash: DefPathHash, ) -> Option; + fn expn_hash_to_expn_id(&self, cnum: CrateNum, index_guess: u32, hash: ExpnHash) -> ExpnId; // utility functions fn encode_metadata(&self, tcx: TyCtxt<'_>) -> EncodedMetadata; diff --git a/compiler/rustc_middle/src/mir/interpret/queries.rs b/compiler/rustc_middle/src/mir/interpret/queries.rs index fa7c0670e8ce6..c63613ae3af29 100644 --- a/compiler/rustc_middle/src/mir/interpret/queries.rs +++ b/compiler/rustc_middle/src/mir/interpret/queries.rs @@ -38,7 +38,7 @@ impl<'tcx> TyCtxt<'tcx> { ct: ty::Unevaluated<'tcx>, span: Option, ) -> EvalToConstValueResult<'tcx> { - match ty::Instance::resolve_opt_const_arg(self, param_env, ct.def, ct.substs) { + match ty::Instance::resolve_opt_const_arg(self, param_env, ct.def, ct.substs(self)) { Ok(Some(instance)) => { let cid = GlobalId { instance, promoted: ct.promoted }; self.const_eval_global_id(param_env, cid, span) diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index da0d2575dcbe3..cac2f9b2fe9d0 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -242,6 +242,7 @@ pub struct Body<'tcx> { impl<'tcx> Body<'tcx> { pub fn new( + tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, basic_blocks: IndexVec>, source_scopes: IndexVec>, @@ -284,7 +285,7 @@ impl<'tcx> Body<'tcx> { predecessor_cache: PredecessorCache::new(), is_cyclic: GraphIsCyclicCache::new(), }; - body.is_polymorphic = body.has_param_types_or_consts(); + body.is_polymorphic = body.has_param_types_or_consts(tcx); body } @@ -293,7 +294,10 @@ impl<'tcx> Body<'tcx> { /// The returned MIR contains no `LocalDecl`s (even for the return place) or source scopes. It /// is only useful for testing but cannot be `#[cfg(test)]` because it is used in a different /// crate. - pub fn new_cfg_only(basic_blocks: IndexVec>) -> Self { + pub fn new_cfg_only( + tcx: TyCtxt<'tcx>, + basic_blocks: IndexVec>, + ) -> Self { let mut body = Body { phase: MirPhase::Build, source: MirSource::item(DefId::local(CRATE_DEF_INDEX)), @@ -311,7 +315,7 @@ impl<'tcx> Body<'tcx> { predecessor_cache: PredecessorCache::new(), is_cyclic: GraphIsCyclicCache::new(), }; - body.is_polymorphic = body.has_param_types_or_consts(); + body.is_polymorphic = body.has_param_types_or_consts(tcx); body } diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 1651853a55205..54f4745c6f3db 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -114,6 +114,10 @@ rustc_queries! { desc { |tcx| "compute const default for a given parameter `{}`", tcx.def_path_str(param) } } + query default_anon_const_substs(key: DefId) -> SubstsRef<'tcx> { + desc { |tcx| "computing the default generic arguments for `{}`", tcx.def_path_str(key) } + } + /// Records the type of every item. query type_of(key: DefId) -> Ty<'tcx> { desc { |tcx| "computing type of `{}`", tcx.def_path_str(key) } @@ -293,12 +297,11 @@ rustc_queries! { } query try_unify_abstract_consts(key: ( - (ty::WithOptConstParam, SubstsRef<'tcx>), - (ty::WithOptConstParam, SubstsRef<'tcx>) + ty::Unevaluated<'tcx>, ty::Unevaluated<'tcx> )) -> bool { desc { |tcx| "trying to unify the generic constants {} and {}", - tcx.def_path_str(key.0.0.did), tcx.def_path_str(key.1.0.did) + tcx.def_path_str(key.0.def.did), tcx.def_path_str(key.1.def.did) } } @@ -724,7 +727,7 @@ rustc_queries! { cache_on_disk_if { true } load_cached(tcx, id) { let typeck_results: Option> = tcx - .on_disk_cache.as_ref() + .on_disk_cache().as_ref() .and_then(|c| c.try_load_query_result(*tcx, id)); typeck_results.map(|x| &*tcx.arena.alloc(x)) diff --git a/compiler/rustc_middle/src/ty/closure.rs b/compiler/rustc_middle/src/ty/closure.rs index b0156daf17eff..6b51adc6aafdd 100644 --- a/compiler/rustc_middle/src/ty/closure.rs +++ b/compiler/rustc_middle/src/ty/closure.rs @@ -281,11 +281,10 @@ pub struct CaptureInfo<'tcx> { } pub fn place_to_string_for_capture(tcx: TyCtxt<'tcx>, place: &HirPlace<'tcx>) -> String { - let name = match place.base { + let mut curr_string: String = match place.base { HirPlaceBase::Upvar(upvar_id) => tcx.hir().name(upvar_id.var_path.hir_id).to_string(), _ => bug!("Capture_information should only contain upvars"), }; - let mut curr_string = name; for (i, proj) in place.projections.iter().enumerate() { match proj.kind { @@ -314,7 +313,7 @@ pub fn place_to_string_for_capture(tcx: TyCtxt<'tcx>, place: &HirPlace<'tcx>) -> } } - curr_string.to_string() + curr_string } #[derive(Clone, PartialEq, Debug, TyEncodable, TyDecodable, TypeFoldable, Copy, HashStable)] diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs index c78151271c171..869b2ab9dbcbc 100644 --- a/compiler/rustc_middle/src/ty/consts.rs +++ b/compiler/rustc_middle/src/ty/consts.rs @@ -1,6 +1,5 @@ use crate::mir::interpret::ConstValue; use crate::mir::interpret::{LitToConstInput, Scalar}; -use crate::ty::subst::InternalSubsts; use crate::ty::{self, Ty, TyCtxt}; use crate::ty::{ParamEnv, ParamEnvAnd}; use rustc_errors::ErrorReported; @@ -100,7 +99,7 @@ impl<'tcx> Const<'tcx> { } _ => ty::ConstKind::Unevaluated(ty::Unevaluated { def: def.to_global(), - substs: InternalSubsts::identity_for_item(tcx, def.did.to_def_id()), + substs_: None, promoted: None, }), }; diff --git a/compiler/rustc_middle/src/ty/consts/kind.rs b/compiler/rustc_middle/src/ty/consts/kind.rs index f2db95d162b88..b1f6a61277662 100644 --- a/compiler/rustc_middle/src/ty/consts/kind.rs +++ b/compiler/rustc_middle/src/ty/consts/kind.rs @@ -12,14 +12,33 @@ use rustc_target::abi::Size; use super::ScalarInt; /// An unevaluated, potentially generic, constant. -#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable)] +/// +/// If `substs_` is `None` it means that this anon const +/// still has its default substs. +/// +/// We check for all possible substs in `fn default_anon_const_substs`, +/// so refer to that check for more info. +#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable, Lift)] #[derive(Hash, HashStable)] pub struct Unevaluated<'tcx> { pub def: ty::WithOptConstParam, - pub substs: SubstsRef<'tcx>, + pub substs_: Option>, pub promoted: Option, } +impl<'tcx> Unevaluated<'tcx> { + pub fn new(def: ty::WithOptConstParam, substs: SubstsRef<'tcx>) -> Unevaluated<'tcx> { + Unevaluated { def, substs_: Some(substs), promoted: None } + } + + pub fn substs(self, tcx: TyCtxt<'tcx>) -> SubstsRef<'tcx> { + self.substs_.unwrap_or_else(|| { + debug_assert_eq!(self.promoted, None); + tcx.default_anon_const_substs(self.def.did) + }) + } +} + /// Represents a constant in Rust. #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable)] #[derive(Hash, HashStable)] @@ -109,7 +128,7 @@ impl<'tcx> ConstKind<'tcx> { tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, ) -> Option, ErrorReported>> { - if let ConstKind::Unevaluated(Unevaluated { def, substs, promoted }) = self { + if let ConstKind::Unevaluated(unevaluated) = self { use crate::mir::interpret::ErrorHandled; // HACK(eddyb) this erases lifetimes even though `const_eval_resolve` @@ -118,29 +137,32 @@ impl<'tcx> ConstKind<'tcx> { // Note that we erase regions *before* calling `with_reveal_all_normalized`, // so that we don't try to invoke this query with // any region variables. - let param_env_and_substs = tcx + let param_env_and = tcx .erase_regions(param_env) .with_reveal_all_normalized(tcx) - .and(tcx.erase_regions(substs)); + .and(tcx.erase_regions(unevaluated)); // HACK(eddyb) when the query key would contain inference variables, // attempt using identity substs and `ParamEnv` instead, that will succeed // when the expression doesn't depend on any parameters. // FIXME(eddyb, skinny121) pass `InferCtxt` into here when it's available, so that // we can call `infcx.const_eval_resolve` which handles inference variables. - let param_env_and_substs = if param_env_and_substs.needs_infer() { - tcx.param_env(def.did).and(InternalSubsts::identity_for_item(tcx, def.did)) + let param_env_and = if param_env_and.needs_infer() { + tcx.param_env(unevaluated.def.did).and(ty::Unevaluated { + def: unevaluated.def, + substs_: Some(InternalSubsts::identity_for_item(tcx, unevaluated.def.did)), + promoted: unevaluated.promoted, + }) } else { - param_env_and_substs + param_env_and }; // FIXME(eddyb) maybe the `const_eval_*` methods should take - // `ty::ParamEnvAnd` instead of having them separate. - let (param_env, substs) = param_env_and_substs.into_parts(); + // `ty::ParamEnvAnd` instead of having them separate. + let (param_env, unevaluated) = param_env_and.into_parts(); // try to resolve e.g. associated constants to their definition on an impl, and then // evaluate the const. - match tcx.const_eval_resolve(param_env, ty::Unevaluated { def, substs, promoted }, None) - { + match tcx.const_eval_resolve(param_env, unevaluated, None) { // NOTE(eddyb) `val` contains no lifetimes/types/consts, // and we use the original type, so nothing from `substs` // (which may be identity substs, see above), diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index f52686c9b5f2e..b84058011066f 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -1,7 +1,7 @@ //! Type context book-keeping. use crate::arena::Arena; -use crate::dep_graph::DepGraph; +use crate::dep_graph::{DepGraph, DepNode}; use crate::hir::place::Place as HirPlace; use crate::ich::{NodeIdHashingMode, StableHashingContext}; use crate::infer::canonical::{Canonical, CanonicalVarInfo, CanonicalVarInfos}; @@ -14,7 +14,7 @@ use crate::mir::interpret::{self, AllocId, Allocation, ConstValue, Scalar}; use crate::mir::{Body, Field, Local, Place, PlaceElem, ProjectionKind, Promoted}; use crate::thir::Thir; use crate::traits; -use crate::ty::query::{self, OnDiskCache, TyCtxtAt}; +use crate::ty::query::{self, TyCtxtAt}; use crate::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, Subst, SubstsRef, UserSubsts}; use crate::ty::TyKind::*; use crate::ty::{ @@ -52,8 +52,8 @@ use rustc_session::config::{BorrowckMode, CrateType, OutputFilenames}; use rustc_session::lint::{Level, Lint}; use rustc_session::Limit; use rustc_session::Session; -use rustc_span::def_id::StableCrateId; -use rustc_span::source_map::MultiSpan; +use rustc_span::def_id::{DefPathHash, StableCrateId}; +use rustc_span::source_map::{MultiSpan, SourceMap}; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{Span, DUMMY_SP}; use rustc_target::abi::{Layout, TargetDataLayout, VariantIdx}; @@ -71,6 +71,40 @@ use std::mem; use std::ops::{Bound, Deref}; 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, start_pos: usize) -> Self + where + Self: Sized; + + fn new_empty(source_map: &'tcx SourceMap) -> Self + where + Self: Sized; + + /// Converts a `DefPathHash` to its corresponding `DefId` in the current compilation + /// session, if it still exists. This is used during incremental compilation to + /// turn a deserialized `DefPathHash` into its current `DefId`. + fn def_path_hash_to_def_id( + &self, + tcx: TyCtxt<'tcx>, + def_path_hash: DefPathHash, + ) -> Option; + + /// If the given `dep_node`'s hash still exists in the current compilation, + /// and its current `DefId` is foreign, calls `store_foreign_def_id` with it. + /// + /// Normally, `store_foreign_def_id_hash` can be called directly by + /// the dependency graph when we construct a `DepNode`. However, + /// when we re-use a deserialized `DepNode` from the previous compilation + /// session, we only have the `DefPathHash` available. This method is used + /// to that any `DepNode` that we re-use has a `DefPathHash` -> `RawId` written + /// out for usage in the next compilation session. + 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 serialize(&self, tcx: TyCtxt<'tcx>, encoder: &mut FileEncoder) -> FileEncodeResult; +} + /// A type that is not publicly constructable. This prevents people from making [`TyKind::Error`]s /// except through the error-reporting functions on a [`tcx`][TyCtxt]. #[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)] @@ -993,7 +1027,7 @@ pub struct GlobalCtxt<'tcx> { /// Do not access this directly. It is only meant to be used by /// `DepGraph::try_mark_green()` and the query infrastructure. /// This is `None` if we are not incremental compilation mode - pub on_disk_cache: Option>, + pub on_disk_cache: Option<&'tcx dyn OnDiskCache<'tcx>>, pub queries: &'tcx dyn query::QueryEngine<'tcx>, pub query_caches: query::QueryCaches<'tcx>, @@ -1141,7 +1175,7 @@ impl<'tcx> TyCtxt<'tcx> { resolutions: ty::ResolverOutputs, krate: &'tcx hir::Crate<'tcx>, dep_graph: DepGraph, - on_disk_cache: Option>, + on_disk_cache: Option<&'tcx dyn OnDiskCache<'tcx>>, queries: &'tcx dyn query::QueryEngine<'tcx>, crate_name: &str, output_filenames: OutputFilenames, @@ -1308,10 +1342,16 @@ impl<'tcx> TyCtxt<'tcx> { self.untracked_resolutions.cstore.encode_metadata(self) } - // Note that this is *untracked* and should only be used within the query - // system if the result is otherwise tracked through queries - pub fn cstore_as_any(self) -> &'tcx dyn Any { - self.untracked_resolutions.cstore.as_any() + /// Note that this is *untracked* and should only be used within the query + /// system if the result is otherwise tracked through queries + pub fn cstore_untracked(self) -> &'tcx ty::CrateStoreDyn { + &*self.untracked_resolutions.cstore + } + + /// Note that this is *untracked* and should only be used within the query + /// system if the result is otherwise tracked through queries + pub fn definitions_untracked(self) -> &'tcx hir::definitions::Definitions { + &self.untracked_resolutions.definitions } #[inline(always)] diff --git a/compiler/rustc_middle/src/ty/erase_regions.rs b/compiler/rustc_middle/src/ty/erase_regions.rs index 759d1a017aa2a..63eb55ed1a620 100644 --- a/compiler/rustc_middle/src/ty/erase_regions.rs +++ b/compiler/rustc_middle/src/ty/erase_regions.rs @@ -21,7 +21,9 @@ impl<'tcx> TyCtxt<'tcx> { T: TypeFoldable<'tcx>, { // If there's nothing to erase avoid performing the query at all - if !value.has_type_flags(TypeFlags::HAS_RE_LATE_BOUND | TypeFlags::HAS_FREE_REGIONS) { + if !value + .has_type_flags(TypeFlags::HAS_RE_LATE_BOUND | TypeFlags::HAS_POTENTIAL_FREE_REGIONS) + { return value; } debug!("erase_regions({:?})", value); diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs index 9faa172a4973f..31f299604b9ba 100644 --- a/compiler/rustc_middle/src/ty/flags.rs +++ b/compiler/rustc_middle/src/ty/flags.rs @@ -34,6 +34,12 @@ impl FlagComputation { result.flags } + pub fn for_unevaluated_const(uv: ty::Unevaluated<'_>) -> TypeFlags { + let mut result = FlagComputation::new(); + result.add_unevaluated_const(uv); + result.flags + } + fn add_flags(&mut self, flags: TypeFlags) { self.flags = self.flags | flags; } @@ -91,7 +97,7 @@ impl FlagComputation { &ty::Error(_) => self.add_flags(TypeFlags::HAS_ERROR), &ty::Param(_) => { - self.add_flags(TypeFlags::HAS_TY_PARAM); + self.add_flags(TypeFlags::HAS_KNOWN_TY_PARAM); self.add_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE); } @@ -242,8 +248,8 @@ impl FlagComputation { ty::PredicateKind::ClosureKind(_def_id, substs, _kind) => { self.add_substs(substs); } - ty::PredicateKind::ConstEvaluatable(_def_id, substs) => { - self.add_substs(substs); + ty::PredicateKind::ConstEvaluatable(uv) => { + self.add_unevaluated_const(uv); } ty::PredicateKind::ConstEquate(expected, found) => { self.add_const(expected); @@ -288,7 +294,7 @@ impl FlagComputation { self.add_bound_var(debruijn); } ty::ConstKind::Param(_) => { - self.add_flags(TypeFlags::HAS_CT_PARAM); + self.add_flags(TypeFlags::HAS_KNOWN_CT_PARAM); self.add_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE); } ty::ConstKind::Placeholder(_) => { @@ -301,7 +307,12 @@ impl FlagComputation { } fn add_unevaluated_const(&mut self, ct: ty::Unevaluated<'tcx>) { - self.add_substs(ct.substs); + if let Some(substs) = ct.substs_ { + self.add_substs(substs); + } else { + self.add_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE); + self.add_flags(TypeFlags::HAS_UNKNOWN_DEFAULT_CONST_SUBSTS); + } self.add_flags(TypeFlags::HAS_CT_PROJECTION); } diff --git a/compiler/rustc_middle/src/ty/fold.rs b/compiler/rustc_middle/src/ty/fold.rs index a40210d5a3622..b249dc8d6f92f 100644 --- a/compiler/rustc_middle/src/ty/fold.rs +++ b/compiler/rustc_middle/src/ty/fold.rs @@ -74,8 +74,14 @@ pub trait TypeFoldable<'tcx>: fmt::Debug + Clone { self.has_vars_bound_at_or_above(ty::INNERMOST) } + fn definitely_has_type_flags(&self, tcx: TyCtxt<'tcx>, flags: TypeFlags) -> bool { + self.visit_with(&mut HasTypeFlagsVisitor { tcx: Some(tcx), flags }).break_value() + == Some(FoundFlags) + } + fn has_type_flags(&self, flags: TypeFlags) -> bool { - self.visit_with(&mut HasTypeFlagsVisitor { flags }).break_value() == Some(FoundFlags) + self.visit_with(&mut HasTypeFlagsVisitor { tcx: None, flags }).break_value() + == Some(FoundFlags) } fn has_projections(&self) -> bool { self.has_type_flags(TypeFlags::HAS_PROJECTION) @@ -86,8 +92,18 @@ pub trait TypeFoldable<'tcx>: fmt::Debug + Clone { fn references_error(&self) -> bool { self.has_type_flags(TypeFlags::HAS_ERROR) } - fn has_param_types_or_consts(&self) -> bool { - self.has_type_flags(TypeFlags::HAS_TY_PARAM | TypeFlags::HAS_CT_PARAM) + fn has_potential_param_types_or_consts(&self) -> bool { + self.has_type_flags( + TypeFlags::HAS_KNOWN_TY_PARAM + | TypeFlags::HAS_KNOWN_CT_PARAM + | TypeFlags::HAS_UNKNOWN_DEFAULT_CONST_SUBSTS, + ) + } + fn has_param_types_or_consts(&self, tcx: TyCtxt<'tcx>) -> bool { + self.definitely_has_type_flags( + tcx, + TypeFlags::HAS_KNOWN_TY_PARAM | TypeFlags::HAS_KNOWN_CT_PARAM, + ) } fn has_infer_regions(&self) -> bool { self.has_type_flags(TypeFlags::HAS_RE_INFER) @@ -108,13 +124,18 @@ pub trait TypeFoldable<'tcx>: fmt::Debug + Clone { | TypeFlags::HAS_CT_PLACEHOLDER, ) } - fn needs_subst(&self) -> bool { - self.has_type_flags(TypeFlags::NEEDS_SUBST) + fn potentially_needs_subst(&self) -> bool { + self.has_type_flags( + TypeFlags::KNOWN_NEEDS_SUBST | TypeFlags::HAS_UNKNOWN_DEFAULT_CONST_SUBSTS, + ) + } + fn needs_subst(&self, tcx: TyCtxt<'tcx>) -> bool { + self.definitely_has_type_flags(tcx, TypeFlags::KNOWN_NEEDS_SUBST) } /// "Free" regions in this context means that it has any region /// that is not (a) erased or (b) late-bound. - fn has_free_regions(&self) -> bool { - self.has_type_flags(TypeFlags::HAS_FREE_REGIONS) + fn has_free_regions(&self, tcx: TyCtxt<'tcx>) -> bool { + self.definitely_has_type_flags(tcx, TypeFlags::HAS_KNOWN_FREE_REGIONS) } fn has_erased_regions(&self) -> bool { @@ -122,15 +143,25 @@ pub trait TypeFoldable<'tcx>: fmt::Debug + Clone { } /// True if there are any un-erased free regions. - fn has_erasable_regions(&self) -> bool { - self.has_type_flags(TypeFlags::HAS_FREE_REGIONS) + fn has_erasable_regions(&self, tcx: TyCtxt<'tcx>) -> bool { + self.definitely_has_type_flags(tcx, TypeFlags::HAS_KNOWN_FREE_REGIONS) + } + + /// Indicates whether this value definitely references only 'global' + /// generic parameters that are the same regardless of what fn we are + /// in. This is used for caching. + /// + /// Note that this function is pessimistic and may incorrectly return + /// `false`. + fn is_known_global(&self) -> bool { + !self.has_type_flags(TypeFlags::HAS_POTENTIAL_FREE_LOCAL_NAMES) } /// Indicates whether this value references only 'global' /// generic parameters that are the same regardless of what fn we are /// in. This is used for caching. - fn is_global(&self) -> bool { - !self.has_type_flags(TypeFlags::HAS_FREE_LOCAL_NAMES) + fn is_global(&self, tcx: TyCtxt<'tcx>) -> bool { + !self.definitely_has_type_flags(tcx, TypeFlags::HAS_KNOWN_FREE_LOCAL_NAMES) } /// True if there are any late-bound regions @@ -182,6 +213,10 @@ pub trait TypeFolder<'tcx>: Sized { c.super_fold_with(self) } + fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> { + p.super_fold_with(self) + } + fn fold_mir_const(&mut self, c: mir::ConstantKind<'tcx>) -> mir::ConstantKind<'tcx> { bug!("most type folders should not be folding MIR datastructures: {:?}", c) } @@ -189,6 +224,14 @@ pub trait TypeFolder<'tcx>: Sized { pub trait TypeVisitor<'tcx>: Sized { type BreakTy = !; + /// Supplies the `tcx` for an unevaluated anonymous constant in case its default substs + /// are not yet supplied. + /// + /// Visitors which do not look into these substs may return `None` here, in which case + /// `super_visit_with` completely skips the default substs. Incorrectly returning + /// `None` can very quickly lead to ICE or other critical bugs, so be careful and + /// try to return an actual `tcx` if at all possible. + fn tcx_for_anon_const_substs(&self) -> Option>; fn visit_binder>( &mut self, @@ -209,6 +252,10 @@ pub trait TypeVisitor<'tcx>: Sized { c.super_visit_with(self) } + fn visit_unevaluated_const(&mut self, uv: ty::Unevaluated<'tcx>) -> ControlFlow { + uv.super_visit_with(self) + } + fn visit_predicate(&mut self, p: ty::Predicate<'tcx>) -> ControlFlow { p.super_visit_with(self) } @@ -301,7 +348,8 @@ impl<'tcx> TyCtxt<'tcx> { value: &impl TypeFoldable<'tcx>, callback: impl FnMut(ty::Region<'tcx>) -> bool, ) -> bool { - struct RegionVisitor { + struct RegionVisitor<'tcx, F> { + tcx: TyCtxt<'tcx>, /// The index of a binder *just outside* the things we have /// traversed. If we encounter a bound region bound by this /// binder or one outer to it, it appears free. Example: @@ -323,12 +371,16 @@ impl<'tcx> TyCtxt<'tcx> { callback: F, } - impl<'tcx, F> TypeVisitor<'tcx> for RegionVisitor + impl<'tcx, F> TypeVisitor<'tcx> for RegionVisitor<'tcx, F> where F: FnMut(ty::Region<'tcx>) -> bool, { type BreakTy = (); + fn tcx_for_anon_const_substs(&self) -> Option> { + Some(self.tcx) + } + fn visit_binder>( &mut self, t: &Binder<'tcx, T>, @@ -356,7 +408,7 @@ impl<'tcx> TyCtxt<'tcx> { fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow { // We're only interested in types involving regions - if ty.flags().intersects(TypeFlags::HAS_FREE_REGIONS) { + if ty.flags().intersects(TypeFlags::HAS_POTENTIAL_FREE_REGIONS) { ty.super_visit_with(self) } else { ControlFlow::CONTINUE @@ -364,7 +416,9 @@ impl<'tcx> TyCtxt<'tcx> { } } - value.visit_with(&mut RegionVisitor { outer_index: ty::INNERMOST, callback }).is_break() + value + .visit_with(&mut RegionVisitor { tcx: self, outer_index: ty::INNERMOST, callback }) + .is_break() } } @@ -708,7 +762,7 @@ impl<'tcx> TyCtxt<'tcx> { where T: TypeFoldable<'tcx>, { - let mut collector = LateBoundRegionsCollector::new(just_constraint); + let mut collector = LateBoundRegionsCollector::new(self, just_constraint); let result = value.as_ref().skip_binder().visit_with(&mut collector); assert!(result.is_continue()); // should never have stopped early collector.regions @@ -775,6 +829,11 @@ impl<'tcx> ValidateBoundVars<'tcx> { impl<'tcx> TypeVisitor<'tcx> for ValidateBoundVars<'tcx> { type BreakTy = (); + fn tcx_for_anon_const_substs(&self) -> Option> { + // Anonymous constants do not contain bound vars in their substs by default. + None + } + fn visit_binder>( &mut self, t: &Binder<'tcx, T>, @@ -989,6 +1048,11 @@ struct HasEscapingVarsVisitor { impl<'tcx> TypeVisitor<'tcx> for HasEscapingVarsVisitor { type BreakTy = FoundEscapingVars; + fn tcx_for_anon_const_substs(&self) -> Option> { + // Anonymous constants do not contain bound vars in their substs by default. + None + } + fn visit_binder>( &mut self, t: &Binder<'tcx, T>, @@ -1053,15 +1117,19 @@ impl<'tcx> TypeVisitor<'tcx> for HasEscapingVarsVisitor { struct FoundFlags; // FIXME: Optimize for checking for infer flags -struct HasTypeFlagsVisitor { +struct HasTypeFlagsVisitor<'tcx> { + tcx: Option>, flags: ty::TypeFlags, } -impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor { +impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor<'tcx> { type BreakTy = FoundFlags; + fn tcx_for_anon_const_substs(&self) -> Option> { + self.tcx + } #[inline] - fn visit_ty(&mut self, t: Ty<'_>) -> ControlFlow { + fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { debug!( "HasTypeFlagsVisitor: t={:?} t.flags={:?} self.flags={:?}", t, @@ -1070,6 +1138,11 @@ impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor { ); if t.flags().intersects(self.flags) { ControlFlow::Break(FoundFlags) + } else if self.tcx.is_some() + && t.flags().intersects(TypeFlags::HAS_UNKNOWN_DEFAULT_CONST_SUBSTS) + && self.flags.intersects(TypeFlags::MAY_NEED_DEFAULT_CONST_SUBSTS) + { + t.super_visit_with(self) } else { ControlFlow::CONTINUE } @@ -1092,6 +1165,26 @@ impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor { debug!("HasTypeFlagsVisitor: c={:?} c.flags={:?} self.flags={:?}", c, flags, self.flags); if flags.intersects(self.flags) { ControlFlow::Break(FoundFlags) + } else if self.tcx.is_some() + && flags.intersects(TypeFlags::HAS_UNKNOWN_DEFAULT_CONST_SUBSTS) + && self.flags.intersects(TypeFlags::MAY_NEED_DEFAULT_CONST_SUBSTS) + { + c.super_visit_with(self) + } else { + ControlFlow::CONTINUE + } + } + + fn visit_unevaluated_const(&mut self, uv: ty::Unevaluated<'tcx>) -> ControlFlow { + let flags = FlagComputation::for_unevaluated_const(uv); + debug!("HasTypeFlagsVisitor: uv={:?} uv.flags={:?} self.flags={:?}", uv, flags, self.flags); + if flags.intersects(self.flags) { + ControlFlow::Break(FoundFlags) + } else if self.tcx.is_some() + && flags.intersects(TypeFlags::HAS_UNKNOWN_DEFAULT_CONST_SUBSTS) + && self.flags.intersects(TypeFlags::MAY_NEED_DEFAULT_CONST_SUBSTS) + { + uv.super_visit_with(self) } else { ControlFlow::CONTINUE } @@ -1105,15 +1198,57 @@ impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor { ); if predicate.inner.flags.intersects(self.flags) { ControlFlow::Break(FoundFlags) + } else if self.tcx.is_some() + && predicate.inner.flags.intersects(TypeFlags::HAS_UNKNOWN_DEFAULT_CONST_SUBSTS) + && self.flags.intersects(TypeFlags::MAY_NEED_DEFAULT_CONST_SUBSTS) + { + predicate.super_visit_with(self) } else { ControlFlow::CONTINUE } } } +impl<'tcx> TyCtxt<'tcx> { + /// This is a HACK(const_generics) and should probably not be needed. + /// Might however be perf relevant, so who knows. + /// + /// FIXME(@lcnr): explain this function a bit more + pub fn expose_default_const_substs>(self, v: T) -> T { + v.fold_with(&mut ExposeDefaultConstSubstsFolder { tcx: self }) + } +} + +struct ExposeDefaultConstSubstsFolder<'tcx> { + tcx: TyCtxt<'tcx>, +} + +impl<'tcx> TypeFolder<'tcx> for ExposeDefaultConstSubstsFolder<'tcx> { + fn tcx(&self) -> TyCtxt<'tcx> { + self.tcx + } + + fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { + if ty.flags().intersects(TypeFlags::HAS_UNKNOWN_DEFAULT_CONST_SUBSTS) { + ty.super_fold_with(self) + } else { + ty + } + } + + fn fold_predicate(&mut self, pred: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> { + if pred.inner.flags.intersects(TypeFlags::HAS_UNKNOWN_DEFAULT_CONST_SUBSTS) { + pred.super_fold_with(self) + } else { + pred + } + } +} + /// Collects all the late-bound regions at the innermost binding level /// into a hash set. -struct LateBoundRegionsCollector { +struct LateBoundRegionsCollector<'tcx> { + tcx: TyCtxt<'tcx>, current_index: ty::DebruijnIndex, regions: FxHashSet, @@ -1127,9 +1262,10 @@ struct LateBoundRegionsCollector { just_constrained: bool, } -impl LateBoundRegionsCollector { - fn new(just_constrained: bool) -> Self { +impl LateBoundRegionsCollector<'tcx> { + fn new(tcx: TyCtxt<'tcx>, just_constrained: bool) -> Self { LateBoundRegionsCollector { + tcx, current_index: ty::INNERMOST, regions: Default::default(), just_constrained, @@ -1137,7 +1273,11 @@ impl LateBoundRegionsCollector { } } -impl<'tcx> TypeVisitor<'tcx> for LateBoundRegionsCollector { +impl<'tcx> TypeVisitor<'tcx> for LateBoundRegionsCollector<'tcx> { + fn tcx_for_anon_const_substs(&self) -> Option> { + Some(self.tcx) + } + fn visit_binder>( &mut self, t: &Binder<'tcx, T>, diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 95ea38d32b695..9cbad3e5aa137 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -1727,7 +1727,9 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { // Ignore layouts that are done with non-empty environments or // non-monomorphic layouts, as the user only wants to see the stuff // resulting from the final codegen session. - if layout.ty.has_param_types_or_consts() || !self.param_env.caller_bounds().is_empty() { + if layout.ty.has_param_types_or_consts(self.tcx) + || !self.param_env.caller_bounds().is_empty() + { return; } @@ -1894,7 +1896,7 @@ impl<'tcx> SizeSkeleton<'tcx> { let tail = tcx.struct_tail_erasing_lifetimes(pointee, param_env); match tail.kind() { ty::Param(_) | ty::Projection(_) => { - debug_assert!(tail.has_param_types_or_consts()); + debug_assert!(tail.has_param_types_or_consts(tcx)); Ok(SizeSkeleton::Pointer { non_zero, tail: tcx.erase_regions(tail) }) } _ => bug!( diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index bfc942e6f10ff..1ea01e4f61dd1 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -59,7 +59,7 @@ pub use self::consts::{Const, ConstInt, ConstKind, InferConst, ScalarInt, Uneval pub use self::context::{ tls, CanonicalUserType, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, CtxtInterners, DelaySpanBugEmitted, FreeRegionInfo, GeneratorInteriorTypeCause, GlobalCtxt, - Lift, TyCtxt, TypeckResults, UserType, UserTypeAnnotationIndex, + Lift, OnDiskCache, TyCtxt, TypeckResults, UserType, UserTypeAnnotationIndex, }; pub use self::instance::{Instance, InstanceDef}; pub use self::list::List; @@ -401,7 +401,7 @@ crate struct PredicateInner<'tcx> { } #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] -static_assert_size!(PredicateInner<'_>, 48); +static_assert_size!(PredicateInner<'_>, 56); #[derive(Clone, Copy, Lift)] pub struct Predicate<'tcx> { @@ -483,7 +483,7 @@ pub enum PredicateKind<'tcx> { Subtype(SubtypePredicate<'tcx>), /// Constant initializer must evaluate successfully. - ConstEvaluatable(ty::WithOptConstParam, SubstsRef<'tcx>), + ConstEvaluatable(ty::Unevaluated<'tcx>), /// Constants must be equal. The first component is the const that is expected. ConstEquate(&'tcx Const<'tcx>, &'tcx Const<'tcx>), @@ -1251,7 +1251,7 @@ impl<'tcx> ParamEnv<'tcx> { Reveal::UserFacing => ParamEnvAnd { param_env: self, value }, Reveal::All => { - if value.is_global() { + if value.is_known_global() { ParamEnvAnd { param_env: self.without_caller_bounds(), value } } else { ParamEnvAnd { param_env: self, value } diff --git a/compiler/rustc_middle/src/ty/outlives.rs b/compiler/rustc_middle/src/ty/outlives.rs index 86750d5c08111..ef4ad998f10c8 100644 --- a/compiler/rustc_middle/src/ty/outlives.rs +++ b/compiler/rustc_middle/src/ty/outlives.rs @@ -194,7 +194,7 @@ fn compute_components_recursive( out: &mut SmallVec<[Component<'tcx>; 4]>, visited: &mut SsoHashSet>, ) { - for child in parent.walk_shallow(visited) { + for child in parent.walk_shallow(tcx, visited) { match child.unpack() { GenericArgKind::Type(ty) => { compute_components(tcx, ty, out, visited); diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 6dfbd28f7763b..e9d9e99959fb7 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -927,20 +927,21 @@ pub trait PrettyPrinter<'tcx>: } match ct.val { - ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted }) => { - if let Some(promoted) = promoted { - p!(print_value_path(def.did, substs)); + ty::ConstKind::Unevaluated(uv) => { + if let Some(promoted) = uv.promoted { + let substs = uv.substs_.unwrap(); + p!(print_value_path(uv.def.did, substs)); p!(write("::{:?}", promoted)); } else { - match self.tcx().def_kind(def.did) { + let tcx = self.tcx(); + match tcx.def_kind(uv.def.did) { DefKind::Static | DefKind::Const | DefKind::AssocConst => { - p!(print_value_path(def.did, substs)) + p!(print_value_path(uv.def.did, uv.substs(tcx))) } _ => { - if def.is_local() { - let span = self.tcx().def_span(def.did); - if let Ok(snip) = self.tcx().sess.source_map().span_to_snippet(span) - { + if uv.def.is_local() { + let span = tcx.def_span(uv.def.did); + if let Ok(snip) = tcx.sess.source_map().span_to_snippet(span) { p!(write("{}", snip)) } else { print_underscore!() @@ -1200,7 +1201,9 @@ pub trait PrettyPrinter<'tcx>: // // FIXME(eddyb) for `--emit=mir`/`-Z dump-mir`, we should provide the // correct `ty::ParamEnv` to allow printing *all* constant values. - (_, ty::Array(..) | ty::Tuple(..) | ty::Adt(..)) if !ty.has_param_types_or_consts() => { + (_, ty::Array(..) | ty::Tuple(..) | ty::Adt(..)) + if !ty.has_potential_param_types_or_consts() => + { let contents = self.tcx().destructure_const( ty::ParamEnv::reveal_all() .and(self.tcx().mk_const(ty::Const { val: ty::ConstKind::Value(ct), ty })), @@ -1949,6 +1952,7 @@ impl FmtPrinter<'_, 'tcx, F> { debug!("prepare_late_bound_region_info(value: {:?})", value); struct LateBoundRegionNameCollector<'a, 'tcx> { + tcx: TyCtxt<'tcx>, used_region_names: &'a mut FxHashSet, type_collector: SsoHashSet>, } @@ -1956,6 +1960,10 @@ impl FmtPrinter<'_, 'tcx, F> { impl<'tcx> ty::fold::TypeVisitor<'tcx> for LateBoundRegionNameCollector<'_, 'tcx> { type BreakTy = (); + fn tcx_for_anon_const_substs(&self) -> Option> { + Some(self.tcx) + } + fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow { debug!("LateBoundRegionNameCollector::visit_region(r: {:?}, address: {:p})", r, &r); if let ty::ReLateBound(_, ty::BoundRegion { kind: ty::BrNamed(_, name), .. }) = *r { @@ -1979,6 +1987,7 @@ impl FmtPrinter<'_, 'tcx, F> { self.used_region_names.clear(); let mut collector = LateBoundRegionNameCollector { + tcx: self.tcx, used_region_names: &mut self.used_region_names, type_collector: SsoHashSet::new(), }; @@ -2211,8 +2220,8 @@ define_print_and_forward_display! { print_value_path(closure_def_id, &[]), write("` implements the trait `{}`", kind)) } - ty::PredicateKind::ConstEvaluatable(def, substs) => { - p!("the constant `", print_value_path(def.did, substs), "` can be evaluated") + ty::PredicateKind::ConstEvaluatable(uv) => { + p!("the constant `", print_value_path(uv.def.did, uv.substs_.map_or(&[], |x| x)), "` can be evaluated") } ty::PredicateKind::ConstEquate(c1, c2) => { p!("the constant `", print(c1), "` equals `", print(c2), "`") diff --git a/compiler/rustc_middle/src/ty/query/mod.rs b/compiler/rustc_middle/src/ty/query.rs similarity index 91% rename from compiler/rustc_middle/src/ty/query/mod.rs rename to compiler/rustc_middle/src/ty/query.rs index 2ed9ede8951c9..15a8888ee65ed 100644 --- a/compiler/rustc_middle/src/ty/query/mod.rs +++ b/compiler/rustc_middle/src/ty/query.rs @@ -38,14 +38,13 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap}; use rustc_data_structures::steal::Steal; use rustc_data_structures::svh::Svh; use rustc_data_structures::sync::Lrc; -use rustc_errors::{ErrorReported, Handler}; +use rustc_errors::ErrorReported; use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, DefIdSet, LocalDefId}; use rustc_hir::lang_items::{LangItem, LanguageItems}; use rustc_hir::{Crate, ItemLocalId, TraitCandidate}; use rustc_index::{bit_set::FiniteBitSet, vec::IndexVec}; -use rustc_serialize::opaque; use rustc_session::config::{EntryFnType, OptLevel, OutputFilenames, SymbolManglingVersion}; use rustc_session::utils::NativeLibKind; use rustc_session::Limits; @@ -63,9 +62,6 @@ use std::sync::Arc; pub(crate) use rustc_query_system::query::QueryJobId; use rustc_query_system::query::*; -pub mod on_disk_cache; -pub use self::on_disk_cache::OnDiskCache; - #[derive(Copy, Clone)] pub struct TyCtxtAt<'tcx> { pub tcx: TyCtxt<'tcx>, @@ -235,28 +231,10 @@ macro_rules! define_callbacks { } pub trait QueryEngine<'tcx>: rustc_data_structures::sync::Sync { - #[cfg(parallel_compiler)] - unsafe fn deadlock(&'tcx self, tcx: TyCtxt<'tcx>, registry: &rustc_rayon_core::Registry); - - fn encode_query_results( - &'tcx self, - tcx: TyCtxt<'tcx>, - encoder: &mut on_disk_cache::CacheEncoder<'a, 'tcx, opaque::FileEncoder>, - query_result_index: &mut on_disk_cache::EncodedQueryResultIndex, - ) -> opaque::FileEncodeResult; - - fn exec_cache_promotions(&'tcx self, tcx: TyCtxt<'tcx>); + fn as_any(&'tcx self) -> &'tcx dyn std::any::Any; fn try_mark_green(&'tcx self, tcx: TyCtxt<'tcx>, dep_node: &dep_graph::DepNode) -> bool; - fn try_print_query_stack( - &'tcx self, - tcx: TyCtxt<'tcx>, - query: Option>, - handler: &Handler, - num_frames: Option, - ) -> usize; - $($(#[$attr])* fn $name( &'tcx self, diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs index a4c36be21992b..5599875da88f8 100644 --- a/compiler/rustc_middle/src/ty/relate.rs +++ b/compiler/rustc_middle/src/ty/relate.rs @@ -552,7 +552,7 @@ pub fn super_relate_consts>( (ty::ConstKind::Unevaluated(au), ty::ConstKind::Unevaluated(bu)) if tcx.features().const_evaluatable_checked => { - tcx.try_unify_abstract_consts(((au.def, au.substs), (bu.def, bu.substs))) + tcx.try_unify_abstract_consts((au, bu)) } // While this is slightly incorrect, it shouldn't matter for `min_const_generics` @@ -564,13 +564,13 @@ pub fn super_relate_consts>( let substs = relation.relate_with_variance( ty::Variance::Invariant, ty::VarianceDiagInfo::default(), - au.substs, - bu.substs, + au.substs(tcx), + bu.substs(tcx), )?; return Ok(tcx.mk_const(ty::Const { val: ty::ConstKind::Unevaluated(ty::Unevaluated { def: au.def, - substs, + substs_: Some(substs), promoted: au.promoted, }), ty: a.ty, diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 7290c41d615df..f8ebd3dc7696b 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -191,8 +191,8 @@ impl fmt::Debug for ty::PredicateKind<'tcx> { ty::PredicateKind::ClosureKind(closure_def_id, closure_substs, kind) => { write!(f, "ClosureKind({:?}, {:?}, {:?})", closure_def_id, closure_substs, kind) } - ty::PredicateKind::ConstEvaluatable(def_id, substs) => { - write!(f, "ConstEvaluatable({:?}, {:?})", def_id, substs) + ty::PredicateKind::ConstEvaluatable(uv) => { + write!(f, "ConstEvaluatable({:?}, {:?})", uv.def, uv.substs_) } ty::PredicateKind::ConstEquate(c1, c2) => write!(f, "ConstEquate({:?}, {:?})", c1, c2), ty::PredicateKind::TypeWellFormedFromEnv(ty) => { @@ -441,8 +441,8 @@ impl<'a, 'tcx> Lift<'tcx> for ty::PredicateKind<'a> { ty::PredicateKind::ObjectSafe(trait_def_id) => { Some(ty::PredicateKind::ObjectSafe(trait_def_id)) } - ty::PredicateKind::ConstEvaluatable(def_id, substs) => { - tcx.lift(substs).map(|substs| ty::PredicateKind::ConstEvaluatable(def_id, substs)) + ty::PredicateKind::ConstEvaluatable(uv) => { + tcx.lift(uv).map(|uv| ty::PredicateKind::ConstEvaluatable(uv)) } ty::PredicateKind::ConstEquate(c1, c2) => { tcx.lift((c1, c2)).map(|(c1, c2)| ty::PredicateKind::ConstEquate(c1, c2)) @@ -967,6 +967,10 @@ impl<'tcx> TypeFoldable<'tcx> for ty::Region<'tcx> { } impl<'tcx> TypeFoldable<'tcx> for ty::Predicate<'tcx> { + fn fold_with>(self, folder: &mut F) -> Self { + folder.fold_predicate(self) + } + fn super_fold_with>(self, folder: &mut F) -> Self { let new = self.inner.kind.fold_with(folder); folder.tcx().reuse_or_mk_predicate(self, new) @@ -1039,13 +1043,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::ConstKind<'tcx> { match self { ty::ConstKind::Infer(ic) => ty::ConstKind::Infer(ic.fold_with(folder)), ty::ConstKind::Param(p) => ty::ConstKind::Param(p.fold_with(folder)), - ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted }) => { - ty::ConstKind::Unevaluated(ty::Unevaluated { - def, - substs: substs.fold_with(folder), - promoted, - }) - } + ty::ConstKind::Unevaluated(uv) => ty::ConstKind::Unevaluated(uv.fold_with(folder)), ty::ConstKind::Value(_) | ty::ConstKind::Bound(..) | ty::ConstKind::Placeholder(..) @@ -1057,7 +1055,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::ConstKind<'tcx> { match *self { ty::ConstKind::Infer(ic) => ic.visit_with(visitor), ty::ConstKind::Param(p) => p.visit_with(visitor), - ty::ConstKind::Unevaluated(ct) => ct.substs.visit_with(visitor), + ty::ConstKind::Unevaluated(uv) => uv.visit_with(visitor), ty::ConstKind::Value(_) | ty::ConstKind::Bound(..) | ty::ConstKind::Placeholder(_) @@ -1075,3 +1073,28 @@ impl<'tcx> TypeFoldable<'tcx> for InferConst<'tcx> { ControlFlow::CONTINUE } } + +impl<'tcx> TypeFoldable<'tcx> for ty::Unevaluated<'tcx> { + fn super_fold_with>(self, folder: &mut F) -> Self { + ty::Unevaluated { + def: self.def, + substs_: Some(self.substs(folder.tcx()).fold_with(folder)), + promoted: self.promoted, + } + } + + fn visit_with>(&self, visitor: &mut V) -> ControlFlow { + visitor.visit_unevaluated_const(*self) + } + + fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow { + if let Some(tcx) = visitor.tcx_for_anon_const_substs() { + self.substs(tcx).visit_with(visitor) + } else if let Some(substs) = self.substs_ { + substs.visit_with(visitor) + } else { + debug!("ignoring default substs of `{:?}`", self.def); + ControlFlow::CONTINUE + } + } +} diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 6a7e349819afd..85aed6273698d 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -1562,26 +1562,26 @@ impl RegionKind { match *self { ty::ReVar(..) => { - flags = flags | TypeFlags::HAS_FREE_REGIONS; - flags = flags | TypeFlags::HAS_FREE_LOCAL_REGIONS; + flags = flags | TypeFlags::HAS_KNOWN_FREE_REGIONS; + flags = flags | TypeFlags::HAS_KNOWN_FREE_LOCAL_REGIONS; flags = flags | TypeFlags::HAS_RE_INFER; } ty::RePlaceholder(..) => { - flags = flags | TypeFlags::HAS_FREE_REGIONS; - flags = flags | TypeFlags::HAS_FREE_LOCAL_REGIONS; + flags = flags | TypeFlags::HAS_KNOWN_FREE_REGIONS; + flags = flags | TypeFlags::HAS_KNOWN_FREE_LOCAL_REGIONS; flags = flags | TypeFlags::HAS_RE_PLACEHOLDER; } ty::ReEarlyBound(..) => { - flags = flags | TypeFlags::HAS_FREE_REGIONS; - flags = flags | TypeFlags::HAS_FREE_LOCAL_REGIONS; - flags = flags | TypeFlags::HAS_RE_PARAM; + flags = flags | TypeFlags::HAS_KNOWN_FREE_REGIONS; + flags = flags | TypeFlags::HAS_KNOWN_FREE_LOCAL_REGIONS; + flags = flags | TypeFlags::HAS_KNOWN_RE_PARAM; } ty::ReFree { .. } => { - flags = flags | TypeFlags::HAS_FREE_REGIONS; - flags = flags | TypeFlags::HAS_FREE_LOCAL_REGIONS; + flags = flags | TypeFlags::HAS_KNOWN_FREE_REGIONS; + flags = flags | TypeFlags::HAS_KNOWN_FREE_LOCAL_REGIONS; } ty::ReEmpty(_) | ty::ReStatic => { - flags = flags | TypeFlags::HAS_FREE_REGIONS; + flags = flags | TypeFlags::HAS_KNOWN_FREE_REGIONS; } ty::ReLateBound(..) => { flags = flags | TypeFlags::HAS_RE_LATE_BOUND; diff --git a/compiler/rustc_middle/src/ty/subst.rs b/compiler/rustc_middle/src/ty/subst.rs index 9b8d22d8eafce..a8234db79ef0d 100644 --- a/compiler/rustc_middle/src/ty/subst.rs +++ b/compiler/rustc_middle/src/ty/subst.rs @@ -486,7 +486,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for SubstFolder<'a, 'tcx> { } fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { - if !t.needs_subst() { + if !t.potentially_needs_subst() { return t; } @@ -497,10 +497,6 @@ impl<'a, 'tcx> TypeFolder<'tcx> for SubstFolder<'a, 'tcx> { } fn fold_const(&mut self, c: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> { - if !c.needs_subst() { - return c; - } - if let ty::ConstKind::Param(p) = c.val { self.const_for_param(p, c) } else { diff --git a/compiler/rustc_middle/src/ty/vtable.rs b/compiler/rustc_middle/src/ty/vtable.rs index 78109fc7b5713..a8ab459e86e3a 100644 --- a/compiler/rustc_middle/src/ty/vtable.rs +++ b/compiler/rustc_middle/src/ty/vtable.rs @@ -38,7 +38,8 @@ impl<'tcx> TyCtxt<'tcx> { // See https://github.com/rust-lang/rust/pull/86475#discussion_r655162674 assert!( - !ty.needs_subst() && !poly_trait_ref.map_or(false, |trait_ref| trait_ref.needs_subst()) + !ty.needs_subst(tcx) + && poly_trait_ref.map_or(true, |trait_ref| !trait_ref.needs_subst(tcx)) ); let param_env = ty::ParamEnv::reveal_all(); let vtable_entries = if let Some(poly_trait_ref) = poly_trait_ref { @@ -81,7 +82,7 @@ impl<'tcx> TyCtxt<'tcx> { VtblEntry::Vacant => continue, VtblEntry::Method(def_id, substs) => { // See https://github.com/rust-lang/rust/pull/86475#discussion_r655162674 - assert!(!substs.needs_subst()); + assert!(!substs.needs_subst(tcx)); // Prepare the fn ptr we write into the vtable. let instance = diff --git a/compiler/rustc_middle/src/ty/walk.rs b/compiler/rustc_middle/src/ty/walk.rs index c2fe5f1ef3f62..73985cf31e0f9 100644 --- a/compiler/rustc_middle/src/ty/walk.rs +++ b/compiler/rustc_middle/src/ty/walk.rs @@ -1,8 +1,8 @@ //! An iterator over the type substructure. //! WARNING: this does not keep track of the region depth. -use crate::ty; use crate::ty::subst::{GenericArg, GenericArgKind}; +use crate::ty::{self, TyCtxt}; use rustc_data_structures::sso::SsoHashSet; use smallvec::{self, SmallVec}; @@ -11,6 +11,7 @@ use smallvec::{self, SmallVec}; type TypeWalkerStack<'tcx> = SmallVec<[GenericArg<'tcx>; 8]>; pub struct TypeWalker<'tcx> { + expose_default_const_substs: Option>, stack: TypeWalkerStack<'tcx>, last_subtree: usize, pub visited: SsoHashSet>, @@ -25,8 +26,13 @@ pub struct TypeWalker<'tcx> { /// It maintains a set of visited types and /// skips any types that are already there. impl<'tcx> TypeWalker<'tcx> { - pub fn new(root: GenericArg<'tcx>) -> Self { - Self { stack: smallvec![root], last_subtree: 1, visited: SsoHashSet::new() } + fn new(expose_default_const_substs: Option>, root: GenericArg<'tcx>) -> Self { + Self { + expose_default_const_substs, + stack: smallvec![root], + last_subtree: 1, + visited: SsoHashSet::new(), + } } /// Skips the subtree corresponding to the last type @@ -55,7 +61,7 @@ impl<'tcx> Iterator for TypeWalker<'tcx> { let next = self.stack.pop()?; self.last_subtree = self.stack.len(); if self.visited.insert(next) { - push_inner(&mut self.stack, next); + push_inner(self.expose_default_const_substs, &mut self.stack, next); debug!("next: stack={:?}", self.stack); return Some(next); } @@ -74,8 +80,8 @@ impl GenericArg<'tcx> { /// Foo> => { Foo>, Bar, isize } /// [isize] => { [isize], isize } /// ``` - pub fn walk(self) -> TypeWalker<'tcx> { - TypeWalker::new(self) + pub fn walk(self, tcx: TyCtxt<'tcx>) -> TypeWalker<'tcx> { + TypeWalker::new(Some(tcx), self) } /// Iterator that walks the immediate children of `self`. Hence @@ -87,16 +93,21 @@ impl GenericArg<'tcx> { /// and skips any types that are already there. pub fn walk_shallow( self, + tcx: TyCtxt<'tcx>, visited: &mut SsoHashSet>, ) -> impl Iterator> { let mut stack = SmallVec::new(); - push_inner(&mut stack, self); + push_inner(Some(tcx), &mut stack, self); stack.retain(|a| visited.insert(*a)); stack.into_iter() } } impl<'tcx> super::TyS<'tcx> { + pub fn walk_ignoring_default_const_substs(&'tcx self) -> TypeWalker<'tcx> { + TypeWalker::new(None, self.into()) + } + /// Iterator that walks `self` and any types reachable from /// `self`, in depth-first order. Note that just walks the types /// that appear in `self`, it does not descend into the fields of @@ -107,18 +118,22 @@ impl<'tcx> super::TyS<'tcx> { /// Foo> => { Foo>, Bar, isize } /// [isize] => { [isize], isize } /// ``` - pub fn walk(&'tcx self) -> TypeWalker<'tcx> { - TypeWalker::new(self.into()) + pub fn walk(&'tcx self, tcx: TyCtxt<'tcx>) -> TypeWalker<'tcx> { + TypeWalker::new(Some(tcx), self.into()) } } -// We push `GenericArg`s on the stack in reverse order so as to -// maintain a pre-order traversal. As of the time of this -// writing, the fact that the traversal is pre-order is not -// known to be significant to any code, but it seems like the -// natural order one would expect (basically, the order of the -// types as they are written). -fn push_inner<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent: GenericArg<'tcx>) { +/// We push `GenericArg`s on the stack in reverse order so as to +/// maintain a pre-order traversal. As of the time of this +/// writing, the fact that the traversal is pre-order is not +/// known to be significant to any code, but it seems like the +/// natural order one would expect (basically, the order of the +/// types as they are written). +fn push_inner<'tcx>( + expose_default_const_substs: Option>, + stack: &mut TypeWalkerStack<'tcx>, + parent: GenericArg<'tcx>, +) { match parent.unpack() { GenericArgKind::Type(parent_ty) => match *parent_ty.kind() { ty::Bool @@ -196,7 +211,11 @@ fn push_inner<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent: GenericArg<'tcx>) | ty::ConstKind::Error(_) => {} ty::ConstKind::Unevaluated(ct) => { - stack.extend(ct.substs.iter().rev()); + if let Some(tcx) = expose_default_const_substs { + stack.extend(ct.substs(tcx).iter().rev()); + } else if let Some(substs) = ct.substs_ { + stack.extend(substs.iter().rev()); + } } } } diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs index 0b01c4efcdbd4..2e854ea5be7df 100644 --- a/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs +++ b/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs @@ -12,7 +12,7 @@ use rustc_middle::mir::{ use rustc_middle::ty::{self, suggest_constraining_type_param, Ty}; use rustc_span::source_map::DesugaringKind; use rustc_span::symbol::sym; -use rustc_span::{Span, DUMMY_SP}; +use rustc_span::{MultiSpan, Span, DUMMY_SP}; use rustc_trait_selection::infer::InferCtxtExt; use crate::dataflow::drop_flag_effects; @@ -66,7 +66,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { self.move_spans(moved_place, location).or_else(|| self.borrow_spans(span, location)); let span = use_spans.args_or_use(); - let move_site_vec = self.get_moved_indexes(location, mpi); + let (move_site_vec, maybe_reinitialized_locations) = self.get_moved_indexes(location, mpi); debug!( "report_use_of_moved_or_uninitialized: move_site_vec={:?} use_spans={:?}", move_site_vec, use_spans @@ -139,6 +139,32 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { self.describe_place_with_options(moved_place, IncludingDowncast(true)), ); + let reinit_spans = maybe_reinitialized_locations + .iter() + .take(3) + .map(|loc| { + self.move_spans(self.move_data.move_paths[mpi].place.as_ref(), *loc) + .args_or_use() + }) + .collect::>(); + let reinits = maybe_reinitialized_locations.len(); + if reinits == 1 { + err.span_label(reinit_spans[0], "this reinitialization might get skipped"); + } else if reinits > 1 { + err.span_note( + MultiSpan::from_spans(reinit_spans), + &if reinits <= 3 { + format!("these {} reinitializations might get skipped", reinits) + } else { + format!( + "these 3 reinitializations and {} other{} might get skipped", + reinits - 3, + if reinits == 4 { "" } else { "s" } + ) + }, + ); + } + self.add_moved_or_invoked_closure_note(location, used_place, &mut err); let mut is_loop_move = false; @@ -219,7 +245,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { ), ); } - if is_option_or_result { + if is_option_or_result && maybe_reinitialized_locations.is_empty() { err.span_suggestion_verbose( fn_call_span.shrink_to_lo(), "consider calling `.as_ref()` to borrow the type's contents", @@ -260,19 +286,23 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } } - if let UseSpans::PatUse(span) = move_spans { - err.span_suggestion_verbose( - span.shrink_to_lo(), - &format!( - "borrow this field in the pattern to avoid moving {}", - self.describe_place(moved_place.as_ref()) - .map(|n| format!("`{}`", n)) - .unwrap_or_else(|| "the value".to_string()) - ), - "ref ".to_string(), - Applicability::MachineApplicable, - ); - in_pattern = true; + if let (UseSpans::PatUse(span), []) = + (move_spans, &maybe_reinitialized_locations[..]) + { + if maybe_reinitialized_locations.is_empty() { + err.span_suggestion_verbose( + span.shrink_to_lo(), + &format!( + "borrow this field in the pattern to avoid moving {}", + self.describe_place(moved_place.as_ref()) + .map(|n| format!("`{}`", n)) + .unwrap_or_else(|| "the value".to_string()) + ), + "ref ".to_string(), + Applicability::MachineApplicable, + ); + in_pattern = true; + } } if let Some(DesugaringKind::ForLoop(_)) = move_span.desugaring_kind() { @@ -1465,7 +1495,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { err } - fn get_moved_indexes(&mut self, location: Location, mpi: MovePathIndex) -> Vec { + fn get_moved_indexes( + &mut self, + location: Location, + mpi: MovePathIndex, + ) -> (Vec, Vec) { fn predecessor_locations( body: &'a mir::Body<'tcx>, location: Location, @@ -1488,6 +1522,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { })); let mut visited = FxHashSet::default(); + let mut move_locations = FxHashSet::default(); + let mut reinits = vec![]; let mut result = vec![]; 'dfs: while let Some((location, is_back_edge)) = stack.pop() { @@ -1529,6 +1565,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { move_paths[path].place ); result.push(MoveSite { moi: *moi, traversed_back_edge: is_back_edge }); + move_locations.insert(location); // Strictly speaking, we could continue our DFS here. There may be // other moves that can reach the point of error. But it is kind of @@ -1565,6 +1602,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { }, ); if any_match { + reinits.push(location); continue 'dfs; } @@ -1574,7 +1612,25 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { })); } - result + // Check if we can reach these reinits from a move location. + let reinits_reachable = reinits + .into_iter() + .filter(|reinit| { + let mut visited = FxHashSet::default(); + let mut stack = vec![*reinit]; + while let Some(location) = stack.pop() { + if !visited.insert(location) { + continue; + } + if move_locations.contains(&location) { + return true; + } + stack.extend(predecessor_locations(self.body, location)); + } + false + }) + .collect::>(); + (result, reinits_reachable) } pub(in crate::borrow_check) fn report_illegal_mutation_of_borrowed( diff --git a/compiler/rustc_mir/src/borrow_check/type_check/liveness/trace.rs b/compiler/rustc_mir/src/borrow_check/type_check/liveness/trace.rs index f04736e04a053..67b354bd2a16f 100644 --- a/compiler/rustc_mir/src/borrow_check/type_check/liveness/trace.rs +++ b/compiler/rustc_mir/src/borrow_check/type_check/liveness/trace.rs @@ -171,7 +171,7 @@ impl LivenessResults<'me, 'typeck, 'flow, 'tcx> { for (local, location) in drop_used { if !live_locals.contains(&local) { let local_ty = self.cx.body.local_decls[local].ty; - if local_ty.has_free_regions() { + if local_ty.has_free_regions(self.cx.typeck.tcx()) { self.cx.add_drop_live_facts_for(local, local_ty, &[location], &locations); } } diff --git a/compiler/rustc_mir/src/borrow_check/type_check/mod.rs b/compiler/rustc_mir/src/borrow_check/type_check/mod.rs index b4fe3313e8a1e..a4ed0660dc0bd 100644 --- a/compiler/rustc_mir/src/borrow_check/type_check/mod.rs +++ b/compiler/rustc_mir/src/borrow_check/type_check/mod.rs @@ -322,8 +322,8 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> { }, _ => None, }; - if let Some(ty::Unevaluated { def, substs, promoted }) = maybe_uneval { - if let Some(promoted) = promoted { + if let Some(uv) = maybe_uneval { + if let Some(promoted) = uv.promoted { let check_err = |verifier: &mut TypeVerifier<'a, 'b, 'tcx>, promoted: &Body<'tcx>, ty, @@ -358,8 +358,8 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> { ConstraintCategory::Boring, self.cx.param_env.and(type_op::ascribe_user_type::AscribeUserType::new( constant.literal.ty(), - def.did, - UserSubsts { substs, user_self_ty: None }, + uv.def.did, + UserSubsts { substs: uv.substs(self.tcx()), user_self_ty: None }, )), ) { span_mirbug!( diff --git a/compiler/rustc_mir/src/interpret/operand.rs b/compiler/rustc_mir/src/interpret/operand.rs index aba7db7816843..c90af5d7663fd 100644 --- a/compiler/rustc_mir/src/interpret/operand.rs +++ b/compiler/rustc_mir/src/interpret/operand.rs @@ -541,9 +541,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { match val.val { ty::ConstKind::Param(_) | ty::ConstKind::Bound(..) => throw_inval!(TooGeneric), ty::ConstKind::Error(_) => throw_inval!(AlreadyReported(ErrorReported)), - ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted }) => { - let instance = self.resolve(def, substs)?; - Ok(self.eval_to_allocation(GlobalId { instance, promoted })?.into()) + ty::ConstKind::Unevaluated(uv) => { + let instance = self.resolve(uv.def, uv.substs(*self.tcx))?; + Ok(self.eval_to_allocation(GlobalId { instance, promoted: uv.promoted })?.into()) } ty::ConstKind::Infer(..) | ty::ConstKind::Placeholder(..) => { span_bug!(self.cur_span(), "const_to_op: Unexpected ConstKind {:?}", val) diff --git a/compiler/rustc_mir/src/interpret/util.rs b/compiler/rustc_mir/src/interpret/util.rs index 89f34cd07aa4b..37c13c2d42aec 100644 --- a/compiler/rustc_mir/src/interpret/util.rs +++ b/compiler/rustc_mir/src/interpret/util.rs @@ -9,7 +9,7 @@ where T: TypeFoldable<'tcx>, { debug!("ensure_monomorphic_enough: ty={:?}", ty); - if !ty.needs_subst() { + if !ty.potentially_needs_subst() { return Ok(()); } @@ -21,19 +21,12 @@ where impl<'tcx> TypeVisitor<'tcx> for UsedParamsNeedSubstVisitor<'tcx> { type BreakTy = FoundParam; - fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow { - if !c.needs_subst() { - return ControlFlow::CONTINUE; - } - - match c.val { - ty::ConstKind::Param(..) => ControlFlow::Break(FoundParam), - _ => c.super_visit_with(self), - } + fn tcx_for_anon_const_substs(&self) -> Option> { + Some(self.tcx) } fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow { - if !ty.needs_subst() { + if !ty.potentially_needs_subst() { return ControlFlow::CONTINUE; } @@ -50,7 +43,7 @@ where let is_used = unused_params.contains(index).map_or(true, |unused| !unused); // Only recurse when generic parameters in fns, closures and generators // are used and require substitution. - match (is_used, subst.needs_subst()) { + match (is_used, subst.needs_subst(self.tcx)) { // Just in case there are closures or generators within this subst, // recurse. (true, true) => return subst.super_visit_with(self), @@ -73,6 +66,13 @@ where _ => ty.super_visit_with(self), } } + + fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow { + match c.val { + ty::ConstKind::Param(..) => ControlFlow::Break(FoundParam), + _ => c.super_visit_with(self), + } + } } let mut vis = UsedParamsNeedSubstVisitor { tcx }; diff --git a/compiler/rustc_mir/src/monomorphize/collector.rs b/compiler/rustc_mir/src/monomorphize/collector.rs index 2ce7cf71116bb..d7c4fbc373730 100644 --- a/compiler/rustc_mir/src/monomorphize/collector.rs +++ b/compiler/rustc_mir/src/monomorphize/collector.rs @@ -573,7 +573,7 @@ fn check_type_length_limit<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) { let type_length = instance .substs .iter() - .flat_map(|arg| arg.walk()) + .flat_map(|arg| arg.walk(tcx)) .filter(|arg| match arg.unpack() { GenericArgKind::Type(_) | GenericArgKind::Const(_) => true, GenericArgKind::Lifetime(_) => false, diff --git a/compiler/rustc_mir/src/monomorphize/polymorphize.rs b/compiler/rustc_mir/src/monomorphize/polymorphize.rs index 30e758c7fdf05..4d69fae463231 100644 --- a/compiler/rustc_mir/src/monomorphize/polymorphize.rs +++ b/compiler/rustc_mir/src/monomorphize/polymorphize.rs @@ -178,7 +178,7 @@ fn mark_used_by_predicates<'tcx>( // Consider all generic params in a predicate as used if any other parameter in the // predicate is used. let any_param_used = { - let mut vis = HasUsedGenericParams { unused_parameters }; + let mut vis = HasUsedGenericParams { tcx, unused_parameters }; predicate.visit_with(&mut vis).is_break() }; @@ -287,9 +287,12 @@ impl<'a, 'tcx> Visitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> { } impl<'a, 'tcx> TypeVisitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> { + fn tcx_for_anon_const_substs(&self) -> Option> { + Some(self.tcx) + } #[instrument(skip(self))] fn visit_const(&mut self, c: &'tcx Const<'tcx>) -> ControlFlow { - if !c.has_param_types_or_consts() { + if !c.has_potential_param_types_or_consts() { return ControlFlow::CONTINUE; } @@ -299,7 +302,7 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> { self.unused_parameters.clear(param.index); ControlFlow::CONTINUE } - ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs: _, promoted: Some(p)}) + ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs_: _, promoted: Some(p)}) // Avoid considering `T` unused when constants are of the form: // `>::foo::promoted[p]` if self.def_id == def.did && !self.tcx.generics_of(def.did).has_self => @@ -310,10 +313,10 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> { self.visit_body(&promoted[p]); ControlFlow::CONTINUE } - ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted: None }) - if self.tcx.def_kind(def.did) == DefKind::AnonConst => + ty::ConstKind::Unevaluated(uv) + if self.tcx.def_kind(uv.def.did) == DefKind::AnonConst => { - self.visit_child_body(def.did, substs); + self.visit_child_body(uv.def.did, uv.substs(self.tcx)); ControlFlow::CONTINUE } _ => c.super_visit_with(self), @@ -322,7 +325,7 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> { #[instrument(skip(self))] fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow { - if !ty.has_param_types_or_consts() { + if !ty.has_potential_param_types_or_consts() { return ControlFlow::CONTINUE; } @@ -350,16 +353,21 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> { } /// Visitor used to check if a generic parameter is used. -struct HasUsedGenericParams<'a> { +struct HasUsedGenericParams<'a, 'tcx> { + tcx: TyCtxt<'tcx>, unused_parameters: &'a FiniteBitSet, } -impl<'a, 'tcx> TypeVisitor<'tcx> for HasUsedGenericParams<'a> { +impl<'a, 'tcx> TypeVisitor<'tcx> for HasUsedGenericParams<'a, 'tcx> { type BreakTy = (); + fn tcx_for_anon_const_substs(&self) -> Option> { + Some(self.tcx) + } + #[instrument(skip(self))] fn visit_const(&mut self, c: &'tcx Const<'tcx>) -> ControlFlow { - if !c.has_param_types_or_consts() { + if !c.has_potential_param_types_or_consts() { return ControlFlow::CONTINUE; } @@ -377,7 +385,7 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for HasUsedGenericParams<'a> { #[instrument(skip(self))] fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow { - if !ty.has_param_types_or_consts() { + if !ty.has_potential_param_types_or_consts() { return ControlFlow::CONTINUE; } diff --git a/compiler/rustc_mir/src/shim.rs b/compiler/rustc_mir/src/shim.rs index 796d024771d7f..a6cb2d82cac42 100644 --- a/compiler/rustc_mir/src/shim.rs +++ b/compiler/rustc_mir/src/shim.rs @@ -163,7 +163,7 @@ fn build_drop_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, ty: Option>) let source = MirSource::from_instance(ty::InstanceDef::DropGlue(def_id, ty)); let mut body = - new_body(source, blocks, local_decls_for_sig(&sig, span), sig.inputs().len(), span); + new_body(tcx, source, blocks, local_decls_for_sig(&sig, span), sig.inputs().len(), span); if ty.is_some() { // The first argument (index 0), but add 1 for the return value. @@ -202,6 +202,7 @@ fn build_drop_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, ty: Option>) } fn new_body<'tcx>( + tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, basic_blocks: IndexVec>, local_decls: IndexVec>, @@ -209,6 +210,7 @@ fn new_body<'tcx>( span: Span, ) -> Body<'tcx> { Body::new( + tcx, source, basic_blocks, IndexVec::from_elem_n( @@ -353,7 +355,14 @@ impl CloneShimBuilder<'tcx> { self.def_id, self.sig.inputs_and_output[0], )); - new_body(source, self.blocks, self.local_decls, self.sig.inputs().len(), self.span) + new_body( + self.tcx, + source, + self.blocks, + self.local_decls, + self.sig.inputs().len(), + self.span, + ) } fn source_info(&self) -> SourceInfo { @@ -851,8 +860,14 @@ fn build_call_shim<'tcx>( block(&mut blocks, vec![], TerminatorKind::Resume, true); } - let mut body = - new_body(MirSource::from_instance(instance), blocks, local_decls, sig.inputs().len(), span); + let mut body = new_body( + tcx, + MirSource::from_instance(instance), + blocks, + local_decls, + sig.inputs().len(), + span, + ); if let Abi::RustCall = sig.abi { body.spread_arg = Some(Local::new(sig.inputs().len())); @@ -917,6 +932,7 @@ pub fn build_adt_ctor(tcx: TyCtxt<'_>, ctor_id: DefId) -> Body<'_> { let source = MirSource::item(ctor_id); let body = new_body( + tcx, source, IndexVec::from_elem_n(start_block, 1), local_decls, diff --git a/compiler/rustc_mir/src/transform/check_consts/qualifs.rs b/compiler/rustc_mir/src/transform/check_consts/qualifs.rs index ac8c748ea8571..413a9638eb37b 100644 --- a/compiler/rustc_mir/src/transform/check_consts/qualifs.rs +++ b/compiler/rustc_mir/src/transform/check_consts/qualifs.rs @@ -247,7 +247,7 @@ where // Check the qualifs of the value of `const` items. if let Some(ct) = constant.literal.const_for_ty() { - if let ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs: _, promoted }) = ct.val { + if let ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs_: _, promoted }) = ct.val { assert!(promoted.is_none()); // Don't peek inside trait associated constants. if cx.tcx.trait_of_item(def.did).is_none() { diff --git a/compiler/rustc_mir/src/transform/check_consts/validation.rs b/compiler/rustc_mir/src/transform/check_consts/validation.rs index 646ae8ced7eb4..79b78c2cb05c5 100644 --- a/compiler/rustc_mir/src/transform/check_consts/validation.rs +++ b/compiler/rustc_mir/src/transform/check_consts/validation.rs @@ -365,7 +365,7 @@ impl Validator<'mir, 'tcx> { fn check_local_or_return_ty(&mut self, ty: Ty<'tcx>, local: Local) { let kind = self.body.local_kind(local); - for ty in ty.walk() { + for ty in ty.walk(self.tcx) { let ty = match ty.unpack() { GenericArgKind::Type(ty) => ty, diff --git a/compiler/rustc_mir/src/transform/const_prop.rs b/compiler/rustc_mir/src/transform/const_prop.rs index e02e41d62061a..78cb3e7a6723c 100644 --- a/compiler/rustc_mir/src/transform/const_prop.rs +++ b/compiler/rustc_mir/src/transform/const_prop.rs @@ -120,7 +120,7 @@ impl<'tcx> MirPass<'tcx> for ConstProp { .predicates_of(def_id.to_def_id()) .predicates .iter() - .filter_map(|(p, _)| if p.is_global() { Some(*p) } else { None }); + .filter_map(|(p, _)| if p.is_global(tcx) { Some(*p) } else { None }); if traits::impossible_predicates( tcx, traits::elaborate_predicates(tcx, predicates).map(|o| o.predicate).collect(), @@ -132,6 +132,7 @@ impl<'tcx> MirPass<'tcx> for ConstProp { trace!("ConstProp starting for {:?}", def_id); let dummy_body = &Body::new( + tcx, body.source, body.basic_blocks().clone(), body.source_scopes.clone(), @@ -468,7 +469,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { /// Returns the value, if any, of evaluating `c`. fn eval_constant(&mut self, c: &Constant<'tcx>, source_info: SourceInfo) -> Option> { // FIXME we need to revisit this for #67176 - if c.needs_subst() { + if c.needs_subst(self.tcx) { return None; } @@ -483,14 +484,14 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { // Promoteds must lint and not error as the user didn't ask for them ConstKind::Unevaluated(ty::Unevaluated { def: _, - substs: _, + substs_: _, promoted: Some(_), }) => true, // Out of backwards compatibility we cannot report hard errors in unused // generic functions using associated constants of the generic parameters. - _ => c.literal.needs_subst(), + _ => c.literal.needs_subst(*tcx), }, - ConstantKind::Val(_, ty) => ty.needs_subst(), + ConstantKind::Val(_, ty) => ty.needs_subst(*tcx), }; if lint_only { // Out of backwards compatibility we cannot report hard errors in unused @@ -720,7 +721,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { } // FIXME we need to revisit this for #67176 - if rvalue.needs_subst() { + if rvalue.needs_subst(self.tcx) { return None; } diff --git a/compiler/rustc_mir/src/transform/function_item_references.rs b/compiler/rustc_mir/src/transform/function_item_references.rs index 8d02ac6d9b774..7ffb5950fdc9e 100644 --- a/compiler/rustc_mir/src/transform/function_item_references.rs +++ b/compiler/rustc_mir/src/transform/function_item_references.rs @@ -49,7 +49,7 @@ impl<'a, 'tcx> Visitor<'tcx> for FunctionItemRefChecker<'a, 'tcx> { // Handle calls to `transmute` if self.tcx.is_diagnostic_item(sym::transmute, def_id) { let arg_ty = args[0].ty(self.body, self.tcx); - for generic_inner_ty in arg_ty.walk() { + for generic_inner_ty in arg_ty.walk(self.tcx) { if let GenericArgKind::Type(inner_ty) = generic_inner_ty.unpack() { if let Some((fn_id, fn_substs)) = FunctionItemRefChecker::is_fn_ref(inner_ty) @@ -110,7 +110,7 @@ impl<'a, 'tcx> FunctionItemRefChecker<'a, 'tcx> { let arg_defs = self.tcx.fn_sig(def_id).skip_binder().inputs(); for (arg_num, arg_def) in arg_defs.iter().enumerate() { // For all types reachable from the argument type in the fn sig - for generic_inner_ty in arg_def.walk() { + for generic_inner_ty in arg_def.walk(self.tcx) { if let GenericArgKind::Type(inner_ty) = generic_inner_ty.unpack() { // If the inner type matches the type bound by `Pointer` if TyS::same_type(inner_ty, bound_ty) { diff --git a/compiler/rustc_mir/src/transform/inline/cycle.rs b/compiler/rustc_mir/src/transform/inline/cycle.rs index c9eafafff57cd..46628b928de92 100644 --- a/compiler/rustc_mir/src/transform/inline/cycle.rs +++ b/compiler/rustc_mir/src/transform/inline/cycle.rs @@ -89,7 +89,7 @@ crate fn mir_callgraph_reachable( // FIXME: A not fully substituted drop shim can cause ICEs if one attempts to // have its MIR built. Likely oli-obk just screwed up the `ParamEnv`s, so this // needs some more analysis. - if callee.needs_subst() { + if callee.needs_subst(tcx) { continue; } } diff --git a/compiler/rustc_mir/src/transform/mod.rs b/compiler/rustc_mir/src/transform/mod.rs index 5c201594ddd89..e04a9611ae1c5 100644 --- a/compiler/rustc_mir/src/transform/mod.rs +++ b/compiler/rustc_mir/src/transform/mod.rs @@ -397,7 +397,7 @@ fn inner_mir_for_ctfe(tcx: TyCtxt<'_>, def: ty::WithOptConstParam) - } } - debug_assert!(!body.has_free_regions(), "Free regions in MIR for CTFE"); + debug_assert!(!body.has_free_regions(tcx), "Free regions in MIR for CTFE"); body } @@ -588,7 +588,7 @@ fn inner_optimized_mir(tcx: TyCtxt<'_>, did: LocalDefId) -> Body<'_> { tcx.mir_drops_elaborated_and_const_checked(ty::WithOptConstParam::unknown(did)).steal(); run_optimization_passes(tcx, &mut body); - debug_assert!(!body.has_free_regions(), "Free regions in optimized MIR"); + debug_assert!(!body.has_free_regions(tcx), "Free regions in optimized MIR"); body } @@ -615,7 +615,7 @@ fn promoted_mir<'tcx>( run_post_borrowck_cleanup_passes(tcx, body); } - debug_assert!(!promoted.has_free_regions(), "Free regions in promoted MIR"); + debug_assert!(!promoted.has_free_regions(tcx), "Free regions in promoted MIR"); tcx.arena.alloc(promoted) } diff --git a/compiler/rustc_mir/src/transform/promote_consts.rs b/compiler/rustc_mir/src/transform/promote_consts.rs index 78e84419c62cd..a4a9df7b7c26f 100644 --- a/compiler/rustc_mir/src/transform/promote_consts.rs +++ b/compiler/rustc_mir/src/transform/promote_consts.rs @@ -859,13 +859,17 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { ty, val: ty::ConstKind::Unevaluated(ty::Unevaluated { def, - substs: InternalSubsts::for_item(tcx, def.did, |param, _| { - if let ty::GenericParamDefKind::Lifetime = param.kind { - tcx.lifetimes.re_erased.into() - } else { - tcx.mk_param_from_def(param) - } - }), + substs_: Some(InternalSubsts::for_item( + tcx, + def.did, + |param, _| { + if let ty::GenericParamDefKind::Lifetime = param.kind { + tcx.lifetimes.re_erased.into() + } else { + tcx.mk_param_from_def(param) + } + }, + )), promoted: Some(promoted_id), }), }) @@ -988,6 +992,7 @@ pub fn promote_candidates<'tcx>( scope.parent_scope = None; let promoted = Body::new( + tcx, body.source, // `promoted` gets filled in below IndexVec::new(), IndexVec::from_elem_n(scope, 1), diff --git a/compiler/rustc_mir/src/util/pretty.rs b/compiler/rustc_mir/src/util/pretty.rs index d0b1bc47ea800..e1399fa6a1b07 100644 --- a/compiler/rustc_mir/src/util/pretty.rs +++ b/compiler/rustc_mir/src/util/pretty.rs @@ -475,7 +475,7 @@ impl Visitor<'tcx> for ExtraComments<'tcx> { ty::ConstKind::Unevaluated(uv) => format!( "Unevaluated({}, {:?}, {:?})", self.tcx.def_path_str(uv.def.did), - uv.substs, + uv.substs(self.tcx), uv.promoted ), ty::ConstKind::Value(val) => format!("Value({:?})", val), @@ -682,6 +682,12 @@ pub fn write_allocations<'tcx>( } struct CollectAllocIds(BTreeSet); impl<'tcx> TypeVisitor<'tcx> for CollectAllocIds { + fn tcx_for_anon_const_substs(&self) -> Option> { + // `AllocId`s are only inside of `ConstKind::Value` which + // can't be part of the anon const default substs. + None + } + fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow { if let ty::ConstKind::Value(val) = c.val { self.0.extend(alloc_ids_from_const(val)); diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs index 60cfd73b19a6e..f218a60c256a3 100644 --- a/compiler/rustc_mir_build/src/build/mod.rs +++ b/compiler/rustc_mir_build/src/build/mod.rs @@ -241,10 +241,10 @@ fn mir_build(tcx: TyCtxt<'_>, def: ty::WithOptConstParam) -> Body<'_ // The exception is `body.user_type_annotations`, which is used unmodified // by borrow checking. debug_assert!( - !(body.local_decls.has_free_regions() - || body.basic_blocks().has_free_regions() - || body.var_debug_info.has_free_regions() - || body.yield_ty().has_free_regions()), + !(body.local_decls.has_free_regions(tcx) + || body.basic_blocks().has_free_regions(tcx) + || body.var_debug_info.has_free_regions(tcx) + || body.yield_ty().has_free_regions(tcx)), "Unexpected free regions in MIR: {:?}", body, ); @@ -812,6 +812,7 @@ fn construct_error<'a, 'tcx>( cfg.terminate(START_BLOCK, source_info, TerminatorKind::Unreachable); let mut body = Body::new( + tcx, MirSource::item(def.did.to_def_id()), cfg.basic_blocks, source_scopes, @@ -900,6 +901,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } Body::new( + self.tcx, MirSource::item(self.def_id), self.cfg.basic_blocks, self.source_scopes, diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index c3908ddd4fbe8..75e356433cce4 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -690,11 +690,10 @@ impl<'tcx> Cx<'tcx> { // and not the beginning of discriminants (which is always `0`) let substs = InternalSubsts::identity_for_item(self.tcx(), did); let lhs = ty::Const { - val: ty::ConstKind::Unevaluated(ty::Unevaluated { - def: ty::WithOptConstParam::unknown(did), + val: ty::ConstKind::Unevaluated(ty::Unevaluated::new( + ty::WithOptConstParam::unknown(did), substs, - promoted: None, - }), + )), ty: var_ty, }; let lhs = self.thir.exprs.push(mk_const(self.tcx().mk_const(lhs))); @@ -886,11 +885,10 @@ impl<'tcx> Cx<'tcx> { debug!("convert_path_expr: (const) user_ty={:?}", user_ty); ExprKind::Literal { literal: self.tcx.mk_const(ty::Const { - val: ty::ConstKind::Unevaluated(ty::Unevaluated { - def: ty::WithOptConstParam::unknown(def_id), + val: ty::ConstKind::Unevaluated(ty::Unevaluated::new( + ty::WithOptConstParam::unknown(def_id), substs, - promoted: None, - }), + )), ty: self.typeck_results().node_type(expr.hir_id), }), user_ty, diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs index 3859b22223c00..6d4234b64a0b3 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs @@ -240,7 +240,7 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { // code at the moment, because types like `for <'a> fn(&'a ())` do // not *yet* implement `PartialEq`. So for now we leave this here. has_impl - || ty.walk().any(|t| match t.unpack() { + || ty.walk(self.tcx()).any(|t| match t.unpack() { ty::subst::GenericArgKind::Lifetime(_) => false, ty::subst::GenericArgKind::Type(t) => t.is_fn_ptr(), ty::subst::GenericArgKind::Const(_) => false, diff --git a/compiler/rustc_parse/src/parser/attr.rs b/compiler/rustc_parse/src/parser/attr.rs index 8b050389078a6..e9f0038b2d65d 100644 --- a/compiler/rustc_parse/src/parser/attr.rs +++ b/compiler/rustc_parse/src/parser/attr.rs @@ -64,7 +64,14 @@ impl<'a> Parser<'a> { } self.bump(); just_parsed_doc_comment = true; - Some(attr::mk_doc_comment(comment_kind, attr_style, data, self.prev_token.span)) + // Always make an outer attribute - this allows us to recover from a misplaced + // inner attribute. + Some(attr::mk_doc_comment( + comment_kind, + ast::AttrStyle::Outer, + data, + self.prev_token.span, + )) } else { None }; diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 47fdd852d90de..ef05f64da94ed 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -431,7 +431,8 @@ impl<'a> Parser<'a> { let span = self.mk_expr_sp(&lhs, lhs.span, rhs_span); let limits = if op == AssocOp::DotDot { RangeLimits::HalfOpen } else { RangeLimits::Closed }; - Ok(self.mk_expr(span, self.mk_range(Some(lhs), rhs, limits), AttrVec::new())) + let range = self.mk_range(Some(lhs), rhs, limits); + Ok(self.mk_expr(span, range, AttrVec::new())) } fn is_at_start_of_range_notation_rhs(&self) -> bool { @@ -479,7 +480,8 @@ impl<'a> Parser<'a> { } else { (lo, None) }; - Ok(this.mk_expr(span, this.mk_range(None, opt_end, limits), attrs.into())) + let range = this.mk_range(None, opt_end, limits); + Ok(this.mk_expr(span, range, attrs.into())) }) } @@ -2517,13 +2519,13 @@ impl<'a> Parser<'a> { } fn mk_range( - &self, + &mut self, start: Option>, end: Option>, limits: RangeLimits, ) -> ExprKind { if end.is_none() && limits == RangeLimits::Closed { - self.error_inclusive_range_with_no_end(self.prev_token.span); + self.inclusive_range_with_incorrect_end(self.prev_token.span); ExprKind::Err } else { ExprKind::Range(start, end, limits) diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index e047dae15973e..7219e39ea6ba0 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -797,15 +797,48 @@ impl<'a> Parser<'a> { // Parsing e.g. `X..`. if let RangeEnd::Included(_) = re.node { // FIXME(Centril): Consider semantic errors instead in `ast_validation`. - // Possibly also do this for `X..=` in *expression* contexts. - self.error_inclusive_range_with_no_end(re.span); + self.inclusive_range_with_incorrect_end(re.span); } None }; Ok(PatKind::Range(Some(begin), end, re)) } - pub(super) fn error_inclusive_range_with_no_end(&self, span: Span) { + pub(super) fn inclusive_range_with_incorrect_end(&mut self, span: Span) { + let tok = &self.token; + + // If the user typed "..==" instead of "..=", we want to give them + // a specific error message telling them to use "..=". + // Otherwise, we assume that they meant to type a half open exclusive + // range and give them an error telling them to do that instead. + if matches!(tok.kind, token::Eq) && tok.span.lo() == span.hi() { + let span_with_eq = span.to(tok.span); + + // Ensure the user doesn't receive unhelpful unexpected token errors + self.bump(); + if self.is_pat_range_end_start(0) { + let _ = self.parse_pat_range_end(); + } + + self.error_inclusive_range_with_extra_equals(span_with_eq); + } else { + self.error_inclusive_range_with_no_end(span); + } + } + + fn error_inclusive_range_with_extra_equals(&self, span: Span) { + self.struct_span_err(span, "unexpected `=` after inclusive range") + .span_suggestion_short( + span, + "use `..=` instead", + "..=".to_string(), + Applicability::MaybeIncorrect, + ) + .note("inclusive ranges end with a single equals sign (`..=`)") + .emit(); + } + + fn error_inclusive_range_with_no_end(&self, span: Span) { struct_span_err!(self.sess.span_diagnostic, span, E0586, "inclusive range with no end") .span_suggestion_short( span, diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index bef56bbc2875f..713d572b93a0b 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -150,6 +150,59 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { } } + fn check_for_self_assign(&mut self, assign: &'tcx hir::Expr<'tcx>) { + fn check_for_self_assign_helper( + tcx: TyCtxt<'tcx>, + typeck_results: &'tcx ty::TypeckResults<'tcx>, + lhs: &'tcx hir::Expr<'tcx>, + rhs: &'tcx hir::Expr<'tcx>, + ) -> bool { + match (&lhs.kind, &rhs.kind) { + (hir::ExprKind::Path(ref qpath_l), hir::ExprKind::Path(ref qpath_r)) => { + if let (Res::Local(id_l), Res::Local(id_r)) = ( + typeck_results.qpath_res(qpath_l, lhs.hir_id), + typeck_results.qpath_res(qpath_r, rhs.hir_id), + ) { + if id_l == id_r { + return true; + } + } + return false; + } + (hir::ExprKind::Field(lhs_l, ident_l), hir::ExprKind::Field(lhs_r, ident_r)) => { + if ident_l == ident_r { + return check_for_self_assign_helper(tcx, typeck_results, lhs_l, lhs_r); + } + return false; + } + _ => { + return false; + } + } + } + + if let hir::ExprKind::Assign(lhs, rhs, _) = assign.kind { + if check_for_self_assign_helper(self.tcx, self.typeck_results(), lhs, rhs) + && !assign.span.from_expansion() + { + let is_field_assign = matches!(lhs.kind, hir::ExprKind::Field(..)); + self.tcx.struct_span_lint_hir( + lint::builtin::DEAD_CODE, + assign.hir_id, + assign.span, + |lint| { + lint.build(&format!( + "useless assignment of {} of type `{}` to itself", + if is_field_assign { "field" } else { "variable" }, + self.typeck_results().expr_ty(lhs), + )) + .emit(); + }, + ) + } + } + } + fn handle_field_pattern_match( &mut self, lhs: &hir::Pat<'_>, @@ -287,6 +340,7 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> { } hir::ExprKind::Assign(ref left, ref right, ..) => { self.handle_assign(left); + self.check_for_self_assign(expr); self.visit_expr(right); return; } diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index d969f50c1d918..c85194213a0b4 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -133,11 +133,11 @@ where ty.visit_with(self) } ty::PredicateKind::RegionOutlives(..) => ControlFlow::CONTINUE, - ty::PredicateKind::ConstEvaluatable(defs, substs) + ty::PredicateKind::ConstEvaluatable(uv) if self.def_id_visitor.tcx().features().const_evaluatable_checked => { let tcx = self.def_id_visitor.tcx(); - if let Ok(Some(ct)) = AbstractConst::new(tcx, defs, substs) { + if let Ok(Some(ct)) = AbstractConst::new(tcx, uv) { self.visit_abstract_const_expr(tcx, ct)?; } ControlFlow::CONTINUE @@ -178,6 +178,10 @@ where { type BreakTy = V::BreakTy; + fn tcx_for_anon_const_substs(&self) -> Option> { + Some(self.def_id_visitor.tcx()) + } + fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow { let tcx = self.def_id_visitor.tcx(); // InternalSubsts are not visited here because they are visited below in `super_visit_with`. diff --git a/compiler/rustc_query_impl/Cargo.toml b/compiler/rustc_query_impl/Cargo.toml index 5be06dfdc7797..6a1768b92dbbb 100644 --- a/compiler/rustc_query_impl/Cargo.toml +++ b/compiler/rustc_query_impl/Cargo.toml @@ -11,10 +11,14 @@ doctest = false measureme = "9.0.0" rustc-rayon-core = "0.3.1" tracing = "0.1" +rustc_ast = { path = "../rustc_ast" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } rustc_hir = { path = "../rustc_hir" } +rustc_index = { path = "../rustc_index" } +rustc_macros = { path = "../rustc_macros" } rustc_middle = { path = "../rustc_middle" } rustc_query_system = { path = "../rustc_query_system" } -rustc_span = { path = "../rustc_span" } rustc_serialize = { path = "../rustc_serialize" } +rustc_session = { path = "../rustc_session" } +rustc_span = { path = "../rustc_span" } diff --git a/compiler/rustc_query_impl/src/keys.rs b/compiler/rustc_query_impl/src/keys.rs index 1993e0a602fa5..092c60050fb65 100644 --- a/compiler/rustc_query_impl/src/keys.rs +++ b/compiler/rustc_query_impl/src/keys.rs @@ -217,18 +217,13 @@ impl<'tcx> Key for (DefId, SubstsRef<'tcx>) { } } -impl<'tcx> Key - for ( - (ty::WithOptConstParam, SubstsRef<'tcx>), - (ty::WithOptConstParam, SubstsRef<'tcx>), - ) -{ +impl<'tcx> Key for (ty::Unevaluated<'tcx>, ty::Unevaluated<'tcx>) { #[inline(always)] fn query_crate_is_local(&self) -> bool { - (self.0).0.did.krate == LOCAL_CRATE + (self.0).def.did.krate == LOCAL_CRATE } fn default_span(&self, tcx: TyCtxt<'_>) -> Span { - (self.0).0.did.default_span(tcx) + (self.0).def.did.default_span(tcx) } } diff --git a/compiler/rustc_query_impl/src/lib.rs b/compiler/rustc_query_impl/src/lib.rs index 1d831affd1dee..5022bf265328a 100644 --- a/compiler/rustc_query_impl/src/lib.rs +++ b/compiler/rustc_query_impl/src/lib.rs @@ -1,12 +1,16 @@ //! Support for serializing the dep-graph and reloading it. #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] +#![feature(crate_visibility_modifier)] #![feature(in_band_lifetimes)] #![feature(nll)] #![feature(min_specialization)] +#![feature(once_cell)] #![feature(rustc_attrs)] #![recursion_limit = "256"] +#[macro_use] +extern crate rustc_macros; #[macro_use] extern crate rustc_middle; #[macro_use] @@ -14,13 +18,12 @@ extern crate tracing; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; -use rustc_errors::{DiagnosticBuilder, Handler}; +use rustc_errors::DiagnosticBuilder; use rustc_middle::dep_graph; use rustc_middle::ich::StableHashingContext; use rustc_middle::ty::query::{query_keys, query_storage, query_stored, query_values}; use rustc_middle::ty::query::{Providers, QueryEngine}; use rustc_middle::ty::{self, TyCtxt}; -use rustc_serialize::opaque; use rustc_span::Span; #[macro_use] @@ -42,7 +45,8 @@ use rustc_query_system::query::QueryAccessors; pub use rustc_query_system::query::QueryConfig; pub(crate) use rustc_query_system::query::QueryDescription; -use rustc_middle::ty::query::on_disk_cache; +mod on_disk_cache; +pub use on_disk_cache::OnDiskCache; mod profiling_support; pub use self::profiling_support::alloc_self_profile_query_strings; diff --git a/compiler/rustc_middle/src/ty/query/on_disk_cache.rs b/compiler/rustc_query_impl/src/on_disk_cache.rs similarity index 90% rename from compiler/rustc_middle/src/ty/query/on_disk_cache.rs rename to compiler/rustc_query_impl/src/on_disk_cache.rs index e3db0d2cf30a6..b024668d63646 100644 --- a/compiler/rustc_middle/src/ty/query/on_disk_cache.rs +++ b/compiler/rustc_query_impl/src/on_disk_cache.rs @@ -1,9 +1,4 @@ -use crate::dep_graph::{DepNode, DepNodeIndex, SerializedDepNodeIndex}; -use crate::mir::interpret::{AllocDecodingSession, AllocDecodingState}; -use crate::mir::{self, interpret}; -use crate::ty::codec::{RefDecodable, TyDecoder, TyEncoder}; -use crate::ty::context::TyCtxt; -use crate::ty::{self, Ty}; +use crate::QueryCtxt; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet}; use rustc_data_structures::sync::{HashMapExt, Lock, Lrc, OnceCell}; use rustc_data_structures::thin_vec::ThinVec; @@ -12,6 +7,11 @@ use rustc_errors::Diagnostic; use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, StableCrateId, LOCAL_CRATE}; use rustc_hir::definitions::DefPathHash; use rustc_index::vec::{Idx, IndexVec}; +use rustc_middle::dep_graph::{DepNode, DepNodeIndex, SerializedDepNodeIndex}; +use rustc_middle::mir::interpret::{AllocDecodingSession, AllocDecodingState}; +use rustc_middle::mir::{self, interpret}; +use rustc_middle::ty::codec::{RefDecodable, TyDecoder, TyEncoder}; +use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_query_system::dep_graph::DepContext; use rustc_query_system::query::QueryContext; use rustc_serialize::{ @@ -20,8 +20,7 @@ use rustc_serialize::{ }; use rustc_session::Session; use rustc_span::hygiene::{ - ExpnDataDecodeMode, ExpnDataEncodeMode, ExpnId, HygieneDecodeContext, HygieneEncodeContext, - SyntaxContext, SyntaxContextData, + ExpnId, HygieneDecodeContext, HygieneEncodeContext, SyntaxContext, SyntaxContextData, }; use rustc_span::source_map::{SourceMap, StableSourceFileId}; use rustc_span::CachingSourceMapView; @@ -84,7 +83,7 @@ pub struct OnDiskCache<'sess> { // `ExpnData` (e.g `ExpnData.krate` may not be `LOCAL_CRATE`). Alternatively, // we could look up the `ExpnData` from the metadata of foreign crates, // but it seemed easier to have `OnDiskCache` be independent of the `CStore`. - expn_data: FxHashMap, + expn_data: UnhashMap, // Additional information used when decoding hygiene data. hygiene_context: HygieneDecodeContext, // Maps `DefPathHash`es to their `RawDefId`s from the *previous* @@ -92,6 +91,8 @@ pub struct OnDiskCache<'sess> { // we try to map a `DefPathHash` to its `DefId` in the current compilation // session. foreign_def_path_hashes: UnhashMap, + // Likewise for ExpnId. + foreign_expn_data: UnhashMap, // The *next* compilation sessison's `foreign_def_path_hashes` - at // the end of our current compilation session, this will get written @@ -119,8 +120,9 @@ struct Footer { // See `OnDiskCache.syntax_contexts` syntax_contexts: FxHashMap, // See `OnDiskCache.expn_data` - expn_data: FxHashMap, + expn_data: UnhashMap, foreign_def_path_hashes: UnhashMap, + foreign_expn_data: UnhashMap, } pub type EncodedQueryResultIndex = Vec<(SerializedDepNodeIndex, AbsoluteBytePos)>; @@ -183,9 +185,8 @@ impl EncodedSourceFileId { } } -impl<'sess> OnDiskCache<'sess> { - /// Creates a new `OnDiskCache` instance from the serialized data in `data`. - pub fn new(sess: &'sess Session, data: Vec, start_pos: usize) -> Self { +impl<'sess> rustc_middle::ty::OnDiskCache<'sess> for OnDiskCache<'sess> { + fn new(sess: &'sess Session, data: Vec, start_pos: usize) -> Self { debug_assert!(sess.opts.incremental.is_some()); // Wrap in a scope so we can borrow `data`. @@ -218,6 +219,7 @@ impl<'sess> OnDiskCache<'sess> { alloc_decoding_state: AllocDecodingState::new(footer.interpret_alloc_index), syntax_contexts: footer.syntax_contexts, expn_data: footer.expn_data, + foreign_expn_data: footer.foreign_expn_data, hygiene_context: Default::default(), foreign_def_path_hashes: footer.foreign_def_path_hashes, latest_foreign_def_path_hashes: Default::default(), @@ -225,7 +227,7 @@ impl<'sess> OnDiskCache<'sess> { } } - pub fn new_empty(source_map: &'sess SourceMap) -> Self { + fn new_empty(source_map: &'sess SourceMap) -> Self { Self { serialized_data: Vec::new(), file_index_to_stable_id: Default::default(), @@ -237,7 +239,8 @@ impl<'sess> OnDiskCache<'sess> { prev_diagnostics_index: Default::default(), alloc_decoding_state: AllocDecodingState::new(Vec::new()), syntax_contexts: FxHashMap::default(), - expn_data: FxHashMap::default(), + expn_data: UnhashMap::default(), + foreign_expn_data: UnhashMap::default(), hygiene_context: Default::default(), foreign_def_path_hashes: Default::default(), latest_foreign_def_path_hashes: Default::default(), @@ -245,11 +248,7 @@ impl<'sess> OnDiskCache<'sess> { } } - pub fn serialize<'tcx>( - &self, - tcx: TyCtxt<'tcx>, - encoder: &mut FileEncoder, - ) -> FileEncodeResult { + fn serialize(&self, tcx: TyCtxt<'sess>, encoder: &mut FileEncoder) -> FileEncodeResult { // Serializing the `DepGraph` should not modify it. tcx.dep_graph.with_ignore(|| { // Allocate `SourceFileIndex`es. @@ -284,7 +283,7 @@ impl<'sess> OnDiskCache<'sess> { // 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.queries.exec_cache_promotions(tcx); + 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(); @@ -307,7 +306,7 @@ impl<'sess> OnDiskCache<'sess> { tcx.sess.time("encode_query_results", || -> FileEncodeResult { let enc = &mut encoder; let qri = &mut query_result_index; - tcx.queries.encode_query_results(tcx, enc, qri) + QueryCtxt::from_tcx(tcx).encode_query_results(enc, qri) })?; // Encode diagnostics. @@ -351,7 +350,8 @@ impl<'sess> OnDiskCache<'sess> { }; let mut syntax_contexts = FxHashMap::default(); - let mut expn_ids = FxHashMap::default(); + let mut expn_data = UnhashMap::default(); + let mut foreign_expn_data = UnhashMap::default(); // Encode all hygiene data (`SyntaxContextData` and `ExpnData`) from the current // session. @@ -364,10 +364,14 @@ impl<'sess> OnDiskCache<'sess> { syntax_contexts.insert(index, pos); Ok(()) }, - |encoder, index, expn_data, hash| -> FileEncodeResult { - let pos = AbsoluteBytePos::new(encoder.position()); - encoder.encode_tagged(TAG_EXPN_DATA, &(expn_data, hash))?; - expn_ids.insert(index, pos); + |encoder, expn_id, data, hash| -> FileEncodeResult { + if expn_id.krate == LOCAL_CRATE { + let pos = AbsoluteBytePos::new(encoder.position()); + encoder.encode_tagged(TAG_EXPN_DATA, data)?; + expn_data.insert(hash, pos); + } else { + foreign_expn_data.insert(hash, expn_id.local_id.as_u32()); + } Ok(()) }, )?; @@ -385,7 +389,8 @@ impl<'sess> OnDiskCache<'sess> { diagnostics_index, interpret_alloc_index, syntax_contexts, - expn_data: expn_ids, + expn_data, + foreign_expn_data, foreign_def_path_hashes, }, )?; @@ -401,6 +406,88 @@ impl<'sess> OnDiskCache<'sess> { }) } + fn def_path_hash_to_def_id(&self, tcx: TyCtxt<'tcx>, hash: DefPathHash) -> Option { + let mut cache = self.def_path_hash_to_def_id_cache.lock(); + match cache.entry(hash) { + Entry::Occupied(e) => *e.get(), + Entry::Vacant(e) => { + debug!("def_path_hash_to_def_id({:?})", hash); + // Check if the `DefPathHash` corresponds to a definition in the current + // crate + if let Some(def_id) = + tcx.definitions_untracked().local_def_path_hash_to_def_id(hash) + { + let def_id = def_id.to_def_id(); + e.insert(Some(def_id)); + return Some(def_id); + } + // This `raw_def_id` represents the `DefId` of this `DefPathHash` in + // the *previous* compliation session. The `DefPathHash` includes the + // owning crate, so if the corresponding definition still exists in the + // current compilation session, the crate is guaranteed to be the same + // (otherwise, we would compute a different `DefPathHash`). + let raw_def_id = self.get_raw_def_id(&hash)?; + debug!("def_path_hash_to_def_id({:?}): raw_def_id = {:?}", hash, raw_def_id); + // If the owning crate no longer exists, the corresponding definition definitely + // no longer exists. + let krate = self.try_remap_cnum(tcx, hash.stable_crate_id())?; + debug!("def_path_hash_to_def_id({:?}): krate = {:?}", hash, krate); + // If our `DefPathHash` corresponded to a definition in the local crate, + // we should have either found it in `local_def_path_hash_to_def_id`, or + // never attempted to load it in the first place. Any query result or `DepNode` + // that references a local `DefId` should depend on some HIR-related `DepNode`. + // If a local definition is removed/modified such that its old `DefPathHash` + // no longer has a corresponding definition, that HIR-related `DepNode` should + // end up red. This should prevent us from ever calling + // `tcx.def_path_hash_to_def_id`, since we'll end up recomputing any + // queries involved. + debug_assert_ne!(krate, LOCAL_CRATE); + // Try to find a definition in the current session, using the previous `DefIndex` + // as an initial guess. + let opt_def_id = + tcx.cstore_untracked().def_path_hash_to_def_id(krate, raw_def_id.index, hash); + debug!("def_path_to_def_id({:?}): opt_def_id = {:?}", hash, opt_def_id); + e.insert(opt_def_id); + opt_def_id + } + } + } + + fn register_reused_dep_node(&self, tcx: TyCtxt<'sess>, dep_node: &DepNode) { + // For reused dep nodes, we only need to store the mapping if the node + // is one whose query key we can reconstruct from the hash. We use the + // mapping to aid that reconstruction in the next session. While we also + // use it to decode `DefId`s we encoded in the cache as `DefPathHashes`, + // they're already registered during `DefId` encoding. + if dep_node.kind.can_reconstruct_query_key() { + let hash = DefPathHash(dep_node.hash.into()); + + // We can't simply copy the `RawDefId` from `foreign_def_path_hashes` to + // `latest_foreign_def_path_hashes`, since the `RawDefId` might have + // changed in the current compilation session (e.g. we've added/removed crates, + // or added/removed definitions before/after the target definition). + if let Some(def_id) = self.def_path_hash_to_def_id(tcx, hash) { + if !def_id.is_local() { + self.store_foreign_def_id_hash(def_id, hash); + } + } + } + } + + fn store_foreign_def_id_hash(&self, def_id: DefId, hash: DefPathHash) { + // We may overwrite an existing entry, but it will have the same value, + // so it's fine + self.latest_foreign_def_path_hashes + .lock() + .insert(hash, RawDefId { krate: def_id.krate.as_u32(), index: def_id.index.as_u32() }); + } +} + +impl<'sess> OnDiskCache<'sess> { + pub fn as_dyn(&self) -> &dyn rustc_middle::ty::OnDiskCache<'sess> { + self as _ + } + /// Loads a diagnostic emitted during the previous compilation session. pub fn load_diagnostics( &self, @@ -439,44 +526,6 @@ impl<'sess> OnDiskCache<'sess> { cnum_map.get(&stable_crate_id).copied() } - pub(crate) fn store_foreign_def_id_hash(&self, def_id: DefId, hash: DefPathHash) { - // We may overwrite an existing entry, but it will have the same value, - // so it's fine - self.latest_foreign_def_path_hashes - .lock() - .insert(hash, RawDefId { krate: def_id.krate.as_u32(), index: def_id.index.as_u32() }); - } - - /// If the given `dep_node`'s hash still exists in the current compilation, - /// and its current `DefId` is foreign, calls `store_foreign_def_id` with it. - /// - /// Normally, `store_foreign_def_id_hash` can be called directly by - /// the dependency graph when we construct a `DepNode`. However, - /// when we re-use a deserialized `DepNode` from the previous compilation - /// session, we only have the `DefPathHash` available. This method is used - /// to that any `DepNode` that we re-use has a `DefPathHash` -> `RawId` written - /// out for usage in the next compilation session. - pub fn register_reused_dep_node(&self, tcx: TyCtxt<'tcx>, dep_node: &DepNode) { - // For reused dep nodes, we only need to store the mapping if the node - // is one whose query key we can reconstruct from the hash. We use the - // mapping to aid that reconstruction in the next session. While we also - // use it to decode `DefId`s we encoded in the cache as `DefPathHashes`, - // they're already registered during `DefId` encoding. - if dep_node.kind.can_reconstruct_query_key() { - let hash = DefPathHash(dep_node.hash.into()); - - // We can't simply copy the `RawDefId` from `foreign_def_path_hashes` to - // `latest_foreign_def_path_hashes`, since the `RawDefId` might have - // changed in the current compilation session (e.g. we've added/removed crates, - // or added/removed definitions before/after the target definition). - if let Some(def_id) = self.def_path_hash_to_def_id(tcx, hash) { - if !def_id.is_local() { - self.store_foreign_def_id_hash(def_id, hash); - } - } - } - } - /// Returns the cached query result if there is something in the cache for /// the given `SerializedDepNodeIndex`; otherwise returns `None`. pub fn try_load_query_result<'tcx, T>( @@ -547,6 +596,7 @@ impl<'sess> OnDiskCache<'sess> { alloc_decoding_session: self.alloc_decoding_state.new_decoding_session(), syntax_contexts: &self.syntax_contexts, expn_data: &self.expn_data, + foreign_expn_data: &self.foreign_expn_data, hygiene_context: &self.hygiene_context, }; f(&mut decoder) @@ -568,63 +618,6 @@ impl<'sess> OnDiskCache<'sess> { .collect() }) } - - /// Converts a `DefPathHash` to its corresponding `DefId` in the current compilation - /// session, if it still exists. This is used during incremental compilation to - /// turn a deserialized `DefPathHash` into its current `DefId`. - pub(crate) fn def_path_hash_to_def_id( - &self, - tcx: TyCtxt<'tcx>, - hash: DefPathHash, - ) -> Option { - let mut cache = self.def_path_hash_to_def_id_cache.lock(); - match cache.entry(hash) { - Entry::Occupied(e) => *e.get(), - Entry::Vacant(e) => { - debug!("def_path_hash_to_def_id({:?})", hash); - // Check if the `DefPathHash` corresponds to a definition in the current - // crate - if let Some(def_id) = - tcx.untracked_resolutions.definitions.local_def_path_hash_to_def_id(hash) - { - let def_id = def_id.to_def_id(); - e.insert(Some(def_id)); - return Some(def_id); - } - // This `raw_def_id` represents the `DefId` of this `DefPathHash` in - // the *previous* compliation session. The `DefPathHash` includes the - // owning crate, so if the corresponding definition still exists in the - // current compilation session, the crate is guaranteed to be the same - // (otherwise, we would compute a different `DefPathHash`). - let raw_def_id = self.get_raw_def_id(&hash)?; - debug!("def_path_hash_to_def_id({:?}): raw_def_id = {:?}", hash, raw_def_id); - // If the owning crate no longer exists, the corresponding definition definitely - // no longer exists. - let krate = self.try_remap_cnum(tcx, hash.stable_crate_id())?; - debug!("def_path_hash_to_def_id({:?}): krate = {:?}", hash, krate); - // If our `DefPathHash` corresponded to a definition in the local crate, - // we should have either found it in `local_def_path_hash_to_def_id`, or - // never attempted to load it in the first place. Any query result or `DepNode` - // that references a local `DefId` should depend on some HIR-related `DepNode`. - // If a local definition is removed/modified such that its old `DefPathHash` - // no longer has a corresponding definition, that HIR-related `DepNode` should - // end up red. This should prevent us from ever calling - // `tcx.def_path_hash_to_def_id`, since we'll end up recomputing any - // queries involved. - debug_assert_ne!(krate, LOCAL_CRATE); - // Try to find a definition in the current session, using the previous `DefIndex` - // as an initial guess. - let opt_def_id = tcx.untracked_resolutions.cstore.def_path_hash_to_def_id( - krate, - raw_def_id.index, - hash, - ); - debug!("def_path_to_def_id({:?}): opt_def_id = {:?}", hash, opt_def_id); - e.insert(opt_def_id); - opt_def_id - } - } - } } //- DECODING ------------------------------------------------------------------- @@ -641,7 +634,8 @@ pub struct CacheDecoder<'a, 'tcx> { file_index_to_stable_id: &'a FxHashMap, alloc_decoding_session: AllocDecodingSession<'a>, syntax_contexts: &'a FxHashMap, - expn_data: &'a FxHashMap, + expn_data: &'a UnhashMap, + foreign_expn_data: &'a UnhashMap, hygiene_context: &'a HygieneDecodeContext, } @@ -764,7 +758,7 @@ impl<'a, 'tcx> TyDecoder<'tcx> for CacheDecoder<'a, 'tcx> { } } -crate::implement_ty_decoder!(CacheDecoder<'a, 'tcx>); +rustc_middle::implement_ty_decoder!(CacheDecoder<'a, 'tcx>); // This ensures that the `Decodable::decode` specialization for `Vec` is used // when a `CacheDecoder` is passed to `Decodable::decode`. Unfortunately, we have to manually opt @@ -792,23 +786,43 @@ impl<'a, 'tcx> Decodable> for SyntaxContext { impl<'a, 'tcx> Decodable> for ExpnId { fn decode(decoder: &mut CacheDecoder<'a, 'tcx>) -> Result { - let expn_data = decoder.expn_data; - rustc_span::hygiene::decode_expn_id( - decoder, - ExpnDataDecodeMode::incr_comp(decoder.hygiene_context), - |this, index| { - // This closure is invoked if we haven't already decoded the data for the `ExpnId` we are deserializing. - // We look up the position of the associated `ExpnData` and decode it. - let pos = expn_data - .get(&index) - .unwrap_or_else(|| panic!("Bad index {:?} (map {:?})", index, expn_data)); - - this.with_position(pos.to_usize(), |decoder| { - let data: (ExpnData, ExpnHash) = decode_tagged(decoder, TAG_EXPN_DATA)?; - Ok(data) - }) - }, - ) + let hash = ExpnHash::decode(decoder)?; + if hash.is_root() { + return Ok(ExpnId::root()); + } + + if let Some(expn_id) = ExpnId::from_hash(hash) { + return Ok(expn_id); + } + + let krate = decoder.cnum_map[&hash.stable_crate_id()]; + + let expn_id = if krate == LOCAL_CRATE { + // We look up the position of the associated `ExpnData` and decode it. + let pos = decoder + .expn_data + .get(&hash) + .unwrap_or_else(|| panic!("Bad hash {:?} (map {:?})", hash, decoder.expn_data)); + + let data: ExpnData = decoder + .with_position(pos.to_usize(), |decoder| decode_tagged(decoder, TAG_EXPN_DATA))?; + rustc_span::hygiene::register_local_expn_id(data, hash) + } else { + let index_guess = decoder.foreign_expn_data[&hash]; + decoder.tcx.cstore_untracked().expn_hash_to_expn_id(krate, index_guess, hash) + }; + + #[cfg(debug_assertions)] + { + use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; + let mut hcx = decoder.tcx.create_stable_hashing_context(); + let mut hasher = StableHasher::new(); + hcx.while_hashing_spans(true, |hcx| expn_id.expn_data().hash_stable(hcx, &mut hasher)); + let local_hash: u64 = hasher.finish(); + debug_assert_eq!(hash.local_hash(), local_hash); + } + + Ok(expn_id) } } @@ -983,12 +997,8 @@ where E: 'a + OpaqueEncoder, { fn encode(&self, s: &mut CacheEncoder<'a, 'tcx, E>) -> Result<(), E::Error> { - rustc_span::hygiene::raw_encode_expn_id( - *self, - s.hygiene_context, - ExpnDataEncodeMode::IncrComp, - s, - ) + s.hygiene_context.schedule_expn_data_for_encoding(*self); + self.expn_hash().encode(s) } } diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs index 5907a587e1690..58c1b57dbb949 100644 --- a/compiler/rustc_query_impl/src/plumbing.rs +++ b/compiler/rustc_query_impl/src/plumbing.rs @@ -2,9 +2,8 @@ //! generate the actual methods on tcx which find and execute the provider, //! manage the caches, and so forth. -use super::queries; +use crate::{on_disk_cache, queries, Queries}; use rustc_middle::dep_graph::{DepKind, DepNode, DepNodeIndex, SerializedDepNodeIndex}; -use rustc_middle::ty::query::on_disk_cache; use rustc_middle::ty::tls::{self, ImplicitCtxt}; use rustc_middle::ty::{self, TyCtxt}; use rustc_query_system::dep_graph::HasDepContext; @@ -12,14 +11,16 @@ use rustc_query_system::query::{QueryContext, QueryDescription, QueryJobId, Quer use rustc_data_structures::sync::Lock; use rustc_data_structures::thin_vec::ThinVec; -use rustc_errors::Diagnostic; +use rustc_errors::{Diagnostic, Handler}; use rustc_serialize::opaque; use rustc_span::def_id::LocalDefId; +use std::any::Any; + #[derive(Copy, Clone)] pub struct QueryCtxt<'tcx> { pub tcx: TyCtxt<'tcx>, - pub queries: &'tcx super::Queries<'tcx>, + pub queries: &'tcx Queries<'tcx>, } impl<'tcx> std::ops::Deref for QueryCtxt<'tcx> { @@ -83,14 +84,15 @@ impl QueryContext for QueryCtxt<'tcx> { // Interactions with on_disk_cache fn load_diagnostics(&self, prev_dep_node_index: SerializedDepNodeIndex) -> Vec { - self.on_disk_cache + self.queries + .on_disk_cache .as_ref() .map(|c| c.load_diagnostics(**self, prev_dep_node_index)) .unwrap_or_default() } fn store_diagnostics(&self, dep_node_index: DepNodeIndex, diagnostics: ThinVec) { - if let Some(c) = self.on_disk_cache.as_ref() { + if let Some(c) = self.queries.on_disk_cache.as_ref() { c.store_diagnostics(dep_node_index, diagnostics) } } @@ -100,7 +102,7 @@ impl QueryContext for QueryCtxt<'tcx> { dep_node_index: DepNodeIndex, diagnostics: ThinVec, ) { - if let Some(c) = self.on_disk_cache.as_ref() { + if let Some(c) = self.queries.on_disk_cache.as_ref() { c.store_diagnostics_for_anon_node(dep_node_index, diagnostics) } } @@ -137,6 +139,27 @@ impl QueryContext for QueryCtxt<'tcx> { } impl<'tcx> QueryCtxt<'tcx> { + #[inline] + pub fn from_tcx(tcx: TyCtxt<'tcx>) -> Self { + let queries = tcx.queries.as_any(); + let queries = unsafe { + let queries = std::mem::transmute::<&dyn Any, &dyn Any>(queries); + let queries = queries.downcast_ref().unwrap(); + let queries = std::mem::transmute::<&Queries<'_>, &Queries<'_>>(queries); + queries + }; + QueryCtxt { tcx, queries } + } + + crate fn on_disk_cache(self) -> Option<&'tcx on_disk_cache::OnDiskCache<'tcx>> { + self.queries.on_disk_cache.as_ref() + } + + #[cfg(parallel_compiler)] + pub unsafe fn deadlock(self, registry: &rustc_rayon_core::Registry) { + rustc_query_system::query::deadlock(self, registry) + } + pub(super) fn encode_query_results( self, encoder: &mut on_disk_cache::CacheEncoder<'a, 'tcx, opaque::FileEncoder>, @@ -158,6 +181,15 @@ impl<'tcx> QueryCtxt<'tcx> { Ok(()) } + + pub fn try_print_query_stack( + self, + query: Option>, + handler: &Handler, + num_frames: Option, + ) -> usize { + rustc_query_system::query::print_query_stack(self, query, handler, num_frames) + } } /// This struct stores metadata about each Query. @@ -462,6 +494,8 @@ macro_rules! define_queries_struct { local_providers: Box, extern_providers: Box, + pub on_disk_cache: Option>, + $($(#[$attr])* $name: QueryState< crate::dep_graph::DepKind, query_keys::$name<$tcx>, @@ -472,10 +506,12 @@ macro_rules! define_queries_struct { pub fn new( local_providers: Providers, extern_providers: Providers, + on_disk_cache: Option>, ) -> Self { Queries { local_providers: Box::new(local_providers), extern_providers: Box::new(extern_providers), + on_disk_cache, $($name: Default::default()),* } } @@ -501,25 +537,9 @@ macro_rules! define_queries_struct { } impl QueryEngine<'tcx> for Queries<'tcx> { - #[cfg(parallel_compiler)] - unsafe fn deadlock(&'tcx self, tcx: TyCtxt<'tcx>, registry: &rustc_rayon_core::Registry) { - let tcx = QueryCtxt { tcx, queries: self }; - rustc_query_system::query::deadlock(tcx, registry) - } - - fn encode_query_results( - &'tcx self, - tcx: TyCtxt<'tcx>, - encoder: &mut on_disk_cache::CacheEncoder<'a, 'tcx, opaque::FileEncoder>, - query_result_index: &mut on_disk_cache::EncodedQueryResultIndex, - ) -> opaque::FileEncodeResult { - let tcx = QueryCtxt { tcx, queries: self }; - tcx.encode_query_results(encoder, query_result_index) - } - - fn exec_cache_promotions(&'tcx self, tcx: TyCtxt<'tcx>) { - let tcx = QueryCtxt { tcx, queries: self }; - tcx.dep_graph.exec_cache_promotions(tcx) + fn as_any(&'tcx self) -> &'tcx dyn std::any::Any { + let this = unsafe { std::mem::transmute::<&Queries<'_>, &Queries<'_>>(self) }; + this as _ } fn try_mark_green(&'tcx self, tcx: TyCtxt<'tcx>, dep_node: &dep_graph::DepNode) -> bool { @@ -527,17 +547,6 @@ macro_rules! define_queries_struct { tcx.dep_graph.try_mark_green(qcx, dep_node).is_some() } - fn try_print_query_stack( - &'tcx self, - tcx: TyCtxt<'tcx>, - query: Option>, - handler: &Handler, - num_frames: Option, - ) -> usize { - let qcx = QueryCtxt { tcx, queries: self }; - rustc_query_system::query::print_query_stack(qcx, query, handler, num_frames) - } - $($(#[$attr])* #[inline(always)] fn $name( diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 35e7688fbe45a..178d727418d74 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -31,7 +31,7 @@ use rustc_middle::bug; use rustc_middle::hir::exports::Export; use rustc_middle::middle::cstore::CrateStore; use rustc_middle::ty; -use rustc_span::hygiene::{ExpnId, MacroKind}; +use rustc_span::hygiene::{ExpnId, LocalExpnId, MacroKind}; use rustc_span::source_map::{respan, Spanned}; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::Span; @@ -42,7 +42,7 @@ use tracing::debug; type Res = def::Res; -impl<'a> ToNameBinding<'a> for (Module<'a>, ty::Visibility, Span, ExpnId) { +impl<'a> ToNameBinding<'a> for (Module<'a>, ty::Visibility, Span, LocalExpnId) { fn to_name_binding(self, arenas: &'a ResolverArenas<'a>) -> &'a NameBinding<'a> { arenas.alloc_name_binding(NameBinding { kind: NameBindingKind::Module(self.0), @@ -54,7 +54,7 @@ impl<'a> ToNameBinding<'a> for (Module<'a>, ty::Visibility, Span, ExpnId) { } } -impl<'a> ToNameBinding<'a> for (Res, ty::Visibility, Span, ExpnId) { +impl<'a> ToNameBinding<'a> for (Res, ty::Visibility, Span, LocalExpnId) { fn to_name_binding(self, arenas: &'a ResolverArenas<'a>) -> &'a NameBinding<'a> { arenas.alloc_name_binding(NameBinding { kind: NameBindingKind::Res(self.0, false), @@ -68,7 +68,7 @@ impl<'a> ToNameBinding<'a> for (Res, ty::Visibility, Span, ExpnId) { struct IsMacroExport; -impl<'a> ToNameBinding<'a> for (Res, ty::Visibility, Span, ExpnId, IsMacroExport) { +impl<'a> ToNameBinding<'a> for (Res, ty::Visibility, Span, LocalExpnId, IsMacroExport) { fn to_name_binding(self, arenas: &'a ResolverArenas<'a>) -> &'a NameBinding<'a> { arenas.alloc_name_binding(NameBinding { kind: NameBindingKind::Res(self.0, true), @@ -157,7 +157,12 @@ impl<'a> Resolver<'a> { crate fn macro_def_scope(&mut self, expn_id: ExpnId) -> Module<'a> { let def_id = match expn_id.expn_data().macro_def_id { Some(def_id) => def_id, - None => return self.ast_transform_scopes.get(&expn_id).unwrap_or(&self.graph_root), + None => { + return expn_id + .as_local() + .and_then(|expn_id| self.ast_transform_scopes.get(&expn_id)) + .unwrap_or(&self.graph_root); + } }; self.macro_def_scope_from_def_id(def_id) } @@ -739,7 +744,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { if ptr::eq(parent, self.r.graph_root) { if let Some(entry) = self.r.extern_prelude.get(&ident.normalize_to_macros_2_0()) { - if expansion != ExpnId::root() + if expansion != LocalExpnId::ROOT && orig_name.is_some() && entry.extern_crate_item.is_none() { @@ -769,7 +774,13 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { no_implicit_prelude: parent.no_implicit_prelude || { self.r.session.contains_name(&item.attrs, sym::no_implicit_prelude) }, - ..ModuleData::new(Some(parent), module_kind, def_id, expansion, item.span) + ..ModuleData::new( + Some(parent), + module_kind, + def_id, + expansion.to_expn_id(), + item.span, + ) }); self.r.define(parent, ident, TypeNS, (module, vis, sp, expansion)); self.r.module_map.insert(local_def_id, module); @@ -808,7 +819,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { parent, module_kind, parent.nearest_parent_mod, - expansion, + expansion.to_expn_id(), item.span, ); self.r.define(parent, ident, TypeNS, (module, vis, sp, expansion)); @@ -883,7 +894,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { parent, module_kind, parent.nearest_parent_mod, - expansion, + expansion.to_expn_id(), item.span, ); self.r.define(parent, ident, TypeNS, (module, vis, sp, expansion)); @@ -926,7 +937,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { parent, ModuleKind::Block(block.id), parent.nearest_parent_mod, - expansion, + expansion.to_expn_id(), block.span, ); self.r.block_map.insert(block.id, module); @@ -946,7 +957,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { parent, ModuleKind::Def(kind, def_id, ident.name), def_id, - expansion, + expansion.to_expn_id(), span, ); self.r.define(parent, ident, TypeNS, (module, vis, span, expansion)); @@ -1112,7 +1123,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { }) }; - let allow_shadowing = self.parent_scope.expansion == ExpnId::root(); + let allow_shadowing = self.parent_scope.expansion == LocalExpnId::ROOT; if let Some(span) = import_all { let import = macro_use_import(self, span); self.r.potentially_unused_imports.push(import); @@ -1175,7 +1186,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { false } - fn visit_invoc(&mut self, id: NodeId) -> ExpnId { + fn visit_invoc(&mut self, id: NodeId) -> LocalExpnId { let invoc_id = id.placeholder_to_expn_id(); let old_parent_scope = self.r.invocation_parent_scopes.insert(invoc_id, self.parent_scope); assert!(old_parent_scope.is_none(), "invocation data is reset for an invocation"); diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index 17f0c39e39735..6f4f1bdaea1b7 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -6,7 +6,7 @@ use rustc_ast_lowering::ResolverAstLowering; use rustc_expand::expand::AstFragment; use rustc_hir::def_id::LocalDefId; use rustc_hir::definitions::*; -use rustc_span::hygiene::ExpnId; +use rustc_span::hygiene::LocalExpnId; use rustc_span::symbol::{kw, sym}; use rustc_span::Span; use tracing::debug; @@ -14,7 +14,7 @@ use tracing::debug; crate fn collect_definitions( resolver: &mut Resolver<'_>, fragment: &AstFragment, - expansion: ExpnId, + expansion: LocalExpnId, ) { let (parent_def, impl_trait_context) = resolver.invocation_parents[&expansion]; fragment.visit_with(&mut DefCollector { resolver, parent_def, expansion, impl_trait_context }); @@ -25,14 +25,14 @@ struct DefCollector<'a, 'b> { resolver: &'a mut Resolver<'b>, parent_def: LocalDefId, impl_trait_context: ImplTraitContext, - expansion: ExpnId, + expansion: LocalExpnId, } impl<'a, 'b> DefCollector<'a, 'b> { fn create_def(&mut self, node_id: NodeId, data: DefPathData, span: Span) -> LocalDefId { let parent_def = self.parent_def; debug!("create_def(node_id={:?}, data={:?}, parent_def={:?})", node_id, data, parent_def); - self.resolver.create_def(parent_def, node_id, data, self.expansion, span) + self.resolver.create_def(parent_def, node_id, data, self.expansion.to_expn_id(), span) } fn with_parent(&mut self, parent_def: LocalDefId, f: F) { @@ -285,7 +285,7 @@ impl<'a, 'b> visit::Visitor<'a> for DefCollector<'a, 'b> { item_def, node_id, DefPathData::ImplTrait, - self.expansion, + self.expansion.to_expn_id(), ty.span, ), ImplTraitContext::Existential => { diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 26858915f45a0..acfa389fed58a 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -22,7 +22,7 @@ use rustc_middle::span_bug; use rustc_middle::ty; use rustc_session::lint::builtin::{PUB_USE_OF_PRIVATE_EXTERN_CRATE, UNUSED_IMPORTS}; use rustc_session::lint::BuiltinLintDiagnostics; -use rustc_span::hygiene::ExpnId; +use rustc_span::hygiene::LocalExpnId; use rustc_span::lev_distance::find_best_match_for_name; use rustc_span::symbol::{kw, Ident, Symbol}; use rustc_span::{MultiSpan, Span}; @@ -237,8 +237,9 @@ impl<'a> Resolver<'a> { if ns == TypeNS { if ident.name == kw::Crate || ident.name == kw::DollarCrate { let module = self.resolve_crate_root(ident); - let binding = (module, ty::Visibility::Public, module.span, ExpnId::root()) - .to_name_binding(self.arenas); + let binding = + (module, ty::Visibility::Public, module.span, LocalExpnId::ROOT) + .to_name_binding(self.arenas); return Ok(binding); } else if ident.name == kw::Super || ident.name == kw::SelfLower { // FIXME: Implement these with renaming requirements so that e.g. @@ -265,7 +266,7 @@ impl<'a> Resolver<'a> { self.resolution(module, key).try_borrow_mut().map_err(|_| (Determined, Weak::No))?; // This happens when there is a cycle of imports. if let Some(binding) = resolution.binding { - if !restricted_shadowing && binding.expansion != ExpnId::root() { + if !restricted_shadowing && binding.expansion != LocalExpnId::ROOT { if let NameBindingKind::Res(_, true) = binding.kind { self.macro_expanded_macro_export_errors.insert((path_span, binding.span)); } @@ -307,7 +308,7 @@ impl<'a> Resolver<'a> { if let Some(shadowed_glob) = resolution.shadowed_glob { // Forbid expanded shadowing to avoid time travel. if restricted_shadowing - && binding.expansion != ExpnId::root() + && binding.expansion != LocalExpnId::ROOT && binding.res() != shadowed_glob.res() { self.ambiguity_errors.push(AmbiguityError { @@ -521,7 +522,7 @@ impl<'a> Resolver<'a> { if old_glob { (old_binding, binding) } else { (binding, old_binding) }; if glob_binding.res() != nonglob_binding.res() && key.ns == MacroNS - && nonglob_binding.expansion != ExpnId::root() + && nonglob_binding.expansion != LocalExpnId::ROOT { resolution.binding = Some(this.ambiguity( AmbiguityKind::GlobVsExpanded, @@ -1271,7 +1272,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { target: Ident, ) { // Skip if the import was produced by a macro. - if import.parent_scope.expansion != ExpnId::root() { + if import.parent_scope.expansion != LocalExpnId::ROOT { return; } diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index fb2eb749e118f..7114fd33188d9 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -53,7 +53,7 @@ use rustc_session::lint; use rustc_session::lint::{BuiltinLintDiagnostics, LintBuffer}; use rustc_session::Session; use rustc_span::edition::Edition; -use rustc_span::hygiene::{ExpnId, ExpnKind, MacroKind, SyntaxContext, Transparency}; +use rustc_span::hygiene::{ExpnId, ExpnKind, LocalExpnId, MacroKind, SyntaxContext, Transparency}; use rustc_span::source_map::{CachingSourceMapView, Spanned}; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{Span, DUMMY_SP}; @@ -103,7 +103,7 @@ impl Determinacy { /// but not for late resolution yet. #[derive(Clone, Copy)] enum Scope<'a> { - DeriveHelpers(ExpnId), + DeriveHelpers(LocalExpnId), DeriveHelpersCompat, MacroRules(MacroRulesScopeRef<'a>), CrateRoot, @@ -143,7 +143,7 @@ enum ScopeSet<'a> { #[derive(Clone, Copy, Debug)] pub struct ParentScope<'a> { module: Module<'a>, - expansion: ExpnId, + expansion: LocalExpnId, macro_rules: MacroRulesScopeRef<'a>, derives: &'a [ast::Path], } @@ -154,7 +154,7 @@ impl<'a> ParentScope<'a> { pub fn module(module: Module<'a>, resolver: &Resolver<'a>) -> ParentScope<'a> { ParentScope { module, - expansion: ExpnId::root(), + expansion: LocalExpnId::ROOT, macro_rules: resolver.arenas.alloc_macro_rules_scope(MacroRulesScope::Empty), derives: &[], } @@ -515,7 +515,7 @@ pub struct ModuleData<'a> { populate_on_access: Cell, /// Macro invocations that can expand into items in this module. - unexpanded_invocations: RefCell>, + unexpanded_invocations: RefCell>, /// Whether `#[no_implicit_prelude]` is active. no_implicit_prelude: bool, @@ -645,7 +645,7 @@ impl<'a> fmt::Debug for ModuleData<'a> { pub struct NameBinding<'a> { kind: NameBindingKind<'a>, ambiguity: Option<(&'a NameBinding<'a>, AmbiguityKind)>, - expansion: ExpnId, + expansion: LocalExpnId, span: Span, vis: ty::Visibility, } @@ -829,7 +829,11 @@ impl<'a> NameBinding<'a> { // in some later round and screw up our previously found resolution. // See more detailed explanation in // https://github.com/rust-lang/rust/pull/53778#issuecomment-419224049 - fn may_appear_after(&self, invoc_parent_expansion: ExpnId, binding: &NameBinding<'_>) -> bool { + fn may_appear_after( + &self, + invoc_parent_expansion: LocalExpnId, + binding: &NameBinding<'_>, + ) -> bool { // self > max(invoc, binding) => !(self <= invoc || self <= binding) // Expansions are partially ordered, so "may appear after" is an inversion of // "certainly appears before or simultaneously" and includes unordered cases. @@ -966,7 +970,7 @@ pub struct Resolver<'a> { dummy_ext_derive: Lrc, non_macro_attrs: [Lrc; 2], local_macro_def_scopes: FxHashMap>, - ast_transform_scopes: FxHashMap>, + ast_transform_scopes: FxHashMap>, unused_macros: FxHashMap, proc_macro_stubs: FxHashSet, /// Traces collected during macro resolution and validated when it's complete. @@ -978,18 +982,18 @@ pub struct Resolver<'a> { /// `derive(Copy)` marks items they are applied to so they are treated specially later. /// Derive macros cannot modify the item themselves and have to store the markers in the global /// context, so they attach the markers to derive container IDs using this resolver table. - containers_deriving_copy: FxHashSet, + containers_deriving_copy: FxHashSet, /// Parent scopes in which the macros were invoked. /// FIXME: `derives` are missing in these parent scopes and need to be taken from elsewhere. - invocation_parent_scopes: FxHashMap>, + invocation_parent_scopes: FxHashMap>, /// `macro_rules` scopes *produced* by expanding the macro invocations, /// include all the `macro_rules` items and other invocations generated by them. - output_macro_rules_scopes: FxHashMap>, + output_macro_rules_scopes: FxHashMap>, /// Helper attributes that are in scope for the given expansion. - helper_attrs: FxHashMap>, + helper_attrs: FxHashMap>, /// Ready or in-progress results of resolving paths inside the `#[derive(...)]` attribute /// with the given `ExpnId`. - derive_data: FxHashMap, + derive_data: FxHashMap, /// Avoid duplicated errors for "name already defined". name_already_seen: FxHashMap, @@ -1018,7 +1022,7 @@ pub struct Resolver<'a> { /// When collecting definitions from an AST fragment produced by a macro invocation `ExpnId` /// we know what parent node that fragment should be attached to thanks to this table, /// and how the `impl Trait` fragments were introduced. - invocation_parents: FxHashMap, + invocation_parents: FxHashMap, next_disambiguator: FxHashMap<(LocalDefId, DefPathData), u32>, /// Some way to know that we are in a *trait* impl in `visit_assoc_item`. @@ -1268,7 +1272,7 @@ impl<'a> Resolver<'a> { node_id_to_def_id.insert(CRATE_NODE_ID, root); let mut invocation_parents = FxHashMap::default(); - invocation_parents.insert(ExpnId::root(), (root, ImplTraitContext::Existential)); + invocation_parents.insert(LocalExpnId::ROOT, (root, ImplTraitContext::Existential)); let mut extern_prelude: FxHashMap> = session .opts @@ -1342,7 +1346,7 @@ impl<'a> Resolver<'a> { dummy_binding: arenas.alloc_name_binding(NameBinding { kind: NameBindingKind::Res(Res::Err, false), ambiguity: None, - expansion: ExpnId::root(), + expansion: LocalExpnId::ROOT, span: DUMMY_SP, vis: ty::Visibility::Public, }), @@ -1392,7 +1396,7 @@ impl<'a> Resolver<'a> { }; let root_parent_scope = ParentScope::module(graph_root, &resolver); - resolver.invocation_parent_scopes.insert(ExpnId::root(), root_parent_scope); + resolver.invocation_parent_scopes.insert(LocalExpnId::ROOT, root_parent_scope); resolver } @@ -1810,7 +1814,8 @@ impl<'a> Resolver<'a> { } scope = match scope { - Scope::DeriveHelpers(expn_id) if expn_id != ExpnId::root() => { + Scope::DeriveHelpers(LocalExpnId::ROOT) => Scope::DeriveHelpersCompat, + Scope::DeriveHelpers(expn_id) => { // Derive helpers are not visible to code generated by bang or derive macros. let expn_data = expn_id.expn_data(); match expn_data.kind { @@ -1818,10 +1823,9 @@ impl<'a> Resolver<'a> { | ExpnKind::Macro(MacroKind::Bang | MacroKind::Derive, _) => { Scope::DeriveHelpersCompat } - _ => Scope::DeriveHelpers(expn_data.parent), + _ => Scope::DeriveHelpers(expn_data.parent.expect_local()), } } - Scope::DeriveHelpers(..) => Scope::DeriveHelpersCompat, Scope::DeriveHelpersCompat => Scope::MacroRules(parent_scope.macro_rules), Scope::MacroRules(macro_rules_scope) => match macro_rules_scope.get() { MacroRulesScope::Binding(binding) => { @@ -3248,7 +3252,7 @@ impl<'a> Resolver<'a> { }; let crate_root = self.get_module(DefId { krate: crate_id, index: CRATE_DEF_INDEX }); Some( - (crate_root, ty::Visibility::Public, DUMMY_SP, ExpnId::root()) + (crate_root, ty::Visibility::Public, DUMMY_SP, LocalExpnId::ROOT) .to_name_binding(self.arenas), ) } diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index 8686704388fee..b2a8aa0ceccaa 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -30,7 +30,7 @@ use rustc_session::lint::BuiltinLintDiagnostics; use rustc_session::parse::feature_err; use rustc_session::Session; use rustc_span::edition::Edition; -use rustc_span::hygiene::{self, ExpnData, ExpnId, ExpnKind}; +use rustc_span::hygiene::{self, ExpnData, ExpnKind, LocalExpnId}; use rustc_span::hygiene::{AstPass, MacroKind}; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{Span, DUMMY_SP}; @@ -62,7 +62,7 @@ pub enum MacroRulesScope<'a> { Binding(&'a MacroRulesBinding<'a>), /// The scope introduced by a macro invocation that can potentially /// create a `macro_rules!` macro definition. - Invocation(ExpnId), + Invocation(LocalExpnId), } /// `macro_rules!` scopes are always kept by reference and inside a cell. @@ -190,7 +190,11 @@ impl<'a> ResolverExpand for Resolver<'a> { }); } - fn visit_ast_fragment_with_placeholders(&mut self, expansion: ExpnId, fragment: &AstFragment) { + fn visit_ast_fragment_with_placeholders( + &mut self, + expansion: LocalExpnId, + fragment: &AstFragment, + ) { // Integrate the new AST fragment into all the definition and module structures. // We are inside the `expansion` now, but other parent scope components are still the same. let parent_scope = ParentScope { expansion, ..self.invocation_parent_scopes[&expansion] }; @@ -216,9 +220,9 @@ impl<'a> ResolverExpand for Resolver<'a> { pass: AstPass, features: &[Symbol], parent_module_id: Option, - ) -> ExpnId { + ) -> LocalExpnId { let parent_module = parent_module_id.map(|module_id| self.local_def_id(module_id)); - let expn_id = ExpnId::fresh( + let expn_id = LocalExpnId::fresh( ExpnData::allow_unstable( ExpnKind::AstPass(pass), call_site, @@ -244,7 +248,7 @@ impl<'a> ResolverExpand for Resolver<'a> { fn resolve_macro_invocation( &mut self, invoc: &Invocation, - eager_expansion_root: ExpnId, + eager_expansion_root: LocalExpnId, force: bool, ) -> Result, Indeterminate> { let invoc_id = invoc.expansion_data.id; @@ -277,7 +281,7 @@ impl<'a> ResolverExpand for Resolver<'a> { // Derives are not included when `invocations` are collected, so we have to add them here. let parent_scope = &ParentScope { derives, ..parent_scope }; let supports_macro_expansion = invoc.fragment_kind.supports_macro_expansion(); - let node_id = self.lint_node_id(eager_expansion_root); + let node_id = invoc.expansion_data.lint_node_id; let (ext, res) = self.smart_resolve_macro_path( path, kind, @@ -328,7 +332,7 @@ impl<'a> ResolverExpand for Resolver<'a> { | ExpnKind::Macro(MacroKind::Bang | MacroKind::Derive, _) => { break; } - _ => expn_id = expn_data.parent, + _ => expn_id = expn_data.parent.expect_local(), } } } @@ -344,21 +348,13 @@ impl<'a> ResolverExpand for Resolver<'a> { } } - fn lint_node_id(&self, expn_id: ExpnId) -> NodeId { - // FIXME - make this more precise. This currently returns the NodeId of the - // nearest closing item - we should try to return the closest parent of the ExpnId - self.invocation_parents - .get(&expn_id) - .map_or(ast::CRATE_NODE_ID, |id| self.def_id_to_node_id[id.0]) - } - - fn has_derive_copy(&self, expn_id: ExpnId) -> bool { + fn has_derive_copy(&self, expn_id: LocalExpnId) -> bool { self.containers_deriving_copy.contains(&expn_id) } fn resolve_derives( &mut self, - expn_id: ExpnId, + expn_id: LocalExpnId, force: bool, derive_paths: &dyn Fn() -> DeriveResolutions, ) -> Result<(), Indeterminate> { @@ -423,7 +419,7 @@ impl<'a> ResolverExpand for Resolver<'a> { Ok(()) } - fn take_derive_resolutions(&mut self, expn_id: ExpnId) -> Option { + fn take_derive_resolutions(&mut self, expn_id: LocalExpnId) -> Option { self.derive_data.remove(&expn_id).map(|data| data.resolutions) } @@ -431,7 +427,11 @@ impl<'a> ResolverExpand for Resolver<'a> { // Returns true if the path can certainly be resolved in one of three namespaces, // returns false if the path certainly cannot be resolved in any of the three namespaces. // Returns `Indeterminate` if we cannot give a certain answer yet. - fn cfg_accessible(&mut self, expn_id: ExpnId, path: &ast::Path) -> Result { + fn cfg_accessible( + &mut self, + expn_id: LocalExpnId, + path: &ast::Path, + ) -> Result { let span = path.span; let path = &Segment::from_path(path); let parent_scope = self.invocation_parent_scopes[&expn_id]; @@ -714,7 +714,8 @@ impl<'a> Resolver<'a> { let ident = Ident::new(orig_ident.name, orig_ident.span.with_ctxt(ctxt)); let ok = |res, span, arenas| { Ok(( - (res, ty::Visibility::Public, span, ExpnId::root()).to_name_binding(arenas), + (res, ty::Visibility::Public, span, LocalExpnId::ROOT) + .to_name_binding(arenas), Flags::empty(), )) }; @@ -1096,9 +1097,13 @@ impl<'a> Resolver<'a> { let seg = Segment::from_ident(ident); check_consistency(self, &[seg], ident.span, kind, initial_res, res); if res == Res::NonMacroAttr(NonMacroAttrKind::DeriveHelperCompat) { + let node_id = self + .invocation_parents + .get(&parent_scope.expansion) + .map_or(ast::CRATE_NODE_ID, |id| self.def_id_to_node_id[id.0]); self.lint_buffer.buffer_lint_with_diagnostic( LEGACY_DERIVE_HELPERS, - self.lint_node_id(parent_scope.expansion), + node_id, ident.span, "derive helper attribute is used before it is introduced", BuiltinLintDiagnostics::LegacyDeriveHelpers(binding.span), diff --git a/compiler/rustc_span/src/def_id.rs b/compiler/rustc_span/src/def_id.rs index c5d605ab57801..64baf94cc0063 100644 --- a/compiler/rustc_span/src/def_id.rs +++ b/compiler/rustc_span/src/def_id.rs @@ -136,7 +136,7 @@ impl Borrow for DefPathHash { /// further trouble. #[derive(Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Debug)] #[derive(HashStable_Generic, Encodable, Decodable)] -pub struct StableCrateId(u64); +pub struct StableCrateId(pub(crate) u64); impl StableCrateId { pub fn to_u64(self) -> u64 { diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs index d292f652896f1..cb3a08439d129 100644 --- a/compiler/rustc_span/src/hygiene.rs +++ b/compiler/rustc_span/src/hygiene.rs @@ -29,12 +29,13 @@ use crate::symbol::{kw, sym, Symbol}; use crate::with_session_globals; use crate::{HashStableContext, Span, DUMMY_SP}; -use crate::def_id::{CrateNum, DefId, CRATE_DEF_INDEX, LOCAL_CRATE}; +use crate::def_id::{CrateNum, DefId, StableCrateId, CRATE_DEF_ID, LOCAL_CRATE}; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::sync::{Lock, Lrc}; use rustc_data_structures::unhash::UnhashMap; +use rustc_index::vec::IndexVec; use rustc_macros::HashStable_Generic; use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; use std::fmt; @@ -58,14 +59,67 @@ pub struct SyntaxContextData { dollar_crate_name: Symbol, } +rustc_index::newtype_index! { + /// A unique ID associated with a macro invocation and expansion. + pub struct ExpnIndex { + ENCODABLE = custom + } +} + /// A unique ID associated with a macro invocation and expansion. -#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] -pub struct ExpnId(u32); +#[derive(Clone, Copy, PartialEq, Eq, Hash)] +pub struct ExpnId { + pub krate: CrateNum, + pub local_id: ExpnIndex, +} + +impl fmt::Debug for ExpnId { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + // Generate crate_::{{expn_}}. + write!(f, "{:?}::{{{{expn{}}}}}", self.krate, self.local_id.private) + } +} + +rustc_index::newtype_index! { + /// A unique ID associated with a macro invocation and expansion. + pub struct LocalExpnId { + ENCODABLE = custom + DEBUG_FORMAT = "expn{}" + } +} /// A unique hash value associated to an expansion. #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Encodable, Decodable, HashStable_Generic)] pub struct ExpnHash(Fingerprint); +impl ExpnHash { + /// Returns the [StableCrateId] identifying the crate this [ExpnHash] + /// originates from. + #[inline] + pub fn stable_crate_id(self) -> StableCrateId { + StableCrateId(self.0.as_value().0) + } + + /// Returns the crate-local part of the [ExpnHash]. + /// + /// Used for tests. + #[inline] + pub fn local_hash(self) -> u64 { + self.0.as_value().1 + } + + #[inline] + pub fn is_root(self) -> bool { + self.0 == Fingerprint::ZERO + } + + /// Builds a new [ExpnHash] with the given [StableCrateId] and + /// `local_hash`, where `local_hash` must be unique within its crate. + fn new(stable_crate_id: StableCrateId, local_hash: u64) -> ExpnHash { + ExpnHash(Fingerprint::new(stable_crate_id.0, local_hash)) + } +} + /// A property of a macro expansion that determines how identifiers /// produced by that expansion are resolved. #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Hash, Debug, Encodable, Decodable)] @@ -86,31 +140,102 @@ pub enum Transparency { Opaque, } -impl ExpnId { - pub fn fresh_empty() -> Self { - HygieneData::with(|data| data.fresh_expn(None)) +impl LocalExpnId { + /// The ID of the theoretical expansion that generates freshly parsed, unexpanded AST. + pub const ROOT: LocalExpnId = LocalExpnId::from_u32(0); + + pub fn from_raw(idx: ExpnIndex) -> LocalExpnId { + LocalExpnId::from_u32(idx.as_u32()) } - pub fn fresh(expn_data: ExpnData, ctx: impl HashStableContext) -> Self { - let expn_id = HygieneData::with(|data| data.fresh_expn(Some(expn_data))); - update_disambiguator(expn_id, ctx); - expn_id + pub fn as_raw(self) -> ExpnIndex { + ExpnIndex::from_u32(self.as_u32()) + } + + pub fn fresh_empty() -> LocalExpnId { + HygieneData::with(|data| { + let expn_id = data.local_expn_data.push(None); + let _eid = data.local_expn_hashes.push(ExpnHash(Fingerprint::ZERO)); + debug_assert_eq!(expn_id, _eid); + expn_id + }) + } + + pub fn fresh(mut expn_data: ExpnData, ctx: impl HashStableContext) -> LocalExpnId { + debug_assert_eq!(expn_data.parent.krate, LOCAL_CRATE); + let expn_hash = update_disambiguator(&mut expn_data, ctx); + HygieneData::with(|data| { + let expn_id = data.local_expn_data.push(Some(expn_data)); + let _eid = data.local_expn_hashes.push(expn_hash); + debug_assert_eq!(expn_id, _eid); + let _old_id = data.expn_hash_to_expn_id.insert(expn_hash, expn_id.to_expn_id()); + debug_assert!(_old_id.is_none()); + expn_id + }) } - /// The ID of the theoretical expansion that generates freshly parsed, unexpanded AST. #[inline] - pub fn root() -> Self { - ExpnId(0) + pub fn expn_hash(self) -> ExpnHash { + HygieneData::with(|data| data.local_expn_hash(self)) } #[inline] - pub fn as_u32(self) -> u32 { - self.0 + pub fn expn_data(self) -> ExpnData { + HygieneData::with(|data| data.local_expn_data(self).clone()) + } + + #[inline] + pub fn to_expn_id(self) -> ExpnId { + ExpnId { krate: LOCAL_CRATE, local_id: self.as_raw() } + } + + #[inline] + pub fn set_expn_data(self, mut expn_data: ExpnData, ctx: impl HashStableContext) { + debug_assert_eq!(expn_data.parent.krate, LOCAL_CRATE); + let expn_hash = update_disambiguator(&mut expn_data, ctx); + HygieneData::with(|data| { + let old_expn_data = &mut data.local_expn_data[self]; + assert!(old_expn_data.is_none(), "expansion data is reset for an expansion ID"); + *old_expn_data = Some(expn_data); + debug_assert_eq!(data.local_expn_hashes[self].0, Fingerprint::ZERO); + data.local_expn_hashes[self] = expn_hash; + let _old_id = data.expn_hash_to_expn_id.insert(expn_hash, self.to_expn_id()); + debug_assert!(_old_id.is_none()); + }); } #[inline] - pub fn from_u32(raw: u32) -> ExpnId { - ExpnId(raw) + pub fn is_descendant_of(self, ancestor: LocalExpnId) -> bool { + self.to_expn_id().is_descendant_of(ancestor.to_expn_id()) + } + + /// `expn_id.outer_expn_is_descendant_of(ctxt)` is equivalent to but faster than + /// `expn_id.is_descendant_of(ctxt.outer_expn())`. + #[inline] + pub fn outer_expn_is_descendant_of(self, ctxt: SyntaxContext) -> bool { + self.to_expn_id().outer_expn_is_descendant_of(ctxt) + } + + /// Returns span for the macro which originally caused this expansion to happen. + /// + /// Stops backtracing at include! boundary. + #[inline] + pub fn expansion_cause(self) -> Option { + self.to_expn_id().expansion_cause() + } + + #[inline] + #[track_caller] + pub fn parent(self) -> LocalExpnId { + self.expn_data().parent.as_local().unwrap() + } +} + +impl ExpnId { + /// The ID of the theoretical expansion that generates freshly parsed, unexpanded AST. + /// Invariant: we do not create any ExpnId with local_id == 0 and krate != 0. + pub const fn root() -> ExpnId { + ExpnId { krate: LOCAL_CRATE, local_id: ExpnIndex::from_u32(0) } } #[inline] @@ -124,20 +249,19 @@ impl ExpnId { } #[inline] - pub fn expn_data(self) -> ExpnData { - HygieneData::with(|data| data.expn_data(self).clone()) + pub fn as_local(self) -> Option { + if self.krate == LOCAL_CRATE { Some(LocalExpnId::from_raw(self.local_id)) } else { None } } #[inline] - pub fn set_expn_data(self, mut expn_data: ExpnData, ctx: impl HashStableContext) { - HygieneData::with(|data| { - let old_expn_data = &mut data.expn_data[self.0 as usize]; - assert!(old_expn_data.is_none(), "expansion data is reset for an expansion ID"); - assert_eq!(expn_data.orig_id, None); - expn_data.orig_id = Some(self.as_u32()); - *old_expn_data = Some(expn_data); - }); - update_disambiguator(self, ctx) + #[track_caller] + pub fn expect_local(self) -> LocalExpnId { + self.as_local().unwrap() + } + + #[inline] + pub fn expn_data(self) -> ExpnData { + HygieneData::with(|data| data.expn_data(self).clone()) } pub fn is_descendant_of(self, ancestor: ExpnId) -> bool { @@ -175,34 +299,39 @@ pub struct HygieneData { /// Each expansion should have an associated expansion data, but sometimes there's a delay /// between creation of an expansion ID and obtaining its data (e.g. macros are collected /// first and then resolved later), so we use an `Option` here. - expn_data: Vec>, - expn_hashes: Vec, + local_expn_data: IndexVec>, + local_expn_hashes: IndexVec, + /// Data and hash information from external crates. We may eventually want to remove these + /// maps, and fetch the information directly from the other crate's metadata like DefIds do. + foreign_expn_data: FxHashMap, + foreign_expn_hashes: FxHashMap, expn_hash_to_expn_id: UnhashMap, syntax_context_data: Vec, syntax_context_map: FxHashMap<(SyntaxContext, ExpnId, Transparency), SyntaxContext>, - /// Maps the `Fingerprint` of an `ExpnData` to the next disambiguator value. + /// Maps the `local_hash` of an `ExpnData` to the next disambiguator value. /// This is used by `update_disambiguator` to keep track of which `ExpnData`s /// would have collisions without a disambiguator. /// The keys of this map are always computed with `ExpnData.disambiguator` /// set to 0. - expn_data_disambiguators: FxHashMap, + expn_data_disambiguators: FxHashMap, } impl HygieneData { crate fn new(edition: Edition) -> Self { - let mut root_data = ExpnData::default( + let root_data = ExpnData::default( ExpnKind::Root, DUMMY_SP, edition, - Some(DefId::local(CRATE_DEF_INDEX)), + Some(CRATE_DEF_ID.to_def_id()), None, ); - root_data.orig_id = Some(0); HygieneData { - expn_data: vec![Some(root_data)], - expn_hashes: vec![ExpnHash(Fingerprint::ZERO)], - expn_hash_to_expn_id: std::iter::once((ExpnHash(Fingerprint::ZERO), ExpnId(0))) + local_expn_data: IndexVec::from_elem_n(Some(root_data), 1), + local_expn_hashes: IndexVec::from_elem_n(ExpnHash(Fingerprint::ZERO), 1), + foreign_expn_data: FxHashMap::default(), + foreign_expn_hashes: FxHashMap::default(), + expn_hash_to_expn_id: std::iter::once((ExpnHash(Fingerprint::ZERO), ExpnId::root())) .collect(), syntax_context_data: vec![SyntaxContextData { outer_expn: ExpnId::root(), @@ -221,24 +350,29 @@ impl HygieneData { with_session_globals(|session_globals| f(&mut *session_globals.hygiene_data.borrow_mut())) } - fn fresh_expn(&mut self, mut expn_data: Option) -> ExpnId { - let raw_id = self.expn_data.len() as u32; - if let Some(data) = expn_data.as_mut() { - assert_eq!(data.orig_id, None); - data.orig_id = Some(raw_id); - } - self.expn_data.push(expn_data); - self.expn_hashes.push(ExpnHash(Fingerprint::ZERO)); - ExpnId(raw_id) + #[inline] + fn local_expn_hash(&self, expn_id: LocalExpnId) -> ExpnHash { + self.local_expn_hashes[expn_id] } #[inline] fn expn_hash(&self, expn_id: ExpnId) -> ExpnHash { - self.expn_hashes[expn_id.0 as usize] + match expn_id.as_local() { + Some(expn_id) => self.local_expn_hashes[expn_id], + None => self.foreign_expn_hashes[&expn_id], + } + } + + fn local_expn_data(&self, expn_id: LocalExpnId) -> &ExpnData { + self.local_expn_data[expn_id].as_ref().expect("no expansion data for an expansion ID") } fn expn_data(&self, expn_id: ExpnId) -> &ExpnData { - self.expn_data[expn_id.0 as usize].as_ref().expect("no expansion data for an expansion ID") + if let Some(expn_id) = expn_id.as_local() { + self.local_expn_data[expn_id].as_ref().expect("no expansion data for an expansion ID") + } else { + &self.foreign_expn_data[&expn_id] + } } fn is_descendant_of(&self, mut expn_id: ExpnId, ancestor: ExpnId) -> bool { @@ -453,17 +587,21 @@ pub fn debug_hygiene_data(verbose: bool) -> String { } else { let mut s = String::from(""); s.push_str("Expansions:"); - data.expn_data.iter().enumerate().for_each(|(id, expn_info)| { - let expn_info = expn_info.as_ref().expect("no expansion data for an expansion ID"); + let mut debug_expn_data = |(id, expn_data): (&ExpnId, &ExpnData)| { s.push_str(&format!( - "\n{}: parent: {:?}, call_site_ctxt: {:?}, def_site_ctxt: {:?}, kind: {:?}", + "\n{:?}: parent: {:?}, call_site_ctxt: {:?}, def_site_ctxt: {:?}, kind: {:?}", id, - expn_info.parent, - expn_info.call_site.ctxt(), - expn_info.def_site.ctxt(), - expn_info.kind, - )); + expn_data.parent, + expn_data.call_site.ctxt(), + expn_data.def_site.ctxt(), + expn_data.kind, + )) + }; + data.local_expn_data.iter_enumerated().for_each(|(id, expn_data)| { + let expn_data = expn_data.as_ref().expect("no expansion data for an expansion ID"); + debug_expn_data((&id.to_expn_id(), expn_data)) }); + data.foreign_expn_data.iter().for_each(debug_expn_data); s.push_str("\n\nSyntaxContexts:"); data.syntax_context_data.iter().enumerate().for_each(|(id, ctxt)| { s.push_str(&format!( @@ -696,7 +834,7 @@ impl Span { transparency: Transparency, ctx: impl HashStableContext, ) -> Span { - let expn_id = ExpnId::fresh(expn_data, ctx); + let expn_id = LocalExpnId::fresh(expn_data, ctx).to_expn_id(); HygieneData::with(|data| { self.with_ctxt(data.apply_mark(SyntaxContext::root(), expn_id, transparency)) }) @@ -738,20 +876,6 @@ pub struct ExpnData { /// call_site span would have its own ExpnData, with the call_site /// pointing to the `foo!` invocation. pub call_site: Span, - /// The crate that originally created this `ExpnData`. During - /// metadata serialization, we only encode `ExpnData`s that were - /// created locally - when our serialized metadata is decoded, - /// foreign `ExpnId`s will have their `ExpnData` looked up - /// from the crate specified by `Crate - krate: CrateNum, - /// The raw that this `ExpnData` had in its original crate. - /// An `ExpnData` can be created before being assigned an `ExpnId`, - /// so this might be `None` until `set_expn_data` is called - // This is used only for serialization/deserialization purposes: - // two `ExpnData`s that differ only in their `orig_id` should - // be considered equivalent. - #[stable_hasher(ignore)] - orig_id: Option, /// Used to force two `ExpnData`s to have different `Fingerprint`s. /// Due to macro expansion, it's possible to end up with two `ExpnId`s /// that have identical `ExpnData`s. This violates the contract of `HashStable` @@ -790,7 +914,6 @@ pub struct ExpnData { pub parent_module: Option, } -// These would require special handling of `orig_id`. impl !PartialEq for ExpnData {} impl !Hash for ExpnData {} @@ -818,8 +941,6 @@ impl ExpnData { edition, macro_def_id, parent_module, - krate: LOCAL_CRATE, - orig_id: None, disambiguator: 0, } } @@ -843,8 +964,6 @@ impl ExpnData { edition, macro_def_id, parent_module, - krate: LOCAL_CRATE, - orig_id: None, disambiguator: 0, } } @@ -869,7 +988,7 @@ impl ExpnData { } #[inline] - fn hash_expn(&self, ctx: &mut impl HashStableContext) -> Fingerprint { + fn hash_expn(&self, ctx: &mut impl HashStableContext) -> u64 { let mut hasher = StableHasher::new(); self.hash_stable(ctx, &mut hasher); hasher.finish() @@ -1020,11 +1139,18 @@ pub struct HygieneEncodeContext { } impl HygieneEncodeContext { + /// Record the fact that we need to serialize the corresponding `ExpnData`. + pub fn schedule_expn_data_for_encoding(&self, expn: ExpnId) { + if !self.serialized_expns.lock().contains(&expn) { + self.latest_expns.lock().insert(expn); + } + } + pub fn encode( &self, encoder: &mut T, mut encode_ctxt: impl FnMut(&mut T, u32, &SyntaxContextData) -> Result<(), R>, - mut encode_expn: impl FnMut(&mut T, u32, ExpnData, ExpnHash) -> Result<(), R>, + mut encode_expn: impl FnMut(&mut T, ExpnId, &ExpnData, ExpnHash) -> Result<(), R>, ) -> Result<(), R> { // When we serialize a `SyntaxContextData`, we may end up serializing // a `SyntaxContext` that we haven't seen before @@ -1051,9 +1177,9 @@ impl HygieneEncodeContext { let latest_expns = { std::mem::take(&mut *self.latest_expns.lock()) }; - for_all_expns_in(latest_expns.into_iter(), |index, expn, data, hash| { + for_all_expns_in(latest_expns.into_iter(), |expn, data, hash| { if self.serialized_expns.lock().insert(expn) { - encode_expn(encoder, index, data, hash)?; + encode_expn(encoder, expn, data, hash)?; } Ok(()) })?; @@ -1072,78 +1198,70 @@ pub struct HygieneDecodeContext { // so that multiple occurrences of the same serialized id are decoded to the same // `SyntaxContext` remapped_ctxts: Lock>>, - // The same as `remapepd_ctxts`, but for `ExpnId`s - remapped_expns: Lock>>, } -pub fn decode_expn_id<'a, D: Decoder, G>( - d: &mut D, - mode: ExpnDataDecodeMode<'a, G>, - decode_data: impl FnOnce(&mut D, u32) -> Result<(ExpnData, ExpnHash), D::Error>, -) -> Result -where - G: FnOnce(CrateNum) -> &'a HygieneDecodeContext, -{ - let index = u32::decode(d)?; - let context = match mode { - ExpnDataDecodeMode::IncrComp(context) => context, - ExpnDataDecodeMode::Metadata(get_context) => { - let krate = CrateNum::decode(d)?; - get_context(krate) - } - }; +/// Register an expansion which has been decoded from the on-disk-cache for the local crate. +pub fn register_local_expn_id(data: ExpnData, hash: ExpnHash) -> ExpnId { + HygieneData::with(|hygiene_data| { + let expn_id = hygiene_data.local_expn_data.next_index(); + hygiene_data.local_expn_data.push(Some(data)); + let _eid = hygiene_data.local_expn_hashes.push(hash); + debug_assert_eq!(expn_id, _eid); - // Do this after decoding, so that we decode a `CrateNum` - // if necessary - if index == ExpnId::root().as_u32() { + let expn_id = expn_id.to_expn_id(); + + let _old_id = hygiene_data.expn_hash_to_expn_id.insert(hash, expn_id); + debug_assert!(_old_id.is_none()); + expn_id + }) +} + +/// Register an expansion which has been decoded from the metadata of a foreign crate. +pub fn register_expn_id( + krate: CrateNum, + local_id: ExpnIndex, + data: ExpnData, + hash: ExpnHash, +) -> ExpnId { + let expn_id = ExpnId { krate, local_id }; + HygieneData::with(|hygiene_data| { + let _old_data = hygiene_data.foreign_expn_data.insert(expn_id, data); + debug_assert!(_old_data.is_none()); + let _old_hash = hygiene_data.foreign_expn_hashes.insert(expn_id, hash); + debug_assert!(_old_hash.is_none()); + let _old_id = hygiene_data.expn_hash_to_expn_id.insert(hash, expn_id); + debug_assert!(_old_id.is_none()); + }); + expn_id +} + +/// Decode an expansion from the metadata of a foreign crate. +pub fn decode_expn_id( + krate: CrateNum, + index: u32, + decode_data: impl FnOnce(ExpnId) -> (ExpnData, ExpnHash), +) -> ExpnId { + if index == 0 { debug!("decode_expn_id: deserialized root"); - return Ok(ExpnId::root()); + return ExpnId::root(); } - let outer_expns = &context.remapped_expns; + let index = ExpnIndex::from_u32(index); - // Ensure that the lock() temporary is dropped early - { - if let Some(expn_id) = outer_expns.lock().get(index as usize).copied().flatten() { - return Ok(expn_id); - } + // This function is used to decode metadata, so it cannot decode information about LOCAL_CRATE. + debug_assert_ne!(krate, LOCAL_CRATE); + let expn_id = ExpnId { krate, local_id: index }; + + // Fast path if the expansion has already been decoded. + if HygieneData::with(|hygiene_data| hygiene_data.foreign_expn_data.contains_key(&expn_id)) { + return expn_id; } // Don't decode the data inside `HygieneData::with`, since we need to recursively decode // other ExpnIds - let (mut expn_data, hash) = decode_data(d, index)?; + let (expn_data, hash) = decode_data(expn_id); - let expn_id = HygieneData::with(|hygiene_data| { - if let Some(&expn_id) = hygiene_data.expn_hash_to_expn_id.get(&hash) { - return expn_id; - } - - let expn_id = ExpnId(hygiene_data.expn_data.len() as u32); - - // If we just deserialized an `ExpnData` owned by - // the local crate, its `orig_id` will be stale, - // so we need to update it to its own value. - // This only happens when we deserialize the incremental cache, - // since a crate will never decode its own metadata. - if expn_data.krate == LOCAL_CRATE { - expn_data.orig_id = Some(expn_id.0); - } - - hygiene_data.expn_data.push(Some(expn_data)); - hygiene_data.expn_hashes.push(hash); - let _old_id = hygiene_data.expn_hash_to_expn_id.insert(hash, expn_id); - debug_assert!(_old_id.is_none()); - - let mut expns = outer_expns.lock(); - let new_len = index as usize + 1; - if expns.len() < new_len { - expns.resize(new_len, None); - } - expns[index as usize] = Some(expn_id); - drop(expns); - expn_id - }); - Ok(expn_id) + register_expn_id(krate, index, expn_data, hash) } // Decodes `SyntaxContext`, using the provided `HygieneDecodeContext` @@ -1234,29 +1352,37 @@ fn for_all_ctxts_in Resul fn for_all_expns_in( expns: impl Iterator, - mut f: impl FnMut(u32, ExpnId, ExpnData, ExpnHash) -> Result<(), E>, + mut f: impl FnMut(ExpnId, &ExpnData, ExpnHash) -> Result<(), E>, ) -> Result<(), E> { let all_data: Vec<_> = HygieneData::with(|data| { expns - .map(|expn| { - let idx = expn.0 as usize; - (expn, data.expn_data[idx].clone(), data.expn_hashes[idx].clone()) - }) + .map(|expn| (expn, data.expn_data(expn).clone(), data.expn_hash(expn).clone())) .collect() }); for (expn, data, hash) in all_data.into_iter() { - let data = data.unwrap_or_else(|| panic!("Missing data for {:?}", expn)); - f(expn.0, expn, data, hash)?; + f(expn, &data, hash)?; } Ok(()) } +impl Encodable for LocalExpnId { + fn encode(&self, e: &mut E) -> Result<(), E::Error> { + self.to_expn_id().encode(e) + } +} + impl Encodable for ExpnId { default fn encode(&self, _: &mut E) -> Result<(), E::Error> { panic!("cannot encode `ExpnId` with `{}`", std::any::type_name::()); } } +impl Decodable for LocalExpnId { + fn decode(d: &mut D) -> Result { + ExpnId::decode(d).map(ExpnId::expect_local) + } +} + impl Decodable for ExpnId { default fn decode(_: &mut D) -> Result { panic!("cannot decode `ExpnId` with `{}`", std::any::type_name::()); @@ -1274,58 +1400,6 @@ pub fn raw_encode_syntax_context( ctxt.0.encode(e) } -pub fn raw_encode_expn_id( - expn: ExpnId, - context: &HygieneEncodeContext, - mode: ExpnDataEncodeMode, - e: &mut E, -) -> Result<(), E::Error> { - // Record the fact that we need to serialize the corresponding - // `ExpnData` - let needs_data = || { - if !context.serialized_expns.lock().contains(&expn) { - context.latest_expns.lock().insert(expn); - } - }; - - match mode { - ExpnDataEncodeMode::IncrComp => { - // Always serialize the `ExpnData` in incr comp mode - needs_data(); - expn.0.encode(e) - } - ExpnDataEncodeMode::Metadata => { - let data = expn.expn_data(); - // We only need to serialize the ExpnData - // if it comes from this crate. - // We currently don't serialize any hygiene information data for - // proc-macro crates: see the `SpecializedEncoder` impl - // for crate metadata. - if data.krate == LOCAL_CRATE { - needs_data(); - } - data.orig_id.expect("Missing orig_id").encode(e)?; - data.krate.encode(e) - } - } -} - -pub enum ExpnDataEncodeMode { - IncrComp, - Metadata, -} - -pub enum ExpnDataDecodeMode<'a, F: FnOnce(CrateNum) -> &'a HygieneDecodeContext> { - IncrComp(&'a HygieneDecodeContext), - Metadata(F), -} - -impl<'a> ExpnDataDecodeMode<'a, Box &'a HygieneDecodeContext>> { - pub fn incr_comp(ctxt: &'a HygieneDecodeContext) -> Self { - ExpnDataDecodeMode::IncrComp(ctxt) - } -} - impl Encodable for SyntaxContext { default fn encode(&self, _: &mut E) -> Result<(), E::Error> { panic!("cannot encode `SyntaxContext` with `{}`", std::any::type_name::()); @@ -1345,10 +1419,9 @@ impl Decodable for SyntaxContext { /// This method is called only when an `ExpnData` is first associated /// with an `ExpnId` (when the `ExpnId` is initially constructed, or via /// `set_expn_data`). It is *not* called for foreign `ExpnId`s deserialized -/// from another crate's metadata - since `ExpnData` includes a `krate` field, +/// from another crate's metadata - since `ExpnHash` includes the stable crate id, /// collisions are only possible between `ExpnId`s within the same crate. -fn update_disambiguator(expn_id: ExpnId, mut ctx: impl HashStableContext) { - let mut expn_data = expn_id.expn_data(); +fn update_disambiguator(expn_data: &mut ExpnData, mut ctx: impl HashStableContext) -> ExpnHash { // This disambiguator should not have been set yet. assert_eq!( expn_data.disambiguator, 0, @@ -1367,8 +1440,7 @@ fn update_disambiguator(expn_id: ExpnId, mut ctx: impl HashStableContext) { }); if disambiguator != 0 { - debug!("Set disambiguator for {:?} (hash {:?})", expn_id, expn_hash); - debug!("expn_data = {:?}", expn_data); + debug!("Set disambiguator for expn_data={:?} expn_hash={:?}", expn_data, expn_hash); expn_data.disambiguator = disambiguator; expn_hash = expn_data.hash_expn(&mut ctx); @@ -1384,14 +1456,7 @@ fn update_disambiguator(expn_id: ExpnId, mut ctx: impl HashStableContext) { }); } - let expn_hash = ExpnHash(expn_hash); - HygieneData::with(|data| { - data.expn_data[expn_id.0 as usize].as_mut().unwrap().disambiguator = disambiguator; - debug_assert_eq!(data.expn_hashes[expn_id.0 as usize].0, Fingerprint::ZERO); - data.expn_hashes[expn_id.0 as usize] = expn_hash; - let _old_id = data.expn_hash_to_expn_id.insert(expn_hash, expn_id); - debug_assert!(_old_id.is_none()); - }); + ExpnHash::new(ctx.def_path_hash(LOCAL_CRATE.as_def_id()).stable_crate_id(), expn_hash) } impl HashStable for SyntaxContext { diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index 7a1ee20ee7951..1c95cc91208d3 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -38,7 +38,7 @@ use edition::Edition; pub mod hygiene; use hygiene::Transparency; pub use hygiene::{DesugaringKind, ExpnKind, ForLoopLoc, MacroKind}; -pub use hygiene::{ExpnData, ExpnHash, ExpnId, SyntaxContext}; +pub use hygiene::{ExpnData, ExpnHash, ExpnId, LocalExpnId, SyntaxContext}; pub mod def_id; use def_id::{CrateNum, DefId, DefPathHash, LOCAL_CRATE}; pub mod lev_distance; diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 07f22159f96c8..a8f969782b22d 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -122,10 +122,14 @@ symbols! { // nice to have. Symbols { Alignment, + Any, Arc, Argument, ArgumentV1, Arguments, + AsMut, + AsRef, + BTreeEntry, BTreeMap, BTreeSet, BinaryHeap, @@ -139,6 +143,7 @@ symbols! { Continue, Copy, Count, + Cow, Debug, DebugStruct, DebugTuple, @@ -146,12 +151,17 @@ symbols! { Decoder, Default, Deref, + DirBuilder, + DoubleEndedIterator, + Duration, Encodable, Encoder, Eq, Equal, Err, Error, + File, + FileType, FormatSpec, Formatter, From, @@ -162,11 +172,14 @@ symbols! { GlobalAlloc, Hash, HashMap, + HashMapEntry, HashSet, Hasher, Implied, Input, IntoIterator, + IoRead, + IoWrite, Is, ItemContext, Iterator, @@ -369,6 +382,8 @@ symbols! { closure, closure_to_fn_coercion, cmp, + cmp_max, + cmp_min, cmpxchg16b_target_feature, cmse_nonsecure_entry, coerce_unsized, @@ -674,6 +689,7 @@ symbols! { item, item_like_imports, iter, + iter_repeat, keyword, kind, kreg, @@ -740,6 +756,12 @@ symbols! { maybe_uninit, maybe_uninit_uninit, maybe_uninit_zeroed, + mem_discriminant, + mem_drop, + mem_forget, + mem_replace, + mem_size_of, + mem_size_of_val, mem_uninitialized, mem_zeroed, member_constraints, diff --git a/compiler/rustc_symbol_mangling/src/legacy.rs b/compiler/rustc_symbol_mangling/src/legacy.rs index 0c64fe6ea60a9..2917eef63c2dd 100644 --- a/compiler/rustc_symbol_mangling/src/legacy.rs +++ b/compiler/rustc_symbol_mangling/src/legacy.rs @@ -108,7 +108,7 @@ fn get_symbol_hash<'tcx>( // Include the main item-type. Note that, in this case, the // assertions about `needs_subst` may not hold, but this item-type // ought to be the same for every reference anyway. - assert!(!item_type.has_erasable_regions()); + assert!(!item_type.has_erasable_regions(tcx)); hcx.while_hashing_spans(false, |hcx| { hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| { item_type.hash_stable(hcx, &mut hasher); diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index 14442806fc0b7..b1d042c988a50 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -286,7 +286,8 @@ impl Printer<'tcx> for SymbolMangler<'tcx> { // Encode impl generic params if the substitutions contain parameters (implying // polymorphization is enabled) and this isn't an inherent impl. - if impl_trait_ref.is_some() && substs.iter().any(|a| a.has_param_types_or_consts()) { + if impl_trait_ref.is_some() && substs.iter().any(|a| a.has_param_types_or_consts(self.tcx)) + { self = self.path_generic_args( |this| { this.path_append_ns( diff --git a/compiler/rustc_trait_selection/src/opaque_types.rs b/compiler/rustc_trait_selection/src/opaque_types.rs index cc98cd7256628..74a4ce30ef9fa 100644 --- a/compiler/rustc_trait_selection/src/opaque_types.rs +++ b/compiler/rustc_trait_selection/src/opaque_types.rs @@ -424,6 +424,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { for required_region in required_region_bounds { concrete_ty.visit_with(&mut ConstrainOpaqueTypeRegionVisitor { + tcx, op: |r| self.sub_regions(infer::CallReturn(span), required_region, r), }); } @@ -499,6 +500,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { } } concrete_ty.visit_with(&mut ConstrainOpaqueTypeRegionVisitor { + tcx, op: |r| self.sub_regions(infer::CallReturn(span), least_region, r), }); } @@ -533,6 +535,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { ); concrete_ty.visit_with(&mut ConstrainOpaqueTypeRegionVisitor { + tcx: self.tcx, op: |r| { self.member_constraint( opaque_type_key.def_id, @@ -618,14 +621,19 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { // // We ignore any type parameters because impl trait values are assumed to // capture all the in-scope type parameters. -struct ConstrainOpaqueTypeRegionVisitor { +struct ConstrainOpaqueTypeRegionVisitor<'tcx, OP> { + tcx: TyCtxt<'tcx>, op: OP, } -impl<'tcx, OP> TypeVisitor<'tcx> for ConstrainOpaqueTypeRegionVisitor +impl<'tcx, OP> TypeVisitor<'tcx> for ConstrainOpaqueTypeRegionVisitor<'tcx, OP> where OP: FnMut(ty::Region<'tcx>), { + fn tcx_for_anon_const_substs(&self) -> Option> { + Some(self.tcx) + } + fn visit_binder>( &mut self, t: &ty::Binder<'tcx, T>, @@ -647,7 +655,7 @@ where fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow { // We're only interested in types involving regions - if !ty.flags().intersects(ty::TypeFlags::HAS_FREE_REGIONS) { + if !ty.flags().intersects(ty::TypeFlags::HAS_POTENTIAL_FREE_REGIONS) { return ControlFlow::CONTINUE; } diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index 9bb4af16a8f53..6ab079ad404d5 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -391,7 +391,7 @@ fn orphan_check_trait_ref<'tcx>( ) -> Result<(), OrphanCheckErr<'tcx>> { debug!("orphan_check_trait_ref(trait_ref={:?}, in_crate={:?})", trait_ref, in_crate); - if trait_ref.needs_infer() && trait_ref.needs_subst() { + if trait_ref.needs_infer() && trait_ref.needs_subst(tcx) { bug!( "can't orphan check a trait ref with both params and inference variables {:?}", trait_ref diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index b1a938836b70e..80c824565d226 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -19,7 +19,7 @@ use rustc_middle::mir::{self, Rvalue, StatementKind, TerminatorKind}; use rustc_middle::ty::subst::{Subst, SubstsRef}; use rustc_middle::ty::{self, TyCtxt, TypeFoldable}; use rustc_session::lint; -use rustc_span::def_id::{DefId, LocalDefId}; +use rustc_span::def_id::LocalDefId; use rustc_span::Span; use std::cmp; @@ -29,26 +29,20 @@ use std::ops::ControlFlow; /// Check if a given constant can be evaluated. pub fn is_const_evaluatable<'cx, 'tcx>( infcx: &InferCtxt<'cx, 'tcx>, - def: ty::WithOptConstParam, - substs: SubstsRef<'tcx>, + uv: ty::Unevaluated<'tcx>, param_env: ty::ParamEnv<'tcx>, span: Span, ) -> Result<(), NotConstEvaluatable> { - debug!("is_const_evaluatable({:?}, {:?})", def, substs); + debug!("is_const_evaluatable({:?})", uv); if infcx.tcx.features().const_evaluatable_checked { let tcx = infcx.tcx; - match AbstractConst::new(tcx, def, substs)? { + match AbstractConst::new(tcx, uv)? { // We are looking at a generic abstract constant. Some(ct) => { for pred in param_env.caller_bounds() { match pred.kind().skip_binder() { - ty::PredicateKind::ConstEvaluatable(b_def, b_substs) => { - if b_def == def && b_substs == substs { - debug!("is_const_evaluatable: caller_bound ~~> ok"); - return Ok(()); - } - - if let Some(b_ct) = AbstractConst::new(tcx, b_def, b_substs)? { + ty::PredicateKind::ConstEvaluatable(uv) => { + if let Some(b_ct) = AbstractConst::new(tcx, uv)? { // Try to unify with each subtree in the AbstractConst to allow for // `N + 1` being const evaluatable even if theres only a `ConstEvaluatable` // predicate for `(N + 1) * 2` @@ -91,7 +85,7 @@ pub fn is_const_evaluatable<'cx, 'tcx>( let leaf = leaf.subst(tcx, ct.substs); if leaf.has_infer_types_or_consts() { failure_kind = FailureKind::MentionsInfer; - } else if leaf.has_param_types_or_consts() { + } else if leaf.has_param_types_or_consts(tcx) { failure_kind = cmp::min(failure_kind, FailureKind::MentionsParam); } @@ -101,7 +95,7 @@ pub fn is_const_evaluatable<'cx, 'tcx>( let ty = ty.subst(tcx, ct.substs); if ty.has_infer_types_or_consts() { failure_kind = FailureKind::MentionsInfer; - } else if ty.has_param_types_or_consts() { + } else if ty.has_param_types_or_consts(tcx) { failure_kind = cmp::min(failure_kind, FailureKind::MentionsParam); } @@ -134,7 +128,7 @@ pub fn is_const_evaluatable<'cx, 'tcx>( } let future_compat_lint = || { - if let Some(local_def_id) = def.did.as_local() { + if let Some(local_def_id) = uv.def.did.as_local() { infcx.tcx.struct_span_lint_hir( lint::builtin::CONST_EVALUATABLE_UNCHECKED, infcx.tcx.hir().local_def_id_to_hir_id(local_def_id), @@ -155,16 +149,12 @@ pub fn is_const_evaluatable<'cx, 'tcx>( // and hopefully soon change this to an error. // // See #74595 for more details about this. - let concrete = infcx.const_eval_resolve( - param_env, - ty::Unevaluated { def, substs, promoted: None }, - Some(span), - ); - - if concrete.is_ok() && substs.has_param_types_or_consts() { - match infcx.tcx.def_kind(def.did) { + let concrete = infcx.const_eval_resolve(param_env, uv, Some(span)); + + if concrete.is_ok() && uv.substs(infcx.tcx).has_param_types_or_consts(infcx.tcx) { + match infcx.tcx.def_kind(uv.def.did) { DefKind::AnonConst => { - let mir_body = infcx.tcx.mir_for_ctfe_opt_const_arg(def); + let mir_body = infcx.tcx.mir_for_ctfe_opt_const_arg(uv.def); if mir_body.is_polymorphic { future_compat_lint(); @@ -176,7 +166,7 @@ pub fn is_const_evaluatable<'cx, 'tcx>( debug!(?concrete, "is_const_evaluatable"); match concrete { - Err(ErrorHandled::TooGeneric) => Err(match substs.has_infer_types_or_consts() { + Err(ErrorHandled::TooGeneric) => Err(match uv.has_infer_types_or_consts() { true => NotConstEvaluatable::MentionsInfer, false => NotConstEvaluatable::MentionsParam, }), @@ -201,15 +191,14 @@ pub struct AbstractConst<'tcx> { pub substs: SubstsRef<'tcx>, } -impl AbstractConst<'tcx> { +impl<'tcx> AbstractConst<'tcx> { pub fn new( tcx: TyCtxt<'tcx>, - def: ty::WithOptConstParam, - substs: SubstsRef<'tcx>, + uv: ty::Unevaluated<'tcx>, ) -> Result>, ErrorReported> { - let inner = tcx.mir_abstract_const_opt_const_arg(def)?; - debug!("AbstractConst::new({:?}) = {:?}", def, inner); - Ok(inner.map(|inner| AbstractConst { inner, substs })) + let inner = tcx.mir_abstract_const_opt_const_arg(uv.def)?; + debug!("AbstractConst::new({:?}) = {:?}", uv, inner); + Ok(inner.map(|inner| AbstractConst { inner, substs: uv.substs(tcx) })) } pub fn from_const( @@ -217,9 +206,7 @@ impl AbstractConst<'tcx> { ct: &ty::Const<'tcx>, ) -> Result>, ErrorReported> { match ct.val { - ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted: _ }) => { - AbstractConst::new(tcx, def, substs) - } + ty::ConstKind::Unevaluated(uv) => AbstractConst::new(tcx, uv), ty::ConstKind::Error(_) => Err(ErrorReported), _ => Ok(None), } @@ -569,14 +556,11 @@ pub(super) fn mir_abstract_const<'tcx>( pub(super) fn try_unify_abstract_consts<'tcx>( tcx: TyCtxt<'tcx>, - ((a, a_substs), (b, b_substs)): ( - (ty::WithOptConstParam, SubstsRef<'tcx>), - (ty::WithOptConstParam, SubstsRef<'tcx>), - ), + (a, b): (ty::Unevaluated<'tcx>, ty::Unevaluated<'tcx>), ) -> bool { (|| { - if let Some(a) = AbstractConst::new(tcx, a, a_substs)? { - if let Some(b) = AbstractConst::new(tcx, b, b_substs)? { + if let Some(a) = AbstractConst::new(tcx, a)? { + if let Some(b) = AbstractConst::new(tcx, b)? { return Ok(try_unify(tcx, a, b)); } } diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index 5c4aef529e5ac..52bed225a57af 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -804,10 +804,10 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { } match obligation.predicate.kind().skip_binder() { - ty::PredicateKind::ConstEvaluatable(def, _) => { + ty::PredicateKind::ConstEvaluatable(uv) => { let mut err = self.tcx.sess.struct_span_err(span, "unconstrained generic constant"); - let const_span = self.tcx.def_span(def.did); + let const_span = self.tcx.def_span(uv.def.did); match self.tcx.sess.source_map().span_to_snippet(const_span) { Ok(snippet) => err.help(&format!( "try adding a `where` bound using this expression: `where [(); {}]:`", diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index 21ed586ab560b..4bbab6f700a82 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -167,6 +167,7 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> { /// `SomeTrait` or a where-clause that lets us unify `$0` with /// something concrete. If this fails, we'll unify `$0` with /// `projection_ty` again. + #[tracing::instrument(level = "debug", skip(self, infcx, param_env, cause))] fn normalize_projection_type( &mut self, infcx: &InferCtxt<'_, 'tcx>, @@ -174,8 +175,6 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> { projection_ty: ty::ProjectionTy<'tcx>, cause: ObligationCause<'tcx>, ) -> Ty<'tcx> { - debug!(?projection_ty, "normalize_projection_type"); - debug_assert!(!projection_ty.has_escaping_bound_vars()); // FIXME(#20304) -- cache @@ -490,11 +489,10 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> { } } - ty::PredicateKind::ConstEvaluatable(def_id, substs) => { + ty::PredicateKind::ConstEvaluatable(uv) => { match const_evaluatable::is_const_evaluatable( self.selcx.infcx(), - def_id, - substs, + uv, obligation.param_env, obligation.cause.span, ) { @@ -502,7 +500,9 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> { Err(NotConstEvaluatable::MentionsInfer) => { pending_obligation.stalled_on.clear(); pending_obligation.stalled_on.extend( - substs.iter().filter_map(TyOrConstInferVar::maybe_from_generic_arg), + uv.substs(infcx.tcx) + .iter() + .filter_map(TyOrConstInferVar::maybe_from_generic_arg), ); ProcessResult::Unchanged } @@ -517,7 +517,8 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> { ty::PredicateKind::ConstEquate(c1, c2) => { debug!(?c1, ?c2, "equating consts"); - if self.selcx.tcx().features().const_evaluatable_checked { + let tcx = self.selcx.tcx(); + if tcx.features().const_evaluatable_checked { // FIXME: we probably should only try to unify abstract constants // if the constants depend on generic parameters. // @@ -525,11 +526,7 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> { if let (ty::ConstKind::Unevaluated(a), ty::ConstKind::Unevaluated(b)) = (c1.val, c2.val) { - if self - .selcx - .tcx() - .try_unify_abstract_consts(((a.def, a.substs), (b.def, b.substs))) - { + if tcx.try_unify_abstract_consts((a, b)) { return ProcessResult::Changed(vec![]); } } @@ -548,7 +545,7 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> { Err(ErrorHandled::TooGeneric) => { stalled_on.extend( unevaluated - .substs + .substs(tcx) .iter() .filter_map(TyOrConstInferVar::maybe_from_generic_arg), ); @@ -619,7 +616,7 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> { stalled_on: &mut Vec>, ) -> ProcessResult, FulfillmentErrorCode<'tcx>> { let infcx = self.selcx.infcx(); - if obligation.predicate.is_global() { + if obligation.predicate.is_known_global() { // no type variables present, can use evaluation for better caching. // FIXME: consider caching errors too. if infcx.predicate_must_hold_considering_regions(obligation) { @@ -695,14 +692,15 @@ fn substs_infer_vars<'a, 'tcx>( selcx: &mut SelectionContext<'a, 'tcx>, substs: ty::Binder<'tcx, SubstsRef<'tcx>>, ) -> impl Iterator> { + let tcx = selcx.tcx(); selcx .infcx() .resolve_vars_if_possible(substs) .skip_binder() // ok because this check doesn't care about regions .iter() .filter(|arg| arg.has_infer_types_or_consts()) - .flat_map(|arg| { - let mut walker = arg.walk(); + .flat_map(move |arg| { + let mut walker = arg.walk(tcx); while let Some(c) = walker.next() { if !c.has_infer_types_or_consts() { walker.visited.remove(&c); diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 3a80e720e8c4b..91790967fdae4 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -447,7 +447,7 @@ fn subst_and_check_impossible_predicates<'tcx>( debug!("subst_and_check_impossible_predicates(key={:?})", key); let mut predicates = tcx.predicates_of(key.0).instantiate(tcx, key.1).predicates; - predicates.retain(|predicate| !predicate.needs_subst()); + predicates.retain(|predicate| !predicate.needs_subst(tcx)); let result = impossible_predicates(tcx, predicates); debug!("subst_and_check_impossible_predicates(key={:?}) = {:?}", key, result); diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index 7ebef7f8883ae..1df707565f4a4 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -278,7 +278,7 @@ fn predicate_references_self( (predicate, sp): (ty::Predicate<'tcx>, Span), ) -> Option { let self_ty = tcx.types.self_param; - let has_self_ty = |arg: &GenericArg<'_>| arg.walk().any(|arg| arg == self_ty.into()); + let has_self_ty = |arg: &GenericArg<'tcx>| arg.walk(tcx).any(|arg| arg == self_ty.into()); match predicate.kind().skip_binder() { ty::PredicateKind::Trait(ref data, _) => { // In the case of a trait predicate, we can skip the "self" type. @@ -769,6 +769,9 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeFoldable<'tcx>>( impl<'tcx> TypeVisitor<'tcx> for IllegalSelfTypeVisitor<'tcx> { type BreakTy = (); + fn tcx_for_anon_const_substs(&self) -> Option> { + Some(self.tcx) + } fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { match t.kind() { @@ -849,12 +852,12 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeFoldable<'tcx>>( } fn visit_predicate(&mut self, pred: ty::Predicate<'tcx>) -> ControlFlow { - if let ty::PredicateKind::ConstEvaluatable(def, substs) = pred.kind().skip_binder() { + if let ty::PredicateKind::ConstEvaluatable(ct) = pred.kind().skip_binder() { // FIXME(const_evaluatable_checked): We should probably deduplicate the logic for // `AbstractConst`s here, it might make sense to change `ConstEvaluatable` to // take a `ty::Const` instead. use rustc_middle::mir::abstract_const::Node; - if let Ok(Some(ct)) = AbstractConst::new(self.tcx, def, substs) { + if let Ok(Some(ct)) = AbstractConst::new(self.tcx, ct) { const_evaluatable::walk_abstract_const(self.tcx, ct, |node| match node.root() { Node::Leaf(leaf) => { let leaf = leaf.subst(self.tcx, ct.substs); diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 98fde3707f70e..d1ab9fa025ed6 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -273,7 +273,7 @@ where Normalized { value, obligations } } -#[instrument(level = "debug", skip(selcx, param_env, cause, obligations))] +#[instrument(level = "info", skip(selcx, param_env, cause, obligations))] pub fn normalize_with_depth_to<'a, 'b, 'tcx, T>( selcx: &'a mut SelectionContext<'b, 'tcx>, param_env: ty::ParamEnv<'tcx>, @@ -285,6 +285,7 @@ pub fn normalize_with_depth_to<'a, 'b, 'tcx, T>( where T: TypeFoldable<'tcx>, { + debug!(obligations.len = obligations.len()); let mut normalizer = AssocTypeNormalizer::new(selcx, param_env, cause, depth, obligations); let result = ensure_sufficient_stack(|| normalizer.fold(value)); debug!(?result, obligations.len = normalizer.obligations.len()); @@ -292,6 +293,18 @@ where result } +pub(crate) fn needs_normalization<'tcx, T: TypeFoldable<'tcx>>(value: &T, reveal: Reveal) -> bool { + match reveal { + Reveal::UserFacing => value + .has_type_flags(ty::TypeFlags::HAS_TY_PROJECTION | ty::TypeFlags::HAS_CT_PROJECTION), + Reveal::All => value.has_type_flags( + ty::TypeFlags::HAS_TY_PROJECTION + | ty::TypeFlags::HAS_TY_OPAQUE + | ty::TypeFlags::HAS_CT_PROJECTION, + ), + } +} + struct AssocTypeNormalizer<'a, 'b, 'tcx> { selcx: &'a mut SelectionContext<'b, 'tcx>, param_env: ty::ParamEnv<'tcx>, @@ -314,6 +327,7 @@ impl<'a, 'b, 'tcx> AssocTypeNormalizer<'a, 'b, 'tcx> { fn fold>(&mut self, value: T) -> T { let value = self.selcx.infcx().resolve_vars_if_possible(value); + debug!(?value); assert!( !value.has_escaping_bound_vars(), @@ -321,7 +335,11 @@ impl<'a, 'b, 'tcx> AssocTypeNormalizer<'a, 'b, 'tcx> { value ); - if !value.has_projections() { value } else { value.fold_with(self) } + if !needs_normalization(&value, self.param_env.reveal()) { + value + } else { + value.fold_with(self) + } } } @@ -341,7 +359,7 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> { } fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { - if !ty.has_projections() { + if !needs_normalization(&ty, self.param_env.reveal()) { return ty; } // We don't want to normalize associated types that occur inside of region @@ -825,7 +843,7 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>( let cache_result = infcx.inner.borrow_mut().projection_cache().try_start(cache_key); match cache_result { - Ok(()) => {} + Ok(()) => debug!("no cache"), Err(ProjectionCacheEntry::Ambiguous) => { // If we found ambiguity the last time, that means we will continue // to do so until some type in the key changes (and we know it @@ -852,6 +870,7 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>( return Err(InProgress); } Err(ProjectionCacheEntry::Recur) => { + debug!("recur cache"); return Err(InProgress); } Err(ProjectionCacheEntry::NormalizedTy(ty)) => { @@ -1058,12 +1077,11 @@ impl<'tcx> Progress<'tcx> { /// /// IMPORTANT: /// - `obligation` must be fully normalized +#[tracing::instrument(level = "info", skip(selcx))] fn project_type<'cx, 'tcx>( selcx: &mut SelectionContext<'cx, 'tcx>, obligation: &ProjectionTyObligation<'tcx>, ) -> Result, ProjectionTyError<'tcx>> { - debug!(?obligation, "project_type"); - if !selcx.tcx().recursion_limit().value_within_limit(obligation.recursion_depth) { debug!("project: overflow!"); // This should really be an immediate error, but some existing code diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs index 94539eda0f89e..d65a378b1edec 100644 --- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs @@ -6,6 +6,7 @@ use crate::infer::at::At; use crate::infer::canonical::OriginalQueryValues; use crate::infer::{InferCtxt, InferOk}; use crate::traits::error_reporting::InferCtxtExt; +use crate::traits::project::needs_normalization; use crate::traits::{Obligation, ObligationCause, PredicateObligation, Reveal}; use rustc_data_structures::sso::SsoHashMap; use rustc_data_structures::stack::ensure_sufficient_stack; @@ -49,7 +50,7 @@ impl<'cx, 'tcx> AtExt<'tcx> for At<'cx, 'tcx> { value, self.param_env, ); - if !value.has_projections() { + if !needs_normalization(&value, self.param_env.reveal()) { return Ok(Normalized { value, obligations: vec![] }); } @@ -65,7 +66,7 @@ impl<'cx, 'tcx> AtExt<'tcx> for At<'cx, 'tcx> { }; let result = value.fold_with(&mut normalizer); - debug!( + info!( "normalize::<{}>: result={:?} with {} obligations", std::any::type_name::(), result, @@ -112,7 +113,7 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> { #[instrument(level = "debug", skip(self))] fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { - if !ty.has_projections() { + if !needs_normalization(&ty, self.param_env.reveal()) { return ty; } diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index f8297ee3a0718..d7726e75010f5 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -831,7 +831,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let mut unsizing_params = GrowableBitSet::new_empty(); if tcx.features().relaxed_struct_unsize { - for arg in tail_field_ty.walk() { + for arg in tail_field_ty.walk(tcx) { if let Some(i) = maybe_unsizing_param_idx(arg) { unsizing_params.insert(i); } @@ -840,7 +840,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // Ensure none of the other fields mention the parameters used // in unsizing. for field in prefix_fields { - for arg in tcx.type_of(field.did).walk() { + for arg in tcx.type_of(field.did).walk(tcx) { if let Some(i) = maybe_unsizing_param_idx(arg) { unsizing_params.remove(i); } @@ -852,7 +852,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } else { let mut found = false; - for arg in tail_field_ty.walk() { + for arg in tail_field_ty.walk(tcx) { if let Some(i) = maybe_unsizing_param_idx(arg) { unsizing_params.insert(i); found = true; @@ -868,7 +868,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // by putting it in a query; it would only need the `DefId` as it // looks at declared field types, not anything substituted. for field in prefix_fields { - for arg in tcx.type_of(field.did).walk() { + for arg in tcx.type_of(field.did).walk(tcx) { if let Some(i) = maybe_unsizing_param_idx(arg) { if unsizing_params.contains(i) { return Err(Unimplemented); diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index f17965f6f6be6..e09d2b8adf179 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -493,7 +493,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { }, ty::PredicateKind::TypeOutlives(pred) => { - if pred.0.is_global() { + if pred.0.is_known_global() { Ok(EvaluatedToOk) } else { Ok(EvaluatedToOkModuloRegions) @@ -547,11 +547,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } - ty::PredicateKind::ConstEvaluatable(def_id, substs) => { + ty::PredicateKind::ConstEvaluatable(uv) => { match const_evaluatable::is_const_evaluatable( self.infcx, - def_id, - substs, + uv, obligation.param_env, obligation.cause.span, ) { @@ -573,10 +572,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { if let (ty::ConstKind::Unevaluated(a), ty::ConstKind::Unevaluated(b)) = (c1.val, c2.val) { - if self - .tcx() - .try_unify_abstract_consts(((a.def, a.substs), (b.def, b.substs))) - { + if self.tcx().try_unify_abstract_consts((a, b)) { return Ok(EvaluatedToOk); } } @@ -644,8 +640,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { debug!(?obligation, "evaluate_trait_predicate_recursively"); if !self.intercrate - && obligation.is_global() - && obligation.param_env.caller_bounds().iter().all(|bound| bound.needs_subst()) + && obligation.is_global(self.tcx()) + && obligation + .param_env + .caller_bounds() + .iter() + .all(|bound| bound.needs_subst(self.tcx())) { // If a param env has no global bounds, global obligations do not // depend on its particular value in order to work, so we can clear @@ -1359,7 +1359,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // the param_env so that it can be given the lowest priority. See // #50825 for the motivation for this. let is_global = - |cand: &ty::PolyTraitRef<'_>| cand.is_global() && !cand.has_late_bound_regions(); + |cand: &ty::PolyTraitRef<'_>| cand.is_known_global() && !cand.has_late_bound_regions(); // (*) Prefer `BuiltinCandidate { has_nested: false }`, `PointeeCandidate`, // and `DiscriminantKindCandidate` to anything else. @@ -1865,12 +1865,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } + #[tracing::instrument(level = "debug", skip(self))] fn match_impl( &mut self, impl_def_id: DefId, obligation: &TraitObligation<'tcx>, ) -> Result>, ()> { - debug!(?impl_def_id, ?obligation, "match_impl"); let impl_trait_ref = self.tcx().impl_trait_ref(impl_def_id).unwrap(); // Before we create the substitutions and everything, first @@ -1888,6 +1888,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let impl_trait_ref = impl_trait_ref.subst(self.tcx(), impl_substs); + debug!(?impl_trait_ref); + let Normalized { value: impl_trait_ref, obligations: mut nested_obligations } = ensure_sufficient_stack(|| { project::normalize_with_depth( @@ -1915,7 +1917,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { return Err(()); } - debug!(?impl_substs, "match_impl: success"); + debug!(?impl_substs, ?nested_obligations, "match_impl: success"); Ok(Normalized { value: impl_substs, obligations: nested_obligations }) } @@ -2068,6 +2070,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { /// impl or trait. The obligations are substituted and fully /// normalized. This is used when confirming an impl or default /// impl. + #[tracing::instrument(level = "debug", skip(self, cause, param_env))] fn impl_or_trait_obligations( &mut self, cause: ObligationCause<'tcx>, @@ -2076,7 +2079,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { def_id: DefId, // of impl or trait substs: SubstsRef<'tcx>, // for impl or trait ) -> Vec> { - debug!(?def_id, "impl_or_trait_obligations"); let tcx = self.tcx(); // To allow for one-pass evaluation of the nested obligation, @@ -2094,9 +2096,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // `$1: Copy`, so we must ensure the obligations are emitted in // that order. let predicates = tcx.predicates_of(def_id); + debug!(?predicates); assert_eq!(predicates.parent, None); let mut obligations = Vec::with_capacity(predicates.predicates.len()); for (predicate, _) in predicates.predicates { + debug!(?predicate); let predicate = normalize_with_depth_to( self, param_env, diff --git a/compiler/rustc_trait_selection/src/traits/structural_match.rs b/compiler/rustc_trait_selection/src/traits/structural_match.rs index 3d20a8d5cf336..0f1d0117ea09c 100644 --- a/compiler/rustc_trait_selection/src/traits/structural_match.rs +++ b/compiler/rustc_trait_selection/src/traits/structural_match.rs @@ -131,6 +131,9 @@ impl Search<'a, 'tcx> { impl<'a, 'tcx> TypeVisitor<'tcx> for Search<'a, 'tcx> { type BreakTy = NonStructuralMatchTy<'tcx>; + fn tcx_for_anon_const_substs(&self) -> Option> { + Some(self.tcx()) + } fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow { debug!("Search visiting ty: {:?}", ty); diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index 9ee6eeb1fd5ed..a11d70eac2a7b 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -85,6 +85,7 @@ pub fn trait_obligations<'a, 'tcx>( let mut wf = WfPredicates { infcx, param_env, body_id, span, out: vec![], recursion_depth: 0, item }; wf.compute_trait_ref(trait_ref, Elaborate::All); + debug!(obligations = ?wf.out); wf.normalize() } @@ -127,8 +128,9 @@ pub fn predicate_obligations<'a, 'tcx>( wf.compute(a.into()); wf.compute(b.into()); } - ty::PredicateKind::ConstEvaluatable(def, substs) => { - let obligations = wf.nominal_obligations(def.did, substs); + ty::PredicateKind::ConstEvaluatable(uv) => { + let substs = uv.substs(wf.tcx()); + let obligations = wf.nominal_obligations(uv.def.did, substs); wf.out.extend(obligations); for arg in substs.iter() { @@ -417,7 +419,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { /// Pushes all the predicates needed to validate that `ty` is WF into `out`. fn compute(&mut self, arg: GenericArg<'tcx>) { - let mut walker = arg.walk(); + let mut walker = arg.walk(self.tcx()); let param_env = self.param_env; let depth = self.recursion_depth; while let Some(arg) = walker.next() { @@ -430,14 +432,17 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { GenericArgKind::Const(constant) => { match constant.val { - ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted }) => { - assert!(promoted.is_none()); + ty::ConstKind::Unevaluated(uv) => { + assert!(uv.promoted.is_none()); + let substs = uv.substs(self.tcx()); - let obligations = self.nominal_obligations(def.did, substs); + let obligations = self.nominal_obligations(uv.def.did, substs); self.out.extend(obligations); - let predicate = ty::PredicateKind::ConstEvaluatable(def, substs) - .to_predicate(self.tcx()); + let predicate = ty::PredicateKind::ConstEvaluatable( + ty::Unevaluated::new(uv.def, substs), + ) + .to_predicate(self.tcx()); let cause = self.cause(traits::MiscObligation); self.out.push(traits::Obligation::with_depth( cause, diff --git a/compiler/rustc_traits/src/chalk/lowering.rs b/compiler/rustc_traits/src/chalk/lowering.rs index a838172d664c3..7efd7d34b807d 100644 --- a/compiler/rustc_traits/src/chalk/lowering.rs +++ b/compiler/rustc_traits/src/chalk/lowering.rs @@ -802,7 +802,7 @@ crate fn collect_bound_vars<'tcx, T: TypeFoldable<'tcx>>( tcx: TyCtxt<'tcx>, ty: Binder<'tcx, T>, ) -> (T, chalk_ir::VariableKinds>, BTreeMap) { - let mut bound_vars_collector = BoundVarsCollector::new(); + let mut bound_vars_collector = BoundVarsCollector::new(tcx); ty.as_ref().skip_binder().visit_with(&mut bound_vars_collector); let mut parameters = bound_vars_collector.parameters; let named_parameters: BTreeMap = bound_vars_collector @@ -832,14 +832,16 @@ crate fn collect_bound_vars<'tcx, T: TypeFoldable<'tcx>>( } crate struct BoundVarsCollector<'tcx> { + tcx: TyCtxt<'tcx>, binder_index: ty::DebruijnIndex, crate parameters: BTreeMap>>, crate named_parameters: Vec, } impl<'tcx> BoundVarsCollector<'tcx> { - crate fn new() -> Self { + crate fn new(tcx: TyCtxt<'tcx>) -> Self { BoundVarsCollector { + tcx, binder_index: ty::INNERMOST, parameters: BTreeMap::new(), named_parameters: vec![], @@ -848,6 +850,10 @@ impl<'tcx> BoundVarsCollector<'tcx> { } impl<'tcx> TypeVisitor<'tcx> for BoundVarsCollector<'tcx> { + fn tcx_for_anon_const_substs(&self) -> Option> { + Some(self.tcx) + } + fn visit_binder>( &mut self, t: &Binder<'tcx, T>, @@ -1066,6 +1072,11 @@ impl PlaceholdersCollector { } impl<'tcx> TypeVisitor<'tcx> for PlaceholdersCollector { + fn tcx_for_anon_const_substs(&self) -> Option> { + // Anon const substs do not contain placeholders by default. + None + } + fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { match t.kind() { ty::Placeholder(p) if p.universe == self.universe_index => { diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs index 469ac04e54515..c1713814e8305 100644 --- a/compiler/rustc_ty_utils/src/instance.rs +++ b/compiler/rustc_ty_utils/src/instance.rs @@ -54,6 +54,10 @@ impl<'tcx> BoundVarsCollector<'tcx> { impl<'tcx> TypeVisitor<'tcx> for BoundVarsCollector<'tcx> { type BreakTy = (); + fn tcx_for_anon_const_substs(&self) -> Option> { + // Anon const substs do not contain bound vars by default. + None + } fn visit_binder>( &mut self, t: &Binder<'tcx, T>, diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs index b0d644ae028ce..cda8f6402ea63 100644 --- a/compiler/rustc_ty_utils/src/ty.rs +++ b/compiler/rustc_ty_utils/src/ty.rs @@ -361,7 +361,7 @@ fn well_formed_types_in_env<'tcx>( // constituents are well-formed. NodeKind::InherentImpl => { let self_ty = tcx.type_of(def_id); - inputs.extend(self_ty.walk()); + inputs.extend(self_ty.walk(tcx)); } // In an fn, we assume that the arguments and all their constituents are @@ -370,7 +370,7 @@ fn well_formed_types_in_env<'tcx>( let fn_sig = tcx.fn_sig(def_id); let fn_sig = tcx.liberate_late_bound_regions(def_id, fn_sig); - inputs.extend(fn_sig.inputs().iter().flat_map(|ty| ty.walk())); + inputs.extend(fn_sig.inputs().iter().flat_map(|ty| ty.walk(tcx))); } NodeKind::Other => (), diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs index 2d102127dd9d6..c405bbe2d1f53 100644 --- a/compiler/rustc_type_ir/src/lib.rs +++ b/compiler/rustc_type_ir/src/lib.rs @@ -19,94 +19,116 @@ bitflags! { // Does this have parameters? Used to determine whether substitution is // required. /// Does this have `Param`? - const HAS_TY_PARAM = 1 << 0; + const HAS_KNOWN_TY_PARAM = 1 << 0; /// Does this have `ReEarlyBound`? - const HAS_RE_PARAM = 1 << 1; + const HAS_KNOWN_RE_PARAM = 1 << 1; /// Does this have `ConstKind::Param`? - const HAS_CT_PARAM = 1 << 2; + const HAS_KNOWN_CT_PARAM = 1 << 2; - const NEEDS_SUBST = TypeFlags::HAS_TY_PARAM.bits - | TypeFlags::HAS_RE_PARAM.bits - | TypeFlags::HAS_CT_PARAM.bits; + const KNOWN_NEEDS_SUBST = TypeFlags::HAS_KNOWN_TY_PARAM.bits + | TypeFlags::HAS_KNOWN_RE_PARAM.bits + | TypeFlags::HAS_KNOWN_CT_PARAM.bits; /// Does this have `Infer`? - const HAS_TY_INFER = 1 << 3; + const HAS_TY_INFER = 1 << 3; /// Does this have `ReVar`? - const HAS_RE_INFER = 1 << 4; + const HAS_RE_INFER = 1 << 4; /// Does this have `ConstKind::Infer`? - const HAS_CT_INFER = 1 << 5; + const HAS_CT_INFER = 1 << 5; /// Does this have inference variables? Used to determine whether /// inference is required. - const NEEDS_INFER = TypeFlags::HAS_TY_INFER.bits - | TypeFlags::HAS_RE_INFER.bits - | TypeFlags::HAS_CT_INFER.bits; + const NEEDS_INFER = TypeFlags::HAS_TY_INFER.bits + | TypeFlags::HAS_RE_INFER.bits + | TypeFlags::HAS_CT_INFER.bits; /// Does this have `Placeholder`? - const HAS_TY_PLACEHOLDER = 1 << 6; + const HAS_TY_PLACEHOLDER = 1 << 6; /// Does this have `RePlaceholder`? - const HAS_RE_PLACEHOLDER = 1 << 7; + const HAS_RE_PLACEHOLDER = 1 << 7; /// Does this have `ConstKind::Placeholder`? - const HAS_CT_PLACEHOLDER = 1 << 8; + const HAS_CT_PLACEHOLDER = 1 << 8; /// `true` if there are "names" of regions and so forth /// that are local to a particular fn/inferctxt - const HAS_FREE_LOCAL_REGIONS = 1 << 9; + const HAS_KNOWN_FREE_LOCAL_REGIONS = 1 << 9; /// `true` if there are "names" of types and regions and so forth /// that are local to a particular fn - const HAS_FREE_LOCAL_NAMES = TypeFlags::HAS_TY_PARAM.bits - | TypeFlags::HAS_CT_PARAM.bits - | TypeFlags::HAS_TY_INFER.bits - | TypeFlags::HAS_CT_INFER.bits - | TypeFlags::HAS_TY_PLACEHOLDER.bits - | TypeFlags::HAS_CT_PLACEHOLDER.bits - // We consider 'freshened' types and constants - // to depend on a particular fn. - // The freshening process throws away information, - // which can make things unsuitable for use in a global - // cache. Note that there is no 'fresh lifetime' flag - - // freshening replaces all lifetimes with `ReErased`, - // which is different from how types/const are freshened. - | TypeFlags::HAS_TY_FRESH.bits - | TypeFlags::HAS_CT_FRESH.bits - | TypeFlags::HAS_FREE_LOCAL_REGIONS.bits; + const HAS_KNOWN_FREE_LOCAL_NAMES = TypeFlags::HAS_KNOWN_TY_PARAM.bits + | TypeFlags::HAS_KNOWN_CT_PARAM.bits + | TypeFlags::HAS_TY_INFER.bits + | TypeFlags::HAS_CT_INFER.bits + | TypeFlags::HAS_TY_PLACEHOLDER.bits + | TypeFlags::HAS_CT_PLACEHOLDER.bits + // We consider 'freshened' types and constants + // to depend on a particular fn. + // The freshening process throws away information, + // which can make things unsuitable for use in a global + // cache. Note that there is no 'fresh lifetime' flag - + // freshening replaces all lifetimes with `ReErased`, + // which is different from how types/const are freshened. + | TypeFlags::HAS_TY_FRESH.bits + | TypeFlags::HAS_CT_FRESH.bits + | TypeFlags::HAS_KNOWN_FREE_LOCAL_REGIONS.bits; + + const HAS_POTENTIAL_FREE_LOCAL_NAMES = TypeFlags::HAS_KNOWN_FREE_LOCAL_NAMES.bits + | TypeFlags::HAS_UNKNOWN_DEFAULT_CONST_SUBSTS.bits; /// Does this have `Projection`? - const HAS_TY_PROJECTION = 1 << 10; + const HAS_TY_PROJECTION = 1 << 10; /// Does this have `Opaque`? - const HAS_TY_OPAQUE = 1 << 11; + const HAS_TY_OPAQUE = 1 << 11; /// Does this have `ConstKind::Unevaluated`? - const HAS_CT_PROJECTION = 1 << 12; + const HAS_CT_PROJECTION = 1 << 12; /// Could this type be normalized further? - const HAS_PROJECTION = TypeFlags::HAS_TY_PROJECTION.bits - | TypeFlags::HAS_TY_OPAQUE.bits - | TypeFlags::HAS_CT_PROJECTION.bits; + const HAS_PROJECTION = TypeFlags::HAS_TY_PROJECTION.bits + | TypeFlags::HAS_TY_OPAQUE.bits + | TypeFlags::HAS_CT_PROJECTION.bits; /// Is an error type/const reachable? - const HAS_ERROR = 1 << 13; + const HAS_ERROR = 1 << 13; /// Does this have any region that "appears free" in the type? /// Basically anything but `ReLateBound` and `ReErased`. - const HAS_FREE_REGIONS = 1 << 14; + const HAS_KNOWN_FREE_REGIONS = 1 << 14; + + const HAS_POTENTIAL_FREE_REGIONS = TypeFlags::HAS_KNOWN_FREE_REGIONS.bits + | TypeFlags::HAS_UNKNOWN_DEFAULT_CONST_SUBSTS.bits; /// Does this have any `ReLateBound` regions? Used to check /// if a global bound is safe to evaluate. - const HAS_RE_LATE_BOUND = 1 << 15; + const HAS_RE_LATE_BOUND = 1 << 15; /// Does this have any `ReErased` regions? - const HAS_RE_ERASED = 1 << 16; + const HAS_RE_ERASED = 1 << 16; /// Does this value have parameters/placeholders/inference variables which could be /// replaced later, in a way that would change the results of `impl` specialization? - const STILL_FURTHER_SPECIALIZABLE = 1 << 17; + /// + /// Note that this flag being set is not a guarantee, as it is also + /// set if there are any anon consts with unknown default substs. + const STILL_FURTHER_SPECIALIZABLE = 1 << 17; /// Does this value have `InferTy::FreshTy/FreshIntTy/FreshFloatTy`? - const HAS_TY_FRESH = 1 << 18; + const HAS_TY_FRESH = 1 << 18; /// Does this value have `InferConst::Fresh`? - const HAS_CT_FRESH = 1 << 19; + const HAS_CT_FRESH = 1 << 19; + + /// Does this value have unknown default anon const substs. + /// + /// For more details refer to... + /// FIXME(@lcnr): ask me for now, still have to write all of this. + const HAS_UNKNOWN_DEFAULT_CONST_SUBSTS = 1 << 20; + /// Flags which can be influenced by default anon const substs. + const MAY_NEED_DEFAULT_CONST_SUBSTS = TypeFlags::HAS_KNOWN_RE_PARAM.bits + | TypeFlags::HAS_KNOWN_TY_PARAM.bits + | TypeFlags::HAS_KNOWN_CT_PARAM.bits + | TypeFlags::HAS_KNOWN_FREE_LOCAL_REGIONS.bits + | TypeFlags::HAS_KNOWN_FREE_REGIONS.bits; + } } diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs index 2e42d65cce29b..75d2f336ac2c8 100644 --- a/compiler/rustc_typeck/src/astconv/mod.rs +++ b/compiler/rustc_typeck/src/astconv/mod.rs @@ -394,7 +394,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { if self.is_object && has_default { let default_ty = tcx.at(self.span).type_of(param.def_id); let self_param = tcx.types.self_param; - if default_ty.walk().any(|arg| arg == self_param.into()) { + if default_ty.walk(tcx).any(|arg| arg == self_param.into()) { // There is no suitable inference default for a type parameter // that references self, in an object type. return true; @@ -1307,7 +1307,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // A `Self` within the original bound will be substituted with a // `trait_object_dummy_self`, so check for that. let references_self = - pred.skip_binder().ty.walk().any(|arg| arg == dummy_self.into()); + pred.skip_binder().ty.walk(tcx).any(|arg| arg == dummy_self.into()); // If the projection output contains `Self`, force the user to // elaborate it explicitly to avoid a lot of complexity. @@ -2149,7 +2149,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { self.prohibit_generics(path.segments); // Try to evaluate any array length constants. let normalized_ty = self.normalize_ty(span, tcx.at(span).type_of(def_id)); - if forbid_generic && normalized_ty.needs_subst() { + if forbid_generic && normalized_ty.needs_subst(tcx) { let mut err = tcx.sess.struct_span_err( path.span, "generic `Self` types are currently not permitted in anonymous constants", diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs index 496721e6f7634..a8e506a46a91f 100644 --- a/compiler/rustc_typeck/src/check/check.rs +++ b/compiler/rustc_typeck/src/check/check.rs @@ -531,14 +531,17 @@ pub(super) fn check_opaque_for_inheriting_lifetimes( debug!(?item, ?span); struct FoundParentLifetime; - struct FindParentLifetimeVisitor<'tcx>(&'tcx ty::Generics); + struct FindParentLifetimeVisitor<'tcx>(TyCtxt<'tcx>, &'tcx ty::Generics); impl<'tcx> ty::fold::TypeVisitor<'tcx> for FindParentLifetimeVisitor<'tcx> { type BreakTy = FoundParentLifetime; + fn tcx_for_anon_const_substs(&self) -> Option> { + Some(self.0) + } fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow { debug!("FindParentLifetimeVisitor: r={:?}", r); if let RegionKind::ReEarlyBound(ty::EarlyBoundRegion { index, .. }) = r { - if *index < self.0.parent_count as u32 { + if *index < self.1.parent_count as u32 { return ControlFlow::Break(FoundParentLifetime); } else { return ControlFlow::CONTINUE; @@ -560,21 +563,24 @@ pub(super) fn check_opaque_for_inheriting_lifetimes( } struct ProhibitOpaqueVisitor<'tcx> { + tcx: TyCtxt<'tcx>, opaque_identity_ty: Ty<'tcx>, generics: &'tcx ty::Generics, - tcx: TyCtxt<'tcx>, selftys: Vec<(Span, Option)>, } impl<'tcx> ty::fold::TypeVisitor<'tcx> for ProhibitOpaqueVisitor<'tcx> { type BreakTy = Ty<'tcx>; + fn tcx_for_anon_const_substs(&self) -> Option> { + Some(self.tcx) + } fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { debug!("check_opaque_for_inheriting_lifetimes: (visit_ty) t={:?}", t); if t == self.opaque_identity_ty { ControlFlow::CONTINUE } else { - t.super_visit_with(&mut FindParentLifetimeVisitor(self.generics)) + t.super_visit_with(&mut FindParentLifetimeVisitor(self.tcx, self.generics)) .map_break(|FoundParentLifetime| t) } } @@ -1519,7 +1525,7 @@ pub(super) fn check_type_params_are_used<'tcx>( return; } - for leaf in ty.walk() { + for leaf in ty.walk(tcx) { if let GenericArgKind::Type(leaf_ty) = leaf.unpack() { if let ty::Param(param) = leaf_ty.kind() { debug!("found use of ty param {:?}", param); @@ -1621,8 +1627,12 @@ fn opaque_type_cycle_error(tcx: TyCtxt<'tcx>, def_id: LocalDefId, span: Span) { .filter_map(|e| typeck_results.node_type_opt(e.hir_id).map(|t| (e.span, t))) .filter(|(_, ty)| !matches!(ty.kind(), ty::Never)) { - struct VisitTypes(Vec); - impl<'tcx> ty::fold::TypeVisitor<'tcx> for VisitTypes { + struct OpaqueTypeCollector(Vec); + impl<'tcx> ty::fold::TypeVisitor<'tcx> for OpaqueTypeCollector { + fn tcx_for_anon_const_substs(&self) -> Option> { + // Default anon const substs cannot contain opaque types. + None + } fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { match *t.kind() { ty::Opaque(def, _) => { @@ -1633,7 +1643,7 @@ fn opaque_type_cycle_error(tcx: TyCtxt<'tcx>, def_id: LocalDefId, span: Span) { } } } - let mut visitor = VisitTypes(vec![]); + let mut visitor = OpaqueTypeCollector(vec![]); ty.visit_with(&mut visitor); for def_id in visitor.0 { let ty_span = tcx.def_span(def_id); diff --git a/compiler/rustc_typeck/src/check/compare_method.rs b/compiler/rustc_typeck/src/check/compare_method.rs index 12d0c14a3d51a..d35868881558e 100644 --- a/compiler/rustc_typeck/src/check/compare_method.rs +++ b/compiler/rustc_typeck/src/check/compare_method.rs @@ -66,6 +66,10 @@ crate fn compare_impl_method<'tcx>( { return; } + + if let Err(ErrorReported) = compare_const_param_types(tcx, impl_m, trait_m, trait_item_span) { + return; + } } fn compare_predicate_entailment<'tcx>( @@ -929,6 +933,68 @@ fn compare_synthetic_generics<'tcx>( if error_found { Err(ErrorReported) } else { Ok(()) } } +fn compare_const_param_types<'tcx>( + tcx: TyCtxt<'tcx>, + impl_m: &ty::AssocItem, + trait_m: &ty::AssocItem, + trait_item_span: Option, +) -> Result<(), ErrorReported> { + let const_params_of = |def_id| { + tcx.generics_of(def_id).params.iter().filter_map(|param| match param.kind { + GenericParamDefKind::Const { .. } => Some(param.def_id), + _ => None, + }) + }; + let const_params_impl = const_params_of(impl_m.def_id); + let const_params_trait = const_params_of(trait_m.def_id); + + for (const_param_impl, const_param_trait) in iter::zip(const_params_impl, const_params_trait) { + let impl_ty = tcx.type_of(const_param_impl); + let trait_ty = tcx.type_of(const_param_trait); + if impl_ty != trait_ty { + let (impl_span, impl_ident) = match tcx.hir().get_if_local(const_param_impl) { + Some(hir::Node::GenericParam(hir::GenericParam { span, name, .. })) => ( + span, + match name { + hir::ParamName::Plain(ident) => Some(ident), + _ => None, + }, + ), + other => bug!( + "expected GenericParam, found {:?}", + other.map_or_else(|| "nothing".to_string(), |n| format!("{:?}", n)) + ), + }; + let trait_span = match tcx.hir().get_if_local(const_param_trait) { + Some(hir::Node::GenericParam(hir::GenericParam { span, .. })) => Some(span), + _ => None, + }; + let mut err = struct_span_err!( + tcx.sess, + *impl_span, + E0053, + "method `{}` has an incompatible const parameter type for trait", + trait_m.ident + ); + err.span_note( + trait_span.map_or_else(|| trait_item_span.unwrap_or(*impl_span), |span| *span), + &format!( + "the const parameter{} has type `{}`, but the declaration \ + in trait `{}` has type `{}`", + &impl_ident.map_or_else(|| "".to_string(), |ident| format!(" `{}`", ident)), + impl_ty, + tcx.def_path_str(trait_m.def_id), + trait_ty + ), + ); + err.emit(); + return Err(ErrorReported); + } + } + + Ok(()) +} + crate fn compare_const_impl<'tcx>( tcx: TyCtxt<'tcx>, impl_c: &ty::AssocItem, diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs index e045c30e0de6b..275c955b15231 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs @@ -239,7 +239,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.tag(), ); - if Self::can_contain_user_lifetime_bounds((substs, user_self_ty)) { + if self.can_contain_user_lifetime_bounds((substs, user_self_ty)) { let canonicalized = self.infcx.canonicalize_user_type_annotation(UserType::TypeOf( def_id, UserSubsts { substs, user_self_ty }, @@ -513,7 +513,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let ty = self.to_ty(ast_ty); debug!("to_ty_saving_user_provided_ty: ty={:?}", ty); - if Self::can_contain_user_lifetime_bounds(ty) { + if self.can_contain_user_lifetime_bounds(ty) { let c_ty = self.infcx.canonicalize_response(UserType::Ty(ty)); debug!("to_ty_saving_user_provided_ty: c_ty={:?}", c_ty); self.typeck_results.borrow_mut().user_provided_types_mut().insert(ast_ty.hir_id, c_ty); @@ -558,11 +558,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // reader, although I have my doubts). Also pass in types with inference // types, because they may be repeated. Other sorts of things are already // sufficiently enforced with erased regions. =) - fn can_contain_user_lifetime_bounds(t: T) -> bool + fn can_contain_user_lifetime_bounds(&self, t: T) -> bool where T: TypeFoldable<'tcx>, { - t.has_free_regions() || t.has_projections() || t.has_infer_types() + t.has_free_regions(self.tcx) || t.has_projections() || t.has_infer_types() } pub fn node_ty(&self, id: hir::HirId) -> Ty<'tcx> { @@ -1578,6 +1578,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } /// Add all the obligations that are required, substituting and normalized appropriately. + #[tracing::instrument(level = "debug", skip(self, span, def_id, substs))] fn add_required_obligations(&self, span: Span, def_id: DefId, substs: &SubstsRef<'tcx>) { let (bounds, spans) = self.instantiate_bounds(span, def_id, &substs); diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs index f65cc429fbd48..b5e62ecc2a062 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs @@ -936,7 +936,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let ty = self.resolve_vars_if_possible(ty); // We walk the argument type because the argument's type could have // been `Option`, but the `FulfillmentError` references `T`. - if ty.walk().any(|arg| arg == predicate.self_ty().into()) { + if ty.walk(self.tcx).any(|arg| arg == predicate.self_ty().into()) { Some(i) } else { None diff --git a/compiler/rustc_typeck/src/check/inherited.rs b/compiler/rustc_typeck/src/check/inherited.rs index 237861f1dd248..7e43e36fe55c6 100644 --- a/compiler/rustc_typeck/src/check/inherited.rs +++ b/compiler/rustc_typeck/src/check/inherited.rs @@ -179,6 +179,7 @@ impl Inherited<'a, 'tcx> { T: TypeFoldable<'tcx>, { let ok = self.partially_normalize_associated_types_in(cause, param_env, value); + debug!(?ok); self.register_infer_ok_obligations(ok) } } diff --git a/compiler/rustc_typeck/src/check/op.rs b/compiler/rustc_typeck/src/check/op.rs index 963436d05d8ef..9b495fba1975d 100644 --- a/compiler/rustc_typeck/src/check/op.rs +++ b/compiler/rustc_typeck/src/check/op.rs @@ -428,7 +428,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } if let Some(missing_trait) = missing_trait { - let mut visitor = TypeParamVisitor(vec![]); + let mut visitor = TypeParamVisitor(self.tcx, vec![]); visitor.visit_ty(lhs_ty); if op.node == hir::BinOpKind::Add @@ -439,7 +439,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // This has nothing here because it means we did string // concatenation (e.g., "Hello " + "World!"). This means // we don't want the note in the else clause to be emitted - } else if let [ty] = &visitor.0[..] { + } else if let [ty] = &visitor.1[..] { if let ty::Param(p) = *ty.kind() { // Check if the method would be found if the type param wasn't // involved. If so, it means that adding a trait bound to the param is @@ -1003,12 +1003,15 @@ fn suggest_constraining_param( } } -struct TypeParamVisitor<'tcx>(Vec>); +struct TypeParamVisitor<'tcx>(TyCtxt<'tcx>, Vec>); impl<'tcx> TypeVisitor<'tcx> for TypeParamVisitor<'tcx> { + fn tcx_for_anon_const_substs(&self) -> Option> { + Some(self.0) + } fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow { if let ty::Param(_) = ty.kind() { - self.0.push(ty); + self.1.push(ty); } ty.super_visit_with(self) } diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs index bff391eb2d7a8..530ff6e460c97 100644 --- a/compiler/rustc_typeck/src/check/wfcheck.rs +++ b/compiler/rustc_typeck/src/check/wfcheck.rs @@ -379,14 +379,13 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) { } } +#[tracing::instrument(level = "debug", skip(tcx, span, sig_if_method))] fn check_associated_item( tcx: TyCtxt<'_>, item_id: hir::HirId, span: Span, sig_if_method: Option<&hir::FnSig<'_>>, ) { - debug!("check_associated_item: {:?}", item_id); - let code = ObligationCauseCode::WellFormed(Some(item_id)); for_id(tcx, item_id, span).with_fcx(|fcx| { let item = fcx.tcx.associated_item(fcx.tcx.hir().local_def_id(item_id)); @@ -532,10 +531,10 @@ fn check_type_defn<'tcx, F>( fcx.register_predicate(traits::Obligation::new( cause, fcx.param_env, - ty::PredicateKind::ConstEvaluatable( + ty::PredicateKind::ConstEvaluatable(ty::Unevaluated::new( ty::WithOptConstParam::unknown(discr_def_id.to_def_id()), discr_substs, - ) + )) .to_predicate(tcx), )); } @@ -650,14 +649,13 @@ fn check_item_type(tcx: TyCtxt<'_>, item_id: hir::HirId, ty_span: Span, allow_fo }); } +#[tracing::instrument(level = "debug", skip(tcx, ast_self_ty, ast_trait_ref))] fn check_impl<'tcx>( tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>, ast_self_ty: &hir::Ty<'_>, ast_trait_ref: &Option>, ) { - debug!("check_impl: {:?}", item); - for_item(tcx, item).with_fcx(|fcx| { match *ast_trait_ref { Some(ref ast_trait_ref) => { @@ -675,6 +673,7 @@ fn check_impl<'tcx>( ast_trait_ref.path.span, Some(item), ); + debug!(?obligations); for obligation in obligations { fcx.register_predicate(obligation); } @@ -731,7 +730,7 @@ fn check_where_clauses<'tcx, 'fcx>( // Ignore dependent defaults -- that is, where the default of one type // parameter includes another (e.g., ``). In those cases, we can't // be sure if it will error or not as user might always specify the other. - if !ty.needs_subst() { + if !ty.needs_subst(tcx) { fcx.register_wf_obligation( ty.into(), tcx.def_span(param.def_id), @@ -747,7 +746,7 @@ fn check_where_clauses<'tcx, 'fcx>( // for `struct Foo` // we should eagerly error. let default_ct = tcx.const_param_default(param.def_id); - if !default_ct.needs_subst() { + if !default_ct.needs_subst(tcx) { fcx.register_wf_obligation( default_ct.into(), tcx.def_span(param.def_id), @@ -781,7 +780,7 @@ fn check_where_clauses<'tcx, 'fcx>( if is_our_default(param) { let default_ty = tcx.type_of(param.def_id); // ... and it's not a dependent default, ... - if !default_ty.needs_subst() { + if !default_ty.needs_subst(tcx) { // ... then substitute it with the default. return default_ty.into(); } @@ -794,7 +793,7 @@ fn check_where_clauses<'tcx, 'fcx>( if is_our_default(param) { let default_ct = tcx.const_param_default(param.def_id); // ... and it's not a dependent default, ... - if !default_ct.needs_subst() { + if !default_ct.needs_subst(tcx) { // ... then substitute it with the default. return default_ct.into(); } @@ -810,12 +809,15 @@ fn check_where_clauses<'tcx, 'fcx>( .predicates .iter() .flat_map(|&(pred, sp)| { - #[derive(Default)] - struct CountParams { + struct CountParams<'tcx> { + tcx: TyCtxt<'tcx>, params: FxHashSet, } - impl<'tcx> ty::fold::TypeVisitor<'tcx> for CountParams { + impl<'tcx> ty::fold::TypeVisitor<'tcx> for CountParams<'tcx> { type BreakTy = (); + fn tcx_for_anon_const_substs(&self) -> Option> { + Some(self.tcx) + } fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { if let ty::Param(param) = t.kind() { @@ -835,12 +837,12 @@ fn check_where_clauses<'tcx, 'fcx>( c.super_visit_with(self) } } - let mut param_count = CountParams::default(); + let mut param_count = CountParams { tcx: fcx.tcx, params: FxHashSet::default() }; let has_region = pred.visit_with(&mut param_count).is_break(); let substituted_pred = pred.subst(tcx, substs); // Don't check non-defaulted params, dependent defaults (including lifetimes) // or preds with multiple params. - if substituted_pred.has_param_types_or_consts() + if substituted_pred.has_param_types_or_consts(tcx) || param_count.params.len() > 1 || has_region { @@ -1327,7 +1329,7 @@ fn check_false_global_bounds(fcx: &FnCtxt<'_, '_>, span: Span, id: hir::HirId) { for obligation in implied_obligations { let pred = obligation.predicate; // Match the existing behavior. - if pred.is_global() && !pred.has_late_bound_regions() { + if pred.is_global(fcx.tcx) && !pred.has_late_bound_regions() { let pred = fcx.normalize_associated_types_in(span, pred); let obligation = traits::Obligation::new( traits::ObligationCause::new(span, id, traits::TrivialBound), diff --git a/compiler/rustc_typeck/src/check/writeback.rs b/compiler/rustc_typeck/src/check/writeback.rs index 0aa059b7de80f..deb2f147c5451 100644 --- a/compiler/rustc_typeck/src/check/writeback.rs +++ b/compiler/rustc_typeck/src/check/writeback.rs @@ -130,7 +130,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { fn write_ty_to_typeck_results(&mut self, hir_id: hir::HirId, ty: Ty<'tcx>) { debug!("write_ty_to_typeck_results({:?}, {:?})", hir_id, ty); - assert!(!ty.needs_infer() && !ty.has_placeholders() && !ty.has_free_regions()); + assert!(!ty.needs_infer() && !ty.has_placeholders() && !ty.has_free_regions(self.tcx())); self.typeck_results.node_types_mut().insert(hir_id, ty); } diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index 506ca98b96026..d39c17e87312f 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -71,6 +71,7 @@ fn collect_mod_item_types(tcx: TyCtxt<'_>, module_def_id: LocalDefId) { pub fn provide(providers: &mut Providers) { *providers = Providers { opt_const_param_of: type_of::opt_const_param_of, + default_anon_const_substs: type_of::default_anon_const_substs, type_of: type_of::type_of, item_bounds: item_bounds::item_bounds, explicit_item_bounds: item_bounds::explicit_item_bounds, @@ -2269,7 +2270,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP tcx, &mut predicates, trait_ref, - &mut cgp::parameters_for_impl(self_ty, trait_ref), + &mut cgp::parameters_for_impl(tcx, self_ty, trait_ref), ); } @@ -2303,10 +2304,8 @@ fn const_evaluatable_predicates_of<'tcx>( if let ty::ConstKind::Unevaluated(uv) = ct.val { assert_eq!(uv.promoted, None); let span = self.tcx.hir().span(c.hir_id); - self.preds.insert(( - ty::PredicateKind::ConstEvaluatable(uv.def, uv.substs).to_predicate(self.tcx), - span, - )); + self.preds + .insert((ty::PredicateKind::ConstEvaluatable(uv).to_predicate(self.tcx), span)); } } diff --git a/compiler/rustc_typeck/src/collect/type_of.rs b/compiler/rustc_typeck/src/collect/type_of.rs index 7b0002914eca8..d4046d47ffedb 100644 --- a/compiler/rustc_typeck/src/collect/type_of.rs +++ b/compiler/rustc_typeck/src/collect/type_of.rs @@ -7,7 +7,7 @@ use rustc_hir::intravisit; use rustc_hir::intravisit::Visitor; use rustc_hir::{HirId, Node}; use rustc_middle::hir::map::Map; -use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts}; +use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts, SubstsRef}; use rustc_middle::ty::util::IntTypeExt; use rustc_middle::ty::{self, DefIdTree, Ty, TyCtxt, TypeFoldable, TypeFolder}; use rustc_span::symbol::Ident; @@ -268,6 +268,24 @@ fn get_path_containing_arg_in_pat<'hir>( arg_path } +pub(super) fn default_anon_const_substs(tcx: TyCtxt<'_>, def_id: DefId) -> SubstsRef<'_> { + let generics = tcx.generics_of(def_id); + if let Some(parent) = generics.parent { + let _cycle_check = tcx.predicates_of(parent); + } + + let substs = InternalSubsts::identity_for_item(tcx, def_id); + // We only expect the following lifetimes, types and constants as default substs. + // + // Getting this wrong can lead to ICE and unsoundness, so we assert it here. + for arg in substs.iter().flat_map(|s| s.walk(tcx)) { + let allowed_flags = ty::TypeFlags::MAY_NEED_DEFAULT_CONST_SUBSTS + | ty::TypeFlags::STILL_FURTHER_SPECIALIZABLE; + assert!(!arg.has_type_flags(!allowed_flags)); + } + substs +} + pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> { let def_id = def_id.expect_local(); use rustc_hir::*; diff --git a/compiler/rustc_typeck/src/constrained_generic_params.rs b/compiler/rustc_typeck/src/constrained_generic_params.rs index 529de1a287484..9b6f0be47caf5 100644 --- a/compiler/rustc_typeck/src/constrained_generic_params.rs +++ b/compiler/rustc_typeck/src/constrained_generic_params.rs @@ -27,12 +27,13 @@ impl From for Parameter { /// Returns the set of parameters constrained by the impl header. pub fn parameters_for_impl<'tcx>( + tcx: TyCtxt<'tcx>, impl_self_ty: Ty<'tcx>, impl_trait_ref: Option>, ) -> FxHashSet { let vec = match impl_trait_ref { - Some(tr) => parameters_for(&tr, false), - None => parameters_for(&impl_self_ty, false), + Some(tr) => parameters_for(tcx, &tr, false), + None => parameters_for(tcx, &impl_self_ty, false), }; vec.into_iter().collect() } @@ -43,20 +44,26 @@ pub fn parameters_for_impl<'tcx>( /// of parameters whose values are needed in order to constrain `ty` - these /// differ, with the latter being a superset, in the presence of projections. pub fn parameters_for<'tcx>( + tcx: TyCtxt<'tcx>, t: &impl TypeFoldable<'tcx>, include_nonconstraining: bool, ) -> Vec { - let mut collector = ParameterCollector { parameters: vec![], include_nonconstraining }; + let mut collector = ParameterCollector { tcx, parameters: vec![], include_nonconstraining }; t.visit_with(&mut collector); collector.parameters } -struct ParameterCollector { +struct ParameterCollector<'tcx> { + tcx: TyCtxt<'tcx>, parameters: Vec, include_nonconstraining: bool, } -impl<'tcx> TypeVisitor<'tcx> for ParameterCollector { +impl<'tcx> TypeVisitor<'tcx> for ParameterCollector<'tcx> { + fn tcx_for_anon_const_substs(&self) -> Option> { + Some(self.tcx) + } + fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { match *t.kind() { ty::Projection(..) | ty::Opaque(..) if !self.include_nonconstraining => { @@ -198,12 +205,12 @@ pub fn setup_constraining_predicates<'tcx>( // `<::Baz as Iterator>::Output = ::Output` // Then the projection only applies if `T` is known, but it still // does not determine `U`. - let inputs = parameters_for(&projection.projection_ty, true); + let inputs = parameters_for(tcx, &projection.projection_ty, true); let relies_only_on_inputs = inputs.iter().all(|p| input_parameters.contains(&p)); if !relies_only_on_inputs { continue; } - input_parameters.extend(parameters_for(&projection.ty, false)); + input_parameters.extend(parameters_for(tcx, &projection.ty, false)); } else { continue; } diff --git a/compiler/rustc_typeck/src/impl_wf_check.rs b/compiler/rustc_typeck/src/impl_wf_check.rs index 1240946860573..194c4efdbb058 100644 --- a/compiler/rustc_typeck/src/impl_wf_check.rs +++ b/compiler/rustc_typeck/src/impl_wf_check.rs @@ -119,7 +119,7 @@ fn enforce_impl_params_are_constrained( let impl_predicates = tcx.predicates_of(impl_def_id); let impl_trait_ref = tcx.impl_trait_ref(impl_def_id); - let mut input_parameters = cgp::parameters_for_impl(impl_self_ty, impl_trait_ref); + let mut input_parameters = cgp::parameters_for_impl(tcx, impl_self_ty, impl_trait_ref); cgp::identify_constrained_generic_params( tcx, impl_predicates, @@ -136,7 +136,7 @@ fn enforce_impl_params_are_constrained( match item.kind { ty::AssocKind::Type => { if item.defaultness.has_value() { - cgp::parameters_for(&tcx.type_of(def_id), true) + cgp::parameters_for(tcx, &tcx.type_of(def_id), true) } else { Vec::new() } diff --git a/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs b/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs index 505d9a59d9c2f..5c3665d19e222 100644 --- a/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs +++ b/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs @@ -207,15 +207,15 @@ fn unconstrained_parent_impl_substs<'tcx>( continue; } - unconstrained_parameters.extend(cgp::parameters_for(&projection_ty, true)); + unconstrained_parameters.extend(cgp::parameters_for(tcx, &projection_ty, true)); - for param in cgp::parameters_for(&projected_ty, false) { + for param in cgp::parameters_for(tcx, &projected_ty, false) { if !unconstrained_parameters.contains(¶m) { constrained_params.insert(param.0); } } - unconstrained_parameters.extend(cgp::parameters_for(&projected_ty, true)); + unconstrained_parameters.extend(cgp::parameters_for(tcx, &projected_ty, true)); } } @@ -249,7 +249,7 @@ fn check_duplicate_params<'tcx>( parent_substs: &Vec>, span: Span, ) { - let mut base_params = cgp::parameters_for(parent_substs, true); + let mut base_params = cgp::parameters_for(tcx, parent_substs, true); base_params.sort_by_key(|param| param.0); if let (_, [duplicate, ..]) = base_params.partition_dedup() { let param = impl1_substs[duplicate.0 as usize]; @@ -363,7 +363,7 @@ fn check_specialization_on<'tcx>(tcx: TyCtxt<'tcx>, predicate: ty::Predicate<'tc match predicate.kind().skip_binder() { // Global predicates are either always true or always false, so we // are fine to specialize on. - _ if predicate.is_global() => (), + _ if predicate.is_global(tcx) => (), // We allow specializing on explicitly marked traits with no associated // items. ty::PredicateKind::Trait(pred, hir::Constness::NotConst) => { diff --git a/compiler/rustc_typeck/src/outlives/implicit_infer.rs b/compiler/rustc_typeck/src/outlives/implicit_infer.rs index 6e6ecf6a22b51..f3f22cb05670c 100644 --- a/compiler/rustc_typeck/src/outlives/implicit_infer.rs +++ b/compiler/rustc_typeck/src/outlives/implicit_infer.rs @@ -114,7 +114,12 @@ fn insert_required_predicates_to_be_wf<'tcx>( required_predicates: &mut RequiredPredicates<'tcx>, explicit_map: &mut ExplicitPredicatesMap<'tcx>, ) { - for arg in field_ty.walk() { + // We must not look into the default substs of consts + // as computing those depends on the results of `predicates_of`. + // + // Luckily the only types contained in default substs are type + // parameters which don't matter here. + for arg in field_ty.walk_ignoring_default_const_substs() { let ty = match arg.unpack() { GenericArgKind::Type(ty) => ty, @@ -306,7 +311,7 @@ pub fn check_explicit_predicates<'tcx>( // 'b`. if let Some(self_ty) = ignored_self_ty { if let GenericArgKind::Type(ty) = outlives_predicate.0.unpack() { - if ty.walk().any(|arg| arg == self_ty.into()) { + if ty.walk(tcx).any(|arg| arg == self_ty.into()) { debug!("skipping self ty = {:?}", &ty); continue; } diff --git a/library/alloc/src/borrow.rs b/library/alloc/src/borrow.rs index 9d61b3684b82c..482a497201de6 100644 --- a/library/alloc/src/borrow.rs +++ b/library/alloc/src/borrow.rs @@ -177,6 +177,7 @@ where /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(not(test), rustc_diagnostic_item = "Cow")] pub enum Cow<'a, B: ?Sized + 'a> where B: ToOwned, diff --git a/library/alloc/src/collections/btree/map/entry.rs b/library/alloc/src/collections/btree/map/entry.rs index 6b30d95977395..5fec8dc2d1334 100644 --- a/library/alloc/src/collections/btree/map/entry.rs +++ b/library/alloc/src/collections/btree/map/entry.rs @@ -14,6 +14,7 @@ use Entry::*; /// /// [`entry`]: BTreeMap::entry #[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(not(test), rustc_diagnostic_item = "BTreeEntry")] pub enum Entry<'a, K: 'a, V: 'a> { /// A vacant entry. #[stable(feature = "rust1", since = "1.0.0")] diff --git a/library/core/src/any.rs b/library/core/src/any.rs index 5e1725cfc7a63..19652106b3d01 100644 --- a/library/core/src/any.rs +++ b/library/core/src/any.rs @@ -108,6 +108,7 @@ use crate::intrinsics; // unsafe traits and unsafe methods (i.e., `type_id` would still be safe to call, // but we would likely want to indicate as such in documentation). #[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(not(test), rustc_diagnostic_item = "Any")] pub trait Any: 'static { /// Gets the `TypeId` of `self`. /// diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs index 879deed3bed5e..79610bb409d37 100644 --- a/library/core/src/cmp.rs +++ b/library/core/src/cmp.rs @@ -1104,6 +1104,7 @@ pub macro PartialOrd($item:item) { #[inline] #[must_use] #[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(not(test), rustc_diagnostic_item = "cmp_min")] pub fn min(v1: T, v2: T) -> T { v1.min(v2) } @@ -1166,6 +1167,7 @@ pub fn min_by_key K, K: Ord>(v1: T, v2: T, mut f: F) -> T { #[inline] #[must_use] #[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(not(test), rustc_diagnostic_item = "cmp_max")] pub fn max(v1: T, v2: T) -> T { v1.max(v2) } diff --git a/library/core/src/convert/mod.rs b/library/core/src/convert/mod.rs index 65af8508a6839..1e512af48051e 100644 --- a/library/core/src/convert/mod.rs +++ b/library/core/src/convert/mod.rs @@ -152,6 +152,7 @@ pub const fn identity(x: T) -> T { /// is_hello(s); /// ``` #[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(not(test), rustc_diagnostic_item = "AsRef")] pub trait AsRef { /// Performs the conversion. #[stable(feature = "rust1", since = "1.0.0")] @@ -193,6 +194,7 @@ pub trait AsRef { /// /// [`Box`]: ../../std/boxed/struct.Box.html #[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(not(test), rustc_diagnostic_item = "AsMut")] pub trait AsMut { /// Performs the conversion. #[stable(feature = "rust1", since = "1.0.0")] diff --git a/library/core/src/iter/sources/repeat.rs b/library/core/src/iter/sources/repeat.rs index a9478041c69c4..733142ed01103 100644 --- a/library/core/src/iter/sources/repeat.rs +++ b/library/core/src/iter/sources/repeat.rs @@ -51,6 +51,7 @@ use crate::iter::{FusedIterator, TrustedLen}; /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(not(test), rustc_diagnostic_item = "iter_repeat")] pub fn repeat(elt: T) -> Repeat { Repeat { element: elt } } diff --git a/library/core/src/iter/traits/double_ended.rs b/library/core/src/iter/traits/double_ended.rs index 6d3ab788e5f48..9a9cf20077096 100644 --- a/library/core/src/iter/traits/double_ended.rs +++ b/library/core/src/iter/traits/double_ended.rs @@ -36,6 +36,7 @@ use crate::ops::{ControlFlow, Try}; /// assert_eq!(None, iter.next_back()); /// ``` #[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(not(test), rustc_diagnostic_item = "DoubleEndedIterator")] pub trait DoubleEndedIterator: Iterator { /// Removes and returns an element from the end of the iterator. /// diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs index 5bf47c3951da2..2c75de39ffa2f 100644 --- a/library/core/src/mem/mod.rs +++ b/library/core/src/mem/mod.rs @@ -140,6 +140,7 @@ pub use crate::intrinsics::transmute; #[inline] #[rustc_const_stable(feature = "const_forget", since = "1.46.0")] #[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(not(test), rustc_diagnostic_item = "mem_forget")] pub const fn forget(t: T) { let _ = ManuallyDrop::new(t); } @@ -298,6 +299,7 @@ pub fn forget_unsized(t: T) { #[stable(feature = "rust1", since = "1.0.0")] #[rustc_promotable] #[rustc_const_stable(feature = "const_size_of", since = "1.24.0")] +#[cfg_attr(not(test), rustc_diagnostic_item = "mem_size_of")] pub const fn size_of() -> usize { intrinsics::size_of::() } @@ -324,6 +326,7 @@ pub const fn size_of() -> usize { #[inline] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_unstable(feature = "const_size_of_val", issue = "46571")] +#[cfg_attr(not(test), rustc_diagnostic_item = "mem_size_of_val")] pub const fn size_of_val(val: &T) -> usize { // SAFETY: `val` is a reference, so it's a valid raw pointer unsafe { intrinsics::size_of_val(val) } @@ -814,6 +817,7 @@ pub fn take(dest: &mut T) -> T { #[stable(feature = "rust1", since = "1.0.0")] #[must_use = "if you don't need the old value, you can just assign the new value directly"] #[rustc_const_unstable(feature = "const_replace", issue = "83164")] +#[cfg_attr(not(test), rustc_diagnostic_item = "mem_replace")] pub const fn replace(dest: &mut T, src: T) -> T { // SAFETY: We read from `dest` but directly write `src` into it afterwards, // such that the old value is not duplicated. Nothing is dropped and @@ -888,6 +892,7 @@ pub const fn replace(dest: &mut T, src: T) -> T { /// [`RefCell`]: crate::cell::RefCell #[inline] #[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(not(test), rustc_diagnostic_item = "mem_drop")] pub fn drop(_x: T) {} /// Interprets `src` as having type `&U`, and then reads `src` without moving @@ -1015,6 +1020,7 @@ impl fmt::Debug for Discriminant { /// ``` #[stable(feature = "discriminant_value", since = "1.21.0")] #[rustc_const_unstable(feature = "const_discriminant", issue = "69821")] +#[cfg_attr(not(test), rustc_diagnostic_item = "mem_discriminant")] pub const fn discriminant(v: &T) -> Discriminant { Discriminant(intrinsics::discriminant_value(v)) } diff --git a/library/core/src/option.rs b/library/core/src/option.rs index b7af3ea8c1af4..8057ff0759107 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -356,7 +356,7 @@ //! // must have the same concrete type. //! fn make_iter(do_insert: bool) -> impl Iterator { //! // Explicit returns to illustrate return types not matching -//! match x { +//! match do_insert { //! true => return (0..4).chain(once(42)).chain(4..8), //! false => return (0..4).chain(empty()).chain(4..8), //! } @@ -1179,6 +1179,7 @@ impl Option { /// *val = 3; /// assert_eq!(opt.unwrap(), 3); /// ``` + #[must_use = "if you intended to set a value, consider assignment instead"] #[inline] #[stable(feature = "option_insert", since = "1.53.0")] pub fn insert(&mut self, value: T) -> &mut T { diff --git a/library/core/src/time.rs b/library/core/src/time.rs index 92a4e60391894..2d8a1cb1ab016 100644 --- a/library/core/src/time.rs +++ b/library/core/src/time.rs @@ -61,6 +61,7 @@ const MICROS_PER_SEC: u64 = 1_000_000; /// crate to do so. #[stable(feature = "duration", since = "1.3.0")] #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)] +#[cfg_attr(not(test), rustc_diagnostic_item = "Duration")] pub struct Duration { secs: u64, nanos: u32, // Always 0 <= nanos < NANOS_PER_SEC diff --git a/library/std/src/collections/hash/map.rs b/library/std/src/collections/hash/map.rs index d7cb8a556367c..fac285c96f00d 100644 --- a/library/std/src/collections/hash/map.rs +++ b/library/std/src/collections/hash/map.rs @@ -1829,6 +1829,7 @@ impl Debug for RawEntryBuilder<'_, K, V, S> { /// /// [`entry`]: HashMap::entry #[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(not(test), rustc_diagnostic_item = "HashMapEntry")] pub enum Entry<'a, K: 'a, V: 'a> { /// An occupied entry. #[stable(feature = "rust1", since = "1.0.0")] diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs index fb928ea55985f..bbe1ab40537f2 100644 --- a/library/std/src/fs.rs +++ b/library/std/src/fs.rs @@ -88,6 +88,7 @@ use crate::time::SystemTime; /// [`BufReader`]: io::BufReader /// [`sync_all`]: File::sync_all #[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(not(test), rustc_diagnostic_item = "File")] pub struct File { inner: fs_imp::File, } @@ -183,12 +184,14 @@ pub struct Permissions(fs_imp::FilePermissions); /// It is returned by [`Metadata::file_type`] method. #[stable(feature = "file_type", since = "1.1.0")] #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] +#[cfg_attr(not(test), rustc_diagnostic_item = "FileType")] pub struct FileType(fs_imp::FileType); /// A builder used to create directories in various manners. /// /// This builder also supports platform-specific options. #[stable(feature = "dir_builder", since = "1.6.0")] +#[cfg_attr(not(test), rustc_diagnostic_item = "DirBuilder")] #[derive(Debug)] pub struct DirBuilder { inner: fs_imp::DirBuilder, diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index ad8975c03f175..cc615b95f8625 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -514,6 +514,7 @@ pub(crate) fn default_read_exact(this: &mut R, mut buf: &mut [ /// [`File`]: crate::fs::File #[stable(feature = "rust1", since = "1.0.0")] #[doc(notable_trait)] +#[cfg_attr(not(test), rustc_diagnostic_item = "IoRead")] pub trait Read { /// Pull some bytes from this source into the specified buffer, returning /// how many bytes were read. @@ -1361,6 +1362,7 @@ impl Initializer { /// [`write_all`]: Write::write_all #[stable(feature = "rust1", since = "1.0.0")] #[doc(notable_trait)] +#[cfg_attr(not(test), rustc_diagnostic_item = "IoWrite")] pub trait Write { /// Write a buffer into this writer, returning how many bytes were written. /// diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 80aaae1580114..1a2852dc6c724 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -14,7 +14,7 @@ use rustc_attr as attr; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir as hir; use rustc_hir::def::{CtorKind, DefKind, Res}; -use rustc_hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX, LOCAL_CRATE}; +use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX, LOCAL_CRATE}; use rustc_index::vec::{Idx, IndexVec}; use rustc_infer::infer::region_constraints::{Constraint, RegionConstraintData}; use rustc_middle::middle::resolve_lifetime as rl; @@ -85,12 +85,6 @@ impl, U> Clean> for Option { } } -impl Clean for CrateNum { - fn clean(&self, _cx: &mut DocContext<'_>) -> ExternalCrate { - ExternalCrate { crate_num: *self } - } -} - impl Clean for doctree::Module<'_> { fn clean(&self, cx: &mut DocContext<'_>) -> Item { let mut items: Vec = vec![]; diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 859746b6a2df7..2fd2d14bcabc3 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -118,7 +118,7 @@ crate struct Crate { crate name: Symbol, crate src: FileName, crate module: Item, - crate externs: Vec<(CrateNum, ExternalCrate)>, + crate externs: Vec, crate primitives: ThinVec<(DefId, PrimitiveType)>, // These are later on moved into `CACHEKEY`, leaving the map empty. // Only here so that they can be filtered through the rustdoc passes. @@ -133,14 +133,14 @@ crate struct TraitWithExtraInfo { crate is_notable: bool, } -#[derive(Clone, Debug)] +#[derive(Copy, Clone, Debug)] crate struct ExternalCrate { crate crate_num: CrateNum, } impl ExternalCrate { #[inline] - fn def_id(&self) -> DefId { + crate fn def_id(&self) -> DefId { DefId { krate: self.crate_num, index: CRATE_DEF_INDEX } } diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index dea016a467d64..bdfe3ffc13f13 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -1,9 +1,9 @@ use crate::clean::auto_trait::AutoTraitFinder; use crate::clean::blanket_impl::BlanketImplFinder; use crate::clean::{ - inline, Clean, Crate, Generic, GenericArg, GenericArgs, ImportSource, Item, ItemKind, Lifetime, - Path, PathSegment, PolyTrait, Primitive, PrimitiveType, ResolvedPath, Type, TypeBinding, - Visibility, + inline, Clean, Crate, ExternalCrate, Generic, GenericArg, GenericArgs, ImportSource, Item, + ItemKind, Lifetime, Path, PathSegment, PolyTrait, Primitive, PrimitiveType, ResolvedPath, Type, + TypeBinding, Visibility, }; use crate::core::DocContext; use crate::formats::item_type::ItemType; @@ -35,11 +35,11 @@ crate fn krate(cx: &mut DocContext<'_>) -> Crate { let mut externs = Vec::new(); for &cnum in cx.tcx.crates(()).iter() { - externs.push((cnum, cnum.clean(cx))); + externs.push(ExternalCrate { crate_num: cnum }); // Analyze doc-reachability for extern items LibEmbargoVisitor::new(cx).visit_lib(cnum); } - externs.sort_by(|&(a, _), &(b, _)| a.cmp(&b)); + externs.sort_unstable_by_key(|e| e.crate_num); // Clean the crate, translating the entire librustc_ast AST to one that is // understood by rustdoc. @@ -61,7 +61,7 @@ crate fn krate(cx: &mut DocContext<'_>) -> Crate { _ => unreachable!(), } - let local_crate = LOCAL_CRATE.clean(cx); + let local_crate = ExternalCrate { crate_num: LOCAL_CRATE }; let src = local_crate.src(cx.tcx); let name = local_crate.name(cx.tcx); let primitives = local_crate.primitives(cx.tcx); @@ -287,7 +287,7 @@ crate fn name_from_pat(p: &hir::Pat<'_>) -> Symbol { crate fn print_const(cx: &DocContext<'_>, n: &'tcx ty::Const<'_>) -> String { match n.val { - ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs: _, promoted }) => { + ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs_: _, promoted }) => { let mut s = if let Some(def) = def.as_local() { let hir_id = cx.tcx.hir().local_def_id_to_hir_id(def.did); print_const_expr(cx.tcx, cx.tcx.hir().body_owned_by(hir_id)) diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs index e7d6e5ac2c24b..5ea2cdc2ad909 100644 --- a/src/librustdoc/formats/cache.rs +++ b/src/librustdoc/formats/cache.rs @@ -151,19 +151,18 @@ impl Cache { // Cache where all our extern crates are located // FIXME: this part is specific to HTML so it'd be nice to remove it from the common code - for &(n, ref e) in &krate.externs { + for &e in &krate.externs { let name = e.name(tcx); let extern_url = extern_html_root_urls.get(&*name.as_str()).map(|u| &**u); - let did = DefId { krate: n, index: CRATE_DEF_INDEX }; - self.extern_locations.insert(n, e.location(extern_url, &dst, tcx)); - self.external_paths.insert(did, (vec![name.to_string()], ItemType::Module)); + self.extern_locations.insert(e.crate_num, e.location(extern_url, &dst, tcx)); + self.external_paths.insert(e.def_id(), (vec![name.to_string()], ItemType::Module)); } // Cache where all known primitives have their documentation located. // // Favor linking to as local extern as possible, so iterate all crates in // reverse topological order. - for &(_, ref e) in krate.externs.iter().rev() { + for &e in krate.externs.iter().rev() { for &(def_id, prim) in &e.primitives(tcx) { self.primitive_locations.insert(prim, def_id); } diff --git a/src/test/ui/borrowck/issue-83760.rs b/src/test/ui/borrowck/issue-83760.rs new file mode 100644 index 0000000000000..e25b4f727856e --- /dev/null +++ b/src/test/ui/borrowck/issue-83760.rs @@ -0,0 +1,40 @@ +struct Struct; + +fn test1() { + let mut val = Some(Struct); + while let Some(foo) = val { //~ ERROR use of moved value + if true { + val = None; + } else { + + } + } +} + +fn test2() { + let mut foo = Some(Struct); + let _x = foo.unwrap(); + if true { + foo = Some(Struct); + } else { + } + let _y = foo; //~ ERROR use of moved value: `foo` +} + +fn test3() { + let mut foo = Some(Struct); + let _x = foo.unwrap(); + if true { + foo = Some(Struct); + } else if true { + foo = Some(Struct); + } else if true { + foo = Some(Struct); + } else if true { + foo = Some(Struct); + } else { + } + let _y = foo; //~ ERROR use of moved value: `foo` +} + +fn main() {} diff --git a/src/test/ui/borrowck/issue-83760.stderr b/src/test/ui/borrowck/issue-83760.stderr new file mode 100644 index 0000000000000..beeda5685dc09 --- /dev/null +++ b/src/test/ui/borrowck/issue-83760.stderr @@ -0,0 +1,62 @@ +error[E0382]: use of moved value + --> $DIR/issue-83760.rs:5:20 + | +LL | while let Some(foo) = val { + | ^^^ value moved here, in previous iteration of loop +LL | if true { +LL | val = None; + | ---------- this reinitialization might get skipped + | + = note: move occurs because value has type `Struct`, which does not implement the `Copy` trait + +error[E0382]: use of moved value: `foo` + --> $DIR/issue-83760.rs:21:14 + | +LL | let mut foo = Some(Struct); + | ------- move occurs because `foo` has type `Option`, which does not implement the `Copy` trait +LL | let _x = foo.unwrap(); + | -------- `foo` moved due to this method call +LL | if true { +LL | foo = Some(Struct); + | ------------------ this reinitialization might get skipped +... +LL | let _y = foo; + | ^^^ value used here after move + | +note: this function takes ownership of the receiver `self`, which moves `foo` + --> $SRC_DIR/core/src/option.rs:LL:COL + | +LL | pub const fn unwrap(self) -> T { + | ^^^^ + +error[E0382]: use of moved value: `foo` + --> $DIR/issue-83760.rs:37:14 + | +LL | let mut foo = Some(Struct); + | ------- move occurs because `foo` has type `Option`, which does not implement the `Copy` trait +LL | let _x = foo.unwrap(); + | -------- `foo` moved due to this method call +... +LL | let _y = foo; + | ^^^ value used here after move + | +note: these 3 reinitializations and 1 other might get skipped + --> $DIR/issue-83760.rs:30:9 + | +LL | foo = Some(Struct); + | ^^^^^^^^^^^^^^^^^^ +LL | } else if true { +LL | foo = Some(Struct); + | ^^^^^^^^^^^^^^^^^^ +LL | } else if true { +LL | foo = Some(Struct); + | ^^^^^^^^^^^^^^^^^^ +note: this function takes ownership of the receiver `self`, which moves `foo` + --> $SRC_DIR/core/src/option.rs:LL:COL + | +LL | pub const fn unwrap(self) -> T { + | ^^^^ + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/const-generics/issue-86820.rs b/src/test/ui/const-generics/issue-86820.rs new file mode 100644 index 0000000000000..04650403c6baf --- /dev/null +++ b/src/test/ui/const-generics/issue-86820.rs @@ -0,0 +1,25 @@ +// Regression test for the ICE described in #86820. + +#![allow(unused,dead_code)] +use std::ops::BitAnd; + +const C: fn() = || is_set(); +fn is_set() { + 0xffu8.bit::<0>(); +} + +trait Bits { + fn bit(self) -> bool; + //~^ NOTE: the const parameter `I` has type `usize`, but the declaration in trait `Bits::bit` has type `u8` +} + +impl Bits for u8 { + fn bit(self) -> bool { + //~^ ERROR: method `bit` has an incompatible const parameter type for trait [E0053] + let i = 1 << I; + let mask = u8::from(i); + mask & self == mask + } +} + +fn main() {} diff --git a/src/test/ui/const-generics/issue-86820.stderr b/src/test/ui/const-generics/issue-86820.stderr new file mode 100644 index 0000000000000..f4396f2f2b0a2 --- /dev/null +++ b/src/test/ui/const-generics/issue-86820.stderr @@ -0,0 +1,15 @@ +error[E0053]: method `bit` has an incompatible const parameter type for trait + --> $DIR/issue-86820.rs:17:18 + | +LL | fn bit(self) -> bool { + | ^ + | +note: the const parameter `I` has type `usize`, but the declaration in trait `Bits::bit` has type `u8` + --> $DIR/issue-86820.rs:12:18 + | +LL | fn bit(self) -> bool; + | ^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0053`. diff --git a/src/test/ui/dyn-drop/dyn-drop.rs b/src/test/ui/dyn-drop/dyn-drop.rs new file mode 100644 index 0000000000000..e1668a3f188d5 --- /dev/null +++ b/src/test/ui/dyn-drop/dyn-drop.rs @@ -0,0 +1,16 @@ +#![deny(dyn_drop)] +#![allow(bare_trait_objects)] +fn foo(_: Box) {} //~ ERROR +fn bar(_: &dyn Drop) {} //~ERROR +fn baz(_: *mut Drop) {} //~ ERROR +struct Foo { + _x: Box //~ ERROR +} +trait Bar { + type T: ?Sized; +} +struct Baz {} +impl Bar for Baz { + type T = dyn Drop; //~ ERROR +} +fn main() {} diff --git a/src/test/ui/dyn-drop/dyn-drop.stderr b/src/test/ui/dyn-drop/dyn-drop.stderr new file mode 100644 index 0000000000000..1b1dbc4d12d4c --- /dev/null +++ b/src/test/ui/dyn-drop/dyn-drop.stderr @@ -0,0 +1,38 @@ +error: types that do not implement `Drop` can still have drop glue, consider instead using `std::mem::needs_drop` to detect whether a type is trivially dropped + --> $DIR/dyn-drop.rs:3:19 + | +LL | fn foo(_: Box) {} + | ^^^^ + | +note: the lint level is defined here + --> $DIR/dyn-drop.rs:1:9 + | +LL | #![deny(dyn_drop)] + | ^^^^^^^^ + +error: types that do not implement `Drop` can still have drop glue, consider instead using `std::mem::needs_drop` to detect whether a type is trivially dropped + --> $DIR/dyn-drop.rs:4:16 + | +LL | fn bar(_: &dyn Drop) {} + | ^^^^ + +error: types that do not implement `Drop` can still have drop glue, consider instead using `std::mem::needs_drop` to detect whether a type is trivially dropped + --> $DIR/dyn-drop.rs:5:16 + | +LL | fn baz(_: *mut Drop) {} + | ^^^^ + +error: types that do not implement `Drop` can still have drop glue, consider instead using `std::mem::needs_drop` to detect whether a type is trivially dropped + --> $DIR/dyn-drop.rs:7:15 + | +LL | _x: Box + | ^^^^ + +error: types that do not implement `Drop` can still have drop glue, consider instead using `std::mem::needs_drop` to detect whether a type is trivially dropped + --> $DIR/dyn-drop.rs:14:16 + | +LL | type T = dyn Drop; + | ^^^^ + +error: aborting due to 5 previous errors + diff --git a/src/test/ui/dyn-keyword/issue-56327-dyn-trait-in-macro-is-okay.rs b/src/test/ui/dyn-keyword/issue-56327-dyn-trait-in-macro-is-okay.rs index 2b46f57c2e26f..59e7f9a6083ce 100644 --- a/src/test/ui/dyn-keyword/issue-56327-dyn-trait-in-macro-is-okay.rs +++ b/src/test/ui/dyn-keyword/issue-56327-dyn-trait-in-macro-is-okay.rs @@ -10,6 +10,7 @@ // anything. #![deny(rust_2018_compatibility)] +#![allow(dyn_drop)] macro_rules! foo { () => { diff --git a/src/test/ui/hygiene/unpretty-debug.stdout b/src/test/ui/hygiene/unpretty-debug.stdout index 84ca046212dc5..ffb9f9eed41fb 100644 --- a/src/test/ui/hygiene/unpretty-debug.stdout +++ b/src/test/ui/hygiene/unpretty-debug.stdout @@ -19,10 +19,10 @@ fn y /* 0#0 */() { } /* Expansions: -0: parent: ExpnId(0), call_site_ctxt: #0, def_site_ctxt: #0, kind: Root -1: parent: ExpnId(0), call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Bang, "foo") +crate0::{{expn0}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Root +crate0::{{expn1}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Bang, "foo") SyntaxContexts: -#0: parent: #0, outer_mark: (ExpnId(0), Opaque) -#1: parent: #0, outer_mark: (ExpnId(1), SemiTransparent) +#0: parent: #0, outer_mark: (crate0::{{expn0}}, Opaque) +#1: parent: #0, outer_mark: (crate0::{{expn1}}, SemiTransparent) */ diff --git a/src/test/ui/issues/issue-3290.rs b/src/test/ui/issues/issue-3290.rs index 63e1b28a60a1e..840c7ff8355d0 100644 --- a/src/test/ui/issues/issue-3290.rs +++ b/src/test/ui/issues/issue-3290.rs @@ -1,5 +1,6 @@ // run-pass #![feature(box_syntax)] +#![allow(dead_code)] pub fn main() { let mut x: Box<_> = box 3; diff --git a/src/test/ui/lint/dead-code/self-assign.rs b/src/test/ui/lint/dead-code/self-assign.rs new file mode 100644 index 0000000000000..b8bf7d860c415 --- /dev/null +++ b/src/test/ui/lint/dead-code/self-assign.rs @@ -0,0 +1,50 @@ +// Test that dead code warnings are issued for superfluous assignments of +// fields or variables to themselves (issue #75356). + +// check-pass +#![allow(unused_assignments)] +#![warn(dead_code)] + +fn main() { + let mut x = 0; + x = x; + //~^ WARNING: useless assignment of variable of type `i32` to itself + + x = (x); + //~^ WARNING: useless assignment of variable of type `i32` to itself + + x = {x}; + // block expressions don't count as self-assignments + + + struct S<'a> { f: &'a str } + let mut s = S { f: "abc" }; + s = s; + //~^ WARNING: useless assignment of variable of type `S` to itself + + s.f = s.f; + //~^ WARNING: useless assignment of field of type `&str` to itself + + + struct N0 { x: Box } + struct N1 { n: N0 } + struct N2(N1); + struct N3 { n: N2 }; + let mut n3 = N3 { n: N2(N1 { n: N0 { x: Box::new(42) } }) }; + n3.n.0.n.x = n3.n.0.n.x; + //~^ WARNING: useless assignment of field of type `Box` to itself + + let mut t = (1, ((2, 3, (4, 5)),)); + t.1.0.2.1 = t.1.0.2.1; + //~^ WARNING: useless assignment of field of type `i32` to itself + + + let mut y = 0; + macro_rules! assign_to_y { + ($cur:expr) => {{ + y = $cur; + }}; + } + assign_to_y!(y); + // self-assignments in macro expansions are not reported either +} diff --git a/src/test/ui/lint/dead-code/self-assign.stderr b/src/test/ui/lint/dead-code/self-assign.stderr new file mode 100644 index 0000000000000..bb79c0ec72a34 --- /dev/null +++ b/src/test/ui/lint/dead-code/self-assign.stderr @@ -0,0 +1,44 @@ +warning: useless assignment of variable of type `i32` to itself + --> $DIR/self-assign.rs:10:5 + | +LL | x = x; + | ^^^^^ + | +note: the lint level is defined here + --> $DIR/self-assign.rs:6:9 + | +LL | #![warn(dead_code)] + | ^^^^^^^^^ + +warning: useless assignment of variable of type `i32` to itself + --> $DIR/self-assign.rs:13:5 + | +LL | x = (x); + | ^^^^^^^ + +warning: useless assignment of variable of type `S` to itself + --> $DIR/self-assign.rs:22:5 + | +LL | s = s; + | ^^^^^ + +warning: useless assignment of field of type `&str` to itself + --> $DIR/self-assign.rs:25:5 + | +LL | s.f = s.f; + | ^^^^^^^^^ + +warning: useless assignment of field of type `Box` to itself + --> $DIR/self-assign.rs:34:5 + | +LL | n3.n.0.n.x = n3.n.0.n.x; + | ^^^^^^^^^^^^^^^^^^^^^^^ + +warning: useless assignment of field of type `i32` to itself + --> $DIR/self-assign.rs:38:5 + | +LL | t.1.0.2.1 = t.1.0.2.1; + | ^^^^^^^^^^^^^^^^^^^^^ + +warning: 6 warnings emitted + diff --git a/src/test/ui/lint/semicolon-in-expressions-from-macros/semicolon-in-expressions-from-macros.rs b/src/test/ui/lint/semicolon-in-expressions-from-macros/semicolon-in-expressions-from-macros.rs index 0bbd7dc6c8a7a..fff380934e8e9 100644 --- a/src/test/ui/lint/semicolon-in-expressions-from-macros/semicolon-in-expressions-from-macros.rs +++ b/src/test/ui/lint/semicolon-in-expressions-from-macros/semicolon-in-expressions-from-macros.rs @@ -1,14 +1,17 @@ // check-pass // edition:2018 +#![feature(stmt_expr_attributes)] #![warn(semicolon_in_expressions_from_macros)] #[allow(dead_code)] macro_rules! foo { ($val:ident) => { - true; //~ WARN trailing - //~| WARN this was previously - //~| WARN trailing - //~| WARN this was previously + true; //~ WARN trailing semicolon in macro + //~| WARN this was previously accepted + //~| WARN trailing semicolon in macro + //~| WARN this was previously accepted + //~| WARN trailing semicolon in macro + //~| WARN this was previously accepted } } @@ -18,17 +21,14 @@ async fn bar() { } fn main() { - // This `allow` doesn't work #[allow(semicolon_in_expressions_from_macros)] let _ = { foo!(first) }; - // This 'allow' doesn't work either #[allow(semicolon_in_expressions_from_macros)] let _ = foo!(second); - // But this 'allow' does #[allow(semicolon_in_expressions_from_macros)] fn inner() { let _ = foo!(third); @@ -38,4 +38,14 @@ fn main() { async { let _ = foo!(fourth); }; + + let _ = { + foo!(warn_in_block) + }; + + let _ = foo!(warn_in_expr); + + // This `#[allow]` does not work, since the attribute gets dropped + // when we expand the macro + let _ = #[allow(semicolon_in_expressions_from_macros)] foo!(allow_does_not_work); } diff --git a/src/test/ui/lint/semicolon-in-expressions-from-macros/semicolon-in-expressions-from-macros.stderr b/src/test/ui/lint/semicolon-in-expressions-from-macros/semicolon-in-expressions-from-macros.stderr index 111ebea61dd12..c00c3d77dcedc 100644 --- a/src/test/ui/lint/semicolon-in-expressions-from-macros/semicolon-in-expressions-from-macros.stderr +++ b/src/test/ui/lint/semicolon-in-expressions-from-macros/semicolon-in-expressions-from-macros.stderr @@ -1,14 +1,14 @@ warning: trailing semicolon in macro used in expression position - --> $DIR/semicolon-in-expressions-from-macros.rs:8:13 + --> $DIR/semicolon-in-expressions-from-macros.rs:9:13 | LL | true; | ^ ... -LL | foo!(first) - | ----------- in this macro invocation +LL | foo!(warn_in_block) + | ------------------- in this macro invocation | note: the lint level is defined here - --> $DIR/semicolon-in-expressions-from-macros.rs:3:9 + --> $DIR/semicolon-in-expressions-from-macros.rs:4:9 | LL | #![warn(semicolon_in_expressions_from_macros)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -17,17 +17,30 @@ LL | #![warn(semicolon_in_expressions_from_macros)] = note: this warning originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info) warning: trailing semicolon in macro used in expression position - --> $DIR/semicolon-in-expressions-from-macros.rs:8:13 + --> $DIR/semicolon-in-expressions-from-macros.rs:9:13 | LL | true; | ^ ... -LL | let _ = foo!(second); - | ------------ in this macro invocation +LL | let _ = foo!(warn_in_expr); + | ------------------ in this macro invocation | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #79813 = note: this warning originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info) -warning: 2 warnings emitted +warning: trailing semicolon in macro used in expression position + --> $DIR/semicolon-in-expressions-from-macros.rs:9:13 + | +LL | true; + | ^ +... +LL | let _ = #[allow(semicolon_in_expressions_from_macros)] foo!(allow_does_not_work); + | ------------------------- in this macro invocation + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #79813 + = note: this warning originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info) + +warning: 3 warnings emitted diff --git a/src/test/ui/nll/issue-50461-used-mut-from-moves.rs b/src/test/ui/nll/issue-50461-used-mut-from-moves.rs index 69d7cdd83a6a1..2458b171e6458 100644 --- a/src/test/ui/nll/issue-50461-used-mut-from-moves.rs +++ b/src/test/ui/nll/issue-50461-used-mut-from-moves.rs @@ -1,6 +1,7 @@ // run-pass #![deny(unused_mut)] +#![allow(dead_code)] struct Foo { pub value: i32 diff --git a/src/test/ui/panic-runtime/incompatible-type.rs b/src/test/ui/panic-runtime/incompatible-type.rs new file mode 100644 index 0000000000000..026364a2058fa --- /dev/null +++ b/src/test/ui/panic-runtime/incompatible-type.rs @@ -0,0 +1,24 @@ +// Check that rust_eh_personality can have a different type signature than the +// one hardcoded in the compiler. Regression test for #70117. Used to fail with: +// +// Assertion `isa(Val) && "cast() argument of incompatible type!"' failed. +// +// build-pass +// compile-flags: --crate-type=lib -Ccodegen-units=1 +#![no_std] +#![panic_runtime] +#![feature(panic_runtime)] +#![feature(rustc_attrs)] + +pub struct DropMe; + +impl Drop for DropMe { + fn drop(&mut self) {} +} + +pub fn test(_: DropMe) { + unreachable!(); +} + +#[rustc_std_internal_symbol] +pub unsafe extern "C" fn rust_eh_personality() {} diff --git a/src/test/ui/parser/range-inclusive-extra-equals.rs b/src/test/ui/parser/range-inclusive-extra-equals.rs new file mode 100644 index 0000000000000..d41c0699cf7fb --- /dev/null +++ b/src/test/ui/parser/range-inclusive-extra-equals.rs @@ -0,0 +1,10 @@ +// Makes sure that a helpful message is shown when someone mistypes +// an inclusive range as `..==` rather than `..=`. This is an +// easy mistake, because of the resemblance to`==`. +// See #86395 for a bit of background. + +pub fn main() { + if let 1..==3 = 1 {} //~ERROR unexpected `=` after inclusive range + //~|HELP use `..=` instead + //~|NOTE inclusive ranges end with a single equals sign +} diff --git a/src/test/ui/parser/range-inclusive-extra-equals.stderr b/src/test/ui/parser/range-inclusive-extra-equals.stderr new file mode 100644 index 0000000000000..d37b6be4fa113 --- /dev/null +++ b/src/test/ui/parser/range-inclusive-extra-equals.stderr @@ -0,0 +1,10 @@ +error: unexpected `=` after inclusive range + --> $DIR/range-inclusive-extra-equals.rs:7:13 + | +LL | if let 1..==3 = 1 {} + | ^^^^ help: use `..=` instead + | + = note: inclusive ranges end with a single equals sign (`..=`) + +error: aborting due to previous error + diff --git a/src/test/ui/proc-macro/auxiliary/call-deprecated.rs b/src/test/ui/proc-macro/auxiliary/call-deprecated.rs new file mode 100644 index 0000000000000..2f484809a5c99 --- /dev/null +++ b/src/test/ui/proc-macro/auxiliary/call-deprecated.rs @@ -0,0 +1,19 @@ +// force-host +// no-prefer-dynamic + +#![crate_type = "proc-macro"] + +extern crate proc_macro; +use proc_macro::*; + +#[proc_macro_attribute] +#[deprecated(since = "1.0.0", note = "test")] +pub fn attr(_: TokenStream, input: TokenStream) -> TokenStream { + input +} + +#[proc_macro_attribute] +#[deprecated(since = "1.0.0", note = "test")] +pub fn attr_remove(_: TokenStream, _: TokenStream) -> TokenStream { + TokenStream::new() +} diff --git a/src/test/ui/proc-macro/call-deprecated.rs b/src/test/ui/proc-macro/call-deprecated.rs new file mode 100644 index 0000000000000..b92cc23638ae1 --- /dev/null +++ b/src/test/ui/proc-macro/call-deprecated.rs @@ -0,0 +1,34 @@ +// check-pass +// aux-build:call-deprecated.rs + +extern crate call_deprecated; + +// These first two `#[allow(deprecated)]` attributes +// do nothing, since the AST nodes for `First` and `Second` +// haven't been been assigned a `NodeId`. +// See #63221 for a discussion about how we should +// handle the interaction of 'inert' attributes and +// proc-macro attributes. + +#[allow(deprecated)] +#[call_deprecated::attr] //~ WARN use of deprecated macro +struct First; + +#[allow(deprecated)] +#[call_deprecated::attr_remove] //~ WARN use of deprecated macro +struct Second; + +#[allow(deprecated)] +mod bar { + #[allow(deprecated)] + #[call_deprecated::attr] + struct Third; + + #[allow(deprecated)] + #[call_deprecated::attr_remove] + struct Fourth; +} + + +fn main() { +} diff --git a/src/test/ui/proc-macro/call-deprecated.stderr b/src/test/ui/proc-macro/call-deprecated.stderr new file mode 100644 index 0000000000000..3506f9a16a3c4 --- /dev/null +++ b/src/test/ui/proc-macro/call-deprecated.stderr @@ -0,0 +1,16 @@ +warning: use of deprecated macro `call_deprecated::attr`: test + --> $DIR/call-deprecated.rs:14:3 + | +LL | #[call_deprecated::attr] + | ^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(deprecated)]` on by default + +warning: use of deprecated macro `call_deprecated::attr_remove`: test + --> $DIR/call-deprecated.rs:18:3 + | +LL | #[call_deprecated::attr_remove] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: 2 warnings emitted + diff --git a/src/test/ui/proc-macro/issue-86781-bad-inner-doc.rs b/src/test/ui/proc-macro/issue-86781-bad-inner-doc.rs new file mode 100644 index 0000000000000..8be1ae77738e9 --- /dev/null +++ b/src/test/ui/proc-macro/issue-86781-bad-inner-doc.rs @@ -0,0 +1,11 @@ +// aux-build:test-macros.rs + +#[macro_use] +extern crate test_macros; + +//! Inner doc comment +//~^ ERROR expected outer doc comment +#[derive(Empty)] +pub struct Foo; + +fn main() {} diff --git a/src/test/ui/proc-macro/issue-86781-bad-inner-doc.stderr b/src/test/ui/proc-macro/issue-86781-bad-inner-doc.stderr new file mode 100644 index 0000000000000..0b2e612ee5bb9 --- /dev/null +++ b/src/test/ui/proc-macro/issue-86781-bad-inner-doc.stderr @@ -0,0 +1,11 @@ +error[E0753]: expected outer doc comment + --> $DIR/issue-86781-bad-inner-doc.rs:6:1 + | +LL | //! Inner doc comment + | ^^^^^^^^^^^^^^^^^^^^^ + | + = note: inner doc comments like this (starting with `//!` or `/*!`) can only appear before items + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0753`. diff --git a/src/test/ui/proc-macro/meta-macro-hygiene.stdout b/src/test/ui/proc-macro/meta-macro-hygiene.stdout index dc63d014451db..2524d8273b705 100644 --- a/src/test/ui/proc-macro/meta-macro-hygiene.stdout +++ b/src/test/ui/proc-macro/meta-macro-hygiene.stdout @@ -43,23 +43,23 @@ fn main /* 0#0 */() { ; } /* Expansions: -0: parent: ExpnId(0), call_site_ctxt: #0, def_site_ctxt: #0, kind: Root -1: parent: ExpnId(0), call_site_ctxt: #0, def_site_ctxt: #0, kind: AstPass(StdImports) -2: parent: ExpnId(0), call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Bang, "produce_it") -3: parent: ExpnId(0), call_site_ctxt: #0, def_site_ctxt: #0, kind: AstPass(StdImports) -4: parent: ExpnId(2), call_site_ctxt: #4, def_site_ctxt: #0, kind: Macro(Bang, "meta_macro::print_def_site") -5: parent: ExpnId(4), call_site_ctxt: #5, def_site_ctxt: #0, kind: Macro(Bang, "$crate::dummy") +crate0::{{expn0}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Root +crate0::{{expn1}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: AstPass(StdImports) +crate0::{{expn2}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Bang, "produce_it") +crate0::{{expn3}}: parent: crate0::{{expn2}}, call_site_ctxt: #4, def_site_ctxt: #0, kind: Macro(Bang, "meta_macro::print_def_site") +crate0::{{expn4}}: parent: crate0::{{expn3}}, call_site_ctxt: #5, def_site_ctxt: #0, kind: Macro(Bang, "$crate::dummy") +crate2::{{expn1}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: AstPass(StdImports) SyntaxContexts: -#0: parent: #0, outer_mark: (ExpnId(0), Opaque) -#1: parent: #0, outer_mark: (ExpnId(1), Opaque) -#2: parent: #0, outer_mark: (ExpnId(1), Transparent) -#3: parent: #0, outer_mark: (ExpnId(3), Opaque) -#4: parent: #0, outer_mark: (ExpnId(2), SemiTransparent) -#5: parent: #0, outer_mark: (ExpnId(4), Opaque) -#6: parent: #4, outer_mark: (ExpnId(4), Transparent) -#7: parent: #0, outer_mark: (ExpnId(4), SemiTransparent) -#8: parent: #0, outer_mark: (ExpnId(5), Opaque) -#9: parent: #5, outer_mark: (ExpnId(5), Transparent) -#10: parent: #5, outer_mark: (ExpnId(5), SemiTransparent) +#0: parent: #0, outer_mark: (crate0::{{expn0}}, Opaque) +#1: parent: #0, outer_mark: (crate0::{{expn1}}, Opaque) +#2: parent: #0, outer_mark: (crate0::{{expn1}}, Transparent) +#3: parent: #0, outer_mark: (crate2::{{expn1}}, Opaque) +#4: parent: #0, outer_mark: (crate0::{{expn2}}, SemiTransparent) +#5: parent: #0, outer_mark: (crate0::{{expn3}}, Opaque) +#6: parent: #4, outer_mark: (crate0::{{expn3}}, Transparent) +#7: parent: #0, outer_mark: (crate0::{{expn3}}, SemiTransparent) +#8: parent: #0, outer_mark: (crate0::{{expn4}}, Opaque) +#9: parent: #5, outer_mark: (crate0::{{expn4}}, Transparent) +#10: parent: #5, outer_mark: (crate0::{{expn4}}, SemiTransparent) */ diff --git a/src/test/ui/proc-macro/nonterminal-token-hygiene.stdout b/src/test/ui/proc-macro/nonterminal-token-hygiene.stdout index 75e6a49b314df..b5ab82737e9b6 100644 --- a/src/test/ui/proc-macro/nonterminal-token-hygiene.stdout +++ b/src/test/ui/proc-macro/nonterminal-token-hygiene.stdout @@ -67,22 +67,22 @@ fn main /* 0#0 */() { } /* Expansions: -0: parent: ExpnId(0), call_site_ctxt: #0, def_site_ctxt: #0, kind: Root -1: parent: ExpnId(0), call_site_ctxt: #0, def_site_ctxt: #0, kind: AstPass(StdImports) -2: parent: ExpnId(0), call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Bang, "outer") -3: parent: ExpnId(0), call_site_ctxt: #0, def_site_ctxt: #0, kind: AstPass(StdImports) -4: parent: ExpnId(2), call_site_ctxt: #4, def_site_ctxt: #4, kind: Macro(Bang, "inner") -5: parent: ExpnId(4), call_site_ctxt: #6, def_site_ctxt: #0, kind: Macro(Bang, "print_bang") +crate0::{{expn0}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Root +crate0::{{expn1}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: AstPass(StdImports) +crate0::{{expn2}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Bang, "outer") +crate0::{{expn3}}: parent: crate0::{{expn2}}, call_site_ctxt: #4, def_site_ctxt: #4, kind: Macro(Bang, "inner") +crate0::{{expn4}}: parent: crate0::{{expn3}}, call_site_ctxt: #6, def_site_ctxt: #0, kind: Macro(Bang, "print_bang") +crate2::{{expn1}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: AstPass(StdImports) SyntaxContexts: -#0: parent: #0, outer_mark: (ExpnId(0), Opaque) -#1: parent: #0, outer_mark: (ExpnId(1), Opaque) -#2: parent: #0, outer_mark: (ExpnId(1), Transparent) -#3: parent: #0, outer_mark: (ExpnId(3), Opaque) -#4: parent: #0, outer_mark: (ExpnId(2), SemiTransparent) -#5: parent: #0, outer_mark: (ExpnId(4), Opaque) -#6: parent: #4, outer_mark: (ExpnId(4), Opaque) -#7: parent: #0, outer_mark: (ExpnId(5), Opaque) -#8: parent: #6, outer_mark: (ExpnId(5), Transparent) -#9: parent: #5, outer_mark: (ExpnId(5), SemiTransparent) +#0: parent: #0, outer_mark: (crate0::{{expn0}}, Opaque) +#1: parent: #0, outer_mark: (crate0::{{expn1}}, Opaque) +#2: parent: #0, outer_mark: (crate0::{{expn1}}, Transparent) +#3: parent: #0, outer_mark: (crate2::{{expn1}}, Opaque) +#4: parent: #0, outer_mark: (crate0::{{expn2}}, SemiTransparent) +#5: parent: #0, outer_mark: (crate0::{{expn3}}, Opaque) +#6: parent: #4, outer_mark: (crate0::{{expn3}}, Opaque) +#7: parent: #0, outer_mark: (crate0::{{expn4}}, Opaque) +#8: parent: #6, outer_mark: (crate0::{{expn4}}, Transparent) +#9: parent: #5, outer_mark: (crate0::{{expn4}}, SemiTransparent) */ diff --git a/src/test/ui/rfc-2627-raw-dylib/multiple-declarations.rs b/src/test/ui/rfc-2627-raw-dylib/multiple-declarations.rs new file mode 100644 index 0000000000000..d02bebc9d61d2 --- /dev/null +++ b/src/test/ui/rfc-2627-raw-dylib/multiple-declarations.rs @@ -0,0 +1,19 @@ +// only-i686-pc-windows-msvc +// compile-flags: --crate-type lib --emit link +#![allow(clashing_extern_declarations)] +#![feature(raw_dylib)] +//~^ WARN the feature `raw_dylib` is incomplete +#[link(name = "foo", kind = "raw-dylib")] +extern "C" { + fn f(x: i32); +} + +pub fn lib_main() { + #[link(name = "foo", kind = "raw-dylib")] + extern "stdcall" { + fn f(x: i32); + //~^ ERROR multiple declarations of external function `f` from library `foo.dll` have different calling conventions + } + + unsafe { f(42); } +} diff --git a/src/test/ui/rfc-2627-raw-dylib/multiple-declarations.stderr b/src/test/ui/rfc-2627-raw-dylib/multiple-declarations.stderr new file mode 100644 index 0000000000000..a9cfd6b23f9f8 --- /dev/null +++ b/src/test/ui/rfc-2627-raw-dylib/multiple-declarations.stderr @@ -0,0 +1,17 @@ +warning: the feature `raw_dylib` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/multiple-declarations.rs:4:12 + | +LL | #![feature(raw_dylib)] + | ^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #58713 for more information + +error: multiple declarations of external function `f` from library `foo.dll` have different calling conventions + --> $DIR/multiple-declarations.rs:14:9 + | +LL | fn f(x: i32); + | ^^^^^^^^^^^^^ + +error: aborting due to previous error; 1 warning emitted + diff --git a/src/test/ui/self/self-re-assign.rs b/src/test/ui/self/self-re-assign.rs index a7b089ebff4c3..88e8614683227 100644 --- a/src/test/ui/self/self-re-assign.rs +++ b/src/test/ui/self/self-re-assign.rs @@ -3,6 +3,7 @@ // that we do not glue_drop before we glue_take (#3290). #![feature(box_syntax)] +#![allow(dead_code)] use std::rc::Rc; diff --git a/src/test/ui/traits/object/issue-33140-traitobject-crate.rs b/src/test/ui/traits/object/issue-33140-traitobject-crate.rs index 46b68f1c9fe07..8abd92da362d3 100644 --- a/src/test/ui/traits/object/issue-33140-traitobject-crate.rs +++ b/src/test/ui/traits/object/issue-33140-traitobject-crate.rs @@ -1,6 +1,7 @@ // check-pass #![warn(order_dependent_trait_objects)] +#![allow(dyn_drop)] // Check that traitobject 0.1.0 compiles diff --git a/src/test/ui/traits/object/issue-33140-traitobject-crate.stderr b/src/test/ui/traits/object/issue-33140-traitobject-crate.stderr index 781decb5ae281..77d71360b806b 100644 --- a/src/test/ui/traits/object/issue-33140-traitobject-crate.stderr +++ b/src/test/ui/traits/object/issue-33140-traitobject-crate.stderr @@ -1,5 +1,5 @@ warning: conflicting implementations of trait `Trait` for type `(dyn std::marker::Send + std::marker::Sync + 'static)`: (E0119) - --> $DIR/issue-33140-traitobject-crate.rs:85:1 + --> $DIR/issue-33140-traitobject-crate.rs:86:1 | LL | unsafe impl Trait for dyn (::std::marker::Send) + Sync { } | ------------------------------------------------------ first implementation here @@ -15,7 +15,7 @@ LL | #![warn(order_dependent_trait_objects)] = note: for more information, see issue #56484 warning: conflicting implementations of trait `Trait` for type `(dyn std::marker::Send + std::marker::Sync + 'static)`: (E0119) - --> $DIR/issue-33140-traitobject-crate.rs:88:1 + --> $DIR/issue-33140-traitobject-crate.rs:89:1 | LL | unsafe impl Trait for dyn (::std::marker::Send) + Send + Sync { } | ------------------------------------------------------------- first implementation here @@ -27,7 +27,7 @@ LL | unsafe impl Trait for dyn (::std::marker::Sync) + Send { } = note: for more information, see issue #56484 warning: conflicting implementations of trait `Trait` for type `(dyn std::marker::Send + std::marker::Sync + 'static)`: (E0119) - --> $DIR/issue-33140-traitobject-crate.rs:92:1 + --> $DIR/issue-33140-traitobject-crate.rs:93:1 | LL | unsafe impl Trait for dyn (::std::marker::Sync) + Send { } | ------------------------------------------------------ first implementation here diff --git a/src/test/ui/type-alias-impl-trait/issue-63355.rs b/src/test/ui/type-alias-impl-trait/issue-63355.rs new file mode 100644 index 0000000000000..8762d189c7389 --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/issue-63355.rs @@ -0,0 +1,50 @@ +#![feature(min_type_alias_impl_trait)] +#![feature(type_alias_impl_trait)] +#![allow(incomplete_features)] + +pub trait Foo {} + +pub trait Bar { + type Foo: Foo; + + fn foo() -> Self::Foo; +} + +pub trait Baz { + type Foo: Foo; + type Bar: Bar; + + fn foo() -> Self::Foo; + fn bar() -> Self::Bar; +} + +impl Foo for () {} + +impl Bar for () { + type Foo = FooImpl; + + fn foo() -> Self::Foo { + () + } +} + +// FIXME(#86731): The below is illegal use of `min_type_alias_impl_trait` +// but the compiler doesn't report it, we should fix it. +pub type FooImpl = impl Foo; +pub type BarImpl = impl Bar; +//~^ ERROR: type mismatch resolving `<() as Bar>::Foo == ()` + +impl Baz for () { + type Foo = FooImpl; + type Bar = BarImpl; + + fn foo() -> Self::Foo { + () + } + + fn bar() -> Self::Bar { + () + } +} + +fn main() {} diff --git a/src/test/ui/type-alias-impl-trait/issue-63355.stderr b/src/test/ui/type-alias-impl-trait/issue-63355.stderr new file mode 100644 index 0000000000000..dc5370a2666b7 --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/issue-63355.stderr @@ -0,0 +1,14 @@ +error[E0271]: type mismatch resolving `<() as Bar>::Foo == ()` + --> $DIR/issue-63355.rs:34:20 + | +LL | pub type FooImpl = impl Foo; + | -------- the found opaque type +LL | pub type BarImpl = impl Bar; + | ^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found opaque type + | + = note: expected unit type `()` + found opaque type `impl Foo` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0271`. diff --git a/src/tools/clippy/clippy_lints/src/escape.rs b/src/tools/clippy/clippy_lints/src/escape.rs index 5f400d079da2f..5f91bd66c87ad 100644 --- a/src/tools/clippy/clippy_lints/src/escape.rs +++ b/src/tools/clippy/clippy_lints/src/escape.rs @@ -53,7 +53,7 @@ fn is_non_trait_box(ty: Ty<'_>) -> bool { struct EscapeDelegate<'a, 'tcx> { cx: &'a LateContext<'tcx>, set: HirIdSet, - trait_self_ty: Option>, + trait_self_ty: Option>, too_large_for_stack: u64, } @@ -171,7 +171,7 @@ impl<'a, 'tcx> Delegate<'tcx> for EscapeDelegate<'a, 'tcx> { // skip if there is a `self` parameter binding to a type // that contains `Self` (i.e.: `self: Box`), see #4804 if let Some(trait_self_ty) = self.trait_self_ty { - if map.name(cmt.hir_id) == kw::SelfLower && contains_ty(cmt.place.ty(), trait_self_ty) { + if map.name(cmt.hir_id) == kw::SelfLower && contains_ty(self.cx.tcx, cmt.place.ty(), trait_self_ty) { return; } } diff --git a/src/tools/clippy/clippy_lints/src/let_underscore.rs b/src/tools/clippy/clippy_lints/src/let_underscore.rs index e627b1385bc7d..2d5c4aba14775 100644 --- a/src/tools/clippy/clippy_lints/src/let_underscore.rs +++ b/src/tools/clippy/clippy_lints/src/let_underscore.rs @@ -119,7 +119,7 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore { if let Some(init) = local.init; then { let init_ty = cx.typeck_results().expr_ty(init); - let contains_sync_guard = init_ty.walk().any(|inner| match inner.unpack() { + let contains_sync_guard = init_ty.walk(cx.tcx).any(|inner| match inner.unpack() { GenericArgKind::Type(inner_ty) => { SYNC_GUARD_PATHS.iter().any(|path| match_type(cx, inner_ty, path)) }, diff --git a/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs b/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs index 0f6cd5de761f9..545498a10478d 100644 --- a/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs +++ b/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs @@ -49,7 +49,7 @@ pub(super) fn check<'tcx>( if same_item_push_visitor.should_lint(); if let Some((vec, pushed_item)) = same_item_push_visitor.vec_push; let vec_ty = cx.typeck_results().expr_ty(vec); - let ty = vec_ty.walk().nth(1).unwrap().expect_ty(); + let ty = vec_ty.walk(cx.tcx).nth(1).unwrap().expect_ty(); if cx .tcx .lang_items() diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs index 283fcf281df18..8e3932f2a8e95 100644 --- a/src/tools/clippy/clippy_lints/src/methods/mod.rs +++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs @@ -1950,10 +1950,10 @@ impl<'tcx> LateLintPass<'tcx> for Methods { // walk the return type and check for Self (this does not check associated types) if let Some(self_adt) = self_ty.ty_adt_def() { - if contains_adt_constructor(ret_ty, self_adt) { + if contains_adt_constructor(cx.tcx, ret_ty, self_adt) { return; } - } else if contains_ty(ret_ty, self_ty) { + } else if contains_ty(cx.tcx, ret_ty, self_ty) { return; } @@ -1964,10 +1964,10 @@ impl<'tcx> LateLintPass<'tcx> for Methods { if let ty::PredicateKind::Projection(projection_predicate) = predicate.kind().skip_binder() { // walk the associated type and check for Self if let Some(self_adt) = self_ty.ty_adt_def() { - if contains_adt_constructor(projection_predicate.ty, self_adt) { + if contains_adt_constructor(cx.tcx, projection_predicate.ty, self_adt) { return; } - } else if contains_ty(projection_predicate.ty, self_ty) { + } else if contains_ty(cx.tcx, projection_predicate.ty, self_ty) { return; } } @@ -2016,7 +2016,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { if let TraitItemKind::Fn(_, _) = item.kind; let ret_ty = return_ty(cx, item.hir_id()); let self_ty = TraitRef::identity(cx.tcx, item.def_id.to_def_id()).self_ty(); - if !contains_ty(ret_ty, self_ty); + if !contains_ty(cx.tcx, ret_ty, self_ty); then { span_lint( diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs index 57fd03f4e12a6..f2670de08d4bc 100644 --- a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs +++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs @@ -116,7 +116,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { let fn_def_id = cx.tcx.hir().local_def_id(hir_id); let preds = traits::elaborate_predicates(cx.tcx, cx.param_env.caller_bounds().iter()) - .filter(|p| !p.is_global()) + .filter(|p| !p.is_global(cx.tcx)) .filter_map(|obligation| { // Note that we do not want to deal with qualified predicates here. match obligation.predicate.kind().no_bound_vars() { diff --git a/src/tools/clippy/clippy_lints/src/non_copy_const.rs b/src/tools/clippy/clippy_lints/src/non_copy_const.rs index d775cd7c7f740..38ce7be1a113a 100644 --- a/src/tools/clippy/clippy_lints/src/non_copy_const.rs +++ b/src/tools/clippy/clippy_lints/src/non_copy_const.rs @@ -181,11 +181,7 @@ fn is_value_unfrozen_expr<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId, def_id: D let result = cx.tcx.const_eval_resolve( cx.param_env, - ty::Unevaluated { - def: ty::WithOptConstParam::unknown(def_id), - substs, - promoted: None, - }, + ty::Unevaluated::new(ty::WithOptConstParam::unknown(def_id), substs), None, ); is_value_unfrozen_raw(cx, result, ty) diff --git a/src/tools/clippy/clippy_lints/src/redundant_clone.rs b/src/tools/clippy/clippy_lints/src/redundant_clone.rs index 7ba7ff3a353f9..a1be0bcca872e 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_clone.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_clone.rs @@ -14,7 +14,7 @@ use rustc_middle::mir::{ visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor as _}, Mutability, }; -use rustc_middle::ty::{self, fold::TypeVisitor, Ty}; +use rustc_middle::ty::{self, fold::TypeVisitor, Ty, TyCtxt}; use rustc_mir::dataflow::{Analysis, AnalysisDomain, GenKill, GenKillAnalysis, ResultsCursor}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::{BytePos, Span}; @@ -575,7 +575,7 @@ impl<'a, 'tcx> mir::visit::Visitor<'tcx> for PossibleBorrowerVisitor<'a, 'tcx> { self.possible_borrower.add(borrowed.local, lhs); }, other => { - if ContainsRegion + if ContainsRegion(self.cx.tcx) .visit_ty(place.ty(&self.body.local_decls, self.cx.tcx).ty) .is_continue() { @@ -624,7 +624,7 @@ impl<'a, 'tcx> mir::visit::Visitor<'tcx> for PossibleBorrowerVisitor<'a, 'tcx> { .flat_map(HybridBitSet::iter) .collect(); - if ContainsRegion.visit_ty(self.body.local_decls[*dest].ty).is_break() { + if ContainsRegion(self.cx.tcx).visit_ty(self.body.local_decls[*dest].ty).is_break() { mutable_variables.push(*dest); } @@ -700,12 +700,15 @@ impl<'a, 'tcx> mir::visit::Visitor<'tcx> for PossibleOriginVisitor<'a, 'tcx> { } } -struct ContainsRegion; +struct ContainsRegion<'tcx>(TyCtxt<'tcx>); -impl TypeVisitor<'_> for ContainsRegion { +impl<'tcx> TypeVisitor<'tcx> for ContainsRegion<'tcx> { type BreakTy = (); + fn tcx_for_anon_const_substs(&self) -> Option> { + Some(self.0) + } - fn visit_region(&mut self, _: ty::Region<'_>) -> ControlFlow { + fn visit_region(&mut self, _: ty::Region<'tcx>) -> ControlFlow { ControlFlow::BREAK } } diff --git a/src/tools/clippy/clippy_lints/src/returns.rs b/src/tools/clippy/clippy_lints/src/returns.rs index 251d527c26522..7349b6525f399 100644 --- a/src/tools/clippy/clippy_lints/src/returns.rs +++ b/src/tools/clippy/clippy_lints/src/returns.rs @@ -296,7 +296,7 @@ impl<'tcx> Visitor<'tcx> for BorrowVisitor<'_, 'tcx> { .fn_sig(def_id) .output() .skip_binder() - .walk() + .walk(self.cx.tcx) .any(|arg| matches!(arg.unpack(), GenericArgKind::Lifetime(_))); } diff --git a/src/tools/clippy/clippy_lints/src/unnecessary_sort_by.rs b/src/tools/clippy/clippy_lints/src/unnecessary_sort_by.rs index 347d858b64026..a9423c05019bd 100644 --- a/src/tools/clippy/clippy_lints/src/unnecessary_sort_by.rs +++ b/src/tools/clippy/clippy_lints/src/unnecessary_sort_by.rs @@ -219,7 +219,7 @@ fn detect_lint(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option { fn expr_borrows(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { let ty = cx.typeck_results().expr_ty(expr); - matches!(ty.kind(), ty::Ref(..)) || ty.walk().any(|arg| matches!(arg.unpack(), GenericArgKind::Lifetime(_))) + matches!(ty.kind(), ty::Ref(..)) || ty.walk(cx.tcx).any(|arg| matches!(arg.unpack(), GenericArgKind::Lifetime(_))) } impl LateLintPass<'_> for UnnecessarySortBy { diff --git a/src/tools/clippy/clippy_lints/src/use_self.rs b/src/tools/clippy/clippy_lints/src/use_self.rs index 71117e967e319..d3a623262521f 100644 --- a/src/tools/clippy/clippy_lints/src/use_self.rs +++ b/src/tools/clippy/clippy_lints/src/use_self.rs @@ -169,7 +169,7 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf { // // See also https://github.com/rust-lang/rust-clippy/issues/2894. for (impl_hir_ty, trait_sem_ty) in impl_inputs_outputs.zip(trait_method_sig.inputs_and_output) { - if trait_sem_ty.walk().any(|inner| inner == self_ty.into()) { + if trait_sem_ty.walk(cx.tcx).any(|inner| inner == self_ty.into()) { let mut visitor = SkipTyCollector::default(); visitor.visit_ty(impl_hir_ty); types_to_skip.extend(visitor.types_to_skip); diff --git a/src/tools/clippy/clippy_utils/src/consts.rs b/src/tools/clippy/clippy_utils/src/consts.rs index 15c27d1a996d7..a2639abcb8078 100644 --- a/src/tools/clippy/clippy_utils/src/consts.rs +++ b/src/tools/clippy/clippy_utils/src/consts.rs @@ -346,11 +346,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> { .tcx .const_eval_resolve( self.param_env, - ty::Unevaluated { - def: ty::WithOptConstParam::unknown(def_id), - substs, - promoted: None, - }, + ty::Unevaluated::new(ty::WithOptConstParam::unknown(def_id), substs), None, ) .ok() diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index 4f0a9f442ed9f..bd08d73e0d7b9 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -1506,7 +1506,7 @@ pub fn fn_has_unsatisfiable_preds(cx: &LateContext<'_>, did: DefId) -> bool { .predicates_of(did) .predicates .iter() - .filter_map(|(p, _)| if p.is_global() { Some(*p) } else { None }); + .filter_map(|(p, _)| if p.is_global(cx.tcx) { Some(*p) } else { None }); traits::impossible_predicates( cx.tcx, traits::elaborate_predicates(cx.tcx, predicates) @@ -1552,7 +1552,7 @@ pub fn is_slice_of_primitives(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option return Some("slice".into()), rustc_ty::Array(..) => return Some("array".into()), rustc_ty::Tuple(..) => return Some("tuple".into()), @@ -1560,7 +1560,7 @@ pub fn is_slice_of_primitives(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option, body: &'a Body<'tcx>, msrv: Option<&Ru } fn check_ty(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, span: Span) -> McfResult { - for arg in ty.walk() { + for arg in ty.walk(tcx) { let ty = match arg.unpack() { GenericArgKind::Type(ty) => ty, diff --git a/src/tools/clippy/clippy_utils/src/ty.rs b/src/tools/clippy/clippy_utils/src/ty.rs index 3f5c5604d43f5..09f3710334af3 100644 --- a/src/tools/clippy/clippy_utils/src/ty.rs +++ b/src/tools/clippy/clippy_utils/src/ty.rs @@ -10,7 +10,7 @@ use rustc_hir::{TyKind, Unsafety}; use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::LateContext; use rustc_middle::ty::subst::{GenericArg, GenericArgKind}; -use rustc_middle::ty::{self, AdtDef, IntTy, Ty, TypeFoldable, UintTy}; +use rustc_middle::ty::{self, TyCtxt, AdtDef, IntTy, Ty, TypeFoldable, UintTy}; use rustc_span::sym; use rustc_span::symbol::{Ident, Symbol}; use rustc_span::DUMMY_SP; @@ -36,8 +36,8 @@ pub fn can_partially_move_ty(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { } /// Walks into `ty` and returns `true` if any inner type is the same as `other_ty` -pub fn contains_ty(ty: Ty<'_>, other_ty: Ty<'_>) -> bool { - ty.walk().any(|inner| match inner.unpack() { +pub fn contains_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, other_ty: Ty<'tcx>) -> bool { + ty.walk(tcx).any(|inner| match inner.unpack() { GenericArgKind::Type(inner_ty) => ty::TyS::same_type(other_ty, inner_ty), GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => false, }) @@ -45,8 +45,8 @@ pub fn contains_ty(ty: Ty<'_>, other_ty: Ty<'_>) -> bool { /// Walks into `ty` and returns `true` if any inner type is an instance of the given adt /// constructor. -pub fn contains_adt_constructor(ty: Ty<'_>, adt: &AdtDef) -> bool { - ty.walk().any(|inner| match inner.unpack() { +pub fn contains_adt_constructor<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, adt: &'tcx AdtDef) -> bool { + ty.walk(tcx).any(|inner| match inner.unpack() { GenericArgKind::Type(inner_ty) => inner_ty.ty_adt_def() == Some(adt), GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => false, }) @@ -209,7 +209,7 @@ fn is_normalizable_helper<'tcx>( .iter() .all(|field| is_normalizable_helper(cx, param_env, field.ty(cx.tcx, substs), cache)) }), - _ => ty.walk().all(|generic_arg| match generic_arg.unpack() { + _ => ty.walk(cx.tcx).all(|generic_arg| match generic_arg.unpack() { GenericArgKind::Type(inner_ty) if inner_ty != ty => { is_normalizable_helper(cx, param_env, inner_ty, cache) }, diff --git a/src/tools/clippy/tests/ui/needless_lifetimes.rs b/src/tools/clippy/tests/ui/needless_lifetimes.rs index bda0801e51c7f..1d77382bf2cd1 100644 --- a/src/tools/clippy/tests/ui/needless_lifetimes.rs +++ b/src/tools/clippy/tests/ui/needless_lifetimes.rs @@ -1,5 +1,5 @@ #![warn(clippy::needless_lifetimes)] -#![allow(dead_code, clippy::needless_pass_by_value, clippy::unnecessary_wraps)] +#![allow(dead_code, clippy::needless_pass_by_value, clippy::unnecessary_wraps, dyn_drop)] fn distinct_lifetimes<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: u8) {} diff --git a/src/tools/miri b/src/tools/miri index b06130762ed75..250eff85c86b0 160000 --- a/src/tools/miri +++ b/src/tools/miri @@ -1 +1 @@ -Subproject commit b06130762ed75f52da7c22979c61c597ced667c6 +Subproject commit 250eff85c86b089b77005691b899cea739f7e0cb diff --git a/src/tools/rustfmt/src/utils.rs b/src/tools/rustfmt/src/utils.rs index d3c349fb701e1..614cda5f911c2 100644 --- a/src/tools/rustfmt/src/utils.rs +++ b/src/tools/rustfmt/src/utils.rs @@ -6,7 +6,7 @@ use rustc_ast::ast::{ }; use rustc_ast::ptr; use rustc_ast_pretty::pprust; -use rustc_span::{sym, symbol, BytePos, ExpnId, Span, Symbol, SyntaxContext}; +use rustc_span::{sym, symbol, BytePos, LocalExpnId, Span, Symbol, SyntaxContext}; use unicode_width::UnicodeWidthStr; use crate::comment::{filter_normal_code, CharClasses, FullCodeCharKind, LineClasses}; @@ -675,7 +675,7 @@ pub(crate) trait NodeIdExt { impl NodeIdExt for NodeId { fn root() -> NodeId { - NodeId::placeholder_from_expn_id(ExpnId::root()) + NodeId::placeholder_from_expn_id(LocalExpnId::ROOT) } }