diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 8dd03aaa72d16..5db0f72919d03 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -702,7 +702,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { .copied() .find_map(find_fn_kind_from_did), ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => tcx - .bound_explicit_item_bounds(def_id) + .explicit_item_bounds(def_id) .subst_iter_copied(tcx, substs) .find_map(find_fn_kind_from_did), ty::Closure(_, substs) => match substs.as_closure().kind() { diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs index 426d2c4034bd8..004017ec5f31a 100644 --- a/compiler/rustc_data_structures/src/lib.rs +++ b/compiler/rustc_data_structures/src/lib.rs @@ -31,6 +31,7 @@ #![feature(unwrap_infallible)] #![feature(strict_provenance)] #![feature(ptr_alignment_type)] +#![feature(macro_metavar_expr)] #![allow(rustc::default_hash_types)] #![allow(rustc::potential_query_instability)] #![deny(rustc::untranslatable_diagnostic)] diff --git a/compiler/rustc_data_structures/src/tagged_ptr.rs b/compiler/rustc_data_structures/src/tagged_ptr.rs index 8568aac67c08c..2914eece6796b 100644 --- a/compiler/rustc_data_structures/src/tagged_ptr.rs +++ b/compiler/rustc_data_structures/src/tagged_ptr.rs @@ -24,6 +24,7 @@ use crate::aligned::Aligned; mod copy; mod drop; +mod impl_tag; pub use copy::CopyTaggedPtr; pub use drop::TaggedPtr; @@ -141,6 +142,30 @@ pub unsafe trait Tag: Copy { unsafe fn from_usize(tag: usize) -> Self; } +/// Returns the number of bits available for use for tags in a pointer to `T` +/// (this is based on `T`'s alignment). +pub const fn bits_for() -> u32 { + crate::aligned::align_of::().as_nonzero().trailing_zeros() +} + +/// Returns the correct [`Tag::BITS`] constant for a set of tag values. +pub const fn bits_for_tags(mut tags: &[usize]) -> u32 { + let mut bits = 0; + + while let &[tag, ref rest @ ..] = tags { + tags = rest; + + // bits required to represent `tag`, + // position of the most significant 1 + let b = usize::BITS - tag.leading_zeros(); + if b > bits { + bits = b; + } + } + + bits +} + unsafe impl Pointer for Box { const BITS: u32 = bits_for::(); @@ -221,12 +246,6 @@ unsafe impl<'a, T: 'a + ?Sized + Aligned> Pointer for &'a mut T { } } -/// Returns the number of bits available for use for tags in a pointer to `T` -/// (this is based on `T`'s alignment). -pub const fn bits_for() -> u32 { - crate::aligned::align_of::().as_nonzero().trailing_zeros() -} - /// A tag type used in [`CopyTaggedPtr`] and [`TaggedPtr`] tests. #[derive(Copy, Clone, Debug, PartialEq, Eq)] #[cfg(test)] diff --git a/compiler/rustc_data_structures/src/tagged_ptr/impl_tag.rs b/compiler/rustc_data_structures/src/tagged_ptr/impl_tag.rs new file mode 100644 index 0000000000000..cb7f7d318dc41 --- /dev/null +++ b/compiler/rustc_data_structures/src/tagged_ptr/impl_tag.rs @@ -0,0 +1,144 @@ +/// Implements [`Tag`] for a given type. +/// +/// You can use `impl_tag` on structs and enums. +/// You need to specify the type and all its possible values, +/// which can only be paths with optional fields. +/// +/// [`Tag`]: crate::tagged_ptr::Tag +/// +/// # Examples +/// +/// Basic usage: +/// +/// ``` +/// #![feature(macro_metavar_expr)] +/// use rustc_data_structures::{impl_tag, tagged_ptr::Tag}; +/// +/// #[derive(Copy, Clone, PartialEq, Debug)] +/// enum SomeTag { +/// A, +/// B, +/// X { v: bool }, +/// Y(bool, bool), +/// } +/// +/// impl_tag! { +/// // The type for which the `Tag` will be implemented +/// impl Tag for SomeTag; +/// // You need to specify all possible tag values: +/// SomeTag::A, // 0 +/// SomeTag::B, // 1 +/// // For variants with fields, you need to specify the fields: +/// SomeTag::X { v: true }, // 2 +/// SomeTag::X { v: false }, // 3 +/// // For tuple variants use named syntax: +/// SomeTag::Y { 0: true, 1: true }, // 4 +/// SomeTag::Y { 0: false, 1: true }, // 5 +/// SomeTag::Y { 0: true, 1: false }, // 6 +/// SomeTag::Y { 0: false, 1: false }, // 7 +/// } +/// +/// // Tag values are assigned in order: +/// assert_eq!(SomeTag::A.into_usize(), 0); +/// assert_eq!(SomeTag::X { v: false }.into_usize(), 3); +/// assert_eq!(SomeTag::Y(false, true).into_usize(), 5); +/// +/// assert_eq!(unsafe { SomeTag::from_usize(1) }, SomeTag::B); +/// assert_eq!(unsafe { SomeTag::from_usize(2) }, SomeTag::X { v: true }); +/// assert_eq!(unsafe { SomeTag::from_usize(7) }, SomeTag::Y(false, false)); +/// ``` +/// +/// Structs are supported: +/// +/// ``` +/// #![feature(macro_metavar_expr)] +/// # use rustc_data_structures::impl_tag; +/// #[derive(Copy, Clone)] +/// struct Flags { a: bool, b: bool } +/// +/// impl_tag! { +/// impl Tag for Flags; +/// Flags { a: true, b: true }, +/// Flags { a: false, b: true }, +/// Flags { a: true, b: false }, +/// Flags { a: false, b: false }, +/// } +/// ``` +/// +/// Not specifying all values results in a compile error: +/// +/// ```compile_fail,E0004 +/// #![feature(macro_metavar_expr)] +/// # use rustc_data_structures::impl_tag; +/// #[derive(Copy, Clone)] +/// enum E { +/// A, +/// B, +/// } +/// +/// impl_tag! { +/// impl Tag for E; +/// E::A, +/// } +/// ``` +#[macro_export] +macro_rules! impl_tag { + ( + impl Tag for $Self:ty; + $( + $($path:ident)::* $( { $( $fields:tt )* })?, + )* + ) => { + // Safety: + // `bits_for_tags` is called on the same `${index()}`-es as + // `into_usize` returns, thus `BITS` constant is correct. + unsafe impl $crate::tagged_ptr::Tag for $Self { + const BITS: u32 = $crate::tagged_ptr::bits_for_tags(&[ + $( + ${index()}, + $( ${ignore(path)} )* + )* + ]); + + #[inline] + fn into_usize(self) -> usize { + // This forbids use of repeating patterns (`Enum::V`&`Enum::V`, etc) + // (or at least it should, see ) + #[forbid(unreachable_patterns)] + match self { + // `match` is doing heavy lifting here, by requiring exhaustiveness + $( + $($path)::* $( { $( $fields )* } )? => ${index()}, + )* + } + } + + #[inline] + unsafe fn from_usize(tag: usize) -> Self { + match tag { + $( + ${index()} => $($path)::* $( { $( $fields )* } )?, + )* + + // Safety: + // `into_usize` only returns `${index()}` of the same + // repetition as we are filtering above, thus if this is + // reached, the safety contract of this function was + // already breached. + _ => unsafe { + debug_assert!( + false, + "invalid tag: {tag}\ + (this is a bug in the caller of `from_usize`)" + ); + std::hint::unreachable_unchecked() + }, + } + } + + } + }; +} + +#[cfg(test)] +mod tests; diff --git a/compiler/rustc_data_structures/src/tagged_ptr/impl_tag/tests.rs b/compiler/rustc_data_structures/src/tagged_ptr/impl_tag/tests.rs new file mode 100644 index 0000000000000..62c926153e1e9 --- /dev/null +++ b/compiler/rustc_data_structures/src/tagged_ptr/impl_tag/tests.rs @@ -0,0 +1,34 @@ +#[test] +fn bits_constant() { + use crate::tagged_ptr::Tag; + + #[derive(Copy, Clone)] + struct Unit; + impl_tag! { impl Tag for Unit; Unit, } + assert_eq!(Unit::BITS, 0); + + #[derive(Copy, Clone)] + enum Enum3 { + A, + B, + C, + } + impl_tag! { impl Tag for Enum3; Enum3::A, Enum3::B, Enum3::C, } + assert_eq!(Enum3::BITS, 2); + + #[derive(Copy, Clone)] + struct Eight(bool, bool, bool); + impl_tag! { + impl Tag for Eight; + Eight { 0: true, 1: true, 2: true }, + Eight { 0: true, 1: true, 2: false }, + Eight { 0: true, 1: false, 2: true }, + Eight { 0: true, 1: false, 2: false }, + Eight { 0: false, 1: true, 2: true }, + Eight { 0: false, 1: true, 2: false }, + Eight { 0: false, 1: false, 2: true }, + Eight { 0: false, 1: false, 2: false }, + } + + assert_eq!(Eight::BITS, 3); +} diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 1a80b4fc3140d..5fac485de6417 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -58,8 +58,16 @@ use std::str; use std::sync::LazyLock; use std::time::Instant; +// This import blocks the use of panicking `print` and `println` in all the code +// below. Please use `safe_print` and `safe_println` to avoid ICE when +// encountering an I/O error during print. +#[allow(unused_imports)] +use std::{compile_error as print, compile_error as println}; + pub mod args; pub mod pretty; +#[macro_use] +mod print; mod session_diagnostics; use crate::session_diagnostics::{ @@ -511,7 +519,7 @@ fn handle_explain(registry: Registry, code: &str, output: ErrorOutputType) { if io::stdout().is_terminal() { show_content_with_pager(&text); } else { - print!("{text}"); + safe_print!("{text}"); } } Err(InvalidErrorCode) => { @@ -547,7 +555,7 @@ fn show_content_with_pager(content: &str) { // If pager fails for whatever reason, we should still print the content // to standard output if fallback_to_println { - print!("{content}"); + safe_print!("{content}"); } } @@ -601,7 +609,7 @@ pub fn list_metadata(sess: &Session, metadata_loader: &dyn MetadataLoader) -> Co let path = &(*ifile); let mut v = Vec::new(); locator::list_file_metadata(&sess.target, path, metadata_loader, &mut v).unwrap(); - println!("{}", String::from_utf8(v).unwrap()); + safe_println!("{}", String::from_utf8(v).unwrap()); } Input::Str { .. } => { early_error(ErrorOutputType::default(), "cannot list metadata for stdin"); @@ -642,12 +650,12 @@ fn print_crate_info( TargetList => { let mut targets = rustc_target::spec::TARGETS.to_vec(); targets.sort_unstable(); - println!("{}", targets.join("\n")); + safe_println!("{}", targets.join("\n")); } - Sysroot => println!("{}", sess.sysroot.display()), - TargetLibdir => println!("{}", sess.target_tlib_path.dir.display()), + Sysroot => safe_println!("{}", sess.sysroot.display()), + TargetLibdir => safe_println!("{}", sess.target_tlib_path.dir.display()), TargetSpec => { - println!("{}", serde_json::to_string_pretty(&sess.target.to_json()).unwrap()); + safe_println!("{}", serde_json::to_string_pretty(&sess.target.to_json()).unwrap()); } AllTargetSpecs => { let mut targets = BTreeMap::new(); @@ -656,7 +664,7 @@ fn print_crate_info( let target = Target::expect_builtin(&triple); targets.insert(name, target.to_json()); } - println!("{}", serde_json::to_string_pretty(&targets).unwrap()); + safe_println!("{}", serde_json::to_string_pretty(&targets).unwrap()); } FileNames | CrateName => { let Some(attrs) = attrs.as_ref() else { @@ -666,14 +674,14 @@ fn print_crate_info( let t_outputs = rustc_interface::util::build_output_filenames(attrs, sess); let id = rustc_session::output::find_crate_name(sess, attrs); if *req == PrintRequest::CrateName { - println!("{id}"); + safe_println!("{id}"); continue; } let crate_types = collect_crate_types(sess, attrs); for &style in &crate_types { let fname = rustc_session::output::filename_for_input(sess, style, id, &t_outputs); - println!("{}", fname.file_name().unwrap().to_string_lossy()); + safe_println!("{}", fname.file_name().unwrap().to_string_lossy()); } } Cfg => { @@ -707,13 +715,13 @@ fn print_crate_info( cfgs.sort(); for cfg in cfgs { - println!("{cfg}"); + safe_println!("{cfg}"); } } CallingConventions => { let mut calling_conventions = rustc_target::spec::abi::all_names(); calling_conventions.sort_unstable(); - println!("{}", calling_conventions.join("\n")); + safe_println!("{}", calling_conventions.join("\n")); } RelocationModels | CodeModels @@ -733,7 +741,7 @@ fn print_crate_info( let stable = sess.target.options.supported_split_debuginfo.contains(split); let unstable_ok = sess.unstable_options(); if stable || unstable_ok { - println!("{split}"); + safe_println!("{split}"); } } } @@ -770,14 +778,14 @@ pub fn version_at_macro_invocation( ) { let verbose = matches.opt_present("verbose"); - println!("{binary} {version}"); + safe_println!("{binary} {version}"); if verbose { - println!("binary: {binary}"); - println!("commit-hash: {commit_hash}"); - println!("commit-date: {commit_date}"); - println!("host: {}", config::host_triple()); - println!("release: {release}"); + safe_println!("binary: {binary}"); + safe_println!("commit-hash: {commit_hash}"); + safe_println!("commit-date: {commit_date}"); + safe_println!("host: {}", config::host_triple()); + safe_println!("release: {release}"); let debug_flags = matches.opt_strs("Z"); let backend_name = debug_flags.iter().find_map(|x| x.strip_prefix("codegen-backend=")); @@ -807,7 +815,7 @@ fn usage(verbose: bool, include_unstable_options: bool, nightly_build: bool) { } else { "" }; - println!( + safe_println!( "{options}{at_path}\nAdditional help: -C help Print codegen options -W help \ @@ -820,7 +828,7 @@ fn usage(verbose: bool, include_unstable_options: bool, nightly_build: bool) { } fn print_wall_help() { - println!( + safe_println!( " The flag `-Wall` does not exist in `rustc`. Most useful lints are enabled by default. Use `rustc -W help` to see all available lints. It's more common to put @@ -832,7 +840,7 @@ the command line flag directly. /// Write to stdout lint command options, together with a list of all available lints pub fn describe_lints(sess: &Session, lint_store: &LintStore, loaded_plugins: bool) { - println!( + safe_println!( " Available lint options: -W Warn about @@ -877,21 +885,21 @@ Available lint options: s }; - println!("Lint checks provided by rustc:\n"); + safe_println!("Lint checks provided by rustc:\n"); let print_lints = |lints: Vec<&Lint>| { - println!(" {} {:7.7} {}", padded("name"), "default", "meaning"); - println!(" {} {:7.7} {}", padded("----"), "-------", "-------"); + safe_println!(" {} {:7.7} {}", padded("name"), "default", "meaning"); + safe_println!(" {} {:7.7} {}", padded("----"), "-------", "-------"); for lint in lints { let name = lint.name_lower().replace('_', "-"); - println!( + safe_println!( " {} {:7.7} {}", padded(&name), lint.default_level(sess.edition()).as_str(), lint.desc ); } - println!("\n"); + safe_println!("\n"); }; print_lints(builtin); @@ -912,14 +920,14 @@ Available lint options: s }; - println!("Lint groups provided by rustc:\n"); + safe_println!("Lint groups provided by rustc:\n"); let print_lint_groups = |lints: Vec<(&'static str, Vec)>, all_warnings| { - println!(" {} sub-lints", padded("name")); - println!(" {} ---------", padded("----")); + safe_println!(" {} sub-lints", padded("name")); + safe_println!(" {} ---------", padded("----")); if all_warnings { - println!(" {} all lints that are set to issue warnings", padded("warnings")); + safe_println!(" {} all lints that are set to issue warnings", padded("warnings")); } for (name, to) in lints { @@ -929,26 +937,26 @@ Available lint options: .map(|x| x.to_string().replace('_', "-")) .collect::>() .join(", "); - println!(" {} {}", padded(&name), desc); + safe_println!(" {} {}", padded(&name), desc); } - println!("\n"); + safe_println!("\n"); }; print_lint_groups(builtin_groups, true); match (loaded_plugins, plugin.len(), plugin_groups.len()) { (false, 0, _) | (false, _, 0) => { - println!("Lint tools like Clippy can provide additional lints and lint groups."); + safe_println!("Lint tools like Clippy can provide additional lints and lint groups."); } (false, ..) => panic!("didn't load lint plugins but got them anyway!"), - (true, 0, 0) => println!("This crate does not load any lint plugins or lint groups."), + (true, 0, 0) => safe_println!("This crate does not load any lint plugins or lint groups."), (true, l, g) => { if l > 0 { - println!("Lint checks provided by plugins loaded by this crate:\n"); + safe_println!("Lint checks provided by plugins loaded by this crate:\n"); print_lints(plugin); } if g > 0 { - println!("Lint groups provided by plugins loaded by this crate:\n"); + safe_println!("Lint groups provided by plugins loaded by this crate:\n"); print_lint_groups(plugin_groups, false); } } @@ -996,12 +1004,12 @@ pub fn describe_flag_categories(matches: &Matches) -> bool { } fn describe_debug_flags() { - println!("\nAvailable options:\n"); + safe_println!("\nAvailable options:\n"); print_flag_list("-Z", config::Z_OPTIONS); } fn describe_codegen_flags() { - println!("\nAvailable codegen options:\n"); + safe_println!("\nAvailable codegen options:\n"); print_flag_list("-C", config::CG_OPTIONS); } @@ -1012,7 +1020,7 @@ fn print_flag_list( let max_len = flag_list.iter().map(|&(name, _, _, _)| name.chars().count()).max().unwrap_or(0); for &(name, _, _, desc) in flag_list { - println!( + safe_println!( " {} {:>width$}=val -- {}", cmdline_opt, name.replace('_', "-"), diff --git a/compiler/rustc_driver_impl/src/print.rs b/compiler/rustc_driver_impl/src/print.rs new file mode 100644 index 0000000000000..70de55320f7ae --- /dev/null +++ b/compiler/rustc_driver_impl/src/print.rs @@ -0,0 +1,20 @@ +use std::fmt; +use std::io::{self, Write as _}; + +macro_rules! safe_print { + ($($arg:tt)*) => {{ + $crate::print::print(std::format_args!($($arg)*)); + }}; +} + +macro_rules! safe_println { + ($($arg:tt)*) => { + safe_print!("{}\n", std::format_args!($($arg)*)) + }; +} + +pub(crate) fn print(args: fmt::Arguments<'_>) { + if let Err(_) = io::stdout().write_fmt(args) { + rustc_errors::FatalError.raise(); + } +} diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index ad2624a5d2d7b..65c2f5955cdd0 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -320,7 +320,7 @@ pub(super) fn check_opaque_for_inheriting_lifetimes( }; let prohibit_opaque = tcx .explicit_item_bounds(def_id) - .iter() + .subst_identity_iter_copied() .try_for_each(|(predicate, _)| predicate.visit_with(&mut visitor)); if let Some(ty) = prohibit_opaque.break_value() { diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index fe87aae8ed111..48214b899a4b8 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -839,7 +839,7 @@ impl<'tcx> TypeFolder> for ImplTraitInTraitCollector<'_, 'tcx> { }); self.types.insert(proj.def_id, (infer_ty, proj.substs)); // Recurse into bounds - for (pred, pred_span) in self.interner().bound_explicit_item_bounds(proj.def_id).subst_iter_copied(self.interner(), proj.substs) { + for (pred, pred_span) in self.interner().explicit_item_bounds(proj.def_id).subst_iter_copied(self.interner(), proj.substs) { let pred = pred.fold_with(self); let pred = self.ocx.normalize( &ObligationCause::misc(self.span, self.body_id), @@ -2023,7 +2023,7 @@ pub(super) fn check_type_bounds<'tcx>( }; let obligations: Vec<_> = tcx - .bound_explicit_item_bounds(trait_ty.def_id) + .explicit_item_bounds(trait_ty.def_id) .subst_iter_copied(tcx, rebased_substs) .map(|(concrete_ty_bound, span)| { debug!("check_type_bounds: concrete_ty_bound = {:?}", concrete_ty_bound); diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index b2ebbf993a1cc..0eafab017c7f3 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -360,7 +360,9 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe tcx, param_env, item_def_id, - tcx.explicit_item_bounds(item_def_id).to_vec(), + tcx.explicit_item_bounds(item_def_id) + .subst_identity_iter_copied() + .collect::>(), &FxIndexSet::default(), gat_def_id.def_id, gat_generics, @@ -1125,7 +1127,7 @@ fn check_associated_type_bounds(wfcx: &WfCheckingCtxt<'_, '_>, item: ty::AssocIt let bounds = wfcx.tcx().explicit_item_bounds(item.def_id); debug!("check_associated_type_bounds: bounds={:?}", bounds); - let wf_obligations = bounds.iter().flat_map(|&(bound, bound_span)| { + let wf_obligations = bounds.subst_identity_iter_copied().flat_map(|(bound, bound_span)| { let normalized_bound = wfcx.normalize(span, None, bound); traits::wf::predicate_obligations( wfcx.infcx, @@ -1588,7 +1590,7 @@ impl<'tcx> TypeVisitor> for ImplTraitInTraitFinder<'_, 'tcx> { } }); for (bound, bound_span) in tcx - .bound_explicit_item_bounds(opaque_ty.def_id) + .explicit_item_bounds(opaque_ty.def_id) .subst_iter_copied(tcx, opaque_ty.substs) { let bound = self.wfcx.normalize(bound_span, None, bound); diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs index 2e56d24638cdb..80d6bc7db9e8f 100644 --- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs +++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs @@ -79,14 +79,14 @@ fn opaque_type_bounds<'tcx>( pub(super) fn explicit_item_bounds( tcx: TyCtxt<'_>, def_id: LocalDefId, -) -> &'_ [(ty::Predicate<'_>, Span)] { +) -> ty::EarlyBinder<&'_ [(ty::Predicate<'_>, Span)]> { match tcx.opt_rpitit_info(def_id.to_def_id()) { // RPITIT's bounds are the same as opaque type bounds, but with // a projection self type. Some(ty::ImplTraitInTraitData::Trait { opaque_def_id, .. }) => { let item = tcx.hir().get_by_def_id(opaque_def_id.expect_local()).expect_item(); let opaque_ty = item.expect_opaque_ty(); - return opaque_type_bounds( + return ty::EarlyBinder(opaque_type_bounds( tcx, opaque_def_id.expect_local(), opaque_ty.bounds, @@ -95,7 +95,7 @@ pub(super) fn explicit_item_bounds( ty::InternalSubsts::identity_for_item(tcx, def_id), ), item.span, - ); + )); } // These should have been fed! Some(ty::ImplTraitInTraitData::Impl { .. }) => unreachable!(), @@ -103,7 +103,7 @@ pub(super) fn explicit_item_bounds( } let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); - match tcx.hir().get(hir_id) { + let bounds = match tcx.hir().get(hir_id) { hir::Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Type(bounds, _), span, @@ -123,16 +123,18 @@ pub(super) fn explicit_item_bounds( opaque_type_bounds(tcx, def_id, bounds, item_ty, *span) } _ => bug!("item_bounds called on {:?}", def_id), - } + }; + ty::EarlyBinder(bounds) } pub(super) fn item_bounds( tcx: TyCtxt<'_>, def_id: DefId, ) -> ty::EarlyBinder<&'_ ty::List>> { - let bounds = tcx.mk_predicates_from_iter(util::elaborate( - tcx, - tcx.explicit_item_bounds(def_id).iter().map(|&(bound, _span)| bound), - )); - ty::EarlyBinder(bounds) + tcx.explicit_item_bounds(def_id).map_bound(|bounds| { + tcx.mk_predicates_from_iter(util::elaborate( + tcx, + bounds.iter().map(|&(bound, _span)| bound), + )) + }) } diff --git a/compiler/rustc_hir_analysis/src/variance/mod.rs b/compiler/rustc_hir_analysis/src/variance/mod.rs index 4d240e90b143d..e735b048d7343 100644 --- a/compiler/rustc_hir_analysis/src/variance/mod.rs +++ b/compiler/rustc_hir_analysis/src/variance/mod.rs @@ -153,8 +153,7 @@ fn variance_of_opaque(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[ty::Varianc let mut collector = OpaqueTypeLifetimeCollector { tcx, root_def_id: item_def_id.to_def_id(), variances }; let id_substs = ty::InternalSubsts::identity_for_item(tcx, item_def_id); - for pred in tcx.bound_explicit_item_bounds(item_def_id.to_def_id()).transpose_iter() { - let pred = pred.map_bound(|(pred, _)| *pred).subst(tcx, id_substs); + for (pred, _) in tcx.explicit_item_bounds(item_def_id).subst_iter_copied(tcx, id_substs) { debug!(?pred); // We only ignore opaque type substs if the opaque type is the outermost type. diff --git a/compiler/rustc_hir_typeck/src/_match.rs b/compiler/rustc_hir_typeck/src/_match.rs index 6c2ce62722a54..aefde8109a07a 100644 --- a/compiler/rustc_hir_typeck/src/_match.rs +++ b/compiler/rustc_hir_typeck/src/_match.rs @@ -530,7 +530,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { for ty in [first_ty, second_ty] { for (pred, _) in self .tcx - .bound_explicit_item_bounds(rpit_def_id) + .explicit_item_bounds(rpit_def_id) .subst_iter_copied(self.tcx, substs) { let pred = pred.kind().rebind(match pred.kind().skip_binder() { diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs index 8c2495e1dd8c5..7046269c2de22 100644 --- a/compiler/rustc_hir_typeck/src/closure.rs +++ b/compiler/rustc_hir_typeck/src/closure.rs @@ -172,7 +172,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => self .deduce_closure_signature_from_predicates( expected_ty, - self.tcx.bound_explicit_item_bounds(def_id).subst_iter_copied(self.tcx, substs), + self.tcx.explicit_item_bounds(def_id).subst_iter_copied(self.tcx, substs), ), ty::Dynamic(ref object_type, ..) => { let sig = object_type.projection_bounds().find_map(|pb| { @@ -713,13 +713,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => self .tcx - .bound_explicit_item_bounds(def_id) + .explicit_item_bounds(def_id) .subst_iter_copied(self.tcx, substs) .find_map(|(p, s)| get_future_output(p, s))?, ty::Error(_) => return None, ty::Alias(ty::Projection, proj) if self.tcx.is_impl_trait_in_trait(proj.def_id) => self .tcx - .bound_explicit_item_bounds(proj.def_id) + .explicit_item_bounds(proj.def_id) .subst_iter_copied(self.tcx, proj.substs) .find_map(|(p, s)| get_future_output(p, s))?, _ => span_bug!( diff --git a/compiler/rustc_hir_typeck/src/generator_interior/mod.rs b/compiler/rustc_hir_typeck/src/generator_interior/mod.rs index 8feef332de8a7..5b432475fc384 100644 --- a/compiler/rustc_hir_typeck/src/generator_interior/mod.rs +++ b/compiler/rustc_hir_typeck/src/generator_interior/mod.rs @@ -571,7 +571,7 @@ fn check_must_not_suspend_ty<'tcx>( // FIXME: support adding the attribute to TAITs ty::Alias(ty::Opaque, ty::AliasTy { def_id: def, .. }) => { let mut has_emitted = false; - for &(predicate, _) in fcx.tcx.explicit_item_bounds(def) { + for &(predicate, _) in fcx.tcx.explicit_item_bounds(def).skip_binder() { // We only look at the `DefId`, so it is safe to skip the binder here. if let ty::PredicateKind::Clause(ty::Clause::Trait(ref poly_trait_predicate)) = predicate.kind().skip_binder() diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index b0c376a26f614..547f851526f0a 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -402,7 +402,7 @@ impl<'tcx> InferCtxt<'tcx> { let future_trait = self.tcx.require_lang_item(LangItem::Future, None); let item_def_id = self.tcx.associated_item_def_ids(future_trait)[0]; - self.tcx.bound_explicit_item_bounds(def_id).subst_iter_copied(self.tcx, substs).find_map( + self.tcx.explicit_item_bounds(def_id).subst_iter_copied(self.tcx, substs).find_map( |(predicate, _)| { predicate .kind() diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs index 680465bdab690..334395945ea96 100644 --- a/compiler/rustc_infer/src/infer/opaque_types.rs +++ b/compiler/rustc_infer/src/infer/opaque_types.rs @@ -540,7 +540,7 @@ impl<'tcx> InferCtxt<'tcx> { .obligations; } - let item_bounds = tcx.bound_explicit_item_bounds(def_id.to_def_id()); + let item_bounds = tcx.explicit_item_bounds(def_id); for (predicate, _) in item_bounds.subst_iter_copied(tcx, substs) { let predicate = predicate.fold_with(&mut BottomUpFolder { diff --git a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs index f9d43fe220036..15715c8fca039 100644 --- a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs +++ b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs @@ -74,7 +74,7 @@ impl<'tcx> LateLintPass<'tcx> for OpaqueHiddenInferredBound { // For every projection predicate in the opaque type's explicit bounds, // check that the type that we're assigning actually satisfies the bounds // of the associated type. - for &(pred, pred_span) in cx.tcx.explicit_item_bounds(def_id) { + for (pred, pred_span) in cx.tcx.explicit_item_bounds(def_id).subst_identity_iter_copied() { // Liberate bound regions in the predicate since we // don't actually care about lifetimes in this check. let predicate = cx.tcx.liberate_late_bound_regions(def_id, pred.kind()); @@ -112,7 +112,7 @@ impl<'tcx> LateLintPass<'tcx> for OpaqueHiddenInferredBound { // with `impl Send: OtherTrait`. for (assoc_pred, assoc_pred_span) in cx .tcx - .bound_explicit_item_bounds(proj.projection_ty.def_id) + .explicit_item_bounds(proj.projection_ty.def_id) .subst_iter_copied(cx.tcx, &proj.projection_ty.substs) { let assoc_pred = assoc_pred.fold_with(proj_replacer); diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index d677d51881e0e..eb175e96997b3 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -254,7 +254,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { } ty::Adt(def, _) => is_def_must_use(cx, def.did(), span), ty::Alias(ty::Opaque, ty::AliasTy { def_id: def, .. }) => { - elaborate(cx.tcx, cx.tcx.explicit_item_bounds(def).iter().cloned()) + elaborate(cx.tcx, cx.tcx.explicit_item_bounds(def).subst_identity_iter_copied()) // We only care about self bounds for the impl-trait .filter_only_self() .find_map(|(pred, _span)| { diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index 64245a0460d8f..0719dfc167fb5 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -23,7 +23,7 @@ use rustc_middle::mir::interpret::{AllocDecodingSession, AllocDecodingState}; use rustc_middle::ty::codec::TyDecoder; use rustc_middle::ty::fast_reject::SimplifiedType; use rustc_middle::ty::GeneratorDiagnosticData; -use rustc_middle::ty::{self, ParameterizedOverTcx, Ty, TyCtxt, Visibility}; +use rustc_middle::ty::{self, ParameterizedOverTcx, Predicate, Ty, TyCtxt, Visibility}; use rustc_serialize::opaque::MemDecoder; use rustc_serialize::{Decodable, Decoder}; use rustc_session::cstore::{ @@ -857,6 +857,20 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { ) } + fn get_explicit_item_bounds( + self, + index: DefIndex, + tcx: TyCtxt<'tcx>, + ) -> ty::EarlyBinder<&'tcx [(Predicate<'tcx>, Span)]> { + let lazy = self.root.tables.explicit_item_bounds.get(self, index); + let output = if lazy.is_default() { + &mut [] + } else { + tcx.arena.alloc_from_iter(lazy.decode((self, tcx))) + }; + ty::EarlyBinder(&*output) + } + fn get_variant(self, kind: &DefKind, index: DefIndex, parent_did: DefId) -> ty::VariantDef { let adt_kind = match kind { DefKind::Variant => ty::AdtKind::Enum, diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 141980912b1d6..4a3b783c63670 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -203,7 +203,7 @@ impl IntoArgs for (CrateNum, SimplifiedType) { } provide! { tcx, def_id, other, cdata, - explicit_item_bounds => { table_defaulted_array } + explicit_item_bounds => { cdata.get_explicit_item_bounds(def_id.index, tcx) } explicit_predicates_of => { table } generics_of => { table } inferred_outlives_of => { table_defaulted_array } diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 17a9daee7d038..f5ffdd27cae3f 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1423,7 +1423,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { fn encode_explicit_item_bounds(&mut self, def_id: DefId) { debug!("EncodeContext::encode_explicit_item_bounds({:?})", def_id); - let bounds = self.tcx.explicit_item_bounds(def_id); + let bounds = self.tcx.explicit_item_bounds(def_id).skip_binder(); record_defaulted_array!(self.tables.explicit_item_bounds[def_id] <- bounds); } diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs index 76a8367b2c460..e9172e767e036 100644 --- a/compiler/rustc_middle/src/lib.rs +++ b/compiler/rustc_middle/src/lib.rs @@ -60,6 +60,7 @@ #![feature(const_option)] #![feature(trait_alias)] #![feature(ptr_alignment_type)] +#![feature(macro_metavar_expr)] #![recursion_limit = "512"] #![allow(rustc::potential_query_instability)] diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 7109ff95b8710..84b5d6b0d0fa1 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -251,7 +251,7 @@ rustc_queries! { /// `key` is the `DefId` of the associated type or opaque type. /// /// Bounds from the parent (e.g. with nested impl trait) are not included. - query explicit_item_bounds(key: DefId) -> &'tcx [(ty::Predicate<'tcx>, Span)] { + query explicit_item_bounds(key: DefId) -> ty::EarlyBinder<&'tcx [(ty::Predicate<'tcx>, Span)]> { desc { |tcx| "finding item bounds for `{}`", tcx.def_path_str(key) } cache_on_disk_if { key.is_local() } separate_provide_extern diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 4a4f6770fc46f..7df4be263d58d 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -1603,7 +1603,7 @@ impl<'tcx> TyCtxt<'tcx> { let ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) = ty.kind() else { return false }; let future_trait = self.require_lang_item(LangItem::Future, None); - self.explicit_item_bounds(def_id).iter().any(|(predicate, _)| { + self.explicit_item_bounds(def_id).skip_binder().iter().any(|&(predicate, _)| { let ty::PredicateKind::Clause(ty::Clause::Trait(trait_predicate)) = predicate.kind().skip_binder() else { return false; }; diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 17647d13f9979..8e4e708b73c45 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -861,6 +861,11 @@ impl<'tcx> PolyTraitPredicate<'tcx> { pub fn is_const_if_const(self) -> bool { self.skip_binder().is_const_if_const() } + + #[inline] + pub fn polarity(self) -> ImplPolarity { + self.skip_binder().polarity + } } /// `A: B` @@ -1497,29 +1502,12 @@ struct ParamTag { constness: hir::Constness, } -unsafe impl rustc_data_structures::tagged_ptr::Tag for ParamTag { - const BITS: u32 = 2; - - #[inline] - fn into_usize(self) -> usize { - match self { - Self { reveal: traits::Reveal::UserFacing, constness: hir::Constness::NotConst } => 0, - Self { reveal: traits::Reveal::All, constness: hir::Constness::NotConst } => 1, - Self { reveal: traits::Reveal::UserFacing, constness: hir::Constness::Const } => 2, - Self { reveal: traits::Reveal::All, constness: hir::Constness::Const } => 3, - } - } - - #[inline] - unsafe fn from_usize(ptr: usize) -> Self { - match ptr { - 0 => Self { reveal: traits::Reveal::UserFacing, constness: hir::Constness::NotConst }, - 1 => Self { reveal: traits::Reveal::All, constness: hir::Constness::NotConst }, - 2 => Self { reveal: traits::Reveal::UserFacing, constness: hir::Constness::Const }, - 3 => Self { reveal: traits::Reveal::All, constness: hir::Constness::Const }, - _ => std::hint::unreachable_unchecked(), - } - } +impl_tag! { + impl Tag for ParamTag; + ParamTag { reveal: traits::Reveal::UserFacing, constness: hir::Constness::NotConst }, + ParamTag { reveal: traits::Reveal::All, constness: hir::Constness::NotConst }, + ParamTag { reveal: traits::Reveal::UserFacing, constness: hir::Constness::Const }, + ParamTag { reveal: traits::Reveal::All, constness: hir::Constness::Const }, } impl<'tcx> fmt::Debug for ParamEnv<'tcx> { diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 4c95d0f841514..1c1432ecd5a05 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -914,7 +914,7 @@ pub trait PrettyPrinter<'tcx>: // Grab the "TraitA + TraitB" from `impl TraitA + TraitB`, // by looking up the projections associated with the def_id. - let bounds = tcx.bound_explicit_item_bounds(def_id); + let bounds = tcx.explicit_item_bounds(def_id); let mut traits = FxIndexMap::default(); let mut fn_traits = FxIndexMap::default(); diff --git a/compiler/rustc_middle/src/ty/subst.rs b/compiler/rustc_middle/src/ty/subst.rs index a439211ca336a..63b2acdbe4e5d 100644 --- a/compiler/rustc_middle/src/ty/subst.rs +++ b/compiler/rustc_middle/src/ty/subst.rs @@ -612,6 +612,12 @@ where ) -> SubstIter<'s, 'tcx, I> { SubstIter { it: self.0.into_iter(), tcx, substs } } + + /// Similar to [`subst_identity`](EarlyBinder::subst_identity), + /// but on an iterator of `TypeFoldable` values. + pub fn subst_identity_iter(self) -> I::IntoIter { + self.0.into_iter() + } } pub struct SubstIter<'s, 'tcx, I: IntoIterator> { @@ -664,6 +670,12 @@ where ) -> SubstIterCopied<'s, 'tcx, I> { SubstIterCopied { it: self.0.into_iter(), tcx, substs } } + + /// Similar to [`subst_identity`](EarlyBinder::subst_identity), + /// but on an iterator of values that deref to a `TypeFoldable`. + pub fn subst_identity_iter_copied(self) -> impl Iterator::Target> { + self.0.into_iter().map(|v| *v) + } } pub struct SubstIterCopied<'a, 'tcx, I: IntoIterator> { diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 7127fdbf26a1c..4c346b00256cc 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -701,13 +701,6 @@ impl<'tcx> TyCtxt<'tcx> { if visitor.found_recursion { Err(expanded_type) } else { Ok(expanded_type) } } - pub fn bound_explicit_item_bounds( - self, - def_id: DefId, - ) -> ty::EarlyBinder<&'tcx [(ty::Predicate<'tcx>, rustc_span::Span)]> { - ty::EarlyBinder(self.explicit_item_bounds(def_id)) - } - /// Returns names of captured upvars for closures and generators. /// /// Here are some examples: diff --git a/compiler/rustc_mir_transform/src/generator.rs b/compiler/rustc_mir_transform/src/generator.rs index 34a7ee9e264f7..e44dd084b2de5 100644 --- a/compiler/rustc_mir_transform/src/generator.rs +++ b/compiler/rustc_mir_transform/src/generator.rs @@ -1800,7 +1800,7 @@ fn check_must_not_suspend_ty<'tcx>( // FIXME: support adding the attribute to TAITs ty::Alias(ty::Opaque, ty::AliasTy { def_id: def, .. }) => { let mut has_emitted = false; - for &(predicate, _) in tcx.explicit_item_bounds(def) { + for &(predicate, _) in tcx.explicit_item_bounds(def).skip_binder() { // We only look at the `DefId`, so it is safe to skip the binder here. if let ty::PredicateKind::Clause(ty::Clause::Trait(ref poly_trait_predicate)) = predicate.kind().skip_binder() diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 9567329192d52..c607c7fd5f4a7 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -269,7 +269,7 @@ where // and are visited by shallow visitors. self.visit_predicates(ty::GenericPredicates { parent: None, - predicates: tcx.explicit_item_bounds(def_id), + predicates: tcx.explicit_item_bounds(def_id).skip_binder(), })?; } } @@ -1784,7 +1784,7 @@ impl SearchInterfaceForPrivateItemsVisitor<'_> { fn bounds(&mut self) -> &mut Self { self.visit_predicates(ty::GenericPredicates { parent: None, - predicates: self.tcx.explicit_item_bounds(self.item_def_id), + predicates: self.tcx.explicit_item_bounds(self.item_def_id).skip_binder(), }); self } diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs index 8e7097ce4a779..c97473e6241f2 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs @@ -86,8 +86,9 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { ) -> QueryResult<'tcx> { if let Some(poly_trait_pred) = assumption.to_opt_poly_trait_pred() && poly_trait_pred.def_id() == goal.predicate.def_id() + && poly_trait_pred.polarity() == goal.predicate.polarity { - // FIXME: Constness and polarity + // FIXME: Constness ecx.probe(|ecx| { let assumption_trait_pred = ecx.instantiate_binder_with_infer(poly_trait_pred); @@ -111,6 +112,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { ) -> QueryResult<'tcx> { if let Some(poly_trait_pred) = assumption.to_opt_poly_trait_pred() && poly_trait_pred.def_id() == goal.predicate.def_id() + && poly_trait_pred.polarity() == goal.predicate.polarity { // FIXME: Constness and polarity ecx.probe(|ecx| { @@ -147,6 +149,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, ) -> QueryResult<'tcx> { + if goal.predicate.polarity != ty::ImplPolarity::Positive { + return Err(NoSolution); + } + if let Some(result) = ecx.disqualify_auto_trait_candidate_due_to_possible_impl(goal) { return result; } @@ -161,6 +167,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, ) -> QueryResult<'tcx> { + if goal.predicate.polarity != ty::ImplPolarity::Positive { + return Err(NoSolution); + } + let tcx = ecx.tcx(); ecx.probe(|ecx| { @@ -176,6 +186,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, ) -> QueryResult<'tcx> { + if goal.predicate.polarity != ty::ImplPolarity::Positive { + return Err(NoSolution); + } + ecx.probe_and_evaluate_goal_for_constituent_tys( goal, structural_traits::instantiate_constituent_tys_for_sized_trait, @@ -186,6 +200,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, ) -> QueryResult<'tcx> { + if goal.predicate.polarity != ty::ImplPolarity::Positive { + return Err(NoSolution); + } + ecx.probe_and_evaluate_goal_for_constituent_tys( goal, structural_traits::instantiate_constituent_tys_for_copy_clone_trait, @@ -196,6 +214,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, ) -> QueryResult<'tcx> { + if goal.predicate.polarity != ty::ImplPolarity::Positive { + return Err(NoSolution); + } + if goal.predicate.self_ty().has_non_region_infer() { return ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS); } @@ -217,6 +239,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, ) -> QueryResult<'tcx> { + if goal.predicate.polarity != ty::ImplPolarity::Positive { + return Err(NoSolution); + } + if let ty::FnPtr(..) = goal.predicate.self_ty().kind() { ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } else { @@ -229,6 +255,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { goal: Goal<'tcx, Self>, goal_kind: ty::ClosureKind, ) -> QueryResult<'tcx> { + if goal.predicate.polarity != ty::ImplPolarity::Positive { + return Err(NoSolution); + } + let tcx = ecx.tcx(); let tupled_inputs_and_output = match structural_traits::extract_tupled_inputs_and_output_from_callable( @@ -259,6 +289,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, ) -> QueryResult<'tcx> { + if goal.predicate.polarity != ty::ImplPolarity::Positive { + return Err(NoSolution); + } + if let ty::Tuple(..) = goal.predicate.self_ty().kind() { ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } else { @@ -268,8 +302,12 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { fn consider_builtin_pointee_candidate( ecx: &mut EvalCtxt<'_, 'tcx>, - _goal: Goal<'tcx, Self>, + goal: Goal<'tcx, Self>, ) -> QueryResult<'tcx> { + if goal.predicate.polarity != ty::ImplPolarity::Positive { + return Err(NoSolution); + } + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } @@ -277,6 +315,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, ) -> QueryResult<'tcx> { + if goal.predicate.polarity != ty::ImplPolarity::Positive { + return Err(NoSolution); + } + let ty::Generator(def_id, _, _) = *goal.predicate.self_ty().kind() else { return Err(NoSolution); }; @@ -297,6 +339,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, ) -> QueryResult<'tcx> { + if goal.predicate.polarity != ty::ImplPolarity::Positive { + return Err(NoSolution); + } + let self_ty = goal.predicate.self_ty(); let ty::Generator(def_id, substs, _) = *self_ty.kind() else { return Err(NoSolution); @@ -326,6 +372,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, ) -> QueryResult<'tcx> { + if goal.predicate.polarity != ty::ImplPolarity::Positive { + return Err(NoSolution); + } + let tcx = ecx.tcx(); let a_ty = goal.predicate.self_ty(); let b_ty = goal.predicate.trait_ref.substs.type_at(1); @@ -447,6 +497,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, ) -> Vec> { + if goal.predicate.polarity != ty::ImplPolarity::Positive { + return vec![]; + } + let tcx = ecx.tcx(); let a_ty = goal.predicate.self_ty(); @@ -521,8 +575,12 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { fn consider_builtin_discriminant_kind_candidate( ecx: &mut EvalCtxt<'_, 'tcx>, - _goal: Goal<'tcx, Self>, + goal: Goal<'tcx, Self>, ) -> QueryResult<'tcx> { + if goal.predicate.polarity != ty::ImplPolarity::Positive { + return Err(NoSolution); + } + // `DiscriminantKind` is automatically implemented for every type. ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } @@ -531,6 +589,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, ) -> QueryResult<'tcx> { + if goal.predicate.polarity != ty::ImplPolarity::Positive { + return Err(NoSolution); + } + if !goal.param_env.is_const() { // `Destruct` is automatically implemented for every type in // non-const environments. @@ -545,6 +607,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, ) -> QueryResult<'tcx> { + if goal.predicate.polarity != ty::ImplPolarity::Positive { + return Err(NoSolution); + } + // `rustc_transmute` does not have support for type or const params if goal.has_non_region_placeholders() { return Err(NoSolution); diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index b8ad1925e4eaa..73e2efc3b000e 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -297,8 +297,8 @@ fn bounds_reference_self(tcx: TyCtxt<'_>, trait_def_id: DefId) -> SmallVec<[Span tcx.associated_items(trait_def_id) .in_definition_order() .filter(|item| item.kind == ty::AssocKind::Type) - .flat_map(|item| tcx.explicit_item_bounds(item.def_id)) - .filter_map(|pred_span| predicate_references_self(tcx, *pred_span)) + .flat_map(|item| tcx.explicit_item_bounds(item.def_id).subst_identity_iter_copied()) + .filter_map(|pred_span| predicate_references_self(tcx, pred_span)) .collect() } diff --git a/compiler/rustc_traits/src/chalk/db.rs b/compiler/rustc_traits/src/chalk/db.rs index 9683e48478edc..c319b2e31c7e6 100644 --- a/compiler/rustc_traits/src/chalk/db.rs +++ b/compiler/rustc_traits/src/chalk/db.rs @@ -50,12 +50,11 @@ impl<'tcx> RustIrDatabase<'tcx> { where ty::Predicate<'tcx>: LowerInto<'tcx, std::option::Option>, { - let bounds = self.interner.tcx.bound_explicit_item_bounds(def_id); - bounds - .0 - .iter() - .map(|(bound, _)| bounds.rebind(*bound).subst(self.interner.tcx, &bound_vars)) - .filter_map(|bound| LowerInto::>::lower_into(bound, self.interner)) + self.interner + .tcx + .explicit_item_bounds(def_id) + .subst_iter_copied(self.interner.tcx, &bound_vars) + .filter_map(|(bound, _)| LowerInto::>::lower_into(bound, self.interner)) .collect() } } @@ -506,15 +505,11 @@ impl<'tcx> chalk_solve::RustIrDatabase> for RustIrDatabase<'t let identity_substs = InternalSubsts::identity_for_item(self.interner.tcx, opaque_ty_id.0); - let explicit_item_bounds = self.interner.tcx.bound_explicit_item_bounds(opaque_ty_id.0); + let explicit_item_bounds = self.interner.tcx.explicit_item_bounds(opaque_ty_id.0); let bounds = explicit_item_bounds - .0 - .iter() + .subst_iter_copied(self.interner.tcx, &bound_vars) .map(|(bound, _)| { - explicit_item_bounds.rebind(*bound).subst(self.interner.tcx, &bound_vars) - }) - .map(|bound| { bound.fold_with(&mut ReplaceOpaqueTyFolder { tcx: self.interner.tcx, opaque_ty_id, diff --git a/library/alloc/src/task.rs b/library/alloc/src/task.rs index 9d8e309a978d9..5d9772b878b03 100644 --- a/library/alloc/src/task.rs +++ b/library/alloc/src/task.rs @@ -39,6 +39,7 @@ use crate::sync::Arc; /// use std::sync::Arc; /// use std::task::{Context, Poll, Wake}; /// use std::thread::{self, Thread}; +/// use core::pin::pin; /// /// /// A waker that wakes up the current thread when called. /// struct ThreadWaker(Thread); @@ -52,7 +53,7 @@ use crate::sync::Arc; /// /// Run a future to completion on the current thread. /// fn block_on(fut: impl Future) -> T { /// // Pin the future so it can be polled. -/// let mut fut = Box::pin(fut); +/// let mut fut = pin!(fut); /// /// // Create a new context to be passed to the future. /// let t = thread::current(); diff --git a/library/core/src/slice/sort.rs b/library/core/src/slice/sort.rs index 07fd96f929586..e6e3b55efa9ae 100644 --- a/library/core/src/slice/sort.rs +++ b/library/core/src/slice/sort.rs @@ -1456,7 +1456,6 @@ pub struct TimSortRun { /// Takes a range as denoted by start and end, that is already sorted and extends it to the right if /// necessary with sorts optimized for smaller ranges such as insertion sort. -#[cfg(not(no_global_oom_handling))] fn provide_sorted_batch(v: &mut [T], start: usize, mut end: usize, is_less: &mut F) -> usize where F: FnMut(&T, &T) -> bool, diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 04379c2bca97d..c992a5388d199 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -422,8 +422,8 @@ fn clean_projection<'tcx>( let bounds = cx .tcx .explicit_item_bounds(ty.skip_binder().def_id) - .iter() - .map(|(bound, _)| EarlyBinder(*bound).subst(cx.tcx, ty.skip_binder().substs)) + .subst_iter_copied(cx.tcx, ty.skip_binder().substs) + .map(|(pred, _)| pred) .collect::>(); return clean_middle_opaque_bounds(cx, bounds); } @@ -1315,10 +1315,11 @@ pub(crate) fn clean_middle_assoc_item<'tcx>( } if let ty::TraitContainer = assoc_item.container { - let bounds = tcx.explicit_item_bounds(assoc_item.def_id); + let bounds = + tcx.explicit_item_bounds(assoc_item.def_id).subst_identity_iter_copied(); let predicates = tcx.explicit_predicates_of(assoc_item.def_id).predicates; let predicates = - tcx.arena.alloc_from_iter(bounds.into_iter().chain(predicates).copied()); + tcx.arena.alloc_from_iter(bounds.chain(predicates.iter().copied())); let mut generics = clean_ty_generics( cx, tcx.generics_of(assoc_item.def_id), @@ -1845,8 +1846,8 @@ pub(crate) fn clean_middle_ty<'tcx>( let bounds = cx .tcx .explicit_item_bounds(def_id) - .iter() - .map(|(bound, _)| EarlyBinder(*bound).subst(cx.tcx, substs)) + .subst_iter_copied(cx.tcx, substs) + .map(|(bound, _)| bound) .collect::>(); clean_middle_opaque_bounds(cx, bounds) } diff --git a/src/tools/clippy/clippy_lints/src/future_not_send.rs b/src/tools/clippy/clippy_lints/src/future_not_send.rs index ed0bd58c770c7..ff838c2d56e43 100644 --- a/src/tools/clippy/clippy_lints/src/future_not_send.rs +++ b/src/tools/clippy/clippy_lints/src/future_not_send.rs @@ -4,7 +4,7 @@ use rustc_hir::intravisit::FnKind; use rustc_hir::{Body, FnDecl}; use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty::{self, AliasTy, Clause, EarlyBinder, PredicateKind}; +use rustc_middle::ty::{self, AliasTy, Clause, PredicateKind}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::def_id::LocalDefId; use rustc_span::{sym, Span}; @@ -66,8 +66,7 @@ impl<'tcx> LateLintPass<'tcx> for FutureNotSend { if let ty::Alias(ty::Opaque, AliasTy { def_id, substs, .. }) = *ret_ty.kind() { let preds = cx.tcx.explicit_item_bounds(def_id); let mut is_future = false; - for &(p, _span) in preds { - let p = EarlyBinder(p).subst(cx.tcx, substs); + for (p, _span) in preds.subst_iter_copied(cx.tcx, substs) { if let Some(trait_pred) = p.to_opt_poly_trait_pred() { if Some(trait_pred.skip_binder().trait_ref.def_id) == cx.tcx.lang_items().future_trait() { is_future = true; diff --git a/src/tools/clippy/clippy_utils/src/ty.rs b/src/tools/clippy/clippy_utils/src/ty.rs index 8b996c188161d..cb700126c2bd5 100644 --- a/src/tools/clippy/clippy_utils/src/ty.rs +++ b/src/tools/clippy/clippy_utils/src/ty.rs @@ -90,7 +90,7 @@ pub fn contains_ty_adt_constructor_opaque<'tcx>(cx: &LateContext<'tcx>, ty: Ty<' return false; } - for &(predicate, _span) in cx.tcx.explicit_item_bounds(def_id) { + for (predicate, _span) in cx.tcx.explicit_item_bounds(def_id).subst_identity_iter_copied() { match predicate.kind().skip_binder() { // For `impl Trait`, it will register a predicate of `T: Trait`, so we go through // and check substituions to find `U`. @@ -267,7 +267,7 @@ pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { }, ty::Tuple(substs) => substs.iter().any(|ty| is_must_use_ty(cx, ty)), ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) => { - for (predicate, _) in cx.tcx.explicit_item_bounds(*def_id) { + for (predicate, _) in cx.tcx.explicit_item_bounds(def_id).skip_binder() { if let ty::PredicateKind::Clause(ty::Clause::Trait(trait_predicate)) = predicate.kind().skip_binder() { if cx.tcx.has_attr(trait_predicate.trait_ref.def_id, sym::must_use) { return true; @@ -743,7 +743,7 @@ fn sig_for_projection<'tcx>(cx: &LateContext<'tcx>, ty: AliasTy<'tcx>) -> Option for (pred, _) in cx .tcx - .bound_explicit_item_bounds(ty.def_id) + .explicit_item_bounds(ty.def_id) .subst_iter_copied(cx.tcx, ty.substs) { match pred.kind().skip_binder() { diff --git a/tests/ui/traits/new-solver/negative-coherence-bounds.rs b/tests/ui/traits/new-solver/negative-coherence-bounds.rs new file mode 100644 index 0000000000000..5436b02c3ded2 --- /dev/null +++ b/tests/ui/traits/new-solver/negative-coherence-bounds.rs @@ -0,0 +1,40 @@ +// check-pass + +// This test verifies that negative trait predicate cannot be satisfied from a +// positive param-env candidate. + +// Negative coherence is one of the only places where we actually construct and +// evaluate negative predicates. Specifically, when verifying whether the first +// and second impls below overlap, we do not want to consider them disjoint, +// otherwise the second impl would be missing an associated type `type Item` +// which is provided by the first impl that it is specializing. + +#![feature(specialization)] +//~^ WARN the feature `specialization` is incomplete +#![feature(with_negative_coherence)] + +trait BoxIter { + type Item; + + fn last(self) -> Option; +} + +impl BoxIter for Box { + type Item = I::Item; + + default fn last(self) -> Option { + todo!() + } +} + +// When checking that this impl does/doesn't overlap the one above, we evaluate +// a negative version of all of the where-clause predicates of the impl below. +// For `I: !Iterator`, we should make sure that the param-env clause `I: Iterator` +// from above doesn't satisfy this predicate. +impl BoxIter for Box { + fn last(self) -> Option { + (*self).last() + } +} + +fn main() {} diff --git a/tests/ui/traits/new-solver/negative-coherence-bounds.stderr b/tests/ui/traits/new-solver/negative-coherence-bounds.stderr new file mode 100644 index 0000000000000..4127f51f56da2 --- /dev/null +++ b/tests/ui/traits/new-solver/negative-coherence-bounds.stderr @@ -0,0 +1,12 @@ +warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/negative-coherence-bounds.rs:12:12 + | +LL | #![feature(specialization)] + | ^^^^^^^^^^^^^^ + | + = note: see issue #31844 for more information + = help: consider using `min_specialization` instead, which is more stable and complete + = note: `#[warn(incomplete_features)]` on by default + +warning: 1 warning emitted +