diff options
Diffstat (limited to 'compiler')
260 files changed, 4077 insertions, 2462 deletions
diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs index f0a6a5e0725..db296aa44db 100644 --- a/compiler/rustc_ast/src/tokenstream.rs +++ b/compiler/rustc_ast/src/tokenstream.rs @@ -48,14 +48,15 @@ pub enum TokenTree { Delimited(DelimSpan, Delimiter, TokenStream), } -// Ensure all fields of `TokenTree` is `Send` and `Sync`. +// Ensure all fields of `TokenTree` are `DynSend` and `DynSync`. #[cfg(parallel_compiler)] fn _dummy() where - Token: Send + Sync, - DelimSpan: Send + Sync, - Delimiter: Send + Sync, - TokenStream: Send + Sync, + Token: sync::DynSend + sync::DynSync, + Spacing: sync::DynSend + sync::DynSync, + DelimSpan: sync::DynSend + sync::DynSync, + Delimiter: sync::DynSend + sync::DynSync, + TokenStream: sync::DynSend + sync::DynSync, { } @@ -118,7 +119,7 @@ where } } -pub trait ToAttrTokenStream: sync::Send + sync::Sync { +pub trait ToAttrTokenStream: sync::DynSend + sync::DynSync { fn to_attr_token_stream(&self) -> AttrTokenStream; } @@ -550,6 +551,10 @@ impl TokenStream { vec_mut.extend(stream_iter); } } + + pub fn chunks(&self, chunk_size: usize) -> core::slice::Chunks<'_, TokenTree> { + self.0.chunks(chunk_size) + } } /// By-reference iterator over a [`TokenStream`], that produces `&TokenTree` diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 3d154a93fb2..08ee3761bac 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -305,7 +305,10 @@ impl<'hir> LoweringContext<'_, 'hir> { ); this.arena.alloc(this.ty(span, hir::TyKind::Err(guar))) } - Some(ty) => this.lower_ty(ty, &ImplTraitContext::TypeAliasesOpaqueTy), + Some(ty) => this.lower_ty( + ty, + &ImplTraitContext::TypeAliasesOpaqueTy { in_assoc_ty: false }, + ), }, ); hir::ItemKind::TyAlias(ty, generics) @@ -852,7 +855,10 @@ impl<'hir> LoweringContext<'_, 'hir> { hir::ImplItemKind::Type(ty) } Some(ty) => { - let ty = this.lower_ty(ty, &ImplTraitContext::TypeAliasesOpaqueTy); + let ty = this.lower_ty( + ty, + &ImplTraitContext::TypeAliasesOpaqueTy { in_assoc_ty: true }, + ); hir::ImplItemKind::Type(ty) } }, diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 1fd7cc66470..cd6614a54a4 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -247,7 +247,7 @@ enum ImplTraitContext { in_trait: bool, }, /// Impl trait in type aliases. - TypeAliasesOpaqueTy, + TypeAliasesOpaqueTy { in_assoc_ty: bool }, /// `impl Trait` is unstably accepted in this position. FeatureGated(ImplTraitPosition, Symbol), /// `impl Trait` is not accepted in this position. @@ -1407,14 +1407,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { *in_trait, itctx, ), - ImplTraitContext::TypeAliasesOpaqueTy => self.lower_opaque_impl_trait( - span, - hir::OpaqueTyOrigin::TyAlias, - *def_node_id, - bounds, - false, - itctx, - ), + &ImplTraitContext::TypeAliasesOpaqueTy { in_assoc_ty } => self + .lower_opaque_impl_trait( + span, + hir::OpaqueTyOrigin::TyAlias { in_assoc_ty }, + *def_node_id, + bounds, + false, + itctx, + ), ImplTraitContext::Universal => { let span = t.span; self.create_def( @@ -1534,13 +1535,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // If this came from a TAIT (as opposed to a function that returns an RPIT), we only want // to capture the lifetimes that appear in the bounds. So visit the bounds to find out // exactly which ones those are. - let lifetimes_to_remap = if origin == hir::OpaqueTyOrigin::TyAlias { - // in a TAIT like `type Foo<'a> = impl Foo<'a>`, we don't keep all the lifetime parameters - Vec::new() - } else { - // in fn return position, like the `fn test<'a>() -> impl Debug + 'a` example, - // we only keep the lifetimes that appear in the `impl Debug` itself: - lifetime_collector::lifetimes_in_bounds(&self.resolver, bounds) + let lifetimes_to_remap = match origin { + hir::OpaqueTyOrigin::TyAlias { .. } => { + // in a TAIT like `type Foo<'a> = impl Foo<'a>`, we don't keep all the lifetime parameters + Vec::new() + } + hir::OpaqueTyOrigin::AsyncFn(..) | hir::OpaqueTyOrigin::FnReturn(..) => { + // in fn return position, like the `fn test<'a>() -> impl Debug + 'a` example, + // we only keep the lifetimes that appear in the `impl Debug` itself: + lifetime_collector::lifetimes_in_bounds(&self.resolver, bounds) + } }; debug!(?lifetimes_to_remap); diff --git a/compiler/rustc_borrowck/src/dataflow.rs b/compiler/rustc_borrowck/src/dataflow.rs index 94939c7e4cd..167f245361a 100644 --- a/compiler/rustc_borrowck/src/dataflow.rs +++ b/compiler/rustc_borrowck/src/dataflow.rs @@ -328,7 +328,7 @@ impl<'tcx> rustc_mir_dataflow::AnalysisDomain<'tcx> for Borrows<'_, 'tcx> { fn bottom_value(&self, _: &mir::Body<'tcx>) -> Self::Domain { // bottom = nothing is reserved or activated yet; - BitSet::new_empty(self.borrow_set.len() * 2) + BitSet::new_empty(self.borrow_set.len()) } fn initialize_start_block(&self, _: &mir::Body<'tcx>, _: &mut Self::Domain) { diff --git a/compiler/rustc_borrowck/src/def_use.rs b/compiler/rustc_borrowck/src/def_use.rs index 74e6ce37e97..b775739fed2 100644 --- a/compiler/rustc_borrowck/src/def_use.rs +++ b/compiler/rustc_borrowck/src/def_use.rs @@ -55,7 +55,7 @@ pub fn categorize(context: PlaceContext) -> Option<DefUse> { // `PlaceMention` and `AscribeUserType` both evaluate the place, which must not // contain dangling references. PlaceContext::NonMutatingUse(NonMutatingUseContext::PlaceMention) | - PlaceContext::NonUse(NonUseContext::AscribeUserTy) | + PlaceContext::NonUse(NonUseContext::AscribeUserTy(_)) | PlaceContext::MutatingUse(MutatingUseContext::AddressOf) | PlaceContext::NonMutatingUse(NonMutatingUseContext::AddressOf) | diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 315303b25fe..eb25d454339 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -35,7 +35,7 @@ use rustc_middle::mir::{ use rustc_middle::mir::{AggregateKind, BasicBlock, BorrowCheckResult, BorrowKind}; use rustc_middle::mir::{InlineAsmOperand, Terminator, TerminatorKind}; use rustc_middle::mir::{ProjectionElem, Promoted, Rvalue, Statement, StatementKind}; -use rustc_middle::ty::query::Providers; +use rustc_middle::query::Providers; use rustc_middle::ty::{self, CapturedPlace, ParamEnv, RegionVid, TyCtxt}; use rustc_session::lint::builtin::UNUSED_MUT; use rustc_span::{Span, Symbol}; diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs index 4970ece5e7d..309f23d9226 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs @@ -265,7 +265,7 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { // Only check this for TAIT. RPIT already supports `tests/ui/impl-trait/nested-return-type2.rs` // on stable and we'd break that. - let OpaqueTyOrigin::TyAlias = origin else { + let OpaqueTyOrigin::TyAlias { .. } = origin else { return definition_ty; }; let def_id = opaque_type_key.def_id; @@ -360,7 +360,7 @@ fn check_opaque_type_parameter_valid( // which would error here on all of the `'static` args. OpaqueTyOrigin::FnReturn(..) | OpaqueTyOrigin::AsyncFn(..) => return Ok(()), // Check these - OpaqueTyOrigin::TyAlias => {} + OpaqueTyOrigin::TyAlias { .. } => {} } let opaque_generics = tcx.generics_of(opaque_type_key.def_id); let mut seen_params: FxIndexMap<_, Vec<_>> = FxIndexMap::default(); diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index dcabeb792be..33b24b68f7c 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -777,7 +777,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { Inspect | Copy | Move | PlaceMention | SharedBorrow | ShallowBorrow | UniqueBorrow | AddressOf | Projection, ) => ty::Covariant, - PlaceContext::NonUse(AscribeUserTy) => ty::Covariant, + PlaceContext::NonUse(AscribeUserTy(variance)) => variance, } } diff --git a/compiler/rustc_builtin_macros/src/concat_idents.rs b/compiler/rustc_builtin_macros/src/concat_idents.rs index 8c737f04323..ee56d45c9c8 100644 --- a/compiler/rustc_builtin_macros/src/concat_idents.rs +++ b/compiler/rustc_builtin_macros/src/concat_idents.rs @@ -19,7 +19,7 @@ pub fn expand_concat_idents<'cx>( } let mut res_str = String::new(); - for (i, e) in tts.into_trees().enumerate() { + for (i, e) in tts.trees().enumerate() { if i & 1 == 1 { match e { TokenTree::Token(Token { kind: token::Comma, .. }, _) => {} diff --git a/compiler/rustc_builtin_macros/src/env.rs b/compiler/rustc_builtin_macros/src/env.rs index 58c972738c4..8f64e332861 100644 --- a/compiler/rustc_builtin_macros/src/env.rs +++ b/compiler/rustc_builtin_macros/src/env.rs @@ -63,7 +63,8 @@ pub fn expand_env<'cx>( Some(exprs) => exprs.into_iter(), }; - let Some((var, _style)) = expr_to_string(cx, exprs.next().unwrap(), "expected string literal") else { + let var_expr = exprs.next().unwrap(); + let Some((var, _)) = expr_to_string(cx, var_expr.clone(), "expected string literal") else { return DummyResult::any(sp); }; @@ -71,7 +72,7 @@ pub fn expand_env<'cx>( None => None, Some(second) => match expr_to_string(cx, second, "expected string literal") { None => return DummyResult::any(sp), - Some((s, _style)) => Some(s), + Some((s, _)) => Some(s), }, }; @@ -80,10 +81,15 @@ pub fn expand_env<'cx>( cx.sess.parse_sess.env_depinfo.borrow_mut().insert((var, value)); let e = match value { None => { + // Use the string literal in the code in the diagnostic to avoid confusing diagnostics, + // e.g. when the literal contains escape sequences. + let ast::ExprKind::Lit(ast::token::Lit { kind: ast::token::LitKind::Str, symbol: original_var, ..}) = &var_expr.kind else { + unreachable!("`expr_to_string` ensures this is a string lit") + }; cx.emit_err(errors::EnvNotDefined { span: sp, msg: custom_msg, - var, + var: *original_var, help: custom_msg.is_none().then(|| help_for_missing_env_var(var.as_str())), }); return DummyResult::any(sp); diff --git a/compiler/rustc_builtin_macros/src/format_foreign.rs b/compiler/rustc_builtin_macros/src/format_foreign.rs index bd9e903b6ba..bd5356575ca 100644 --- a/compiler/rustc_builtin_macros/src/format_foreign.rs +++ b/compiler/rustc_builtin_macros/src/format_foreign.rs @@ -562,15 +562,13 @@ pub(crate) mod printf { } if let Type = state { - drop(c); type_ = at.slice_between(next).unwrap(); // Don't use `move_to!` here, as we *can* be at the end of the input. at = next; } - drop(c); - drop(next); + let _ = c; // to avoid never used value end = at; let position = InnerSpan::new(start.at, end.at); diff --git a/compiler/rustc_builtin_macros/src/trace_macros.rs b/compiler/rustc_builtin_macros/src/trace_macros.rs index cc5ae6894e6..9c98723e1f4 100644 --- a/compiler/rustc_builtin_macros/src/trace_macros.rs +++ b/compiler/rustc_builtin_macros/src/trace_macros.rs @@ -8,7 +8,7 @@ pub fn expand_trace_macros( sp: Span, tt: TokenStream, ) -> Box<dyn base::MacResult + 'static> { - let mut cursor = tt.into_trees(); + let mut cursor = tt.trees(); let mut err = false; let value = match &cursor.next() { Some(TokenTree::Token(token, _)) if token.is_keyword(kw::True) => true, diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs index 1cabb05de97..442ce0ea542 100644 --- a/compiler/rustc_codegen_gcc/src/lib.rs +++ b/compiler/rustc_codegen_gcc/src/lib.rs @@ -80,8 +80,8 @@ use rustc_errors::{DiagnosticMessage, ErrorGuaranteed, Handler, SubdiagnosticMes use rustc_fluent_macro::fluent_messages; use rustc_metadata::EncodedMetadata; use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; +use rustc_middle::query::Providers; use rustc_middle::ty::TyCtxt; -use rustc_middle::ty::query::Providers; use rustc_session::config::{Lto, OptLevel, OutputFilenames}; use rustc_session::Session; use rustc_span::Symbol; diff --git a/compiler/rustc_codegen_llvm/src/callee.rs b/compiler/rustc_codegen_llvm/src/callee.rs index 30a0cf1d019..4b9ca2e7d19 100644 --- a/compiler/rustc_codegen_llvm/src/callee.rs +++ b/compiler/rustc_codegen_llvm/src/callee.rs @@ -94,11 +94,11 @@ pub fn get_fn<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, instance: Instance<'tcx>) -> // LLVM will prefix the name with `__imp_`. Ideally, we'd like the // existing logic below to set the Storage Class, but it has an // exemption for MinGW for backwards compatability. - let llfn = cx.declare_fn(&common::i686_decorated_name(&dllimport, common::is_mingw_gnu_toolchain(&tcx.sess.target), true), fn_abi); + let llfn = cx.declare_fn(&common::i686_decorated_name(&dllimport, common::is_mingw_gnu_toolchain(&tcx.sess.target), true), fn_abi, Some(instance)); unsafe { llvm::LLVMSetDLLStorageClass(llfn, llvm::DLLStorageClass::DllImport); } llfn } else { - cx.declare_fn(sym, fn_abi) + cx.declare_fn(sym, fn_abi, Some(instance)) }; debug!("get_fn: not casting pointer!"); diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs index 3dc0ac03312..cd261293e9b 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs @@ -207,6 +207,7 @@ fn declare_unused_fn<'tcx>(cx: &CodegenCx<'_, 'tcx>, def_id: DefId) -> Instance< )), ty::List::empty(), ), + None, ); llvm::set_linkage(llfn, llvm::Linkage::PrivateLinkage); diff --git a/compiler/rustc_codegen_llvm/src/declare.rs b/compiler/rustc_codegen_llvm/src/declare.rs index cc2a5d158be..164b12cf8d4 100644 --- a/compiler/rustc_codegen_llvm/src/declare.rs +++ b/compiler/rustc_codegen_llvm/src/declare.rs @@ -19,8 +19,11 @@ use crate::llvm::AttributePlace::Function; use crate::type_::Type; use crate::value::Value; use rustc_codegen_ssa::traits::TypeMembershipMethods; -use rustc_middle::ty::Ty; -use rustc_symbol_mangling::typeid::{kcfi_typeid_for_fnabi, typeid_for_fnabi, TypeIdOptions}; +use rustc_middle::ty::{Instance, Ty}; +use rustc_symbol_mangling::typeid::{ + kcfi_typeid_for_fnabi, kcfi_typeid_for_instance, typeid_for_fnabi, typeid_for_instance, + TypeIdOptions, +}; use smallvec::SmallVec; /// Declare a function. @@ -116,7 +119,12 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { /// /// If there’s a value with the same name already declared, the function will /// update the declaration and return existing Value instead. - pub fn declare_fn(&self, name: &str, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> &'ll Value { + pub fn declare_fn( + &self, + name: &str, + fn_abi: &FnAbi<'tcx, Ty<'tcx>>, + instance: Option<Instance<'tcx>>, + ) -> &'ll Value { debug!("declare_rust_fn(name={:?}, fn_abi={:?})", name, fn_abi); // Function addresses in Rust are never significant, allowing functions to @@ -132,18 +140,35 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { fn_abi.apply_attrs_llfn(self, llfn); if self.tcx.sess.is_sanitizer_cfi_enabled() { - let typeid = typeid_for_fnabi(self.tcx, fn_abi, TypeIdOptions::empty()); - self.set_type_metadata(llfn, typeid); - let typeid = typeid_for_fnabi(self.tcx, fn_abi, TypeIdOptions::GENERALIZE_POINTERS); - self.add_type_metadata(llfn, typeid); - let typeid = typeid_for_fnabi(self.tcx, fn_abi, TypeIdOptions::NORMALIZE_INTEGERS); - self.add_type_metadata(llfn, typeid); - let typeid = typeid_for_fnabi( - self.tcx, - fn_abi, - TypeIdOptions::GENERALIZE_POINTERS | TypeIdOptions::NORMALIZE_INTEGERS, - ); - self.add_type_metadata(llfn, typeid); + if let Some(instance) = instance { + let typeid = typeid_for_instance(self.tcx, &instance, TypeIdOptions::empty()); + self.set_type_metadata(llfn, typeid); + let typeid = + typeid_for_instance(self.tcx, &instance, TypeIdOptions::GENERALIZE_POINTERS); + self.add_type_metadata(llfn, typeid); + let typeid = + typeid_for_instance(self.tcx, &instance, TypeIdOptions::NORMALIZE_INTEGERS); + self.add_type_metadata(llfn, typeid); + let typeid = typeid_for_instance( + self.tcx, + &instance, + TypeIdOptions::GENERALIZE_POINTERS | TypeIdOptions::NORMALIZE_INTEGERS, + ); + self.add_type_metadata(llfn, typeid); + } else { + let typeid = typeid_for_fnabi(self.tcx, fn_abi, TypeIdOptions::empty()); + self.set_type_metadata(llfn, typeid); + let typeid = typeid_for_fnabi(self.tcx, fn_abi, TypeIdOptions::GENERALIZE_POINTERS); + self.add_type_metadata(llfn, typeid); + let typeid = typeid_for_fnabi(self.tcx, fn_abi, TypeIdOptions::NORMALIZE_INTEGERS); + self.add_type_metadata(llfn, typeid); + let typeid = typeid_for_fnabi( + self.tcx, + fn_abi, + TypeIdOptions::GENERALIZE_POINTERS | TypeIdOptions::NORMALIZE_INTEGERS, + ); + self.add_type_metadata(llfn, typeid); + } } if self.tcx.sess.is_sanitizer_kcfi_enabled() { @@ -156,8 +181,13 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { options.insert(TypeIdOptions::NORMALIZE_INTEGERS); } - let kcfi_typeid = kcfi_typeid_for_fnabi(self.tcx, fn_abi, options); - self.set_kcfi_type_metadata(llfn, kcfi_typeid); + if let Some(instance) = instance { + let kcfi_typeid = kcfi_typeid_for_instance(self.tcx, &instance, options); + self.set_kcfi_type_metadata(llfn, kcfi_typeid); + } else { + let kcfi_typeid = kcfi_typeid_for_fnabi(self.tcx, fn_abi, options); + self.set_kcfi_type_metadata(llfn, kcfi_typeid); + } } llfn diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index 00d1796f210..4e28034a850 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -772,7 +772,7 @@ fn gen_fn<'ll, 'tcx>( ) -> (&'ll Type, &'ll Value) { let fn_abi = cx.fn_abi_of_fn_ptr(rust_fn_sig, ty::List::empty()); let llty = fn_abi.llvm_type(cx); - let llfn = cx.declare_fn(name, fn_abi); + let llfn = cx.declare_fn(name, fn_abi, None); cx.set_frame_pointer_type(llfn); cx.apply_target_cpu_attr(llfn); // FIXME(eddyb) find a nicer way to do this. diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index 8305a0a4c28..6a86237d79e 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -37,7 +37,7 @@ use rustc_errors::{DiagnosticMessage, ErrorGuaranteed, FatalError, Handler, Subd use rustc_fluent_macro::fluent_messages; use rustc_metadata::EncodedMetadata; use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; -use rustc_middle::ty::query::Providers; +use rustc_middle::query::Providers; use rustc_middle::ty::TyCtxt; use rustc_session::config::{OptLevel, OutputFilenames, PrintRequest}; use rustc_session::Session; diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 61365e6dc4b..aefd5b2a13c 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -680,7 +680,9 @@ pub type InlineAsmDiagHandlerTy = unsafe extern "C" fn(&SMDiagnostic, *const c_v pub mod coverageinfo { use super::coverage_map; - /// Aligns with [llvm::coverage::CounterMappingRegion::RegionKind](https://github.com/rust-lang/llvm-project/blob/rustc/13.0-2021-09-30/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L209-L230) + /// Corresponds to enum `llvm::coverage::CounterMappingRegion::RegionKind`. + /// + /// Must match the layout of `LLVMRustCounterMappingRegionKind`. #[derive(Copy, Clone, Debug)] #[repr(C)] pub enum RegionKind { @@ -714,7 +716,9 @@ pub mod coverageinfo { /// array", encoded separately), and source location (start and end positions of the represented /// code region). /// - /// Matches LLVMRustCounterMappingRegion. + /// Corresponds to struct `llvm::coverage::CounterMappingRegion`. + /// + /// Must match the layout of `LLVMRustCounterMappingRegion`. #[derive(Copy, Clone, Debug)] #[repr(C)] pub struct CounterMappingRegion { diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index 2fbdab9f8ce..994addf12eb 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -155,12 +155,6 @@ pub fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> SmallVec<[&'a str; 2] ("x86", "rdrand") => smallvec!["rdrnd"], ("x86", "bmi1") => smallvec!["bmi"], ("x86", "cmpxchg16b") => smallvec!["cx16"], - // FIXME: These aliases are misleading, and should be removed before avx512_target_feature is - // stabilized. They must remain until std::arch switches off them. - // rust#100752 - ("x86", "avx512vaes") => smallvec!["vaes"], - ("x86", "avx512gfni") => smallvec!["gfni"], - ("x86", "avx512vpclmulqdq") => smallvec!["vpclmulqdq"], ("aarch64", "rcpc2") => smallvec!["rcpc-immo"], ("aarch64", "dpb") => smallvec!["ccpp"], ("aarch64", "dpb2") => smallvec!["ccdp"], diff --git a/compiler/rustc_codegen_llvm/src/mono_item.rs b/compiler/rustc_codegen_llvm/src/mono_item.rs index 59bdc60830f..e8f8c321510 100644 --- a/compiler/rustc_codegen_llvm/src/mono_item.rs +++ b/compiler/rustc_codegen_llvm/src/mono_item.rs @@ -51,7 +51,7 @@ impl<'tcx> PreDefineMethods<'tcx> for CodegenCx<'_, 'tcx> { assert!(!instance.substs.has_infer()); let fn_abi = self.fn_abi_of_instance(instance, ty::List::empty()); - let lldecl = self.declare_fn(symbol_name, fn_abi); + let lldecl = self.declare_fn(symbol_name, fn_abi, Some(instance)); unsafe { llvm::LLVMRustSetLinkage(lldecl, base::linkage_to_llvm(linkage)) }; let attrs = self.tcx.codegen_fn_attrs(instance.def_id()); base::set_link_section(lldecl, attrs); diff --git a/compiler/rustc_codegen_ssa/Cargo.toml b/compiler/rustc_codegen_ssa/Cargo.toml index 4f73b731f5a..02be88df103 100644 --- a/compiler/rustc_codegen_ssa/Cargo.toml +++ b/compiler/rustc_codegen_ssa/Cargo.toml @@ -51,5 +51,5 @@ default-features = false features = ["read_core", "elf", "macho", "pe", "unaligned", "archive", "write"] [target.'cfg(windows)'.dependencies.windows] -version = "0.46.0" +version = "0.48.0" features = ["Win32_Globalization"] diff --git a/compiler/rustc_codegen_ssa/src/back/metadata.rs b/compiler/rustc_codegen_ssa/src/back/metadata.rs index 8968133bac5..8bf84772f08 100644 --- a/compiler/rustc_codegen_ssa/src/back/metadata.rs +++ b/compiler/rustc_codegen_ssa/src/back/metadata.rs @@ -14,8 +14,7 @@ use snap::write::FrameEncoder; use object::elf::NT_GNU_PROPERTY_TYPE_0; use rustc_data_structures::memmap::Mmap; -use rustc_data_structures::owned_slice::try_slice_owned; -use rustc_data_structures::sync::MetadataRef; +use rustc_data_structures::owned_slice::{try_slice_owned, OwnedSlice}; use rustc_metadata::fs::METADATA_FILENAME; use rustc_metadata::EncodedMetadata; use rustc_session::cstore::MetadataLoader; @@ -39,7 +38,7 @@ pub struct DefaultMetadataLoader; fn load_metadata_with( path: &Path, f: impl for<'a> FnOnce(&'a [u8]) -> Result<&'a [u8], String>, -) -> Result<MetadataRef, String> { +) -> Result<OwnedSlice, String> { let file = File::open(path).map_err(|e| format!("failed to open file '{}': {}", path.display(), e))?; @@ -49,7 +48,7 @@ fn load_metadata_with( } impl MetadataLoader for DefaultMetadataLoader { - fn get_rlib_metadata(&self, _target: &Target, path: &Path) -> Result<MetadataRef, String> { + fn get_rlib_metadata(&self, _target: &Target, path: &Path) -> Result<OwnedSlice, String> { load_metadata_with(path, |data| { let archive = object::read::archive::ArchiveFile::parse(&*data) .map_err(|e| format!("failed to parse rlib '{}': {}", path.display(), e))?; @@ -69,7 +68,7 @@ impl MetadataLoader for DefaultMetadataLoader { }) } - fn get_dylib_metadata(&self, _target: &Target, path: &Path) -> Result<MetadataRef, String> { + fn get_dylib_metadata(&self, _target: &Target, path: &Path) -> Result<OwnedSlice, String> { load_metadata_with(path, |data| search_for_section(path, data, ".rustc")) } } diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs index 8f2f829c17c..14460efc1b0 100644 --- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs +++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs @@ -11,7 +11,7 @@ use rustc_middle::middle::exported_symbols::{ metadata_symbol_name, ExportedSymbol, SymbolExportInfo, SymbolExportKind, SymbolExportLevel, }; use rustc_middle::query::LocalCrate; -use rustc_middle::ty::query::{ExternProviders, Providers}; +use rustc_middle::query::{ExternProviders, Providers}; use rustc_middle::ty::subst::{GenericArgKind, SubstsRef}; use rustc_middle::ty::Instance; use rustc_middle::ty::{self, SymbolName, TyCtxt}; diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index ae45ae9d802..d9b0a152594 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -17,10 +17,7 @@ use rustc_ast::expand::allocator::AllocatorKind; use rustc_attr as attr; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::profiling::{get_resident_set_size, print_time_passes_entry}; - -use rustc_data_structures::sync::par_iter; -#[cfg(parallel_compiler)] -use rustc_data_structures::sync::ParallelIterator; +use rustc_data_structures::sync::par_map; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; use rustc_hir::lang_items::LangItem; @@ -30,8 +27,8 @@ use rustc_middle::middle::exported_symbols; use rustc_middle::middle::exported_symbols::SymbolExportKind; use rustc_middle::middle::lang_items; use rustc_middle::mir::mono::{CodegenUnit, CodegenUnitNameBuilder, MonoItem}; +use rustc_middle::query::Providers; use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, TyAndLayout}; -use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, Instance, Ty, TyCtxt}; use rustc_session::cgu_reuse_tracker::CguReuse; use rustc_session::config::{self, CrateType, EntryFnType, OutputType}; @@ -689,7 +686,7 @@ pub fn codegen_crate<B: ExtraBackendMethods>( // This likely is a temporary measure. Once we don't have to support the // non-parallel compiler anymore, we can compile CGUs end-to-end in // parallel and get rid of the complicated scheduling logic. - let mut pre_compiled_cgus = if cfg!(parallel_compiler) { + let mut pre_compiled_cgus = if tcx.sess.threads() > 1 { tcx.sess.time("compile_first_CGU_batch", || { // Try to find one CGU to compile per thread. let cgus: Vec<_> = cgu_reuse @@ -702,12 +699,10 @@ pub fn codegen_crate<B: ExtraBackendMethods>( // Compile the found CGUs in parallel. let start_time = Instant::now(); - let pre_compiled_cgus = par_iter(cgus) - .map(|(i, _)| { - let module = backend.compile_codegen_unit(tcx, codegen_units[i].name()); - (i, module) - }) - .collect(); + let pre_compiled_cgus = par_map(cgus, |(i, _)| { + let module = backend.compile_codegen_unit(tcx, codegen_units[i].name()); + (i, module) + }); total_codegen_time += start_time.elapsed(); diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index 8dae5dab429..d6c23012762 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -7,7 +7,7 @@ use rustc_hir::def_id::{DefId, LocalDefId, LOCAL_CRATE}; use rustc_hir::{lang_items, weak_lang_items::WEAK_LANG_ITEMS, LangItem}; use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs}; use rustc_middle::mir::mono::Linkage; -use rustc_middle::ty::query::Providers; +use rustc_middle::query::Providers; use rustc_middle::ty::{self as ty, TyCtxt}; use rustc_session::{lint, parse::feature_err}; use rustc_span::symbol::Ident; diff --git a/compiler/rustc_codegen_ssa/src/coverageinfo/ffi.rs b/compiler/rustc_codegen_ssa/src/coverageinfo/ffi.rs index e288760a02b..1791ce4b315 100644 --- a/compiler/rustc_codegen_ssa/src/coverageinfo/ffi.rs +++ b/compiler/rustc_codegen_ssa/src/coverageinfo/ffi.rs @@ -1,6 +1,6 @@ use rustc_middle::mir::coverage::{CounterValueReference, MappedExpressionIndex}; -/// Aligns with [llvm::coverage::Counter::CounterKind](https://github.com/rust-lang/llvm-project/blob/rustc/13.0-2021-09-30/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L95) +/// Must match the layout of `LLVMRustCounterKind`. #[derive(Copy, Clone, Debug)] #[repr(C)] pub enum CounterKind { @@ -17,8 +17,10 @@ pub enum CounterKind { /// `instrprof.increment()`) /// * For `CounterKind::Expression`, `id` is the index into the coverage map's array of /// counter expressions. -/// Aligns with [llvm::coverage::Counter](https://github.com/rust-lang/llvm-project/blob/rustc/13.0-2021-09-30/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L102-L103) -/// Important: The Rust struct layout (order and types of fields) must match its C++ counterpart. +/// +/// Corresponds to struct `llvm::coverage::Counter`. +/// +/// Must match the layout of `LLVMRustCounter`. #[derive(Copy, Clone, Debug)] #[repr(C)] pub struct Counter { @@ -59,7 +61,9 @@ impl Counter { } } -/// Aligns with [llvm::coverage::CounterExpression::ExprKind](https://github.com/rust-lang/llvm-project/blob/rustc/13.0-2021-09-30/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L150) +/// Corresponds to enum `llvm::coverage::CounterExpression::ExprKind`. +/// +/// Must match the layout of `LLVMRustCounterExprKind`. #[derive(Copy, Clone, Debug)] #[repr(C)] pub enum ExprKind { @@ -67,9 +71,9 @@ pub enum ExprKind { Add = 1, } -/// Aligns with [llvm::coverage::CounterExpression](https://github.com/rust-lang/llvm-project/blob/rustc/13.0-2021-09-30/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L151-L152) -/// Important: The Rust struct layout (order and types of fields) must match its C++ -/// counterpart. +/// Corresponds to struct `llvm::coverage::CounterExpression`. +/// +/// Must match the layout of `LLVMRustCounterExpression`. #[derive(Copy, Clone, Debug)] #[repr(C)] pub struct CounterExpression { diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs index c3cc17c255b..f4b9d1dea58 100644 --- a/compiler/rustc_codegen_ssa/src/lib.rs +++ b/compiler/rustc_codegen_ssa/src/lib.rs @@ -30,7 +30,7 @@ use rustc_hir::def_id::CrateNum; use rustc_middle::dep_graph::WorkProduct; use rustc_middle::middle::dependency_format::Dependencies; use rustc_middle::middle::exported_symbols::SymbolExportKind; -use rustc_middle::ty::query::{ExternProviders, Providers}; +use rustc_middle::query::{ExternProviders, Providers}; use rustc_serialize::opaque::{FileEncoder, MemDecoder}; use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; use rustc_session::config::{CrateType, OutputFilenames, OutputType, RUST_CGU_EXT}; diff --git a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs index 4e5e2dd5d50..bba2800fb05 100644 --- a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs +++ b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs @@ -8,7 +8,7 @@ use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf}; use rustc_session::config::DebugInfo; use rustc_span::symbol::{kw, Symbol}; use rustc_span::{BytePos, Span}; -use rustc_target::abi::{Abi, FieldIdx, Size, VariantIdx}; +use rustc_target::abi::{Abi, FieldIdx, FieldsShape, Size, VariantIdx}; use super::operand::{OperandRef, OperandValue}; use super::place::PlaceRef; @@ -41,6 +41,9 @@ pub struct PerLocalVarDebugInfo<'tcx, D> { /// `.place.projection` from `mir::VarDebugInfo`. pub projection: &'tcx ty::List<mir::PlaceElem<'tcx>>, + + /// `references` from `mir::VarDebugInfo`. + pub references: u8, } #[derive(Clone, Copy, Debug)] @@ -80,6 +83,7 @@ trait DebugInfoOffsetLocation<'tcx, Bx> { fn deref(&self, bx: &mut Bx) -> Self; fn layout(&self) -> TyAndLayout<'tcx>; fn project_field(&self, bx: &mut Bx, field: FieldIdx) -> Self; + fn project_constant_index(&self, bx: &mut Bx, offset: u64) -> Self; fn downcast(&self, bx: &mut Bx, variant: VariantIdx) -> Self; } @@ -98,6 +102,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> DebugInfoOffsetLocation<'tcx, Bx> PlaceRef::project_field(*self, bx, field.index()) } + fn project_constant_index(&self, bx: &mut Bx, offset: u64) -> Self { + let lloffset = bx.cx().const_usize(offset); + self.project_index(bx, lloffset) + } + fn downcast(&self, bx: &mut Bx, variant: VariantIdx) -> Self { self.project_downcast(bx, variant) } @@ -120,6 +129,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> DebugInfoOffsetLocation<'tcx, Bx> self.field(bx.cx(), field.index()) } + fn project_constant_index(&self, bx: &mut Bx, index: u64) -> Self { + self.field(bx.cx(), index as usize) + } + fn downcast(&self, bx: &mut Bx, variant: VariantIdx) -> Self { self.for_variant(bx.cx(), variant) } @@ -165,6 +178,18 @@ fn calculate_debuginfo_offset< mir::ProjectionElem::Downcast(_, variant) => { place = place.downcast(bx, variant); } + mir::ProjectionElem::ConstantIndex { + offset: index, + min_length: _, + from_end: false, + } => { + let offset = indirect_offsets.last_mut().unwrap_or(&mut direct_offset); + let FieldsShape::Array { stride, count: _ } = place.layout().fields else { + span_bug!(var.source_info.span, "ConstantIndex on non-array type {:?}", place.layout()) + }; + *offset += stride * index; + place = place.project_constant_index(bx, index); + } _ => { // Sanity check for `can_use_in_debuginfo`. debug_assert!(!elem.can_use_in_debuginfo()); @@ -293,6 +318,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { dbg_var, fragment: None, projection: ty::List::empty(), + references: 0, }) } } else { @@ -358,55 +384,74 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let vars = vars.iter().cloned().chain(fallback_var); for var in vars { - let Some(dbg_var) = var.dbg_var else { continue }; - let Some(dbg_loc) = self.dbg_loc(var.source_info) else { continue }; - - let DebugInfoOffset { direct_offset, indirect_offsets, result: _ } = - calculate_debuginfo_offset(bx, local, &var, base.layout); - - // When targeting MSVC, create extra allocas for arguments instead of pointing multiple - // dbg_var_addr() calls into the same alloca with offsets. MSVC uses CodeView records - // not DWARF and LLVM doesn't support translating the resulting - // [DW_OP_deref, DW_OP_plus_uconst, offset, DW_OP_deref] debug info to CodeView. - // Creating extra allocas on the stack makes the resulting debug info simple enough - // that LLVM can generate correct CodeView records and thus the values appear in the - // debugger. (#83709) - let should_create_individual_allocas = bx.cx().sess().target.is_like_msvc - && self.mir.local_kind(local) == mir::LocalKind::Arg - // LLVM can handle simple things but anything more complex than just a direct - // offset or one indirect offset of 0 is too complex for it to generate CV records - // correctly. - && (direct_offset != Size::ZERO - || !matches!(&indirect_offsets[..], [Size::ZERO] | [])); - - if should_create_individual_allocas { - let DebugInfoOffset { direct_offset: _, indirect_offsets: _, result: place } = - calculate_debuginfo_offset(bx, local, &var, base); - - // Create a variable which will be a pointer to the actual value - let ptr_ty = bx - .tcx() - .mk_ptr(ty::TypeAndMut { mutbl: mir::Mutability::Mut, ty: place.layout.ty }); - let ptr_layout = bx.layout_of(ptr_ty); - let alloca = PlaceRef::alloca(bx, ptr_layout); - bx.set_var_name(alloca.llval, &(var.name.to_string() + ".dbg.spill")); - - // Write the pointer to the variable - bx.store(place.llval, alloca.llval, alloca.align); - - // Point the debug info to `*alloca` for the current variable - bx.dbg_var_addr(dbg_var, dbg_loc, alloca.llval, Size::ZERO, &[Size::ZERO], None); - } else { - bx.dbg_var_addr( - dbg_var, - dbg_loc, - base.llval, - direct_offset, - &indirect_offsets, - None, - ); + self.debug_introduce_local_as_var(bx, local, base, var); + } + } + + fn debug_introduce_local_as_var( + &self, + bx: &mut Bx, + local: mir::Local, + mut base: PlaceRef<'tcx, Bx::Value>, + var: PerLocalVarDebugInfo<'tcx, Bx::DIVariable>, + ) { + let Some(dbg_var) = var.dbg_var else { return }; + let Some(dbg_loc) = self.dbg_loc(var.source_info) else { return }; + + let DebugInfoOffset { mut direct_offset, indirect_offsets, result: _ } = + calculate_debuginfo_offset(bx, local, &var, base.layout); + let mut indirect_offsets = &indirect_offsets[..]; + + // When targeting MSVC, create extra allocas for arguments instead of pointing multiple + // dbg_var_addr() calls into the same alloca with offsets. MSVC uses CodeView records + // not DWARF and LLVM doesn't support translating the resulting + // [DW_OP_deref, DW_OP_plus_uconst, offset, DW_OP_deref] debug info to CodeView. + // Creating extra allocas on the stack makes the resulting debug info simple enough + // that LLVM can generate correct CodeView records and thus the values appear in the + // debugger. (#83709) + let should_create_individual_allocas = bx.cx().sess().target.is_like_msvc + && self.mir.local_kind(local) == mir::LocalKind::Arg + // LLVM can handle simple things but anything more complex than just a direct + // offset or one indirect offset of 0 is too complex for it to generate CV records + // correctly. + && (direct_offset != Size::ZERO || !matches!(indirect_offsets, [Size::ZERO] | [])); + + let create_alloca = |bx: &mut Bx, place: PlaceRef<'tcx, Bx::Value>, refcount| { + // Create a variable which will be a pointer to the actual value + let ptr_ty = bx + .tcx() + .mk_ptr(ty::TypeAndMut { mutbl: mir::Mutability::Mut, ty: place.layout.ty }); + let ptr_layout = bx.layout_of(ptr_ty); + let alloca = PlaceRef::alloca(bx, ptr_layout); + bx.set_var_name(alloca.llval, &format!("{}.ref{}.dbg.spill", var.name, refcount)); + + // Write the pointer to the variable + bx.store(place.llval, alloca.llval, alloca.align); + + // Point the debug info to `*alloca` for the current variable + alloca + }; + + if var.references > 0 { + base = calculate_debuginfo_offset(bx, local, &var, base).result; + + // Point the debug info to `&...&base == alloca` for the current variable + for refcount in 0..var.references { + base = create_alloca(bx, base, refcount); } + + direct_offset = Size::ZERO; + indirect_offsets = &[]; + } else if should_create_individual_allocas { + let place = calculate_debuginfo_offset(bx, local, &var, base).result; + + // Point the debug info to `*alloca` for the current variable + base = create_alloca(bx, place, 0); + direct_offset = Size::ZERO; + indirect_offsets = &[Size::ZERO]; } + + bx.dbg_var_addr(dbg_var, dbg_loc, base.llval, direct_offset, indirect_offsets, None); } pub fn debug_introduce_locals(&self, bx: &mut Bx) { @@ -439,7 +484,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { }; let dbg_var = dbg_scope_and_span.map(|(dbg_scope, _, span)| { - let (var_ty, var_kind) = match var.value { + let (mut var_ty, var_kind) = match var.value { mir::VarDebugInfoContents::Place(place) => { let var_ty = self.monomorphized_place_ty(place.as_ref()); let var_kind = if let Some(arg_index) = var.argument_index @@ -476,6 +521,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } }; + for _ in 0..var.references { + var_ty = + bx.tcx().mk_ptr(ty::TypeAndMut { mutbl: mir::Mutability::Mut, ty: var_ty }); + } + self.cx.create_dbg_var(var.name, var_ty, dbg_scope, var_kind, span) }); @@ -487,6 +537,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { dbg_var, fragment: None, projection: place.projection, + references: var.references, }); } mir::VarDebugInfoContents::Const(c) => { @@ -540,6 +591,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { Some(fragment_start..fragment_start + fragment_layout.size) }, projection: place.projection, + references: var.references, }); } } diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs index 9efbb34b515..2301c3ef13e 100644 --- a/compiler/rustc_codegen_ssa/src/mir/operand.rs +++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs @@ -402,8 +402,6 @@ impl<'a, 'tcx, V: CodegenObject> OperandValue<V> { indirect_dest: PlaceRef<'tcx, V>, ) { debug!("OperandRef::store_unsized: operand={:?}, indirect_dest={:?}", self, indirect_dest); - let flags = MemFlags::empty(); - // `indirect_dest` must have `*mut T` type. We extract `T` out of it. let unsized_ty = indirect_dest .layout @@ -416,17 +414,23 @@ impl<'a, 'tcx, V: CodegenObject> OperandValue<V> { bug!("store_unsized called with a sized value") }; - // FIXME: choose an appropriate alignment, or use dynamic align somehow - let max_align = Align::from_bits(128).unwrap(); - let min_align = Align::from_bits(8).unwrap(); - - // Allocate an appropriate region on the stack, and copy the value into it - let (llsize, _) = glue::size_and_align_of_dst(bx, unsized_ty, Some(llextra)); - let lldst = bx.byte_array_alloca(llsize, max_align); - bx.memcpy(lldst, max_align, llptr, min_align, llsize, flags); + // Allocate an appropriate region on the stack, and copy the value into it. Since alloca + // doesn't support dynamic alignment, we allocate an extra align - 1 bytes, and align the + // pointer manually. + let (size, align) = glue::size_and_align_of_dst(bx, unsized_ty, Some(llextra)); + let one = bx.const_usize(1); + let align_minus_1 = bx.sub(align, one); + let size_extra = bx.add(size, align_minus_1); + let min_align = Align::ONE; + let alloca = bx.byte_array_alloca(size_extra, min_align); + let address = bx.ptrtoint(alloca, bx.type_isize()); + let neg_address = bx.neg(address); + let offset = bx.and(neg_address, align_minus_1); + let dst = bx.inbounds_gep(bx.type_i8(), alloca, &[offset]); + bx.memcpy(dst, min_align, llptr, min_align, size, MemFlags::empty()); // Store the allocated region and the extra to the indirect place. - let indirect_operand = OperandValue::Pair(lldst, llextra); + let indirect_operand = OperandValue::Pair(dst, llextra); indirect_operand.store(bx, indirect_dest); } } diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs index 1cfc4b933a8..3719283cccc 100644 --- a/compiler/rustc_codegen_ssa/src/target_features.rs +++ b/compiler/rustc_codegen_ssa/src/target_features.rs @@ -8,7 +8,7 @@ use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; use rustc_hir::def_id::LocalDefId; use rustc_hir::def_id::LOCAL_CRATE; -use rustc_middle::ty::query::Providers; +use rustc_middle::query::Providers; use rustc_middle::ty::TyCtxt; use rustc_session::parse::feature_err; use rustc_session::Session; @@ -173,16 +173,13 @@ const X86_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[ ("avx512dq", Some(sym::avx512_target_feature)), ("avx512er", Some(sym::avx512_target_feature)), ("avx512f", Some(sym::avx512_target_feature)), - ("avx512gfni", Some(sym::avx512_target_feature)), ("avx512ifma", Some(sym::avx512_target_feature)), ("avx512pf", Some(sym::avx512_target_feature)), - ("avx512vaes", Some(sym::avx512_target_feature)), ("avx512vbmi", Some(sym::avx512_target_feature)), ("avx512vbmi2", Some(sym::avx512_target_feature)), ("avx512vl", Some(sym::avx512_target_feature)), ("avx512vnni", Some(sym::avx512_target_feature)), ("avx512vp2intersect", Some(sym::avx512_target_feature)), - ("avx512vpclmulqdq", Some(sym::avx512_target_feature)), ("avx512vpopcntdq", Some(sym::avx512_target_feature)), ("bmi1", None), ("bmi2", None), diff --git a/compiler/rustc_codegen_ssa/src/traits/backend.rs b/compiler/rustc_codegen_ssa/src/traits/backend.rs index 64bebe50ddb..d83bfc74082 100644 --- a/compiler/rustc_codegen_ssa/src/traits/backend.rs +++ b/compiler/rustc_codegen_ssa/src/traits/backend.rs @@ -1,3 +1,5 @@ +use std::any::Any; + use super::write::WriteBackendMethods; use super::CodegenObject; use crate::back::write::TargetMachineFactoryFn; @@ -5,11 +7,12 @@ use crate::{CodegenResults, ModuleCodegen}; use rustc_ast::expand::allocator::AllocatorKind; use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::sync::{DynSend, DynSync}; use rustc_errors::ErrorGuaranteed; use rustc_metadata::EncodedMetadata; use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; +use rustc_middle::query::{ExternProviders, Providers}; use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, LayoutOf, TyAndLayout}; -use rustc_middle::ty::query::{ExternProviders, Providers}; use rustc_middle::ty::{Ty, TyCtxt}; use rustc_session::{ config::{self, OutputFilenames, PrintRequest}, @@ -20,10 +23,6 @@ use rustc_span::symbol::Symbol; use rustc_target::abi::call::FnAbi; use rustc_target::spec::Target; -pub use rustc_data_structures::sync::MetadataRef; - -use std::any::Any; - pub trait BackendTypes { type Value: CodegenObject; type Function: CodegenObject; @@ -117,7 +116,9 @@ pub trait CodegenBackend { ) -> Result<(), ErrorGuaranteed>; } -pub trait ExtraBackendMethods: CodegenBackend + WriteBackendMethods + Sized + Send + Sync { +pub trait ExtraBackendMethods: + CodegenBackend + WriteBackendMethods + Sized + Send + Sync + DynSend + DynSync +{ fn codegen_allocator<'tcx>( &self, tcx: TyCtxt<'tcx>, diff --git a/compiler/rustc_const_eval/src/const_eval/error.rs b/compiler/rustc_const_eval/src/const_eval/error.rs index cdef3fb2339..5037c210e7d 100644 --- a/compiler/rustc_const_eval/src/const_eval/error.rs +++ b/compiler/rustc_const_eval/src/const_eval/error.rs @@ -169,14 +169,14 @@ impl<'tcx> ConstEvalErr<'tcx> { // See <https://github.com/rust-lang/rust/pull/63152>. let mut err = struct_error(tcx, &self.error.to_string()); self.decorate(&mut err, decorate); - ErrorHandled::Reported(err.emit()) + ErrorHandled::Reported(err.emit().into()) } _ => { // Report as hard error. let mut err = struct_error(tcx, message); err.span_label(self.span, self.error.to_string()); self.decorate(&mut err, decorate); - ErrorHandled::Reported(err.emit()) + ErrorHandled::Reported(err.emit().into()) } } } diff --git a/compiler/rustc_const_eval/src/const_eval/fn_queries.rs b/compiler/rustc_const_eval/src/const_eval/fn_queries.rs index 088a824fd8f..fa8253d5e49 100644 --- a/compiler/rustc_const_eval/src/const_eval/fn_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/fn_queries.rs @@ -2,7 +2,7 @@ use rustc_attr as attr; use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId}; -use rustc_middle::ty::query::Providers; +use rustc_middle::query::Providers; use rustc_middle::ty::TyCtxt; use rustc_span::symbol::Symbol; diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index 814b67b46ec..58b5755af07 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -382,7 +382,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, rustc_span::DUMMY_SP, "This is likely a const item that is missing from its impl", ); - throw_inval!(AlreadyReported(guar)); + throw_inval!(AlreadyReported(guar.into())); } else { // `find_mir_or_eval_fn` checks that this is a const fn before even calling us, // so this should be unreachable. diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs index b2197a0aabb..2fa63dc8c93 100644 --- a/compiler/rustc_const_eval/src/interpret/eval_context.rs +++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs @@ -7,7 +7,7 @@ use either::{Either, Left, Right}; use rustc_hir::{self as hir, def_id::DefId, definitions::DefPathData}; use rustc_index::IndexVec; use rustc_middle::mir; -use rustc_middle::mir::interpret::{ErrorHandled, InterpError}; +use rustc_middle::mir::interpret::{ErrorHandled, InterpError, ReportedErrorInfo}; use rustc_middle::ty::layout::{ self, FnAbiError, FnAbiOfHelpers, FnAbiRequest, LayoutError, LayoutOf, LayoutOfHelpers, TyAndLayout, @@ -470,7 +470,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { }; // do not continue if typeck errors occurred (can only occur in local crate) if let Some(err) = body.tainted_by_errors { - throw_inval!(AlreadyReported(err)); + throw_inval!(AlreadyReported(ReportedErrorInfo::tainted_by_errors(err))); } Ok(body) } @@ -517,7 +517,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Ok(None) => throw_inval!(TooGeneric), // FIXME(eddyb) this could be a bit more specific than `AlreadyReported`. - Err(error_reported) => throw_inval!(AlreadyReported(error_reported)), + Err(error_reported) => throw_inval!(AlreadyReported(error_reported.into())), } } @@ -905,7 +905,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { query(self.tcx.at(span.unwrap_or_else(|| self.cur_span()))).map_err(|err| { match err { ErrorHandled::Reported(err) => { - if let Some(span) = span { + if !err.is_tainted_by_errors() && let Some(span) = span { // To make it easier to figure out where this error comes from, also add a note at the current location. self.tcx.sess.span_note_without_error(span, "erroneous constant used"); } diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs index a7f66071fe2..e30af165501 100644 --- a/compiler/rustc_const_eval/src/interpret/operand.rs +++ b/compiler/rustc_const_eval/src/interpret/operand.rs @@ -595,7 +595,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // FIXME(generic_const_exprs): `ConstKind::Expr` should be able to be evaluated ty::ConstKind::Expr(_) => throw_inval!(TooGeneric), ty::ConstKind::Error(reported) => { - throw_inval!(AlreadyReported(reported)) + throw_inval!(AlreadyReported(reported.into())) } ty::ConstKind::Unevaluated(uv) => { let instance = self.resolve(uv.def, uv.substs)?; diff --git a/compiler/rustc_const_eval/src/lib.rs b/compiler/rustc_const_eval/src/lib.rs index 1b66eca97a5..c36282d5ed4 100644 --- a/compiler/rustc_const_eval/src/lib.rs +++ b/compiler/rustc_const_eval/src/lib.rs @@ -35,8 +35,8 @@ pub mod util; use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage}; use rustc_fluent_macro::fluent_messages; +use rustc_middle::query::Providers; use rustc_middle::ty; -use rustc_middle::ty::query::Providers; fluent_messages! { "../messages.ftl" } diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs index f46c2d00fe4..3c350e25ba6 100644 --- a/compiler/rustc_const_eval/src/transform/validate.rs +++ b/compiler/rustc_const_eval/src/transform/validate.rs @@ -164,7 +164,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { if let Some(root) = post_contract_node.get(&bb) { break *root; } - let parent = doms.immediate_dominator(bb); + let parent = doms.immediate_dominator(bb).unwrap(); dom_path.push(bb); if !self.body.basic_blocks[parent].is_cleanup { break bb; @@ -448,7 +448,15 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { }; match debuginfo.value { VarDebugInfoContents::Const(_) => {} - VarDebugInfoContents::Place(place) => check_place(place), + VarDebugInfoContents::Place(place) => { + check_place(place); + if debuginfo.references != 0 && place.projection.last() == Some(&PlaceElem::Deref) { + self.fail( + START_BLOCK.start_location(), + format!("debuginfo {:?}, has both ref and deref", debuginfo), + ); + } + } VarDebugInfoContents::Composite { ty, ref fragments } => { for f in fragments { check_place(f.contents); diff --git a/compiler/rustc_data_structures/Cargo.toml b/compiler/rustc_data_structures/Cargo.toml index 5e05fe463ed..78f73d193e3 100644 --- a/compiler/rustc_data_structures/Cargo.toml +++ b/compiler/rustc_data_structures/Cargo.toml @@ -16,6 +16,7 @@ libc = "0.2" measureme = "10.0.0" rustc-rayon-core = { version = "0.5.0", optional = true } rustc-rayon = { version = "0.5.0", optional = true } +rustc_arena = { path = "../rustc_arena" } rustc_graphviz = { path = "../rustc_graphviz" } rustc-hash = "1.1.0" rustc_index = { path = "../rustc_index", package = "rustc_index" } @@ -37,7 +38,7 @@ itertools = "0.10.1" version = "0.11" [target.'cfg(windows)'.dependencies.windows] -version = "0.46.0" +version = "0.48.0" features = [ "Win32_Foundation", "Win32_Storage_FileSystem", diff --git a/compiler/rustc_data_structures/src/graph/dominators/mod.rs b/compiler/rustc_data_structures/src/graph/dominators/mod.rs index e76bdac2864..a7de709ba72 100644 --- a/compiler/rustc_data_structures/src/graph/dominators/mod.rs +++ b/compiler/rustc_data_structures/src/graph/dominators/mod.rs @@ -242,7 +242,9 @@ pub fn dominators<G: ControlFlowGraph>(graph: G) -> Dominators<G::Node> { immediate_dominators[*node] = Some(pre_order_to_real[idom[idx]]); } - Dominators { post_order_rank, immediate_dominators } + let start_node = graph.start_node(); + immediate_dominators[start_node] = None; + Dominators { start_node, post_order_rank, immediate_dominators } } /// Evaluate the link-eval virtual forest, providing the currently minimum semi @@ -308,6 +310,7 @@ fn compress( /// Tracks the list of dominators for each node. #[derive(Clone, Debug)] pub struct Dominators<N: Idx> { + start_node: N, post_order_rank: IndexVec<N, usize>, // Even though we track only the immediate dominator of each node, it's // possible to get its full list of dominators by looking up the dominator @@ -316,14 +319,14 @@ pub struct Dominators<N: Idx> { } impl<Node: Idx> Dominators<Node> { - /// Whether the given Node has an immediate dominator. + /// Returns true if node is reachable from the start node. pub fn is_reachable(&self, node: Node) -> bool { - self.immediate_dominators[node].is_some() + node == self.start_node || self.immediate_dominators[node].is_some() } - pub fn immediate_dominator(&self, node: Node) -> Node { - assert!(self.is_reachable(node), "node {node:?} is not reachable"); - self.immediate_dominators[node].unwrap() + /// Returns the immediate dominator of node, if any. + pub fn immediate_dominator(&self, node: Node) -> Option<Node> { + self.immediate_dominators[node] } /// Provides an iterator over each dominator up the CFG, for the given Node. @@ -357,12 +360,7 @@ impl<'dom, Node: Idx> Iterator for Iter<'dom, Node> { fn next(&mut self) -> Option<Self::Item> { if let Some(node) = self.node { - let dom = self.dominators.immediate_dominator(node); - if dom == node { - self.node = None; // reached the root - } else { - self.node = Some(dom); - } + self.node = self.dominators.immediate_dominator(node); Some(node) } else { None diff --git a/compiler/rustc_data_structures/src/graph/dominators/tests.rs b/compiler/rustc_data_structures/src/graph/dominators/tests.rs index ff31d8f7fdc..8b124516623 100644 --- a/compiler/rustc_data_structures/src/graph/dominators/tests.rs +++ b/compiler/rustc_data_structures/src/graph/dominators/tests.rs @@ -8,7 +8,7 @@ fn diamond() { let dominators = dominators(&graph); let immediate_dominators = &dominators.immediate_dominators; - assert_eq!(immediate_dominators[0], Some(0)); + assert_eq!(immediate_dominators[0], None); assert_eq!(immediate_dominators[1], Some(0)); assert_eq!(immediate_dominators[2], Some(0)); assert_eq!(immediate_dominators[3], Some(0)); @@ -30,7 +30,7 @@ fn paper() { assert_eq!(immediate_dominators[3], Some(6)); assert_eq!(immediate_dominators[4], Some(6)); assert_eq!(immediate_dominators[5], Some(6)); - assert_eq!(immediate_dominators[6], Some(6)); + assert_eq!(immediate_dominators[6], None); } #[test] @@ -43,3 +43,13 @@ fn paper_slt() { dominators(&graph); } + +#[test] +fn immediate_dominator() { + let graph = TestGraph::new(1, &[(1, 2), (2, 3)]); + let dominators = dominators(&graph); + assert_eq!(dominators.immediate_dominator(0), None); + assert_eq!(dominators.immediate_dominator(1), None); + assert_eq!(dominators.immediate_dominator(2), Some(1)); + assert_eq!(dominators.immediate_dominator(3), Some(2)); +} diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs index 004017ec5f3..5b9b0e106d2 100644 --- a/compiler/rustc_data_structures/src/lib.rs +++ b/compiler/rustc_data_structures/src/lib.rs @@ -26,6 +26,7 @@ #![feature(test)] #![feature(thread_id_value)] #![feature(vec_into_raw_parts)] +#![feature(allocator_api)] #![feature(get_mut_unchecked)] #![feature(lint_reasons)] #![feature(unwrap_infallible)] @@ -77,6 +78,7 @@ pub mod sorted_map; pub mod stable_hasher; mod atomic_ref; pub mod fingerprint; +pub mod marker; pub mod profiling; pub mod sharded; pub mod stack; diff --git a/compiler/rustc_data_structures/src/marker.rs b/compiler/rustc_data_structures/src/marker.rs new file mode 100644 index 00000000000..f8c06f9a814 --- /dev/null +++ b/compiler/rustc_data_structures/src/marker.rs @@ -0,0 +1,257 @@ +cfg_if!( + if #[cfg(not(parallel_compiler))] { + pub auto trait DynSend {} + pub auto trait DynSync {} + + impl<T> DynSend for T {} + impl<T> DynSync for T {} + } else { + #[rustc_on_unimplemented( + message = "`{Self}` doesn't implement `DynSend`. \ + Add it to `rustc_data_structures::marker` or use `IntoDynSyncSend` if it's already `Send`" + )] + // This is an auto trait for types which can be sent across threads if `sync::is_dyn_thread_safe()` + // is true. These types can be wrapped in a `FromDyn` to get a `Send` type. Wrapping a + // `Send` type in `IntoDynSyncSend` will create a `DynSend` type. + pub unsafe auto trait DynSend {} + + #[rustc_on_unimplemented( + message = "`{Self}` doesn't implement `DynSync`. \ + Add it to `rustc_data_structures::marker` or use `IntoDynSyncSend` if it's already `Sync`" + )] + // This is an auto trait for types which can be shared across threads if `sync::is_dyn_thread_safe()` + // is true. These types can be wrapped in a `FromDyn` to get a `Sync` type. Wrapping a + // `Sync` type in `IntoDynSyncSend` will create a `DynSync` type. + pub unsafe auto trait DynSync {} + + // Same with `Sync` and `Send`. + unsafe impl<T: DynSync + ?Sized> DynSend for &T {} + + macro_rules! impls_dyn_send_neg { + ($([$t1: ty $(where $($generics1: tt)*)?])*) => { + $(impl$(<$($generics1)*>)? !DynSend for $t1 {})* + }; + } + + // Consistent with `std` + impls_dyn_send_neg!( + [std::env::Args] + [std::env::ArgsOs] + [*const T where T: ?Sized] + [*mut T where T: ?Sized] + [std::ptr::NonNull<T> where T: ?Sized] + [std::rc::Rc<T> where T: ?Sized] + [std::rc::Weak<T> where T: ?Sized] + [std::sync::MutexGuard<'_, T> where T: ?Sized] + [std::sync::RwLockReadGuard<'_, T> where T: ?Sized] + [std::sync::RwLockWriteGuard<'_, T> where T: ?Sized] + [std::io::StdoutLock<'_>] + [std::io::StderrLock<'_>] + ); + cfg_if!( + // Consistent with `std` + // `os_imp::Env` is `!Send` in these platforms + if #[cfg(any(unix, target_os = "hermit", target_os = "wasi", target_os = "solid_asp3"))] { + impl !DynSend for std::env::VarsOs {} + } + ); + + macro_rules! already_send { + ($([$ty: ty])*) => { + $(unsafe impl DynSend for $ty where $ty: Send {})* + }; + } + + // These structures are already `Send`. + already_send!( + [std::backtrace::Backtrace] + [std::io::Stdout] + [std::io::Stderr] + [std::io::Error] + [std::fs::File] + [rustc_arena::DroplessArena] + [crate::memmap::Mmap] + [crate::profiling::SelfProfiler] + [crate::owned_slice::OwnedSlice] + ); + + macro_rules! impl_dyn_send { + ($($($attr: meta)* [$ty: ty where $($generics2: tt)*])*) => { + $(unsafe impl<$($generics2)*> DynSend for $ty {})* + }; + } + + impl_dyn_send!( + [std::sync::atomic::AtomicPtr<T> where T] + [std::sync::Mutex<T> where T: ?Sized+ DynSend] + [std::sync::mpsc::Sender<T> where T: DynSend] + [std::sync::Arc<T> where T: ?Sized + DynSync + DynSend] + [std::sync::LazyLock<T, F> where T: DynSend, F: DynSend] + [std::collections::HashSet<K, S> where K: DynSend, S: DynSend] + [std::collections::HashMap<K, V, S> where K: DynSend, V: DynSend, S: DynSend] + [std::collections::BTreeMap<K, V, A> where K: DynSend, V: DynSend, A: std::alloc::Allocator + Clone + DynSend] + [Vec<T, A> where T: DynSend, A: std::alloc::Allocator + DynSend] + [Box<T, A> where T: ?Sized + DynSend, A: std::alloc::Allocator + DynSend] + [crate::sync::Lock<T> where T: DynSend] + [crate::sync::RwLock<T> where T: DynSend] + [crate::tagged_ptr::CopyTaggedPtr<P, T, CP> where P: Send + crate::tagged_ptr::Pointer, T: Send + crate::tagged_ptr::Tag, const CP: bool] + [rustc_arena::TypedArena<T> where T: DynSend] + [indexmap::IndexSet<V, S> where V: DynSend, S: DynSend] + [indexmap::IndexMap<K, V, S> where K: DynSend, V: DynSend, S: DynSend] + [thin_vec::ThinVec<T> where T: DynSend] + [smallvec::SmallVec<A> where A: smallvec::Array + DynSend] + ); + + macro_rules! impls_dyn_sync_neg { + ($([$t1: ty $(where $($generics1: tt)*)?])*) => { + $(impl$(<$($generics1)*>)? !DynSync for $t1 {})* + }; + } + + // Consistent with `std` + impls_dyn_sync_neg!( + [std::env::Args] + [std::env::ArgsOs] + [*const T where T: ?Sized] + [*mut T where T: ?Sized] + [std::cell::Cell<T> where T: ?Sized] + [std::cell::RefCell<T> where T: ?Sized] + [std::cell::UnsafeCell<T> where T: ?Sized] + [std::ptr::NonNull<T> where T: ?Sized] + [std::rc::Rc<T> where T: ?Sized] + [std::rc::Weak<T> where T: ?Sized] + [std::cell::OnceCell<T> where T] + [std::sync::mpsc::Receiver<T> where T] + [std::sync::mpsc::Sender<T> where T] + ); + cfg_if!( + // Consistent with `std` + // `os_imp::Env` is `!Sync` in these platforms + if #[cfg(any(unix, target_os = "hermit", target_os = "wasi", target_os = "solid_asp3"))] { + impl !DynSync for std::env::VarsOs {} + } + ); + + macro_rules! already_sync { + ($([$ty: ty])*) => { + $(unsafe impl DynSync for $ty where $ty: Sync {})* + }; + } + + // These structures are already `Sync`. + already_sync!( + [std::sync::atomic::AtomicBool] + [std::sync::atomic::AtomicUsize] + [std::sync::atomic::AtomicU8] + [std::sync::atomic::AtomicU32] + [std::sync::atomic::AtomicU64] + [std::backtrace::Backtrace] + [std::io::Error] + [std::fs::File] + [jobserver_crate::Client] + [crate::memmap::Mmap] + [crate::profiling::SelfProfiler] + [crate::owned_slice::OwnedSlice] + ); + + macro_rules! impl_dyn_sync { + ($($($attr: meta)* [$ty: ty where $($generics2: tt)*])*) => { + $(unsafe impl<$($generics2)*> DynSync for $ty {})* + }; + } + + impl_dyn_sync!( + [std::sync::atomic::AtomicPtr<T> where T] + [std::sync::OnceLock<T> where T: DynSend + DynSync] + [std::sync::Mutex<T> where T: ?Sized + DynSend] + [std::sync::Arc<T> where T: ?Sized + DynSync + DynSend] + [std::sync::LazyLock<T, F> where T: DynSend + DynSync, F: DynSend] + [std::collections::HashSet<K, S> where K: DynSync, S: DynSync] + [std::collections::HashMap<K, V, S> where K: DynSync, V: DynSync, S: DynSync] + [std::collections::BTreeMap<K, V, A> where K: DynSync, V: DynSync, A: std::alloc::Allocator + Clone + DynSync] + [Vec<T, A> where T: DynSync, A: std::alloc::Allocator + DynSync] + [Box<T, A> where T: ?Sized + DynSync, A: std::alloc::Allocator + DynSync] + [crate::sync::Lock<T> where T: DynSend] + [crate::sync::RwLock<T> where T: DynSend + DynSync] + [crate::sync::OneThread<T> where T] + [crate::sync::WorkerLocal<T> where T: DynSend] + [crate::intern::Interned<'a, T> where 'a, T: DynSync] + [crate::tagged_ptr::CopyTaggedPtr<P, T, CP> where P: Sync + crate::tagged_ptr::Pointer, T: Sync + crate::tagged_ptr::Tag, const CP: bool] + [parking_lot::lock_api::Mutex<R, T> where R: DynSync, T: ?Sized + DynSend] + [parking_lot::lock_api::RwLock<R, T> where R: DynSync, T: ?Sized + DynSend + DynSync] + [indexmap::IndexSet<V, S> where V: DynSync, S: DynSync] + [indexmap::IndexMap<K, V, S> where K: DynSync, V: DynSync, S: DynSync] + [smallvec::SmallVec<A> where A: smallvec::Array + DynSync] + [thin_vec::ThinVec<T> where T: DynSync] + ); + } +); + +pub fn assert_dyn_sync<T: ?Sized + DynSync>() {} +pub fn assert_dyn_send<T: ?Sized + DynSend>() {} +pub fn assert_dyn_send_val<T: ?Sized + DynSend>(_t: &T) {} +pub fn assert_dyn_send_sync_val<T: ?Sized + DynSync + DynSend>(_t: &T) {} + +#[derive(Copy, Clone)] +pub struct FromDyn<T>(T); + +impl<T> FromDyn<T> { + #[inline(always)] + pub fn from(val: T) -> Self { + // Check that `sync::is_dyn_thread_safe()` is true on creation so we can + // implement `Send` and `Sync` for this structure when `T` + // implements `DynSend` and `DynSync` respectively. + #[cfg(parallel_compiler)] + assert!(crate::sync::is_dyn_thread_safe()); + FromDyn(val) + } + + #[inline(always)] + pub fn into_inner(self) -> T { + self.0 + } +} + +// `FromDyn` is `Send` if `T` is `DynSend`, since it ensures that sync::is_dyn_thread_safe() is true. +#[cfg(parallel_compiler)] +unsafe impl<T: DynSend> Send for FromDyn<T> {} + +// `FromDyn` is `Sync` if `T` is `DynSync`, since it ensures that sync::is_dyn_thread_safe() is true. +#[cfg(parallel_compiler)] +unsafe impl<T: DynSync> Sync for FromDyn<T> {} + +impl<T> std::ops::Deref for FromDyn<T> { + type Target = T; + + #[inline(always)] + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +// A wrapper to convert a struct that is already a `Send` or `Sync` into +// an instance of `DynSend` and `DynSync`, since the compiler cannot infer +// it automatically in some cases. (e.g. Box<dyn Send / Sync>) +#[derive(Copy, Clone)] +pub struct IntoDynSyncSend<T: ?Sized>(pub T); + +#[cfg(parallel_compiler)] +unsafe impl<T: ?Sized + Send> DynSend for IntoDynSyncSend<T> {} +#[cfg(parallel_compiler)] +unsafe impl<T: ?Sized + Sync> DynSync for IntoDynSyncSend<T> {} + +impl<T> std::ops::Deref for IntoDynSyncSend<T> { + type Target = T; + + #[inline(always)] + fn deref(&self) -> &T { + &self.0 + } +} + +impl<T> std::ops::DerefMut for IntoDynSyncSend<T> { + #[inline(always)] + fn deref_mut(&mut self) -> &mut T { + &mut self.0 + } +} diff --git a/compiler/rustc_data_structures/src/owned_slice.rs b/compiler/rustc_data_structures/src/owned_slice.rs index 311a42aa42a..cbb3047d884 100644 --- a/compiler/rustc_data_structures/src/owned_slice.rs +++ b/compiler/rustc_data_structures/src/owned_slice.rs @@ -1,5 +1,6 @@ use std::{borrow::Borrow, ops::Deref}; +use crate::sync::Lrc; // Use our fake Send/Sync traits when on not parallel compiler, // so that `OwnedSlice` only implements/requires Send/Sync // for parallel compiler builds. @@ -7,7 +8,7 @@ use crate::sync::{Send, Sync}; /// An owned slice. /// -/// This is similar to `Box<[u8]>` but allows slicing and using anything as the +/// This is similar to `Lrc<[u8]>` but allows slicing and using anything as the /// backing buffer. /// /// See [`slice_owned`] for `OwnedSlice` construction and examples. @@ -16,6 +17,7 @@ use crate::sync::{Send, Sync}; /// /// This is essentially a replacement for `owning_ref` which is a lot simpler /// and even sound! 🌸 +#[derive(Clone)] pub struct OwnedSlice { /// This is conceptually a `&'self.owner [u8]`. bytes: *const [u8], @@ -31,7 +33,7 @@ pub struct OwnedSlice { // \/ // ⊂(´・◡・⊂ )∘˚˳° (I am the phantom remnant of #97770) #[expect(dead_code)] - owner: Box<dyn Send + Sync>, + owner: Lrc<dyn Send + Sync>, } /// Makes an [`OwnedSlice`] out of an `owner` and a `slicer` function. @@ -72,10 +74,10 @@ where O: Send + Sync + 'static, F: FnOnce(&O) -> Result<&[u8], E>, { - // We box the owner of the bytes, so it doesn't move. + // We wrap the owner of the bytes in, so it doesn't move. // // Since the owner does not move and we don't access it in any way - // before drop, there is nothing that can invalidate the bytes pointer. + // before dropping, there is nothing that can invalidate the bytes pointer. // // Thus, "extending" the lifetime of the reference returned from `F` is fine. // We pretend that we pass it a reference that lives as long as the returned slice. @@ -83,12 +85,39 @@ where // N.B. the HRTB on the `slicer` is important — without it the caller could provide // a short lived slice, unrelated to the owner. - let owner = Box::new(owner); + let owner = Lrc::new(owner); let bytes = slicer(&*owner)?; Ok(OwnedSlice { bytes, owner }) } +impl OwnedSlice { + /// Slice this slice by `slicer`. + /// + /// # Examples + /// + /// ```rust + /// # use rustc_data_structures::owned_slice::{OwnedSlice, slice_owned}; + /// let vec = vec![1, 2, 3, 4]; + /// + /// // Identical to slicing via `&v[1..3]` but produces an owned slice + /// let slice: OwnedSlice = slice_owned(vec, |v| &v[..]); + /// assert_eq!(&*slice, [1, 2, 3, 4]); + /// + /// let slice = slice.slice(|slice| &slice[1..][..2]); + /// assert_eq!(&*slice, [2, 3]); + /// ``` + /// + pub fn slice(self, slicer: impl FnOnce(&[u8]) -> &[u8]) -> OwnedSlice { + // This is basically identical to `try_slice_owned`, + // `slicer` can only return slices of its argument or some static data, + // both of which are valid while `owner` is alive. + + let bytes = slicer(&self); + OwnedSlice { bytes, ..self } + } +} + impl Deref for OwnedSlice { type Target = [u8]; @@ -108,11 +137,11 @@ impl Borrow<[u8]> for OwnedSlice { } } -// Safety: `OwnedSlice` is conceptually `(&'self.1 [u8], Box<dyn Send + Sync>)`, which is `Send` +// Safety: `OwnedSlice` is conceptually `(&'self.1 [u8], Arc<dyn Send + Sync>)`, which is `Send` #[cfg(parallel_compiler)] unsafe impl Send for OwnedSlice {} -// Safety: `OwnedSlice` is conceptually `(&'self.1 [u8], Box<dyn Send + Sync>)`, which is `Sync` +// Safety: `OwnedSlice` is conceptually `(&'self.1 [u8], Arc<dyn Send + Sync>)`, which is `Sync` #[cfg(parallel_compiler)] unsafe impl Sync for OwnedSlice {} diff --git a/compiler/rustc_data_structures/src/owned_slice/tests.rs b/compiler/rustc_data_structures/src/owned_slice/tests.rs index e715fb55362..1eb5378cd1a 100644 --- a/compiler/rustc_data_structures/src/owned_slice/tests.rs +++ b/compiler/rustc_data_structures/src/owned_slice/tests.rs @@ -26,7 +26,7 @@ fn static_storage() { } #[test] -fn slice_the_slice() { +fn slice_owned_the_slice() { let slice = slice_owned(vec![1, 2, 3, 4, 5, 6], Vec::as_slice); let slice = slice_owned(slice, |s| &s[1..][..4]); let slice = slice_owned(slice, |s| s); @@ -36,6 +36,16 @@ fn slice_the_slice() { } #[test] +fn slice_the_slice() { + let slice = slice_owned(vec![1, 2, 3, 4, 5, 6], Vec::as_slice) + .slice(|s| &s[1..][..4]) + .slice(|s| s) + .slice(|s| &s[1..]); + + assert_eq!(&*slice, &[1, 2, 3, 4, 5, 6][1..][..4][1..]); +} + +#[test] fn try_and_fail() { let res = try_slice_owned(vec![0], |v| v.get(12..).ok_or(())); @@ -69,6 +79,6 @@ fn drop_drops() { #[test] fn send_sync() { - crate::sync::assert_send::<OwnedSlice>(); - crate::sync::assert_sync::<OwnedSlice>(); + crate::sync::assert_dyn_send::<OwnedSlice>(); + crate::sync::assert_dyn_sync::<OwnedSlice>(); } diff --git a/compiler/rustc_data_structures/src/profiling.rs b/compiler/rustc_data_structures/src/profiling.rs index 5e13e7c8aaf..3c76c2b7991 100644 --- a/compiler/rustc_data_structures/src/profiling.rs +++ b/compiler/rustc_data_structures/src/profiling.rs @@ -865,14 +865,16 @@ cfg_if! { use std::mem; use windows::{ - Win32::System::ProcessStatus::{K32GetProcessMemoryInfo, PROCESS_MEMORY_COUNTERS}, + // FIXME: change back to K32GetProcessMemoryInfo when windows crate + // updated to 0.49.0+ to drop dependency on psapi.dll + Win32::System::ProcessStatus::{GetProcessMemoryInfo, PROCESS_MEMORY_COUNTERS}, Win32::System::Threading::GetCurrentProcess, }; let mut pmc = PROCESS_MEMORY_COUNTERS::default(); let pmc_size = mem::size_of_val(&pmc); unsafe { - K32GetProcessMemoryInfo( + GetProcessMemoryInfo( GetCurrentProcess(), &mut pmc, pmc_size as u32, diff --git a/compiler/rustc_data_structures/src/sync.rs b/compiler/rustc_data_structures/src/sync.rs index e73ca56efa0..6c3197d8ec2 100644 --- a/compiler/rustc_data_structures/src/sync.rs +++ b/compiler/rustc_data_structures/src/sync.rs @@ -39,7 +39,7 @@ //! //! [^2] `MTLockRef` is a typedef. -use crate::owned_slice::OwnedSlice; +pub use crate::marker::*; use std::collections::HashMap; use std::hash::{BuildHasher, Hash}; use std::ops::{Deref, DerefMut}; @@ -55,6 +55,43 @@ pub use vec::{AppendOnlyIndexVec, AppendOnlyVec}; mod vec; +mod mode { + use super::Ordering; + use std::sync::atomic::AtomicU8; + + const UNINITIALIZED: u8 = 0; + const DYN_NOT_THREAD_SAFE: u8 = 1; + const DYN_THREAD_SAFE: u8 = 2; + + static DYN_THREAD_SAFE_MODE: AtomicU8 = AtomicU8::new(UNINITIALIZED); + + // Whether thread safety is enabled (due to running under multiple threads). + #[inline] + pub fn is_dyn_thread_safe() -> bool { + match DYN_THREAD_SAFE_MODE.load(Ordering::Relaxed) { + DYN_NOT_THREAD_SAFE => false, + DYN_THREAD_SAFE => true, + _ => panic!("uninitialized dyn_thread_safe mode!"), + } + } + + // Only set by the `-Z threads` compile option + pub fn set_dyn_thread_safe_mode(mode: bool) { + let set: u8 = if mode { DYN_THREAD_SAFE } else { DYN_NOT_THREAD_SAFE }; + let previous = DYN_THREAD_SAFE_MODE.compare_exchange( + UNINITIALIZED, + set, + Ordering::Relaxed, + Ordering::Relaxed, + ); + + // Check that the mode was either uninitialized or was already set to the requested mode. + assert!(previous.is_ok() || previous == Err(set)); + } +} + +pub use mode::{is_dyn_thread_safe, set_dyn_thread_safe_mode}; + cfg_if! { if #[cfg(not(parallel_compiler))] { pub unsafe auto trait Send {} @@ -149,7 +186,7 @@ cfg_if! { #[macro_export] macro_rules! parallel { - ($($blocks:tt),*) => { + ($($blocks:block),*) => { // We catch panics here ensuring that all the blocks execute. // This makes behavior consistent with the parallel compiler. let mut panic = None; @@ -168,12 +205,6 @@ cfg_if! { } } - pub use Iterator as ParallelIterator; - - pub fn par_iter<T: IntoIterator>(t: T) -> T::IntoIter { - t.into_iter() - } - pub fn par_for_each_in<T: IntoIterator>(t: T, mut for_each: impl FnMut(T::Item) + Sync + Send) { // We catch panics here ensuring that all the loop iterations execute. // This makes behavior consistent with the parallel compiler. @@ -190,7 +221,28 @@ cfg_if! { } } - pub type MetadataRef = OwnedSlice; + pub fn par_map<T: IntoIterator, R, C: FromIterator<R>>( + t: T, + mut map: impl FnMut(<<T as IntoIterator>::IntoIter as Iterator>::Item) -> R, + ) -> C { + // We catch panics here ensuring that all the loop iterations execute. + let mut panic = None; + let r = t.into_iter().filter_map(|i| { + match catch_unwind(AssertUnwindSafe(|| map(i))) { + Ok(r) => Some(r), + Err(p) => { + if panic.is_none() { + panic = Some(p); + } + None + } + } + }).collect(); + if let Some(panic) = panic { + resume_unwind(panic); + } + r + } pub use std::rc::Rc as Lrc; pub use std::rc::Weak as Weak; @@ -302,49 +354,166 @@ cfg_if! { use parking_lot::RwLock as InnerRwLock; use std::thread; - pub use rayon::{join, scope}; + + #[inline] + pub fn join<A, B, RA: DynSend, RB: DynSend>(oper_a: A, oper_b: B) -> (RA, RB) + where + A: FnOnce() -> RA + DynSend, + B: FnOnce() -> RB + DynSend, + { + if mode::is_dyn_thread_safe() { + let oper_a = FromDyn::from(oper_a); + let oper_b = FromDyn::from(oper_b); + let (a, b) = rayon::join(move || FromDyn::from(oper_a.into_inner()()), move || FromDyn::from(oper_b.into_inner()())); + (a.into_inner(), b.into_inner()) + } else { + (oper_a(), oper_b()) + } + } + + // This function only works when `mode::is_dyn_thread_safe()`. + pub fn scope<'scope, OP, R>(op: OP) -> R + where + OP: FnOnce(&rayon::Scope<'scope>) -> R + DynSend, + R: DynSend, + { + let op = FromDyn::from(op); + rayon::scope(|s| FromDyn::from(op.into_inner()(s))).into_inner() + } /// Runs a list of blocks in parallel. The first block is executed immediately on /// the current thread. Use that for the longest running block. #[macro_export] macro_rules! parallel { - (impl $fblock:tt [$($c:tt,)*] [$block:tt $(, $rest:tt)*]) => { + (impl $fblock:block [$($c:expr,)*] [$block:expr $(, $rest:expr)*]) => { parallel!(impl $fblock [$block, $($c,)*] [$($rest),*]) }; - (impl $fblock:tt [$($blocks:tt,)*] []) => { + (impl $fblock:block [$($blocks:expr,)*] []) => { ::rustc_data_structures::sync::scope(|s| { + $(let block = rustc_data_structures::sync::FromDyn::from(|| $blocks); + s.spawn(move |_| block.into_inner()());)* + (|| $fblock)(); + }); + }; + ($fblock:block, $($blocks:block),*) => { + if rustc_data_structures::sync::is_dyn_thread_safe() { + // Reverse the order of the later blocks since Rayon executes them in reverse order + // when using a single thread. This ensures the execution order matches that + // of a single threaded rustc. + parallel!(impl $fblock [] [$($blocks),*]); + } else { + // We catch panics here ensuring that all the blocks execute. + // This makes behavior consistent with the parallel compiler. + let mut panic = None; + if let Err(p) = ::std::panic::catch_unwind( + ::std::panic::AssertUnwindSafe(|| $fblock) + ) { + if panic.is_none() { + panic = Some(p); + } + } $( - s.spawn(|_| $blocks); + if let Err(p) = ::std::panic::catch_unwind( + ::std::panic::AssertUnwindSafe(|| $blocks) + ) { + if panic.is_none() { + panic = Some(p); + } + } )* - $fblock; - }) - }; - ($fblock:tt, $($blocks:tt),*) => { - // Reverse the order of the later blocks since Rayon executes them in reverse order - // when using a single thread. This ensures the execution order matches that - // of a single threaded rustc - parallel!(impl $fblock [] [$($blocks),*]); + if let Some(panic) = panic { + ::std::panic::resume_unwind(panic); + } + } }; } - pub use rayon::iter::ParallelIterator; - use rayon::iter::IntoParallelIterator; + use rayon::iter::{FromParallelIterator, IntoParallelIterator, ParallelIterator}; - pub fn par_iter<T: IntoParallelIterator>(t: T) -> T::Iter { - t.into_par_iter() - } - - pub fn par_for_each_in<T: IntoParallelIterator>( + pub fn par_for_each_in<I, T: IntoIterator<Item = I> + IntoParallelIterator<Item = I>>( t: T, - for_each: impl Fn(T::Item) + Sync + Send, + for_each: impl Fn(I) + DynSync + DynSend ) { - let ps: Vec<_> = t.into_par_iter().map(|i| catch_unwind(AssertUnwindSafe(|| for_each(i)))).collect(); - ps.into_iter().for_each(|p| if let Err(panic) = p { - resume_unwind(panic) - }); + if mode::is_dyn_thread_safe() { + let for_each = FromDyn::from(for_each); + let panic: Lock<Option<_>> = Lock::new(None); + t.into_par_iter().for_each(|i| if let Err(p) = catch_unwind(AssertUnwindSafe(|| for_each(i))) { + let mut l = panic.lock(); + if l.is_none() { + *l = Some(p) + } + }); + + if let Some(panic) = panic.into_inner() { + resume_unwind(panic); + } + } else { + // We catch panics here ensuring that all the loop iterations execute. + // This makes behavior consistent with the parallel compiler. + let mut panic = None; + t.into_iter().for_each(|i| { + if let Err(p) = catch_unwind(AssertUnwindSafe(|| for_each(i))) { + if panic.is_none() { + panic = Some(p); + } + } + }); + if let Some(panic) = panic { + resume_unwind(panic); + } + } } - pub type MetadataRef = OwnedSlice; + pub fn par_map< + I, + T: IntoIterator<Item = I> + IntoParallelIterator<Item = I>, + R: std::marker::Send, + C: FromIterator<R> + FromParallelIterator<R> + >( + t: T, + map: impl Fn(I) -> R + DynSync + DynSend + ) -> C { + if mode::is_dyn_thread_safe() { + let panic: Lock<Option<_>> = Lock::new(None); + let map = FromDyn::from(map); + // We catch panics here ensuring that all the loop iterations execute. + let r = t.into_par_iter().filter_map(|i| { + match catch_unwind(AssertUnwindSafe(|| map(i))) { + Ok(r) => Some(r), + Err(p) => { + let mut l = panic.lock(); + if l.is_none() { + *l = Some(p); + } + None + }, + } + }).collect(); + + if let Some(panic) = panic.into_inner() { + resume_unwind(panic); + } + r + } else { + // We catch panics here ensuring that all the loop iterations execute. + let mut panic = None; + let r = t.into_iter().filter_map(|i| { + match catch_unwind(AssertUnwindSafe(|| map(i))) { + Ok(r) => Some(r), + Err(p) => { + if panic.is_none() { + panic = Some(p); + } + None + } + } + }).collect(); + if let Some(panic) = panic { + resume_unwind(panic); + } + r + } + } /// This makes locks panic if they are already held. /// It is only useful when you are running in a single thread @@ -352,11 +521,6 @@ cfg_if! { } } -pub fn assert_sync<T: ?Sized + Sync>() {} -pub fn assert_send<T: ?Sized + Send>() {} -pub fn assert_send_val<T: ?Sized + Send>(_t: &T) {} -pub fn assert_send_sync_val<T: ?Sized + Sync + Send>(_t: &T) {} - #[derive(Default)] #[cfg_attr(parallel_compiler, repr(align(64)))] pub struct CacheAligned<T>(pub T); diff --git a/compiler/rustc_driver_impl/Cargo.toml b/compiler/rustc_driver_impl/Cargo.toml index d7d97fcc3e7..67352c55c90 100644 --- a/compiler/rustc_driver_impl/Cargo.toml +++ b/compiler/rustc_driver_impl/Cargo.toml @@ -57,7 +57,7 @@ rustc_mir_transform = { path = "../rustc_mir_transform" } libc = "0.2" [target.'cfg(windows)'.dependencies.windows] -version = "0.46.0" +version = "0.48.0" features = [ "Win32_System_Diagnostics_Debug", ] diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 9b16f246193..80a9dfd251a 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -256,6 +256,9 @@ fn run_compiler( let sopts = config::build_session_options(&matches); + // Set parallel mode before thread pool creation, which will create `Lock`s. + interface::set_thread_safe_mode(&sopts.unstable_opts); + if let Some(ref code) = matches.opt_str("explain") { handle_explain(diagnostics_registry(), code, sopts.error_format); return Ok(()); diff --git a/compiler/rustc_error_messages/src/lib.rs b/compiler/rustc_error_messages/src/lib.rs index 6c3f677ab8e..0accb4ab96f 100644 --- a/compiler/rustc_error_messages/src/lib.rs +++ b/compiler/rustc_error_messages/src/lib.rs @@ -11,7 +11,7 @@ extern crate tracing; use fluent_bundle::FluentResource; use fluent_syntax::parser::ParserError; use icu_provider_adapters::fallback::{LocaleFallbackProvider, LocaleFallbacker}; -use rustc_data_structures::sync::Lrc; +use rustc_data_structures::sync::{IntoDynSyncSend, Lrc}; use rustc_fluent_macro::fluent_messages; use rustc_macros::{Decodable, Encodable}; use rustc_span::Span; @@ -37,16 +37,17 @@ pub use unic_langid::{langid, LanguageIdentifier}; fluent_messages! { "../messages.ftl" } -pub type FluentBundle = fluent_bundle::bundle::FluentBundle<FluentResource, IntlLangMemoizer>; +pub type FluentBundle = + IntoDynSyncSend<fluent_bundle::bundle::FluentBundle<FluentResource, IntlLangMemoizer>>; -#[cfg(parallel_compiler)] +#[cfg(not(parallel_compiler))] fn new_bundle(locales: Vec<LanguageIdentifier>) -> FluentBundle { - FluentBundle::new_concurrent(locales) + IntoDynSyncSend(fluent_bundle::bundle::FluentBundle::new(locales)) } -#[cfg(not(parallel_compiler))] +#[cfg(parallel_compiler)] fn new_bundle(locales: Vec<LanguageIdentifier>) -> FluentBundle { - FluentBundle::new(locales) + IntoDynSyncSend(fluent_bundle::bundle::FluentBundle::new_concurrent(locales)) } #[derive(Debug)] diff --git a/compiler/rustc_errors/Cargo.toml b/compiler/rustc_errors/Cargo.toml index 46ace8eb2dd..bd3033fcb3e 100644 --- a/compiler/rustc_errors/Cargo.toml +++ b/compiler/rustc_errors/Cargo.toml @@ -27,12 +27,11 @@ serde = { version = "1.0.125", features = [ "derive" ] } serde_json = "1.0.59" [target.'cfg(windows)'.dependencies.windows] -version = "0.46.0" +version = "0.48.0" features = [ "Win32_Foundation", "Win32_Security", "Win32_System_Threading", - "Win32_System_WindowsProgramming", ] [features] diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index fcbd9a53b48..22c41f7b93f 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -32,7 +32,7 @@ use emitter::{is_case_difference, Emitter, EmitterWriter}; use registry::Registry; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet}; use rustc_data_structures::stable_hasher::{Hash128, StableHasher}; -use rustc_data_structures::sync::{self, Lock, Lrc}; +use rustc_data_structures::sync::{self, IntoDynSyncSend, Lock, Lrc}; use rustc_data_structures::AtomicRef; pub use rustc_error_messages::{ fallback_fluent_bundle, fluent_bundle, DelayDm, DiagnosticMessage, FluentBundle, @@ -409,7 +409,7 @@ struct HandlerInner { err_count: usize, warn_count: usize, deduplicated_err_count: usize, - emitter: Box<dyn Emitter + sync::Send>, + emitter: IntoDynSyncSend<Box<dyn Emitter + sync::Send>>, delayed_span_bugs: Vec<DelayedDiagnostic>, delayed_good_path_bugs: Vec<DelayedDiagnostic>, /// This flag indicates that an expected diagnostic was emitted and suppressed. @@ -605,7 +605,7 @@ impl Handler { warn_count: 0, deduplicated_err_count: 0, deduplicated_warn_count: 0, - emitter, + emitter: IntoDynSyncSend(emitter), delayed_span_bugs: Vec::new(), delayed_good_path_bugs: Vec::new(), suppressed_expected_diag: false, diff --git a/compiler/rustc_errors/src/lock.rs b/compiler/rustc_errors/src/lock.rs index 7db262abfde..bd5cf49b56b 100644 --- a/compiler/rustc_errors/src/lock.rs +++ b/compiler/rustc_errors/src/lock.rs @@ -19,8 +19,7 @@ pub fn acquire_global_lock(name: &str) -> Box<dyn Any> { use windows::{ core::PCSTR, Win32::Foundation::{CloseHandle, HANDLE, WAIT_ABANDONED, WAIT_OBJECT_0}, - Win32::System::Threading::{CreateMutexA, ReleaseMutex, WaitForSingleObject}, - Win32::System::WindowsProgramming::INFINITE, + Win32::System::Threading::{CreateMutexA, ReleaseMutex, WaitForSingleObject, INFINITE}, }; struct Handle(HANDLE); diff --git a/compiler/rustc_errors/src/tests.rs b/compiler/rustc_errors/src/tests.rs index 52103e46097..0e729b71680 100644 --- a/compiler/rustc_errors/src/tests.rs +++ b/compiler/rustc_errors/src/tests.rs @@ -2,7 +2,7 @@ use crate::error::{TranslateError, TranslateErrorKind}; use crate::fluent_bundle::*; use crate::translation::Translate; use crate::FluentBundle; -use rustc_data_structures::sync::Lrc; +use rustc_data_structures::sync::{IntoDynSyncSend, Lrc}; use rustc_error_messages::fluent_bundle::resolver::errors::{ReferenceKind, ResolverError}; use rustc_error_messages::langid; use rustc_error_messages::DiagnosticMessage; @@ -27,10 +27,14 @@ fn make_dummy(ftl: &'static str) -> Dummy { let langid_en = langid!("en-US"); #[cfg(parallel_compiler)] - let mut bundle = FluentBundle::new_concurrent(vec![langid_en]); + let mut bundle: FluentBundle = + IntoDynSyncSend(crate::fluent_bundle::bundle::FluentBundle::new_concurrent(vec![ + langid_en, + ])); #[cfg(not(parallel_compiler))] - let mut bundle = FluentBundle::new(vec![langid_en]); + let mut bundle: FluentBundle = + IntoDynSyncSend(crate::fluent_bundle::bundle::FluentBundle::new(vec![langid_en])); bundle.add_resource(resource).expect("Failed to add FTL resources to the bundle."); diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index c1cca89df8c..e03576c55f4 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -653,13 +653,13 @@ pub enum SyntaxExtensionKind { /// A token-based function-like macro. Bang( /// An expander with signature TokenStream -> TokenStream. - Box<dyn BangProcMacro + sync::Sync + sync::Send>, + Box<dyn BangProcMacro + sync::DynSync + sync::DynSend>, ), /// An AST-based function-like macro. LegacyBang( /// An expander with signature TokenStream -> AST. - Box<dyn TTMacroExpander + sync::Sync + sync::Send>, + Box<dyn TTMacroExpander + sync::DynSync + sync::DynSend>, ), /// A token-based attribute macro. @@ -667,7 +667,7 @@ pub enum SyntaxExtensionKind { /// An expander with signature (TokenStream, TokenStream) -> TokenStream. /// The first TokenSteam is the attribute itself, the second is the annotated item. /// The produced TokenSteam replaces the input TokenSteam. - Box<dyn AttrProcMacro + sync::Sync + sync::Send>, + Box<dyn AttrProcMacro + sync::DynSync + sync::DynSend>, ), /// An AST-based attribute macro. @@ -675,7 +675,7 @@ pub enum SyntaxExtensionKind { /// An expander with signature (AST, AST) -> AST. /// The first AST fragment is the attribute itself, the second is the annotated item. /// The produced AST fragment replaces the input AST fragment. - Box<dyn MultiItemModifier + sync::Sync + sync::Send>, + Box<dyn MultiItemModifier + sync::DynSync + sync::DynSend>, ), /// A trivial attribute "macro" that does nothing, @@ -692,14 +692,14 @@ pub enum SyntaxExtensionKind { /// is handled identically to `LegacyDerive`. It should be migrated to /// a token-based representation like `Bang` and `Attr`, instead of /// using `MultiItemModifier`. - Box<dyn MultiItemModifier + sync::Sync + sync::Send>, + Box<dyn MultiItemModifier + sync::DynSync + sync::DynSend>, ), /// An AST-based derive macro. LegacyDerive( /// An expander with signature AST -> AST. /// The produced AST fragment is appended to the input AST fragment. - Box<dyn MultiItemModifier + sync::Sync + sync::Send>, + Box<dyn MultiItemModifier + sync::DynSync + sync::DynSend>, ), } diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index f4615445f8e..57e55752027 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -321,6 +321,8 @@ declare_features! ( (active, c_unwind, "1.52.0", Some(74990), None), /// Allows using C-variadics. (active, c_variadic, "1.34.0", Some(44930), None), + /// Allows the use of `#[cfg(overflow_checks)` to check if integer overflow behaviour. + (active, cfg_overflow_checks, "CURRENT_RUSTC_VERSION", Some(111466), None), /// Allows the use of `#[cfg(sanitize = "option")]`; set when -Zsanitizer is used. (active, cfg_sanitize, "1.41.0", Some(39699), None), /// Allows `cfg(target_abi = "...")`. @@ -336,7 +338,7 @@ declare_features! ( /// Allow conditional compilation depending on rust version (active, cfg_version, "1.45.0", Some(64796), None), /// Allows to use the `#[cfi_encoding = ""]` attribute. - (active, cfi_encoding, "1.69.0", Some(89653), None), + (active, cfi_encoding, "CURRENT_RUSTC_VERSION", Some(89653), None), /// Allows `for<...>` on closures and generators. (active, closure_lifetime_binder, "1.64.0", Some(97362), None), /// Allows `#[track_caller]` on closures and generators. diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index fe05d4590e7..61cfbf5c5e5 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -24,6 +24,7 @@ pub type GatedCfg = (Symbol, Symbol, GateFn); /// `cfg(...)`'s that are feature gated. const GATED_CFGS: &[GatedCfg] = &[ // (name in cfg, feature, function to check if the feature is enabled) + (sym::overflow_checks, sym::cfg_overflow_checks, cfg_fn!(cfg_overflow_checks)), (sym::target_abi, sym::cfg_target_abi, cfg_fn!(cfg_target_abi)), (sym::target_thread_local, sym::cfg_target_thread_local, cfg_fn!(cfg_target_thread_local)), ( diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 38cd5865cc3..932f0396282 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -2662,7 +2662,10 @@ pub enum OpaqueTyOrigin { /// `async fn` AsyncFn(LocalDefId), /// type aliases: `type Foo = impl Trait;` - TyAlias, + TyAlias { + /// associated types in impl blocks for traits. + in_assoc_ty: bool, + }, } /// The various kinds of types recognized by the compiler. diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs index 6ac1df6a079..7e591fd25bf 100644 --- a/compiler/rustc_hir_analysis/src/astconv/mod.rs +++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs @@ -464,7 +464,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { self.astconv.ct_infer(ty, Some(param), inf.span).into() } else { self.inferred_params.push(inf.span); - tcx.const_error(ty).into() + tcx.const_error_misc(ty).into() } } _ => unreachable!(), @@ -518,7 +518,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { .no_bound_vars() .expect("const parameter types cannot be generic"); if let Err(guar) = ty.error_reported() { - return tcx.const_error_with_guaranteed(ty, guar).into(); + return tcx.const_error(ty, guar).into(); } if !infer_args && has_default { tcx.const_param_default(param.def_id).subst(tcx, substs.unwrap()).into() @@ -527,7 +527,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { self.astconv.ct_infer(ty, Some(param), self.span).into() } else { // We've already errored above about the mismatch. - tcx.const_error(ty).into() + tcx.const_error_misc(ty).into() } } } @@ -1387,7 +1387,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { term = match def_kind { hir::def::DefKind::AssocTy => tcx.ty_error(reported).into(), hir::def::DefKind::AssocConst => tcx - .const_error_with_guaranteed( + .const_error( tcx.type_of(assoc_item_def_id) .subst(tcx, projection_ty.skip_binder().substs), reported, diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index c4d4e0d6d78..d3495d3dbd7 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -31,6 +31,7 @@ use rustc_target::abi::FieldIdx; use rustc_target::spec::abi::Abi; use rustc_trait_selection::traits::error_reporting::on_unimplemented::OnUnimplementedDirective; use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _; +use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _; use rustc_trait_selection::traits::{self, ObligationCtxt, TraitEngine, TraitEngineExt as _}; use std::ops::ControlFlow; @@ -222,7 +223,7 @@ fn check_opaque(tcx: TyCtxt<'_>, id: hir::ItemId) { if check_opaque_for_cycles(tcx, item.owner_id.def_id, substs, span, &origin).is_err() { return; } - check_opaque_meets_bounds(tcx, item.owner_id.def_id, substs, span, &origin); + check_opaque_meets_bounds(tcx, item.owner_id.def_id, span, &origin); } /// Checks that an opaque type does not use `Self` or `T::Foo` projections that would result @@ -391,13 +392,12 @@ pub(super) fn check_opaque_for_cycles<'tcx>( fn check_opaque_meets_bounds<'tcx>( tcx: TyCtxt<'tcx>, def_id: LocalDefId, - substs: SubstsRef<'tcx>, span: Span, origin: &hir::OpaqueTyOrigin, ) { let defining_use_anchor = match *origin { hir::OpaqueTyOrigin::FnReturn(did) | hir::OpaqueTyOrigin::AsyncFn(did) => did, - hir::OpaqueTyOrigin::TyAlias => def_id, + hir::OpaqueTyOrigin::TyAlias { .. } => tcx.impl_trait_parent(def_id), }; let param_env = tcx.param_env(defining_use_anchor); @@ -406,6 +406,8 @@ fn check_opaque_meets_bounds<'tcx>( .with_opaque_type_inference(DefiningAnchor::Bind(defining_use_anchor)) .build(); let ocx = ObligationCtxt::new(&infcx); + + let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id()); let opaque_ty = tcx.mk_opaque(def_id.to_def_id(), substs); // `ReErased` regions appear in the "parent_substs" of closures/generators. @@ -448,9 +450,18 @@ fn check_opaque_meets_bounds<'tcx>( match origin { // Checked when type checking the function containing them. hir::OpaqueTyOrigin::FnReturn(..) | hir::OpaqueTyOrigin::AsyncFn(..) => {} + // Nested opaque types occur only in associated types: + // ` type Opaque<T> = impl Trait<&'static T, AssocTy = impl Nested>; ` + // They can only be referenced as `<Opaque<T> as Trait<&'static T>>::AssocTy`. + // We don't have to check them here because their well-formedness follows from the WF of + // the projection input types in the defining- and use-sites. + hir::OpaqueTyOrigin::TyAlias { .. } + if tcx.def_kind(tcx.parent(def_id.to_def_id())) == DefKind::OpaqueTy => {} // Can have different predicates to their defining use - hir::OpaqueTyOrigin::TyAlias => { - let outlives_env = OutlivesEnvironment::new(param_env); + hir::OpaqueTyOrigin::TyAlias { .. } => { + let wf_tys = ocx.assumed_wf_types(param_env, span, def_id); + let implied_bounds = infcx.implied_bounds_tys(param_env, def_id, wf_tys); + let outlives_env = OutlivesEnvironment::with_bounds(param_env, implied_bounds); let _ = ocx.resolve_regions_and_report_errors(defining_use_anchor, &outlives_env); } } @@ -1503,8 +1514,8 @@ fn opaque_type_cycle_error( } if tcx.sess.opts.unstable_opts.drop_tracking_mir && let DefKind::Generator = tcx.def_kind(closure_def_id) + && let Some(generator_layout) = tcx.mir_generator_witnesses(closure_def_id) { - let generator_layout = tcx.mir_generator_witnesses(closure_def_id); for interior_ty in &generator_layout.field_tys { label_match(interior_ty.ty, interior_ty.source_info.span); } diff --git a/compiler/rustc_hir_analysis/src/check/dropck.rs b/compiler/rustc_hir_analysis/src/check/dropck.rs index 5ba1ca1c807..e0ba255cc06 100644 --- a/compiler/rustc_hir_analysis/src/check/dropck.rs +++ b/compiler/rustc_hir_analysis/src/check/dropck.rs @@ -6,7 +6,7 @@ use rustc_errors::{struct_span_err, ErrorGuaranteed}; use rustc_infer::infer::outlives::env::OutlivesEnvironment; use rustc_infer::infer::{RegionResolutionError, TyCtxtInferExt}; use rustc_middle::ty::subst::SubstsRef; -use rustc_middle::ty::util::IgnoreRegions; +use rustc_middle::ty::util::CheckRegions; use rustc_middle::ty::{self, TyCtxt}; use rustc_trait_selection::traits::{self, ObligationCtxt}; @@ -81,7 +81,7 @@ fn ensure_drop_params_and_item_params_correspond<'tcx>( self_type_did: DefId, adt_to_impl_substs: SubstsRef<'tcx>, ) -> Result<(), ErrorGuaranteed> { - let Err(arg) = tcx.uses_unique_generic_params(adt_to_impl_substs, IgnoreRegions::No) else { + let Err(arg) = tcx.uses_unique_generic_params(adt_to_impl_substs, CheckRegions::OnlyEarlyBound) else { return Ok(()) }; diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index 08154cdae47..3971a4c01d6 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -78,7 +78,7 @@ use rustc_errors::{pluralize, struct_span_err, Diagnostic, DiagnosticBuilder}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::Visitor; use rustc_index::bit_set::BitSet; -use rustc_middle::ty::query::Providers; +use rustc_middle::query::Providers; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::ty::{InternalSubsts, SubstsRef}; use rustc_session::parse::feature_err; diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 862f0a9b0e2..8918553e5f9 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -12,7 +12,7 @@ use rustc_infer::infer::outlives::env::{OutlivesEnvironment, RegionBoundPairs}; use rustc_infer::infer::outlives::obligations::TypeOutlives; use rustc_infer::infer::{self, InferCtxt, TyCtxtInferExt}; use rustc_middle::mir::ConstraintCategory; -use rustc_middle::ty::query::Providers; +use rustc_middle::query::Providers; use rustc_middle::ty::trait_def::TraitSpecializationKind; use rustc_middle::ty::{ self, AdtKind, GenericParamDefKind, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable, diff --git a/compiler/rustc_hir_analysis/src/coherence/mod.rs b/compiler/rustc_hir_analysis/src/coherence/mod.rs index cd2ec2bef20..4524b87a418 100644 --- a/compiler/rustc_hir_analysis/src/coherence/mod.rs +++ b/compiler/rustc_hir_analysis/src/coherence/mod.rs @@ -8,7 +8,7 @@ use crate::errors; use rustc_errors::{error_code, struct_span_err}; use rustc_hir::def_id::{DefId, LocalDefId}; -use rustc_middle::ty::query::Providers; +use rustc_middle::query::Providers; use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt}; use rustc_span::sym; use rustc_trait_selection::traits; diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs index 272177dfbd0..23beacd2a8c 100644 --- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs +++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs @@ -6,7 +6,7 @@ use rustc_errors::{struct_span_err, DelayDm}; use rustc_errors::{Diagnostic, ErrorGuaranteed}; use rustc_hir as hir; use rustc_middle::ty::subst::InternalSubsts; -use rustc_middle::ty::util::IgnoreRegions; +use rustc_middle::ty::util::CheckRegions; use rustc_middle::ty::{ self, AliasKind, ImplPolarity, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, @@ -507,7 +507,7 @@ fn lint_auto_trait_impl<'tcx>( // Impls which completely cover a given root type are fine as they // disable auto impls entirely. So only lint if the substs // are not a permutation of the identity substs. - let Err(arg) = tcx.uses_unique_generic_params(substs, IgnoreRegions::Yes) else { + let Err(arg) = tcx.uses_unique_generic_params(substs, CheckRegions::No) else { // ok return; }; diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index b65817ee95e..9f00dc418ee 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -28,7 +28,7 @@ use rustc_hir::{GenericParamKind, Node}; use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; use rustc_infer::traits::ObligationCause; use rustc_middle::hir::nested_filter; -use rustc_middle::ty::query::Providers; +use rustc_middle::query::Providers; use rustc_middle::ty::util::{Discr, IntTypeExt}; use rustc_middle::ty::{self, AdtKind, Const, IsSuggestable, ToPredicate, Ty, TyCtxt}; use rustc_span::symbol::{kw, sym, Ident, Symbol}; @@ -1483,7 +1483,7 @@ fn generator_kind(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<hir::GeneratorK fn is_type_alias_impl_trait<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> bool { match tcx.hir().get_by_def_id(def_id) { Node::Item(hir::Item { kind: hir::ItemKind::OpaqueTy(opaque), .. }) => { - matches!(opaque.origin, hir::OpaqueTyOrigin::TyAlias) + matches!(opaque.origin, hir::OpaqueTyOrigin::TyAlias { .. }) } _ => bug!("tried getting opaque_ty_origin for non-opaque: {:?}", def_id), } diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs index ab2932bf969..ed60998ec8d 100644 --- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs @@ -159,7 +159,10 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { } Some(fn_def_id.to_def_id()) } - ItemKind::OpaqueTy(hir::OpaqueTy { origin: hir::OpaqueTyOrigin::TyAlias, .. }) => { + ItemKind::OpaqueTy(hir::OpaqueTy { + origin: hir::OpaqueTyOrigin::TyAlias { .. }, + .. + }) => { let parent_id = tcx.hir().get_parent_item(hir_id); assert_ne!(parent_id, hir::CRATE_OWNER_ID); debug!("generics_of: parent of opaque ty {:?} is {:?}", def_id, parent_id); diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index e04658c8e77..a33990813b8 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -721,7 +721,7 @@ pub(super) fn type_param_predicates( | ItemKind::TyAlias(_, generics) | ItemKind::OpaqueTy(OpaqueTy { generics, - origin: hir::OpaqueTyOrigin::TyAlias, + origin: hir::OpaqueTyOrigin::TyAlias { .. }, .. }) | ItemKind::Enum(_, generics) diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index 5c7f7f10b17..794812a5ce7 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -17,6 +17,7 @@ use rustc_hir::{GenericArg, GenericParam, GenericParamKind, HirIdMap, LifetimeNa use rustc_middle::bug; use rustc_middle::hir::nested_filter; use rustc_middle::middle::resolve_bound_vars::*; +use rustc_middle::query::Providers; use rustc_middle::ty::{self, TyCtxt, TypeSuperVisitable, TypeVisitor}; use rustc_session::lint; use rustc_span::def_id::DefId; @@ -232,8 +233,8 @@ impl<'a> fmt::Debug for TruncatedScopeDebug<'a> { type ScopeRef<'a> = &'a Scope<'a>; -pub(crate) fn provide(providers: &mut ty::query::Providers) { - *providers = ty::query::Providers { +pub(crate) fn provide(providers: &mut Providers) { + *providers = Providers { resolve_bound_vars, named_variable_map: |tcx, id| tcx.resolve_bound_vars(id).defs.get(&id), @@ -526,7 +527,8 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { }); } hir::ItemKind::OpaqueTy(hir::OpaqueTy { - origin: hir::OpaqueTyOrigin::TyAlias, .. + origin: hir::OpaqueTyOrigin::TyAlias { .. }, + .. }) => { // Opaque types are visited when we visit the // `TyKind::OpaqueDef`, so that they have the lifetimes from @@ -707,7 +709,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { let opaque_ty = self.tcx.hir().item(item_id); match &opaque_ty.kind { hir::ItemKind::OpaqueTy(hir::OpaqueTy { - origin: hir::OpaqueTyOrigin::TyAlias, + origin: hir::OpaqueTyOrigin::TyAlias { .. }, .. }) => { intravisit::walk_ty(self, ty); diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs index 8df0166f76b..6c7c2b9eea2 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs @@ -426,9 +426,10 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Ty let substs = InternalSubsts::identity_for_item(tcx, def_id); tcx.mk_adt(def, substs) } - ItemKind::OpaqueTy(OpaqueTy { origin: hir::OpaqueTyOrigin::TyAlias, .. }) => { - find_opaque_ty_constraints_for_tait(tcx, def_id) - } + ItemKind::OpaqueTy(OpaqueTy { + origin: hir::OpaqueTyOrigin::TyAlias { .. }, + .. + }) => find_opaque_ty_constraints_for_tait(tcx, def_id), // Opaque types desugared from `impl Trait`. ItemKind::OpaqueTy(OpaqueTy { origin: diff --git a/compiler/rustc_hir_analysis/src/hir_wf_check.rs b/compiler/rustc_hir_analysis/src/hir_wf_check.rs index 8269a6ddea5..e4c6e6e391a 100644 --- a/compiler/rustc_hir_analysis/src/hir_wf_check.rs +++ b/compiler/rustc_hir_analysis/src/hir_wf_check.rs @@ -4,7 +4,7 @@ use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{ForeignItem, ForeignItemKind}; use rustc_infer::infer::TyCtxtInferExt; use rustc_infer::traits::{ObligationCause, WellFormedLoc}; -use rustc_middle::ty::query::Providers; +use rustc_middle::query::Providers; use rustc_middle::ty::{self, Region, TyCtxt, TypeFoldable, TypeFolder}; use rustc_span::def_id::LocalDefId; use rustc_trait_selection::traits::{self, ObligationCtxt}; diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check.rs b/compiler/rustc_hir_analysis/src/impl_wf_check.rs index f070b4f9bae..612d4ff3df8 100644 --- a/compiler/rustc_hir_analysis/src/impl_wf_check.rs +++ b/compiler/rustc_hir_analysis/src/impl_wf_check.rs @@ -15,7 +15,7 @@ use rustc_data_structures::fx::FxHashSet; use rustc_errors::struct_span_err; use rustc_hir::def::DefKind; use rustc_hir::def_id::LocalDefId; -use rustc_middle::ty::query::Providers; +use rustc_middle::query::Providers; use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt}; use rustc_span::{Span, Symbol}; diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index 3fe34f23aef..5cd2cd50c11 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -104,7 +104,7 @@ use rustc_hir as hir; use rustc_hir::Node; use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::middle; -use rustc_middle::ty::query::Providers; +use rustc_middle::query::Providers; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::util; use rustc_session::{config::EntryFnType, parse::feature_err}; diff --git a/compiler/rustc_hir_analysis/src/outlives/mod.rs b/compiler/rustc_hir_analysis/src/outlives/mod.rs index 42612eed750..a8596c707f3 100644 --- a/compiler/rustc_hir_analysis/src/outlives/mod.rs +++ b/compiler/rustc_hir_analysis/src/outlives/mod.rs @@ -1,7 +1,7 @@ use hir::Node; use rustc_hir as hir; use rustc_hir::def_id::LocalDefId; -use rustc_middle::ty::query::Providers; +use rustc_middle::query::Providers; use rustc_middle::ty::subst::GenericArgKind; use rustc_middle::ty::{self, CratePredicatesMap, TyCtxt}; use rustc_span::symbol::sym; diff --git a/compiler/rustc_hir_analysis/src/variance/mod.rs b/compiler/rustc_hir_analysis/src/variance/mod.rs index e735b048d73..3ebd9e134bf 100644 --- a/compiler/rustc_hir_analysis/src/variance/mod.rs +++ b/compiler/rustc_hir_analysis/src/variance/mod.rs @@ -6,7 +6,7 @@ use rustc_arena::DroplessArena; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId}; -use rustc_middle::ty::query::Providers; +use rustc_middle::query::Providers; use rustc_middle::ty::{self, CrateVariancesMap, SubstsRef, Ty, TyCtxt}; use rustc_middle::ty::{TypeSuperVisitable, TypeVisitable}; use std::ops::ControlFlow; diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs index 05e5d850bf9..3efdab53438 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs @@ -278,9 +278,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span: Span, ) -> bool { if let traits::FulfillmentErrorCode::CodeSelectionError( - traits::SelectionError::OutputTypeParameterMismatch(_, expected, _), + traits::SelectionError::OutputTypeParameterMismatch(box traits::SelectionOutputTypeParameterMismatch{ + expected_trait_ref, .. + }), ) = error.code - && let ty::Closure(def_id, _) | ty::Generator(def_id, ..) = expected.skip_binder().self_ty().kind() + && let ty::Closure(def_id, _) | ty::Generator(def_id, ..) = expected_trait_ref.skip_binder().self_ty().kind() && span.overlaps(self.tcx.def_span(*def_id)) { true diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index a2a4362e2f5..54b222ade03 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -2,6 +2,7 @@ #![feature(let_chains)] #![feature(try_blocks)] #![feature(never_type)] +#![feature(box_patterns)] #![feature(min_specialization)] #![feature(control_flow_enum)] #![feature(drain_filter)] @@ -67,8 +68,8 @@ use rustc_hir::{HirIdMap, Node}; use rustc_hir_analysis::astconv::AstConv; use rustc_hir_analysis::check::check_abi; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; +use rustc_middle::query::Providers; use rustc_middle::traits; -use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_session::config; use rustc_session::Session; diff --git a/compiler/rustc_hir_typeck/src/method/mod.rs b/compiler/rustc_hir_typeck/src/method/mod.rs index 5963a1632c5..cf9290c1a48 100644 --- a/compiler/rustc_hir_typeck/src/method/mod.rs +++ b/compiler/rustc_hir_typeck/src/method/mod.rs @@ -18,6 +18,7 @@ use rustc_hir as hir; use rustc_hir::def::{CtorOf, DefKind, Namespace}; use rustc_hir::def_id::DefId; use rustc_infer::infer::{self, InferOk}; +use rustc_middle::query::Providers; use rustc_middle::traits::ObligationCause; use rustc_middle::ty::subst::{InternalSubsts, SubstsRef}; use rustc_middle::ty::{self, GenericParamDefKind, Ty, TypeVisitableExt}; @@ -28,7 +29,7 @@ use rustc_trait_selection::traits::{self, NormalizeExt}; use self::probe::{IsSuggestion, ProbeScope}; -pub fn provide(providers: &mut ty::query::Providers) { +pub fn provide(providers: &mut Providers) { probe::provide(providers); } diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index 483e17460b3..f91f4f887c6 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -16,6 +16,7 @@ use rustc_infer::infer::canonical::{Canonical, QueryResponse}; use rustc_infer::infer::DefineOpaqueTypes; use rustc_infer::infer::{self, InferOk, TyCtxtInferExt}; use rustc_middle::middle::stability; +use rustc_middle::query::Providers; use rustc_middle::ty::fast_reject::{simplify_type, TreatParams}; use rustc_middle::ty::AssocItem; use rustc_middle::ty::GenericParamDefKind; @@ -495,7 +496,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } -pub fn provide(providers: &mut ty::query::Providers) { +pub fn provide(providers: &mut Providers) { providers.method_autoderef_steps = method_autoderef_steps; } diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 486c217707e..550a87e6102 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -2633,47 +2633,62 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Nothing, } let ast_generics = hir.get_generics(id.owner.def_id).unwrap(); - let (sp, mut introducer) = if let Some(span) = - ast_generics.bounds_span_for_suggestions(def_id) - { - (span, Introducer::Plus) - } else if let Some(colon_span) = param.colon_span { - (colon_span.shrink_to_hi(), Introducer::Nothing) - } else { - (param.span.shrink_to_hi(), Introducer::Colon) - }; - if matches!( - param.kind, - hir::GenericParamKind::Type { synthetic: true, .. }, - ) { - introducer = Introducer::Plus - } let trait_def_ids: FxHashSet<DefId> = ast_generics .bounds_for_param(def_id) .flat_map(|bp| bp.bounds.iter()) .filter_map(|bound| bound.trait_ref()?.trait_def_id()) .collect(); - if !candidates.iter().any(|t| trait_def_ids.contains(&t.def_id)) { - err.span_suggestions( - sp, - message(format!( - "restrict type parameter `{}` with", - param.name.ident(), - )), + if candidates.iter().any(|t| trait_def_ids.contains(&t.def_id)) { + return; + } + let msg = message(format!( + "restrict type parameter `{}` with", + param.name.ident(), + )); + let bounds_span = ast_generics.bounds_span_for_suggestions(def_id); + if rcvr_ty.is_ref() && param.is_impl_trait() && bounds_span.is_some() { + err.multipart_suggestions( + msg, candidates.iter().map(|t| { - format!( - "{} {}", - match introducer { - Introducer::Plus => " +", - Introducer::Colon => ":", - Introducer::Nothing => "", - }, - self.tcx.def_path_str(t.def_id), - ) + vec![ + (param.span.shrink_to_lo(), "(".to_string()), + ( + bounds_span.unwrap(), + format!(" + {})", self.tcx.def_path_str(t.def_id)), + ), + ] }), Applicability::MaybeIncorrect, ); + return; } + + let (sp, introducer) = if let Some(span) = bounds_span { + (span, Introducer::Plus) + } else if let Some(colon_span) = param.colon_span { + (colon_span.shrink_to_hi(), Introducer::Nothing) + } else if param.is_impl_trait() { + (param.span.shrink_to_hi(), Introducer::Plus) + } else { + (param.span.shrink_to_hi(), Introducer::Colon) + }; + + err.span_suggestions( + sp, + msg, + candidates.iter().map(|t| { + format!( + "{} {}", + match introducer { + Introducer::Plus => " +", + Introducer::Colon => ":", + Introducer::Nothing => "", + }, + self.tcx.def_path_str(t.def_id) + ) + }), + Applicability::MaybeIncorrect, + ); return; } Node::Item(hir::Item { diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs index cf95d4f04bb..59bee69cfff 100644 --- a/compiler/rustc_hir_typeck/src/writeback.rs +++ b/compiler/rustc_hir_typeck/src/writeback.rs @@ -836,7 +836,7 @@ impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Resolver<'cx, 'tcx> { debug!("Resolver::fold_const: input const `{:?}` not fully resolvable", ct); let e = self.report_error(ct); self.replaced_with_error = Some(e); - self.interner().const_error_with_guaranteed(ct.ty(), e) + self.interner().const_error(ct.ty(), e) } } } diff --git a/compiler/rustc_infer/src/infer/combine.rs b/compiler/rustc_infer/src/infer/combine.rs index 08eec0707c0..79fc02c6c79 100644 --- a/compiler/rustc_infer/src/infer/combine.rs +++ b/compiler/rustc_infer/src/infer/combine.rs @@ -26,24 +26,17 @@ use super::equate::Equate; use super::glb::Glb; use super::lub::Lub; use super::sub::Sub; -use super::type_variable::TypeVariableValue; -use super::{DefineOpaqueTypes, InferCtxt, MiscVariable, TypeTrace}; +use super::{DefineOpaqueTypes, InferCtxt, TypeTrace}; +use crate::infer::generalize::{self, CombineDelegate, Generalization}; use crate::traits::{Obligation, PredicateObligations}; -use rustc_data_structures::sso::SsoHashMap; -use rustc_hir::def_id::DefId; use rustc_middle::infer::canonical::OriginalQueryValues; use rustc_middle::infer::unify_key::{ConstVarValue, ConstVariableValue}; use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind}; -use rustc_middle::traits::ObligationCause; use rustc_middle::ty::error::{ExpectedFound, TypeError}; -use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation}; -use rustc_middle::ty::subst::SubstsRef; -use rustc_middle::ty::{ - self, AliasKind, FallibleTypeFolder, InferConst, ToPredicate, Ty, TyCtxt, TypeFoldable, - TypeSuperFoldable, TypeVisitableExt, -}; +use rustc_middle::ty::relate::{RelateResult, TypeRelation}; +use rustc_middle::ty::{self, AliasKind, InferConst, ToPredicate, Ty, TyCtxt, TypeVisitableExt}; use rustc_middle::ty::{IntType, UintType}; -use rustc_span::{Span, DUMMY_SP}; +use rustc_span::DUMMY_SP; #[derive(Clone)] pub struct CombineFields<'infcx, 'tcx> { @@ -55,13 +48,6 @@ pub struct CombineFields<'infcx, 'tcx> { pub define_opaque_types: DefineOpaqueTypes, } -#[derive(Copy, Clone, Debug)] -pub enum RelationDir { - SubtypeOf, - SupertypeOf, - EqTo, -} - impl<'tcx> InferCtxt<'tcx> { pub fn super_combine_tys<R>( &self, @@ -152,7 +138,7 @@ impl<'tcx> InferCtxt<'tcx> { Ok(a) } - _ => ty::relate::super_relate_tys(relation, a, b), + _ => ty::relate::structurally_relate_tys(relation, a, b), } } @@ -209,13 +195,13 @@ impl<'tcx> InferCtxt<'tcx> { // HACK: equating both sides with `[const error]` eagerly prevents us // from leaving unconstrained inference vars during things like impl // matching in the solver. - let a_error = self.tcx.const_error_with_guaranteed(a.ty(), guar); + let a_error = self.tcx.const_error(a.ty(), guar); if let ty::ConstKind::Infer(InferConst::Var(vid)) = a.kind() { - return self.unify_const_variable(vid, a_error); + return self.unify_const_variable(vid, a_error, relation.param_env()); } - let b_error = self.tcx.const_error_with_guaranteed(b.ty(), guar); + let b_error = self.tcx.const_error(b.ty(), guar); if let ty::ConstKind::Infer(InferConst::Var(vid)) = b.kind() { - return self.unify_const_variable(vid, b_error); + return self.unify_const_variable(vid, b_error, relation.param_env()); } return Ok(if relation.a_is_expected() { a_error } else { b_error }); @@ -237,11 +223,11 @@ impl<'tcx> InferCtxt<'tcx> { } (ty::ConstKind::Infer(InferConst::Var(vid)), _) => { - return self.unify_const_variable(vid, b); + return self.unify_const_variable(vid, b, relation.param_env()); } (_, ty::ConstKind::Infer(InferConst::Var(vid))) => { - return self.unify_const_variable(vid, a); + return self.unify_const_variable(vid, a, relation.param_env()); } (ty::ConstKind::Unevaluated(..), _) | (_, ty::ConstKind::Unevaluated(..)) if self.tcx.lazy_normalization() => @@ -252,7 +238,7 @@ impl<'tcx> InferCtxt<'tcx> { _ => {} } - ty::relate::super_relate_consts(relation, a, b) + ty::relate::structurally_relate_consts(relation, a, b) } /// Unifies the const variable `target_vid` with the given constant. @@ -294,24 +280,17 @@ impl<'tcx> InferCtxt<'tcx> { &self, target_vid: ty::ConstVid<'tcx>, ct: ty::Const<'tcx>, + param_env: ty::ParamEnv<'tcx>, ) -> RelateResult<'tcx, ty::Const<'tcx>> { - let (for_universe, span) = { - let mut inner = self.inner.borrow_mut(); - let variable_table = &mut inner.const_unification_table(); - let var_value = variable_table.probe_value(target_vid); - match var_value.val { - ConstVariableValue::Known { value } => { - bug!("instantiating {:?} which has a known value {:?}", target_vid, value) - } - ConstVariableValue::Unknown { universe } => (universe, var_value.origin.span), - } - }; - let value = ct.try_fold_with(&mut ConstInferUnifier { - infcx: self, - span, - for_universe, + let span = + self.inner.borrow_mut().const_unification_table().probe_value(target_vid).origin.span; + let Generalization { value, needs_wf: _ } = generalize::generalize( + self, + &mut CombineDelegate { infcx: self, span, param_env }, + ct, target_vid, - })?; + ty::Variance::Invariant, + )?; self.inner.borrow_mut().const_unification_table().union_value( target_vid, @@ -392,12 +371,10 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> { pub fn instantiate( &mut self, a_ty: Ty<'tcx>, - dir: RelationDir, + ambient_variance: ty::Variance, b_vid: ty::TyVid, a_is_expected: bool, ) -> RelateResult<'tcx, ()> { - use self::RelationDir::*; - // Get the actual variable that b_vid has been inferred to debug_assert!(self.infcx.inner.borrow_mut().type_variables().probe(b_vid).is_unknown()); @@ -412,7 +389,18 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> { // `'?2` and `?3` are fresh region/type inference // variables. (Down below, we will relate `a_ty <: b_ty`, // adding constraints like `'x: '?2` and `?1 <: ?3`.) - let Generalization { ty: b_ty, needs_wf } = self.generalize(a_ty, b_vid, dir)?; + let Generalization { value: b_ty, needs_wf } = generalize::generalize( + self.infcx, + &mut CombineDelegate { + infcx: self.infcx, + param_env: self.param_env, + span: self.trace.span(), + }, + a_ty, + b_vid, + ambient_variance, + )?; + debug!(?b_ty); self.infcx.inner.borrow_mut().type_variables().instantiate(b_vid, b_ty); @@ -431,78 +419,23 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> { // relations wind up attributed to the same spans. We need // to associate causes/spans with each of the relations in // the stack to get this right. - match dir { - EqTo => self.equate(a_is_expected).relate(a_ty, b_ty), - SubtypeOf => self.sub(a_is_expected).relate(a_ty, b_ty), - SupertypeOf => self.sub(a_is_expected).relate_with_variance( + match ambient_variance { + ty::Variance::Invariant => self.equate(a_is_expected).relate(a_ty, b_ty), + ty::Variance::Covariant => self.sub(a_is_expected).relate(a_ty, b_ty), + ty::Variance::Contravariant => self.sub(a_is_expected).relate_with_variance( ty::Contravariant, ty::VarianceDiagInfo::default(), a_ty, b_ty, ), + ty::Variance::Bivariant => { + unreachable!("no code should be generalizing bivariantly (currently)") + } }?; Ok(()) } - /// Attempts to generalize `ty` for the type variable `for_vid`. - /// This checks for cycle -- that is, whether the type `ty` - /// references `for_vid`. The `dir` is the "direction" for which we - /// a performing the generalization (i.e., are we producing a type - /// that can be used as a supertype etc). - /// - /// Preconditions: - /// - /// - `for_vid` is a "root vid" - #[instrument(skip(self), level = "trace", ret)] - fn generalize( - &self, - ty: Ty<'tcx>, - for_vid: ty::TyVid, - dir: RelationDir, - ) -> RelateResult<'tcx, Generalization<'tcx>> { - // Determine the ambient variance within which `ty` appears. - // The surrounding equation is: - // - // ty [op] ty2 - // - // where `op` is either `==`, `<:`, or `:>`. This maps quite - // naturally. - let ambient_variance = match dir { - RelationDir::EqTo => ty::Invariant, - RelationDir::SubtypeOf => ty::Covariant, - RelationDir::SupertypeOf => ty::Contravariant, - }; - - trace!(?ambient_variance); - - let for_universe = match self.infcx.inner.borrow_mut().type_variables().probe(for_vid) { - v @ TypeVariableValue::Known { .. } => { - bug!("instantiating {:?} which has a known value {:?}", for_vid, v,) - } - TypeVariableValue::Unknown { universe } => universe, - }; - - trace!(?for_universe); - trace!(?self.trace); - - let mut generalize = Generalizer { - infcx: self.infcx, - cause: &self.trace.cause, - for_vid_sub_root: self.infcx.inner.borrow_mut().type_variables().sub_root_var(for_vid), - for_universe, - ambient_variance, - needs_wf: false, - root_ty: ty, - param_env: self.param_env, - cache: SsoHashMap::new(), - }; - - let ty = generalize.relate(ty, ty)?; - let needs_wf = generalize.needs_wf; - Ok(Generalization { ty, needs_wf }) - } - pub fn register_obligations(&mut self, obligations: PredicateObligations<'tcx>) { self.obligations.extend(obligations.into_iter()); } @@ -514,313 +447,6 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> { } } -struct Generalizer<'cx, 'tcx> { - infcx: &'cx InferCtxt<'tcx>, - - /// The span, used when creating new type variables and things. - cause: &'cx ObligationCause<'tcx>, - - /// The vid of the type variable that is in the process of being - /// instantiated; if we find this within the type we are folding, - /// that means we would have created a cyclic type. - for_vid_sub_root: ty::TyVid, - - /// The universe of the type variable that is in the process of - /// being instantiated. Any fresh variables that we create in this - /// process should be in that same universe. - for_universe: ty::UniverseIndex, - - /// Track the variance as we descend into the type. - ambient_variance: ty::Variance, - - /// See the field `needs_wf` in `Generalization`. - needs_wf: bool, - - /// The root type that we are generalizing. Used when reporting cycles. - root_ty: Ty<'tcx>, - - param_env: ty::ParamEnv<'tcx>, - - cache: SsoHashMap<Ty<'tcx>, Ty<'tcx>>, -} - -/// Result from a generalization operation. This includes -/// not only the generalized type, but also a bool flag -/// indicating whether further WF checks are needed. -#[derive(Debug)] -struct Generalization<'tcx> { - ty: Ty<'tcx>, - - /// If true, then the generalized type may not be well-formed, - /// even if the source type is well-formed, so we should add an - /// additional check to enforce that it is. This arises in - /// particular around 'bivariant' type parameters that are only - /// constrained by a where-clause. As an example, imagine a type: - /// - /// struct Foo<A, B> where A: Iterator<Item = B> { - /// data: A - /// } - /// - /// here, `A` will be covariant, but `B` is - /// unconstrained. However, whatever it is, for `Foo` to be WF, it - /// must be equal to `A::Item`. If we have an input `Foo<?A, ?B>`, - /// then after generalization we will wind up with a type like - /// `Foo<?C, ?D>`. When we enforce that `Foo<?A, ?B> <: Foo<?C, - /// ?D>` (or `>:`), we will wind up with the requirement that `?A - /// <: ?C`, but no particular relationship between `?B` and `?D` - /// (after all, we do not know the variance of the normalized form - /// of `A::Item` with respect to `A`). If we do nothing else, this - /// may mean that `?D` goes unconstrained (as in #41677). So, in - /// this scenario where we create a new type variable in a - /// bivariant context, we set the `needs_wf` flag to true. This - /// will force the calling code to check that `WF(Foo<?C, ?D>)` - /// holds, which in turn implies that `?C::Item == ?D`. So once - /// `?C` is constrained, that should suffice to restrict `?D`. - needs_wf: bool, -} - -impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> { - fn tcx(&self) -> TyCtxt<'tcx> { - self.infcx.tcx - } - - fn param_env(&self) -> ty::ParamEnv<'tcx> { - self.param_env - } - - fn tag(&self) -> &'static str { - "Generalizer" - } - - fn a_is_expected(&self) -> bool { - true - } - - fn binders<T>( - &mut self, - a: ty::Binder<'tcx, T>, - b: ty::Binder<'tcx, T>, - ) -> RelateResult<'tcx, ty::Binder<'tcx, T>> - where - T: Relate<'tcx>, - { - Ok(a.rebind(self.relate(a.skip_binder(), b.skip_binder())?)) - } - - fn relate_item_substs( - &mut self, - item_def_id: DefId, - a_subst: SubstsRef<'tcx>, - b_subst: SubstsRef<'tcx>, - ) -> RelateResult<'tcx, SubstsRef<'tcx>> { - if self.ambient_variance == ty::Variance::Invariant { - // Avoid fetching the variance if we are in an invariant - // context; no need, and it can induce dependency cycles - // (e.g., #41849). - relate::relate_substs(self, a_subst, b_subst) - } else { - let tcx = self.tcx(); - let opt_variances = tcx.variances_of(item_def_id); - relate::relate_substs_with_variances( - self, - item_def_id, - &opt_variances, - a_subst, - b_subst, - true, - ) - } - } - - fn relate_with_variance<T: Relate<'tcx>>( - &mut self, - variance: ty::Variance, - _info: ty::VarianceDiagInfo<'tcx>, - a: T, - b: T, - ) -> RelateResult<'tcx, T> { - let old_ambient_variance = self.ambient_variance; - self.ambient_variance = self.ambient_variance.xform(variance); - - let result = self.relate(a, b); - self.ambient_variance = old_ambient_variance; - result - } - - fn tys(&mut self, t: Ty<'tcx>, t2: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { - assert_eq!(t, t2); // we are abusing TypeRelation here; both LHS and RHS ought to be == - - if let Some(&result) = self.cache.get(&t) { - return Ok(result); - } - debug!("generalize: t={:?}", t); - - // Check to see whether the type we are generalizing references - // any other type variable related to `vid` via - // subtyping. This is basically our "occurs check", preventing - // us from creating infinitely sized types. - let result = match *t.kind() { - ty::Infer(ty::TyVar(vid)) => { - let vid = self.infcx.inner.borrow_mut().type_variables().root_var(vid); - let sub_vid = self.infcx.inner.borrow_mut().type_variables().sub_root_var(vid); - if sub_vid == self.for_vid_sub_root { - // If sub-roots are equal, then `for_vid` and - // `vid` are related via subtyping. - Err(TypeError::CyclicTy(self.root_ty)) - } else { - let probe = self.infcx.inner.borrow_mut().type_variables().probe(vid); - match probe { - TypeVariableValue::Known { value: u } => { - debug!("generalize: known value {:?}", u); - self.relate(u, u) - } - TypeVariableValue::Unknown { universe } => { - match self.ambient_variance { - // Invariant: no need to make a fresh type variable. - ty::Invariant => { - if self.for_universe.can_name(universe) { - return Ok(t); - } - } - - // Bivariant: make a fresh var, but we - // may need a WF predicate. See - // comment on `needs_wf` field for - // more info. - ty::Bivariant => self.needs_wf = true, - - // Co/contravariant: this will be - // sufficiently constrained later on. - ty::Covariant | ty::Contravariant => (), - } - - let origin = - *self.infcx.inner.borrow_mut().type_variables().var_origin(vid); - let new_var_id = self - .infcx - .inner - .borrow_mut() - .type_variables() - .new_var(self.for_universe, origin); - let u = self.tcx().mk_ty_var(new_var_id); - - // Record that we replaced `vid` with `new_var_id` as part of a generalization - // operation. This is needed to detect cyclic types. To see why, see the - // docs in the `type_variables` module. - self.infcx.inner.borrow_mut().type_variables().sub(vid, new_var_id); - debug!("generalize: replacing original vid={:?} with new={:?}", vid, u); - Ok(u) - } - } - } - } - ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) => { - // No matter what mode we are in, - // integer/floating-point types must be equal to be - // relatable. - Ok(t) - } - ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => { - let s = self.relate(substs, substs)?; - Ok(if s == substs { t } else { self.infcx.tcx.mk_opaque(def_id, s) }) - } - _ => relate::super_relate_tys(self, t, t), - }?; - - self.cache.insert(t, result); - Ok(result) - } - - fn regions( - &mut self, - r: ty::Region<'tcx>, - r2: ty::Region<'tcx>, - ) -> RelateResult<'tcx, ty::Region<'tcx>> { - assert_eq!(r, r2); // we are abusing TypeRelation here; both LHS and RHS ought to be == - - debug!("generalize: regions r={:?}", r); - - match *r { - // Never make variables for regions bound within the type itself, - // nor for erased regions. - ty::ReLateBound(..) | ty::ReErased => { - return Ok(r); - } - - ty::ReError(_) => { - return Ok(r); - } - - ty::RePlaceholder(..) - | ty::ReVar(..) - | ty::ReStatic - | ty::ReEarlyBound(..) - | ty::ReFree(..) => { - // see common code below - } - } - - // If we are in an invariant context, we can re-use the region - // as is, unless it happens to be in some universe that we - // can't name. (In the case of a region *variable*, we could - // use it if we promoted it into our universe, but we don't - // bother.) - if let ty::Invariant = self.ambient_variance { - let r_universe = self.infcx.universe_of_region(r); - if self.for_universe.can_name(r_universe) { - return Ok(r); - } - } - - // FIXME: This is non-ideal because we don't give a - // very descriptive origin for this region variable. - Ok(self.infcx.next_region_var_in_universe(MiscVariable(self.cause.span), self.for_universe)) - } - - fn consts( - &mut self, - c: ty::Const<'tcx>, - c2: ty::Const<'tcx>, - ) -> RelateResult<'tcx, ty::Const<'tcx>> { - assert_eq!(c, c2); // we are abusing TypeRelation here; both LHS and RHS ought to be == - - match c.kind() { - ty::ConstKind::Infer(InferConst::Var(vid)) => { - let mut inner = self.infcx.inner.borrow_mut(); - let variable_table = &mut inner.const_unification_table(); - let var_value = variable_table.probe_value(vid); - match var_value.val { - ConstVariableValue::Known { value: u } => { - drop(inner); - self.relate(u, u) - } - ConstVariableValue::Unknown { universe } => { - if self.for_universe.can_name(universe) { - Ok(c) - } else { - let new_var_id = variable_table.new_key(ConstVarValue { - origin: var_value.origin, - val: ConstVariableValue::Unknown { universe: self.for_universe }, - }); - Ok(self.tcx().mk_const(new_var_id, c.ty())) - } - } - } - } - ty::ConstKind::Unevaluated(ty::UnevaluatedConst { def, substs }) => { - let substs = self.relate_with_variance( - ty::Variance::Invariant, - ty::VarianceDiagInfo::default(), - substs, - substs, - )?; - Ok(self.tcx().mk_const(ty::UnevaluatedConst { def, substs }, c.ty())) - } - _ => relate::super_relate_consts(self, c, c), - } - } -} - pub trait ObligationEmittingRelation<'tcx>: TypeRelation<'tcx> { /// Register obligations that must hold in order for this relation to hold fn register_obligations(&mut self, obligations: PredicateObligations<'tcx>); @@ -873,135 +499,3 @@ fn float_unification_error<'tcx>( let (ty::FloatVarValue(a), ty::FloatVarValue(b)) = v; TypeError::FloatMismatch(ExpectedFound::new(a_is_expected, a, b)) } - -struct ConstInferUnifier<'cx, 'tcx> { - infcx: &'cx InferCtxt<'tcx>, - - span: Span, - - for_universe: ty::UniverseIndex, - - /// The vid of the const variable that is in the process of being - /// instantiated; if we find this within the const we are folding, - /// that means we would have created a cyclic const. - target_vid: ty::ConstVid<'tcx>, -} - -impl<'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for ConstInferUnifier<'_, 'tcx> { - type Error = TypeError<'tcx>; - - fn interner(&self) -> TyCtxt<'tcx> { - self.infcx.tcx - } - - #[instrument(level = "debug", skip(self), ret)] - fn try_fold_ty(&mut self, t: Ty<'tcx>) -> Result<Ty<'tcx>, TypeError<'tcx>> { - match t.kind() { - &ty::Infer(ty::TyVar(vid)) => { - let vid = self.infcx.inner.borrow_mut().type_variables().root_var(vid); - let probe = self.infcx.inner.borrow_mut().type_variables().probe(vid); - match probe { - TypeVariableValue::Known { value: u } => { - debug!("ConstOccursChecker: known value {:?}", u); - u.try_fold_with(self) - } - TypeVariableValue::Unknown { universe } => { - if self.for_universe.can_name(universe) { - return Ok(t); - } - - let origin = - *self.infcx.inner.borrow_mut().type_variables().var_origin(vid); - let new_var_id = self - .infcx - .inner - .borrow_mut() - .type_variables() - .new_var(self.for_universe, origin); - Ok(self.interner().mk_ty_var(new_var_id)) - } - } - } - ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) => Ok(t), - _ => t.try_super_fold_with(self), - } - } - - #[instrument(level = "debug", skip(self), ret)] - fn try_fold_region( - &mut self, - r: ty::Region<'tcx>, - ) -> Result<ty::Region<'tcx>, TypeError<'tcx>> { - debug!("ConstInferUnifier: r={:?}", r); - - match *r { - // Never make variables for regions bound within the type itself, - // nor for erased regions. - ty::ReLateBound(..) | ty::ReErased | ty::ReError(_) => { - return Ok(r); - } - - ty::RePlaceholder(..) - | ty::ReVar(..) - | ty::ReStatic - | ty::ReEarlyBound(..) - | ty::ReFree(..) => { - // see common code below - } - } - - let r_universe = self.infcx.universe_of_region(r); - if self.for_universe.can_name(r_universe) { - return Ok(r); - } else { - // FIXME: This is non-ideal because we don't give a - // very descriptive origin for this region variable. - Ok(self.infcx.next_region_var_in_universe(MiscVariable(self.span), self.for_universe)) - } - } - - #[instrument(level = "debug", skip(self), ret)] - fn try_fold_const(&mut self, c: ty::Const<'tcx>) -> Result<ty::Const<'tcx>, TypeError<'tcx>> { - match c.kind() { - ty::ConstKind::Infer(InferConst::Var(vid)) => { - // Check if the current unification would end up - // unifying `target_vid` with a const which contains - // an inference variable which is unioned with `target_vid`. - // - // Not doing so can easily result in stack overflows. - if self - .infcx - .inner - .borrow_mut() - .const_unification_table() - .unioned(self.target_vid, vid) - { - return Err(TypeError::CyclicConst(c)); - } - - let var_value = - self.infcx.inner.borrow_mut().const_unification_table().probe_value(vid); - match var_value.val { - ConstVariableValue::Known { value: u } => u.try_fold_with(self), - ConstVariableValue::Unknown { universe } => { - if self.for_universe.can_name(universe) { - Ok(c) - } else { - let new_var_id = - self.infcx.inner.borrow_mut().const_unification_table().new_key( - ConstVarValue { - origin: var_value.origin, - val: ConstVariableValue::Unknown { - universe: self.for_universe, - }, - }, - ); - Ok(self.interner().mk_const(new_var_id, c.ty())) - } - } - } - } - _ => c.try_super_fold_with(self), - } - } -} diff --git a/compiler/rustc_infer/src/infer/equate.rs b/compiler/rustc_infer/src/infer/equate.rs index f90f7674b55..793505e4ab2 100644 --- a/compiler/rustc_infer/src/infer/equate.rs +++ b/compiler/rustc_infer/src/infer/equate.rs @@ -1,7 +1,7 @@ use crate::infer::DefineOpaqueTypes; use crate::traits::PredicateObligations; -use super::combine::{CombineFields, ObligationEmittingRelation, RelationDir}; +use super::combine::{CombineFields, ObligationEmittingRelation}; use super::Subtype; use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation}; @@ -88,11 +88,11 @@ impl<'tcx> TypeRelation<'tcx> for Equate<'_, '_, 'tcx> { } (&ty::Infer(TyVar(a_id)), _) => { - self.fields.instantiate(b, RelationDir::EqTo, a_id, self.a_is_expected)?; + self.fields.instantiate(b, ty::Invariant, a_id, self.a_is_expected)?; } (_, &ty::Infer(TyVar(b_id))) => { - self.fields.instantiate(a, RelationDir::EqTo, b_id, self.a_is_expected)?; + self.fields.instantiate(a, ty::Invariant, b_id, self.a_is_expected)?; } ( diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index ce70f39cc40..ad4f5058b5e 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -2723,7 +2723,7 @@ impl<'tcx> TypeRelation<'tcx> for SameTypeModuloInfer<'_, 'tcx> { | (ty::Infer(ty::InferTy::TyVar(_)), _) | (_, ty::Infer(ty::InferTy::TyVar(_))) => Ok(a), (ty::Infer(_), _) | (_, ty::Infer(_)) => Err(TypeError::Mismatch), - _ => relate::super_relate_tys(self, a, b), + _ => relate::structurally_relate_tys(self, a, b), } } diff --git a/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs b/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs index 064811bd29d..421eb807a14 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs @@ -2,6 +2,7 @@ use super::TypeErrCtxt; use rustc_errors::Applicability::{MachineApplicable, MaybeIncorrect}; use rustc_errors::{pluralize, Diagnostic, MultiSpan}; use rustc_hir as hir; +use rustc_hir::def::DefKind; use rustc_middle::traits::ObligationCauseCode; use rustc_middle::ty::error::ExpectedFound; use rustc_middle::ty::print::Printer; @@ -256,6 +257,15 @@ impl<T> Trait<T> for X { ); } } + (ty::Alias(ty::Opaque, alias), _) | (_, ty::Alias(ty::Opaque, alias)) if alias.def_id.is_local() && matches!(tcx.def_kind(body_owner_def_id), DefKind::AssocFn | DefKind::AssocConst) => { + if tcx.is_type_alias_impl_trait(alias.def_id) { + if !tcx.opaque_types_defined_by(body_owner_def_id.expect_local()).contains(&alias.def_id.expect_local()) { + diag.span_note(tcx.def_span(body_owner_def_id), "\ + this item must have the opaque type in its signature \ + in order to be able to register hidden types"); + } + } + } (ty::FnPtr(_), ty::FnDef(def, _)) if let hir::def::DefKind::Fn = tcx.def_kind(def) => { diag.note( diff --git a/compiler/rustc_infer/src/infer/generalize.rs b/compiler/rustc_infer/src/infer/generalize.rs new file mode 100644 index 00000000000..d4a1dacde10 --- /dev/null +++ b/compiler/rustc_infer/src/infer/generalize.rs @@ -0,0 +1,479 @@ +use rustc_data_structures::sso::SsoHashMap; +use rustc_hir::def_id::DefId; +use rustc_middle::infer::unify_key::{ConstVarValue, ConstVariableValue}; +use rustc_middle::ty::error::TypeError; +use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation}; +use rustc_middle::ty::{self, InferConst, Term, Ty, TyCtxt, TypeVisitableExt}; +use rustc_span::Span; + +use crate::infer::nll_relate::TypeRelatingDelegate; +use crate::infer::type_variable::TypeVariableValue; +use crate::infer::{InferCtxt, RegionVariableOrigin}; + +/// Attempts to generalize `term` for the type variable `for_vid`. +/// This checks for cycles -- that is, whether the type `term` +/// references `for_vid`. +pub(super) fn generalize<'tcx, D: GeneralizerDelegate<'tcx>, T: Into<Term<'tcx>> + Relate<'tcx>>( + infcx: &InferCtxt<'tcx>, + delegate: &mut D, + term: T, + for_vid: impl Into<ty::TermVid<'tcx>>, + ambient_variance: ty::Variance, +) -> RelateResult<'tcx, Generalization<T>> { + let (for_universe, root_vid) = match for_vid.into() { + ty::TermVid::Ty(ty_vid) => ( + infcx.probe_ty_var(ty_vid).unwrap_err(), + ty::TermVid::Ty(infcx.inner.borrow_mut().type_variables().sub_root_var(ty_vid)), + ), + ty::TermVid::Const(ct_vid) => ( + infcx.probe_const_var(ct_vid).unwrap_err(), + ty::TermVid::Const(infcx.inner.borrow_mut().const_unification_table().find(ct_vid)), + ), + }; + + let mut generalizer = Generalizer { + infcx, + delegate, + ambient_variance, + root_vid, + for_universe, + root_term: term.into(), + needs_wf: false, + cache: Default::default(), + }; + + assert!(!term.has_escaping_bound_vars()); + let value = generalizer.relate(term, term)?; + let needs_wf = generalizer.needs_wf; + Ok(Generalization { value, needs_wf }) +} + +/// Abstracts the handling of region vars between HIR and MIR/NLL typechecking +/// in the generalizer code. +pub trait GeneralizerDelegate<'tcx> { + fn param_env(&self) -> ty::ParamEnv<'tcx>; + + fn forbid_inference_vars() -> bool; + + fn generalize_region(&mut self, universe: ty::UniverseIndex) -> ty::Region<'tcx>; +} + +pub struct CombineDelegate<'cx, 'tcx> { + pub infcx: &'cx InferCtxt<'tcx>, + pub param_env: ty::ParamEnv<'tcx>, + pub span: Span, +} + +impl<'tcx> GeneralizerDelegate<'tcx> for CombineDelegate<'_, 'tcx> { + fn param_env(&self) -> ty::ParamEnv<'tcx> { + self.param_env + } + + fn forbid_inference_vars() -> bool { + false + } + + fn generalize_region(&mut self, universe: ty::UniverseIndex) -> ty::Region<'tcx> { + // FIXME: This is non-ideal because we don't give a + // very descriptive origin for this region variable. + self.infcx + .next_region_var_in_universe(RegionVariableOrigin::MiscVariable(self.span), universe) + } +} + +impl<'tcx, T> GeneralizerDelegate<'tcx> for T +where + T: TypeRelatingDelegate<'tcx>, +{ + fn param_env(&self) -> ty::ParamEnv<'tcx> { + <Self as TypeRelatingDelegate<'tcx>>::param_env(self) + } + + fn forbid_inference_vars() -> bool { + <Self as TypeRelatingDelegate<'tcx>>::forbid_inference_vars() + } + + fn generalize_region(&mut self, universe: ty::UniverseIndex) -> ty::Region<'tcx> { + <Self as TypeRelatingDelegate<'tcx>>::generalize_existential(self, universe) + } +} + +/// The "generalizer" is used when handling inference variables. +/// +/// The basic strategy for handling a constraint like `?A <: B` is to +/// apply a "generalization strategy" to the term `B` -- this replaces +/// all the lifetimes in the term `B` with fresh inference variables. +/// (You can read more about the strategy in this [blog post].) +/// +/// As an example, if we had `?A <: &'x u32`, we would generalize `&'x +/// u32` to `&'0 u32` where `'0` is a fresh variable. This becomes the +/// value of `A`. Finally, we relate `&'0 u32 <: &'x u32`, which +/// establishes `'0: 'x` as a constraint. +/// +/// [blog post]: https://is.gd/0hKvIr +struct Generalizer<'me, 'tcx, D> { + infcx: &'me InferCtxt<'tcx>, + + /// This is used to abstract the behaviors of the three previous + /// generalizer-like implementations (`Generalizer`, `TypeGeneralizer`, + /// and `ConstInferUnifier`). See [`GeneralizerDelegate`] for more + /// information. + delegate: &'me mut D, + + /// After we generalize this type, we are going to relate it to + /// some other type. What will be the variance at this point? + ambient_variance: ty::Variance, + + /// The vid of the type variable that is in the process of being + /// instantiated. If we find this within the value we are folding, + /// that means we would have created a cyclic value. + root_vid: ty::TermVid<'tcx>, + + /// The universe of the type variable that is in the process of being + /// instantiated. If we find anything that this universe cannot name, + /// we reject the relation. + for_universe: ty::UniverseIndex, + + /// The root term (const or type) we're generalizing. Used for cycle errors. + root_term: Term<'tcx>, + + cache: SsoHashMap<Ty<'tcx>, Ty<'tcx>>, + + /// See the field `needs_wf` in `Generalization`. + needs_wf: bool, +} + +impl<'tcx, D> Generalizer<'_, 'tcx, D> { + /// Create an error that corresponds to the term kind in `root_term` + fn cyclic_term_error(&self) -> TypeError<'tcx> { + match self.root_term.unpack() { + ty::TermKind::Ty(ty) => TypeError::CyclicTy(ty), + ty::TermKind::Const(ct) => TypeError::CyclicConst(ct), + } + } +} + +impl<'tcx, D> TypeRelation<'tcx> for Generalizer<'_, 'tcx, D> +where + D: GeneralizerDelegate<'tcx>, +{ + fn tcx(&self) -> TyCtxt<'tcx> { + self.infcx.tcx + } + + fn param_env(&self) -> ty::ParamEnv<'tcx> { + self.delegate.param_env() + } + + fn tag(&self) -> &'static str { + "Generalizer" + } + + fn a_is_expected(&self) -> bool { + true + } + + fn relate_item_substs( + &mut self, + item_def_id: DefId, + a_subst: ty::SubstsRef<'tcx>, + b_subst: ty::SubstsRef<'tcx>, + ) -> RelateResult<'tcx, ty::SubstsRef<'tcx>> { + if self.ambient_variance == ty::Variance::Invariant { + // Avoid fetching the variance if we are in an invariant + // context; no need, and it can induce dependency cycles + // (e.g., #41849). + relate::relate_substs(self, a_subst, b_subst) + } else { + let tcx = self.tcx(); + let opt_variances = tcx.variances_of(item_def_id); + relate::relate_substs_with_variances( + self, + item_def_id, + opt_variances, + a_subst, + b_subst, + true, + ) + } + } + + #[instrument(level = "debug", skip(self, variance, b), ret)] + fn relate_with_variance<T: Relate<'tcx>>( + &mut self, + variance: ty::Variance, + _info: ty::VarianceDiagInfo<'tcx>, + a: T, + b: T, + ) -> RelateResult<'tcx, T> { + let old_ambient_variance = self.ambient_variance; + self.ambient_variance = self.ambient_variance.xform(variance); + debug!(?self.ambient_variance, "new ambient variance"); + let r = self.relate(a, b)?; + self.ambient_variance = old_ambient_variance; + Ok(r) + } + + #[instrument(level = "debug", skip(self, t2), ret)] + fn tys(&mut self, t: Ty<'tcx>, t2: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { + assert_eq!(t, t2); // we are misusing TypeRelation here; both LHS and RHS ought to be == + + if let Some(&result) = self.cache.get(&t) { + return Ok(result); + } + + // Check to see whether the type we are generalizing references + // any other type variable related to `vid` via + // subtyping. This is basically our "occurs check", preventing + // us from creating infinitely sized types. + let g = match *t.kind() { + ty::Infer(ty::TyVar(_)) | ty::Infer(ty::IntVar(_)) | ty::Infer(ty::FloatVar(_)) + if D::forbid_inference_vars() => + { + bug!("unexpected inference variable encountered in NLL generalization: {t}"); + } + + ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => { + bug!("unexpected infer type: {t}") + } + + ty::Infer(ty::TyVar(vid)) => { + let mut inner = self.infcx.inner.borrow_mut(); + let vid = inner.type_variables().root_var(vid); + let sub_vid = inner.type_variables().sub_root_var(vid); + + if ty::TermVid::Ty(sub_vid) == self.root_vid { + // If sub-roots are equal, then `root_vid` and + // `vid` are related via subtyping. + Err(self.cyclic_term_error()) + } else { + let probe = inner.type_variables().probe(vid); + match probe { + TypeVariableValue::Known { value: u } => { + drop(inner); + self.relate(u, u) + } + TypeVariableValue::Unknown { universe } => { + match self.ambient_variance { + // Invariant: no need to make a fresh type variable + // if we can name the universe. + ty::Invariant => { + if self.for_universe.can_name(universe) { + return Ok(t); + } + } + + // Bivariant: make a fresh var, but we + // may need a WF predicate. See + // comment on `needs_wf` field for + // more info. + ty::Bivariant => self.needs_wf = true, + + // Co/contravariant: this will be + // sufficiently constrained later on. + ty::Covariant | ty::Contravariant => (), + } + + let origin = *inner.type_variables().var_origin(vid); + let new_var_id = + inner.type_variables().new_var(self.for_universe, origin); + let u = self.tcx().mk_ty_var(new_var_id); + + // Record that we replaced `vid` with `new_var_id` as part of a generalization + // operation. This is needed to detect cyclic types. To see why, see the + // docs in the `type_variables` module. + inner.type_variables().sub(vid, new_var_id); + debug!("replacing original vid={:?} with new={:?}", vid, u); + Ok(u) + } + } + } + } + + ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) => { + // No matter what mode we are in, + // integer/floating-point types must be equal to be + // relatable. + Ok(t) + } + + ty::Placeholder(placeholder) => { + if self.for_universe.can_name(placeholder.universe) { + Ok(t) + } else { + debug!( + "root universe {:?} cannot name placeholder in universe {:?}", + self.for_universe, placeholder.universe + ); + Err(TypeError::Mismatch) + } + } + + _ => relate::structurally_relate_tys(self, t, t), + }?; + + self.cache.insert(t, g); + Ok(g) + } + + #[instrument(level = "debug", skip(self, r2), ret)] + fn regions( + &mut self, + r: ty::Region<'tcx>, + r2: ty::Region<'tcx>, + ) -> RelateResult<'tcx, ty::Region<'tcx>> { + assert_eq!(r, r2); // we are misusing TypeRelation here; both LHS and RHS ought to be == + + match *r { + // Never make variables for regions bound within the type itself, + // nor for erased regions. + ty::ReLateBound(..) | ty::ReErased => { + return Ok(r); + } + + // It doesn't really matter for correctness if we generalize ReError, + // since we're already on a doomed compilation path. + ty::ReError(_) => { + return Ok(r); + } + + ty::RePlaceholder(..) + | ty::ReVar(..) + | ty::ReStatic + | ty::ReEarlyBound(..) + | ty::ReFree(..) => { + // see common code below + } + } + + // If we are in an invariant context, we can re-use the region + // as is, unless it happens to be in some universe that we + // can't name. + if let ty::Invariant = self.ambient_variance { + let r_universe = self.infcx.universe_of_region(r); + if self.for_universe.can_name(r_universe) { + return Ok(r); + } + } + + Ok(self.delegate.generalize_region(self.for_universe)) + } + + #[instrument(level = "debug", skip(self, c2), ret)] + fn consts( + &mut self, + c: ty::Const<'tcx>, + c2: ty::Const<'tcx>, + ) -> RelateResult<'tcx, ty::Const<'tcx>> { + assert_eq!(c, c2); // we are misusing TypeRelation here; both LHS and RHS ought to be == + + match c.kind() { + ty::ConstKind::Infer(InferConst::Var(_)) if D::forbid_inference_vars() => { + bug!("unexpected inference variable encountered in NLL generalization: {:?}", c); + } + ty::ConstKind::Infer(InferConst::Var(vid)) => { + // If root const vids are equal, then `root_vid` and + // `vid` are related and we'd be inferring an infinitely + // deep const. + if ty::TermVid::Const( + self.infcx.inner.borrow_mut().const_unification_table().find(vid), + ) == self.root_vid + { + return Err(self.cyclic_term_error()); + } + + let mut inner = self.infcx.inner.borrow_mut(); + let variable_table = &mut inner.const_unification_table(); + let var_value = variable_table.probe_value(vid); + match var_value.val { + ConstVariableValue::Known { value: u } => { + drop(inner); + self.relate(u, u) + } + ConstVariableValue::Unknown { universe } => { + if self.for_universe.can_name(universe) { + Ok(c) + } else { + let new_var_id = variable_table.new_key(ConstVarValue { + origin: var_value.origin, + val: ConstVariableValue::Unknown { universe: self.for_universe }, + }); + Ok(self.tcx().mk_const(new_var_id, c.ty())) + } + } + } + } + // FIXME: remove this branch once `structurally_relate_consts` is fully + // structural. + ty::ConstKind::Unevaluated(ty::UnevaluatedConst { def, substs }) => { + let substs = self.relate_with_variance( + ty::Variance::Invariant, + ty::VarianceDiagInfo::default(), + substs, + substs, + )?; + Ok(self.tcx().mk_const(ty::UnevaluatedConst { def, substs }, c.ty())) + } + ty::ConstKind::Placeholder(placeholder) => { + if self.for_universe.can_name(placeholder.universe) { + Ok(c) + } else { + debug!( + "root universe {:?} cannot name placeholder in universe {:?}", + self.for_universe, placeholder.universe + ); + Err(TypeError::Mismatch) + } + } + _ => relate::structurally_relate_consts(self, c, c), + } + } + + #[instrument(level = "debug", skip(self), ret)] + fn binders<T>( + &mut self, + a: ty::Binder<'tcx, T>, + _: ty::Binder<'tcx, T>, + ) -> RelateResult<'tcx, ty::Binder<'tcx, T>> + where + T: Relate<'tcx>, + { + let result = self.relate(a.skip_binder(), a.skip_binder())?; + Ok(a.rebind(result)) + } +} + +/// Result from a generalization operation. This includes +/// not only the generalized type, but also a bool flag +/// indicating whether further WF checks are needed. +#[derive(Debug)] +pub struct Generalization<T> { + pub value: T, + + /// If true, then the generalized type may not be well-formed, + /// even if the source type is well-formed, so we should add an + /// additional check to enforce that it is. This arises in + /// particular around 'bivariant' type parameters that are only + /// constrained by a where-clause. As an example, imagine a type: + /// + /// struct Foo<A, B> where A: Iterator<Item = B> { + /// data: A + /// } + /// + /// here, `A` will be covariant, but `B` is + /// unconstrained. However, whatever it is, for `Foo` to be WF, it + /// must be equal to `A::Item`. If we have an input `Foo<?A, ?B>`, + /// then after generalization we will wind up with a type like + /// `Foo<?C, ?D>`. When we enforce that `Foo<?A, ?B> <: Foo<?C, + /// ?D>` (or `>:`), we will wind up with the requirement that `?A + /// <: ?C`, but no particular relationship between `?B` and `?D` + /// (after all, we do not know the variance of the normalized form + /// of `A::Item` with respect to `A`). If we do nothing else, this + /// may mean that `?D` goes unconstrained (as in #41677). So, in + /// this scenario where we create a new type variable in a + /// bivariant context, we set the `needs_wf` flag to true. This + /// will force the calling code to check that `WF(Foo<?C, ?D>)` + /// holds, which in turn implies that `?C::Item == ?D`. So once + /// `?C` is constrained, that should suffice to restrict `?D`. + pub needs_wf: bool, +} diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 9a95a9c8375..f8329965c43 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -58,6 +58,7 @@ pub mod error_reporting; pub mod free_regions; mod freshen; mod fudge; +mod generalize; mod glb; mod higher_ranked; pub mod lattice; @@ -1533,7 +1534,7 @@ impl<'tcx> InferCtxt<'tcx> { if let Some(ct) = tcx.thir_abstract_const(unevaluated.def)? { let ct = tcx.expand_abstract_consts(ct.subst(tcx, substs)); if let Err(e) = ct.error_reported() { - return Err(ErrorHandled::Reported(e)); + return Err(ErrorHandled::Reported(e.into())); } else if ct.has_non_region_infer() || ct.has_non_region_param() { return Err(ErrorHandled::TooGeneric); } else { diff --git a/compiler/rustc_infer/src/infer/nll_relate/mod.rs b/compiler/rustc_infer/src/infer/nll_relate/mod.rs index 88a0a81e276..4ae6af5f5be 100644 --- a/compiler/rustc_infer/src/infer/nll_relate/mod.rs +++ b/compiler/rustc_infer/src/infer/nll_relate/mod.rs @@ -21,21 +21,20 @@ //! thing we relate in chalk are basically domain goals and their //! constituents) -use crate::infer::InferCtxt; -use crate::infer::{ConstVarValue, ConstVariableValue}; -use crate::infer::{TypeVariableOrigin, TypeVariableOriginKind}; -use crate::traits::{Obligation, PredicateObligations}; use rustc_data_structures::fx::FxHashMap; use rustc_middle::traits::ObligationCause; -use rustc_middle::ty::error::TypeError; use rustc_middle::ty::fold::FnMutDelegate; -use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation}; +use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation}; use rustc_middle::ty::visit::TypeVisitableExt; use rustc_middle::ty::{self, InferConst, Ty, TyCtxt}; use rustc_span::{Span, Symbol}; use std::fmt::Debug; -use super::combine::ObligationEmittingRelation; +use crate::infer::combine::ObligationEmittingRelation; +use crate::infer::generalize::{self, Generalization}; +use crate::infer::InferCtxt; +use crate::infer::{TypeVariableOrigin, TypeVariableOriginKind}; +use crate::traits::{Obligation, PredicateObligations}; pub struct TypeRelating<'me, 'tcx, D> where @@ -198,7 +197,7 @@ where _ => (), } - let generalized_ty = self.generalize_value(value_ty, vid)?; + let generalized_ty = self.generalize(value_ty, vid)?; debug!("relate_ty_var: generalized_ty = {:?}", generalized_ty); if D::forbid_inference_vars() { @@ -217,26 +216,15 @@ where result } - fn generalize_value<T: Relate<'tcx>>( - &mut self, - value: T, - for_vid: ty::TyVid, - ) -> RelateResult<'tcx, T> { - let universe = self.infcx.probe_ty_var(for_vid).unwrap_err(); - - if value.has_escaping_bound_vars() { - bug!("trying to instantiate {for_vid:?} with escaping bound vars: {value:?}"); - } - - let mut generalizer = TypeGeneralizer { - infcx: self.infcx, - delegate: &mut self.delegate, - ambient_variance: self.ambient_variance, - for_vid_sub_root: self.infcx.inner.borrow_mut().type_variables().sub_root_var(for_vid), - universe, - }; - - generalizer.relate(value, value) + fn generalize(&mut self, ty: Ty<'tcx>, for_vid: ty::TyVid) -> RelateResult<'tcx, Ty<'tcx>> { + let Generalization { value: ty, needs_wf: _ } = generalize::generalize( + self.infcx, + &mut self.delegate, + ty, + for_vid, + self.ambient_variance, + )?; + Ok(ty) } fn relate_opaques(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { @@ -716,235 +704,3 @@ where })]); } } - -/// The "type generalizer" is used when handling inference variables. -/// -/// The basic strategy for handling a constraint like `?A <: B` is to -/// apply a "generalization strategy" to the type `B` -- this replaces -/// all the lifetimes in the type `B` with fresh inference -/// variables. (You can read more about the strategy in this [blog -/// post].) -/// -/// As an example, if we had `?A <: &'x u32`, we would generalize `&'x -/// u32` to `&'0 u32` where `'0` is a fresh variable. This becomes the -/// value of `A`. Finally, we relate `&'0 u32 <: &'x u32`, which -/// establishes `'0: 'x` as a constraint. -/// -/// [blog post]: https://is.gd/0hKvIr -struct TypeGeneralizer<'me, 'tcx, D> -where - D: TypeRelatingDelegate<'tcx>, -{ - infcx: &'me InferCtxt<'tcx>, - - delegate: &'me mut D, - - /// After we generalize this type, we are going to relate it to - /// some other type. What will be the variance at this point? - ambient_variance: ty::Variance, - - /// The vid of the type variable that is in the process of being - /// instantiated. If we find this within the value we are folding, - /// that means we would have created a cyclic value. - for_vid_sub_root: ty::TyVid, - - /// The universe of the type variable that is in the process of being - /// instantiated. If we find anything that this universe cannot name, - /// we reject the relation. - universe: ty::UniverseIndex, -} - -impl<'tcx, D> TypeRelation<'tcx> for TypeGeneralizer<'_, 'tcx, D> -where - D: TypeRelatingDelegate<'tcx>, -{ - fn tcx(&self) -> TyCtxt<'tcx> { - self.infcx.tcx - } - - fn param_env(&self) -> ty::ParamEnv<'tcx> { - self.delegate.param_env() - } - - fn tag(&self) -> &'static str { - "nll::generalizer" - } - - fn a_is_expected(&self) -> bool { - true - } - - fn relate_with_variance<T: Relate<'tcx>>( - &mut self, - variance: ty::Variance, - _info: ty::VarianceDiagInfo<'tcx>, - a: T, - b: T, - ) -> RelateResult<'tcx, T> { - debug!( - "TypeGeneralizer::relate_with_variance(variance={:?}, a={:?}, b={:?})", - variance, a, b - ); - - let old_ambient_variance = self.ambient_variance; - self.ambient_variance = self.ambient_variance.xform(variance); - - debug!( - "TypeGeneralizer::relate_with_variance: ambient_variance = {:?}", - self.ambient_variance - ); - - let r = self.relate(a, b)?; - - self.ambient_variance = old_ambient_variance; - - debug!("TypeGeneralizer::relate_with_variance: r={:?}", r); - - Ok(r) - } - - fn tys(&mut self, a: Ty<'tcx>, _: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { - use crate::infer::type_variable::TypeVariableValue; - - debug!("TypeGeneralizer::tys(a={:?})", a); - - match *a.kind() { - ty::Infer(ty::TyVar(_)) | ty::Infer(ty::IntVar(_)) | ty::Infer(ty::FloatVar(_)) - if D::forbid_inference_vars() => - { - bug!("unexpected inference variable encountered in NLL generalization: {:?}", a); - } - - ty::Infer(ty::TyVar(vid)) => { - let mut inner = self.infcx.inner.borrow_mut(); - let variables = &mut inner.type_variables(); - let vid = variables.root_var(vid); - let sub_vid = variables.sub_root_var(vid); - if sub_vid == self.for_vid_sub_root { - // If sub-roots are equal, then `for_vid` and - // `vid` are related via subtyping. - debug!("TypeGeneralizer::tys: occurs check failed"); - Err(TypeError::Mismatch) - } else { - match variables.probe(vid) { - TypeVariableValue::Known { value: u } => { - drop(variables); - self.relate(u, u) - } - TypeVariableValue::Unknown { universe: _universe } => { - if self.ambient_variance == ty::Bivariant { - // FIXME: we may need a WF predicate (related to #54105). - } - - let origin = *variables.var_origin(vid); - - // Replacing with a new variable in the universe `self.universe`, - // it will be unified later with the original type variable in - // the universe `_universe`. - let new_var_id = variables.new_var(self.universe, origin); - - let u = self.tcx().mk_ty_var(new_var_id); - debug!("generalize: replacing original vid={:?} with new={:?}", vid, u); - Ok(u) - } - } - } - } - - ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) => { - // No matter what mode we are in, - // integer/floating-point types must be equal to be - // relatable. - Ok(a) - } - - ty::Placeholder(placeholder) => { - if self.universe.cannot_name(placeholder.universe) { - debug!( - "TypeGeneralizer::tys: root universe {:?} cannot name\ - placeholder in universe {:?}", - self.universe, placeholder.universe - ); - Err(TypeError::Mismatch) - } else { - Ok(a) - } - } - - _ => relate::super_relate_tys(self, a, a), - } - } - - fn regions( - &mut self, - a: ty::Region<'tcx>, - _: ty::Region<'tcx>, - ) -> RelateResult<'tcx, ty::Region<'tcx>> { - debug!("TypeGeneralizer::regions(a={:?})", a); - - if let ty::ReLateBound(..) = *a { - return Ok(a); - } - - // For now, we just always create a fresh region variable to - // replace all the regions in the source type. In the main - // type checker, we special case the case where the ambient - // variance is `Invariant` and try to avoid creating a fresh - // region variable, but since this comes up so much less in - // NLL (only when users use `_` etc) it is much less - // important. - // - // As an aside, since these new variables are created in - // `self.universe` universe, this also serves to enforce the - // universe scoping rules. - // - // FIXME(#54105) -- if the ambient variance is bivariant, - // though, we may however need to check well-formedness or - // risk a problem like #41677 again. - let replacement_region_vid = self.delegate.generalize_existential(self.universe); - - Ok(replacement_region_vid) - } - - fn consts( - &mut self, - a: ty::Const<'tcx>, - _: ty::Const<'tcx>, - ) -> RelateResult<'tcx, ty::Const<'tcx>> { - match a.kind() { - ty::ConstKind::Infer(InferConst::Var(_)) if D::forbid_inference_vars() => { - bug!("unexpected inference variable encountered in NLL generalization: {:?}", a); - } - ty::ConstKind::Infer(InferConst::Var(vid)) => { - let mut inner = self.infcx.inner.borrow_mut(); - let variable_table = &mut inner.const_unification_table(); - let var_value = variable_table.probe_value(vid); - match var_value.val.known() { - Some(u) => self.relate(u, u), - None => { - let new_var_id = variable_table.new_key(ConstVarValue { - origin: var_value.origin, - val: ConstVariableValue::Unknown { universe: self.universe }, - }); - Ok(self.tcx().mk_const(new_var_id, a.ty())) - } - } - } - ty::ConstKind::Unevaluated(..) if self.tcx().lazy_normalization() => Ok(a), - _ => relate::super_relate_consts(self, a, a), - } - } - - fn binders<T>( - &mut self, - a: ty::Binder<'tcx, T>, - _: ty::Binder<'tcx, T>, - ) -> RelateResult<'tcx, ty::Binder<'tcx, T>> - where - T: Relate<'tcx>, - { - debug!("TypeGeneralizer::binders(a={:?})", a); - let result = self.relate(a.skip_binder(), a.skip_binder())?; - Ok(a.rebind(result)) - } -} diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs index 362b22b23a8..545310ad351 100644 --- a/compiler/rustc_infer/src/infer/opaque_types.rs +++ b/compiler/rustc_infer/src/infer/opaque_types.rs @@ -149,7 +149,7 @@ impl<'tcx> InferCtxt<'tcx> { // no one encounters it in practice. // It does occur however in `fn fut() -> impl Future<Output = i32> { async { 42 } }`, // where it is of no concern, so we only check for TAITs. - if let Some(OpaqueTyOrigin::TyAlias) = + if let Some(OpaqueTyOrigin::TyAlias { .. }) = b_def_id.as_local().and_then(|b_def_id| self.opaque_type_origin(b_def_id)) { self.tcx.sess.emit_err(OpaqueHiddenTypeDiag { @@ -381,8 +381,12 @@ impl<'tcx> InferCtxt<'tcx> { // Anonymous `impl Trait` hir::OpaqueTyOrigin::FnReturn(parent) => parent == parent_def_id, // Named `type Foo = impl Bar;` - hir::OpaqueTyOrigin::TyAlias => { - may_define_opaque_type(self.tcx, parent_def_id, opaque_hir_id) + hir::OpaqueTyOrigin::TyAlias { in_assoc_ty } => { + if in_assoc_ty { + self.tcx.opaque_types_defined_by(parent_def_id).contains(&def_id) + } else { + may_define_opaque_type(self.tcx, parent_def_id, opaque_hir_id) + } } }; in_definition_scope.then_some(origin) diff --git a/compiler/rustc_infer/src/infer/outlives/test_type_match.rs b/compiler/rustc_infer/src/infer/outlives/test_type_match.rs index 75ce0f83fd6..cd2462d3c31 100644 --- a/compiler/rustc_infer/src/infer/outlives/test_type_match.rs +++ b/compiler/rustc_infer/src/infer/outlives/test_type_match.rs @@ -187,7 +187,7 @@ impl<'tcx> TypeRelation<'tcx> for Match<'tcx> { } else if pattern == value { Ok(pattern) } else { - relate::super_relate_tys(self, pattern, value) + relate::structurally_relate_tys(self, pattern, value) } } @@ -201,7 +201,7 @@ impl<'tcx> TypeRelation<'tcx> for Match<'tcx> { if pattern == value { Ok(pattern) } else { - relate::super_relate_consts(self, pattern, value) + relate::structurally_relate_consts(self, pattern, value) } } diff --git a/compiler/rustc_infer/src/infer/sub.rs b/compiler/rustc_infer/src/infer/sub.rs index 3766c250a9c..e0f29a8de8f 100644 --- a/compiler/rustc_infer/src/infer/sub.rs +++ b/compiler/rustc_infer/src/infer/sub.rs @@ -1,4 +1,4 @@ -use super::combine::{CombineFields, RelationDir}; +use super::combine::CombineFields; use super::{DefineOpaqueTypes, ObligationEmittingRelation, SubregionOrigin}; use crate::traits::{Obligation, PredicateObligations}; @@ -108,11 +108,11 @@ impl<'tcx> TypeRelation<'tcx> for Sub<'_, '_, 'tcx> { Ok(a) } (&ty::Infer(TyVar(a_id)), _) => { - self.fields.instantiate(b, RelationDir::SupertypeOf, a_id, !self.a_is_expected)?; + self.fields.instantiate(b, ty::Contravariant, a_id, !self.a_is_expected)?; Ok(a) } (_, &ty::Infer(TyVar(b_id))) => { - self.fields.instantiate(a, RelationDir::SubtypeOf, b_id, self.a_is_expected)?; + self.fields.instantiate(a, ty::Covariant, b_id, self.a_is_expected)?; Ok(a) } diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs index 9d9f4ee13f4..c9e857141c9 100644 --- a/compiler/rustc_interface/src/interface.rs +++ b/compiler/rustc_interface/src/interface.rs @@ -9,6 +9,7 @@ use rustc_data_structures::OnDrop; use rustc_errors::registry::Registry; use rustc_errors::{ErrorGuaranteed, Handler}; use rustc_lint::LintStore; +use rustc_middle::query::{ExternProviders, Providers}; use rustc_middle::{bug, ty}; use rustc_parse::maybe_new_parser_from_source_str; use rustc_query_impl::QueryCtxt; @@ -37,8 +38,7 @@ pub struct Compiler { pub(crate) sess: Lrc<Session>, codegen_backend: Lrc<Box<dyn CodegenBackend>>, pub(crate) register_lints: Option<Box<dyn Fn(&Session, &mut LintStore) + Send + Sync>>, - pub(crate) override_queries: - Option<fn(&Session, &mut ty::query::Providers, &mut ty::query::ExternProviders)>, + pub(crate) override_queries: Option<fn(&Session, &mut Providers, &mut ExternProviders)>, } impl Compiler { @@ -60,6 +60,11 @@ impl Compiler { } } +#[allow(rustc::bad_opt_access)] +pub fn set_thread_safe_mode(sopts: &config::UnstableOptions) { + rustc_data_structures::sync::set_dyn_thread_safe_mode(sopts.threads > 1); +} + /// Converts strings provided as `--cfg [cfgspec]` into a `crate_cfg`. pub fn parse_cfgspecs(cfgspecs: Vec<String>) -> FxHashSet<(String, Option<String>)> { rustc_span::create_default_session_if_not_set_then(move |_| { @@ -173,12 +178,21 @@ pub fn parse_check_cfg(specs: Vec<String>) -> CheckCfg { let expected_values = check_cfg .expecteds .entry(ident.name.to_string()) + .and_modify(|expected_values| match expected_values { + ExpectedValues::Some(_) => {} + ExpectedValues::Any => { + // handle the case where names(...) was done + // before values by changing to a list + *expected_values = + ExpectedValues::Some(FxHashSet::default()); + } + }) .or_insert_with(|| { ExpectedValues::Some(FxHashSet::default()) }); let ExpectedValues::Some(expected_values) = expected_values else { - bug!("shoudn't be possible") + bug!("`expected_values` should be a list a values") }; for val in values { @@ -261,8 +275,7 @@ pub struct Config { /// the list of queries. /// /// The second parameter is local providers and the third parameter is external providers. - pub override_queries: - Option<fn(&Session, &mut ty::query::Providers, &mut ty::query::ExternProviders)>, + pub override_queries: Option<fn(&Session, &mut Providers, &mut ExternProviders)>, /// This is a callback from the driver that is called to create a codegen backend. pub make_codegen_backend: @@ -338,7 +351,7 @@ pub fn try_print_query_stack(handler: &Handler, num_frames: Option<usize>) { // state if it was responsible for triggering the panic. let i = ty::tls::with_context_opt(|icx| { if let Some(icx) = icx { - print_query_stack(QueryCtxt { tcx: icx.tcx }, icx.query, handler, num_frames) + print_query_stack(QueryCtxt::new(icx.tcx), icx.query, handler, num_frames) } else { 0 } diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 48401eabd1e..bbf9d9d515d 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -17,7 +17,7 @@ use rustc_lint::{unerased_lint_store, BufferedEarlyLint, EarlyCheckNode, LintSto use rustc_metadata::creader::CStore; use rustc_middle::arena::Arena; use rustc_middle::dep_graph::DepGraph; -use rustc_middle::ty::query::{ExternProviders, Providers}; +use rustc_middle::query::{ExternProviders, Providers}; use rustc_middle::ty::{self, GlobalCtxt, RegisteredTools, TyCtxt}; use rustc_mir_build as mir_build; use rustc_parse::{parse_crate_from_file, parse_crate_from_source_str, validate_attr}; @@ -691,6 +691,8 @@ pub fn create_global_ctxt<'tcx>( callback(sess, &mut local_providers, &mut extern_providers); } + let incremental = dep_graph.is_fully_enabled(); + sess.time("setup_global_ctxt", || { gcx_cell.get_or_init(move || { TyCtxt::create_global_ctxt( @@ -700,9 +702,13 @@ pub fn create_global_ctxt<'tcx>( hir_arena, untracked, dep_graph, - query_result_on_disk_cache, rustc_query_impl::query_callbacks(arena), - rustc_query_impl::query_system_fns(local_providers, extern_providers), + rustc_query_impl::query_system( + local_providers, + extern_providers, + query_result_on_disk_cache, + incremental, + ), ) }) }) diff --git a/compiler/rustc_interface/src/proc_macro_decls.rs b/compiler/rustc_interface/src/proc_macro_decls.rs index 1c58caa0353..2c8014d8b3a 100644 --- a/compiler/rustc_interface/src/proc_macro_decls.rs +++ b/compiler/rustc_interface/src/proc_macro_decls.rs @@ -1,6 +1,6 @@ use rustc_ast::attr; use rustc_hir::def_id::LocalDefId; -use rustc_middle::ty::query::Providers; +use rustc_middle::query::Providers; use rustc_middle::ty::TyCtxt; use rustc_span::symbol::sym; diff --git a/compiler/rustc_lexer/src/lib.rs b/compiler/rustc_lexer/src/lib.rs index c07dc19a0ac..d511d2b1280 100644 --- a/compiler/rustc_lexer/src/lib.rs +++ b/compiler/rustc_lexer/src/lib.rs @@ -582,34 +582,38 @@ impl Cursor<'_> { let mut base = Base::Decimal; if first_digit == '0' { // Attempt to parse encoding base. - let has_digits = match self.first() { + match self.first() { 'b' => { base = Base::Binary; self.bump(); - self.eat_decimal_digits() + if !self.eat_decimal_digits() { + return Int { base, empty_int: true }; + } } 'o' => { base = Base::Octal; self.bump(); - self.eat_decimal_digits() + if !self.eat_decimal_digits() { + return Int { base, empty_int: true }; + } } 'x' => { base = Base::Hexadecimal; self.bump(); - self.eat_hexadecimal_digits() + if !self.eat_hexadecimal_digits() { + return Int { base, empty_int: true }; + } } - // Not a base prefix. - '0'..='9' | '_' | '.' | 'e' | 'E' => { + // Not a base prefix; consume additional digits. + '0'..='9' | '_' => { self.eat_decimal_digits(); - true } + + // Also not a base prefix; nothing more to do here. + '.' | 'e' | 'E' => {} + // Just a 0. _ => return Int { base, empty_int: false }, - }; - // Base prefix was provided, but there were no digits - // after it, e.g. "0x". - if !has_digits { - return Int { base, empty_int: true }; } } else { // No base prefix, parse number in the usual way. diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index 71cf644eb50..a5639404faf 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -520,3 +520,19 @@ lint_opaque_hidden_inferred_bound = opaque type `{$ty}` does not satisfy its ass .specifically = this associated type bound is unsatisfied for `{$proj_ty}` lint_opaque_hidden_inferred_bound_sugg = add this bound + +lint_drop_ref = calls to `std::mem::drop` with a reference instead of an owned value does nothing + .label = argument has type `{$arg_ty}` + .note = use `let _ = ...` to ignore the expression or result + +lint_drop_copy = calls to `std::mem::drop` with a value that implements `Copy` does nothing + .label = argument has type `{$arg_ty}` + .note = use `let _ = ...` to ignore the expression or result + +lint_forget_ref = calls to `std::mem::forget` with a reference instead of an owned value does nothing + .label = argument has type `{$arg_ty}` + .note = use `let _ = ...` to ignore the expression or result + +lint_forget_copy = calls to `std::mem::forget` with a value that implements `Copy` does nothing + .label = argument has type `{$arg_ty}` + .note = use `let _ = ...` to ignore the expression or result diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 3025cce7ba7..6601a80920b 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -611,7 +611,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc { declare_lint! { /// The `missing_copy_implementations` lint detects potentially-forgotten - /// implementations of [`Copy`]. + /// implementations of [`Copy`] for public types. /// /// [`Copy`]: https://doc.rust-lang.org/std/marker/trait.Copy.html /// @@ -647,7 +647,9 @@ declare_lint_pass!(MissingCopyImplementations => [MISSING_COPY_IMPLEMENTATIONS]) impl<'tcx> LateLintPass<'tcx> for MissingCopyImplementations { fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) { - if !cx.effective_visibilities.is_reachable(item.owner_id.def_id) { + if !(cx.effective_visibilities.is_reachable(item.owner_id.def_id) + && cx.tcx.local_visibility(item.owner_id.def_id).is_public()) + { return; } let (def, ty) = match item.kind { @@ -727,7 +729,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingCopyImplementations { declare_lint! { /// The `missing_debug_implementations` lint detects missing - /// implementations of [`fmt::Debug`]. + /// implementations of [`fmt::Debug`] for public types. /// /// [`fmt::Debug`]: https://doc.rust-lang.org/std/fmt/trait.Debug.html /// @@ -766,7 +768,9 @@ impl_lint_pass!(MissingDebugImplementations => [MISSING_DEBUG_IMPLEMENTATIONS]); impl<'tcx> LateLintPass<'tcx> for MissingDebugImplementations { fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) { - if !cx.effective_visibilities.is_reachable(item.owner_id.def_id) { + if !(cx.effective_visibilities.is_reachable(item.owner_id.def_id) + && cx.tcx.local_visibility(item.owner_id.def_id).is_public()) + { return; } @@ -1882,8 +1886,8 @@ declare_lint_pass!( struct UnderMacro(bool); impl KeywordIdents { - fn check_tokens(&mut self, cx: &EarlyContext<'_>, tokens: TokenStream) { - for tt in tokens.into_trees() { + fn check_tokens(&mut self, cx: &EarlyContext<'_>, tokens: &TokenStream) { + for tt in tokens.trees() { match tt { // Only report non-raw idents. TokenTree::Token(token, _) => { @@ -1944,10 +1948,10 @@ impl KeywordIdents { impl EarlyLintPass for KeywordIdents { fn check_mac_def(&mut self, cx: &EarlyContext<'_>, mac_def: &ast::MacroDef) { - self.check_tokens(cx, mac_def.body.tokens.clone()); + self.check_tokens(cx, &mac_def.body.tokens); } fn check_mac(&mut self, cx: &EarlyContext<'_>, mac: &ast::MacCall) { - self.check_tokens(cx, mac.args.tokens.clone()); + self.check_tokens(cx, &mac.args.tokens); } fn check_ident(&mut self, cx: &EarlyContext<'_>, ident: Ident) { self.check_ident_token(cx, UnderMacro(false), ident); diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index 53d7cf74cde..1d0c43e95e0 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -49,9 +49,9 @@ use std::cell::Cell; use std::iter; use std::slice; -type EarlyLintPassFactory = dyn Fn() -> EarlyLintPassObject + sync::Send + sync::Sync; +type EarlyLintPassFactory = dyn Fn() -> EarlyLintPassObject + sync::DynSend + sync::DynSync; type LateLintPassFactory = - dyn for<'tcx> Fn(TyCtxt<'tcx>) -> LateLintPassObject<'tcx> + sync::Send + sync::Sync; + dyn for<'tcx> Fn(TyCtxt<'tcx>) -> LateLintPassObject<'tcx> + sync::DynSend + sync::DynSync; /// Information about the registered lints. /// @@ -169,7 +169,7 @@ impl LintStore { pub fn register_early_pass( &mut self, - pass: impl Fn() -> EarlyLintPassObject + 'static + sync::Send + sync::Sync, + pass: impl Fn() -> EarlyLintPassObject + 'static + sync::DynSend + sync::DynSync, ) { self.early_passes.push(Box::new(pass)); } @@ -182,7 +182,7 @@ impl LintStore { /// * See [rust-clippy#5518](https://github.com/rust-lang/rust-clippy/pull/5518) pub fn register_pre_expansion_pass( &mut self, - pass: impl Fn() -> EarlyLintPassObject + 'static + sync::Send + sync::Sync, + pass: impl Fn() -> EarlyLintPassObject + 'static + sync::DynSend + sync::DynSync, ) { self.pre_expansion_passes.push(Box::new(pass)); } @@ -191,8 +191,8 @@ impl LintStore { &mut self, pass: impl for<'tcx> Fn(TyCtxt<'tcx>) -> LateLintPassObject<'tcx> + 'static - + sync::Send - + sync::Sync, + + sync::DynSend + + sync::DynSync, ) { self.late_passes.push(Box::new(pass)); } @@ -201,8 +201,8 @@ impl LintStore { &mut self, pass: impl for<'tcx> Fn(TyCtxt<'tcx>) -> LateLintPassObject<'tcx> + 'static - + sync::Send - + sync::Sync, + + sync::DynSend + + sync::DynSync, ) { self.late_module_passes.push(Box::new(pass)); } diff --git a/compiler/rustc_lint/src/drop_forget_useless.rs b/compiler/rustc_lint/src/drop_forget_useless.rs new file mode 100644 index 00000000000..259abc2af11 --- /dev/null +++ b/compiler/rustc_lint/src/drop_forget_useless.rs @@ -0,0 +1,164 @@ +use rustc_hir::{Arm, Expr, ExprKind, Node}; +use rustc_span::sym; + +use crate::{ + lints::{DropCopyDiag, DropRefDiag, ForgetCopyDiag, ForgetRefDiag}, + LateContext, LateLintPass, LintContext, +}; + +declare_lint! { + /// The `drop_ref` lint checks for calls to `std::mem::drop` with a reference + /// instead of an owned value. + /// + /// ### Example + /// + /// ```rust + /// # fn operation_that_requires_mutex_to_be_unlocked() {} // just to make it compile + /// # let mutex = std::sync::Mutex::new(1); // just to make it compile + /// let mut lock_guard = mutex.lock(); + /// std::mem::drop(&lock_guard); // Should have been drop(lock_guard), mutex + /// // still locked + /// operation_that_requires_mutex_to_be_unlocked(); + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Calling `drop` on a reference will only drop the + /// reference itself, which is a no-op. It will not call the `drop` method (from + /// the `Drop` trait implementation) on the underlying referenced value, which + /// is likely what was intended. + pub DROP_REF, + Warn, + "calls to `std::mem::drop` with a reference instead of an owned value" +} + +declare_lint! { + /// The `forget_ref` lint checks for calls to `std::mem::forget` with a reference + /// instead of an owned value. + /// + /// ### Example + /// + /// ```rust + /// let x = Box::new(1); + /// std::mem::forget(&x); // Should have been forget(x), x will still be dropped + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Calling `forget` on a reference will only forget the + /// reference itself, which is a no-op. It will not forget the underlying + /// referenced value, which is likely what was intended. + pub FORGET_REF, + Warn, + "calls to `std::mem::forget` with a reference instead of an owned value" +} + +declare_lint! { + /// The `drop_copy` lint checks for calls to `std::mem::drop` with a value + /// that derives the Copy trait. + /// + /// ### Example + /// + /// ```rust + /// let x: i32 = 42; // i32 implements Copy + /// std::mem::drop(x); // A copy of x is passed to the function, leaving the + /// // original unaffected + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Calling `std::mem::drop` [does nothing for types that + /// implement Copy](https://doc.rust-lang.org/std/mem/fn.drop.html), since the + /// value will be copied and moved into the function on invocation. + pub DROP_COPY, + Warn, + "calls to `std::mem::drop` with a value that implements Copy" +} + +declare_lint! { + /// The `forget_copy` lint checks for calls to `std::mem::forget` with a value + /// that derives the Copy trait. + /// + /// ### Example + /// + /// ```rust + /// let x: i32 = 42; // i32 implements Copy + /// std::mem::forget(x); // A copy of x is passed to the function, leaving the + /// // original unaffected + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Calling `std::mem::forget` [does nothing for types that + /// implement Copy](https://doc.rust-lang.org/std/mem/fn.drop.html) since the + /// value will be copied and moved into the function on invocation. + /// + /// An alternative, but also valid, explanation is that Copy types do not + /// implement the Drop trait, which means they have no destructors. Without a + /// destructor, there is nothing for `std::mem::forget` to ignore. + pub FORGET_COPY, + Warn, + "calls to `std::mem::forget` with a value that implements Copy" +} + +declare_lint_pass!(DropForgetUseless => [DROP_REF, FORGET_REF, DROP_COPY, FORGET_COPY]); + +impl<'tcx> LateLintPass<'tcx> for DropForgetUseless { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { + if let ExprKind::Call(path, [arg]) = expr.kind + && let ExprKind::Path(ref qpath) = path.kind + && let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id() + && let Some(fn_name) = cx.tcx.get_diagnostic_name(def_id) + { + let arg_ty = cx.typeck_results().expr_ty(arg); + let is_copy = arg_ty.is_copy_modulo_regions(cx.tcx, cx.param_env); + let drop_is_single_call_in_arm = is_single_call_in_arm(cx, arg, expr); + match fn_name { + sym::mem_drop if arg_ty.is_ref() && !drop_is_single_call_in_arm => { + cx.emit_spanned_lint(DROP_REF, expr.span, DropRefDiag { arg_ty, label: arg.span }); + }, + sym::mem_forget if arg_ty.is_ref() => { + cx.emit_spanned_lint(FORGET_REF, expr.span, ForgetRefDiag { arg_ty, label: arg.span }); + }, + sym::mem_drop if is_copy && !drop_is_single_call_in_arm => { + cx.emit_spanned_lint(DROP_COPY, expr.span, DropCopyDiag { arg_ty, label: arg.span }); + } + sym::mem_forget if is_copy => { + cx.emit_spanned_lint(FORGET_COPY, expr.span, ForgetCopyDiag { arg_ty, label: arg.span }); + } + _ => return, + }; + } + } +} + +// Dropping returned value of a function, as in the following snippet is considered idiomatic, see +// rust-lang/rust-clippy#9482 for examples. +// +// ``` +// match <var> { +// <pat> => drop(fn_with_side_effect_and_returning_some_value()), +// .. +// } +// ``` +fn is_single_call_in_arm<'tcx>( + cx: &LateContext<'tcx>, + arg: &'tcx Expr<'_>, + drop_expr: &'tcx Expr<'_>, +) -> bool { + if matches!(arg.kind, ExprKind::Call(..) | ExprKind::MethodCall(..)) { + let parent_node = cx.tcx.hir().find_parent(drop_expr.hir_id); + if let Some(Node::Arm(Arm { body, .. })) = &parent_node { + return body.hir_id == drop_expr.hir_id; + } + } + false +} diff --git a/compiler/rustc_lint/src/expect.rs b/compiler/rustc_lint/src/expect.rs index e9eb14ea188..b1266b58a61 100644 --- a/compiler/rustc_lint/src/expect.rs +++ b/compiler/rustc_lint/src/expect.rs @@ -1,5 +1,5 @@ use crate::lints::{Expectation, ExpectationNote}; -use rustc_middle::ty::query::Providers; +use rustc_middle::query::Providers; use rustc_middle::ty::TyCtxt; use rustc_session::lint::builtin::UNFULFILLED_LINT_EXPECTATIONS; use rustc_session::lint::LintExpectationId; diff --git a/compiler/rustc_lint/src/late.rs b/compiler/rustc_lint/src/late.rs index b42878a02ee..c9781a72704 100644 --- a/compiler/rustc_lint/src/late.rs +++ b/compiler/rustc_lint/src/late.rs @@ -16,7 +16,7 @@ use crate::{passes::LateLintPassObject, LateContext, LateLintPass, LintStore}; use rustc_ast as ast; -use rustc_data_structures::sync::join; +use rustc_data_structures::sync::{join, DynSend}; use rustc_hir as hir; use rustc_hir::def_id::LocalDefId; use rustc_hir::intravisit as hir_visit; @@ -429,7 +429,7 @@ fn late_lint_crate_inner<'tcx, T: LateLintPass<'tcx>>( /// Performs lint checking on a crate. pub fn check_crate<'tcx, T: LateLintPass<'tcx> + 'tcx>( tcx: TyCtxt<'tcx>, - builtin_lints: impl FnOnce() -> T + Send, + builtin_lints: impl FnOnce() -> T + Send + DynSend, ) { join( || { diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs index a43c09a7939..b92ed11f38a 100644 --- a/compiler/rustc_lint/src/levels.rs +++ b/compiler/rustc_lint/src/levels.rs @@ -20,7 +20,7 @@ use rustc_middle::lint::{ reveal_actual_level, struct_lint_level, LevelAndSource, LintExpectation, LintLevelSource, ShallowLintLevelMap, }; -use rustc_middle::ty::query::Providers; +use rustc_middle::query::Providers; use rustc_middle::ty::{RegisteredTools, TyCtxt}; use rustc_session::lint::builtin::{RENAMED_AND_REMOVED_LINTS, UNKNOWN_LINTS, UNUSED_ATTRIBUTES}; use rustc_session::lint::{ diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 319eb2ea445..dfddfe09ab3 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -52,6 +52,7 @@ mod array_into_iter; pub mod builtin; mod context; mod deref_into_dyn_supertrait; +mod drop_forget_useless; mod early; mod enum_intrinsics_non_enums; mod errors; @@ -85,7 +86,7 @@ use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage}; use rustc_fluent_macro::fluent_messages; use rustc_hir as hir; use rustc_hir::def_id::LocalDefId; -use rustc_middle::ty::query::Providers; +use rustc_middle::query::Providers; use rustc_middle::ty::TyCtxt; use rustc_session::lint::builtin::{ BARE_TRAIT_OBJECTS, ELIDED_LIFETIMES_IN_PATHS, EXPLICIT_OUTLIVES_REQUIREMENTS, @@ -96,6 +97,7 @@ use rustc_span::Span; use array_into_iter::ArrayIntoIter; use builtin::*; use deref_into_dyn_supertrait::*; +use drop_forget_useless::*; use enum_intrinsics_non_enums::EnumIntrinsicsNonEnums; use for_loops_over_fallibles::*; use hidden_unicode_codepoints::*; @@ -201,6 +203,7 @@ late_lint_methods!( [ ForLoopsOverFallibles: ForLoopsOverFallibles, DerefIntoDynSupertrait: DerefIntoDynSupertrait, + DropForgetUseless: DropForgetUseless, HardwiredLints: HardwiredLints, ImproperCTypesDeclarations: ImproperCTypesDeclarations, ImproperCTypesDefinitions: ImproperCTypesDefinitions, diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index d7bacc6485f..8e48806b504 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -662,6 +662,43 @@ pub struct ForLoopsOverFalliblesSuggestion<'a> { pub end_span: Span, } +// drop_ref.rs +#[derive(LintDiagnostic)] +#[diag(lint_drop_ref)] +#[note] +pub struct DropRefDiag<'a> { + pub arg_ty: Ty<'a>, + #[label] + pub label: Span, +} + +#[derive(LintDiagnostic)] +#[diag(lint_drop_copy)] +#[note] +pub struct DropCopyDiag<'a> { + pub arg_ty: Ty<'a>, + #[label] + pub label: Span, +} + +#[derive(LintDiagnostic)] +#[diag(lint_forget_ref)] +#[note] +pub struct ForgetRefDiag<'a> { + pub arg_ty: Ty<'a>, + #[label] + pub label: Span, +} + +#[derive(LintDiagnostic)] +#[diag(lint_forget_copy)] +#[note] +pub struct ForgetCopyDiag<'a> { + pub arg_ty: Ty<'a>, + #[label] + pub label: Span, +} + // hidden_unicode_codepoints.rs #[derive(LintDiagnostic)] #[diag(lint_hidden_unicode_codepoints)] diff --git a/compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp index 03e6d2149e9..87906dee4d3 100644 --- a/compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp @@ -8,18 +8,100 @@ using namespace llvm; +// FFI equivalent of enum `llvm::coverage::Counter::CounterKind` +// https://github.com/rust-lang/llvm-project/blob/ea6fa9c2/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L97-L99 +enum class LLVMRustCounterKind { + Zero = 0, + CounterValueReference = 1, + Expression = 2, +}; + +// FFI equivalent of struct `llvm::coverage::Counter` +// https://github.com/rust-lang/llvm-project/blob/ea6fa9c2/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L94-L149 +struct LLVMRustCounter { + LLVMRustCounterKind CounterKind; + uint32_t ID; +}; + +static coverage::Counter fromRust(LLVMRustCounter Counter) { + switch (Counter.CounterKind) { + case LLVMRustCounterKind::Zero: + return coverage::Counter::getZero(); + case LLVMRustCounterKind::CounterValueReference: + return coverage::Counter::getCounter(Counter.ID); + case LLVMRustCounterKind::Expression: + return coverage::Counter::getExpression(Counter.ID); + } + report_fatal_error("Bad LLVMRustCounterKind!"); +} + +// FFI equivalent of enum `llvm::coverage::CounterMappingRegion::RegionKind` +// https://github.com/rust-lang/llvm-project/blob/ea6fa9c2/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L213-L234 +enum class LLVMRustCounterMappingRegionKind { + CodeRegion = 0, + ExpansionRegion = 1, + SkippedRegion = 2, + GapRegion = 3, + BranchRegion = 4, +}; + +static coverage::CounterMappingRegion::RegionKind +fromRust(LLVMRustCounterMappingRegionKind Kind) { + switch (Kind) { + case LLVMRustCounterMappingRegionKind::CodeRegion: + return coverage::CounterMappingRegion::CodeRegion; + case LLVMRustCounterMappingRegionKind::ExpansionRegion: + return coverage::CounterMappingRegion::ExpansionRegion; + case LLVMRustCounterMappingRegionKind::SkippedRegion: + return coverage::CounterMappingRegion::SkippedRegion; + case LLVMRustCounterMappingRegionKind::GapRegion: + return coverage::CounterMappingRegion::GapRegion; + case LLVMRustCounterMappingRegionKind::BranchRegion: + return coverage::CounterMappingRegion::BranchRegion; + } + report_fatal_error("Bad LLVMRustCounterMappingRegionKind!"); +} + +// FFI equivalent of struct `llvm::coverage::CounterMappingRegion` +// https://github.com/rust-lang/llvm-project/blob/ea6fa9c2/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L211-L304 struct LLVMRustCounterMappingRegion { - coverage::Counter Count; - coverage::Counter FalseCount; + LLVMRustCounter Count; + LLVMRustCounter FalseCount; uint32_t FileID; uint32_t ExpandedFileID; uint32_t LineStart; uint32_t ColumnStart; uint32_t LineEnd; uint32_t ColumnEnd; - coverage::CounterMappingRegion::RegionKind Kind; + LLVMRustCounterMappingRegionKind Kind; +}; + +// FFI equivalent of enum `llvm::coverage::CounterExpression::ExprKind` +// https://github.com/rust-lang/llvm-project/blob/ea6fa9c2/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L154 +enum class LLVMRustCounterExprKind { + Subtract = 0, + Add = 1, }; +// FFI equivalent of struct `llvm::coverage::CounterExpression` +// https://github.com/rust-lang/llvm-project/blob/ea6fa9c2/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L151-L160 +struct LLVMRustCounterExpression { + LLVMRustCounterExprKind Kind; + LLVMRustCounter LHS; + LLVMRustCounter RHS; +}; + +static coverage::CounterExpression::ExprKind +fromRust(LLVMRustCounterExprKind Kind) { + switch (Kind) { + case LLVMRustCounterExprKind::Subtract: + return coverage::CounterExpression::Subtract; + case LLVMRustCounterExprKind::Add: + return coverage::CounterExpression::Add; + } + report_fatal_error("Bad LLVMRustCounterExprKind!"); +} + extern "C" void LLVMRustCoverageWriteFilenamesSectionToBuffer( const char* const Filenames[], size_t FilenamesLen, @@ -37,9 +119,9 @@ extern "C" void LLVMRustCoverageWriteFilenamesSectionToBuffer( extern "C" void LLVMRustCoverageWriteMappingToBuffer( const unsigned *VirtualFileMappingIDs, unsigned NumVirtualFileMappingIDs, - const coverage::CounterExpression *Expressions, + const LLVMRustCounterExpression *RustExpressions, unsigned NumExpressions, - LLVMRustCounterMappingRegion *RustMappingRegions, + const LLVMRustCounterMappingRegion *RustMappingRegions, unsigned NumMappingRegions, RustStringRef BufferOut) { // Convert from FFI representation to LLVM representation. @@ -48,13 +130,24 @@ extern "C" void LLVMRustCoverageWriteMappingToBuffer( for (const auto &Region : ArrayRef<LLVMRustCounterMappingRegion>( RustMappingRegions, NumMappingRegions)) { MappingRegions.emplace_back( - Region.Count, Region.FalseCount, Region.FileID, Region.ExpandedFileID, + fromRust(Region.Count), fromRust(Region.FalseCount), + Region.FileID, Region.ExpandedFileID, Region.LineStart, Region.ColumnStart, Region.LineEnd, Region.ColumnEnd, - Region.Kind); + fromRust(Region.Kind)); } + + std::vector<coverage::CounterExpression> Expressions; + Expressions.reserve(NumExpressions); + for (const auto &Expression : + ArrayRef<LLVMRustCounterExpression>(RustExpressions, NumExpressions)) { + Expressions.emplace_back(fromRust(Expression.Kind), + fromRust(Expression.LHS), + fromRust(Expression.RHS)); + } + auto CoverageMappingWriter = coverage::CoverageMappingWriter( ArrayRef<unsigned>(VirtualFileMappingIDs, NumVirtualFileMappingIDs), - ArrayRef<coverage::CounterExpression>(Expressions, NumExpressions), + Expressions, MappingRegions); RawRustStringOstream OS(BufferOut); CoverageMappingWriter.write(OS); diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index 5ec3b95225d..7b774d6865c 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -745,6 +745,9 @@ LLVMRustOptimize( if (InstrProfileOutput) { Options.InstrProfileOutput = InstrProfileOutput; } + // cargo run tests in multhreading mode by default + // so use atomics for coverage counters + Options.Atomic = true; MPM.addPass(InstrProfiling(Options, false)); } ); diff --git a/compiler/rustc_macros/src/query.rs b/compiler/rustc_macros/src/query.rs index a8b25ff66d7..001d53b1099 100644 --- a/compiler/rustc_macros/src/query.rs +++ b/compiler/rustc_macros/src/query.rs @@ -253,7 +253,7 @@ fn add_query_desc_cached_impl( quote! { #[allow(unused_variables, unused_braces, rustc::pass_by_value)] #[inline] - pub fn #name<'tcx>(#tcx: TyCtxt<'tcx>, #key: &crate::ty::query::query_keys::#name<'tcx>) -> bool { + pub fn #name<'tcx>(#tcx: TyCtxt<'tcx>, #key: &crate::query::query_keys::#name<'tcx>) -> bool { #expr } } @@ -262,7 +262,7 @@ fn add_query_desc_cached_impl( // we're taking `key` by reference, but some rustc types usually prefer being passed by value #[allow(rustc::pass_by_value)] #[inline] - pub fn #name<'tcx>(_: TyCtxt<'tcx>, _: &crate::ty::query::query_keys::#name<'tcx>) -> bool { + pub fn #name<'tcx>(_: TyCtxt<'tcx>, _: &crate::query::query_keys::#name<'tcx>) -> bool { false } } @@ -273,7 +273,7 @@ fn add_query_desc_cached_impl( let desc = quote! { #[allow(unused_variables)] - pub fn #name<'tcx>(tcx: TyCtxt<'tcx>, key: crate::ty::query::query_keys::#name<'tcx>) -> String { + pub fn #name<'tcx>(tcx: TyCtxt<'tcx>, key: crate::query::query_keys::#name<'tcx>) -> String { let (#tcx, #key) = (tcx, key); ::rustc_middle::ty::print::with_no_trimmed_paths!( format!(#desc) diff --git a/compiler/rustc_metadata/src/locator.rs b/compiler/rustc_metadata/src/locator.rs index c6af8d63289..6c4d121fd01 100644 --- a/compiler/rustc_metadata/src/locator.rs +++ b/compiler/rustc_metadata/src/locator.rs @@ -220,7 +220,6 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::memmap::Mmap; use rustc_data_structures::owned_slice::slice_owned; use rustc_data_structures::svh::Svh; -use rustc_data_structures::sync::MetadataRef; use rustc_errors::{DiagnosticArgValue, FatalError, IntoDiagnosticArg}; use rustc_fs_util::try_canonicalize; use rustc_session::config::{self, CrateType}; @@ -782,7 +781,7 @@ fn get_metadata_section<'p>( if !filename.exists() { return Err(MetadataError::NotPresent(filename)); } - let raw_bytes: MetadataRef = match flavor { + let raw_bytes = match flavor { CrateFlavor::Rlib => { loader.get_rlib_metadata(target, filename).map_err(MetadataError::LoadFailure)? } @@ -843,7 +842,7 @@ fn get_metadata_section<'p>( slice_owned(mmap, Deref::deref) } }; - let blob = MetadataBlob::new(raw_bytes); + let blob = MetadataBlob(raw_bytes); if blob.is_compatible() { Ok(blob) } else { diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index a310cbb8029..699e1f49ed6 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -7,6 +7,7 @@ use crate::rmeta::*; use rustc_ast as ast; use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::owned_slice::OwnedSlice; use rustc_data_structures::svh::Svh; use rustc_data_structures::sync::{AppendOnlyVec, Lock, Lrc, OnceCell}; use rustc_data_structures::unhash::UnhashMap; @@ -50,7 +51,7 @@ mod cstore_impl; /// A `MetadataBlob` internally is just a reference counted pointer to /// the actual data, so cloning it is cheap. #[derive(Clone)] -pub(crate) struct MetadataBlob(Lrc<MetadataRef>); +pub(crate) struct MetadataBlob(pub(crate) OwnedSlice); impl std::ops::Deref for MetadataBlob { type Target = [u8]; @@ -660,10 +661,6 @@ impl<'a, 'tcx, I: Idx, T> Decodable<DecodeContext<'a, 'tcx>> for LazyTable<I, T> implement_ty_decoder!(DecodeContext<'a, 'tcx>); impl MetadataBlob { - pub(crate) fn new(metadata_ref: MetadataRef) -> MetadataBlob { - MetadataBlob(Lrc::new(metadata_ref)) - } - pub(crate) fn is_compatible(&self) -> bool { self.blob().starts_with(METADATA_HEADER) } @@ -856,7 +853,12 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { ty::EarlyBinder(&*output) } - fn get_variant(self, kind: &DefKind, index: DefIndex, parent_did: DefId) -> ty::VariantDef { + fn get_variant( + self, + kind: DefKind, + index: DefIndex, + parent_did: DefId, + ) -> (VariantIdx, ty::VariantDef) { let adt_kind = match kind { DefKind::Variant => ty::AdtKind::Enum, DefKind::Struct => ty::AdtKind::Struct, @@ -870,22 +872,25 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { if adt_kind == ty::AdtKind::Enum { Some(self.local_def_id(index)) } else { None }; let ctor = data.ctor.map(|(kind, index)| (kind, self.local_def_id(index))); - ty::VariantDef::new( - self.item_name(index), - variant_did, - ctor, - data.discr, - self.get_associated_item_or_field_def_ids(index) - .map(|did| ty::FieldDef { - did, - name: self.item_name(did.index), - vis: self.get_visibility(did.index), - }) - .collect(), - adt_kind, - parent_did, - false, - data.is_non_exhaustive, + ( + data.idx, + ty::VariantDef::new( + self.item_name(index), + variant_did, + ctor, + data.discr, + self.get_associated_item_or_field_def_ids(index) + .map(|did| ty::FieldDef { + did, + name: self.item_name(did.index), + vis: self.get_visibility(did.index), + }) + .collect(), + adt_kind, + parent_did, + false, + data.is_non_exhaustive, + ), ) } @@ -901,7 +906,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { }; let repr = self.root.tables.repr_options.get(self, item_id).unwrap().decode(self); - let variants = if let ty::AdtKind::Enum = adt_kind { + let mut variants: Vec<_> = if let ty::AdtKind::Enum = adt_kind { self.root .tables .module_children_non_reexports @@ -912,15 +917,22 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { let kind = self.def_kind(index); match kind { DefKind::Ctor(..) => None, - _ => Some(self.get_variant(&kind, index, did)), + _ => Some(self.get_variant(kind, index, did)), } }) .collect() } else { - std::iter::once(self.get_variant(&kind, item_id, did)).collect() + std::iter::once(self.get_variant(kind, item_id, did)).collect() }; - tcx.mk_adt_def(did, adt_kind, variants, repr) + variants.sort_by_key(|(idx, _)| *idx); + + tcx.mk_adt_def( + did, + adt_kind, + variants.into_iter().map(|(_, variant)| variant).collect(), + repr, + ) } fn get_visibility(self, id: DefIndex) -> Visibility<DefId> { @@ -1457,28 +1469,30 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { .. } = source_file_to_import; - // If this file is under $sysroot/lib/rustlib/src/ but has not been remapped - // during rust bootstrapping by `remap-debuginfo = true`, and the user - // wish to simulate that behaviour by -Z simulate-remapped-rust-src-base, + // If this file is under $sysroot/lib/rustlib/src/ + // and the user wish to simulate remapping with -Z simulate-remapped-rust-src-base, // then we change `name` to a similar state as if the rust was bootstrapped // with `remap-debuginfo = true`. // This is useful for testing so that tests about the effects of // `try_to_translate_virtual_to_real` don't have to worry about how the // compiler is bootstrapped. if let Some(virtual_dir) = &sess.opts.unstable_opts.simulate_remapped_rust_src_base - { - if let Some(real_dir) = &sess.opts.real_rust_source_base_dir { - for subdir in ["library", "compiler"] { - if let rustc_span::FileName::Real(ref mut old_name) = name { - if let rustc_span::RealFileName::LocalPath(local) = old_name { - if let Ok(rest) = local.strip_prefix(real_dir.join(subdir)) { - *old_name = rustc_span::RealFileName::Remapped { - local_path: None, - virtual_name: virtual_dir.join(subdir).join(rest), - }; - } - } - } + && let Some(real_dir) = &sess.opts.real_rust_source_base_dir + && let rustc_span::FileName::Real(ref mut old_name) = name { + let relative_path = match old_name { + rustc_span::RealFileName::LocalPath(local) => local.strip_prefix(real_dir).ok(), + rustc_span::RealFileName::Remapped { virtual_name, .. } => { + option_env!("CFG_VIRTUAL_RUST_SOURCE_BASE_DIR").and_then(|virtual_dir| virtual_name.strip_prefix(virtual_dir).ok()) + } + }; + debug!(?relative_path, ?virtual_dir, "simulate_remapped_rust_src_base"); + for subdir in ["library", "compiler"] { + if let Some(rest) = relative_path.and_then(|p| p.strip_prefix(subdir).ok()) { + *old_name = rustc_span::RealFileName::Remapped { + local_path: None, // FIXME: maybe we should preserve this? + virtual_name: virtual_dir.join(subdir).join(rest), + }; + break; } } } diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 4a3b783c636..fe880b939ef 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -14,8 +14,8 @@ use rustc_middle::metadata::ModChild; use rustc_middle::middle::exported_symbols::ExportedSymbol; use rustc_middle::middle::stability::DeprecationEntry; use rustc_middle::query::LocalCrate; +use rustc_middle::query::{ExternProviders, Providers}; use rustc_middle::ty::fast_reject::SimplifiedType; -use rustc_middle::ty::query::{ExternProviders, Providers}; use rustc_middle::ty::{self, TyCtxt}; use rustc_session::cstore::CrateStore; use rustc_session::{Session, StableCrateId}; @@ -114,8 +114,8 @@ macro_rules! provide_one { ($tcx:ident, $def_id:ident, $other:ident, $cdata:ident, $name:ident => $compute:block) => { fn $name<'tcx>( $tcx: TyCtxt<'tcx>, - def_id_arg: ty::query::query_keys::$name<'tcx>, - ) -> ty::query::query_provided::$name<'tcx> { + def_id_arg: rustc_middle::query::query_keys::$name<'tcx>, + ) -> rustc_middle::query::query_provided::$name<'tcx> { let _prof_timer = $tcx.prof.generic_activity(concat!("metadata_decode_entry_", stringify!($name))); diff --git a/compiler/rustc_metadata/src/rmeta/def_path_hash_map.rs b/compiler/rustc_metadata/src/rmeta/def_path_hash_map.rs index 05402a58701..4f280bb9d80 100644 --- a/compiler/rustc_metadata/src/rmeta/def_path_hash_map.rs +++ b/compiler/rustc_metadata/src/rmeta/def_path_hash_map.rs @@ -1,6 +1,5 @@ use crate::rmeta::DecodeContext; use crate::rmeta::EncodeContext; -use rustc_data_structures::owned_slice::slice_owned; use rustc_data_structures::owned_slice::OwnedSlice; use rustc_hir::def_path_hash_map::{Config as HashMapConfig, DefPathHashMap}; use rustc_middle::parameterized_over_tcx; @@ -47,7 +46,7 @@ impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for DefPathHashMapRef<'static> fn decode(d: &mut DecodeContext<'a, 'tcx>) -> DefPathHashMapRef<'static> { let len = d.read_usize(); let pos = d.position(); - let o = slice_owned(d.blob().clone(), |blob| &blob[pos..pos + len]); + let o = d.blob().clone().0.slice(|blob| &blob[pos..pos + len]); // Although we already have the data we need via the `OwnedSlice`, we still need // to advance the `DecodeContext`'s position so it's in a valid state after diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 29cf432b8f9..79eb48a1a31 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -8,7 +8,7 @@ use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::{FxHashMap, FxIndexSet}; use rustc_data_structures::memmap::{Mmap, MmapMut}; use rustc_data_structures::stable_hasher::{Hash128, HashStable, StableHasher}; -use rustc_data_structures::sync::{join, par_iter, Lrc, ParallelIterator}; +use rustc_data_structures::sync::{join, par_for_each_in, Lrc}; use rustc_data_structures::temp_dir::MaybeTempDir; use rustc_hir as hir; use rustc_hir::def::DefKind; @@ -25,10 +25,10 @@ use rustc_middle::middle::exported_symbols::{ }; use rustc_middle::mir::interpret; use rustc_middle::query::LocalCrate; +use rustc_middle::query::Providers; use rustc_middle::traits::specialization_graph; use rustc_middle::ty::codec::TyEncoder; use rustc_middle::ty::fast_reject::{self, SimplifiedType, TreatParams}; -use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, SymbolName, Ty, TyCtxt}; use rustc_middle::util::common::to_readable_str; use rustc_serialize::{opaque, Decodable, Decoder, Encodable, Encoder}; @@ -1375,9 +1375,10 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { // Therefore, the loop over variants will encode its fields as the adt's children. } - for variant in adt_def.variants().iter() { + for (idx, variant) in adt_def.variants().iter_enumerated() { let data = VariantData { discr: variant.discr, + idx, ctor: variant.ctor.map(|(kind, def_id)| (kind, def_id.index)), is_non_exhaustive: variant.is_field_list_non_exhaustive(), }; @@ -1515,8 +1516,11 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { if encode_opt { record!(self.tables.optimized_mir[def_id.to_def_id()] <- tcx.optimized_mir(def_id)); - if tcx.sess.opts.unstable_opts.drop_tracking_mir && let DefKind::Generator = self.tcx.def_kind(def_id) { - record!(self.tables.mir_generator_witnesses[def_id.to_def_id()] <- tcx.mir_generator_witnesses(def_id)); + if tcx.sess.opts.unstable_opts.drop_tracking_mir + && let DefKind::Generator = self.tcx.def_kind(def_id) + && let Some(witnesses) = tcx.mir_generator_witnesses(def_id) + { + record!(self.tables.mir_generator_witnesses[def_id.to_def_id()] <- witnesses); } } if encode_const { @@ -1641,9 +1645,10 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } hir::ItemKind::OpaqueTy(ref opaque) => { self.encode_explicit_item_bounds(def_id); - self.tables - .is_type_alias_impl_trait - .set(def_id.index, matches!(opaque.origin, hir::OpaqueTyOrigin::TyAlias)); + self.tables.is_type_alias_impl_trait.set( + def_id.index, + matches!(opaque.origin, hir::OpaqueTyOrigin::TyAlias { .. }), + ); } hir::ItemKind::Impl(hir::Impl { defaultness, constness, .. }) => { self.tables.impl_defaultness.set_some(def_id.index, *defaultness); @@ -2129,7 +2134,7 @@ fn prefetch_mir(tcx: TyCtxt<'_>) { return; } - par_iter(tcx.mir_keys(())).for_each(|&def_id| { + par_for_each_in(tcx.mir_keys(()), |&def_id| { let (encode_const, encode_opt) = should_encode_mir(tcx, def_id); if encode_const { diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index e2f6acb186b..987a484049f 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -7,7 +7,6 @@ use table::TableBuilder; use rustc_ast as ast; use rustc_attr as attr; use rustc_data_structures::svh::Svh; -use rustc_data_structures::sync::MetadataRef; use rustc_hir as hir; use rustc_hir::def::{CtorKind, DefKind, DocLinkResMap}; use rustc_hir::def_id::{CrateNum, DefId, DefIndex, DefPathHash, StableCrateId}; @@ -20,8 +19,8 @@ use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs; use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo}; use rustc_middle::middle::resolve_bound_vars::ObjectLifetimeDefault; use rustc_middle::mir; +use rustc_middle::query::Providers; use rustc_middle::ty::fast_reject::SimplifiedType; -use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, ReprOptions, Ty, UnusedGenericParams}; use rustc_middle::ty::{DeducedParamAttrs, GeneratorDiagnosticData, ParameterizedOverTcx, TyCtxt}; use rustc_serialize::opaque::FileEncoder; @@ -31,6 +30,7 @@ use rustc_span::edition::Edition; use rustc_span::hygiene::{ExpnIndex, MacroKind}; use rustc_span::symbol::{Ident, Symbol}; use rustc_span::{self, ExpnData, ExpnHash, ExpnId, Span}; +use rustc_target::abi::VariantIdx; use rustc_target::spec::{PanicStrategy, TargetTriple}; use std::marker::PhantomData; @@ -430,6 +430,7 @@ define_tables! { #[derive(TyEncodable, TyDecodable)] struct VariantData { + idx: VariantIdx, discr: ty::VariantDiscr, /// If this is unit or tuple-variant/struct, then this is the index of the ctor id. ctor: Option<(CtorKind, DefIndex)>, diff --git a/compiler/rustc_middle/Cargo.toml b/compiler/rustc_middle/Cargo.toml index a7d97bd3cf5..7c56af1da41 100644 --- a/compiler/rustc_middle/Cargo.toml +++ b/compiler/rustc_middle/Cargo.toml @@ -11,6 +11,7 @@ chalk-ir = "0.87.0" derive_more = "0.99.17" either = "1.5.0" gsgdt = "0.1.2" +field-offset = "0.3.5" measureme = "10.0.0" polonius-engine = "0.13.0" rustc_apfloat = { path = "../rustc_apfloat" } diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index 15d672c1408..5bf0938d518 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -5,7 +5,7 @@ use rustc_ast as ast; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::svh::Svh; -use rustc_data_structures::sync::{par_for_each_in, Send, Sync}; +use rustc_data_structures::sync::{par_for_each_in, DynSend, DynSync}; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID, LOCAL_CRATE}; use rustc_hir::definitions::{DefKey, DefPath, DefPathData, DefPathHash}; @@ -150,11 +150,6 @@ impl<'hir> Map<'hir> { self.tcx.hir_module_items(module).items() } - #[inline] - pub fn par_for_each_item(self, f: impl Fn(ItemId) + Sync + Send) { - par_for_each_in(&self.tcx.hir_crate_items(()).items[..], |id| f(*id)); - } - pub fn def_key(self, def_id: LocalDefId) -> DefKey { // Accessing the DefKey is ok, since it is part of DefPathHash. self.tcx.definitions_untracked().def_key(def_id) @@ -502,7 +497,7 @@ impl<'hir> Map<'hir> { } #[inline] - pub fn par_body_owners(self, f: impl Fn(LocalDefId) + Sync + Send) { + pub fn par_body_owners(self, f: impl Fn(LocalDefId) + DynSend + DynSync) { par_for_each_in(&self.tcx.hir_crate_items(()).body_owners[..], |&def_id| f(def_id)); } @@ -640,7 +635,7 @@ impl<'hir> Map<'hir> { } #[inline] - pub fn par_for_each_module(self, f: impl Fn(LocalDefId) + Sync + Send) { + pub fn par_for_each_module(self, f: impl Fn(LocalDefId) + DynSend + DynSync) { let crate_items = self.tcx.hir_crate_items(()); par_for_each_in(&crate_items.submodules[..], |module| f(module.def_id)) } diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs index 7770a5e4764..61c9e72db2c 100644 --- a/compiler/rustc_middle/src/hir/mod.rs +++ b/compiler/rustc_middle/src/hir/mod.rs @@ -6,10 +6,10 @@ pub mod map; pub mod nested_filter; pub mod place; -use crate::ty::query::Providers; +use crate::query::Providers; use crate::ty::{EarlyBinder, ImplSubject, TyCtxt}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; -use rustc_data_structures::sync::{par_for_each_in, Send, Sync}; +use rustc_data_structures::sync::{par_for_each_in, DynSend, DynSync}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::*; use rustc_query_system::ich::StableHashingContext; @@ -77,19 +77,19 @@ impl ModuleItems { self.owners().map(|id| id.def_id) } - pub fn par_items(&self, f: impl Fn(ItemId) + Send + Sync) { + pub fn par_items(&self, f: impl Fn(ItemId) + DynSend + DynSync) { par_for_each_in(&self.items[..], |&id| f(id)) } - pub fn par_trait_items(&self, f: impl Fn(TraitItemId) + Send + Sync) { + pub fn par_trait_items(&self, f: impl Fn(TraitItemId) + DynSend + DynSync) { par_for_each_in(&self.trait_items[..], |&id| f(id)) } - pub fn par_impl_items(&self, f: impl Fn(ImplItemId) + Send + Sync) { + pub fn par_impl_items(&self, f: impl Fn(ImplItemId) + DynSend + DynSync) { par_for_each_in(&self.impl_items[..], |&id| f(id)) } - pub fn par_foreign_items(&self, f: impl Fn(ForeignItemId) + Send + Sync) { + pub fn par_foreign_items(&self, f: impl Fn(ForeignItemId) + DynSend + DynSync) { par_for_each_in(&self.foreign_items[..], |&id| f(id)) } } diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs index e9172e767e0..dc911c88574 100644 --- a/compiler/rustc_middle/src/lib.rs +++ b/compiler/rustc_middle/src/lib.rs @@ -85,12 +85,7 @@ mod tests; mod macros; #[macro_use] -pub mod query; - -#[macro_use] pub mod arena; -#[macro_use] -pub mod dep_graph; pub(crate) mod error; pub mod hir; pub mod infer; @@ -100,10 +95,16 @@ pub mod middle; pub mod mir; pub mod thir; pub mod traits; +#[macro_use] pub mod ty; pub mod util; mod values; +#[macro_use] +pub mod query; +#[macro_use] +pub mod dep_graph; + // Allows macros to refer to this crate as `::rustc_middle` extern crate self as rustc_middle; diff --git a/compiler/rustc_middle/src/middle/limits.rs b/compiler/rustc_middle/src/middle/limits.rs index 12aef66bcf9..bd859d4d61b 100644 --- a/compiler/rustc_middle/src/middle/limits.rs +++ b/compiler/rustc_middle/src/middle/limits.rs @@ -11,7 +11,7 @@ use crate::bug; use crate::error::LimitInvalid; -use crate::ty; +use crate::query::Providers; use rustc_ast::Attribute; use rustc_session::Session; use rustc_session::{Limit, Limits}; @@ -19,7 +19,7 @@ use rustc_span::symbol::{sym, Symbol}; use std::num::IntErrorKind; -pub fn provide(providers: &mut ty::query::Providers) { +pub fn provide(providers: &mut Providers) { providers.limits = |tcx, ()| Limits { recursion_limit: get_recursion_limit(tcx.hir().krate_attrs(), tcx.sess), move_size_limit: get_limit( diff --git a/compiler/rustc_middle/src/middle/mod.rs b/compiler/rustc_middle/src/middle/mod.rs index 9c25f3009ba..9bb4570ef14 100644 --- a/compiler/rustc_middle/src/middle/mod.rs +++ b/compiler/rustc_middle/src/middle/mod.rs @@ -32,6 +32,6 @@ pub mod region; pub mod resolve_bound_vars; pub mod stability; -pub fn provide(providers: &mut crate::ty::query::Providers) { +pub fn provide(providers: &mut crate::query::Providers) { limits::provide(providers); } diff --git a/compiler/rustc_middle/src/middle/privacy.rs b/compiler/rustc_middle/src/middle/privacy.rs index 967fed687b6..aeb6a1601fc 100644 --- a/compiler/rustc_middle/src/middle/privacy.rs +++ b/compiler/rustc_middle/src/middle/privacy.rs @@ -64,7 +64,7 @@ impl EffectiveVisibility { self.at_level(level).is_public() } - pub fn from_vis(vis: Visibility) -> EffectiveVisibility { + pub const fn from_vis(vis: Visibility) -> EffectiveVisibility { EffectiveVisibility { direct: vis, reexported: vis, @@ -72,6 +72,18 @@ impl EffectiveVisibility { reachable_through_impl_trait: vis, } } + + #[must_use] + pub fn min(mut self, lhs: EffectiveVisibility, tcx: TyCtxt<'_>) -> Self { + for l in Level::all_levels() { + let rhs_vis = self.at_level_mut(l); + let lhs_vis = *lhs.at_level(l); + if rhs_vis.is_at_least(lhs_vis, tcx) { + *rhs_vis = lhs_vis; + }; + } + self + } } /// Holds a map of effective visibilities for reachable HIR nodes. @@ -137,24 +149,6 @@ impl EffectiveVisibilities { }; } - pub fn set_public_at_level( - &mut self, - id: LocalDefId, - lazy_private_vis: impl FnOnce() -> Visibility, - level: Level, - ) { - let mut effective_vis = self - .effective_vis(id) - .copied() - .unwrap_or_else(|| EffectiveVisibility::from_vis(lazy_private_vis())); - for l in Level::all_levels() { - if l <= level { - *effective_vis.at_level_mut(l) = Visibility::Public; - } - } - self.map.insert(id, effective_vis); - } - pub fn check_invariants(&self, tcx: TyCtxt<'_>, early: bool) { if !cfg!(debug_assertions) { return; @@ -219,7 +213,7 @@ impl<Id: Eq + Hash> EffectiveVisibilities<Id> { pub fn update( &mut self, id: Id, - nominal_vis: Visibility, + nominal_vis: Option<Visibility>, lazy_private_vis: impl FnOnce() -> Visibility, inherited_effective_vis: EffectiveVisibility, level: Level, @@ -243,12 +237,11 @@ impl<Id: Eq + Hash> EffectiveVisibilities<Id> { if !(inherited_effective_vis_at_prev_level == inherited_effective_vis_at_level && level != l) { - calculated_effective_vis = - if nominal_vis.is_at_least(inherited_effective_vis_at_level, tcx) { - inherited_effective_vis_at_level - } else { - nominal_vis - }; + calculated_effective_vis = if let Some(nominal_vis) = nominal_vis && !nominal_vis.is_at_least(inherited_effective_vis_at_level, tcx) { + nominal_vis + } else { + inherited_effective_vis_at_level + } } // effective visibility can't be decreased at next update call for the // same id diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs index e45284ca506..d65ceef2472 100644 --- a/compiler/rustc_middle/src/mir/interpret/error.rs +++ b/compiler/rustc_middle/src/mir/interpret/error.rs @@ -15,15 +15,49 @@ use std::{any::Any, backtrace::Backtrace, fmt}; pub enum ErrorHandled { /// Already reported an error for this evaluation, and the compilation is /// *guaranteed* to fail. Warnings/lints *must not* produce `Reported`. - Reported(ErrorGuaranteed), + Reported(ReportedErrorInfo), /// Don't emit an error, the evaluation failed because the MIR was generic /// and the substs didn't fully monomorphize it. TooGeneric, } impl From<ErrorGuaranteed> for ErrorHandled { - fn from(err: ErrorGuaranteed) -> ErrorHandled { - ErrorHandled::Reported(err) + #[inline] + fn from(error: ErrorGuaranteed) -> ErrorHandled { + ErrorHandled::Reported(error.into()) + } +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)] +pub struct ReportedErrorInfo { + error: ErrorGuaranteed, + is_tainted_by_errors: bool, +} + +impl ReportedErrorInfo { + #[inline] + pub fn tainted_by_errors(error: ErrorGuaranteed) -> ReportedErrorInfo { + ReportedErrorInfo { is_tainted_by_errors: true, error } + } + + /// Returns true if evaluation failed because MIR was tainted by errors. + #[inline] + pub fn is_tainted_by_errors(self) -> bool { + self.is_tainted_by_errors + } +} + +impl From<ErrorGuaranteed> for ReportedErrorInfo { + #[inline] + fn from(error: ErrorGuaranteed) -> ReportedErrorInfo { + ReportedErrorInfo { is_tainted_by_errors: false, error } + } +} + +impl Into<ErrorGuaranteed> for ReportedErrorInfo { + #[inline] + fn into(self) -> ErrorGuaranteed { + self.error } } @@ -89,7 +123,7 @@ fn print_backtrace(backtrace: &Backtrace) { impl From<ErrorGuaranteed> for InterpErrorInfo<'_> { fn from(err: ErrorGuaranteed) -> Self { - InterpError::InvalidProgram(InvalidProgramInfo::AlreadyReported(err)).into() + InterpError::InvalidProgram(InvalidProgramInfo::AlreadyReported(err.into())).into() } } @@ -125,7 +159,7 @@ pub enum InvalidProgramInfo<'tcx> { /// Resolution can fail if we are in a too generic context. TooGeneric, /// Abort in case errors are already reported. - AlreadyReported(ErrorGuaranteed), + AlreadyReported(ReportedErrorInfo), /// An error occurred during layout computation. Layout(layout::LayoutError<'tcx>), /// An error occurred during FnAbi computation: the passed --target lacks FFI support @@ -144,7 +178,7 @@ impl fmt::Display for InvalidProgramInfo<'_> { use InvalidProgramInfo::*; match self { TooGeneric => write!(f, "encountered overly generic constant"), - AlreadyReported(ErrorGuaranteed { .. }) => { + AlreadyReported(_) => { write!( f, "an error has already been reported elsewhere (this should not usually be printed)" diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs index e5a9766c84d..3620385fab1 100644 --- a/compiler/rustc_middle/src/mir/interpret/mod.rs +++ b/compiler/rustc_middle/src/mir/interpret/mod.rs @@ -120,8 +120,8 @@ use crate::ty::{self, Instance, Ty, TyCtxt}; pub use self::error::{ struct_error, CheckInAllocMsg, ErrorHandled, EvalToAllocationRawResult, EvalToConstValueResult, EvalToValTreeResult, InterpError, InterpErrorInfo, InterpResult, InvalidProgramInfo, - MachineStopType, ResourceExhaustionInfo, ScalarSizeMismatch, UndefinedBehaviorInfo, - UninitBytesAccess, UnsupportedOpInfo, + MachineStopType, ReportedErrorInfo, ResourceExhaustionInfo, ScalarSizeMismatch, + UndefinedBehaviorInfo, UninitBytesAccess, UnsupportedOpInfo, }; pub use self::value::{get_slice_bytes, ConstAlloc, ConstValue, Scalar}; diff --git a/compiler/rustc_middle/src/mir/interpret/queries.rs b/compiler/rustc_middle/src/mir/interpret/queries.rs index ed4ee93e97d..ce11dabc195 100644 --- a/compiler/rustc_middle/src/mir/interpret/queries.rs +++ b/compiler/rustc_middle/src/mir/interpret/queries.rs @@ -61,7 +61,7 @@ impl<'tcx> TyCtxt<'tcx> { self.const_eval_global_id(param_env, cid, span) } Ok(None) => Err(ErrorHandled::TooGeneric), - Err(error_reported) => Err(ErrorHandled::Reported(error_reported)), + Err(err) => Err(ErrorHandled::Reported(err.into())), } } @@ -110,7 +110,7 @@ impl<'tcx> TyCtxt<'tcx> { }) } Ok(None) => Err(ErrorHandled::TooGeneric), - Err(error_reported) => Err(ErrorHandled::Reported(error_reported)), + Err(err) => Err(ErrorHandled::Reported(err.into())), } } diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 55991facd89..1da94dd7917 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -1111,6 +1111,10 @@ pub struct VarDebugInfo<'tcx> { /// originated from (starting from 1). Note, if MIR inlining is enabled, then this is the /// argument number in the original function before it was inlined. pub argument_index: Option<u16>, + + /// The data represents `name` dereferenced `references` times, + /// and not the direct value. + pub references: u8, } /////////////////////////////////////////////////////////////////////////// @@ -1550,8 +1554,11 @@ impl<V, T> ProjectionElem<V, T> { /// Returns `true` if this is accepted inside `VarDebugInfoContents::Place`. pub fn can_use_in_debuginfo(&self) -> bool { match self { - Self::Deref | Self::Downcast(_, _) | Self::Field(_, _) => true, - Self::ConstantIndex { .. } + Self::ConstantIndex { from_end: false, .. } + | Self::Deref + | Self::Downcast(_, _) + | Self::Field(_, _) => true, + Self::ConstantIndex { from_end: true, .. } | Self::Index(_) | Self::OpaqueCast(_) | Self::Subslice { .. } => false, @@ -1639,18 +1646,7 @@ impl<'tcx> Place<'tcx> { return self; } - let mut v: Vec<PlaceElem<'tcx>>; - - let new_projections = if self.projection.is_empty() { - more_projections - } else { - v = Vec::with_capacity(self.projection.len() + more_projections.len()); - v.extend(self.projection); - v.extend(more_projections); - &v - }; - - Place { local: self.local, projection: tcx.mk_place_elems(new_projections) } + self.as_ref().project_deeper(more_projections, tcx) } } @@ -1721,6 +1717,27 @@ impl<'tcx> PlaceRef<'tcx> { (base, *proj) }) } + + /// Generates a new place by appending `more_projections` to the existing ones + /// and interning the result. + pub fn project_deeper( + self, + more_projections: &[PlaceElem<'tcx>], + tcx: TyCtxt<'tcx>, + ) -> Place<'tcx> { + let mut v: Vec<PlaceElem<'tcx>>; + + let new_projections = if self.projection.is_empty() { + more_projections + } else { + v = Vec::with_capacity(self.projection.len() + more_projections.len()); + v.extend(self.projection); + v.extend(more_projections); + &v + }; + + Place { local: self.local, projection: tcx.mk_place_elems(new_projections) } + } } impl Debug for Place<'_> { @@ -2313,7 +2330,7 @@ impl<'tcx> ConstantKind<'tcx> { if let Some(val) = c.kind().try_eval_for_mir(tcx, param_env) { match val { Ok(val) => Self::Val(val, c.ty()), - Err(_) => Self::Ty(tcx.const_error(self.ty())), + Err(guar) => Self::Ty(tcx.const_error(self.ty(), guar)), } } else { self @@ -2325,9 +2342,7 @@ impl<'tcx> ConstantKind<'tcx> { match tcx.const_eval_resolve(param_env, uneval, None) { Ok(val) => Self::Val(val, ty), Err(ErrorHandled::TooGeneric) => self, - Err(ErrorHandled::Reported(guar)) => { - Self::Ty(tcx.const_error_with_guaranteed(ty, guar)) - } + Err(ErrorHandled::Reported(guar)) => Self::Ty(tcx.const_error(ty, guar.into())), } } } diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index fa8a339631e..62c3d8cf239 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -551,8 +551,13 @@ fn write_scope_tree( } let indented_debug_info = format!( - "{0:1$}debug {2} => {3:?};", - INDENT, indent, var_debug_info.name, var_debug_info.value, + "{0:1$}debug {2} => {3:&<4$}{5:?};", + INDENT, + indent, + var_debug_info.name, + "", + var_debug_info.references as usize, + var_debug_info.value, ); writeln!( diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index 6718605ed0b..596dd80bf48 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -64,7 +64,7 @@ use crate::mir::*; use crate::ty::subst::SubstsRef; -use crate::ty::{CanonicalUserTypeAnnotation, Ty}; +use crate::ty::{self, CanonicalUserTypeAnnotation, Ty}; use rustc_span::Span; macro_rules! make_mir_visitor { @@ -782,12 +782,12 @@ macro_rules! make_mir_visitor { fn super_ascribe_user_ty(&mut self, place: & $($mutability)? Place<'tcx>, - _variance: $(& $mutability)? ty::Variance, + variance: $(& $mutability)? ty::Variance, user_ty: & $($mutability)? UserTypeProjection, location: Location) { self.visit_place( place, - PlaceContext::NonUse(NonUseContext::AscribeUserTy), + PlaceContext::NonUse(NonUseContext::AscribeUserTy($(* &$mutability *)? variance)), location ); self.visit_user_type_projection(user_ty); @@ -842,6 +842,7 @@ macro_rules! make_mir_visitor { source_info, value, argument_index: _, + references: _, } = var_debug_info; self.visit_source_info(source_info); @@ -880,12 +881,11 @@ macro_rules! make_mir_visitor { ) { let Constant { span, - user_ty, + user_ty: _, // no visit method for this literal, } = constant; self.visit_span($(& $mutability)? *span); - drop(user_ty); // no visit method for this match literal { ConstantKind::Ty(ct) => self.visit_ty_const($(&$mutability)? *ct, location), ConstantKind::Val(_, ty) => self.visit_ty($(& $mutability)? *ty, TyContext::Location(location)), @@ -1320,7 +1320,7 @@ pub enum NonUseContext { /// Ending a storage live range. StorageDead, /// User type annotation assertions for NLL. - AscribeUserTy, + AscribeUserTy(ty::Variance), /// The data of a user variable, for debug info. VarDebugInfo, } diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs index 28a9c1eef1a..b45f7caaabe 100644 --- a/compiler/rustc_middle/src/query/erase.rs +++ b/compiler/rustc_middle/src/query/erase.rs @@ -172,6 +172,10 @@ impl EraseType for ty::Binder<'_, ty::FnSig<'_>> { type Result = [u8; size_of::<ty::Binder<'static, ty::FnSig<'static>>>()]; } +impl EraseType for ty::Binder<'_, &'_ ty::List<Ty<'_>>> { + type Result = [u8; size_of::<ty::Binder<'static, &'static ty::List<Ty<'static>>>>()]; +} + impl<T0, T1> EraseType for (&'_ T0, &'_ T1) { type Result = [u8; size_of::<(&'static (), &'static ())>()]; } diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index dd89283d704..f564f5e99e8 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -4,8 +4,89 @@ //! ["Queries: demand-driven compilation"](https://rustc-dev-guide.rust-lang.org/query.html). //! This chapter includes instructions for adding new queries. -use crate::ty::{self, print::describe_as_module, TyCtxt}; +#![allow(unused_parens)] + +use crate::dep_graph; +use crate::dep_graph::DepKind; +use crate::infer::canonical::{self, Canonical}; +use crate::lint::LintExpectation; +use crate::metadata::ModChild; +use crate::middle::codegen_fn_attrs::CodegenFnAttrs; +use crate::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo}; +use crate::middle::lib_features::LibFeatures; +use crate::middle::privacy::EffectiveVisibilities; +use crate::middle::resolve_bound_vars::{ObjectLifetimeDefault, ResolveBoundVars, ResolvedArg}; +use crate::middle::stability::{self, DeprecationEntry}; +use crate::mir; +use crate::mir::interpret::GlobalId; +use crate::mir::interpret::{ + ConstValue, EvalToAllocationRawResult, EvalToConstValueResult, EvalToValTreeResult, +}; +use crate::mir::interpret::{LitToConstError, LitToConstInput}; +use crate::mir::mono::CodegenUnit; +use crate::query::erase::{erase, restore, Erase}; +use crate::thir; +use crate::traits::query::{ + CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTyGoal, + CanonicalTypeOpAscribeUserTypeGoal, CanonicalTypeOpEqGoal, CanonicalTypeOpNormalizeGoal, + CanonicalTypeOpProvePredicateGoal, CanonicalTypeOpSubtypeGoal, NoSolution, +}; +use crate::traits::query::{ + DropckConstraint, DropckOutlivesResult, MethodAutoderefStepsResult, NormalizationResult, + OutlivesBound, +}; +use crate::traits::specialization_graph; +use crate::traits::{self, ImplSource}; +use crate::ty::fast_reject::SimplifiedType; +use crate::ty::layout::ValidityRequirement; +use crate::ty::query::{ + query_ensure, query_get_at, DynamicQuery, IntoQueryParam, TyCtxtAt, TyCtxtEnsure, + TyCtxtEnsureWithValue, +}; +use crate::ty::subst::{GenericArg, SubstsRef}; +use crate::ty::util::AlwaysRequiresDrop; +use crate::ty::GeneratorDiagnosticData; +use crate::ty::TyCtxtFeed; +use crate::ty::{ + self, print::describe_as_module, CrateInherentImpls, ParamEnvAnd, Ty, TyCtxt, + UnusedGenericParams, +}; +use rustc_arena::TypedArena; +use rustc_ast as ast; +use rustc_ast::expand::allocator::AllocatorKind; +use rustc_attr as attr; +use rustc_data_structures::fingerprint::Fingerprint; +use rustc_data_structures::fx::{FxHashMap, FxIndexMap, FxIndexSet}; +use rustc_data_structures::steal::Steal; +use rustc_data_structures::svh::Svh; +use rustc_data_structures::sync::Lrc; +use rustc_data_structures::sync::WorkerLocal; +use rustc_data_structures::unord::UnordSet; +use rustc_errors::ErrorGuaranteed; +use rustc_hir as hir; +use rustc_hir::def::{DefKind, DocLinkResMap}; +use rustc_hir::def_id::{ + CrateNum, DefId, DefIdMap, DefIdSet, LocalDefId, LocalDefIdMap, LocalDefIdSet, +}; +use rustc_hir::lang_items::{LangItem, LanguageItems}; +use rustc_hir::{Crate, ItemLocalId, TraitCandidate}; +use rustc_index::IndexVec; +use rustc_query_system::ich::StableHashingContext; +use rustc_query_system::query::{try_get_cached, CacheSelector, QueryCache, QueryMode, QueryState}; +use rustc_session::config::{EntryFnType, OptLevel, OutputFilenames, SymbolManglingVersion}; +use rustc_session::cstore::{CrateDepKind, CrateSource}; +use rustc_session::cstore::{ExternCrate, ForeignModule, LinkagePreference, NativeLib}; +use rustc_session::lint::LintExpectationId; +use rustc_session::Limits; use rustc_span::def_id::LOCAL_CRATE; +use rustc_span::symbol::Symbol; +use rustc_span::{Span, DUMMY_SP}; +use rustc_target::abi; +use rustc_target::spec::PanicStrategy; +use std::mem; +use std::ops::Deref; +use std::path::PathBuf; +use std::sync::Arc; pub mod erase; mod keys; @@ -236,6 +317,15 @@ rustc_queries! { cache_on_disk_if { key.is_local() } } + query opaque_types_defined_by( + key: LocalDefId + ) -> &'tcx [LocalDefId] { + desc { + |tcx| "computing the opaque types defined by `{}`", + tcx.def_path_str(key.to_def_id()) + } + } + /// Returns the list of bounds that can be used for /// `SelectionCandidate::ProjectionCandidate(_)` and /// `ProjectionTyCandidate::TraitDef`. @@ -437,7 +527,7 @@ rustc_queries! { } } - query mir_generator_witnesses(key: DefId) -> &'tcx mir::GeneratorLayout<'tcx> { + query mir_generator_witnesses(key: DefId) -> &'tcx Option<mir::GeneratorLayout<'tcx>> { arena_cache desc { |tcx| "generator witness types for `{}`", tcx.def_path_str(key) } cache_on_disk_if { key.is_local() } @@ -1016,7 +1106,7 @@ rustc_queries! { desc { "converting literal to mir constant" } } - query check_match(key: LocalDefId) { + query check_match(key: LocalDefId) -> Result<(), rustc_errors::ErrorGuaranteed> { desc { |tcx| "match-checking `{}`", tcx.def_path_str(key) } cache_on_disk_if { true } } @@ -2093,3 +2183,6 @@ rustc_queries! { desc { "check whether two const param are definitely not equal to eachother"} } } + +rustc_query_append! { define_callbacks! } +rustc_feedable_queries! { define_feedable! } diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index 8366567c2c3..2f0b07d4c71 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -281,9 +281,6 @@ pub enum ObligationCauseCode<'tcx> { /// A type like `Box<Foo<'a> + 'b>` is WF only if `'b: 'a`. ObjectTypeBound(Ty<'tcx>, ty::Region<'tcx>), - /// Obligation incurred due to an object cast. - ObjectCastObligation(/* Concrete type */ Ty<'tcx>, /* Object type */ Ty<'tcx>), - /// Obligation incurred due to a coercion. Coercion { source: Ty<'tcx>, @@ -580,11 +577,7 @@ pub enum SelectionError<'tcx> { /// After a closure impl has selected, its "outputs" were evaluated /// (which for closures includes the "input" type params) and they /// didn't resolve. See `confirm_poly_trait_refs` for more. - OutputTypeParameterMismatch( - ty::PolyTraitRef<'tcx>, - ty::PolyTraitRef<'tcx>, - ty::error::TypeError<'tcx>, - ), + OutputTypeParameterMismatch(Box<SelectionOutputTypeParameterMismatch<'tcx>>), /// The trait pointed by `DefId` is not object safe. TraitNotObjectSafe(DefId), /// A given constant couldn't be evaluated. @@ -596,6 +589,13 @@ pub enum SelectionError<'tcx> { ErrorReporting, } +#[derive(Clone, Debug, TypeVisitable, Lift)] +pub struct SelectionOutputTypeParameterMismatch<'tcx> { + pub found_trait_ref: ty::PolyTraitRef<'tcx>, + pub expected_trait_ref: ty::PolyTraitRef<'tcx>, + pub terr: ty::error::TypeError<'tcx>, +} + /// When performing resolution, it is typically the case that there /// can be one of three outcomes: /// diff --git a/compiler/rustc_middle/src/ty/_match.rs b/compiler/rustc_middle/src/ty/_match.rs index 468c2c818b2..cbc68fde9d9 100644 --- a/compiler/rustc_middle/src/ty/_match.rs +++ b/compiler/rustc_middle/src/ty/_match.rs @@ -83,7 +83,7 @@ impl<'tcx> TypeRelation<'tcx> for Match<'tcx> { (&ty::Error(guar), _) | (_, &ty::Error(guar)) => Ok(self.tcx().ty_error(guar)), - _ => relate::super_relate_tys(self, a, b), + _ => relate::structurally_relate_tys(self, a, b), } } @@ -109,7 +109,7 @@ impl<'tcx> TypeRelation<'tcx> for Match<'tcx> { _ => {} } - relate::super_relate_consts(self, a, b) + relate::structurally_relate_consts(self, a, b) } fn binders<T>( diff --git a/compiler/rustc_middle/src/ty/abstract_const.rs b/compiler/rustc_middle/src/ty/abstract_const.rs index 972c417cbba..a39631da936 100644 --- a/compiler/rustc_middle/src/ty/abstract_const.rs +++ b/compiler/rustc_middle/src/ty/abstract_const.rs @@ -53,7 +53,7 @@ impl<'tcx> TyCtxt<'tcx> { fn fold_const(&mut self, c: Const<'tcx>) -> Const<'tcx> { let ct = match c.kind() { ty::ConstKind::Unevaluated(uv) => match self.tcx.thir_abstract_const(uv.def) { - Err(e) => self.tcx.const_error_with_guaranteed(c.ty(), e), + Err(e) => self.tcx.const_error(c.ty(), e), Ok(Some(bac)) => { let substs = self.tcx.erase_regions(uv.substs); let bac = bac.subst(self.tcx, substs); diff --git a/compiler/rustc_middle/src/ty/closure.rs b/compiler/rustc_middle/src/ty/closure.rs index f29bf92b0ed..be7b2b7ec67 100644 --- a/compiler/rustc_middle/src/ty/closure.rs +++ b/compiler/rustc_middle/src/ty/closure.rs @@ -5,6 +5,7 @@ use crate::{mir, ty}; use std::fmt::Write; +use crate::query::Providers; use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::{self as hir, LangItem}; @@ -457,6 +458,6 @@ impl BorrowKind { } } -pub fn provide(providers: &mut ty::query::Providers) { - *providers = ty::query::Providers { closure_typeinfo, ..*providers } +pub fn provide(providers: &mut Providers) { + *providers = Providers { closure_typeinfo, ..*providers } } diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs index e7107c28bf4..0a5792a9c47 100644 --- a/compiler/rustc_middle/src/ty/consts.rs +++ b/compiler/rustc_middle/src/ty/consts.rs @@ -142,9 +142,7 @@ impl<'tcx> Const<'tcx> { ty::ConstKind::Bound(debruijn, ty::BoundVar::from_u32(index)), param_ty, )), - Some(rbv::ResolvedArg::Error(guar)) => { - Some(tcx.const_error_with_guaranteed(param_ty, guar)) - } + Some(rbv::ResolvedArg::Error(guar)) => Some(tcx.const_error(param_ty, guar)), arg => bug!("unexpected bound var resolution for {:?}: {arg:?}", expr.hir_id), } } @@ -228,7 +226,7 @@ impl<'tcx> Const<'tcx> { if let Some(val) = self.kind().try_eval_for_typeck(tcx, param_env) { match val { Ok(val) => tcx.mk_const(val, self.ty()), - Err(guar) => tcx.const_error_with_guaranteed(self.ty(), guar), + Err(guar) => tcx.const_error(self.ty(), guar), } } else { // Either the constant isn't evaluatable or ValTree creation failed. diff --git a/compiler/rustc_middle/src/ty/consts/kind.rs b/compiler/rustc_middle/src/ty/consts/kind.rs index 1ac2cd13982..a108f6c8947 100644 --- a/compiler/rustc_middle/src/ty/consts/kind.rs +++ b/compiler/rustc_middle/src/ty/consts/kind.rs @@ -245,7 +245,7 @@ impl<'tcx> ConstKind<'tcx> { // can leak through `val` into the const we return. Ok(val) => Some(Ok(EvalResult::ValTree(val?))), Err(ErrorHandled::TooGeneric) => None, - Err(ErrorHandled::Reported(e)) => Some(Err(e)), + Err(ErrorHandled::Reported(e)) => Some(Err(e.into())), } } EvalMode::Mir => { @@ -256,7 +256,7 @@ impl<'tcx> ConstKind<'tcx> { // can leak through `val` into the const we return. Ok(val) => Some(Ok(EvalResult::ConstVal(val))), Err(ErrorHandled::TooGeneric) => None, - Err(ErrorHandled::Reported(e)) => Some(Err(e)), + Err(ErrorHandled::Reported(e)) => Some(Err(e.into())), } } } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 8aea2d8aedf..097bfb71a6f 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -14,14 +14,13 @@ use crate::middle::resolve_bound_vars; use crate::middle::stability; use crate::mir::interpret::{self, Allocation, ConstAllocation}; use crate::mir::{Body, Local, Place, PlaceElem, ProjectionKind, Promoted}; -use crate::query::on_disk_cache::OnDiskCache; use crate::query::LocalCrate; +use crate::query::Providers; use crate::thir::Thir; use crate::traits; use crate::traits::solve; use crate::traits::solve::{ExternalConstraints, ExternalConstraintsData}; use crate::ty::query::QuerySystem; -use crate::ty::query::QuerySystemFns; use crate::ty::query::{self, TyCtxtAt}; use crate::ty::{ self, AdtDef, AdtDefData, AdtKind, Binder, Const, ConstData, FloatTy, FloatVar, FloatVid, @@ -496,7 +495,7 @@ pub struct GlobalCtxt<'tcx> { /// /// FIXME(Centril): consider `dyn LintStoreMarker` once /// we can upcast to `Any` for some additional type safety. - pub lint_store: Lrc<dyn Any + sync::Sync + sync::Send>, + pub lint_store: Lrc<dyn Any + sync::DynSync + sync::DynSend>, pub dep_graph: DepGraph, @@ -648,14 +647,13 @@ impl<'tcx> TyCtxt<'tcx> { /// reference to the context, to allow formatting values that need it. pub fn create_global_ctxt( s: &'tcx Session, - lint_store: Lrc<dyn Any + sync::Send + sync::Sync>, + lint_store: Lrc<dyn Any + sync::DynSend + sync::DynSync>, arena: &'tcx WorkerLocal<Arena<'tcx>>, hir_arena: &'tcx WorkerLocal<hir::Arena<'tcx>>, untracked: Untracked, dep_graph: DepGraph, - on_disk_cache: Option<OnDiskCache<'tcx>>, query_kinds: &'tcx [DepKindStruct<'tcx>], - query_system_fns: QuerySystemFns<'tcx>, + query_system: QuerySystem<'tcx>, ) -> GlobalCtxt<'tcx> { let data_layout = s.target.parse_data_layout().unwrap_or_else(|err| { s.emit_fatal(err); @@ -677,7 +675,7 @@ impl<'tcx> TyCtxt<'tcx> { lifetimes: common_lifetimes, consts: common_consts, untracked, - query_system: QuerySystem::new(query_system_fns, on_disk_cache), + query_system, query_kinds, ty_rcache: Default::default(), pred_rcache: Default::default(), @@ -735,17 +733,13 @@ impl<'tcx> TyCtxt<'tcx> { /// Like [TyCtxt::ty_error] but for constants, with current `ErrorGuaranteed` #[track_caller] - pub fn const_error_with_guaranteed( - self, - ty: Ty<'tcx>, - reported: ErrorGuaranteed, - ) -> Const<'tcx> { + pub fn const_error(self, ty: Ty<'tcx>, reported: ErrorGuaranteed) -> Const<'tcx> { self.mk_const(ty::ConstKind::Error(reported), ty) } /// Like [TyCtxt::ty_error] but for constants. #[track_caller] - pub fn const_error(self, ty: Ty<'tcx>) -> Const<'tcx> { + pub fn const_error_misc(self, ty: Ty<'tcx>) -> Const<'tcx> { self.const_error_with_message( ty, DUMMY_SP, @@ -2461,7 +2455,7 @@ pub struct DeducedParamAttrs { pub read_only: bool, } -pub fn provide(providers: &mut ty::query::Providers) { +pub fn provide(providers: &mut Providers) { providers.maybe_unused_trait_imports = |tcx, ()| &tcx.resolutions(()).maybe_unused_trait_imports; providers.names_imported_by_glob_use = |tcx, id| { diff --git a/compiler/rustc_middle/src/ty/context/tls.rs b/compiler/rustc_middle/src/ty/context/tls.rs index fb0d909307e..bf9806f6406 100644 --- a/compiler/rustc_middle/src/ty/context/tls.rs +++ b/compiler/rustc_middle/src/ty/context/tls.rs @@ -94,8 +94,8 @@ where f(None) } else { // We could get an `ImplicitCtxt` pointer from another thread. - // Ensure that `ImplicitCtxt` is `Sync`. - sync::assert_sync::<ImplicitCtxt<'_, '_>>(); + // Ensure that `ImplicitCtxt` is `DynSync`. + sync::assert_dyn_sync::<ImplicitCtxt<'_, '_>>(); unsafe { f(Some(downcast(context))) } } diff --git a/compiler/rustc_middle/src/ty/erase_regions.rs b/compiler/rustc_middle/src/ty/erase_regions.rs index ad930d1e6b6..7895993ccff 100644 --- a/compiler/rustc_middle/src/ty/erase_regions.rs +++ b/compiler/rustc_middle/src/ty/erase_regions.rs @@ -1,8 +1,9 @@ +use crate::query::Providers; use crate::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable}; use crate::ty::{self, Ty, TyCtxt, TypeFlags, TypeVisitableExt}; -pub(super) fn provide(providers: &mut ty::query::Providers) { - *providers = ty::query::Providers { erase_regions_ty, ..*providers }; +pub(super) fn provide(providers: &mut Providers) { + *providers = Providers { erase_regions_ty, ..*providers }; } fn erase_regions_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> { diff --git a/compiler/rustc_middle/src/ty/generics.rs b/compiler/rustc_middle/src/ty/generics.rs index baef4ffeda7..99174bae3f6 100644 --- a/compiler/rustc_middle/src/ty/generics.rs +++ b/compiler/rustc_middle/src/ty/generics.rs @@ -103,7 +103,7 @@ impl GenericParamDef { ty::GenericParamDefKind::Lifetime => tcx.mk_re_error_misc().into(), ty::GenericParamDefKind::Type { .. } => tcx.ty_error_misc().into(), ty::GenericParamDefKind::Const { .. } => { - tcx.const_error(tcx.type_of(self.def_id).subst(tcx, preceding_substs)).into() + tcx.const_error_misc(tcx.type_of(self.def_id).subst(tcx, preceding_substs)).into() } } } diff --git a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs index 9e672004cf9..4223502848e 100644 --- a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs +++ b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs @@ -43,6 +43,7 @@ //! This code should only compile in modules where the uninhabitedness of `Foo` //! is visible. +use crate::query::Providers; use crate::ty::context::TyCtxt; use crate::ty::{self, DefId, Ty, VariantDef, Visibility}; @@ -52,9 +53,8 @@ pub mod inhabited_predicate; pub use inhabited_predicate::InhabitedPredicate; -pub(crate) fn provide(providers: &mut ty::query::Providers) { - *providers = - ty::query::Providers { inhabited_predicate_adt, inhabited_predicate_type, ..*providers }; +pub(crate) fn provide(providers: &mut Providers) { + *providers = Providers { inhabited_predicate_adt, inhabited_predicate_type, ..*providers }; } /// Returns an `InhabitedPredicate` that is generic over type parameters and diff --git a/compiler/rustc_middle/src/ty/list.rs b/compiler/rustc_middle/src/ty/list.rs index 30f036e471c..71911a5a618 100644 --- a/compiler/rustc_middle/src/ty/list.rs +++ b/compiler/rustc_middle/src/ty/list.rs @@ -199,6 +199,12 @@ impl<'a, T: Copy> IntoIterator for &'a List<T> { unsafe impl<T: Sync> Sync for List<T> {} +// We need this since `List` uses extern type `OpaqueListContents`. +#[cfg(parallel_compiler)] +use rustc_data_structures::sync::DynSync; +#[cfg(parallel_compiler)] +unsafe impl<T: DynSync> DynSync for List<T> {} + // Safety: // Layouts of `Equivalent<T>` and `List<T>` are the same, modulo opaque tail, // thus aligns of `Equivalent<T>` and `List<T>` must be the same. diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index f882f54d628..df324bcc52c 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -21,6 +21,7 @@ use crate::error::{OpaqueHiddenTypeMismatch, TypeMismatchReason}; use crate::metadata::ModChild; use crate::middle::privacy::EffectiveVisibilities; use crate::mir::{Body, GeneratorLayout}; +use crate::query::Providers; use crate::traits::{self, Reveal}; use crate::ty; use crate::ty::fast_reject::SimplifiedType; @@ -121,6 +122,7 @@ pub mod inhabitedness; pub mod layout; pub mod normalize_erasing_regions; pub mod print; +#[macro_use] pub mod query; pub mod relate; pub mod subst; @@ -1070,6 +1072,24 @@ impl ParamTerm { } } +#[derive(Copy, Clone, Eq, PartialEq, Debug)] +pub enum TermVid<'tcx> { + Ty(ty::TyVid), + Const(ty::ConstVid<'tcx>), +} + +impl From<ty::TyVid> for TermVid<'_> { + fn from(value: ty::TyVid) -> Self { + TermVid::Ty(value) + } +} + +impl<'tcx> From<ty::ConstVid<'tcx>> for TermVid<'tcx> { + fn from(value: ty::ConstVid<'tcx>) -> Self { + TermVid::Const(value) + } +} + /// This kind of predicate has no *direct* correspondent in the /// syntax, but it roughly corresponds to the syntactic forms: /// @@ -2476,6 +2496,18 @@ impl<'tcx> TyCtxt<'tcx> { } } + /// Returns the `DefId` of the item within which the `impl Trait` is declared. + /// For type-alias-impl-trait this is the `type` alias. + /// For impl-trait-in-assoc-type this is the assoc type. + /// For return-position-impl-trait this is the function. + pub fn impl_trait_parent(self, mut def_id: LocalDefId) -> LocalDefId { + // Find the surrounding item (type alias or assoc type) + while let DefKind::OpaqueTy = self.def_kind(def_id) { + def_id = self.local_parent(def_id); + } + def_id + } + pub fn impl_method_has_trait_impl_trait_tys(self, def_id: DefId) -> bool { if self.def_kind(def_id) != DefKind::AssocFn { return false; @@ -2520,7 +2552,7 @@ pub fn is_impl_trait_defn(tcx: TyCtxt<'_>, def_id: DefId) -> Option<LocalDefId> hir::OpaqueTyOrigin::FnReturn(parent) | hir::OpaqueTyOrigin::AsyncFn(parent) => { Some(parent) } - hir::OpaqueTyOrigin::TyAlias => None, + hir::OpaqueTyOrigin::TyAlias { .. } => None, }; } } @@ -2578,7 +2610,7 @@ pub fn ast_uint_ty(uty: UintTy) -> ast::UintTy { } } -pub fn provide(providers: &mut ty::query::Providers) { +pub fn provide(providers: &mut Providers) { closure::provide(providers); context::provide(providers); erase_regions::provide(providers); @@ -2587,7 +2619,7 @@ pub fn provide(providers: &mut ty::query::Providers) { print::provide(providers); super::util::bug::provide(providers); super::middle::provide(providers); - *providers = ty::query::Providers { + *providers = Providers { trait_impls_of: trait_def::trait_impls_of_provider, incoherent_impls: trait_def::incoherent_impls_provider, const_param_default: consts::const_param_default, diff --git a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs index 9332b0430ff..a0c8d299f48 100644 --- a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs +++ b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs @@ -32,7 +32,7 @@ impl<'tcx> TyCtxt<'tcx> { /// /// This should only be used outside of type inference. For example, /// it assumes that normalization will succeed. - #[tracing::instrument(level = "debug", skip(self, param_env))] + #[tracing::instrument(level = "debug", skip(self, param_env), ret)] pub fn normalize_erasing_regions<T>(self, param_env: ty::ParamEnv<'tcx>, value: T) -> T where T: TypeFoldable<TyCtxt<'tcx>>, diff --git a/compiler/rustc_middle/src/ty/opaque_types.rs b/compiler/rustc_middle/src/ty/opaque_types.rs index 72710b78c93..1b336b7bfc6 100644 --- a/compiler/rustc_middle/src/ty/opaque_types.rs +++ b/compiler/rustc_middle/src/ty/opaque_types.rs @@ -207,14 +207,16 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ReverseMapper<'tcx> { Some(GenericArgKind::Const(c1)) => c1, Some(u) => panic!("const mapped to unexpected kind: {:?}", u), None => { - if !self.ignore_errors { - self.tcx.sess.emit_err(ConstNotUsedTraitAlias { + let guar = self + .tcx + .sess + .create_err(ConstNotUsedTraitAlias { ct: ct.to_string(), span: self.span, - }); - } + }) + .emit_unless(self.ignore_errors); - self.interner().const_error(ct.ty()) + self.interner().const_error(ct.ty(), guar) } } } diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 926172ff828..385156262c7 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -1,4 +1,5 @@ use crate::mir::interpret::{AllocRange, GlobalAlloc, Pointer, Provenance, Scalar}; +use crate::query::Providers; use crate::ty::query::IntoQueryParam; use crate::ty::{ self, ConstInt, ParamConst, ScalarInt, Term, TermKind, Ty, TyCtxt, TypeFoldable, @@ -3054,8 +3055,8 @@ fn trimmed_def_paths(tcx: TyCtxt<'_>, (): ()) -> FxHashMap<DefId, Symbol> { map } -pub fn provide(providers: &mut ty::query::Providers) { - *providers = ty::query::Providers { trimmed_def_paths, ..*providers }; +pub fn provide(providers: &mut Providers) { + *providers = Providers { trimmed_def_paths, ..*providers }; } #[derive(Default)] diff --git a/compiler/rustc_middle/src/ty/query.rs b/compiler/rustc_middle/src/ty/query.rs index 07d47cae5ee..647f4826876 100644 --- a/compiler/rustc_middle/src/ty/query.rs +++ b/compiler/rustc_middle/src/ty/query.rs @@ -1,89 +1,26 @@ -#![allow(unused_parens)] - use crate::dep_graph; use crate::dep_graph::DepKind; -use crate::infer::canonical::{self, Canonical}; -use crate::lint::LintExpectation; -use crate::metadata::ModChild; -use crate::middle::codegen_fn_attrs::CodegenFnAttrs; -use crate::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo}; -use crate::middle::lib_features::LibFeatures; -use crate::middle::privacy::EffectiveVisibilities; -use crate::middle::resolve_bound_vars::{ObjectLifetimeDefault, ResolveBoundVars, ResolvedArg}; -use crate::middle::stability::{self, DeprecationEntry}; -use crate::mir; -use crate::mir::interpret::GlobalId; -use crate::mir::interpret::{ - ConstValue, EvalToAllocationRawResult, EvalToConstValueResult, EvalToValTreeResult, -}; -use crate::mir::interpret::{LitToConstError, LitToConstInput}; -use crate::mir::mono::CodegenUnit; - -use crate::query::erase::{erase, restore, Erase}; use crate::query::on_disk_cache::CacheEncoder; use crate::query::on_disk_cache::EncodedDepNodeIndex; use crate::query::on_disk_cache::OnDiskCache; -use crate::query::{AsLocalKey, Key}; -use crate::thir; -use crate::traits::query::{ - CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTyGoal, - CanonicalTypeOpAscribeUserTypeGoal, CanonicalTypeOpEqGoal, CanonicalTypeOpNormalizeGoal, - CanonicalTypeOpProvePredicateGoal, CanonicalTypeOpSubtypeGoal, NoSolution, +use crate::query::{ + DynamicQueries, ExternProviders, Providers, QueryArenas, QueryCaches, QueryEngine, QueryStates, }; -use crate::traits::query::{ - DropckConstraint, DropckOutlivesResult, MethodAutoderefStepsResult, NormalizationResult, - OutlivesBound, -}; -use crate::traits::specialization_graph; -use crate::traits::{self, ImplSource}; -use crate::ty::context::TyCtxtFeed; -use crate::ty::fast_reject::SimplifiedType; -use crate::ty::layout::ValidityRequirement; -use crate::ty::subst::{GenericArg, SubstsRef}; -use crate::ty::util::AlwaysRequiresDrop; -use crate::ty::GeneratorDiagnosticData; -use crate::ty::{self, CrateInherentImpls, ParamEnvAnd, Ty, TyCtxt, UnusedGenericParams}; +use crate::ty::TyCtxt; +use field_offset::FieldOffset; use measureme::StringId; -use rustc_arena::TypedArena; -use rustc_ast as ast; -use rustc_ast::expand::allocator::AllocatorKind; -use rustc_attr as attr; -use rustc_data_structures::fingerprint::Fingerprint; -use rustc_data_structures::fx::{FxHashMap, FxIndexMap, FxIndexSet}; -use rustc_data_structures::steal::Steal; -use rustc_data_structures::svh::Svh; +use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync::AtomicU64; -use rustc_data_structures::sync::Lrc; -use rustc_data_structures::sync::WorkerLocal; -use rustc_data_structures::unord::UnordSet; -use rustc_errors::ErrorGuaranteed; -use rustc_hir as hir; -use rustc_hir::def::{DefKind, DocLinkResMap}; -use rustc_hir::def_id::{ - CrateNum, DefId, DefIdMap, DefIdSet, LocalDefId, LocalDefIdMap, LocalDefIdSet, -}; +use rustc_hir::def::DefKind; +use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::hir_id::OwnerId; -use rustc_hir::lang_items::{LangItem, LanguageItems}; -use rustc_hir::{Crate, ItemLocalId, TraitCandidate}; -use rustc_index::IndexVec; -use rustc_query_system::ich::StableHashingContext; +use rustc_query_system::dep_graph::DepNodeIndex; +use rustc_query_system::dep_graph::SerializedDepNodeIndex; pub(crate) use rustc_query_system::query::QueryJobId; use rustc_query_system::query::*; -use rustc_session::config::{EntryFnType, OptLevel, OutputFilenames, SymbolManglingVersion}; -use rustc_session::cstore::{CrateDepKind, CrateSource}; -use rustc_session::cstore::{ExternCrate, ForeignModule, LinkagePreference, NativeLib}; -use rustc_session::lint::LintExpectationId; -use rustc_session::Limits; -use rustc_span::symbol::Symbol; +use rustc_query_system::HandleCycleError; use rustc_span::{Span, DUMMY_SP}; -use rustc_target::abi; -use rustc_target::spec::PanicStrategy; - -use std::marker::PhantomData; -use std::mem; use std::ops::Deref; -use std::path::PathBuf; -use std::sync::Arc; pub struct QueryKeyStringCache { pub def_id_cache: FxHashMap<DefId, StringId>, @@ -103,6 +40,31 @@ pub struct QueryStruct<'tcx> { Option<fn(TyCtxt<'tcx>, &mut CacheEncoder<'_, 'tcx>, &mut EncodedDepNodeIndex)>, } +pub struct DynamicQuery<'tcx, C: QueryCache> { + pub name: &'static str, + pub eval_always: bool, + pub dep_kind: rustc_middle::dep_graph::DepKind, + pub handle_cycle_error: HandleCycleError, + pub query_state: FieldOffset<QueryStates<'tcx>, QueryState<C::Key, crate::dep_graph::DepKind>>, + pub query_cache: FieldOffset<QueryCaches<'tcx>, C>, + pub cache_on_disk: fn(tcx: TyCtxt<'tcx>, key: &C::Key) -> bool, + pub execute_query: fn(tcx: TyCtxt<'tcx>, k: C::Key) -> C::Value, + pub compute: fn(tcx: TyCtxt<'tcx>, key: C::Key) -> C::Value, + pub can_load_from_disk: bool, + pub try_load_from_disk: fn( + tcx: TyCtxt<'tcx>, + key: &C::Key, + prev_index: SerializedDepNodeIndex, + index: DepNodeIndex, + ) -> Option<C::Value>, + pub loadable_from_disk: + fn(tcx: TyCtxt<'tcx>, key: &C::Key, index: SerializedDepNodeIndex) -> bool, + pub hash_result: HashResult<C::Value>, + pub value_from_cycle_error: + fn(tcx: TyCtxt<'tcx>, cycle: &[QueryInfo<crate::dep_graph::DepKind>]) -> C::Value, + pub format_value: fn(&C::Value) -> String, +} + pub struct QuerySystemFns<'tcx> { pub engine: QueryEngine, pub local_providers: Providers, @@ -120,6 +82,7 @@ pub struct QuerySystem<'tcx> { pub states: QueryStates<'tcx>, pub arenas: QueryArenas<'tcx>, pub caches: QueryCaches<'tcx>, + pub dynamic_queries: DynamicQueries<'tcx>, /// This provides access to the incremental compilation on-disk cache for query results. /// Do not access this directly. It is only meant to be used by @@ -130,23 +93,6 @@ pub struct QuerySystem<'tcx> { pub fns: QuerySystemFns<'tcx>, pub jobs: AtomicU64, - - // Since we erase query value types we tell the typesystem about them with `PhantomData`. - _phantom_values: QueryPhantomValues<'tcx>, -} - -impl<'tcx> QuerySystem<'tcx> { - pub fn new(fns: QuerySystemFns<'tcx>, on_disk_cache: Option<OnDiskCache<'tcx>>) -> Self { - QuerySystem { - states: Default::default(), - arenas: Default::default(), - caches: Default::default(), - on_disk_cache, - fns, - jobs: AtomicU64::new(1), - _phantom_values: Default::default(), - } - } } #[derive(Copy, Clone)] @@ -203,7 +149,7 @@ impl<'tcx> TyCtxt<'tcx> { } #[inline] -fn query_get_at<'tcx, Cache>( +pub fn query_get_at<'tcx, Cache>( tcx: TyCtxt<'tcx>, execute_query: fn(TyCtxt<'tcx>, Span, Cache::Key, QueryMode) -> Option<Cache::Value>, query_cache: &Cache, @@ -221,7 +167,7 @@ where } #[inline] -fn query_ensure<'tcx, Cache>( +pub fn query_ensure<'tcx, Cache>( tcx: TyCtxt<'tcx>, execute_query: fn(TyCtxt<'tcx>, Span, Cache::Key, QueryMode) -> Option<Cache::Value>, query_cache: &Cache, @@ -428,11 +374,6 @@ macro_rules! define_callbacks { } #[derive(Default)] - pub struct QueryPhantomValues<'tcx> { - $($(#[$attr])* pub $name: PhantomData<query_values::$name<'tcx>>,)* - } - - #[derive(Default)] pub struct QueryCaches<'tcx> { $($(#[$attr])* pub $name: query_storage::$name<'tcx>,)* } @@ -490,6 +431,12 @@ macro_rules! define_callbacks { })* } + pub struct DynamicQueries<'tcx> { + $( + pub $name: DynamicQuery<'tcx, query_storage::$name<'tcx>>, + )* + } + #[derive(Default)] pub struct QueryStates<'tcx> { $( @@ -627,9 +574,6 @@ macro_rules! define_feedable { // Queries marked with `fatal_cycle` do not need the latter implementation, // as they will raise an fatal error on query cycles instead. -rustc_query_append! { define_callbacks! } -rustc_feedable_queries! { define_feedable! } - mod sealed { use super::{DefId, LocalDefId, OwnerId}; diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs index da43475941e..3bbe6a23b66 100644 --- a/compiler/rustc_middle/src/ty/relate.rs +++ b/compiler/rustc_middle/src/ty/relate.rs @@ -388,24 +388,24 @@ impl<'tcx> Relate<'tcx> for Ty<'tcx> { } } -/// The main "type relation" routine. Note that this does not handle -/// inference artifacts, so you should filter those out before calling -/// it. -pub fn super_relate_tys<'tcx, R: TypeRelation<'tcx>>( +/// Relates `a` and `b` structurally, calling the relation for all nested values. +/// Any semantic equality, e.g. of projections, and inference variables have to be +/// handled by the caller. +pub fn structurally_relate_tys<'tcx, R: TypeRelation<'tcx>>( relation: &mut R, a: Ty<'tcx>, b: Ty<'tcx>, ) -> RelateResult<'tcx, Ty<'tcx>> { let tcx = relation.tcx(); - debug!("super_relate_tys: a={:?} b={:?}", a, b); + debug!("structurally_relate_tys: a={:?} b={:?}", a, b); match (a.kind(), b.kind()) { (&ty::Infer(_), _) | (_, &ty::Infer(_)) => { // The caller should handle these cases! - bug!("var types encountered in super_relate_tys") + bug!("var types encountered in structurally_relate_tys") } (ty::Bound(..), _) | (_, ty::Bound(..)) => { - bug!("bound types encountered in super_relate_tys") + bug!("bound types encountered in structurally_relate_tys") } (&ty::Error(guar), _) | (_, &ty::Error(guar)) => Ok(tcx.ty_error(guar)), @@ -575,15 +575,18 @@ pub fn super_relate_tys<'tcx, R: TypeRelation<'tcx>>( } } -/// The main "const relation" routine. Note that this does not handle -/// inference artifacts, so you should filter those out before calling -/// it. -pub fn super_relate_consts<'tcx, R: TypeRelation<'tcx>>( +/// Relates `a` and `b` structurally, calling the relation for all nested values. +/// Any semantic equality, e.g. of unevaluated consts, and inference variables have +/// to be handled by the caller. +/// +/// FIXME: This is not totally structual, which probably should be fixed. +/// See the HACKs below. +pub fn structurally_relate_consts<'tcx, R: TypeRelation<'tcx>>( relation: &mut R, mut a: ty::Const<'tcx>, mut b: ty::Const<'tcx>, ) -> RelateResult<'tcx, ty::Const<'tcx>> { - debug!("{}.super_relate_consts(a = {:?}, b = {:?})", relation.tag(), a, b); + debug!("{}.structurally_relate_consts(a = {:?}, b = {:?})", relation.tag(), a, b); let tcx = relation.tcx(); // HACK(const_generics): We still need to eagerly evaluate consts when @@ -602,7 +605,7 @@ pub fn super_relate_consts<'tcx, R: TypeRelation<'tcx>>( b = tcx.expand_abstract_consts(b); } - debug!("{}.super_relate_consts(normed_a = {:?}, normed_b = {:?})", relation.tag(), a, b); + debug!("{}.structurally_relate_consts(normed_a = {:?}, normed_b = {:?})", relation.tag(), a, b); // Currently, the values that can be unified are primitive types, // and those that derive both `PartialEq` and `Eq`, corresponding @@ -610,7 +613,7 @@ pub fn super_relate_consts<'tcx, R: TypeRelation<'tcx>>( let is_match = match (a.kind(), b.kind()) { (ty::ConstKind::Infer(_), _) | (_, ty::ConstKind::Infer(_)) => { // The caller should handle these cases! - bug!("var types encountered in super_relate_consts: {:?} {:?}", a, b) + bug!("var types encountered in structurally_relate_consts: {:?} {:?}", a, b) } (ty::ConstKind::Error(_), _) => return Ok(a), diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 29a3bc8bb97..e73208b877f 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -204,6 +204,7 @@ CloneLiftImpls! { (), bool, usize, + u8, u16, u32, u64, diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 8d0737e1eee..e6d51c4ec97 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -1265,7 +1265,7 @@ impl<'tcx> AliasTy<'tcx> { /// Extracts the underlying trait reference and own substs from this projection. /// For example, if this is a projection of `<T as StreamingIterator>::Item<'a>`, - /// then this function would return a `T: Iterator` trait reference and `['a]` as the own substs + /// then this function would return a `T: StreamingIterator` trait reference and `['a]` as the own substs pub fn trait_ref_and_own_substs( self, tcx: TyCtxt<'tcx>, @@ -1708,7 +1708,9 @@ impl<'tcx> Region<'tcx> { ty::ReErased => { flags = flags | TypeFlags::HAS_RE_ERASED; } - ty::ReError(_) => {} + ty::ReError(_) => { + flags = flags | TypeFlags::HAS_FREE_REGIONS; + } } debug!("type_flags({:?}) = {:?}", self, flags); @@ -2366,13 +2368,11 @@ impl<'tcx> Ty<'tcx> { ty::Adt(def, _substs) => def.sized_constraint(tcx).0.is_empty(), - ty::Alias(..) | ty::Param(_) => false, + ty::Alias(..) | ty::Param(_) | ty::Placeholder(..) => false, ty::Infer(ty::TyVar(_)) => false, - ty::Bound(..) - | ty::Placeholder(..) - | ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => { + ty::Bound(..) | ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => { bug!("`is_trivially_sized` applied to unexpected type: {:?}", self) } } diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index e5b2d342452..eb903ebfd99 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -2,6 +2,7 @@ use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags; use crate::mir; +use crate::query::Providers; use crate::ty::layout::IntegerExt; use crate::ty::{ self, FallibleTypeFolder, ToPredicate, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, @@ -34,9 +35,14 @@ pub struct Discr<'tcx> { /// Used as an input to [`TyCtxt::uses_unique_generic_params`]. #[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub enum IgnoreRegions { - Yes, +pub enum CheckRegions { No, + /// Only permit early bound regions. This is useful for Adts which + /// can never have late bound regions. + OnlyEarlyBound, + /// Permit both late bound and early bound regions. Use this for functions, + /// which frequently have late bound regions. + Bound, } #[derive(Copy, Clone, Debug)] @@ -468,21 +474,28 @@ impl<'tcx> TyCtxt<'tcx> { pub fn uses_unique_generic_params( self, substs: SubstsRef<'tcx>, - ignore_regions: IgnoreRegions, + ignore_regions: CheckRegions, ) -> Result<(), NotUniqueParam<'tcx>> { let mut seen = GrowableBitSet::default(); + let mut seen_late = FxHashSet::default(); for arg in substs { match arg.unpack() { - GenericArgKind::Lifetime(lt) => { - if ignore_regions == IgnoreRegions::No { - let ty::ReEarlyBound(p) = lt.kind() else { - return Err(NotUniqueParam::NotParam(lt.into())) - }; + GenericArgKind::Lifetime(lt) => match (ignore_regions, lt.kind()) { + (CheckRegions::Bound, ty::ReLateBound(di, reg)) => { + if !seen_late.insert((di, reg)) { + return Err(NotUniqueParam::DuplicateParam(lt.into())); + } + } + (CheckRegions::OnlyEarlyBound | CheckRegions::Bound, ty::ReEarlyBound(p)) => { if !seen.insert(p.index) { return Err(NotUniqueParam::DuplicateParam(lt.into())); } } - } + (CheckRegions::OnlyEarlyBound | CheckRegions::Bound, _) => { + return Err(NotUniqueParam::NotParam(lt.into())); + } + (CheckRegions::No, _) => {} + }, GenericArgKind::Type(t) => match t.kind() { ty::Param(p) => { if !seen.insert(p.index) { @@ -655,10 +668,10 @@ impl<'tcx> TyCtxt<'tcx> { self, def_id: DefId, ) -> impl Iterator<Item = ty::EarlyBinder<Ty<'tcx>>> { - let generator_layout = &self.mir_generator_witnesses(def_id); + let generator_layout = self.mir_generator_witnesses(def_id); generator_layout - .field_tys - .iter() + .as_ref() + .map_or_else(|| [].iter(), |l| l.field_tys.iter()) .filter(|decl| !decl.ignore_for_traits) .map(|decl| ty::EarlyBinder(decl.ty)) } @@ -1253,7 +1266,7 @@ pub enum ExplicitSelf<'tcx> { impl<'tcx> ExplicitSelf<'tcx> { /// Categorizes an explicit self declaration like `self: SomeType` - /// into either `self`, `&self`, `&mut self`, `Box<self>`, or + /// into either `self`, `&self`, `&mut self`, `Box<Self>`, or /// `Other`. /// This is mainly used to require the arbitrary_self_types feature /// in the case of `Other`, to improve error messages in the common cases, @@ -1472,8 +1485,8 @@ pub fn is_intrinsic(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { matches!(tcx.fn_sig(def_id).skip_binder().abi(), Abi::RustIntrinsic | Abi::PlatformIntrinsic) } -pub fn provide(providers: &mut ty::query::Providers) { - *providers = ty::query::Providers { +pub fn provide(providers: &mut Providers) { + *providers = Providers { reveal_opaque_types_in_bounds, is_doc_hidden, is_doc_notable_trait, diff --git a/compiler/rustc_middle/src/util/bug.rs b/compiler/rustc_middle/src/util/bug.rs index 3dfd0824f98..43ee0343f5a 100644 --- a/compiler/rustc_middle/src/util/bug.rs +++ b/compiler/rustc_middle/src/util/bug.rs @@ -48,6 +48,6 @@ pub fn trigger_delay_span_bug(tcx: TyCtxt<'_>, key: rustc_hir::def_id::DefId) { ); } -pub fn provide(providers: &mut crate::ty::query::Providers) { - *providers = crate::ty::query::Providers { trigger_delay_span_bug, ..*providers }; +pub fn provide(providers: &mut crate::query::Providers) { + *providers = crate::query::Providers { trigger_delay_span_bug, ..*providers }; } diff --git a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs index 931fe1b2433..b74422708ce 100644 --- a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs +++ b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs @@ -154,6 +154,7 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> { Ok(Rvalue::BinaryOp(BinOp::Offset, Box::new((ptr, offset)))) }, @call("mir_len", args) => Ok(Rvalue::Len(self.parse_place(args[0])?)), + @call("mir_copy_for_deref", args) => Ok(Rvalue::CopyForDeref(self.parse_place(args[0])?)), ExprKind::Borrow { borrow_kind, arg } => Ok( Rvalue::Ref(self.tcx.lifetimes.re_erased, *borrow_kind, self.parse_place(*arg)?) ), diff --git a/compiler/rustc_mir_build/src/build/expr/as_constant.rs b/compiler/rustc_mir_build/src/build/expr/as_constant.rs index 59549435233..4d99ab4b0ec 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_constant.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_constant.rs @@ -52,7 +52,7 @@ pub fn as_constant_inner<'tcx>( match lit_to_mir_constant(tcx, LitToConstInput { lit: &lit.node, ty, neg }) { Ok(c) => c, Err(LitToConstError::Reported(guar)) => { - ConstantKind::Ty(tcx.const_error_with_guaranteed(ty, guar)) + ConstantKind::Ty(tcx.const_error(ty, guar)) } Err(LitToConstError::TypeError) => { bug!("encountered type error in `lit_to_mir_constant`") diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 4926ff85de3..6df06df5c60 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -2241,6 +2241,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.var_debug_info.push(VarDebugInfo { name, source_info: debug_source_info, + references: 0, value: VarDebugInfoContents::Place(for_arm_body.into()), argument_index: None, }); @@ -2260,6 +2261,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.var_debug_info.push(VarDebugInfo { name, source_info: debug_source_info, + references: 0, value: VarDebugInfoContents::Place(ref_for_guard.into()), argument_index: None, }); diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs index 4536ecf17b8..dbdb5b4a9a1 100644 --- a/compiler/rustc_mir_build/src/build/matches/test.rs +++ b/compiler/rustc_mir_build/src/build/matches/test.rs @@ -380,18 +380,19 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ); } - /// Compare two `&T` values using `<T as std::compare::PartialEq>::eq` + /// Compare two values using `<T as std::compare::PartialEq>::eq`. + /// If the values are already references, just call it directly, otherwise + /// take a reference to the values first and then call it. fn non_scalar_compare( &mut self, block: BasicBlock, make_target_blocks: impl FnOnce(&mut Self) -> Vec<BasicBlock>, source_info: SourceInfo, value: ConstantKind<'tcx>, - place: Place<'tcx>, + mut val: Place<'tcx>, mut ty: Ty<'tcx>, ) { let mut expect = self.literal_operand(source_info.span, value); - let mut val = Operand::Copy(place); // If we're using `b"..."` as a pattern, we need to insert an // unsizing coercion, as the byte string has the type `&[u8; N]`. @@ -421,9 +422,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block, source_info, temp, - Rvalue::Cast(CastKind::Pointer(PointerCast::Unsize), val, ty), + Rvalue::Cast( + CastKind::Pointer(PointerCast::Unsize), + Operand::Copy(val), + ty, + ), ); - val = Operand::Move(temp); + val = temp; } if opt_ref_test_ty.is_some() { let slice = self.temp(ty, source_info.span); @@ -438,12 +443,36 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } - let ty::Ref(_, deref_ty, _) = *ty.kind() else { - bug!("non_scalar_compare called on non-reference type: {}", ty); - }; + match *ty.kind() { + ty::Ref(_, deref_ty, _) => ty = deref_ty, + _ => { + // non_scalar_compare called on non-reference type + let temp = self.temp(ty, source_info.span); + self.cfg.push_assign(block, source_info, temp, Rvalue::Use(expect)); + let ref_ty = self.tcx.mk_imm_ref(self.tcx.lifetimes.re_erased, ty); + let ref_temp = self.temp(ref_ty, source_info.span); + + self.cfg.push_assign( + block, + source_info, + ref_temp, + Rvalue::Ref(self.tcx.lifetimes.re_erased, BorrowKind::Shared, temp), + ); + expect = Operand::Move(ref_temp); + + let ref_temp = self.temp(ref_ty, source_info.span); + self.cfg.push_assign( + block, + source_info, + ref_temp, + Rvalue::Ref(self.tcx.lifetimes.re_erased, BorrowKind::Shared, val), + ); + val = ref_temp; + } + } let eq_def_id = self.tcx.require_lang_item(LangItem::PartialEq, Some(source_info.span)); - let method = trait_method(self.tcx, eq_def_id, sym::eq, [deref_ty, deref_ty]); + let method = trait_method(self.tcx, eq_def_id, sym::eq, [ty, ty]); let bool_ty = self.tcx.types.bool; let eq_result = self.temp(bool_ty, source_info.span); @@ -463,7 +492,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { literal: method, })), - args: vec![val, expect], + args: vec![Operand::Copy(val), expect], destination: eq_result, target: Some(eq_block), unwind: UnwindAction::Continue, diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs index 3f006765a71..4e3e98b56e7 100644 --- a/compiler/rustc_mir_build/src/build/mod.rs +++ b/compiler/rustc_mir_build/src/build/mod.rs @@ -42,7 +42,9 @@ fn mir_build(tcx: TyCtxt<'_>, def: LocalDefId) -> Body<'_> { // Ensure unsafeck and abstract const building is ran before we steal the THIR. tcx.ensure_with_value().thir_check_unsafety(def); tcx.ensure_with_value().thir_abstract_const(def); - tcx.ensure_with_value().check_match(def); + if let Err(e) = tcx.check_match(def) { + return construct_error(tcx, def, e); + } let body = match tcx.thir_body(def) { Err(error_reported) => construct_error(tcx, def, error_reported), @@ -796,6 +798,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { }; self.var_debug_info.push(VarDebugInfo { name, + references: 0, source_info: SourceInfo::outermost(captured_place.var_ident.span), value: VarDebugInfoContents::Place(use_place), argument_index: None, @@ -826,6 +829,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.var_debug_info.push(VarDebugInfo { name, source_info, + references: 0, value: VarDebugInfoContents::Place(arg_local.into()), argument_index: Some(argument_index as u16 + 1), }); diff --git a/compiler/rustc_mir_build/src/lib.rs b/compiler/rustc_mir_build/src/lib.rs index 2765a107cf0..c964e62c9d0 100644 --- a/compiler/rustc_mir_build/src/lib.rs +++ b/compiler/rustc_mir_build/src/lib.rs @@ -22,7 +22,7 @@ mod errors; mod lints; pub mod thir; -use rustc_middle::ty::query::Providers; +use rustc_middle::query::Providers; use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage}; use rustc_fluent_macro::fluent_messages; diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index 8cb3b00c9ad..ca25f83e643 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -26,8 +26,8 @@ use rustc_session::Session; use rustc_span::hygiene::DesugaringKind; use rustc_span::Span; -pub(crate) fn check_match(tcx: TyCtxt<'_>, def_id: LocalDefId) { - let Ok((thir, expr)) = tcx.thir_body(def_id) else { return }; +pub(crate) fn check_match(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(), ErrorGuaranteed> { + let (thir, expr) = tcx.thir_body(def_id)?; let thir = thir.borrow(); let pattern_arena = TypedArena::default(); let mut visitor = MatchVisitor { @@ -37,13 +37,16 @@ pub(crate) fn check_match(tcx: TyCtxt<'_>, def_id: LocalDefId) { lint_level: tcx.hir().local_def_id_to_hir_id(def_id), let_source: LetSource::None, pattern_arena: &pattern_arena, + error: Ok(()), }; visitor.visit_expr(&thir[expr]); + for param in thir.params.iter() { if let Some(box ref pattern) = param.pat { visitor.check_irrefutable(pattern, "function argument", None); } } + visitor.error } fn create_e0004( @@ -77,6 +80,7 @@ struct MatchVisitor<'a, 'p, 'tcx> { lint_level: HirId, let_source: LetSource, pattern_arena: &'p TypedArena<DeconstructedPat<'p, 'tcx>>, + error: Result<(), ErrorGuaranteed>, } impl<'a, 'tcx> Visitor<'a, 'tcx> for MatchVisitor<'a, '_, 'tcx> { @@ -276,9 +280,9 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> { let [pat_field] = &subpatterns[..] else { bug!() }; self.check_irrefutable(&pat_field.pattern, "`for` loop binding", None); } else { - non_exhaustive_match( + self.error = Err(non_exhaustive_match( &cx, self.thir, scrut_ty, scrut.span, witnesses, arms, expr_span, - ); + )); } } } @@ -406,7 +410,7 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> { } #[instrument(level = "trace", skip(self))] - fn check_irrefutable(&self, pat: &Pat<'tcx>, origin: &str, sp: Option<Span>) { + fn check_irrefutable(&mut self, pat: &Pat<'tcx>, origin: &str, sp: Option<Span>) { let mut cx = self.new_cx(self.lint_level, false); let pattern = self.lower_pattern(&mut cx, pat); @@ -475,7 +479,7 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> { AdtDefinedHere { adt_def_span, ty, variants } }; - self.tcx.sess.emit_err(PatternNotCovered { + self.error = Err(self.tcx.sess.emit_err(PatternNotCovered { span: pat.span, origin, uncovered: Uncovered::new(pat.span, &cx, witnesses), @@ -486,7 +490,7 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> { let_suggestion, misc_suggestion, adt_defined_here, - }); + })); } } @@ -628,7 +632,7 @@ fn non_exhaustive_match<'p, 'tcx>( witnesses: Vec<DeconstructedPat<'p, 'tcx>>, arms: &[ArmId], expr_span: Span, -) { +) -> ErrorGuaranteed { let is_empty_match = arms.is_empty(); let non_empty_enum = match scrut_ty.kind() { ty::Adt(def, _) => def.is_enum() && !def.variants().is_empty(), @@ -640,13 +644,12 @@ fn non_exhaustive_match<'p, 'tcx>( let pattern; let patterns_len; if is_empty_match && !non_empty_enum { - cx.tcx.sess.emit_err(NonExhaustivePatternsTypeNotEmpty { + return cx.tcx.sess.emit_err(NonExhaustivePatternsTypeNotEmpty { cx, expr_span, span: sp, ty: scrut_ty, }); - return; } else { // FIXME: migration of this diagnostic will require list support let joined_patterns = joined_uncovered_patterns(cx, &witnesses); @@ -797,7 +800,7 @@ fn non_exhaustive_match<'p, 'tcx>( } else { err.help(msg); } - err.emit(); + err.emit() } pub(crate) fn joined_uncovered_patterns<'p, 'tcx>( 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 c73f8284ca5..b243f1dc8d0 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 @@ -62,21 +62,13 @@ struct ConstToPat<'tcx> { treat_byte_string_as_slice: bool, } -mod fallback_to_const_ref { - #[derive(Debug)] - /// This error type signals that we encountered a non-struct-eq situation behind a reference. - /// We bubble this up in order to get back to the reference destructuring and make that emit - /// a const pattern instead of a deref pattern. This allows us to simply call `PartialEq::eq` - /// on such patterns (since that function takes a reference) and not have to jump through any - /// hoops to get a reference to the value. - pub(super) struct FallbackToConstRef(()); - - pub(super) fn fallback_to_const_ref(c2p: &super::ConstToPat<'_>) -> FallbackToConstRef { - assert!(c2p.behind_reference.get()); - FallbackToConstRef(()) - } -} -use fallback_to_const_ref::{fallback_to_const_ref, FallbackToConstRef}; +/// This error type signals that we encountered a non-struct-eq situation. +/// We bubble this up in order to get back to the reference destructuring and make that emit +/// a const pattern instead of a deref pattern. This allows us to simply call `PartialEq::eq` +/// on such patterns (since that function takes a reference) and not have to jump through any +/// hoops to get a reference to the value. +#[derive(Debug)] +struct FallbackToConstRef; impl<'tcx> ConstToPat<'tcx> { fn new( @@ -236,13 +228,13 @@ impl<'tcx> ConstToPat<'tcx> { let kind = match cv.ty().kind() { ty::Float(_) => { - tcx.emit_spanned_lint( - lint::builtin::ILLEGAL_FLOATING_POINT_LITERAL_PATTERN, - id, - span, - FloatPattern, - ); - PatKind::Constant { value: cv } + tcx.emit_spanned_lint( + lint::builtin::ILLEGAL_FLOATING_POINT_LITERAL_PATTERN, + id, + span, + FloatPattern, + ); + return Err(FallbackToConstRef); } ty::Adt(adt_def, _) if adt_def.is_union() => { // Matching on union fields is unsafe, we can't hide it in constants @@ -289,7 +281,7 @@ impl<'tcx> ConstToPat<'tcx> { // Since we are behind a reference, we can just bubble the error up so we get a // constant at reference type, making it easy to let the fallback call // `PartialEq::eq` on it. - return Err(fallback_to_const_ref(self)); + return Err(FallbackToConstRef); } ty::Adt(adt_def, _) if !self.type_marked_structural(cv.ty()) => { debug!( @@ -393,11 +385,11 @@ impl<'tcx> ConstToPat<'tcx> { self.behind_reference.set(old); val } - // Backwards compatibility hack: support references to non-structural types. - // We'll lower - // this pattern to a `PartialEq::eq` comparison and `PartialEq::eq` takes a - // reference. This makes the rest of the matching logic simpler as it doesn't have - // to figure out how to get a reference again. + // Backwards compatibility hack: support references to non-structural types, + // but hard error if we aren't behind a double reference. We could just use + // the fallback code path below, but that would allow *more* of this fishy + // code to compile, as then it only goes through the future incompat lint + // instead of a hard error. ty::Adt(_, _) if !self.type_marked_structural(*pointee_ty) => { if self.behind_reference.get() { if !self.saw_const_match_error.get() @@ -411,7 +403,7 @@ impl<'tcx> ConstToPat<'tcx> { IndirectStructuralMatch { non_sm_ty: *pointee_ty }, ); } - PatKind::Constant { value: cv } + return Err(FallbackToConstRef); } else { if !self.saw_const_match_error.get() { self.saw_const_match_error.set(true); @@ -435,16 +427,9 @@ impl<'tcx> ConstToPat<'tcx> { PatKind::Wild } else { let old = self.behind_reference.replace(true); - // In case there are structural-match violations somewhere in this subpattern, - // we fall back to a const pattern. If we do not do this, we may end up with - // a !structural-match constant that is not of reference type, which makes it - // very hard to invoke `PartialEq::eq` on it as a fallback. - let val = match self.recur(tcx.deref_mir_constant(self.param_env.and(cv)), false) { - Ok(subpattern) => PatKind::Deref { subpattern }, - Err(_) => PatKind::Constant { value: cv }, - }; + let subpattern = self.recur(tcx.deref_mir_constant(self.param_env.and(cv)), false)?; self.behind_reference.set(old); - val + PatKind::Deref { subpattern } } } }, @@ -452,7 +437,7 @@ impl<'tcx> ConstToPat<'tcx> { PatKind::Constant { value: cv } } ty::RawPtr(pointee) if pointee.ty.is_sized(tcx, param_env) => { - PatKind::Constant { value: cv } + return Err(FallbackToConstRef); } // FIXME: these can have very surprising behaviour where optimization levels or other // compilation choices change the runtime behaviour of the match. @@ -469,7 +454,7 @@ impl<'tcx> ConstToPat<'tcx> { PointerPattern ); } - PatKind::Constant { value: cv } + return Err(FallbackToConstRef); } _ => { self.saw_const_match_error.set(true); diff --git a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs index 9af13781312..6a77146138b 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs @@ -844,8 +844,8 @@ impl<'tcx> Constructor<'tcx> { } /// Faster version of `is_covered_by` when applied to many constructors. `used_ctors` is - /// assumed to be built from `matrix.head_ctors()` with wildcards filtered out, and `self` is - /// assumed to have been split from a wildcard. + /// assumed to be built from `matrix.head_ctors()` with wildcards and opaques filtered out, + /// and `self` is assumed to have been split from a wildcard. fn is_covered_by_any<'p>( &self, pcx: &PatCtxt<'_, 'p, 'tcx>, @@ -894,7 +894,7 @@ impl<'tcx> Constructor<'tcx> { /// in `to_ctors`: in some cases we only return `Missing`. #[derive(Debug)] pub(super) struct SplitWildcard<'tcx> { - /// Constructors seen in the matrix. + /// Constructors (other than wildcards and opaques) seen in the matrix. matrix_ctors: Vec<Constructor<'tcx>>, /// All the constructors for this type all_ctors: SmallVec<[Constructor<'tcx>; 1]>, @@ -1037,7 +1037,7 @@ impl<'tcx> SplitWildcard<'tcx> { // Since `all_ctors` never contains wildcards, this won't recurse further. self.all_ctors = self.all_ctors.iter().flat_map(|ctor| ctor.split(pcx, ctors.clone())).collect(); - self.matrix_ctors = ctors.filter(|c| !c.is_wildcard()).cloned().collect(); + self.matrix_ctors = ctors.filter(|c| !matches!(c, Wildcard | Opaque)).cloned().collect(); } /// Whether there are any value constructors for this type that are not present in the matrix. diff --git a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs index f229b10c447..e5b63506906 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs @@ -288,6 +288,22 @@ //! //! The details are not necessary to understand this file, so we explain them in //! [`super::deconstruct_pat`]. Splitting is done by the [`Constructor::split`] function. +//! +//! # Constants in patterns +//! +//! There are two kinds of constants in patterns: +//! +//! * literals (`1`, `true`, `"foo"`) +//! * named or inline consts (`FOO`, `const { 5 + 6 }`) +//! +//! The latter are converted into other patterns with literals at the leaves. For example +//! `const_to_pat(const { [1, 2, 3] })` becomes an `Array(vec![Const(1), Const(2), Const(3)])` +//! pattern. This gets problematic when comparing the constant via `==` would behave differently +//! from matching on the constant converted to a pattern. Situations like that can occur, when +//! the user implements `PartialEq` manually, and thus could make `==` behave arbitrarily different. +//! In order to honor the `==` implementation, constants of types that implement `PartialEq` manually +//! stay as a full constant and become an `Opaque` pattern. These `Opaque` patterns do not participate +//! in exhaustiveness, specialization or overlap checking. use self::ArmType::*; use self::Usefulness::*; diff --git a/compiler/rustc_mir_dataflow/src/framework/lattice.rs b/compiler/rustc_mir_dataflow/src/framework/lattice.rs index af44a4329bf..3952f44ad48 100644 --- a/compiler/rustc_mir_dataflow/src/framework/lattice.rs +++ b/compiler/rustc_mir_dataflow/src/framework/lattice.rs @@ -75,12 +75,12 @@ pub trait MeetSemiLattice: Eq { /// A set that has a "bottom" element, which is less than or equal to any other element. pub trait HasBottom { - fn bottom() -> Self; + const BOTTOM: Self; } /// A set that has a "top" element, which is greater than or equal to any other element. pub trait HasTop { - fn top() -> Self; + const TOP: Self; } /// A `bool` is a "two-point" lattice with `true` as the top element and `false` as the bottom: @@ -113,15 +113,11 @@ impl MeetSemiLattice for bool { } impl HasBottom for bool { - fn bottom() -> Self { - false - } + const BOTTOM: Self = false; } impl HasTop for bool { - fn top() -> Self { - true - } + const TOP: Self = true; } /// A tuple (or list) of lattices is itself a lattice whose least upper bound is the concatenation @@ -274,13 +270,9 @@ impl<T: Clone + Eq> MeetSemiLattice for FlatSet<T> { } impl<T> HasBottom for FlatSet<T> { - fn bottom() -> Self { - Self::Bottom - } + const BOTTOM: Self = Self::Bottom; } impl<T> HasTop for FlatSet<T> { - fn top() -> Self { - Self::Top - } + const TOP: Self = Self::Top; } diff --git a/compiler/rustc_mir_dataflow/src/value_analysis.rs b/compiler/rustc_mir_dataflow/src/value_analysis.rs index fdff1ec788d..b74d06e5ae8 100644 --- a/compiler/rustc_mir_dataflow/src/value_analysis.rs +++ b/compiler/rustc_mir_dataflow/src/value_analysis.rs @@ -32,9 +32,12 @@ //! Because of that, we can assume that the only way to change the value behind a tracked place is //! by direct assignment. +use std::collections::VecDeque; use std::fmt::{Debug, Formatter}; +use std::ops::Range; use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_index::bit_set::BitSet; use rustc_index::{IndexSlice, IndexVec}; use rustc_middle::mir::visit::{MutatingUseContext, PlaceContext, Visitor}; @@ -65,8 +68,8 @@ pub trait ValueAnalysis<'tcx> { StatementKind::Assign(box (place, rvalue)) => { self.handle_assign(*place, rvalue, state); } - StatementKind::SetDiscriminant { box ref place, .. } => { - state.flood_discr(place.as_ref(), self.map()); + StatementKind::SetDiscriminant { box place, variant_index } => { + self.handle_set_discriminant(*place, *variant_index, state); } StatementKind::Intrinsic(box intrinsic) => { self.handle_intrinsic(intrinsic, state); @@ -74,11 +77,11 @@ pub trait ValueAnalysis<'tcx> { StatementKind::StorageLive(local) | StatementKind::StorageDead(local) => { // StorageLive leaves the local in an uninitialized state. // StorageDead makes it UB to access the local afterwards. - state.flood_with(Place::from(*local).as_ref(), self.map(), Self::Value::bottom()); + state.flood_with(Place::from(*local).as_ref(), self.map(), Self::Value::BOTTOM); } StatementKind::Deinit(box place) => { // Deinit makes the place uninitialized. - state.flood_with(place.as_ref(), self.map(), Self::Value::bottom()); + state.flood_with(place.as_ref(), self.map(), Self::Value::BOTTOM); } StatementKind::Retag(..) => { // We don't track references. @@ -92,6 +95,24 @@ pub trait ValueAnalysis<'tcx> { } } + fn handle_set_discriminant( + &self, + place: Place<'tcx>, + variant_index: VariantIdx, + state: &mut State<Self::Value>, + ) { + self.super_set_discriminant(place, variant_index, state) + } + + fn super_set_discriminant( + &self, + place: Place<'tcx>, + _variant_index: VariantIdx, + state: &mut State<Self::Value>, + ) { + state.flood_discr(place.as_ref(), self.map()); + } + fn handle_intrinsic( &self, intrinsic: &NonDivergingIntrinsic<'tcx>, @@ -103,16 +124,18 @@ pub trait ValueAnalysis<'tcx> { fn super_intrinsic( &self, intrinsic: &NonDivergingIntrinsic<'tcx>, - state: &mut State<Self::Value>, + _state: &mut State<Self::Value>, ) { match intrinsic { NonDivergingIntrinsic::Assume(..) => { // Could use this, but ignoring it is sound. } - NonDivergingIntrinsic::CopyNonOverlapping(CopyNonOverlapping { dst, .. }) => { - if let Some(place) = dst.place() { - state.flood(place.as_ref(), self.map()); - } + NonDivergingIntrinsic::CopyNonOverlapping(CopyNonOverlapping { + dst: _, + src: _, + count: _, + }) => { + // This statement represents `*dst = *src`, `count` times. } } } @@ -154,7 +177,7 @@ pub trait ValueAnalysis<'tcx> { Rvalue::CopyForDeref(place) => self.handle_operand(&Operand::Copy(*place), state), Rvalue::Ref(..) | Rvalue::AddressOf(..) => { // We don't track such places. - ValueOrPlace::top() + ValueOrPlace::TOP } Rvalue::Repeat(..) | Rvalue::ThreadLocalRef(..) @@ -168,7 +191,7 @@ pub trait ValueAnalysis<'tcx> { | Rvalue::Aggregate(..) | Rvalue::ShallowInitBox(..) => { // No modification is possible through these r-values. - ValueOrPlace::top() + ValueOrPlace::TOP } } } @@ -196,7 +219,7 @@ pub trait ValueAnalysis<'tcx> { self.map() .find(place.as_ref()) .map(ValueOrPlace::Place) - .unwrap_or(ValueOrPlace::top()) + .unwrap_or(ValueOrPlace::TOP) } } } @@ -214,7 +237,7 @@ pub trait ValueAnalysis<'tcx> { _constant: &Constant<'tcx>, _state: &mut State<Self::Value>, ) -> Self::Value { - Self::Value::top() + Self::Value::TOP } /// The effect of a successful function call return should not be @@ -229,7 +252,7 @@ pub trait ValueAnalysis<'tcx> { // Effect is applied by `handle_call_return`. } TerminatorKind::Drop { place, .. } => { - state.flood_with(place.as_ref(), self.map(), Self::Value::bottom()); + state.flood_with(place.as_ref(), self.map(), Self::Value::BOTTOM); } TerminatorKind::Yield { .. } => { // They would have an effect, but are not allowed in this phase. @@ -307,7 +330,7 @@ impl<'tcx, T: ValueAnalysis<'tcx>> AnalysisDomain<'tcx> for ValueAnalysisWrapper fn initialize_start_block(&self, body: &Body<'tcx>, state: &mut Self::Domain) { // The initial state maps all tracked places of argument projections to ⊤ and the rest to ⊥. assert!(matches!(state.0, StateData::Unreachable)); - let values = IndexVec::from_elem_n(T::Value::bottom(), self.0.map().value_count); + let values = IndexVec::from_elem_n(T::Value::BOTTOM, self.0.map().value_count); *state = State(StateData::Reachable(values)); for arg in body.args_iter() { state.flood(PlaceRef { local: arg, projection: &[] }, self.0.map()); @@ -437,7 +460,7 @@ impl<V: Clone + HasTop + HasBottom> State<V> { } pub fn flood_all(&mut self) { - self.flood_all_with(V::top()) + self.flood_all_with(V::TOP) } pub fn flood_all_with(&mut self, value: V) { @@ -447,28 +470,24 @@ impl<V: Clone + HasTop + HasBottom> State<V> { pub fn flood_with(&mut self, place: PlaceRef<'_>, map: &Map, value: V) { let StateData::Reachable(values) = &mut self.0 else { return }; - map.for_each_aliasing_place(place, None, &mut |place| { - if let Some(vi) = map.places[place].value_index { - values[vi] = value.clone(); - } + map.for_each_aliasing_place(place, None, &mut |vi| { + values[vi] = value.clone(); }); } pub fn flood(&mut self, place: PlaceRef<'_>, map: &Map) { - self.flood_with(place, map, V::top()) + self.flood_with(place, map, V::TOP) } pub fn flood_discr_with(&mut self, place: PlaceRef<'_>, map: &Map, value: V) { let StateData::Reachable(values) = &mut self.0 else { return }; - map.for_each_aliasing_place(place, Some(TrackElem::Discriminant), &mut |place| { - if let Some(vi) = map.places[place].value_index { - values[vi] = value.clone(); - } + map.for_each_aliasing_place(place, Some(TrackElem::Discriminant), &mut |vi| { + values[vi] = value.clone(); }); } pub fn flood_discr(&mut self, place: PlaceRef<'_>, map: &Map) { - self.flood_discr_with(place, map, V::top()) + self.flood_discr_with(place, map, V::TOP) } /// Low-level method that assigns to a place. @@ -538,14 +557,14 @@ impl<V: Clone + HasTop + HasBottom> State<V> { /// Retrieve the value stored for a place, or ⊤ if it is not tracked. pub fn get(&self, place: PlaceRef<'_>, map: &Map) -> V { - map.find(place).map(|place| self.get_idx(place, map)).unwrap_or(V::top()) + map.find(place).map(|place| self.get_idx(place, map)).unwrap_or(V::TOP) } /// Retrieve the value stored for a place, or ⊤ if it is not tracked. pub fn get_discr(&self, place: PlaceRef<'_>, map: &Map) -> V { match map.find_discr(place) { Some(place) => self.get_idx(place, map), - None => V::top(), + None => V::TOP, } } @@ -553,11 +572,11 @@ impl<V: Clone + HasTop + HasBottom> State<V> { pub fn get_idx(&self, place: PlaceIndex, map: &Map) -> V { match &self.0 { StateData::Reachable(values) => { - map.places[place].value_index.map(|v| values[v].clone()).unwrap_or(V::top()) + map.places[place].value_index.map(|v| values[v].clone()).unwrap_or(V::TOP) } StateData::Unreachable => { // Because this is unreachable, we can return any value we want. - V::bottom() + V::BOTTOM } } } @@ -588,6 +607,9 @@ pub struct Map { projections: FxHashMap<(PlaceIndex, TrackElem), PlaceIndex>, places: IndexVec<PlaceIndex, PlaceInfo>, value_count: usize, + // The Range corresponds to a slice into `inner_values_buffer`. + inner_values: IndexVec<PlaceIndex, Range<usize>>, + inner_values_buffer: Vec<ValueIndex>, } impl Map { @@ -597,6 +619,8 @@ impl Map { projections: FxHashMap::default(), places: IndexVec::new(), value_count: 0, + inner_values: IndexVec::new(), + inner_values_buffer: Vec::new(), } } @@ -608,12 +632,12 @@ impl Map { pub fn from_filter<'tcx>( tcx: TyCtxt<'tcx>, body: &Body<'tcx>, - filter: impl FnMut(Ty<'tcx>) -> bool, - place_limit: Option<usize>, + filter: impl Fn(Ty<'tcx>) -> bool, + value_limit: Option<usize>, ) -> Self { let mut map = Self::new(); let exclude = excluded_locals(body); - map.register_with_filter(tcx, body, filter, exclude, place_limit); + map.register_with_filter(tcx, body, filter, exclude, value_limit); debug!("registered {} places ({} nodes in total)", map.value_count, map.places.len()); map } @@ -623,51 +647,90 @@ impl Map { &mut self, tcx: TyCtxt<'tcx>, body: &Body<'tcx>, - mut filter: impl FnMut(Ty<'tcx>) -> bool, + filter: impl Fn(Ty<'tcx>) -> bool, exclude: BitSet<Local>, - place_limit: Option<usize>, + value_limit: Option<usize>, ) { - // We use this vector as stack, pushing and popping projections. - let mut projection = Vec::new(); + let mut worklist = VecDeque::with_capacity(value_limit.unwrap_or(body.local_decls.len())); + + // Start by constructing the places for each bare local. + self.locals = IndexVec::from_elem(None, &body.local_decls); for (local, decl) in body.local_decls.iter_enumerated() { - if !exclude.contains(local) { - self.register_with_filter_rec( - tcx, - local, - &mut projection, - decl.ty, - &mut filter, - place_limit, - ); + if exclude.contains(local) { + continue; } + + // Create a place for the local. + debug_assert!(self.locals[local].is_none()); + let place = self.places.push(PlaceInfo::new(None)); + self.locals[local] = Some(place); + + // And push the eventual children places to the worklist. + self.register_children(tcx, place, decl.ty, &filter, &mut worklist); } + + // `place.elem1.elem2` with type `ty`. + // `elem1` is either `Some(Variant(i))` or `None`. + while let Some((mut place, elem1, elem2, ty)) = worklist.pop_front() { + // The user requires a bound on the number of created values. + if let Some(value_limit) = value_limit && self.value_count >= value_limit { + break + } + + // Create a place for this projection. + for elem in [elem1, Some(elem2)].into_iter().flatten() { + place = *self.projections.entry((place, elem)).or_insert_with(|| { + // Prepend new child to the linked list. + let next = self.places.push(PlaceInfo::new(Some(elem))); + self.places[next].next_sibling = self.places[place].first_child; + self.places[place].first_child = Some(next); + next + }); + } + + // And push the eventual children places to the worklist. + self.register_children(tcx, place, ty, &filter, &mut worklist); + } + + // Pre-compute the tree of ValueIndex nested in each PlaceIndex. + // `inner_values_buffer[inner_values[place]]` is the set of all the values + // reachable by projecting `place`. + self.inner_values_buffer = Vec::with_capacity(self.value_count); + self.inner_values = IndexVec::from_elem(0..0, &self.places); + for local in body.local_decls.indices() { + if let Some(place) = self.locals[local] { + self.cache_preorder_invoke(place); + } + } + + // Trim useless places. + for opt_place in self.locals.iter_mut() { + if let Some(place) = *opt_place && self.inner_values[place].is_empty() { + *opt_place = None; + } + } + #[allow(rustc::potential_query_instability)] + self.projections.retain(|_, child| !self.inner_values[*child].is_empty()); } /// Potentially register the (local, projection) place and its fields, recursively. /// /// Invariant: The projection must only contain trackable elements. - fn register_with_filter_rec<'tcx>( + fn register_children<'tcx>( &mut self, tcx: TyCtxt<'tcx>, - local: Local, - projection: &mut Vec<PlaceElem<'tcx>>, + place: PlaceIndex, ty: Ty<'tcx>, - filter: &mut impl FnMut(Ty<'tcx>) -> bool, - place_limit: Option<usize>, + filter: &impl Fn(Ty<'tcx>) -> bool, + worklist: &mut VecDeque<(PlaceIndex, Option<TrackElem>, TrackElem, Ty<'tcx>)>, ) { - if let Some(place_limit) = place_limit && self.value_count >= place_limit { - return - } - - // We know that the projection only contains trackable elements. - let place = self.make_place(local, projection).unwrap(); - // Allocate a value slot if it doesn't have one, and the user requested one. if self.places[place].value_index.is_none() && filter(ty) { self.places[place].value_index = Some(self.value_count.into()); self.value_count += 1; } + // For enums, directly create the `Discriminant`, as that's their main use. if ty.is_enum() { let discr_ty = ty.discriminant_ty(tcx); if filter(discr_ty) { @@ -692,46 +755,32 @@ impl Map { // Recurse with all fields of this place. iter_fields(ty, tcx, ty::ParamEnv::reveal_all(), |variant, field, ty| { - if let Some(variant) = variant { - projection.push(PlaceElem::Downcast(None, variant)); - let _ = self.make_place(local, projection); - projection.push(PlaceElem::Field(field, ty)); - self.register_with_filter_rec(tcx, local, projection, ty, filter, place_limit); - projection.pop(); - projection.pop(); - return; - } - projection.push(PlaceElem::Field(field, ty)); - self.register_with_filter_rec(tcx, local, projection, ty, filter, place_limit); - projection.pop(); + worklist.push_back(( + place, + variant.map(TrackElem::Variant), + TrackElem::Field(field), + ty, + )) }); } - /// Tries to add the place to the map, without allocating a value slot. - /// - /// Can fail if the projection contains non-trackable elements. - fn make_place<'tcx>( - &mut self, - local: Local, - projection: &[PlaceElem<'tcx>], - ) -> Result<PlaceIndex, ()> { - // Get the base index of the local. - let mut index = - *self.locals.get_or_insert_with(local, || self.places.push(PlaceInfo::new(None))); - - // Apply the projection. - for &elem in projection { - let elem = elem.try_into()?; - index = *self.projections.entry((index, elem)).or_insert_with(|| { - // Prepend new child to the linked list. - let next = self.places.push(PlaceInfo::new(Some(elem))); - self.places[next].next_sibling = self.places[index].first_child; - self.places[index].first_child = Some(next); - next - }); + /// Precompute the list of values inside `root` and store it inside + /// as a slice within `inner_values_buffer`. + fn cache_preorder_invoke(&mut self, root: PlaceIndex) { + let start = self.inner_values_buffer.len(); + if let Some(vi) = self.places[root].value_index { + self.inner_values_buffer.push(vi); + } + + // We manually iterate instead of using `children` as we need to mutate `self`. + let mut next_child = self.places[root].first_child; + while let Some(child) = next_child { + ensure_sufficient_stack(|| self.cache_preorder_invoke(child)); + next_child = self.places[child].next_sibling; } - Ok(index) + let end = self.inner_values_buffer.len(); + self.inner_values[root] = start..end; } /// Returns the number of tracked places, i.e., those for which a value can be stored. @@ -750,7 +799,7 @@ impl Map { place: PlaceRef<'_>, extra: impl IntoIterator<Item = TrackElem>, ) -> Option<PlaceIndex> { - let mut index = *self.locals.get(place.local)?.as_ref()?; + let mut index = *self.locals[place.local].as_ref()?; for &elem in place.projection { index = self.apply(index, elem.try_into().ok()?)?; @@ -784,17 +833,17 @@ impl Map { /// /// `tail_elem` allows to support discriminants that are not a place in MIR, but that we track /// as such. - pub fn for_each_aliasing_place( + fn for_each_aliasing_place( &self, place: PlaceRef<'_>, tail_elem: Option<TrackElem>, - f: &mut impl FnMut(PlaceIndex), + f: &mut impl FnMut(ValueIndex), ) { - if place.is_indirect() { + if place.has_deref() { // We do not track indirect places. return; } - let Some(&Some(mut index)) = self.locals.get(place.local) else { + let Some(mut index) = self.locals[place.local] else { // The local is not tracked at all, so it does not alias anything. return; }; @@ -805,7 +854,9 @@ impl Map { .chain(tail_elem.map(Ok).into_iter()); for elem in elems { // A field aliases the parent place. - f(index); + if let Some(vi) = self.places[index].value_index { + f(vi); + } let Ok(elem) = elem else { return }; let sub = self.apply(index, elem); @@ -819,7 +870,7 @@ impl Map { return; } } - self.preorder_invoke(index, f); + self.for_each_value_inside(index, f); } /// Invoke the given function on all the descendants of the given place, except one branch. @@ -827,7 +878,7 @@ impl Map { &self, parent: PlaceIndex, preserved_child: Option<PlaceIndex>, - f: &mut impl FnMut(PlaceIndex), + f: &mut impl FnMut(ValueIndex), ) { for sibling in self.children(parent) { let elem = self.places[sibling].proj_elem; @@ -837,16 +888,17 @@ impl Map { // Only invalidate the other variants, the current one is fine. && Some(sibling) != preserved_child { - self.preorder_invoke(sibling, f); + self.for_each_value_inside(sibling, f); } } } - /// Invoke a function on the given place and all descendants. - fn preorder_invoke(&self, root: PlaceIndex, f: &mut impl FnMut(PlaceIndex)) { - f(root); - for child in self.children(root) { - self.preorder_invoke(child, f); + /// Invoke a function on each value in the given place and all descendants. + fn for_each_value_inside(&self, root: PlaceIndex, f: &mut impl FnMut(ValueIndex)) { + let range = self.inner_values[root].clone(); + let values = &self.inner_values_buffer[range]; + for &v in values { + f(v) } } } @@ -909,9 +961,7 @@ pub enum ValueOrPlace<V> { } impl<V: HasTop> ValueOrPlace<V> { - pub fn top() -> Self { - ValueOrPlace::Value(V::top()) - } + pub const TOP: Self = ValueOrPlace::Value(V::TOP); } /// The set of projection elements that can be used by a tracked place. diff --git a/compiler/rustc_mir_transform/src/check_unsafety.rs b/compiler/rustc_mir_transform/src/check_unsafety.rs index bdb4f20da10..069514d8a3b 100644 --- a/compiler/rustc_mir_transform/src/check_unsafety.rs +++ b/compiler/rustc_mir_transform/src/check_unsafety.rs @@ -7,7 +7,7 @@ use rustc_hir::intravisit; use rustc_hir::{BlockCheckMode, ExprKind, Node}; use rustc_middle::mir::visit::{MutatingUseContext, PlaceContext, Visitor}; use rustc_middle::mir::*; -use rustc_middle::ty::query::Providers; +use rustc_middle::query::Providers; use rustc_middle::ty::{self, TyCtxt}; use rustc_session::lint::builtin::{UNSAFE_OP_IN_UNSAFE_FN, UNUSED_UNSAFE}; use rustc_session::lint::Level; diff --git a/compiler/rustc_mir_transform/src/copy_prop.rs b/compiler/rustc_mir_transform/src/copy_prop.rs index c565d6f13b1..319f3a79705 100644 --- a/compiler/rustc_mir_transform/src/copy_prop.rs +++ b/compiler/rustc_mir_transform/src/copy_prop.rs @@ -162,20 +162,22 @@ impl<'tcx> MutVisitor<'tcx> for Replacer<'_, 'tcx> { } fn visit_statement(&mut self, stmt: &mut Statement<'tcx>, loc: Location) { - match stmt.kind { - // When removing storage statements, we need to remove both (#107511). - StatementKind::StorageLive(l) | StatementKind::StorageDead(l) - if self.storage_to_remove.contains(l) => - { - stmt.make_nop() - } - StatementKind::Assign(box (ref place, ref mut rvalue)) - if place.as_local().is_some() => - { - // Do not replace assignments. - self.visit_rvalue(rvalue, loc) - } - _ => self.super_statement(stmt, loc), + // When removing storage statements, we need to remove both (#107511). + if let StatementKind::StorageLive(l) | StatementKind::StorageDead(l) = stmt.kind + && self.storage_to_remove.contains(l) + { + stmt.make_nop(); + return + } + + self.super_statement(stmt, loc); + + // Do not leave tautological assignments around. + if let StatementKind::Assign(box (lhs, ref rhs)) = stmt.kind + && let Rvalue::Use(Operand::Copy(rhs) | Operand::Move(rhs)) | Rvalue::CopyForDeref(rhs) = *rhs + && lhs == rhs + { + stmt.make_nop(); } } } diff --git a/compiler/rustc_mir_transform/src/coverage/query.rs b/compiler/rustc_mir_transform/src/coverage/query.rs index bf01b45eb40..74b4b4a07c5 100644 --- a/compiler/rustc_mir_transform/src/coverage/query.rs +++ b/compiler/rustc_mir_transform/src/coverage/query.rs @@ -2,7 +2,7 @@ use super::*; use rustc_middle::mir::coverage::*; use rustc_middle::mir::{self, Body, Coverage, CoverageInfo}; -use rustc_middle::ty::query::Providers; +use rustc_middle::query::Providers; use rustc_middle::ty::{self, TyCtxt}; use rustc_span::def_id::DefId; diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs index 254b704f9fc..7adfc9dff2a 100644 --- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs +++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs @@ -79,22 +79,22 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> { &self.map } - fn handle_statement(&self, statement: &Statement<'tcx>, state: &mut State<Self::Value>) { - match statement.kind { - StatementKind::SetDiscriminant { box ref place, variant_index } => { - state.flood_discr(place.as_ref(), &self.map); - if self.map.find_discr(place.as_ref()).is_some() { - let enum_ty = place.ty(self.local_decls, self.tcx).ty; - if let Some(discr) = self.eval_discriminant(enum_ty, variant_index) { - state.assign_discr( - place.as_ref(), - ValueOrPlace::Value(FlatSet::Elem(discr)), - &self.map, - ); - } - } + fn handle_set_discriminant( + &self, + place: Place<'tcx>, + variant_index: VariantIdx, + state: &mut State<Self::Value>, + ) { + state.flood_discr(place.as_ref(), &self.map); + if self.map.find_discr(place.as_ref()).is_some() { + let enum_ty = place.ty(self.local_decls, self.tcx).ty; + if let Some(discr) = self.eval_discriminant(enum_ty, variant_index) { + state.assign_discr( + place.as_ref(), + ValueOrPlace::Value(FlatSet::Elem(discr)), + &self.map, + ); } - _ => self.super_statement(statement, state), } } @@ -208,8 +208,8 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> { _ => unreachable!(), } .map(|result| ValueOrPlace::Value(self.wrap_immediate(result, *ty))) - .unwrap_or(ValueOrPlace::top()), - _ => ValueOrPlace::top(), + .unwrap_or(ValueOrPlace::TOP), + _ => ValueOrPlace::TOP, }, Rvalue::BinaryOp(op, box (left, right)) => { // Overflows must be ignored here. diff --git a/compiler/rustc_mir_transform/src/deduce_param_attrs.rs b/compiler/rustc_mir_transform/src/deduce_param_attrs.rs index 8ee08c5be34..a133c9d4782 100644 --- a/compiler/rustc_mir_transform/src/deduce_param_attrs.rs +++ b/compiler/rustc_mir_transform/src/deduce_param_attrs.rs @@ -8,7 +8,7 @@ use rustc_hir::def_id::LocalDefId; use rustc_index::bit_set::BitSet; use rustc_middle::mir::visit::{NonMutatingUseContext, PlaceContext, Visitor}; -use rustc_middle::mir::{Body, Local, Location, Operand, Terminator, TerminatorKind, RETURN_PLACE}; +use rustc_middle::mir::{Body, Location, Operand, Place, Terminator, TerminatorKind, RETURN_PLACE}; use rustc_middle::ty::{self, DeducedParamAttrs, Ty, TyCtxt}; use rustc_session::config::OptLevel; @@ -29,31 +29,31 @@ impl DeduceReadOnly { } impl<'tcx> Visitor<'tcx> for DeduceReadOnly { - fn visit_local(&mut self, local: Local, mut context: PlaceContext, _: Location) { + fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, _location: Location) { // We're only interested in arguments. - if local == RETURN_PLACE || local.index() > self.mutable_args.domain_size() { + if place.local == RETURN_PLACE || place.local.index() > self.mutable_args.domain_size() { return; } - // Replace place contexts that are moves with copies. This is safe in all cases except - // function argument position, which we already handled in `visit_terminator()` by using the - // ArgumentChecker. See the comment in that method for more details. - // - // In the future, we might want to move this out into a separate pass, but for now let's - // just do it on the fly because that's faster. - if matches!(context, PlaceContext::NonMutatingUse(NonMutatingUseContext::Move)) { - context = PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy); - } - - match context { - PlaceContext::MutatingUse(..) - | PlaceContext::NonMutatingUse(NonMutatingUseContext::Move) => { + let mark_as_mutable = match context { + PlaceContext::MutatingUse(..) => { // This is a mutation, so mark it as such. - self.mutable_args.insert(local.index() - 1); + true + } + PlaceContext::NonMutatingUse(NonMutatingUseContext::AddressOf) => { + // Whether mutating though a `&raw const` is allowed is still undecided, so we + // disable any sketchy `readonly` optimizations for now. + // But we only need to do this if the pointer would point into the argument. + !place.is_indirect() } PlaceContext::NonMutatingUse(..) | PlaceContext::NonUse(..) => { // Not mutating, so it's fine. + false } + }; + + if mark_as_mutable { + self.mutable_args.insert(place.local.index() - 1); } } diff --git a/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs b/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs index ac1de989a72..58cc161ddcc 100644 --- a/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs +++ b/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs @@ -1,8 +1,8 @@ use rustc_hir::def_id::{LocalDefId, LOCAL_CRATE}; use rustc_middle::mir::*; use rustc_middle::query::LocalCrate; +use rustc_middle::query::Providers; use rustc_middle::ty::layout; -use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, TyCtxt}; use rustc_session::lint::builtin::FFI_UNWIND_CALLS; use rustc_target::spec::abi::Abi; diff --git a/compiler/rustc_mir_transform/src/generator.rs b/compiler/rustc_mir_transform/src/generator.rs index c9144729145..891e446942e 100644 --- a/compiler/rustc_mir_transform/src/generator.rs +++ b/compiler/rustc_mir_transform/src/generator.rs @@ -1397,7 +1397,7 @@ fn create_cases<'tcx>( pub(crate) fn mir_generator_witnesses<'tcx>( tcx: TyCtxt<'tcx>, def_id: LocalDefId, -) -> GeneratorLayout<'tcx> { +) -> Option<GeneratorLayout<'tcx>> { assert!(tcx.sess.opts.unstable_opts.drop_tracking_mir); let (body, _) = tcx.mir_promoted(def_id); @@ -1410,6 +1410,7 @@ pub(crate) fn mir_generator_witnesses<'tcx>( // Get the interior types and substs which typeck computed let movable = match *gen_ty.kind() { ty::Generator(_, _, movability) => movability == hir::Movability::Movable, + ty::Error(_) => return None, _ => span_bug!(body.span, "unexpected generator type {}", gen_ty), }; @@ -1425,7 +1426,7 @@ pub(crate) fn mir_generator_witnesses<'tcx>( check_suspend_tys(tcx, &generator_layout, &body); - generator_layout + Some(generator_layout) } impl<'tcx> MirPass<'tcx> for StateTransform { diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index 277237a5515..65864dc016f 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -34,7 +34,7 @@ use rustc_middle::mir::{ MirPhase, Operand, Place, ProjectionElem, Promoted, RuntimePhase, Rvalue, SourceInfo, Statement, StatementKind, TerminatorKind, START_BLOCK, }; -use rustc_middle::ty::query::Providers; +use rustc_middle::query::Providers; use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt}; use rustc_span::sym; use rustc_trait_selection::traits; diff --git a/compiler/rustc_mir_transform/src/ref_prop.rs b/compiler/rustc_mir_transform/src/ref_prop.rs index dafd2ae23a6..bbd9f76ba5c 100644 --- a/compiler/rustc_mir_transform/src/ref_prop.rs +++ b/compiler/rustc_mir_transform/src/ref_prop.rs @@ -77,21 +77,25 @@ impl<'tcx> MirPass<'tcx> for ReferencePropagation { #[instrument(level = "trace", skip(self, tcx, body))] fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { debug!(def_id = ?body.source.def_id()); - propagate_ssa(tcx, body); + while propagate_ssa(tcx, body) {} } } -fn propagate_ssa<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { +fn propagate_ssa<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) -> bool { let ssa = SsaLocals::new(body); let mut replacer = compute_replacement(tcx, body, &ssa); - debug!(?replacer.targets, ?replacer.allowed_replacements, ?replacer.storage_to_remove); + debug!(?replacer.targets); + debug!(?replacer.allowed_replacements); + debug!(?replacer.storage_to_remove); replacer.visit_body_preserves_cfg(body); if replacer.any_replacement { crate::simplify::remove_unused_definitions(body); } + + replacer.any_replacement } #[derive(Copy, Clone, Debug, PartialEq, Eq)] @@ -190,8 +194,11 @@ fn compute_replacement<'tcx>( continue; } + // Whether the current local is subject to the uniqueness rule. + let needs_unique = ty.is_mutable_ptr(); + // If this a mutable reference that we cannot fully replace, mark it as unknown. - if ty.is_mutable_ptr() && !fully_replacable_locals.contains(local) { + if needs_unique && !fully_replacable_locals.contains(local) { debug!("not fully replaceable"); continue; } @@ -203,13 +210,14 @@ fn compute_replacement<'tcx>( // have been visited before. Rvalue::Use(Operand::Copy(place) | Operand::Move(place)) | Rvalue::CopyForDeref(place) => { - if let Some(rhs) = place.as_local() { + if let Some(rhs) = place.as_local() && ssa.is_ssa(rhs) { let target = targets[rhs]; - if matches!(target, Value::Pointer(..)) { + // Only see through immutable reference and pointers, as we do not know yet if + // mutable references are fully replaced. + if !needs_unique && matches!(target, Value::Pointer(..)) { targets[local] = target; - } else if ssa.is_ssa(rhs) { - let refmut = body.local_decls[rhs].ty.is_mutable_ptr(); - targets[local] = Value::Pointer(tcx.mk_place_deref(rhs.into()), refmut); + } else { + targets[local] = Value::Pointer(tcx.mk_place_deref(rhs.into()), needs_unique); } } } @@ -217,10 +225,10 @@ fn compute_replacement<'tcx>( let mut place = *place; // Try to see through `place` in order to collapse reborrow chains. if place.projection.first() == Some(&PlaceElem::Deref) - && let Value::Pointer(target, refmut) = targets[place.local] + && let Value::Pointer(target, inner_needs_unique) = targets[place.local] // Only see through immutable reference and pointers, as we do not know yet if // mutable references are fully replaced. - && !refmut + && !inner_needs_unique // Only collapse chain if the pointee is definitely live. && can_perform_opt(target, location) { @@ -228,7 +236,7 @@ fn compute_replacement<'tcx>( } assert_ne!(place.local, local); if is_constant_place(place) { - targets[local] = Value::Pointer(place, ty.is_mutable_ptr()); + targets[local] = Value::Pointer(place, needs_unique); } } // We do not know what to do, so keep as not-a-pointer. @@ -257,6 +265,7 @@ fn compute_replacement<'tcx>( targets, storage_to_remove, allowed_replacements, + fully_replacable_locals, any_replacement: false, }; @@ -276,16 +285,35 @@ fn compute_replacement<'tcx>( return; } - if let Value::Pointer(target, refmut) = self.targets[place.local] - && place.projection.first() == Some(&PlaceElem::Deref) - { - let perform_opt = (self.can_perform_opt)(target, loc); - if perform_opt { - self.allowed_replacements.insert((target.local, loc)); - } else if refmut { - // This mutable reference is not fully replacable, so drop it. - self.targets[place.local] = Value::Unknown; + if place.projection.first() != Some(&PlaceElem::Deref) { + // This is not a dereference, nothing to do. + return; + } + + let mut place = place.as_ref(); + loop { + if let Value::Pointer(target, needs_unique) = self.targets[place.local] { + let perform_opt = (self.can_perform_opt)(target, loc); + debug!(?place, ?target, ?needs_unique, ?perform_opt); + + // This a reborrow chain, recursively allow the replacement. + // + // This also allows to detect cases where `target.local` is not replacable, + // and mark it as such. + if let &[PlaceElem::Deref] = &target.projection[..] { + assert!(perform_opt); + self.allowed_replacements.insert((target.local, loc)); + place.local = target.local; + continue; + } else if perform_opt { + self.allowed_replacements.insert((target.local, loc)); + } else if needs_unique { + // This mutable reference is not fully replacable, so drop it. + self.targets[place.local] = Value::Unknown; + } } + + break; } } } @@ -318,6 +346,7 @@ struct Replacer<'tcx> { storage_to_remove: BitSet<Local>, allowed_replacements: FxHashSet<(Local, Location)>, any_replacement: bool, + fully_replacable_locals: BitSet<Local>, } impl<'tcx> MutVisitor<'tcx> for Replacer<'tcx> { @@ -325,19 +354,43 @@ impl<'tcx> MutVisitor<'tcx> for Replacer<'tcx> { self.tcx } - fn visit_place(&mut self, place: &mut Place<'tcx>, ctxt: PlaceContext, loc: Location) { - if let Value::Pointer(target, _) = self.targets[place.local] - && place.projection.first() == Some(&PlaceElem::Deref) + fn visit_var_debug_info(&mut self, debuginfo: &mut VarDebugInfo<'tcx>) { + if let VarDebugInfoContents::Place(ref mut place) = debuginfo.value + && place.projection.is_empty() + && let Value::Pointer(target, _) = self.targets[place.local] + && target.projection.iter().all(|p| p.can_use_in_debuginfo()) { - let perform_opt = matches!(ctxt, PlaceContext::NonUse(_)) - || self.allowed_replacements.contains(&(target.local, loc)); - - if perform_opt { - *place = target.project_deeper(&place.projection[1..], self.tcx); + if let Some((&PlaceElem::Deref, rest)) = target.projection.split_last() { + *place = Place::from(target.local).project_deeper(rest, self.tcx); + self.any_replacement = true; + } else if self.fully_replacable_locals.contains(place.local) + && let Some(references) = debuginfo.references.checked_add(1) + { + debuginfo.references = references; + *place = target; self.any_replacement = true; } - } else { - self.super_place(place, ctxt, loc); + } + } + + fn visit_place(&mut self, place: &mut Place<'tcx>, ctxt: PlaceContext, loc: Location) { + if place.projection.first() != Some(&PlaceElem::Deref) { + return; + } + + loop { + if let Value::Pointer(target, _) = self.targets[place.local] { + let perform_opt = matches!(ctxt, PlaceContext::NonUse(_)) + || self.allowed_replacements.contains(&(target.local, loc)); + + if perform_opt { + *place = target.project_deeper(&place.projection[1..], self.tcx); + self.any_replacement = true; + continue; + } + } + + break; } } diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs index 19d07fab0b9..7c47d8814db 100644 --- a/compiler/rustc_mir_transform/src/shim.rs +++ b/compiler/rustc_mir_transform/src/shim.rs @@ -2,7 +2,7 @@ use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::lang_items::LangItem; use rustc_middle::mir::*; -use rustc_middle::ty::query::Providers; +use rustc_middle::query::Providers; use rustc_middle::ty::InternalSubsts; use rustc_middle::ty::{self, EarlyBinder, GeneratorSubsts, Ty, TyCtxt}; use rustc_target::abi::{FieldIdx, VariantIdx, FIRST_VARIANT}; diff --git a/compiler/rustc_mir_transform/src/ssa.rs b/compiler/rustc_mir_transform/src/ssa.rs index 05a7b226f0c..2b404efccc7 100644 --- a/compiler/rustc_mir_transform/src/ssa.rs +++ b/compiler/rustc_mir_transform/src/ssa.rs @@ -101,14 +101,15 @@ impl SsaLocals { .retain(|&local| matches!(visitor.assignments[local], Set1::One(_))); debug!(?visitor.assignment_order); - let copy_classes = compute_copy_classes(&mut visitor, body); - - SsaLocals { + let mut ssa = SsaLocals { assignments: visitor.assignments, assignment_order: visitor.assignment_order, direct_uses: visitor.direct_uses, - copy_classes, - } + // This is filled by `compute_copy_classes`. + copy_classes: IndexVec::default(), + }; + compute_copy_classes(&mut ssa, body); + ssa } pub fn num_locals(&self) -> usize { @@ -209,13 +210,6 @@ impl<'tcx> Visitor<'tcx> for SsaVisitor { match ctxt { PlaceContext::MutatingUse(MutatingUseContext::Projection) | PlaceContext::NonMutatingUse(NonMutatingUseContext::Projection) => bug!(), - PlaceContext::MutatingUse(MutatingUseContext::Store) => { - self.assignments[local].insert(LocationExtended::Plain(loc)); - if let Set1::One(_) = self.assignments[local] { - // Only record if SSA-like, to avoid growing the vector needlessly. - self.assignment_order.push(local); - } - } // Anything can happen with raw pointers, so remove them. // We do not verify that all uses of the borrow dominate the assignment to `local`, // so we have to remove them too. @@ -252,52 +246,70 @@ impl<'tcx> Visitor<'tcx> for SsaVisitor { self.visit_local(place.local, ctxt, loc); } } + + fn visit_assign(&mut self, place: &Place<'tcx>, rvalue: &Rvalue<'tcx>, loc: Location) { + if let Some(local) = place.as_local() { + self.assignments[local].insert(LocationExtended::Plain(loc)); + if let Set1::One(_) = self.assignments[local] { + // Only record if SSA-like, to avoid growing the vector needlessly. + self.assignment_order.push(local); + } + } else { + self.visit_place(place, PlaceContext::MutatingUse(MutatingUseContext::Store), loc); + } + self.visit_rvalue(rvalue, loc); + } } #[instrument(level = "trace", skip(ssa, body))] -fn compute_copy_classes(ssa: &mut SsaVisitor, body: &Body<'_>) -> IndexVec<Local, Local> { +fn compute_copy_classes(ssa: &mut SsaLocals, body: &Body<'_>) { + let mut direct_uses = std::mem::take(&mut ssa.direct_uses); let mut copies = IndexVec::from_fn_n(|l| l, body.local_decls.len()); - for &local in &ssa.assignment_order { - debug!(?local); - - if local == RETURN_PLACE { - // `_0` is special, we cannot rename it. - continue; - } - - // This is not SSA: mark that we don't know the value. - debug!(assignments = ?ssa.assignments[local]); - let Set1::One(LocationExtended::Plain(loc)) = ssa.assignments[local] else { continue }; - - // `loc` must point to a direct assignment to `local`. - let Either::Left(stmt) = body.stmt_at(loc) else { bug!() }; - let Some((_target, rvalue)) = stmt.kind.as_assign() else { bug!() }; - assert_eq!(_target.as_local(), Some(local)); - + for (local, rvalue, _) in ssa.assignments(body) { let (Rvalue::Use(Operand::Copy(place) | Operand::Move(place)) | Rvalue::CopyForDeref(place)) = rvalue else { continue }; let Some(rhs) = place.as_local() else { continue }; - let Set1::One(_) = ssa.assignments[rhs] else { continue }; + if !ssa.is_ssa(rhs) { + continue; + } // We visit in `assignment_order`, ie. reverse post-order, so `rhs` has been // visited before `local`, and we just have to copy the representing local. - copies[local] = copies[rhs]; - ssa.direct_uses[rhs] -= 1; + let head = copies[rhs]; + + if local == RETURN_PLACE { + // `_0` is special, we cannot rename it. Instead, rename the class of `rhs` to + // `RETURN_PLACE`. This is only possible if the class head is a temporary, not an + // argument. + if body.local_kind(head) != LocalKind::Temp { + continue; + } + for h in copies.iter_mut() { + if *h == head { + *h = RETURN_PLACE; + } + } + } else { + copies[local] = head; + } + direct_uses[rhs] -= 1; } debug!(?copies); - debug!(?ssa.direct_uses); + debug!(?direct_uses); // Invariant: `copies` must point to the head of an equivalence class. #[cfg(debug_assertions)] for &head in copies.iter() { assert_eq!(copies[head], head); } + debug_assert_eq!(copies[RETURN_PLACE], RETURN_PLACE); - copies + ssa.direct_uses = direct_uses; + ssa.copy_classes = copies; } #[derive(Debug)] diff --git a/compiler/rustc_monomorphize/src/lib.rs b/compiler/rustc_monomorphize/src/lib.rs index 7253acf61e6..1c18e6b0b02 100644 --- a/compiler/rustc_monomorphize/src/lib.rs +++ b/compiler/rustc_monomorphize/src/lib.rs @@ -12,9 +12,10 @@ extern crate rustc_middle; use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage}; use rustc_fluent_macro::fluent_messages; use rustc_hir::lang_items::LangItem; +use rustc_middle::query::Providers; use rustc_middle::traits; use rustc_middle::ty::adjustment::CustomCoerceUnsized; -use rustc_middle::ty::query::{Providers, TyCtxtAt}; +use rustc_middle::ty::query::TyCtxtAt; use rustc_middle::ty::{self, Ty}; mod collector; diff --git a/compiler/rustc_monomorphize/src/partitioning/mod.rs b/compiler/rustc_monomorphize/src/partitioning/mod.rs index 993e35c7fd2..c10180ee3f4 100644 --- a/compiler/rustc_monomorphize/src/partitioning/mod.rs +++ b/compiler/rustc_monomorphize/src/partitioning/mod.rs @@ -106,8 +106,8 @@ use rustc_hir::def_id::{DefIdSet, LOCAL_CRATE}; use rustc_middle::mir; use rustc_middle::mir::mono::MonoItem; use rustc_middle::mir::mono::{CodegenUnit, Linkage}; +use rustc_middle::query::Providers; use rustc_middle::ty::print::with_no_trimmed_paths; -use rustc_middle::ty::query::Providers; use rustc_middle::ty::TyCtxt; use rustc_session::config::{DumpMonoStatsFormat, SwitchWithOptPath}; use rustc_span::symbol::Symbol; diff --git a/compiler/rustc_monomorphize/src/polymorphize.rs b/compiler/rustc_monomorphize/src/polymorphize.rs index ddc62d9c390..88a3e028527 100644 --- a/compiler/rustc_monomorphize/src/polymorphize.rs +++ b/compiler/rustc_monomorphize/src/polymorphize.rs @@ -11,9 +11,9 @@ use rustc_middle::mir::{ visit::{TyContext, Visitor}, Constant, ConstantKind, Local, LocalDecl, Location, }; +use rustc_middle::query::Providers; use rustc_middle::ty::{ self, - query::Providers, subst::SubstsRef, visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor}, Const, Ty, TyCtxt, UnusedGenericParams, diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index 1bbf833e3cd..2d0f466e236 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -478,6 +478,11 @@ parse_missing_for_in_trait_impl = missing `for` in a trait impl parse_expected_trait_in_trait_impl_found_type = expected a trait, found type +parse_extra_impl_keyword_in_trait_impl = unexpected `impl` keyword + .suggestion = remove the extra `impl` + .note = this is parsed as an `impl Trait` type, but a trait is expected at this position + + parse_non_item_in_item_list = non-item in item list .suggestion_use_const_not_let = consider using `const` instead of `let` for associated const .label_list_start = item list starts here diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index b6aeaf3d59f..84494eab855 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -1520,6 +1520,16 @@ pub(crate) struct ExpectedTraitInTraitImplFoundType { } #[derive(Diagnostic)] +#[diag(parse_extra_impl_keyword_in_trait_impl)] +pub(crate) struct ExtraImplKeywordInTraitImpl { + #[primary_span] + #[suggestion(code = "", applicability = "maybe-incorrect")] + pub extra_impl_kw: Span, + #[note] + pub impl_trait_span: Span, +} + +#[derive(Diagnostic)] #[diag(parse_bounds_not_allowed_on_trait_aliases)] pub(crate) struct BoundsNotAllowedOnTraitAliases { #[primary_span] diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 887e155426f..ee712a8e1b5 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -1180,6 +1180,10 @@ impl<'a> Parser<'a> { self.restore_snapshot(snapshot); let close_paren = self.prev_token.span; let span = lo.to(close_paren); + // filter shorthand fields + let fields: Vec<_> = + fields.into_iter().filter(|field| !field.is_shorthand).collect(); + if !fields.is_empty() && // `token.kind` should not be compared here. // This is because the `snapshot.token.kind` is treated as the same as diff --git a/compiler/rustc_parse/src/parser/generics.rs b/compiler/rustc_parse/src/parser/generics.rs index e6d0f9fbc76..cd779b0b43e 100644 --- a/compiler/rustc_parse/src/parser/generics.rs +++ b/compiler/rustc_parse/src/parser/generics.rs @@ -453,6 +453,8 @@ impl<'a> Parser<'a> { // `<` (LIFETIME|IDENT) `:` - generic parameter with bounds // `<` (LIFETIME|IDENT) `=` - generic parameter with a default // `<` const - generic const parameter + // `<` IDENT `?` - RECOVERY for `impl<T ?Bound` missing a `:`, meant to + // avoid the `T?` to `Option<T>` recovery for types. // The only truly ambiguous case is // `<` IDENT `>` `::` IDENT ... // we disambiguate it in favor of generics (`impl<T> ::absolute::Path<T> { ... }`) @@ -463,6 +465,9 @@ impl<'a> Parser<'a> { || self.look_ahead(start + 1, |t| t.is_lifetime() || t.is_ident()) && self.look_ahead(start + 2, |t| { matches!(t.kind, token::Gt | token::Comma | token::Colon | token::Eq) + // Recovery-only branch -- this could be removed, + // since it only affects diagnostics currently. + || matches!(t.kind, token::Question) }) || self.is_keyword_ahead(start + 1, &[kw::Const])) } diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 840cfe90899..dc18d400f1e 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -603,10 +603,24 @@ impl<'a> Parser<'a> { let path = match ty_first.kind { // This notably includes paths passed through `ty` macro fragments (#46438). TyKind::Path(None, path) => path, - _ => { - self.sess.emit_err(errors::ExpectedTraitInTraitImplFoundType { - span: ty_first.span, - }); + other => { + if let TyKind::ImplTrait(_, bounds) = other + && let [bound] = bounds.as_slice() + { + // Suggest removing extra `impl` keyword: + // `impl<T: Default> impl Default for Wrapper<T>` + // ^^^^^ + let extra_impl_kw = ty_first.span.until(bound.span()); + self.sess + .emit_err(errors::ExtraImplKeywordInTraitImpl { + extra_impl_kw, + impl_trait_span: ty_first.span + }); + } else { + self.sess.emit_err(errors::ExpectedTraitInTraitImplFoundType { + span: ty_first.span, + }); + } err_path(ty_first.span) } }; diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 06aa2737915..455d7b89f9c 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -19,9 +19,9 @@ use rustc_hir::{ use rustc_hir::{MethodKind, Target, Unsafety}; use rustc_middle::hir::nested_filter; use rustc_middle::middle::resolve_bound_vars::ObjectLifetimeDefault; +use rustc_middle::query::Providers; use rustc_middle::traits::ObligationCause; use rustc_middle::ty::error::{ExpectedFound, TypeError}; -use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, TyCtxt}; use rustc_session::lint::builtin::{ CONFLICTING_REPR_HINTS, INVALID_DOC_ATTRIBUTES, INVALID_MACRO_EXPORT_ARGUMENTS, diff --git a/compiler/rustc_passes/src/check_const.rs b/compiler/rustc_passes/src/check_const.rs index 6742722ce52..2357b0aadef 100644 --- a/compiler/rustc_passes/src/check_const.rs +++ b/compiler/rustc_passes/src/check_const.rs @@ -12,7 +12,7 @@ use rustc_hir as hir; use rustc_hir::def_id::LocalDefId; use rustc_hir::intravisit::{self, Visitor}; use rustc_middle::hir::nested_filter; -use rustc_middle::ty::query::Providers; +use rustc_middle::query::Providers; use rustc_middle::ty::TyCtxt; use rustc_session::parse::feature_err; use rustc_span::{sym, Span, Symbol}; diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index 3ae5b45d330..7812dcde44c 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -12,7 +12,7 @@ use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{Node, PatKind, TyKind}; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::middle::privacy::Level; -use rustc_middle::ty::query::Providers; +use rustc_middle::query::Providers; use rustc_middle::ty::{self, TyCtxt}; use rustc_session::lint; use rustc_span::symbol::{sym, Symbol}; diff --git a/compiler/rustc_passes/src/debugger_visualizer.rs b/compiler/rustc_passes/src/debugger_visualizer.rs index 72371b9950b..8ea95b3f383 100644 --- a/compiler/rustc_passes/src/debugger_visualizer.rs +++ b/compiler/rustc_passes/src/debugger_visualizer.rs @@ -6,8 +6,8 @@ use rustc_data_structures::sync::Lrc; use rustc_expand::base::resolve_path; use rustc_hir as hir; use rustc_hir::HirId; +use rustc_middle::query::{LocalCrate, Providers}; use rustc_middle::ty::TyCtxt; -use rustc_middle::{query::LocalCrate, ty::query::Providers}; use rustc_span::{sym, DebuggerVisualizerFile, DebuggerVisualizerType}; use crate::errors::DebugVisualizerUnreadable; diff --git a/compiler/rustc_passes/src/diagnostic_items.rs b/compiler/rustc_passes/src/diagnostic_items.rs index eb6ea673c85..d8b9f4fae87 100644 --- a/compiler/rustc_passes/src/diagnostic_items.rs +++ b/compiler/rustc_passes/src/diagnostic_items.rs @@ -13,7 +13,7 @@ use rustc_ast as ast; use rustc_hir::diagnostic_items::DiagnosticItems; use rustc_hir::OwnerId; use rustc_middle::query::LocalCrate; -use rustc_middle::ty::query::Providers; +use rustc_middle::query::Providers; use rustc_middle::ty::TyCtxt; use rustc_span::def_id::{DefId, LOCAL_CRATE}; use rustc_span::symbol::{sym, Symbol}; diff --git a/compiler/rustc_passes/src/entry.rs b/compiler/rustc_passes/src/entry.rs index e3e4b73efa3..ffd8f77b78b 100644 --- a/compiler/rustc_passes/src/entry.rs +++ b/compiler/rustc_passes/src/entry.rs @@ -4,7 +4,7 @@ use rustc_errors::error_code; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID, LOCAL_CRATE}; use rustc_hir::{ItemId, Node, CRATE_HIR_ID}; -use rustc_middle::ty::query::Providers; +use rustc_middle::query::Providers; use rustc_middle::ty::TyCtxt; use rustc_session::config::{sigpipe, CrateType, EntryFnType}; use rustc_session::parse::feature_err; diff --git a/compiler/rustc_passes/src/lang_items.rs b/compiler/rustc_passes/src/lang_items.rs index fdd0e5dab70..476394f30cc 100644 --- a/compiler/rustc_passes/src/lang_items.rs +++ b/compiler/rustc_passes/src/lang_items.rs @@ -22,7 +22,7 @@ use rustc_middle::ty::TyCtxt; use rustc_session::cstore::ExternCrate; use rustc_span::{symbol::kw::Empty, Span}; -use rustc_middle::ty::query::Providers; +use rustc_middle::query::Providers; pub(crate) enum Duplicate { Plain, diff --git a/compiler/rustc_passes/src/lib.rs b/compiler/rustc_passes/src/lib.rs index 8b7338e29aa..0da4b294648 100644 --- a/compiler/rustc_passes/src/lib.rs +++ b/compiler/rustc_passes/src/lib.rs @@ -22,7 +22,7 @@ extern crate tracing; use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage}; use rustc_fluent_macro::fluent_messages; -use rustc_middle::ty::query::Providers; +use rustc_middle::query::Providers; mod check_attr; mod check_const; diff --git a/compiler/rustc_passes/src/lib_features.rs b/compiler/rustc_passes/src/lib_features.rs index f4da1aaec11..44174b1b89d 100644 --- a/compiler/rustc_passes/src/lib_features.rs +++ b/compiler/rustc_passes/src/lib_features.rs @@ -9,7 +9,7 @@ use rustc_attr::{rust_version_symbol, VERSION_PLACEHOLDER}; use rustc_hir::intravisit::Visitor; use rustc_middle::hir::nested_filter; use rustc_middle::middle::lib_features::LibFeatures; -use rustc_middle::ty::query::Providers; +use rustc_middle::query::Providers; use rustc_middle::ty::TyCtxt; use rustc_span::symbol::Symbol; use rustc_span::{sym, Span}; diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs index 6758024419d..63b1578d43f 100644 --- a/compiler/rustc_passes/src/liveness.rs +++ b/compiler/rustc_passes/src/liveness.rs @@ -94,7 +94,7 @@ use rustc_hir::def_id::LocalDefId; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{Expr, HirId, HirIdMap, HirIdSet}; use rustc_index::IndexVec; -use rustc_middle::ty::query::Providers; +use rustc_middle::query::Providers; use rustc_middle::ty::{self, RootVariableMinCaptureList, Ty, TyCtxt}; use rustc_session::lint; use rustc_span::symbol::{kw, sym, Symbol}; diff --git a/compiler/rustc_passes/src/loops.rs b/compiler/rustc_passes/src/loops.rs index b4cf19e4a34..73cfe68e7f2 100644 --- a/compiler/rustc_passes/src/loops.rs +++ b/compiler/rustc_passes/src/loops.rs @@ -6,7 +6,7 @@ use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{Destination, Movability, Node}; use rustc_middle::hir::map::Map; use rustc_middle::hir::nested_filter; -use rustc_middle::ty::query::Providers; +use rustc_middle::query::Providers; use rustc_middle::ty::TyCtxt; use rustc_session::Session; use rustc_span::hygiene::DesugaringKind; diff --git a/compiler/rustc_passes/src/naked_functions.rs b/compiler/rustc_passes/src/naked_functions.rs index cf8d9300a11..a849d61edfe 100644 --- a/compiler/rustc_passes/src/naked_functions.rs +++ b/compiler/rustc_passes/src/naked_functions.rs @@ -6,7 +6,7 @@ use rustc_hir::def::DefKind; use rustc_hir::def_id::LocalDefId; use rustc_hir::intravisit::Visitor; use rustc_hir::{ExprKind, InlineAsmOperand, StmtKind}; -use rustc_middle::ty::query::Providers; +use rustc_middle::query::Providers; use rustc_middle::ty::TyCtxt; use rustc_session::lint::builtin::UNDEFINED_NAKED_FUNCTION_ABI; use rustc_span::symbol::sym; diff --git a/compiler/rustc_passes/src/reachable.rs b/compiler/rustc_passes/src/reachable.rs index a5f7b07fe52..160528e4074 100644 --- a/compiler/rustc_passes/src/reachable.rs +++ b/compiler/rustc_passes/src/reachable.rs @@ -13,7 +13,7 @@ use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::Node; use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs}; use rustc_middle::middle::privacy::{self, Level}; -use rustc_middle::ty::query::Providers; +use rustc_middle::query::Providers; use rustc_middle::ty::{self, TyCtxt}; use rustc_session::config::CrateType; use rustc_target::spec::abi::Abi; diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index 9615f283ff4..f9060328f48 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -16,7 +16,8 @@ use rustc_hir::{FieldDef, Item, ItemKind, TraitRef, Ty, TyKind, Variant}; use rustc_middle::hir::nested_filter; use rustc_middle::middle::privacy::EffectiveVisibilities; use rustc_middle::middle::stability::{AllowUnstable, DeprecationEntry, Index}; -use rustc_middle::ty::{query::Providers, TyCtxt}; +use rustc_middle::query::Providers; +use rustc_middle::ty::TyCtxt; use rustc_session::lint; use rustc_session::lint::builtin::{INEFFECTIVE_UNSTABLE_TRAIT_IMPL, USELESS_DEPRECATED}; use rustc_span::symbol::{sym, Symbol}; diff --git a/compiler/rustc_passes/src/upvars.rs b/compiler/rustc_passes/src/upvars.rs index 605cf0a93b8..d87df706cc8 100644 --- a/compiler/rustc_passes/src/upvars.rs +++ b/compiler/rustc_passes/src/upvars.rs @@ -5,7 +5,7 @@ use rustc_hir as hir; use rustc_hir::def::Res; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{self, HirId}; -use rustc_middle::ty::query::Providers; +use rustc_middle::query::Providers; use rustc_middle::ty::TyCtxt; use rustc_span::Span; diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index d6eb5463870..7b39cb0a068 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -25,9 +25,9 @@ use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{AssocItemKind, HirIdSet, ItemId, Node, PatKind}; use rustc_middle::bug; use rustc_middle::hir::nested_filter; -use rustc_middle::middle::privacy::{EffectiveVisibilities, Level}; +use rustc_middle::middle::privacy::{EffectiveVisibilities, EffectiveVisibility, Level}; +use rustc_middle::query::Providers; use rustc_middle::span_bug; -use rustc_middle::ty::query::Providers; use rustc_middle::ty::subst::InternalSubsts; use rustc_middle::ty::{self, Const, GenericParamDefKind}; use rustc_middle::ty::{TraitRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor}; @@ -38,7 +38,7 @@ use rustc_span::Span; use std::marker::PhantomData; use std::ops::ControlFlow; -use std::{cmp, fmt, mem}; +use std::{fmt, mem}; use errors::{ FieldIsPrivate, FieldIsPrivateLabel, FromPrivateDependencyInPublicInterface, InPublicInterface, @@ -408,8 +408,9 @@ impl VisibilityLike for ty::Visibility { min(find.tcx.local_visibility(def_id), find.min, find.tcx) } } -impl VisibilityLike for Option<Level> { - const MAX: Self = Some(Level::Direct); + +impl VisibilityLike for Option<EffectiveVisibility> { + const MAX: Self = Some(EffectiveVisibility::from_vis(ty::Visibility::Public)); // Type inference is very smart sometimes. // It can make an impl reachable even some components of its type or trait are unreachable. // E.g. methods of `impl ReachableTrait<UnreachableTy> for ReachableTy<UnreachableTy> { ... }` @@ -421,7 +422,13 @@ impl VisibilityLike for Option<Level> { // (which require reaching the `DefId`s in them). const SHALLOW: bool = true; fn new_min(find: &FindMin<'_, '_, Self>, def_id: LocalDefId) -> Self { - cmp::min(find.effective_visibilities.public_at_level(def_id), find.min) + if let Some(min) = find.min { + return find + .effective_visibilities + .effective_vis(def_id) + .map(|eff_vis| min.min(*eff_vis, find.tcx)); + } + None } } @@ -447,49 +454,79 @@ struct EmbargoVisitor<'tcx> { /// n::p::f() /// } macro_reachable: FxHashSet<(LocalDefId, LocalDefId)>, - /// Previous visibility level; `None` means unreachable. - prev_level: Option<Level>, /// Has something changed in the level map? changed: bool, } struct ReachEverythingInTheInterfaceVisitor<'a, 'tcx> { - level: Option<Level>, + effective_vis: Option<EffectiveVisibility>, item_def_id: LocalDefId, ev: &'a mut EmbargoVisitor<'tcx>, + level: Level, } impl<'tcx> EmbargoVisitor<'tcx> { - fn get(&self, def_id: LocalDefId) -> Option<Level> { - self.effective_visibilities.public_at_level(def_id) - } - - /// Updates node level and returns the updated level. - fn update(&mut self, def_id: LocalDefId, level: Option<Level>) -> Option<Level> { - let old_level = self.get(def_id); - // Visibility levels can only grow. - if level > old_level { - self.effective_visibilities.set_public_at_level( - def_id, - || ty::Visibility::Restricted(self.tcx.parent_module_from_def_id(def_id)), - level.unwrap(), - ); - self.changed = true; - level - } else { - old_level + fn get(&self, def_id: LocalDefId) -> Option<EffectiveVisibility> { + self.effective_visibilities.effective_vis(def_id).copied() + } + + // Updates node effective visibility. + fn update( + &mut self, + def_id: LocalDefId, + inherited_effective_vis: Option<EffectiveVisibility>, + level: Level, + ) { + let nominal_vis = self.tcx.local_visibility(def_id); + self.update_eff_vis(def_id, inherited_effective_vis, Some(nominal_vis), level); + } + + fn update_eff_vis( + &mut self, + def_id: LocalDefId, + inherited_effective_vis: Option<EffectiveVisibility>, + nominal_vis: Option<ty::Visibility>, + level: Level, + ) { + if let Some(inherited_effective_vis) = inherited_effective_vis { + let private_vis = + ty::Visibility::Restricted(self.tcx.parent_module_from_def_id(def_id)); + if Some(private_vis) != nominal_vis { + self.changed |= self.effective_visibilities.update( + def_id, + nominal_vis, + || private_vis, + inherited_effective_vis, + level, + self.tcx, + ); + } } } fn reach( &mut self, def_id: LocalDefId, - level: Option<Level>, + effective_vis: Option<EffectiveVisibility>, ) -> ReachEverythingInTheInterfaceVisitor<'_, 'tcx> { ReachEverythingInTheInterfaceVisitor { - level: cmp::min(level, Some(Level::Reachable)), + effective_vis, item_def_id: def_id, ev: self, + level: Level::Reachable, + } + } + + fn reach_through_impl_trait( + &mut self, + def_id: LocalDefId, + effective_vis: Option<EffectiveVisibility>, + ) -> ReachEverythingInTheInterfaceVisitor<'_, 'tcx> { + ReachEverythingInTheInterfaceVisitor { + effective_vis, + item_def_id: def_id, + ev: self, + level: Level::ReachableThroughImplTrait, } } @@ -510,16 +547,18 @@ impl<'tcx> EmbargoVisitor<'tcx> { return; } - if self.get(local_def_id).is_none() { + if self.effective_visibilities.public_at_level(local_def_id).is_none() { return; } // Since we are starting from an externally visible module, // all the parents in the loop below are also guaranteed to be modules. let mut module_def_id = macro_module_def_id; + let macro_ev = self.get(local_def_id); + assert!(macro_ev.is_some()); loop { let changed_reachability = - self.update_macro_reachable(module_def_id, macro_module_def_id); + self.update_macro_reachable(module_def_id, macro_module_def_id, macro_ev); if changed_reachability || module_def_id == CRATE_DEF_ID { break; } @@ -533,21 +572,33 @@ impl<'tcx> EmbargoVisitor<'tcx> { &mut self, module_def_id: LocalDefId, defining_mod: LocalDefId, + macro_ev: Option<EffectiveVisibility>, ) -> bool { if self.macro_reachable.insert((module_def_id, defining_mod)) { - self.update_macro_reachable_mod(module_def_id, defining_mod); + self.update_macro_reachable_mod(module_def_id, defining_mod, macro_ev); true } else { false } } - fn update_macro_reachable_mod(&mut self, module_def_id: LocalDefId, defining_mod: LocalDefId) { + fn update_macro_reachable_mod( + &mut self, + module_def_id: LocalDefId, + defining_mod: LocalDefId, + macro_ev: Option<EffectiveVisibility>, + ) { let module = self.tcx.hir().get_module(module_def_id).0; for item_id in module.item_ids { let def_kind = self.tcx.def_kind(item_id.owner_id); let vis = self.tcx.local_visibility(item_id.owner_id.def_id); - self.update_macro_reachable_def(item_id.owner_id.def_id, def_kind, vis, defining_mod); + self.update_macro_reachable_def( + item_id.owner_id.def_id, + def_kind, + vis, + defining_mod, + macro_ev, + ); } for child in self.tcx.module_children_local(module_def_id) { // FIXME: Use module children for the logic above too. @@ -556,7 +607,7 @@ impl<'tcx> EmbargoVisitor<'tcx> { && let Res::Def(def_kind, def_id) = child.res && let Some(def_id) = def_id.as_local() { let vis = self.tcx.local_visibility(def_id); - self.update_macro_reachable_def(def_id, def_kind, vis, defining_mod); + self.update_macro_reachable_def(def_id, def_kind, vis, defining_mod, macro_ev); } } } @@ -567,16 +618,14 @@ impl<'tcx> EmbargoVisitor<'tcx> { def_kind: DefKind, vis: ty::Visibility, module: LocalDefId, + macro_ev: Option<EffectiveVisibility>, ) { - let level = Some(Level::Reachable); - if vis.is_public() { - self.update(def_id, level); - } + self.update(def_id, macro_ev, Level::Reachable); match def_kind { // No type privacy, so can be directly marked as reachable. DefKind::Const | DefKind::Static(_) | DefKind::TraitAlias | DefKind::TyAlias => { if vis.is_accessible_from(module, self.tcx) { - self.update(def_id, level); + self.update(def_id, macro_ev, Level::Reachable); } } @@ -588,7 +637,7 @@ impl<'tcx> EmbargoVisitor<'tcx> { let item = self.tcx.hir().expect_item(def_id); if let hir::ItemKind::Macro(MacroDef { macro_rules: false, .. }, _) = item.kind { if vis.is_accessible_from(module, self.tcx) { - self.update(def_id, level); + self.update(def_id, macro_ev, Level::Reachable); } } } @@ -599,26 +648,24 @@ impl<'tcx> EmbargoVisitor<'tcx> { // the module, however may be reachable. DefKind::Mod => { if vis.is_accessible_from(module, self.tcx) { - self.update_macro_reachable(def_id, module); + self.update_macro_reachable(def_id, module, macro_ev); } } DefKind::Struct | DefKind::Union => { // While structs and unions have type privacy, their fields do not. - if vis.is_public() { - let item = self.tcx.hir().expect_item(def_id); - if let hir::ItemKind::Struct(ref struct_def, _) - | hir::ItemKind::Union(ref struct_def, _) = item.kind - { - for field in struct_def.fields() { - let field_vis = self.tcx.local_visibility(field.def_id); - if field_vis.is_accessible_from(module, self.tcx) { - self.reach(field.def_id, level).ty(); - } + let item = self.tcx.hir().expect_item(def_id); + if let hir::ItemKind::Struct(ref struct_def, _) + | hir::ItemKind::Union(ref struct_def, _) = item.kind + { + for field in struct_def.fields() { + let field_vis = self.tcx.local_visibility(field.def_id); + if field_vis.is_accessible_from(module, self.tcx) { + self.reach(field.def_id, macro_ev).ty(); } - } else { - bug!("item {:?} with DefKind {:?}", item, def_kind); } + } else { + bug!("item {:?} with DefKind {:?}", item, def_kind); } } @@ -662,14 +709,16 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> { } fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) { - let item_level = match item.kind { + let item_ev = match item.kind { hir::ItemKind::Impl { .. } => { - let impl_level = Option::<Level>::of_impl( + let impl_ev = Option::<EffectiveVisibility>::of_impl( item.owner_id.def_id, self.tcx, &self.effective_visibilities, ); - self.update(item.owner_id.def_id, impl_level) + + self.update_eff_vis(item.owner_id.def_id, impl_ev, None, Level::Direct); + impl_ev } _ => self.get(item.owner_id.def_id), }; @@ -678,38 +727,35 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> { match item.kind { hir::ItemKind::Enum(ref def, _) => { for variant in def.variants { - let variant_level = self.update(variant.def_id, item_level); + self.update(variant.def_id, item_ev, Level::Reachable); + let variant_ev = self.get(variant.def_id); if let Some(ctor_def_id) = variant.data.ctor_def_id() { - self.update(ctor_def_id, item_level); + self.update(ctor_def_id, variant_ev, Level::Reachable); } for field in variant.data.fields() { - self.update(field.def_id, variant_level); + self.update(field.def_id, variant_ev, Level::Reachable); } } } hir::ItemKind::Impl(ref impl_) => { for impl_item_ref in impl_.items { - if impl_.of_trait.is_some() - || self.tcx.visibility(impl_item_ref.id.owner_id).is_public() - { - self.update(impl_item_ref.id.owner_id.def_id, item_level); - } + let def_id = impl_item_ref.id.owner_id.def_id; + let nominal_vis = + impl_.of_trait.is_none().then(|| self.tcx.local_visibility(def_id)); + self.update_eff_vis(def_id, item_ev, nominal_vis, Level::Direct); } } hir::ItemKind::Trait(.., trait_item_refs) => { for trait_item_ref in trait_item_refs { - self.update(trait_item_ref.id.owner_id.def_id, item_level); + self.update(trait_item_ref.id.owner_id.def_id, item_ev, Level::Reachable); } } hir::ItemKind::Struct(ref def, _) | hir::ItemKind::Union(ref def, _) => { if let Some(ctor_def_id) = def.ctor_def_id() { - self.update(ctor_def_id, item_level); + self.update(ctor_def_id, item_ev, Level::Reachable); } for field in def.fields() { - let vis = self.tcx.visibility(field.def_id); - if vis.is_public() { - self.update(field.def_id, item_level); - } + self.update(field.def_id, item_ev, Level::Reachable); } } hir::ItemKind::Macro(ref macro_def, _) => { @@ -717,9 +763,7 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> { } hir::ItemKind::ForeignMod { items, .. } => { for foreign_item in items { - if self.tcx.visibility(foreign_item.id.owner_id).is_public() { - self.update(foreign_item.id.owner_id.def_id, item_level); - } + self.update(foreign_item.id.owner_id.def_id, item_ev, Level::Reachable); } } @@ -754,8 +798,11 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> { // FIXME: This is some serious pessimization intended to workaround deficiencies // in the reachability pass (`middle/reachable.rs`). Types are marked as link-time // reachable if they are returned via `impl Trait`, even from private functions. - let exist_level = cmp::max(item_level, Some(Level::ReachableThroughImplTrait)); - self.reach(item.owner_id.def_id, exist_level).generics().predicates().ty(); + let exist_ev = Some(EffectiveVisibility::from_vis(ty::Visibility::Public)); + self.reach_through_impl_trait(item.owner_id.def_id, exist_ev) + .generics() + .predicates() + .ty(); } } // Visit everything. @@ -763,17 +810,18 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> { | hir::ItemKind::Static(..) | hir::ItemKind::Fn(..) | hir::ItemKind::TyAlias(..) => { - if item_level.is_some() { - self.reach(item.owner_id.def_id, item_level).generics().predicates().ty(); + if item_ev.is_some() { + self.reach(item.owner_id.def_id, item_ev).generics().predicates().ty(); } } hir::ItemKind::Trait(.., trait_item_refs) => { - if item_level.is_some() { - self.reach(item.owner_id.def_id, item_level).generics().predicates(); + if item_ev.is_some() { + self.reach(item.owner_id.def_id, item_ev).generics().predicates(); for trait_item_ref in trait_item_refs { let tcx = self.tcx; - let mut reach = self.reach(trait_item_ref.id.owner_id.def_id, item_level); + let mut reach = self.reach(trait_item_ref.id.owner_id.def_id, item_ev); + reach.generics().predicates(); if trait_item_ref.kind == AssocItemKind::Type @@ -787,23 +835,24 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> { } } hir::ItemKind::TraitAlias(..) => { - if item_level.is_some() { - self.reach(item.owner_id.def_id, item_level).generics().predicates(); + if item_ev.is_some() { + self.reach(item.owner_id.def_id, item_ev).generics().predicates(); } } // Visit everything except for private impl items. hir::ItemKind::Impl(ref impl_) => { - if item_level.is_some() { - self.reach(item.owner_id.def_id, item_level) + if item_ev.is_some() { + self.reach(item.owner_id.def_id, item_ev) .generics() .predicates() .ty() .trait_ref(); for impl_item_ref in impl_.items { - let impl_item_level = self.get(impl_item_ref.id.owner_id.def_id); - if impl_item_level.is_some() { - self.reach(impl_item_ref.id.owner_id.def_id, impl_item_level) + let impl_item_ev = self.get(impl_item_ref.id.owner_id.def_id); + + if impl_item_ev.is_some() { + self.reach(impl_item_ref.id.owner_id.def_id, impl_item_ev) .generics() .predicates() .ty(); @@ -814,23 +863,23 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> { // Visit everything, but enum variants have their own levels. hir::ItemKind::Enum(ref def, _) => { - if item_level.is_some() { - self.reach(item.owner_id.def_id, item_level).generics().predicates(); + if item_ev.is_some() { + self.reach(item.owner_id.def_id, item_ev).generics().predicates(); } for variant in def.variants { - let variant_level = self.get(variant.def_id); - if variant_level.is_some() { + let variant_ev = self.get(variant.def_id); + if variant_ev.is_some() { for field in variant.data.fields() { - self.reach(field.def_id, variant_level).ty(); + self.reach(field.def_id, variant_ev).ty(); } // Corner case: if the variant is reachable, but its // enum is not, make the enum reachable as well. - self.reach(item.owner_id.def_id, variant_level).ty(); + self.reach(item.owner_id.def_id, variant_ev).ty(); } if let Some(ctor_def_id) = variant.data.ctor_def_id() { - let ctor_level = self.get(ctor_def_id); - if ctor_level.is_some() { - self.reach(item.owner_id.def_id, ctor_level).ty(); + let ctor_ev = self.get(ctor_def_id); + if ctor_ev.is_some() { + self.reach(item.owner_id.def_id, ctor_ev).ty(); } } } @@ -838,9 +887,9 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> { // Visit everything, but foreign items have their own levels. hir::ItemKind::ForeignMod { items, .. } => { for foreign_item in items { - let foreign_item_level = self.get(foreign_item.id.owner_id.def_id); - if foreign_item_level.is_some() { - self.reach(foreign_item.id.owner_id.def_id, foreign_item_level) + let foreign_item_ev = self.get(foreign_item.id.owner_id.def_id); + if foreign_item_ev.is_some() { + self.reach(foreign_item.id.owner_id.def_id, foreign_item_ev) .generics() .predicates() .ty(); @@ -849,36 +898,32 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> { } // Visit everything except for private fields. hir::ItemKind::Struct(ref struct_def, _) | hir::ItemKind::Union(ref struct_def, _) => { - if item_level.is_some() { - self.reach(item.owner_id.def_id, item_level).generics().predicates(); + if item_ev.is_some() { + self.reach(item.owner_id.def_id, item_ev).generics().predicates(); for field in struct_def.fields() { - let field_level = self.get(field.def_id); - if field_level.is_some() { - self.reach(field.def_id, field_level).ty(); + let field_ev = self.get(field.def_id); + if field_ev.is_some() { + self.reach(field.def_id, field_ev).ty(); } } } if let Some(ctor_def_id) = struct_def.ctor_def_id() { - let ctor_level = self.get(ctor_def_id); - if ctor_level.is_some() { - self.reach(item.owner_id.def_id, ctor_level).ty(); + let ctor_ev = self.get(ctor_def_id); + if ctor_ev.is_some() { + self.reach(item.owner_id.def_id, ctor_ev).ty(); } } } } - let orig_level = mem::replace(&mut self.prev_level, item_level); intravisit::walk_item(self, item); - self.prev_level = orig_level; } fn visit_block(&mut self, b: &'tcx hir::Block<'tcx>) { // Blocks can have public items, for example impls, but they always // start as completely private regardless of publicity of a function, // constant, type, field, etc., in which this block resides. - let orig_level = mem::replace(&mut self.prev_level, None); intravisit::walk_block(self, b); - self.prev_level = orig_level; } } @@ -932,11 +977,7 @@ impl<'tcx> DefIdVisitor<'tcx> for ReachEverythingInTheInterfaceVisitor<'_, 'tcx> _descr: &dyn fmt::Display, ) -> ControlFlow<Self::BreakTy> { if let Some(def_id) = def_id.as_local() { - if let (ty::Visibility::Public, _) | (_, Some(Level::ReachableThroughImplTrait)) = - (self.tcx().visibility(def_id.to_def_id()), self.level) - { - self.ev.update(def_id, self.level); - } + self.ev.update_eff_vis(def_id, self.effective_vis, None, self.level); } ControlFlow::Continue(()) } @@ -2164,7 +2205,6 @@ fn effective_visibilities(tcx: TyCtxt<'_>, (): ()) -> &EffectiveVisibilities { tcx, effective_visibilities: tcx.resolutions(()).effective_visibilities.clone(), macro_reachable: Default::default(), - prev_level: Some(Level::Direct), changed: false, }; diff --git a/compiler/rustc_query_impl/Cargo.toml b/compiler/rustc_query_impl/Cargo.toml index b107a3f03fe..e596993465c 100644 --- a/compiler/rustc_query_impl/Cargo.toml +++ b/compiler/rustc_query_impl/Cargo.toml @@ -7,6 +7,8 @@ edition = "2021" [dependencies] +memoffset = { version = "0.6.0", features = ["unstable_const"] } +field-offset = "0.3.5" measureme = "10.0.0" rustc_ast = { path = "../rustc_ast" } rustc_data_structures = { path = "../rustc_data_structures" } diff --git a/compiler/rustc_query_impl/src/lib.rs b/compiler/rustc_query_impl/src/lib.rs index 82b335f4b4b..3c542821b67 100644 --- a/compiler/rustc_query_impl/src/lib.rs +++ b/compiler/rustc_query_impl/src/lib.rs @@ -3,11 +3,12 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] // this shouldn't be necessary, but the check for `&mut _` is too naive and denies returning a function pointer that takes a mut ref #![feature(const_mut_refs)] +#![feature(const_refs_to_cell)] #![feature(min_specialization)] #![feature(never_type)] #![feature(rustc_attrs)] #![recursion_limit = "256"] -#![allow(rustc::potential_query_instability)] +#![allow(rustc::potential_query_instability, unused_parens)] #![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::diagnostic_outside_of_impl)] @@ -15,16 +16,28 @@ extern crate rustc_middle; use crate::plumbing::{encode_all_query_results, try_mark_green}; +use field_offset::offset_of; +use rustc_data_structures::stable_hasher::HashStable; +use rustc_data_structures::sync::AtomicU64; use rustc_middle::arena::Arena; +use rustc_middle::dep_graph::DepNodeIndex; use rustc_middle::dep_graph::{self, DepKind, DepKindStruct}; use rustc_middle::query::erase::{erase, restore, Erase}; +use rustc_middle::query::on_disk_cache::OnDiskCache; use rustc_middle::query::AsLocalKey; -use rustc_middle::ty::query::{ +use rustc_middle::query::{ query_keys, query_provided, query_provided_to_value, query_storage, query_values, + DynamicQueries, ExternProviders, Providers, QueryCaches, QueryEngine, QueryStates, }; -use rustc_middle::ty::query::{ExternProviders, Providers, QueryEngine, QuerySystemFns}; +use rustc_middle::ty::query::{DynamicQuery, QuerySystem, QuerySystemFns}; use rustc_middle::ty::TyCtxt; use rustc_query_system::dep_graph::SerializedDepNodeIndex; +use rustc_query_system::ich::StableHashingContext; +use rustc_query_system::query::{ + get_query_incr, get_query_non_incr, HashResult, QueryCache, QueryConfig, QueryInfo, QueryMap, + QueryMode, QueryState, +}; +use rustc_query_system::HandleCycleError; use rustc_query_system::Value; use rustc_span::Span; @@ -32,31 +45,183 @@ use rustc_span::Span; mod plumbing; pub use crate::plumbing::QueryCtxt; -pub use rustc_query_system::query::QueryConfig; -use rustc_query_system::query::*; - mod profiling_support; pub use self::profiling_support::alloc_self_profile_query_strings; -/// This is implemented per query and restoring query values from their erased state. -trait QueryConfigRestored<'tcx>: QueryConfig<QueryCtxt<'tcx>> + Default { - type RestoredValue; +struct DynamicConfig< + 'tcx, + C: QueryCache, + const ANON: bool, + const DEPTH_LIMIT: bool, + const FEEDABLE: bool, +> { + dynamic: &'tcx DynamicQuery<'tcx, C>, +} - fn restore(value: <Self as QueryConfig<QueryCtxt<'tcx>>>::Value) -> Self::RestoredValue; +impl<'tcx, C: QueryCache, const ANON: bool, const DEPTH_LIMIT: bool, const FEEDABLE: bool> Copy + for DynamicConfig<'tcx, C, ANON, DEPTH_LIMIT, FEEDABLE> +{ +} +impl<'tcx, C: QueryCache, const ANON: bool, const DEPTH_LIMIT: bool, const FEEDABLE: bool> Clone + for DynamicConfig<'tcx, C, ANON, DEPTH_LIMIT, FEEDABLE> +{ + fn clone(&self) -> Self { + DynamicConfig { dynamic: self.dynamic } + } } -rustc_query_append! { define_queries! } +impl<'tcx, C: QueryCache, const ANON: bool, const DEPTH_LIMIT: bool, const FEEDABLE: bool> + QueryConfig<QueryCtxt<'tcx>> for DynamicConfig<'tcx, C, ANON, DEPTH_LIMIT, FEEDABLE> +where + for<'a> C::Key: HashStable<StableHashingContext<'a>>, +{ + type Key = C::Key; + type Value = C::Value; + type Cache = C; + + #[inline(always)] + fn name(self) -> &'static str { + self.dynamic.name + } + + #[inline(always)] + fn cache_on_disk(self, tcx: TyCtxt<'tcx>, key: &Self::Key) -> bool { + (self.dynamic.cache_on_disk)(tcx, key) + } + + #[inline(always)] + fn query_state<'a>(self, qcx: QueryCtxt<'tcx>) -> &'a QueryState<Self::Key, DepKind> + where + QueryCtxt<'tcx>: 'a, + { + self.dynamic.query_state.apply(&qcx.tcx.query_system.states) + } + + #[inline(always)] + fn query_cache<'a>(self, qcx: QueryCtxt<'tcx>) -> &'a Self::Cache + where + 'tcx: 'a, + { + self.dynamic.query_cache.apply(&qcx.tcx.query_system.caches) + } + + #[inline(always)] + fn execute_query(self, tcx: TyCtxt<'tcx>, key: Self::Key) -> Self::Value { + (self.dynamic.execute_query)(tcx, key) + } + + #[inline(always)] + fn compute(self, qcx: QueryCtxt<'tcx>, key: Self::Key) -> Self::Value { + (self.dynamic.compute)(qcx.tcx, key) + } + + #[inline(always)] + fn try_load_from_disk( + self, + qcx: QueryCtxt<'tcx>, + key: &Self::Key, + prev_index: SerializedDepNodeIndex, + index: DepNodeIndex, + ) -> Option<Self::Value> { + if self.dynamic.can_load_from_disk { + (self.dynamic.try_load_from_disk)(qcx.tcx, key, prev_index, index) + } else { + None + } + } + + #[inline] + fn loadable_from_disk( + self, + qcx: QueryCtxt<'tcx>, + key: &Self::Key, + index: SerializedDepNodeIndex, + ) -> bool { + (self.dynamic.loadable_from_disk)(qcx.tcx, key, index) + } + + fn value_from_cycle_error( + self, + tcx: TyCtxt<'tcx>, + cycle: &[QueryInfo<DepKind>], + ) -> Self::Value { + (self.dynamic.value_from_cycle_error)(tcx, cycle) + } + + #[inline(always)] + fn format_value(self) -> fn(&Self::Value) -> String { + self.dynamic.format_value + } + + #[inline(always)] + fn anon(self) -> bool { + ANON + } + + #[inline(always)] + fn eval_always(self) -> bool { + self.dynamic.eval_always + } + + #[inline(always)] + fn depth_limit(self) -> bool { + DEPTH_LIMIT + } + + #[inline(always)] + fn feedable(self) -> bool { + FEEDABLE + } + + #[inline(always)] + fn dep_kind(self) -> DepKind { + self.dynamic.dep_kind + } + + #[inline(always)] + fn handle_cycle_error(self) -> HandleCycleError { + self.dynamic.handle_cycle_error + } + + #[inline(always)] + fn hash_result(self) -> HashResult<Self::Value> { + self.dynamic.hash_result + } +} -pub fn query_system_fns<'tcx>( +/// This is implemented per query. It allows restoring query values from their erased state +/// and constructing a QueryConfig. +trait QueryConfigRestored<'tcx> { + type RestoredValue; + type Config: QueryConfig<QueryCtxt<'tcx>>; + + fn config(tcx: TyCtxt<'tcx>) -> Self::Config; + fn restore(value: <Self::Config as QueryConfig<QueryCtxt<'tcx>>>::Value) + -> Self::RestoredValue; +} + +pub fn query_system<'tcx>( local_providers: Providers, extern_providers: ExternProviders, -) -> QuerySystemFns<'tcx> { - QuerySystemFns { - engine: engine(), - local_providers, - extern_providers, - query_structs: make_dep_kind_array!(query_structs).to_vec(), - encode_query_results: encode_all_query_results, - try_mark_green: try_mark_green, + on_disk_cache: Option<OnDiskCache<'tcx>>, + incremental: bool, +) -> QuerySystem<'tcx> { + QuerySystem { + states: Default::default(), + arenas: Default::default(), + caches: Default::default(), + dynamic_queries: dynamic_queries(), + on_disk_cache, + fns: QuerySystemFns { + engine: engine(incremental), + local_providers, + extern_providers, + query_structs: make_dep_kind_array!(query_structs).to_vec(), + encode_query_results: encode_all_query_results, + try_mark_green: try_mark_green, + }, + jobs: AtomicU64::new(1), } } + +rustc_query_append! { define_queries! } diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs index 9f8ac7ccd0b..5acfeb47a12 100644 --- a/compiler/rustc_query_impl/src/plumbing.rs +++ b/compiler/rustc_query_impl/src/plumbing.rs @@ -4,6 +4,7 @@ use crate::rustc_middle::dep_graph::DepContext; use crate::rustc_middle::ty::TyEncoder; +use crate::QueryConfigRestored; use rustc_data_structures::stable_hasher::{Hash64, HashStable, StableHasher}; use rustc_data_structures::sync::Lock; use rustc_errors::Diagnostic; @@ -265,14 +266,14 @@ macro_rules! hash_result { } macro_rules! call_provider { - ([][$qcx:expr, $name:ident, $key:expr]) => {{ - ($qcx.query_system.fns.local_providers.$name)($qcx, $key) + ([][$tcx:expr, $name:ident, $key:expr]) => {{ + ($tcx.query_system.fns.local_providers.$name)($tcx, $key) }}; - ([(separate_provide_extern) $($rest:tt)*][$qcx:expr, $name:ident, $key:expr]) => {{ + ([(separate_provide_extern) $($rest:tt)*][$tcx:expr, $name:ident, $key:expr]) => {{ if let Some(key) = $key.as_local_key() { - ($qcx.query_system.fns.local_providers.$name)($qcx, key) + ($tcx.query_system.fns.local_providers.$name)($tcx, key) } else { - ($qcx.query_system.fns.extern_providers.$name)($qcx, $key) + ($tcx.query_system.fns.extern_providers.$name)($tcx, $key) } }}; ([$other:tt $($modifiers:tt)*][$($args:tt)*]) => { @@ -341,7 +342,7 @@ pub(crate) fn create_query_frame< } pub(crate) fn encode_query_results<'a, 'tcx, Q>( - query: Q, + query: Q::Config, qcx: QueryCtxt<'tcx>, encoder: &mut CacheEncoder<'a, 'tcx>, query_result_index: &mut EncodedDepNodeIndex, @@ -392,12 +393,26 @@ pub(crate) fn loadable_from_disk<'tcx>(tcx: TyCtxt<'tcx>, id: SerializedDepNodeI pub(crate) fn try_load_from_disk<'tcx, V>( tcx: TyCtxt<'tcx>, - id: SerializedDepNodeIndex, + prev_index: SerializedDepNodeIndex, + index: DepNodeIndex, ) -> Option<V> where V: for<'a> Decodable<CacheDecoder<'a, 'tcx>>, { - tcx.query_system.on_disk_cache.as_ref()?.try_load_query_result(tcx, id) + let on_disk_cache = tcx.query_system.on_disk_cache.as_ref()?; + + let prof_timer = tcx.prof.incr_cache_loading(); + + // The call to `with_query_deserialization` enforces that no new `DepNodes` + // are created during deserialization. See the docs of that method for more + // details. + let value = tcx + .dep_graph + .with_query_deserialization(|| on_disk_cache.try_load_query_result(tcx, prev_index)); + + prof_timer.finish_with_query_invocation_id(index.into()); + + value } fn force_from_dep_node<'tcx, Q>(query: Q, tcx: TyCtxt<'tcx>, dep_node: DepNode) -> bool @@ -434,10 +449,9 @@ where pub(crate) fn query_callback<'tcx, Q>(is_anon: bool, is_eval_always: bool) -> DepKindStruct<'tcx> where - Q: QueryConfig<QueryCtxt<'tcx>> + Default, - Q::Key: DepNodeParams<TyCtxt<'tcx>>, + Q: QueryConfigRestored<'tcx>, { - let fingerprint_style = Q::Key::fingerprint_style(); + let fingerprint_style = <Q::Config as QueryConfig<QueryCtxt<'tcx>>>::Key::fingerprint_style(); if is_anon || !fingerprint_style.reconstructible() { return DepKindStruct { @@ -453,9 +467,11 @@ where is_anon, is_eval_always, fingerprint_style, - force_from_dep_node: Some(|tcx, dep_node| force_from_dep_node(Q::default(), tcx, dep_node)), + force_from_dep_node: Some(|tcx, dep_node| { + force_from_dep_node(Q::config(tcx), tcx, dep_node) + }), try_load_from_on_disk_cache: Some(|tcx, dep_node| { - try_load_from_on_disk_cache(Q::default(), tcx, dep_node) + try_load_from_on_disk_cache(Q::config(tcx), tcx, dep_node) }), } } @@ -478,7 +494,7 @@ macro_rules! define_queries { ( $($(#[$attr:meta])* [$($modifiers:tt)*] fn $name:ident($($K:tt)*) -> $V:ty,)*) => { - mod get_query { + mod get_query_incr { use super::*; $( @@ -490,8 +506,8 @@ macro_rules! define_queries { key: query_keys::$name<'tcx>, mode: QueryMode, ) -> Option<Erase<query_values::$name<'tcx>>> { - get_query( - queries::$name::default(), + get_query_incr( + queries::$name::config(tcx), QueryCtxt::new(tcx), span, key, @@ -501,9 +517,37 @@ macro_rules! define_queries { )* } - pub(crate) fn engine() -> QueryEngine { - QueryEngine { - $($name: get_query::$name,)* + mod get_query_non_incr { + use super::*; + + $( + #[inline(always)] + #[tracing::instrument(level = "trace", skip(tcx))] + pub(super) fn $name<'tcx>( + tcx: TyCtxt<'tcx>, + span: Span, + key: query_keys::$name<'tcx>, + __mode: QueryMode, + ) -> Option<Erase<query_values::$name<'tcx>>> { + Some(get_query_non_incr( + queries::$name::config(tcx), + QueryCtxt::new(tcx), + span, + key, + )) + } + )* + } + + pub(crate) fn engine(incremental: bool) -> QueryEngine { + if incremental { + QueryEngine { + $($name: get_query_incr::$name,)* + } + } else { + QueryEngine { + $($name: get_query_non_incr::$name,)* + } } } @@ -519,146 +563,91 @@ macro_rules! define_queries { )* } - $(impl<'tcx> QueryConfig<QueryCtxt<'tcx>> for queries::$name<'tcx> { - type Key = query_keys::$name<'tcx>; - type Value = Erase<query_values::$name<'tcx>>; - - #[inline(always)] - fn name(self) -> &'static str { - stringify!($name) - } - - #[inline] - fn format_value(self) -> fn(&Self::Value) -> String { - |value| format!("{:?}", restore::<query_values::$name<'tcx>>(*value)) - } - - #[inline] - fn cache_on_disk(self, tcx: TyCtxt<'tcx>, key: &Self::Key) -> bool { - ::rustc_middle::query::cached::$name(tcx, key) - } - - type Cache = query_storage::$name<'tcx>; - - #[inline(always)] - fn query_state<'a>(self, tcx: QueryCtxt<'tcx>) -> &'a QueryState<Self::Key, crate::dep_graph::DepKind> - where QueryCtxt<'tcx>: 'a - { - &tcx.query_system.states.$name - } - - #[inline(always)] - fn query_cache<'a>(self, tcx: QueryCtxt<'tcx>) -> &'a Self::Cache - where 'tcx:'a - { - &tcx.query_system.caches.$name - } - - fn execute_query(self, tcx: TyCtxt<'tcx>, key: Self::Key) -> Self::Value { - erase(tcx.$name(key)) - } - - #[inline] - #[allow(unused_variables)] - fn compute(self, qcx: QueryCtxt<'tcx>, key: Self::Key) -> Self::Value { - query_provided_to_value::$name( - qcx.tcx, - call_provider!([$($modifiers)*][qcx.tcx, $name, key]) - ) - } + #[allow(nonstandard_style)] + mod dynamic_query { + use super::*; - #[inline] - fn try_load_from_disk( - self, - _qcx: QueryCtxt<'tcx>, - _key: &Self::Key - ) -> rustc_query_system::query::TryLoadFromDisk<QueryCtxt<'tcx>, Self::Value> { - should_ever_cache_on_disk!([$($modifiers)*] { - if ::rustc_middle::query::cached::$name(_qcx.tcx, _key) { - Some(|qcx: QueryCtxt<'tcx>, dep_node| { - let value = $crate::plumbing::try_load_from_disk::<query_provided::$name<'tcx>>( - qcx.tcx, - dep_node - ); - value.map(|value| query_provided_to_value::$name(qcx.tcx, value)) - }) - } else { - None + $( + pub(super) fn $name<'tcx>() -> DynamicQuery<'tcx, query_storage::$name<'tcx>> { + DynamicQuery { + name: stringify!($name), + eval_always: is_eval_always!([$($modifiers)*]), + dep_kind: dep_graph::DepKind::$name, + handle_cycle_error: handle_cycle_error!([$($modifiers)*]), + query_state: offset_of!(QueryStates<'tcx> => $name), + query_cache: offset_of!(QueryCaches<'tcx> => $name), + cache_on_disk: |tcx, key| ::rustc_middle::query::cached::$name(tcx, key), + execute_query: |tcx, key| erase(tcx.$name(key)), + compute: |tcx, key| query_provided_to_value::$name( + tcx, + call_provider!([$($modifiers)*][tcx, $name, key]) + ), + can_load_from_disk: should_ever_cache_on_disk!([$($modifiers)*] true false), + try_load_from_disk: should_ever_cache_on_disk!([$($modifiers)*] { + |tcx, key, prev_index, index| { + if ::rustc_middle::query::cached::$name(tcx, key) { + let value = $crate::plumbing::try_load_from_disk::<query_provided::$name<'tcx>>( + tcx, + prev_index, + index, + ); + value.map(|value| query_provided_to_value::$name(tcx, value)) + } else { + None + } + } + } { + |_tcx, _key, _prev_index, _index| None + }), + value_from_cycle_error: |tcx, cycle| { + let result: query_values::$name<'tcx> = Value::from_cycle_error(tcx, cycle); + erase(result) + }, + loadable_from_disk: |_tcx, _key, _index| { + should_ever_cache_on_disk!([$($modifiers)*] { + ::rustc_middle::query::cached::$name(_tcx, _key) && + $crate::plumbing::loadable_from_disk(_tcx, _index) + } { + false + }) + }, + hash_result: hash_result!([$($modifiers)*][query_values::$name<'tcx>]), + format_value: |value| format!("{:?}", restore::<query_values::$name<'tcx>>(*value)), } - } { - None - }) - } - - #[inline] - fn loadable_from_disk( - self, - _qcx: QueryCtxt<'tcx>, - _key: &Self::Key, - _index: SerializedDepNodeIndex, - ) -> bool { - should_ever_cache_on_disk!([$($modifiers)*] { - self.cache_on_disk(_qcx.tcx, _key) && - $crate::plumbing::loadable_from_disk(_qcx.tcx, _index) - } { - false - }) - } - - #[inline] - fn value_from_cycle_error( - self, - tcx: TyCtxt<'tcx>, - cycle: &[QueryInfo<DepKind>], - ) -> Self::Value { - let result: query_values::$name<'tcx> = Value::from_cycle_error(tcx, cycle); - erase(result) - } - - #[inline(always)] - fn anon(self) -> bool { - is_anon!([$($modifiers)*]) - } - - #[inline(always)] - fn eval_always(self) -> bool { - is_eval_always!([$($modifiers)*]) - } - - #[inline(always)] - fn depth_limit(self) -> bool { - depth_limit!([$($modifiers)*]) - } - - #[inline(always)] - fn feedable(self) -> bool { - feedable!([$($modifiers)*]) - } + } + )* + } - #[inline(always)] - fn dep_kind(self) -> rustc_middle::dep_graph::DepKind { - dep_graph::DepKind::$name - } + $(impl<'tcx> QueryConfigRestored<'tcx> for queries::$name<'tcx> { + type RestoredValue = query_values::$name<'tcx>; + type Config = DynamicConfig< + 'tcx, + query_storage::$name<'tcx>, + { is_anon!([$($modifiers)*]) }, + { depth_limit!([$($modifiers)*]) }, + { feedable!([$($modifiers)*]) }, + >; #[inline(always)] - fn handle_cycle_error(self) -> rustc_query_system::HandleCycleError { - handle_cycle_error!([$($modifiers)*]) + fn config(tcx: TyCtxt<'tcx>) -> Self::Config { + DynamicConfig { + dynamic: &tcx.query_system.dynamic_queries.$name, + } } #[inline(always)] - fn hash_result(self) -> rustc_query_system::query::HashResult<Self::Value> { - hash_result!([$($modifiers)*][query_values::$name<'tcx>]) + fn restore(value: <Self::Config as QueryConfig<QueryCtxt<'tcx>>>::Value) -> Self::RestoredValue { + restore::<query_values::$name<'tcx>>(value) } })* - $(impl<'tcx> QueryConfigRestored<'tcx> for queries::$name<'tcx> { - type RestoredValue = query_values::$name<'tcx>; - - #[inline(always)] - fn restore(value: <Self as QueryConfig<QueryCtxt<'tcx>>>::Value) -> Self::RestoredValue { - restore::<query_values::$name<'tcx>>(value) + pub fn dynamic_queries<'tcx>() -> DynamicQueries<'tcx> { + DynamicQueries { + $( + $name: dynamic_query::$name(), + )* } - })* + } #[allow(nonstandard_style)] mod query_callbacks { @@ -730,6 +719,7 @@ macro_rules! define_queries { use rustc_middle::ty::query::QueryStruct; use rustc_middle::ty::query::QueryKeyStringCache; use rustc_middle::dep_graph::DepKind; + use crate::QueryConfigRestored; pub(super) const fn dummy_query_struct<'tcx>() -> QueryStruct<'tcx> { fn noop_try_collect_active_jobs(_: TyCtxt<'_>, _: &mut QueryMap<DepKind>) -> Option<()> { @@ -774,7 +764,7 @@ macro_rules! define_queries { }, encode_query_results: expand_if_cached!([$($modifiers)*], |tcx, encoder, query_result_index| $crate::plumbing::encode_query_results::<super::queries::$name<'tcx>>( - super::queries::$name::default(), + super::queries::$name::config(tcx), QueryCtxt::new(tcx), encoder, query_result_index, diff --git a/compiler/rustc_query_system/src/query/config.rs b/compiler/rustc_query_system/src/query/config.rs index bb9ea50a1ea..7e47d701205 100644 --- a/compiler/rustc_query_system/src/query/config.rs +++ b/compiler/rustc_query_system/src/query/config.rs @@ -4,6 +4,7 @@ use crate::dep_graph::{DepNode, DepNodeParams, SerializedDepNodeIndex}; use crate::error::HandleCycleError; use crate::ich::StableHashingContext; use crate::query::caches::QueryCache; +use crate::query::DepNodeIndex; use crate::query::{QueryContext, QueryInfo, QueryState}; use rustc_data_structures::fingerprint::Fingerprint; @@ -12,8 +13,6 @@ use std::hash::Hash; pub type HashResult<V> = Option<fn(&mut StableHashingContext<'_>, &V) -> Fingerprint>; -pub type TryLoadFromDisk<Qcx, V> = Option<fn(Qcx, SerializedDepNodeIndex) -> Option<V>>; - pub trait QueryConfig<Qcx: QueryContext>: Copy { fn name(self) -> &'static str; @@ -43,7 +42,13 @@ pub trait QueryConfig<Qcx: QueryContext>: Copy { fn compute(self, tcx: Qcx, key: Self::Key) -> Self::Value; - fn try_load_from_disk(self, qcx: Qcx, idx: &Self::Key) -> TryLoadFromDisk<Qcx, Self::Value>; + fn try_load_from_disk( + self, + tcx: Qcx, + key: &Self::Key, + prev_index: SerializedDepNodeIndex, + index: DepNodeIndex, + ) -> Option<Self::Value>; fn loadable_from_disk(self, qcx: Qcx, key: &Self::Key, idx: SerializedDepNodeIndex) -> bool; diff --git a/compiler/rustc_query_system/src/query/mod.rs b/compiler/rustc_query_system/src/query/mod.rs index fa1f51b04da..f7619d75be7 100644 --- a/compiler/rustc_query_system/src/query/mod.rs +++ b/compiler/rustc_query_system/src/query/mod.rs @@ -12,7 +12,7 @@ pub use self::caches::{ }; mod config; -pub use self::config::{HashResult, QueryConfig, TryLoadFromDisk}; +pub use self::config::{HashResult, QueryConfig}; use crate::dep_graph::DepKind; use crate::dep_graph::{DepNodeIndex, HasDepContext, SerializedDepNodeIndex}; diff --git a/compiler/rustc_query_system/src/query/plumbing.rs b/compiler/rustc_query_system/src/query/plumbing.rs index 3b17c665fb7..dbfe62ae6e9 100644 --- a/compiler/rustc_query_system/src/query/plumbing.rs +++ b/compiler/rustc_query_system/src/query/plumbing.rs @@ -312,7 +312,7 @@ where } #[inline(never)] -fn try_execute_query<Q, Qcx>( +fn try_execute_query<Q, Qcx, const INCR: bool>( query: Q, qcx: Qcx, span: Span, @@ -355,7 +355,7 @@ where // Drop the lock before we start executing the query drop(state_lock); - execute_job(query, qcx, state, key, id, dep_node) + execute_job::<_, _, INCR>(query, qcx, state, key, id, dep_node) } Entry::Occupied(mut entry) => { match entry.get_mut() { @@ -383,7 +383,7 @@ where } #[inline(always)] -fn execute_job<Q, Qcx>( +fn execute_job<Q, Qcx, const INCR: bool>( query: Q, qcx: Qcx, state: &QueryState<Q::Key, Qcx::DepKind>, @@ -398,9 +398,19 @@ where // Use `JobOwner` so the query will be poisoned if executing it panics. let job_owner = JobOwner { state, key }; - let (result, dep_node_index) = match qcx.dep_context().dep_graph().data() { - None => execute_job_non_incr(query, qcx, key, id), - Some(data) => execute_job_incr(query, qcx, data, key, dep_node, id), + debug_assert_eq!(qcx.dep_context().dep_graph().is_fully_enabled(), INCR); + + let (result, dep_node_index) = if INCR { + execute_job_incr( + query, + qcx, + qcx.dep_context().dep_graph().data().unwrap(), + key, + dep_node, + id, + ) + } else { + execute_job_non_incr(query, qcx, key, id) }; let cache = query.query_cache(qcx); @@ -564,59 +574,44 @@ where // First we try to load the result from the on-disk cache. // Some things are never cached on disk. - if let Some(try_load_from_disk) = query.try_load_from_disk(qcx, &key) { - let prof_timer = qcx.dep_context().profiler().incr_cache_loading(); - - // The call to `with_query_deserialization` enforces that no new `DepNodes` - // are created during deserialization. See the docs of that method for more - // details. - let result = qcx - .dep_context() - .dep_graph() - .with_query_deserialization(|| try_load_from_disk(qcx, prev_dep_node_index)); - - prof_timer.finish_with_query_invocation_id(dep_node_index.into()); - - if let Some(result) = result { - if std::intrinsics::unlikely( - qcx.dep_context().sess().opts.unstable_opts.query_dep_graph, - ) { - dep_graph_data.mark_debug_loaded_from_disk(*dep_node) - } - - let prev_fingerprint = dep_graph_data.prev_fingerprint_of(prev_dep_node_index); - // If `-Zincremental-verify-ich` is specified, re-hash results from - // the cache and make sure that they have the expected fingerprint. - // - // If not, we still seek to verify a subset of fingerprints loaded - // from disk. Re-hashing results is fairly expensive, so we can't - // currently afford to verify every hash. This subset should still - // give us some coverage of potential bugs though. - let try_verify = prev_fingerprint.split().1.as_u64() % 32 == 0; - if std::intrinsics::unlikely( - try_verify || qcx.dep_context().sess().opts.unstable_opts.incremental_verify_ich, - ) { - incremental_verify_ich( - *qcx.dep_context(), - dep_graph_data, - &result, - prev_dep_node_index, - query.hash_result(), - query.format_value(), - ); - } + if let Some(result) = query.try_load_from_disk(qcx, key, prev_dep_node_index, dep_node_index) { + if std::intrinsics::unlikely(qcx.dep_context().sess().opts.unstable_opts.query_dep_graph) { + dep_graph_data.mark_debug_loaded_from_disk(*dep_node) + } - return Some((result, dep_node_index)); + let prev_fingerprint = dep_graph_data.prev_fingerprint_of(prev_dep_node_index); + // If `-Zincremental-verify-ich` is specified, re-hash results from + // the cache and make sure that they have the expected fingerprint. + // + // If not, we still seek to verify a subset of fingerprints loaded + // from disk. Re-hashing results is fairly expensive, so we can't + // currently afford to verify every hash. This subset should still + // give us some coverage of potential bugs though. + let try_verify = prev_fingerprint.split().1.as_u64() % 32 == 0; + if std::intrinsics::unlikely( + try_verify || qcx.dep_context().sess().opts.unstable_opts.incremental_verify_ich, + ) { + incremental_verify_ich( + *qcx.dep_context(), + dep_graph_data, + &result, + prev_dep_node_index, + query.hash_result(), + query.format_value(), + ); } - // We always expect to find a cached result for things that - // can be forced from `DepNode`. - debug_assert!( - !qcx.dep_context().fingerprint_style(dep_node.kind).reconstructible(), - "missing on-disk cache entry for reconstructible {dep_node:?}" - ); + return Some((result, dep_node_index)); } + // We always expect to find a cached result for things that + // can be forced from `DepNode`. + debug_assert!( + !query.cache_on_disk(*qcx.dep_context(), key) + || !qcx.dep_context().fingerprint_style(dep_node.kind).reconstructible(), + "missing on-disk cache entry for {dep_node:?}" + ); + // Sanity check for the logic in `ensure`: if the node is green and the result loadable, // we should actually be able to load it. debug_assert!( @@ -799,7 +794,18 @@ pub enum QueryMode { } #[inline(always)] -pub fn get_query<Q, Qcx>( +pub fn get_query_non_incr<Q, Qcx>(query: Q, qcx: Qcx, span: Span, key: Q::Key) -> Q::Value +where + Q: QueryConfig<Qcx>, + Qcx: QueryContext, +{ + debug_assert!(!qcx.dep_context().dep_graph().is_fully_enabled()); + + ensure_sufficient_stack(|| try_execute_query::<Q, Qcx, false>(query, qcx, span, key, None).0) +} + +#[inline(always)] +pub fn get_query_incr<Q, Qcx>( query: Q, qcx: Qcx, span: Span, @@ -810,6 +816,8 @@ where Q: QueryConfig<Qcx>, Qcx: QueryContext, { + debug_assert!(qcx.dep_context().dep_graph().is_fully_enabled()); + let dep_node = if let QueryMode::Ensure { check_cache } = mode { let (must_run, dep_node) = ensure_must_run(query, qcx, &key, check_cache); if !must_run { @@ -820,8 +828,9 @@ where None }; - let (result, dep_node_index) = - ensure_sufficient_stack(|| try_execute_query(query, qcx, span, key, dep_node)); + let (result, dep_node_index) = ensure_sufficient_stack(|| { + try_execute_query::<_, _, true>(query, qcx, span, key, dep_node) + }); if let Some(dep_node_index) = dep_node_index { qcx.dep_context().dep_graph().read_index(dep_node_index) } @@ -846,5 +855,7 @@ pub fn force_query<Q, Qcx>( debug_assert!(!query.anon()); - ensure_sufficient_stack(|| try_execute_query(query, qcx, DUMMY_SP, key, Some(dep_node))); + ensure_sufficient_stack(|| { + try_execute_query::<_, _, true>(query, qcx, DUMMY_SP, key, Some(dep_node)) + }); } diff --git a/compiler/rustc_resolve/messages.ftl b/compiler/rustc_resolve/messages.ftl index ff8bd462dd8..345255c4c69 100644 --- a/compiler/rustc_resolve/messages.ftl +++ b/compiler/rustc_resolve/messages.ftl @@ -199,6 +199,10 @@ resolve_invalid_asm_sym = .label = is a local variable .help = `sym` operands must refer to either a function or a static +resolve_lowercase_self = + attempt to use a non-constant value in a constant + .suggestion = try using `Self` + resolve_trait_impl_duplicate = duplicate definitions with name `{$name}`: .label = duplicate definition diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 72cdce5c8f0..6675b8ed59b 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -948,6 +948,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { ResolutionError::InvalidAsmSym => { self.tcx.sess.create_err(errs::InvalidAsmSym { span }) } + ResolutionError::LowercaseSelf => { + self.tcx.sess.create_err(errs::LowercaseSelf { span }) + } } } diff --git a/compiler/rustc_resolve/src/effective_visibilities.rs b/compiler/rustc_resolve/src/effective_visibilities.rs index 87067189a77..7393bdb388a 100644 --- a/compiler/rustc_resolve/src/effective_visibilities.rs +++ b/compiler/rustc_resolve/src/effective_visibilities.rs @@ -199,7 +199,7 @@ impl<'r, 'a, 'tcx> EffectiveVisibilitiesVisitor<'r, 'a, 'tcx> { let tcx = self.r.tcx; self.changed |= self.import_effective_visibilities.update( binding, - nominal_vis, + Some(nominal_vis), || cheap_private_vis.unwrap_or_else(|| self.r.private_vis_import(binding)), inherited_eff_vis, parent_id.level(), @@ -213,7 +213,7 @@ impl<'r, 'a, 'tcx> EffectiveVisibilitiesVisitor<'r, 'a, 'tcx> { let tcx = self.r.tcx; self.changed |= self.def_effective_visibilities.update( def_id, - nominal_vis, + Some(nominal_vis), || cheap_private_vis.unwrap_or_else(|| self.r.private_vis_def(def_id)), inherited_eff_vis, parent_id.level(), diff --git a/compiler/rustc_resolve/src/errors.rs b/compiler/rustc_resolve/src/errors.rs index f6d7e8b4c87..2ab55f12637 100644 --- a/compiler/rustc_resolve/src/errors.rs +++ b/compiler/rustc_resolve/src/errors.rs @@ -443,6 +443,14 @@ pub(crate) struct InvalidAsmSym { } #[derive(Diagnostic)] +#[diag(resolve_lowercase_self)] +pub(crate) struct LowercaseSelf { + #[primary_span] + #[suggestion(code = "Self", applicability = "maybe-incorrect", style = "short")] + pub(crate) span: Span, +} + +#[derive(Diagnostic)] #[diag(resolve_trait_impl_duplicate, code = "E0201")] pub(crate) struct TraitImplDuplicate { #[primary_span] diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index 5a3ae656ad4..755acdd81fe 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -15,8 +15,7 @@ use std::ptr; use crate::errors::{ParamKindInEnumDiscriminant, ParamKindInNonTrivialAnonConst}; use crate::late::{ - ConstantHasGenerics, ConstantItemKind, HasGenericParams, NoConstantGenericsReason, PathSource, - Rib, RibKind, + ConstantHasGenerics, HasGenericParams, NoConstantGenericsReason, PathSource, Rib, RibKind, }; use crate::macros::{sub_namespace_match, MacroRulesScope}; use crate::{errors, AmbiguityError, AmbiguityErrorMisc, AmbiguityKind, Determinacy, Finalize}; @@ -1127,28 +1126,25 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { RibKind::ConstantItem(_, item) => { // Still doesn't deal with upvars if let Some(span) = finalize { - let (span, resolution_error) = - if let Some((ident, constant_item_kind)) = item { - let kind_str = match constant_item_kind { - ConstantItemKind::Const => "const", - ConstantItemKind::Static => "static", - }; - ( - span, - AttemptToUseNonConstantValueInConstant( - ident, "let", kind_str, - ), - ) - } else { - ( - rib_ident.span, - AttemptToUseNonConstantValueInConstant( - original_rib_ident_def, - "const", - "let", - ), - ) - }; + let (span, resolution_error) = match item { + None if rib_ident.as_str() == "self" => (span, LowercaseSelf), + None => ( + rib_ident.span, + AttemptToUseNonConstantValueInConstant( + original_rib_ident_def, + "const", + "let", + ), + ), + Some((ident, kind)) => ( + span, + AttemptToUseNonConstantValueInConstant( + ident, + "let", + kind.as_str(), + ), + ), + }; self.report_error(span, resolution_error); } return Res::Err; diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 2a8287d5554..c053ea222a0 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -150,6 +150,15 @@ pub(crate) enum ConstantItemKind { Static, } +impl ConstantItemKind { + pub(crate) fn as_str(&self) -> &'static str { + match self { + Self::Const => "const", + Self::Static => "static", + } + } +} + #[derive(Debug, Copy, Clone, PartialEq, Eq)] enum RecordPartialRes { Yes, @@ -1482,7 +1491,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { if let Some(&(_, res)) = rib.bindings.get(&normalized_ident) { self.record_lifetime_res(lifetime.id, res, LifetimeElisionCandidate::Named); - if let LifetimeRes::Param { param, .. } = res { + if let LifetimeRes::Param { param, binder } = res { match self.lifetime_uses.entry(param) { Entry::Vacant(v) => { debug!("First use of {:?} at {:?}", res, ident.span); @@ -1496,10 +1505,16 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { LifetimeRibKind::Item | LifetimeRibKind::AnonymousReportError | LifetimeRibKind::ElisionFailure => Some(LifetimeUseSet::Many), - // An anonymous lifetime is legal here, go ahead. - LifetimeRibKind::AnonymousCreateParameter { .. } => { - Some(LifetimeUseSet::One { use_span: ident.span, use_ctxt }) - } + // An anonymous lifetime is legal here, and bound to the right + // place, go ahead. + LifetimeRibKind::AnonymousCreateParameter { + binder: anon_binder, + .. + } => Some(if binder == anon_binder { + LifetimeUseSet::One { use_span: ident.span, use_ctxt } + } else { + LifetimeUseSet::Many + }), // Only report if eliding the lifetime would have the same // semantics. LifetimeRibKind::Elided(r) => Some(if res == r { @@ -3528,10 +3543,6 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { // // Similar thing, for types, happens in `report_errors` above. let report_errors_for_call = |this: &mut Self, parent_err: Spanned<ResolutionError<'a>>| { - if !source.is_call() { - return Some(parent_err); - } - // Before we start looking for candidates, we have to get our hands // on the type user is trying to perform invocation on; basically: // we're transforming `HashMap::new` into just `HashMap`. diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 590609f9ed3..323b78fcd98 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -47,6 +47,7 @@ use rustc_index::IndexVec; use rustc_metadata::creader::{CStore, CrateLoader}; use rustc_middle::metadata::ModChild; use rustc_middle::middle::privacy::EffectiveVisibilities; +use rustc_middle::query::Providers; use rustc_middle::span_bug; use rustc_middle::ty::{self, MainDefinition, RegisteredTools, TyCtxt}; use rustc_middle::ty::{ResolverGlobalCtxt, ResolverOutputs}; @@ -251,6 +252,8 @@ enum ResolutionError<'a> { TraitImplDuplicate { name: Symbol, trait_item_span: Span, old_span: Span }, /// Inline asm `sym` operand must refer to a `fn` or `static`. InvalidAsmSym, + /// `self` used instead of `Self` in a generic parameter + LowercaseSelf, } enum VisResolutionError<'a> { @@ -2024,6 +2027,6 @@ impl Finalize { } } -pub fn provide(providers: &mut ty::query::Providers) { +pub fn provide(providers: &mut Providers) { providers.registered_tools = macros::registered_tools; } diff --git a/compiler/rustc_serialize/src/opaque.rs b/compiler/rustc_serialize/src/opaque.rs index 6b559cb5b2f..0ffc537eee0 100644 --- a/compiler/rustc_serialize/src/opaque.rs +++ b/compiler/rustc_serialize/src/opaque.rs @@ -1,4 +1,4 @@ -use crate::leb128::{self, largest_max_leb128_len}; +use crate::leb128; use crate::serialize::{Decodable, Decoder, Encodable, Encoder}; use std::fs::File; use std::io::{self, Write}; @@ -14,6 +14,9 @@ use std::ptr; pub type FileEncodeResult = Result<usize, io::Error>; +/// The size of the buffer in `FileEncoder`. +const BUF_SIZE: usize = 8192; + /// `FileEncoder` encodes data to file via fixed-size buffer. /// /// There used to be a `MemEncoder` type that encoded all the data into a @@ -35,26 +38,12 @@ pub struct FileEncoder { impl FileEncoder { pub fn new<P: AsRef<Path>>(path: P) -> io::Result<Self> { - const DEFAULT_BUF_SIZE: usize = 8192; - FileEncoder::with_capacity(path, DEFAULT_BUF_SIZE) - } - - pub fn with_capacity<P: AsRef<Path>>(path: P, capacity: usize) -> io::Result<Self> { - // Require capacity at least as large as the largest LEB128 encoding - // here, so that we don't have to check or handle this on every write. - assert!(capacity >= largest_max_leb128_len()); - - // Require capacity small enough such that some capacity checks can be - // done using guaranteed non-overflowing add rather than sub, which - // shaves an instruction off those code paths (on x86 at least). - assert!(capacity <= usize::MAX - largest_max_leb128_len()); - // Create the file for reading and writing, because some encoders do both // (e.g. the metadata encoder when -Zmeta-stats is enabled) let file = File::options().read(true).write(true).create(true).truncate(true).open(path)?; Ok(FileEncoder { - buf: Box::new_uninit_slice(capacity), + buf: Box::new_uninit_slice(BUF_SIZE), buffered: 0, flushed: 0, file, @@ -160,18 +149,10 @@ impl FileEncoder { } #[inline] - fn capacity(&self) -> usize { - self.buf.len() - } - - #[inline] fn write_one(&mut self, value: u8) { - // We ensure this during `FileEncoder` construction. - debug_assert!(self.capacity() >= 1); - let mut buffered = self.buffered; - if std::intrinsics::unlikely(buffered >= self.capacity()) { + if std::intrinsics::unlikely(buffered + 1 > BUF_SIZE) { self.flush(); buffered = 0; } @@ -187,13 +168,12 @@ impl FileEncoder { #[inline] fn write_all(&mut self, buf: &[u8]) { - let capacity = self.capacity(); let buf_len = buf.len(); - if std::intrinsics::likely(buf_len <= capacity) { + if std::intrinsics::likely(buf_len <= BUF_SIZE) { let mut buffered = self.buffered; - if std::intrinsics::unlikely(buf_len > capacity - buffered) { + if std::intrinsics::unlikely(buffered + buf_len > BUF_SIZE) { self.flush(); buffered = 0; } @@ -271,13 +251,11 @@ macro_rules! write_leb128 { fn $this_fn(&mut self, v: $int_ty) { const MAX_ENCODED_LEN: usize = $crate::leb128::max_leb128_len::<$int_ty>(); - // We ensure this during `FileEncoder` construction. - debug_assert!(self.capacity() >= MAX_ENCODED_LEN); - let mut buffered = self.buffered; - // This can't overflow. See assertion in `FileEncoder::with_capacity`. - if std::intrinsics::unlikely(buffered + MAX_ENCODED_LEN > self.capacity()) { + // This can't overflow because BUF_SIZE and MAX_ENCODED_LEN are both + // quite small. + if std::intrinsics::unlikely(buffered + MAX_ENCODED_LEN > BUF_SIZE) { self.flush(); buffered = 0; } diff --git a/compiler/rustc_session/Cargo.toml b/compiler/rustc_session/Cargo.toml index 3477b97438c..3af83aaaaa8 100644 --- a/compiler/rustc_session/Cargo.toml +++ b/compiler/rustc_session/Cargo.toml @@ -25,7 +25,7 @@ termize = "0.1.1" libc = "0.2" [target.'cfg(windows)'.dependencies.windows] -version = "0.46.0" +version = "0.48.0" features = [ "Win32_Foundation", "Win32_System_LibraryLoader", diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index aa3cb03bad8..e2b8d3eea2d 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -1060,6 +1060,9 @@ fn default_configuration(sess: &Session) -> CrateConfig { if sess.opts.debug_assertions { ret.insert((sym::debug_assertions, None)); } + if sess.overflow_checks() { + ret.insert((sym::overflow_checks, None)); + } // JUSTIFICATION: before wrapper fn is available #[allow(rustc::bad_opt_access)] if sess.opts.crate_types.contains(&CrateType::ProcMacro) { @@ -1209,6 +1212,7 @@ impl CrateCheckConfig { sym::windows, sym::proc_macro, sym::debug_assertions, + sym::overflow_checks, sym::target_thread_local, ] { self.expecteds.entry(name).or_insert_with(no_values); diff --git a/compiler/rustc_session/src/cstore.rs b/compiler/rustc_session/src/cstore.rs index dd1721801f3..dc475e8c6d5 100644 --- a/compiler/rustc_session/src/cstore.rs +++ b/compiler/rustc_session/src/cstore.rs @@ -6,7 +6,8 @@ use crate::search_paths::PathKind; use crate::utils::NativeLibKind; use crate::Session; use rustc_ast as ast; -use rustc_data_structures::sync::{self, AppendOnlyIndexVec, MetadataRef, RwLock}; +use rustc_data_structures::owned_slice::OwnedSlice; +use rustc_data_structures::sync::{self, AppendOnlyIndexVec, RwLock}; use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, StableCrateId, LOCAL_CRATE}; use rustc_hir::definitions::{DefKey, DefPath, DefPathHash, Definitions}; use rustc_span::hygiene::{ExpnHash, ExpnId}; @@ -203,11 +204,11 @@ pub enum ExternCrateSource { /// metadata in library -- this trait just serves to decouple rustc_metadata from /// the archive reader, which depends on LLVM. pub trait MetadataLoader: std::fmt::Debug { - fn get_rlib_metadata(&self, target: &Target, filename: &Path) -> Result<MetadataRef, String>; - fn get_dylib_metadata(&self, target: &Target, filename: &Path) -> Result<MetadataRef, String>; + fn get_rlib_metadata(&self, target: &Target, filename: &Path) -> Result<OwnedSlice, String>; + fn get_dylib_metadata(&self, target: &Target, filename: &Path) -> Result<OwnedSlice, String>; } -pub type MetadataLoaderDyn = dyn MetadataLoader + Send + Sync; +pub type MetadataLoaderDyn = dyn MetadataLoader + Send + Sync + sync::DynSend + sync::DynSync; /// A store of Rust crates, through which their metadata can be accessed. /// @@ -252,7 +253,7 @@ pub trait CrateStore: std::fmt::Debug { fn import_source_files(&self, sess: &Session, cnum: CrateNum); } -pub type CrateStoreDyn = dyn CrateStore + sync::Sync + sync::Send; +pub type CrateStoreDyn = dyn CrateStore + sync::DynSync + sync::DynSend; pub struct Untracked { pub cstore: RwLock<Box<CrateStoreDyn>>, diff --git a/compiler/rustc_session/src/filesearch.rs b/compiler/rustc_session/src/filesearch.rs index 7fdbd48d563..3988416d0c7 100644 --- a/compiler/rustc_session/src/filesearch.rs +++ b/compiler/rustc_session/src/filesearch.rs @@ -135,13 +135,13 @@ fn current_dll_path() -> Result<PathBuf, String> { use windows::{ core::PCWSTR, - Win32::Foundation::HINSTANCE, + Win32::Foundation::HMODULE, Win32::System::LibraryLoader::{ GetModuleFileNameW, GetModuleHandleExW, GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, }, }; - let mut module = HINSTANCE::default(); + let mut module = HMODULE::default(); unsafe { GetModuleHandleExW( GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index 7bbab34c69a..97cb734619e 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -20,6 +20,7 @@ #![feature(min_specialization)] #![feature(rustc_attrs)] #![feature(let_chains)] +#![feature(round_char_boundary)] #![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::diagnostic_outside_of_impl)] diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs index 1294a8b8e6b..11ea5fe4ddf 100644 --- a/compiler/rustc_span/src/source_map.rs +++ b/compiler/rustc_span/src/source_map.rs @@ -14,7 +14,9 @@ pub use crate::*; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::stable_hasher::{Hash128, Hash64, StableHasher}; -use rustc_data_structures::sync::{AtomicU32, Lrc, MappedReadGuard, ReadGuard, RwLock}; +use rustc_data_structures::sync::{ + AtomicU32, IntoDynSyncSend, Lrc, MappedReadGuard, ReadGuard, RwLock, +}; use std::cmp; use std::hash::Hash; use std::path::{self, Path, PathBuf}; @@ -176,7 +178,7 @@ pub struct SourceMap { used_address_space: AtomicU32, files: RwLock<SourceMapFiles>, - file_loader: Box<dyn FileLoader + Sync + Send>, + file_loader: IntoDynSyncSend<Box<dyn FileLoader + Sync + Send>>, // This is used to apply the file path remapping as specified via // `--remap-path-prefix` to all `SourceFile`s allocated within this `SourceMap`. path_mapping: FilePathMapping, @@ -202,7 +204,7 @@ impl SourceMap { SourceMap { used_address_space: AtomicU32::new(0), files: Default::default(), - file_loader, + file_loader: IntoDynSyncSend(file_loader), path_mapping, hash_kind, } @@ -1017,36 +1019,19 @@ impl SourceMap { let src = local_begin.sf.external_src.borrow(); - // We need to extend the snippet to the end of the src rather than to end_index so when - // searching forwards for boundaries we've got somewhere to search. - let snippet = if let Some(ref src) = local_begin.sf.src { - &src[start_index..] + let snippet = if let Some(src) = &local_begin.sf.src { + src } else if let Some(src) = src.get_source() { - &src[start_index..] + src } else { return 1; }; - debug!("snippet=`{:?}`", snippet); - let mut target = if forwards { end_index + 1 } else { end_index - 1 }; - debug!("initial target=`{:?}`", target); - - while !snippet.is_char_boundary(target - start_index) && target < source_len { - target = if forwards { - target + 1 - } else { - match target.checked_sub(1) { - Some(target) => target, - None => { - break; - } - } - }; - debug!("target=`{:?}`", target); + if forwards { + (snippet.ceil_char_boundary(end_index + 1) - end_index) as u32 + } else { + (end_index - snippet.floor_char_boundary(end_index - 1)) as u32 } - debug!("final target=`{:?}`", target); - - if forwards { (target - end_index) as u32 } else { (end_index - target) as u32 } } pub fn get_source_file(&self, filename: &FileName) -> Option<Lrc<SourceFile>> { diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 60efcb768cb..9951d8f4fc1 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -463,6 +463,7 @@ symbols! { cfg_doctest, cfg_eval, cfg_hide, + cfg_overflow_checks, cfg_panic, cfg_sanitize, cfg_target_abi, @@ -1065,6 +1066,7 @@ symbols! { or_patterns, other, out, + overflow_checks, overlapping_marker_traits, owned_box, packed, diff --git a/compiler/rustc_symbol_mangling/src/lib.rs b/compiler/rustc_symbol_mangling/src/lib.rs index c97406868b6..692542da78e 100644 --- a/compiler/rustc_symbol_mangling/src/lib.rs +++ b/compiler/rustc_symbol_mangling/src/lib.rs @@ -107,7 +107,7 @@ use rustc_hir::def_id::{CrateNum, LOCAL_CRATE}; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs; use rustc_middle::mir::mono::{InstantiationMode, MonoItem}; -use rustc_middle::ty::query::Providers; +use rustc_middle::query::Providers; use rustc_middle::ty::subst::SubstsRef; use rustc_middle::ty::{self, Instance, TyCtxt}; use rustc_session::config::SymbolManglingVersion; diff --git a/compiler/rustc_symbol_mangling/src/typeid.rs b/compiler/rustc_symbol_mangling/src/typeid.rs index 81dbff9ea4e..cda16e3a3f5 100644 --- a/compiler/rustc_symbol_mangling/src/typeid.rs +++ b/compiler/rustc_symbol_mangling/src/typeid.rs @@ -4,7 +4,7 @@ /// For more information about LLVM CFI and cross-language LLVM CFI support for the Rust compiler, /// see design document in the tracking issue #89653. use bitflags::bitflags; -use rustc_middle::ty::{FnSig, Ty, TyCtxt}; +use rustc_middle::ty::{FnSig, Instance, Ty, TyCtxt}; use rustc_target::abi::call::FnAbi; use std::hash::Hasher; use twox_hash::XxHash64; @@ -38,6 +38,15 @@ pub fn typeid_for_fnsig<'tcx>( typeid_itanium_cxx_abi::typeid_for_fnsig(tcx, fn_sig, options) } +/// Returns a type metadata identifier for the specified Instance. +pub fn typeid_for_instance<'tcx>( + tcx: TyCtxt<'tcx>, + instance: &Instance<'tcx>, + options: TypeIdOptions, +) -> String { + typeid_itanium_cxx_abi::typeid_for_instance(tcx, instance, options) +} + /// Returns a KCFI type metadata identifier for the specified FnAbi. pub fn kcfi_typeid_for_fnabi<'tcx>( tcx: TyCtxt<'tcx>, @@ -63,3 +72,16 @@ pub fn kcfi_typeid_for_fnsig<'tcx>( hash.write(typeid_itanium_cxx_abi::typeid_for_fnsig(tcx, fn_sig, options).as_bytes()); hash.finish() as u32 } + +/// Returns a KCFI type metadata identifier for the specified Instance. +pub fn kcfi_typeid_for_instance<'tcx>( + tcx: TyCtxt<'tcx>, + instance: &Instance<'tcx>, + options: TypeIdOptions, +) -> u32 { + // A KCFI type metadata identifier is a 32-bit constant produced by taking the lower half of the + // xxHash64 of the type metadata identifier. (See llvm/llvm-project@cff5bef.) + let mut hash: XxHash64 = Default::default(); + hash.write(typeid_itanium_cxx_abi::typeid_for_instance(tcx, instance, options).as_bytes()); + hash.finish() as u32 +} diff --git a/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs b/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs index 5310ef26da7..c281aa7e83a 100644 --- a/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs +++ b/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs @@ -14,8 +14,8 @@ use rustc_errors::DiagnosticMessage; use rustc_hir as hir; use rustc_middle::ty::subst::{GenericArg, GenericArgKind, SubstsRef}; use rustc_middle::ty::{ - self, Const, ExistentialPredicate, FloatTy, FnSig, IntTy, List, Region, RegionKind, TermKind, - Ty, TyCtxt, UintTy, + self, Const, ExistentialPredicate, FloatTy, FnSig, Instance, IntTy, List, Region, RegionKind, + TermKind, Ty, TyCtxt, UintTy, }; use rustc_span::def_id::DefId; use rustc_span::sym; @@ -1010,3 +1010,56 @@ pub fn typeid_for_fnsig<'tcx>( typeid } + +/// Returns a type metadata identifier for the specified Instance using the Itanium C++ ABI with +/// vendor extended type qualifiers and types for Rust types that are not used at the FFI boundary. +pub fn typeid_for_instance<'tcx>( + tcx: TyCtxt<'tcx>, + instance: &Instance<'tcx>, + options: TypeIdOptions, +) -> String { + let fn_abi = tcx + .fn_abi_of_instance(tcx.param_env(instance.def_id()).and((*instance, ty::List::empty()))) + .unwrap_or_else(|instance| { + bug!("typeid_for_instance: couldn't get fn_abi of instance {:?}", instance) + }); + + // If this instance is a method and self is a reference, get the impl it belongs to + let impl_def_id = tcx.impl_of_method(instance.def_id()); + if impl_def_id.is_some() && !fn_abi.args.is_empty() && fn_abi.args[0].layout.ty.is_ref() { + // If this impl is not an inherent impl, get the trait it implements + if let Some(trait_ref) = tcx.impl_trait_ref(impl_def_id.unwrap()) { + // Transform the concrete self into a reference to a trait object + let existential_predicate = trait_ref.map_bound(|trait_ref| { + ty::ExistentialPredicate::Trait(ty::ExistentialTraitRef::erase_self_ty( + tcx, trait_ref, + )) + }); + let existential_predicates = tcx.mk_poly_existential_predicates(&[ty::Binder::dummy( + existential_predicate.skip_binder(), + )]); + // Is the concrete self mutable? + let self_ty = if fn_abi.args[0].layout.ty.is_mutable_ptr() { + tcx.mk_mut_ref( + tcx.lifetimes.re_erased, + tcx.mk_dynamic(existential_predicates, tcx.lifetimes.re_erased, ty::Dyn), + ) + } else { + tcx.mk_imm_ref( + tcx.lifetimes.re_erased, + tcx.mk_dynamic(existential_predicates, tcx.lifetimes.re_erased, ty::Dyn), + ) + }; + + // Replace the concrete self in an fn_abi clone by the reference to a trait object + let mut fn_abi = fn_abi.clone(); + // HACK(rcvalle): It is okay to not replace or update the entire ArgAbi here because the + // other fields are never used. + fn_abi.args[0].layout.ty = self_ty; + + return typeid_for_fnabi(tcx, &fn_abi, options); + } + } + + typeid_for_fnabi(tcx, &fn_abi, options) +} diff --git a/compiler/rustc_target/src/abi/call/mod.rs b/compiler/rustc_target/src/abi/call/mod.rs index 52159a7b06a..1ae11f5671c 100644 --- a/compiler/rustc_target/src/abi/call/mod.rs +++ b/compiler/rustc_target/src/abi/call/mod.rs @@ -28,7 +28,7 @@ mod x86; mod x86_64; mod x86_win64; -#[derive(PartialEq, Eq, Hash, Debug, HashStable_Generic)] +#[derive(Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)] pub enum PassMode { /// Ignore the argument. /// @@ -211,7 +211,7 @@ impl Uniform { } } -#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, HashStable_Generic)] +#[derive(Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)] pub struct CastTarget { pub prefix: [Option<Reg>; 8], pub rest: Uniform, @@ -458,7 +458,7 @@ impl<'a, Ty> TyAndLayout<'a, Ty> { /// Information about how to pass an argument to, /// or return a value from, a function, under some ABI. -#[derive(PartialEq, Eq, Hash, Debug, HashStable_Generic)] +#[derive(Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)] pub struct ArgAbi<'a, Ty> { pub layout: TyAndLayout<'a, Ty>, pub mode: PassMode, @@ -605,7 +605,7 @@ pub enum Conv { /// /// I will do my best to describe this structure, but these /// comments are reverse-engineered and may be inaccurate. -NDM -#[derive(PartialEq, Eq, Hash, Debug, HashStable_Generic)] +#[derive(Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)] pub struct FnAbi<'a, Ty> { /// The LLVM types of each argument. pub args: Box<[ArgAbi<'a, Ty>]>, diff --git a/compiler/rustc_target/src/asm/mod.rs b/compiler/rustc_target/src/asm/mod.rs index 705966f5237..e60b8e78e5d 100644 --- a/compiler/rustc_target/src/asm/mod.rs +++ b/compiler/rustc_target/src/asm/mod.rs @@ -882,8 +882,8 @@ impl InlineAsmClobberAbi { _ => Err(&["C", "system", "efiapi"]), }, InlineAsmArch::LoongArch64 => match name { - "C" | "system" | "efiapi" => Ok(InlineAsmClobberAbi::LoongArch), - _ => Err(&["C", "system", "efiapi"]), + "C" | "system" => Ok(InlineAsmClobberAbi::LoongArch), + _ => Err(&["C", "system"]), }, _ => Err(&[]), } diff --git a/compiler/rustc_trait_selection/src/solve/project_goals.rs b/compiler/rustc_trait_selection/src/solve/project_goals.rs index 20ce2d9416e..d3228074421 100644 --- a/compiler/rustc_trait_selection/src/solve/project_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/project_goals.rs @@ -124,10 +124,24 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { }; if !assoc_def.item.defaultness(tcx).has_value() { - tcx.sess.delay_span_bug( + let guar = tcx.sess.delay_span_bug( tcx.def_span(assoc_def.item.def_id), "missing value for assoc item in impl", ); + let error_term = match assoc_def.item.kind { + ty::AssocKind::Const => tcx + .const_error( + tcx.type_of(goal.predicate.def_id()) + .subst(tcx, goal.predicate.projection_ty.substs), + guar, + ) + .into(), + ty::AssocKind::Type => tcx.ty_error(guar).into(), + ty::AssocKind::Fn => unreachable!(), + }; + ecx.eq(goal.param_env, goal.predicate.term, error_term) + .expect("expected goal term to be fully unconstrained"); + return ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes); } // Getting the right substitutions here is complex, e.g. given: diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs index 6b080a132f3..183c2401fc3 100644 --- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs +++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs @@ -801,7 +801,7 @@ impl<'tcx> AutoTraitFinder<'tcx> { span: tcx.def_span(unevaluated.def), unevaluated: unevaluated, }); - Err(ErrorHandled::Reported(reported)) + Err(ErrorHandled::Reported(reported.into())) } Err(err) => Err(err), } diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index 9d99d30d45c..bd1ea43a78e 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -79,7 +79,7 @@ pub fn is_const_evaluatable<'tcx>( "Missing value for constant, but no error reported?", ))) } - Err(ErrorHandled::Reported(e)) => Err(NotConstEvaluatable::Error(e)), + Err(ErrorHandled::Reported(e)) => Err(NotConstEvaluatable::Error(e.into())), Ok(_) => Ok(()), } } @@ -147,7 +147,7 @@ pub fn is_const_evaluatable<'tcx>( Err(err) } - Err(ErrorHandled::Reported(e)) => Err(NotConstEvaluatable::Error(e)), + Err(ErrorHandled::Reported(e)) => Err(NotConstEvaluatable::Error(e.into())), Ok(_) => Ok(()), } } 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 c9e2ed092d1..f5f2fe54217 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -28,6 +28,7 @@ use rustc_hir::{GenericParam, Item, Node}; use rustc_infer::infer::error_reporting::TypeErrCtxt; use rustc_infer::infer::{InferOk, TypeTrace}; use rustc_middle::traits::select::OverflowError; +use rustc_middle::traits::SelectionOutputTypeParameterMismatch; use rustc_middle::ty::abstract_const::NotConstEvaluatable; use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::fold::{TypeFolder, TypeSuperFoldable}; @@ -796,9 +797,17 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { err.span_label(span, explanation); } - if let ObligationCauseCode::ObjectCastObligation(concrete_ty, obj_ty) = obligation.cause.code().peel_derives() && - Some(trait_ref.def_id()) == self.tcx.lang_items().sized_trait() { - self.suggest_borrowing_for_object_cast(&mut err, &root_obligation, *concrete_ty, *obj_ty); + if let ObligationCauseCode::Coercion { source, target } = + *obligation.cause.code().peel_derives() + { + if Some(trait_ref.def_id()) == self.tcx.lang_items().sized_trait() { + self.suggest_borrowing_for_object_cast( + &mut err, + &root_obligation, + source, + target, + ); + } } let UnsatisfiedConst(unsatisfied_const) = self @@ -1087,17 +1096,21 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } } - OutputTypeParameterMismatch( + OutputTypeParameterMismatch(box SelectionOutputTypeParameterMismatch { found_trait_ref, expected_trait_ref, - terr @ TypeError::CyclicTy(_), - ) => self.report_type_parameter_mismatch_cyclic_type_error( + terr: terr @ TypeError::CyclicTy(_), + }) => self.report_type_parameter_mismatch_cyclic_type_error( &obligation, found_trait_ref, expected_trait_ref, terr, ), - OutputTypeParameterMismatch(found_trait_ref, expected_trait_ref, _) => { + OutputTypeParameterMismatch(box SelectionOutputTypeParameterMismatch { + found_trait_ref, + expected_trait_ref, + terr: _, + }) => { match self.report_type_parameter_mismatch_error( &obligation, span, @@ -1505,7 +1518,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { | ObligationCauseCode::BindingObligation(_, _) | ObligationCauseCode::ExprItemObligation(..) | ObligationCauseCode::ExprBindingObligation(..) - | ObligationCauseCode::ObjectCastObligation(..) + | ObligationCauseCode::Coercion { .. } | ObligationCauseCode::OpaqueType ); diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 53bf38c0a34..ea17f23434b 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -1442,8 +1442,9 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { err: &mut Diagnostic, obligation: &PredicateObligation<'tcx>, self_ty: Ty<'tcx>, - object_ty: Ty<'tcx>, + target_ty: Ty<'tcx>, ) { + let ty::Ref(_, object_ty, hir::Mutability::Not) = target_ty.kind() else { return; }; let ty::Dynamic(predicates, _, ty::Dyn) = object_ty.kind() else { return; }; let self_ref_ty = self.tcx.mk_imm_ref(self.tcx.lifetimes.re_erased, self_ty); @@ -1458,7 +1459,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { err.span_suggestion( obligation.cause.span.shrink_to_lo(), format!( - "consider borrowing the value, since `&{self_ty}` can be coerced into `{object_ty}`" + "consider borrowing the value, since `&{self_ty}` can be coerced into `{target_ty}`" ), "&", Applicability::MaybeIncorrect, @@ -2446,10 +2447,9 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { && generator_did.is_local() // Try to avoid cycles. && !generator_within_in_progress_typeck + && let Some(generator_info) = self.tcx.mir_generator_witnesses(generator_did) { - let generator_info = &self.tcx.mir_generator_witnesses(generator_did); debug!(?generator_info); - 'find_source: for (variant, source_info) in generator_info.variant_fields.iter().zip(&generator_info.variant_source_info) { @@ -2851,30 +2851,27 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { err.span_note(tcx.def_span(item_def_id), descr); } } - ObligationCauseCode::ObjectCastObligation(concrete_ty, object_ty) => { - let (concrete_ty, concrete_file) = - self.tcx.short_ty_string(self.resolve_vars_if_possible(concrete_ty)); - let (object_ty, object_file) = - self.tcx.short_ty_string(self.resolve_vars_if_possible(object_ty)); + ObligationCauseCode::Coercion { source, target } => { + let (source, source_file) = + self.tcx.short_ty_string(self.resolve_vars_if_possible(source)); + let (target, target_file) = + self.tcx.short_ty_string(self.resolve_vars_if_possible(target)); err.note(with_forced_trimmed_paths!(format!( - "required for the cast from `{concrete_ty}` to the object type `{object_ty}`", + "required for the cast from `{source}` to `{target}`", ))); - if let Some(file) = concrete_file { + if let Some(file) = source_file { err.note(format!( - "the full name for the casted type has been written to '{}'", + "the full name for the source type has been written to '{}'", file.display(), )); } - if let Some(file) = object_file { + if let Some(file) = target_file { err.note(format!( - "the full name for the object type has been written to '{}'", + "the full name for the target type has been written to '{}'", file.display(), )); } } - ObligationCauseCode::Coercion { source: _, target } => { - err.note(format!("required by cast to type `{}`", self.ty_to_string(target))); - } ObligationCauseCode::RepeatElementCopy { is_const_fn } => { err.note( "the `Copy` trait is required because this value will be copied for each element of the array", diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index 43196d1e629..2f85c32b575 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -615,7 +615,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { (Err(ErrorHandled::Reported(reported)), _) | (_, Err(ErrorHandled::Reported(reported))) => ProcessResult::Error( CodeSelectionError(SelectionError::NotConstEvaluatable( - NotConstEvaluatable::Error(reported), + NotConstEvaluatable::Error(reported.into()), )), ), (Err(ErrorHandled::TooGeneric), _) | (_, Err(ErrorHandled::TooGeneric)) => { diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 38daca5377a..223cdc48f0b 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -26,6 +26,7 @@ use crate::infer::{InferCtxt, TyCtxtInferExt}; use crate::traits::error_reporting::TypeErrCtxtExt as _; use crate::traits::query::evaluate_obligation::InferCtxtExt as _; use rustc_errors::ErrorGuaranteed; +use rustc_middle::query::Providers; use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::visit::{TypeVisitable, TypeVisitableExt}; use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, TypeSuperVisitable}; @@ -498,10 +499,10 @@ fn is_impossible_method(tcx: TyCtxt<'_>, (impl_def_id, trait_item_def_id): (DefI false } -pub fn provide(providers: &mut ty::query::Providers) { +pub fn provide(providers: &mut Providers) { object_safety::provide(providers); vtable::provide(providers); - *providers = ty::query::Providers { + *providers = Providers { specialization_graph_of: specialize::specialization_graph_provider, specializes: specialize::specializes, subst_and_check_impossible_predicates, diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index 06d9c10386e..c81bf6ebc2e 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -16,6 +16,7 @@ use crate::traits::{self, Obligation, ObligationCause}; use rustc_errors::{DelayDm, FatalError, MultiSpan}; use rustc_hir as hir; use rustc_hir::def_id::DefId; +use rustc_middle::query::Providers; use rustc_middle::ty::subst::{GenericArg, InternalSubsts}; use rustc_middle::ty::{ self, EarlyBinder, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor, @@ -947,7 +948,6 @@ pub fn contains_illegal_impl_trait_in_trait<'tcx>( }) } -pub fn provide(providers: &mut ty::query::Providers) { - *providers = - ty::query::Providers { object_safety_violations, check_is_object_safe, ..*providers }; +pub fn provide(providers: &mut Providers) { + *providers = Providers { object_safety_violations, check_is_object_safe, ..*providers }; } diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 616187b69dd..6a648294efd 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -10,6 +10,7 @@ use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_hir::lang_items::LangItem; use rustc_infer::infer::LateBoundRegionConversionTime::HigherRankedType; use rustc_infer::infer::{DefineOpaqueTypes, InferOk}; +use rustc_middle::traits::SelectionOutputTypeParameterMismatch; use rustc_middle::ty::{ self, Binder, GenericParamDefKind, InternalSubsts, SubstsRef, ToPolyTraitRef, ToPredicate, TraitRef, Ty, TyCtxt, TypeVisitableExt, @@ -28,9 +29,9 @@ use crate::traits::{ ImplSourceAutoImplData, ImplSourceBuiltinData, ImplSourceClosureData, ImplSourceConstDestructData, ImplSourceFnPointerData, ImplSourceFutureData, ImplSourceGeneratorData, ImplSourceObjectData, ImplSourceTraitAliasData, - ImplSourceTraitUpcastingData, ImplSourceUserDefinedData, Normalized, ObjectCastObligation, - Obligation, ObligationCause, OutputTypeParameterMismatch, PredicateObligation, Selection, - SelectionError, TraitNotObjectSafe, TraitObligation, Unimplemented, + ImplSourceTraitUpcastingData, ImplSourceUserDefinedData, Normalized, Obligation, + ObligationCause, OutputTypeParameterMismatch, PredicateObligation, Selection, SelectionError, + TraitNotObjectSafe, TraitObligation, Unimplemented, }; use super::BuiltinImplConditions; @@ -811,7 +812,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { fn confirm_poly_trait_refs( &mut self, obligation: &TraitObligation<'tcx>, - expected_trait_ref: ty::PolyTraitRef<'tcx>, + self_ty_trait_ref: ty::PolyTraitRef<'tcx>, ) -> Result<Vec<PredicateObligation<'tcx>>, SelectionError<'tcx>> { let obligation_trait_ref = obligation.predicate.to_poly_trait_ref(); // Normalize the obligation and expected trait refs together, because why not @@ -822,7 +823,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation.param_env, obligation.cause.clone(), obligation.recursion_depth + 1, - (obligation_trait_ref, expected_trait_ref), + (obligation_trait_ref, self_ty_trait_ref), ) }); @@ -834,7 +835,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligations.extend(nested); obligations }) - .map_err(|e| OutputTypeParameterMismatch(expected_trait_ref, obligation_trait_ref, e)) + .map_err(|terr| { + OutputTypeParameterMismatch(Box::new(SelectionOutputTypeParameterMismatch { + expected_trait_ref: obligation_trait_ref, + found_trait_ref: expected_trait_ref, + terr, + })) + }) } fn confirm_trait_upcasting_unsize_candidate( @@ -898,16 +905,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { .map_err(|_| Unimplemented)?; nested.extend(obligations); - // Register one obligation for 'a: 'b. - let cause = ObligationCause::new( - obligation.cause.span, - obligation.cause.body_id, - ObjectCastObligation(source, target), - ); let outlives = ty::OutlivesPredicate(r_a, r_b); nested.push(Obligation::with_depth( tcx, - cause, + obligation.cause.clone(), obligation.recursion_depth + 1, obligation.param_env, obligation.predicate.rebind(outlives), @@ -998,15 +999,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { nested.extend(obligations); // Register one obligation for 'a: 'b. - let cause = ObligationCause::new( - obligation.cause.span, - obligation.cause.body_id, - ObjectCastObligation(source, target), - ); let outlives = ty::OutlivesPredicate(r_a, r_b); nested.push(Obligation::with_depth( tcx, - cause, + obligation.cause.clone(), obligation.recursion_depth + 1, obligation.param_env, obligation.predicate.rebind(outlives), @@ -1020,16 +1016,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { return Err(TraitNotObjectSafe(did)); } - let cause = ObligationCause::new( - obligation.cause.span, - obligation.cause.body_id, - ObjectCastObligation(source, target), - ); - let predicate_to_obligation = |predicate| { Obligation::with_depth( tcx, - cause.clone(), + obligation.cause.clone(), obligation.recursion_depth + 1, obligation.param_env, predicate, @@ -1049,7 +1039,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ); // We can only make objects from sized types. - let tr = ty::TraitRef::from_lang_item(tcx, LangItem::Sized, cause.span, [source]); + let tr = ty::TraitRef::from_lang_item( + tcx, + LangItem::Sized, + obligation.cause.span, + [source], + ); nested.push(predicate_to_obligation(tr.without_const().to_predicate(tcx))); // If the type is `Foo + 'a`, ensure that the type diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index e4f5a84f424..b72ff5b78e4 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -2647,14 +2647,19 @@ impl<'tcx> SelectionContext<'_, 'tcx> { let predicates = predicates.instantiate_own(tcx, substs); let mut obligations = Vec::with_capacity(predicates.len()); for (index, (predicate, span)) in predicates.into_iter().enumerate() { - let cause = cause.clone().derived_cause(parent_trait_pred, |derived| { - ImplDerivedObligation(Box::new(ImplDerivedObligationCause { - derived, - impl_or_alias_def_id: def_id, - impl_def_predicate_index: Some(index), - span, - })) - }); + let cause = + if Some(parent_trait_pred.def_id()) == tcx.lang_items().coerce_unsized_trait() { + cause.clone() + } else { + cause.clone().derived_cause(parent_trait_pred, |derived| { + ImplDerivedObligation(Box::new(ImplDerivedObligationCause { + derived, + impl_or_alias_def_id: def_id, + impl_def_predicate_index: Some(index), + span, + })) + }) + }; let predicate = normalize_with_depth_to( self, param_env, diff --git a/compiler/rustc_trait_selection/src/traits/vtable.rs b/compiler/rustc_trait_selection/src/traits/vtable.rs index f7a3126b4aa..cc674ceee3d 100644 --- a/compiler/rustc_trait_selection/src/traits/vtable.rs +++ b/compiler/rustc_trait_selection/src/traits/vtable.rs @@ -4,6 +4,7 @@ use rustc_hir::def_id::DefId; use rustc_hir::lang_items::LangItem; use rustc_infer::traits::util::PredicateSet; use rustc_infer::traits::ImplSource; +use rustc_middle::query::Providers; use rustc_middle::ty::visit::TypeVisitableExt; use rustc_middle::ty::InternalSubsts; use rustc_middle::ty::{self, GenericParamDefKind, ToPredicate, Ty, TyCtxt, VtblEntry}; @@ -379,8 +380,8 @@ pub(crate) fn count_own_vtable_entries<'tcx>( tcx.own_existential_vtable_entries(trait_ref.def_id()).len() } -pub(super) fn provide(providers: &mut ty::query::Providers) { - *providers = ty::query::Providers { +pub(super) fn provide(providers: &mut Providers) { + *providers = Providers { own_existential_vtable_entries, vtable_entries, vtable_trait_upcasting_coercion_new_vptr_slot, diff --git a/compiler/rustc_traits/src/chalk/mod.rs b/compiler/rustc_traits/src/chalk/mod.rs index a5ebc26a8bc..8834449c9a4 100644 --- a/compiler/rustc_traits/src/chalk/mod.rs +++ b/compiler/rustc_traits/src/chalk/mod.rs @@ -7,8 +7,8 @@ pub(crate) mod db; pub(crate) mod lowering; use rustc_middle::infer::canonical::{CanonicalTyVarKind, CanonicalVarKind}; +use rustc_middle::query::Providers; use rustc_middle::traits::ChalkRustInterner; -use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, TyCtxt, TypeFoldable, TypeVisitable}; use rustc_infer::infer::canonical::{ diff --git a/compiler/rustc_traits/src/dropck_outlives.rs b/compiler/rustc_traits/src/dropck_outlives.rs index fcdffc7468b..83f6c7d07fe 100644 --- a/compiler/rustc_traits/src/dropck_outlives.rs +++ b/compiler/rustc_traits/src/dropck_outlives.rs @@ -2,7 +2,7 @@ use rustc_data_structures::fx::FxHashSet; use rustc_hir::def_id::DefId; use rustc_infer::infer::canonical::{Canonical, QueryResponse}; use rustc_infer::infer::TyCtxtInferExt; -use rustc_middle::ty::query::Providers; +use rustc_middle::query::Providers; use rustc_middle::ty::InternalSubsts; use rustc_middle::ty::{self, EarlyBinder, ParamEnvAnd, Ty, TyCtxt}; use rustc_span::source_map::{Span, DUMMY_SP}; diff --git a/compiler/rustc_traits/src/evaluate_obligation.rs b/compiler/rustc_traits/src/evaluate_obligation.rs index e94c8efe69a..149dffc7e31 100644 --- a/compiler/rustc_traits/src/evaluate_obligation.rs +++ b/compiler/rustc_traits/src/evaluate_obligation.rs @@ -1,5 +1,5 @@ use rustc_infer::infer::{DefiningAnchor, TyCtxtInferExt}; -use rustc_middle::ty::query::Providers; +use rustc_middle::query::Providers; use rustc_middle::ty::{ParamEnvAnd, TyCtxt}; use rustc_span::source_map::DUMMY_SP; use rustc_trait_selection::traits::query::CanonicalPredicateGoal; diff --git a/compiler/rustc_traits/src/implied_outlives_bounds.rs b/compiler/rustc_traits/src/implied_outlives_bounds.rs index f5bba14d2fb..0c2bb863e1f 100644 --- a/compiler/rustc_traits/src/implied_outlives_bounds.rs +++ b/compiler/rustc_traits/src/implied_outlives_bounds.rs @@ -6,7 +6,7 @@ use rustc_infer::infer::canonical::{self, Canonical}; use rustc_infer::infer::outlives::components::{push_outlives_components, Component}; use rustc_infer::infer::TyCtxtInferExt; use rustc_infer::traits::query::OutlivesBound; -use rustc_middle::ty::query::Providers; +use rustc_middle::query::Providers; use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt}; use rustc_span::def_id::CRATE_DEF_ID; use rustc_span::source_map::DUMMY_SP; diff --git a/compiler/rustc_traits/src/lib.rs b/compiler/rustc_traits/src/lib.rs index 8bea5588ae7..b0f9c57154f 100644 --- a/compiler/rustc_traits/src/lib.rs +++ b/compiler/rustc_traits/src/lib.rs @@ -23,7 +23,7 @@ mod type_op; pub use type_op::{type_op_ascribe_user_type_with_span, type_op_prove_predicate_with_cause}; -use rustc_middle::ty::query::Providers; +use rustc_middle::query::Providers; pub fn provide(p: &mut Providers) { dropck_outlives::provide(p); diff --git a/compiler/rustc_traits/src/normalize_erasing_regions.rs b/compiler/rustc_traits/src/normalize_erasing_regions.rs index 5da0f16c2bf..94c33efaeff 100644 --- a/compiler/rustc_traits/src/normalize_erasing_regions.rs +++ b/compiler/rustc_traits/src/normalize_erasing_regions.rs @@ -1,6 +1,6 @@ use rustc_infer::infer::TyCtxtInferExt; +use rustc_middle::query::Providers; use rustc_middle::traits::query::NoSolution; -use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, ParamEnvAnd, TyCtxt, TypeFoldable, TypeVisitableExt}; use rustc_trait_selection::traits::query::normalize::QueryNormalizeExt; use rustc_trait_selection::traits::{Normalized, ObligationCause}; diff --git a/compiler/rustc_traits/src/normalize_projection_ty.rs b/compiler/rustc_traits/src/normalize_projection_ty.rs index 36d80a06ee7..b552ba41acd 100644 --- a/compiler/rustc_traits/src/normalize_projection_ty.rs +++ b/compiler/rustc_traits/src/normalize_projection_ty.rs @@ -1,6 +1,6 @@ use rustc_infer::infer::canonical::{Canonical, QueryResponse}; use rustc_infer::infer::TyCtxtInferExt; -use rustc_middle::ty::query::Providers; +use rustc_middle::query::Providers; use rustc_middle::ty::{ParamEnvAnd, TyCtxt}; use rustc_trait_selection::infer::InferCtxtBuilderExt; use rustc_trait_selection::traits::query::{ diff --git a/compiler/rustc_traits/src/type_op.rs b/compiler/rustc_traits/src/type_op.rs index 19622112f2a..70dc7ccec63 100644 --- a/compiler/rustc_traits/src/type_op.rs +++ b/compiler/rustc_traits/src/type_op.rs @@ -2,7 +2,7 @@ use rustc_hir as hir; use rustc_infer::infer::canonical::{Canonical, QueryResponse}; use rustc_infer::infer::{DefiningAnchor, TyCtxtInferExt}; use rustc_infer::traits::ObligationCauseCode; -use rustc_middle::ty::query::Providers; +use rustc_middle::query::Providers; use rustc_middle::ty::{self, FnSig, Lift, PolyFnSig, Ty, TyCtxt, TypeFoldable}; use rustc_middle::ty::{ParamEnvAnd, Predicate}; use rustc_middle::ty::{UserSelfTy, UserSubsts, UserType}; diff --git a/compiler/rustc_ty_utils/messages.ftl b/compiler/rustc_ty_utils/messages.ftl index 15a14112f4a..5bc3e3c00c9 100644 --- a/compiler/rustc_ty_utils/messages.ftl +++ b/compiler/rustc_ty_utils/messages.ftl @@ -55,3 +55,11 @@ ty_utils_multiple_array_fields_simd_type = monomorphising SIMD type `{$ty}` with ty_utils_oversized_simd_type = monomorphising SIMD type `{$ty}` of length greater than {$max_lanes} ty_utils_non_primitive_simd_type = monomorphising SIMD type `{$ty}` with a non-primitive-scalar (integer/float/pointer) element type `{$e_ty}` + +ty_utils_impl_trait_duplicate_arg = non-defining opaque type use in defining scope + .label = generic argument `{$arg}` used twice + .note = for this opaque type + +ty_utils_impl_trait_not_param = non-defining opaque type use in defining scope + .label = argument `{$arg}` is not a generic parameter + .note = for this opaque type diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs index 271284b2d81..442d041a8a7 100644 --- a/compiler/rustc_ty_utils/src/abi.rs +++ b/compiler/rustc_ty_utils/src/abi.rs @@ -1,5 +1,6 @@ use rustc_hir as hir; use rustc_hir::lang_items::LangItem; +use rustc_middle::query::Providers; use rustc_middle::ty::layout::{ fn_can_unwind, FnAbiError, HasParamEnv, HasTyCtxt, LayoutCx, LayoutOf, TyAndLayout, }; @@ -14,8 +15,8 @@ use rustc_target::spec::abi::Abi as SpecAbi; use std::iter; -pub fn provide(providers: &mut ty::query::Providers) { - *providers = ty::query::Providers { fn_abi_of_fn_ptr, fn_abi_of_instance, ..*providers }; +pub fn provide(providers: &mut Providers) { + *providers = Providers { fn_abi_of_fn_ptr, fn_abi_of_instance, ..*providers }; } // NOTE(eddyb) this is private to avoid using it from outside of diff --git a/compiler/rustc_ty_utils/src/assoc.rs b/compiler/rustc_ty_utils/src/assoc.rs index 9029ba2a51a..ed574f22e61 100644 --- a/compiler/rustc_ty_utils/src/assoc.rs +++ b/compiler/rustc_ty_utils/src/assoc.rs @@ -4,11 +4,12 @@ use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId}; use rustc_hir::definitions::DefPathData; use rustc_hir::intravisit::{self, Visitor}; +use rustc_middle::query::Providers; use rustc_middle::ty::{self, ImplTraitInTraitData, InternalSubsts, TyCtxt}; use rustc_span::symbol::kw; -pub fn provide(providers: &mut ty::query::Providers) { - *providers = ty::query::Providers { +pub fn provide(providers: &mut Providers) { + *providers = Providers { associated_item, associated_item_def_ids, associated_items, diff --git a/compiler/rustc_ty_utils/src/common_traits.rs b/compiler/rustc_ty_utils/src/common_traits.rs index 3b1abdcb24f..51b908881eb 100644 --- a/compiler/rustc_ty_utils/src/common_traits.rs +++ b/compiler/rustc_ty_utils/src/common_traits.rs @@ -2,6 +2,7 @@ use rustc_hir::lang_items::LangItem; use rustc_infer::infer::TyCtxtInferExt; +use rustc_middle::query::Providers; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_trait_selection::traits; @@ -32,12 +33,6 @@ fn is_item_raw<'tcx>( traits::type_known_to_meet_bound_modulo_regions(&infcx, param_env, ty, trait_def_id) } -pub(crate) fn provide(providers: &mut ty::query::Providers) { - *providers = ty::query::Providers { - is_copy_raw, - is_sized_raw, - is_freeze_raw, - is_unpin_raw, - ..*providers - }; +pub(crate) fn provide(providers: &mut Providers) { + *providers = Providers { is_copy_raw, is_sized_raw, is_freeze_raw, is_unpin_raw, ..*providers }; } diff --git a/compiler/rustc_ty_utils/src/consts.rs b/compiler/rustc_ty_utils/src/consts.rs index 3dd1d056be2..1219bb40098 100644 --- a/compiler/rustc_ty_utils/src/consts.rs +++ b/compiler/rustc_ty_utils/src/consts.rs @@ -2,6 +2,7 @@ use rustc_errors::ErrorGuaranteed; use rustc_hir::def::DefKind; use rustc_hir::def_id::LocalDefId; use rustc_middle::mir::interpret::{LitToConstError, LitToConstInput}; +use rustc_middle::query::Providers; use rustc_middle::thir::visit; use rustc_middle::thir::visit::Visitor; use rustc_middle::ty::abstract_const::CastKind; @@ -115,9 +116,7 @@ fn recurse_build<'tcx>( let sp = node.span; match tcx.at(sp).lit_to_const(LitToConstInput { lit: &lit.node, ty: node.ty, neg }) { Ok(c) => c, - Err(LitToConstError::Reported(guar)) => { - tcx.const_error_with_guaranteed(node.ty, guar) - } + Err(LitToConstError::Reported(guar)) => tcx.const_error(node.ty, guar), Err(LitToConstError::TypeError) => { bug!("encountered type error in lit_to_const") } @@ -423,6 +422,6 @@ pub fn thir_abstract_const( Ok(Some(ty::EarlyBinder(recurse_build(tcx, body, body_id, root_span)?))) } -pub fn provide(providers: &mut ty::query::Providers) { - *providers = ty::query::Providers { destructure_const, thir_abstract_const, ..*providers }; +pub fn provide(providers: &mut Providers) { + *providers = Providers { destructure_const, thir_abstract_const, ..*providers }; } diff --git a/compiler/rustc_ty_utils/src/errors.rs b/compiler/rustc_ty_utils/src/errors.rs index 3d3fc50e6e5..553bf40ef3a 100644 --- a/compiler/rustc_ty_utils/src/errors.rs +++ b/compiler/rustc_ty_utils/src/errors.rs @@ -1,7 +1,7 @@ //! Errors emitted by ty_utils use rustc_macros::{Diagnostic, Subdiagnostic}; -use rustc_middle::ty::Ty; +use rustc_middle::ty::{GenericArg, Ty}; use rustc_span::Span; #[derive(Diagnostic)] @@ -100,3 +100,25 @@ pub struct NonPrimitiveSimdType<'tcx> { pub ty: Ty<'tcx>, pub e_ty: Ty<'tcx>, } + +#[derive(Diagnostic)] +#[diag(ty_utils_impl_trait_duplicate_arg)] +pub struct DuplicateArg<'tcx> { + pub arg: GenericArg<'tcx>, + #[primary_span] + #[label] + pub span: Span, + #[note] + pub opaque_span: Span, +} + +#[derive(Diagnostic)] +#[diag(ty_utils_impl_trait_not_param)] +pub struct NotParam<'tcx> { + pub arg: GenericArg<'tcx>, + #[primary_span] + #[label] + pub span: Span, + #[note] + pub opaque_span: Span, +} diff --git a/compiler/rustc_ty_utils/src/implied_bounds.rs b/compiler/rustc_ty_utils/src/implied_bounds.rs index 56d6cc28bc8..081be065864 100644 --- a/compiler/rustc_ty_utils/src/implied_bounds.rs +++ b/compiler/rustc_ty_utils/src/implied_bounds.rs @@ -1,8 +1,9 @@ use rustc_hir::{def::DefKind, def_id::DefId}; +use rustc_middle::query::Providers; use rustc_middle::ty::{self, Ty, TyCtxt}; -pub fn provide(providers: &mut ty::query::Providers) { - *providers = ty::query::Providers { assumed_wf_types, ..*providers }; +pub fn provide(providers: &mut Providers) { + *providers = Providers { assumed_wf_types, ..*providers }; } fn assumed_wf_types(tcx: TyCtxt<'_>, def_id: DefId) -> &ty::List<Ty<'_>> { @@ -31,6 +32,18 @@ fn assumed_wf_types(tcx: TyCtxt<'_>, def_id: DefId) -> &ty::List<Ty<'_>> { } } DefKind::AssocConst | DefKind::AssocTy => tcx.assumed_wf_types(tcx.parent(def_id)), + DefKind::OpaqueTy => match tcx.def_kind(tcx.parent(def_id)) { + DefKind::TyAlias => ty::List::empty(), + DefKind::AssocTy => tcx.assumed_wf_types(tcx.parent(def_id)), + // Nested opaque types only occur in associated types: + // ` type Opaque<T> = impl Trait<&'static T, AssocTy = impl Nested>; ` + // assumed_wf_types should include those of `Opaque<T>`, `Opaque<T>` itself + // and `&'static T`. + DefKind::OpaqueTy => bug!("unimplemented implied bounds for neseted opaque types"), + def_kind @ _ => { + bug!("unimplemented implied bounds for opaque types with parent {def_kind:?}") + } + }, DefKind::Mod | DefKind::Struct | DefKind::Union @@ -51,7 +64,6 @@ fn assumed_wf_types(tcx: TyCtxt<'_>, def_id: DefId) -> &ty::List<Ty<'_>> { | DefKind::ForeignMod | DefKind::AnonConst | DefKind::InlineConst - | DefKind::OpaqueTy | DefKind::ImplTraitPlaceholder | DefKind::Field | DefKind::LifetimeParam diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs index eb3c21163ab..36a20c78fcc 100644 --- a/compiler/rustc_ty_utils/src/instance.rs +++ b/compiler/rustc_ty_utils/src/instance.rs @@ -1,6 +1,7 @@ use rustc_errors::ErrorGuaranteed; use rustc_hir::def_id::DefId; use rustc_infer::infer::TyCtxtInferExt; +use rustc_middle::query::Providers; use rustc_middle::traits::CodegenObligationError; use rustc_middle::ty::subst::SubstsRef; use rustc_middle::ty::{self, Instance, TyCtxt, TypeVisitableExt}; @@ -319,6 +320,6 @@ fn resolve_associated_item<'tcx>( }) } -pub fn provide(providers: &mut ty::query::Providers) { - *providers = ty::query::Providers { resolve_instance, ..*providers }; +pub fn provide(providers: &mut Providers) { + *providers = Providers { resolve_instance, ..*providers }; } diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs index f7c75583f60..16cd8bc8e69 100644 --- a/compiler/rustc_ty_utils/src/layout.rs +++ b/compiler/rustc_ty_utils/src/layout.rs @@ -3,6 +3,7 @@ use rustc_hir as hir; use rustc_index::bit_set::BitSet; use rustc_index::{IndexSlice, IndexVec}; use rustc_middle::mir::{GeneratorLayout, GeneratorSavedLocal}; +use rustc_middle::query::Providers; use rustc_middle::ty::layout::{ IntegerExt, LayoutCx, LayoutError, LayoutOf, TyAndLayout, MAX_SIMD_LANES, }; @@ -22,8 +23,8 @@ use crate::errors::{ }; use crate::layout_sanity_check::sanity_check_layout; -pub fn provide(providers: &mut ty::query::Providers) { - *providers = ty::query::Providers { layout_of, ..*providers }; +pub fn provide(providers: &mut Providers) { + *providers = Providers { layout_of, ..*providers }; } #[instrument(skip(tcx, query), level = "debug")] diff --git a/compiler/rustc_ty_utils/src/lib.rs b/compiler/rustc_ty_utils/src/lib.rs index 73a2f6af579..55b8857ed39 100644 --- a/compiler/rustc_ty_utils/src/lib.rs +++ b/compiler/rustc_ty_utils/src/lib.rs @@ -21,7 +21,7 @@ extern crate tracing; use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage}; use rustc_fluent_macro::fluent_messages; -use rustc_middle::ty::query::Providers; +use rustc_middle::query::Providers; mod abi; mod assoc; @@ -33,6 +33,7 @@ pub mod instance; mod layout; mod layout_sanity_check; mod needs_drop; +mod opaque_types; pub mod representability; mod structural_match; mod ty; @@ -47,6 +48,7 @@ pub fn provide(providers: &mut Providers) { implied_bounds::provide(providers); layout::provide(providers); needs_drop::provide(providers); + opaque_types::provide(providers); representability::provide(providers); ty::provide(providers); instance::provide(providers); diff --git a/compiler/rustc_ty_utils/src/needs_drop.rs b/compiler/rustc_ty_utils/src/needs_drop.rs index a04f85afb9e..1f9701b9322 100644 --- a/compiler/rustc_ty_utils/src/needs_drop.rs +++ b/compiler/rustc_ty_utils/src/needs_drop.rs @@ -2,6 +2,7 @@ use rustc_data_structures::fx::FxHashSet; use rustc_hir::def_id::DefId; +use rustc_middle::query::Providers; use rustc_middle::ty::subst::SubstsRef; use rustc_middle::ty::util::{needs_drop_components, AlwaysRequiresDrop}; use rustc_middle::ty::{self, EarlyBinder, Ty, TyCtxt}; @@ -323,8 +324,8 @@ fn adt_significant_drop_tys( .map(|components| tcx.mk_type_list(&components)) } -pub(crate) fn provide(providers: &mut ty::query::Providers) { - *providers = ty::query::Providers { +pub(crate) fn provide(providers: &mut Providers) { + *providers = Providers { needs_drop_raw, has_significant_drop_raw, adt_drop_tys, diff --git a/compiler/rustc_ty_utils/src/opaque_types.rs b/compiler/rustc_ty_utils/src/opaque_types.rs new file mode 100644 index 00000000000..4e91dd380e8 --- /dev/null +++ b/compiler/rustc_ty_utils/src/opaque_types.rs @@ -0,0 +1,198 @@ +use rustc_data_structures::fx::FxHashSet; +use rustc_errors::ErrorGuaranteed; +use rustc_hir::{def::DefKind, def_id::LocalDefId}; +use rustc_middle::query::Providers; +use rustc_middle::ty::util::{CheckRegions, NotUniqueParam}; +use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_middle::ty::{TypeSuperVisitable, TypeVisitable, TypeVisitor}; +use rustc_span::Span; +use rustc_type_ir::AliasKind; +use std::ops::ControlFlow; + +use crate::errors::{DuplicateArg, NotParam}; + +struct OpaqueTypeCollector<'tcx> { + tcx: TyCtxt<'tcx>, + opaques: Vec<LocalDefId>, + /// The `DefId` of the item which we are collecting opaque types for. + item: LocalDefId, + + /// Avoid infinite recursion due to recursive declarations. + seen: FxHashSet<LocalDefId>, +} + +impl<'tcx> OpaqueTypeCollector<'tcx> { + fn collect( + tcx: TyCtxt<'tcx>, + item: LocalDefId, + val: ty::Binder<'tcx, impl TypeVisitable<TyCtxt<'tcx>>>, + ) -> Vec<LocalDefId> { + let mut collector = Self { tcx, opaques: Vec::new(), item, seen: Default::default() }; + val.skip_binder().visit_with(&mut collector); + collector.opaques + } + + fn span(&self) -> Span { + self.tcx.def_span(self.item) + } + + fn parent(&self) -> Option<LocalDefId> { + match self.tcx.def_kind(self.item) { + DefKind::Fn => None, + DefKind::AssocFn | DefKind::AssocTy | DefKind::AssocConst => { + Some(self.tcx.local_parent(self.item)) + } + other => span_bug!( + self.tcx.def_span(self.item), + "unhandled item with opaque types: {other:?}" + ), + } + } +} + +impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for OpaqueTypeCollector<'tcx> { + type BreakTy = ErrorGuaranteed; + + #[instrument(skip(self), ret, level = "trace")] + fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<ErrorGuaranteed> { + match t.kind() { + ty::Alias(AliasKind::Opaque, alias_ty) if alias_ty.def_id.is_local() => { + if !self.seen.insert(alias_ty.def_id.expect_local()) { + return ControlFlow::Continue(()); + } + match self.tcx.uses_unique_generic_params(alias_ty.substs, CheckRegions::Bound) { + Ok(()) => { + // FIXME: implement higher kinded lifetime bounds on nested opaque types. They are not + // supported at all, so this is sound to do, but once we want to support them, you'll + // start seeing the error below. + + self.opaques.push(alias_ty.def_id.expect_local()); + + // Collect opaque types nested within the associated type bounds of this opaque type. + for (pred, _span) in self + .tcx + .explicit_item_bounds(alias_ty.def_id) + .subst_iter_copied(self.tcx, alias_ty.substs) + { + trace!(?pred); + pred.visit_with(self)?; + } + + ControlFlow::Continue(()) + } + Err(NotUniqueParam::NotParam(arg)) => { + let err = self.tcx.sess.emit_err(NotParam { + arg, + span: self.span(), + opaque_span: self.tcx.def_span(alias_ty.def_id), + }); + ControlFlow::Break(err) + } + Err(NotUniqueParam::DuplicateParam(arg)) => { + let err = self.tcx.sess.emit_err(DuplicateArg { + arg, + span: self.span(), + opaque_span: self.tcx.def_span(alias_ty.def_id), + }); + ControlFlow::Break(err) + } + } + } + ty::Alias(AliasKind::Projection, alias_ty) => { + if let Some(parent) = self.parent() { + trace!(?alias_ty); + let (trait_ref, own_substs) = alias_ty.trait_ref_and_own_substs(self.tcx); + + trace!(?trait_ref, ?own_substs); + // This avoids having to do normalization of `Self::AssocTy` by only + // supporting the case of a method defining opaque types from assoc types + // in the same impl block. + if trait_ref.self_ty() == self.tcx.type_of(parent).subst_identity() { + for assoc in self.tcx.associated_items(parent).in_definition_order() { + trace!(?assoc); + if assoc.trait_item_def_id == Some(alias_ty.def_id) { + // We reconstruct the generic args of the associated type within the impl + // from the impl's generics and the generic args passed to the type via the + // projection. + let substs = ty::InternalSubsts::identity_for_item( + self.tcx, + parent.to_def_id(), + ); + trace!(?substs); + let substs: Vec<_> = + substs.iter().chain(own_substs.iter().copied()).collect(); + trace!(?substs); + // Find opaque types in this associated type. + return self + .tcx + .type_of(assoc.def_id) + .subst(self.tcx, &substs) + .visit_with(self); + } + } + } + } + t.super_visit_with(self) + } + _ => t.super_visit_with(self), + } + } +} + +fn opaque_types_defined_by<'tcx>(tcx: TyCtxt<'tcx>, item: LocalDefId) -> &'tcx [LocalDefId] { + let kind = tcx.def_kind(item); + trace!(?kind); + // FIXME(type_alias_impl_trait): This is definitely still wrong except for RPIT and impl trait in assoc types. + match kind { + // We're also doing this for `AssocTy` for the wf checks in `check_opaque_meets_bounds` + DefKind::Fn | DefKind::AssocFn | DefKind::AssocTy | DefKind::AssocConst => { + let defined_opaques = match kind { + DefKind::Fn => { + OpaqueTypeCollector::collect(tcx, item, tcx.fn_sig(item).subst_identity()) + } + DefKind::AssocFn => { + OpaqueTypeCollector::collect(tcx, item, tcx.fn_sig(item).subst_identity()) + } + DefKind::AssocTy | DefKind::AssocConst => OpaqueTypeCollector::collect( + tcx, + item, + ty::Binder::dummy(tcx.type_of(item).subst_identity()), + ), + _ => unreachable!(), + }; + tcx.arena.alloc_from_iter(defined_opaques) + } + DefKind::Mod + | DefKind::Struct + | DefKind::Union + | DefKind::Enum + | DefKind::Variant + | DefKind::Trait + | DefKind::TyAlias + | DefKind::ForeignTy + | DefKind::TraitAlias + | DefKind::TyParam + | DefKind::Const + | DefKind::ConstParam + | DefKind::Static(_) + | DefKind::Ctor(_, _) + | DefKind::Macro(_) + | DefKind::ExternCrate + | DefKind::Use + | DefKind::ForeignMod + | DefKind::AnonConst + | DefKind::InlineConst + | DefKind::OpaqueTy + | DefKind::ImplTraitPlaceholder + | DefKind::Field + | DefKind::LifetimeParam + | DefKind::GlobalAsm + | DefKind::Impl { .. } + | DefKind::Closure + | DefKind::Generator => &[], + } +} + +pub(super) fn provide(providers: &mut Providers) { + *providers = Providers { opaque_types_defined_by, ..*providers }; +} diff --git a/compiler/rustc_ty_utils/src/representability.rs b/compiler/rustc_ty_utils/src/representability.rs index 26d6deab883..0b5e27c2c74 100644 --- a/compiler/rustc_ty_utils/src/representability.rs +++ b/compiler/rustc_ty_utils/src/representability.rs @@ -2,7 +2,7 @@ use rustc_hir::def::DefKind; use rustc_index::bit_set::BitSet; -use rustc_middle::ty::query::Providers; +use rustc_middle::query::Providers; use rustc_middle::ty::{self, Representability, Ty, TyCtxt}; use rustc_span::def_id::LocalDefId; diff --git a/compiler/rustc_ty_utils/src/structural_match.rs b/compiler/rustc_ty_utils/src/structural_match.rs index 9cb0fc10594..215acbe2c8f 100644 --- a/compiler/rustc_ty_utils/src/structural_match.rs +++ b/compiler/rustc_ty_utils/src/structural_match.rs @@ -1,5 +1,5 @@ use rustc_hir::lang_items::LangItem; -use rustc_middle::ty::query::Providers; +use rustc_middle::query::Providers; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_infer::infer::TyCtxtInferExt; diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs index 78efcce572d..65dc3c39c6a 100644 --- a/compiler/rustc_ty_utils/src/ty.rs +++ b/compiler/rustc_ty_utils/src/ty.rs @@ -2,6 +2,7 @@ use rustc_data_structures::fx::{FxHashSet, FxIndexSet}; use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_index::bit_set::BitSet; +use rustc_middle::query::Providers; use rustc_middle::ty::{ self, Binder, EarlyBinder, ImplTraitInTraitData, Predicate, PredicateKind, ToPredicate, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor, @@ -566,8 +567,8 @@ fn unsizing_params_for_adt<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> BitSet<u32 unsizing_params } -pub fn provide(providers: &mut ty::query::Providers) { - *providers = ty::query::Providers { +pub fn provide(providers: &mut Providers) { + *providers = Providers { asyncness, adt_sized_constraint, param_env, diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs index 7e5a4d1c735..f6b44bdf27e 100644 --- a/compiler/rustc_type_ir/src/lib.rs +++ b/compiler/rustc_type_ir/src/lib.rs @@ -643,7 +643,7 @@ impl UnifyKey for FloatVid { } } -#[derive(Copy, Clone, PartialEq, Decodable, Encodable, Hash, HashStable_Generic)] +#[derive(Copy, Clone, PartialEq, Eq, Decodable, Encodable, Hash, HashStable_Generic)] #[rustc_pass_by_value] pub enum Variance { Covariant, // T<A> <: T<B> iff A <: B -- e.g., function return type diff --git a/compiler/rustc_type_ir/src/structural_impls.rs b/compiler/rustc_type_ir/src/structural_impls.rs index c9675f93f95..45a2e9023c9 100644 --- a/compiler/rustc_type_ir/src/structural_impls.rs +++ b/compiler/rustc_type_ir/src/structural_impls.rs @@ -21,6 +21,7 @@ TrivialTypeTraversalImpls! { (), bool, usize, + u8, u16, u32, u64, |