diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index 31ca0e46091cc..2a92a4b48edcc 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -415,10 +415,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { infcx.instantiate_canonical(span, &query_input.canonical); let query::MethodAutoderefSteps { predefined_opaques_in_body: _, self_ty } = value; debug!(?self_ty, ?query_input, "probe_op: Mode::Path"); + let prev_opaque_entries = self.inner.borrow_mut().opaque_types().num_entries(); MethodAutoderefStepsResult { steps: infcx.tcx.arena.alloc_from_iter([CandidateStep { - self_ty: self - .make_query_response_ignoring_pending_obligations(var_values, self_ty), + self_ty: self.make_query_response_ignoring_pending_obligations( + var_values, + self_ty, + prev_opaque_entries, + ), self_ty_is_opaque: false, autoderefs: 0, from_unsafe_deref: false, @@ -607,6 +611,7 @@ pub(crate) fn method_autoderef_steps<'tcx>( debug!(?key, ?ty, ?prev, "ignore duplicate in `opaque_types_storage`"); } } + let prev_opaque_entries = infcx.inner.borrow_mut().opaque_types().num_entries(); // We accept not-yet-defined opaque types in the autoderef // chain to support recursive calls. We do error if the final @@ -650,8 +655,11 @@ pub(crate) fn method_autoderef_steps<'tcx>( .zip(reachable_via_deref) .map(|((ty, d), reachable_via_deref)| { let step = CandidateStep { - self_ty: infcx - .make_query_response_ignoring_pending_obligations(inference_vars, ty), + self_ty: infcx.make_query_response_ignoring_pending_obligations( + inference_vars, + ty, + prev_opaque_entries, + ), self_ty_is_opaque: self_ty_is_opaque(ty), autoderefs: d, from_unsafe_deref: reached_raw_pointer, @@ -671,8 +679,11 @@ pub(crate) fn method_autoderef_steps<'tcx>( .by_ref() .map(|(ty, d)| { let step = CandidateStep { - self_ty: infcx - .make_query_response_ignoring_pending_obligations(inference_vars, ty), + self_ty: infcx.make_query_response_ignoring_pending_obligations( + inference_vars, + ty, + prev_opaque_entries, + ), self_ty_is_opaque: self_ty_is_opaque(ty), autoderefs: d, from_unsafe_deref: reached_raw_pointer, @@ -692,11 +703,19 @@ pub(crate) fn method_autoderef_steps<'tcx>( let opt_bad_ty = match final_ty.kind() { ty::Infer(ty::TyVar(_)) if !self_ty_is_opaque(final_ty) => Some(MethodAutoderefBadTy { reached_raw_pointer, - ty: infcx.make_query_response_ignoring_pending_obligations(inference_vars, final_ty), + ty: infcx.make_query_response_ignoring_pending_obligations( + inference_vars, + final_ty, + prev_opaque_entries, + ), }), ty::Error(_) => Some(MethodAutoderefBadTy { reached_raw_pointer, - ty: infcx.make_query_response_ignoring_pending_obligations(inference_vars, final_ty), + ty: infcx.make_query_response_ignoring_pending_obligations( + inference_vars, + final_ty, + prev_opaque_entries, + ), }), ty::Array(elem_ty, _) => { let autoderefs = steps.iter().filter(|s| s.reachable_via_deref).count() - 1; @@ -704,6 +723,7 @@ pub(crate) fn method_autoderef_steps<'tcx>( self_ty: infcx.make_query_response_ignoring_pending_obligations( inference_vars, Ty::new_slice(infcx.tcx, *elem_ty), + prev_opaque_entries, ), self_ty_is_opaque: false, autoderefs, diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs index 65b0f82114329..846123b8aad93 100644 --- a/compiler/rustc_infer/src/infer/canonical/query_response.rs +++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs @@ -24,7 +24,8 @@ use crate::infer::canonical::{ }; use crate::infer::region_constraints::RegionConstraintData; use crate::infer::{ - DefineOpaqueTypes, InferCtxt, InferOk, InferResult, SubregionOrigin, TypeOutlivesConstraint, + DefineOpaqueTypes, InferCtxt, InferOk, InferResult, OpaqueTypeStorageEntries, SubregionOrigin, + TypeOutlivesConstraint, }; use crate::traits::query::NoSolution; use crate::traits::{ObligationCause, PredicateObligations, ScrubbedTraitError, TraitEngine}; @@ -81,6 +82,7 @@ impl<'tcx> InferCtxt<'tcx> { &self, inference_vars: CanonicalVarValues<'tcx>, answer: T, + prev_entries: OpaqueTypeStorageEntries, ) -> Canonical<'tcx, QueryResponse<'tcx, T>> where T: Debug + TypeFoldable>, @@ -96,7 +98,7 @@ impl<'tcx> InferCtxt<'tcx> { self.inner .borrow_mut() .opaque_type_storage - .iter_opaque_types() + .opaque_types_added_since(prev_entries) .map(|(k, v)| (k, v.ty)) .collect() } else { diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs index 246152f5390c6..72985ff607789 100644 --- a/compiler/rustc_query_impl/src/plumbing.rs +++ b/compiler/rustc_query_impl/src/plumbing.rs @@ -35,6 +35,8 @@ use rustc_span::def_id::LOCAL_CRATE; use crate::QueryConfigRestored; +/// Implements [`QueryContext`] for use by [`rustc_query_system`], since that +/// crate does not have direct access to [`TyCtxt`]. #[derive(Copy, Clone)] pub struct QueryCtxt<'tcx> { pub tcx: TyCtxt<'tcx>, @@ -47,15 +49,6 @@ impl<'tcx> QueryCtxt<'tcx> { } } -impl<'tcx> std::ops::Deref for QueryCtxt<'tcx> { - type Target = TyCtxt<'tcx>; - - #[inline] - fn deref(&self) -> &Self::Target { - &self.tcx - } -} - impl<'tcx> HasDepContext for QueryCtxt<'tcx> { type Deps = rustc_middle::dep_graph::DepsType; type DepContext = TyCtxt<'tcx>; @@ -69,14 +62,16 @@ impl<'tcx> HasDepContext for QueryCtxt<'tcx> { impl QueryContext for QueryCtxt<'_> { #[inline] fn jobserver_proxy(&self) -> &Proxy { - &*self.jobserver_proxy + &self.tcx.jobserver_proxy } #[inline] fn next_job_id(self) -> QueryJobId { QueryJobId( - NonZero::new(self.query_system.jobs.fetch_add(1, std::sync::atomic::Ordering::Relaxed)) - .unwrap(), + NonZero::new( + self.tcx.query_system.jobs.fetch_add(1, std::sync::atomic::Ordering::Relaxed), + ) + .unwrap(), ) } @@ -113,7 +108,8 @@ impl QueryContext for QueryCtxt<'_> { self, prev_dep_node_index: SerializedDepNodeIndex, ) -> Option { - self.query_system + self.tcx + .query_system .on_disk_cache .as_ref() .and_then(|c| c.load_side_effect(self.tcx, prev_dep_node_index)) @@ -122,7 +118,7 @@ impl QueryContext for QueryCtxt<'_> { #[inline(never)] #[cold] fn store_side_effect(self, dep_node_index: DepNodeIndex, side_effect: QuerySideEffect) { - if let Some(c) = self.query_system.on_disk_cache.as_ref() { + if let Some(c) = self.tcx.query_system.on_disk_cache.as_ref() { c.store_side_effect(dep_node_index, side_effect) } } @@ -140,7 +136,9 @@ impl QueryContext for QueryCtxt<'_> { // as `self`, so we use `with_related_context` to relate the 'tcx lifetimes // when accessing the `ImplicitCtxt`. tls::with_related_context(self.tcx, move |current_icx| { - if depth_limit && !self.recursion_limit().value_within_limit(current_icx.query_depth) { + if depth_limit + && !self.tcx.recursion_limit().value_within_limit(current_icx.query_depth) + { self.depth_limit_error(token); } @@ -161,16 +159,16 @@ impl QueryContext for QueryCtxt<'_> { let query_map = self.collect_active_jobs(true).expect("failed to collect active queries"); let (info, depth) = job.find_dep_kind_root(query_map); - let suggested_limit = match self.recursion_limit() { + let suggested_limit = match self.tcx.recursion_limit() { Limit(0) => Limit(2), limit => limit * 2, }; - self.sess.dcx().emit_fatal(QueryOverflow { + self.tcx.sess.dcx().emit_fatal(QueryOverflow { span: info.job.span, note: QueryOverflowNote { desc: info.query.description, depth }, suggested_limit, - crate_name: self.crate_name(LOCAL_CRATE), + crate_name: self.tcx.crate_name(LOCAL_CRATE), }); } } @@ -367,7 +365,7 @@ pub(crate) fn encode_query_results<'a, 'tcx, Q>( Q: super::QueryConfigRestored<'tcx>, Q::RestoredValue: Encodable>, { - let _timer = qcx.profiler().generic_activity_with_arg("encode_query_results_for", query.name()); + let _timer = qcx.tcx.prof.generic_activity_with_arg("encode_query_results_for", query.name()); assert!(query.query_state(qcx).all_inactive()); let cache = query.query_cache(qcx); @@ -389,8 +387,7 @@ pub(crate) fn query_key_hash_verify<'tcx>( query: impl QueryConfig>, qcx: QueryCtxt<'tcx>, ) { - let _timer = - qcx.profiler().generic_activity_with_arg("query_key_hash_verify_for", query.name()); + let _timer = qcx.tcx.prof.generic_activity_with_arg("query_key_hash_verify_for", query.name()); let mut map = UnordMap::default(); diff --git a/library/core/src/hint.rs b/library/core/src/hint.rs index b7f78288b2b62..dccac26e07e69 100644 --- a/library/core/src/hint.rs +++ b/library/core/src/hint.rs @@ -658,7 +658,7 @@ pub const fn must_use(value: T) -> T { /// } /// } /// ``` -#[unstable(feature = "likely_unlikely", issue = "136873")] +#[unstable(feature = "likely_unlikely", issue = "151619")] #[inline(always)] pub const fn likely(b: bool) -> bool { crate::intrinsics::likely(b) @@ -708,7 +708,7 @@ pub const fn likely(b: bool) -> bool { /// } /// } /// ``` -#[unstable(feature = "likely_unlikely", issue = "136873")] +#[unstable(feature = "likely_unlikely", issue = "151619")] #[inline(always)] pub const fn unlikely(b: bool) -> bool { crate::intrinsics::unlikely(b) @@ -717,6 +717,10 @@ pub const fn unlikely(b: bool) -> bool { /// Hints to the compiler that given path is cold, i.e., unlikely to be taken. The compiler may /// choose to optimize paths that are not cold at the expense of paths that are cold. /// +/// Note that like all hints, the exact effect to codegen is not guaranteed. Using `cold_path` +/// can actually *decrease* performance if the branch is called more than expected. It is advisable +/// to perform benchmarks to tell if this function is useful. +/// /// # Examples /// /// ``` @@ -741,6 +745,38 @@ pub const fn unlikely(b: bool) -> bool { /// } /// } /// ``` +/// +/// This can also be used to implement `likely` and `unlikely` helpers to hint the condition rather +/// than the branch: +/// +/// ``` +/// #![feature(cold_path)] +/// use core::hint::cold_path; +/// +/// #[inline(always)] +/// pub const fn likely(b: bool) -> bool { +/// if !b { +/// cold_path(); +/// } +/// b +/// } +/// +/// #[inline(always)] +/// pub const fn unlikely(b: bool) -> bool { +/// if b { +/// cold_path(); +/// } +/// b +/// } +/// +/// fn foo(x: i32) { +/// if likely(x > 0) { +/// println!("this branch is likely to be taken"); +/// } else { +/// println!("this branch is unlikely to be taken"); +/// } +/// } +/// ``` #[unstable(feature = "cold_path", issue = "136873")] #[inline(always)] pub const fn cold_path() { diff --git a/src/tools/compiletest/src/directives/auxiliary.rs b/src/tools/compiletest/src/directives/auxiliary.rs index 1d5b7926a8e34..14cbab640eb6b 100644 --- a/src/tools/compiletest/src/directives/auxiliary.rs +++ b/src/tools/compiletest/src/directives/auxiliary.rs @@ -25,6 +25,13 @@ pub struct AuxCrate { pub path: String, } +/// The value of a `proc-macro` directive. +#[derive(Clone, Debug, Default)] +pub(crate) struct ProcMacro { + /// With `proc-macro: bar.rs` this will be `bar.rs`. + pub path: String, +} + /// Properties parsed from `aux-*` test directives. #[derive(Clone, Debug, Default)] pub(crate) struct AuxProps { @@ -37,7 +44,7 @@ pub(crate) struct AuxProps { /// to build and pass with the `--extern` flag. pub(crate) crates: Vec, /// Same as `builds`, but for proc-macros. - pub(crate) proc_macros: Vec, + pub(crate) proc_macros: Vec, /// Similar to `builds`, but also uses the resulting dylib as a /// `-Zcodegen-backend` when compiling the test file. pub(crate) codegen_backend: Option, @@ -53,7 +60,7 @@ impl AuxProps { .chain(builds.iter().map(String::as_str)) .chain(bins.iter().map(String::as_str)) .chain(crates.iter().map(|c| c.path.as_str())) - .chain(proc_macros.iter().map(String::as_str)) + .chain(proc_macros.iter().map(|p| p.path.as_str())) .chain(codegen_backend.iter().map(String::as_str)) } } @@ -74,8 +81,8 @@ pub(super) fn parse_and_update_aux( config.push_name_value_directive(ln, AUX_BUILD, &mut aux.builds, |r| r.trim().to_string()); config.push_name_value_directive(ln, AUX_BIN, &mut aux.bins, |r| r.trim().to_string()); config.push_name_value_directive(ln, AUX_CRATE, &mut aux.crates, parse_aux_crate); - config - .push_name_value_directive(ln, PROC_MACRO, &mut aux.proc_macros, |r| r.trim().to_string()); + config.push_name_value_directive(ln, PROC_MACRO, &mut aux.proc_macros, parse_proc_macro); + if let Some(r) = config.parse_name_value_directive(ln, AUX_CODEGEN_BACKEND) { aux.codegen_backend = Some(r.trim().to_owned()); } @@ -99,3 +106,7 @@ fn parse_aux_crate(r: String) -> AuxCrate { AuxCrate { extern_modifiers: modifiers, name, path } } + +fn parse_proc_macro(r: String) -> ProcMacro { + ProcMacro { path: r.trim().to_string() } +} diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index dfbe84d5da721..2bfb73f05d169 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -1298,13 +1298,13 @@ impl<'test> TestCx<'test> { } for proc_macro in &self.props.aux.proc_macros { - self.build_auxiliary(proc_macro, &aux_dir, Some(AuxType::ProcMacro)); - let crate_name = path_to_crate_name(proc_macro); + self.build_auxiliary(&proc_macro.path, &aux_dir, Some(AuxType::ProcMacro)); + let crate_name = path_to_crate_name(&proc_macro.path); add_extern( rustc, None, // `extern_modifiers` &crate_name, - proc_macro, + &proc_macro.path, AuxType::ProcMacro, ); } diff --git a/tests/ui/traits/next-solver/opaques/method_autoderef_constraints.rs b/tests/ui/traits/next-solver/opaques/method_autoderef_constraints.rs new file mode 100644 index 0000000000000..d8375a62bb376 --- /dev/null +++ b/tests/ui/traits/next-solver/opaques/method_autoderef_constraints.rs @@ -0,0 +1,38 @@ +//@ compile-flags: -Znext-solver + +// Regression test for trait-system-refactor-initiative/issues/263 +// Previously `method_auto_deref_steps` would also return opaque +// types which have already been defined in the parent context. +// +// We then handled these opaque types by emitting `AliasRelate` goals +// when instantiating its result, assuming that operation to be infallible. +// By returning opaque type constraints from the parent context and +// constraining the hidden type without reproving the item bounds of +// the opaque, this ended up causing ICE. + +use std::ops::Deref; +trait Trait {} +struct Inv(*mut T); +impl Trait for i32 {} +impl Deref for Inv { + type Target = u32; + fn deref(&self) -> &Self::Target { + todo!() + } +} + +fn mk() -> T { todo!() } +fn foo() -> Inv { + //~^ ERROR: the trait bound `u32: Trait` is not satisfied [E0277] + let mut x: Inv<_> = mk(); + if false { + return x; + //~^ ERROR: the trait bound `u32: Trait` is not satisfied [E0277] + } + + x.count_ones(); + x + //~^ ERROR: mismatched types [E0308] +} + +fn main() {} diff --git a/tests/ui/traits/next-solver/opaques/method_autoderef_constraints.stderr b/tests/ui/traits/next-solver/opaques/method_autoderef_constraints.stderr new file mode 100644 index 0000000000000..c421222309a03 --- /dev/null +++ b/tests/ui/traits/next-solver/opaques/method_autoderef_constraints.stderr @@ -0,0 +1,43 @@ +error[E0277]: the trait bound `u32: Trait` is not satisfied + --> $DIR/method_autoderef_constraints.rs:29:16 + | +LL | return x; + | ^ the trait `Trait` is not implemented for `u32` + | +help: the trait `Trait` is implemented for `i32` + --> $DIR/method_autoderef_constraints.rs:16:1 + | +LL | impl Trait for i32 {} + | ^^^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/method_autoderef_constraints.rs:34:5 + | +LL | fn foo() -> Inv { + | --------------- + | | | + | | the expected opaque type + | expected `Inv` because of return type +... +LL | x + | ^ types differ + | + = note: expected struct `Inv` + found struct `Inv` + +error[E0277]: the trait bound `u32: Trait` is not satisfied + --> $DIR/method_autoderef_constraints.rs:25:1 + | +LL | fn foo() -> Inv { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `u32` + | +help: the trait `Trait` is implemented for `i32` + --> $DIR/method_autoderef_constraints.rs:16:1 + | +LL | impl Trait for i32 {} + | ^^^^^^^^^^^^^^^^^^ + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0277, E0308. +For more information about an error, try `rustc --explain E0277`.