diff --git a/Cargo.lock b/Cargo.lock
index 300cc02330f97..4daf6f42b78e8 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -556,7 +556,7 @@ checksum = "2da6da31387c7e4ef160ffab6d5e7f00c42626fe39aea70a7b0f1773f7dd6c1b"
[[package]]
name = "clippy"
-version = "0.1.77"
+version = "0.1.78"
dependencies = [
"anstream",
"clippy_config",
@@ -584,7 +584,7 @@ dependencies = [
[[package]]
name = "clippy_config"
-version = "0.1.77"
+version = "0.1.78"
dependencies = [
"rustc-semver",
"serde",
@@ -607,7 +607,7 @@ dependencies = [
[[package]]
name = "clippy_lints"
-version = "0.1.77"
+version = "0.1.78"
dependencies = [
"arrayvec",
"cargo_metadata 0.18.0",
@@ -632,7 +632,7 @@ dependencies = [
[[package]]
name = "clippy_utils"
-version = "0.1.77"
+version = "0.1.78"
dependencies = [
"arrayvec",
"clippy_config",
@@ -1003,7 +1003,7 @@ checksum = "a0afaad2b26fa326569eb264b1363e8ae3357618c43982b3f285f0774ce76b69"
[[package]]
name = "declare_clippy_lint"
-version = "0.1.77"
+version = "0.1.78"
dependencies = [
"itertools",
"quote",
diff --git a/RELEASES.md b/RELEASES.md
index 3751b15b361b1..20e317a4d236a 100644
--- a/RELEASES.md
+++ b/RELEASES.md
@@ -7,7 +7,6 @@ Language
--------
- [Document Rust ABI compatibility between various types](https://github.com/rust-lang/rust/pull/115476/)
- [Also: guarantee that char and u32 are ABI-compatible](https://github.com/rust-lang/rust/pull/118032/)
-- [Warn against ambiguous wide pointer comparisons](https://github.com/rust-lang/rust/pull/117758/)
- [Add lint `ambiguous_wide_pointer_comparisons` that supersedes `clippy::vtable_address_comparisons`](https://github.com/rust-lang/rust/pull/117758)
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
index 76c9ac6614a30..f961cd2d00b06 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
@@ -461,6 +461,7 @@ pub fn type_di_node<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) -> &'ll D
}
ty::FnDef(..) | ty::FnPtr(_) => build_subroutine_type_di_node(cx, unique_type_id),
ty::Closure(..) => build_closure_env_di_node(cx, unique_type_id),
+ ty::CoroutineClosure(..) => build_closure_env_di_node(cx, unique_type_id),
ty::Coroutine(..) => enums::build_coroutine_di_node(cx, unique_type_id),
ty::Adt(def, ..) => match def.adt_kind() {
AdtKind::Struct => build_struct_type_di_node(cx, unique_type_id),
@@ -1068,6 +1069,7 @@ fn build_upvar_field_di_nodes<'ll, 'tcx>(
let (&def_id, up_var_tys) = match closure_or_coroutine_ty.kind() {
ty::Coroutine(def_id, args) => (def_id, args.as_coroutine().prefix_tys()),
ty::Closure(def_id, args) => (def_id, args.as_closure().upvar_tys()),
+ ty::CoroutineClosure(def_id, args) => (def_id, args.as_coroutine_closure().upvar_tys()),
_ => {
bug!(
"build_upvar_field_di_nodes() called with non-closure-or-coroutine-type: {:?}",
@@ -1153,7 +1155,8 @@ fn build_closure_env_di_node<'ll, 'tcx>(
unique_type_id: UniqueTypeId<'tcx>,
) -> DINodeCreationResult<'ll> {
let closure_env_type = unique_type_id.expect_ty();
- let &ty::Closure(def_id, _args) = closure_env_type.kind() else {
+ let &(ty::Closure(def_id, _) | ty::CoroutineClosure(def_id, _)) = closure_env_type.kind()
+ else {
bug!("build_closure_env_di_node() called with non-closure-type: {:?}", closure_env_type)
};
let containing_scope = get_namespace_for_item(cx, def_id);
diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs
index b4512af38e37b..e3e48ecb3aa5f 100644
--- a/compiler/rustc_codegen_llvm/src/intrinsic.rs
+++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs
@@ -1985,10 +1985,9 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
match in_elem.kind() {
ty::RawPtr(p) => {
- let (metadata, check_sized) = p.ty.ptr_metadata_ty(bx.tcx, |ty| {
+ let metadata = p.ty.ptr_metadata_ty(bx.tcx, |ty| {
bx.tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), ty)
});
- assert!(!check_sized); // we are in codegen, so we shouldn't see these types
require!(
metadata.is_unit(),
InvalidMonomorphization::CastFatPointer { span, name, ty: in_elem }
@@ -2000,10 +1999,9 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
}
match out_elem.kind() {
ty::RawPtr(p) => {
- let (metadata, check_sized) = p.ty.ptr_metadata_ty(bx.tcx, |ty| {
+ let metadata = p.ty.ptr_metadata_ty(bx.tcx, |ty| {
bx.tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), ty)
});
- assert!(!check_sized); // we are in codegen, so we shouldn't see these types
require!(
metadata.is_unit(),
InvalidMonomorphization::CastFatPointer { span, name, ty: out_elem }
diff --git a/compiler/rustc_const_eval/src/interpret/terminator.rs b/compiler/rustc_const_eval/src/interpret/terminator.rs
index 85a2e4778d252..ff20fc5092c60 100644
--- a/compiler/rustc_const_eval/src/interpret/terminator.rs
+++ b/compiler/rustc_const_eval/src/interpret/terminator.rs
@@ -377,12 +377,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
// to fields, which can yield non-normalized types. So we need to provide a
// normalization function.
let normalize = |ty| self.tcx.normalize_erasing_regions(self.param_env, ty);
- let (meta, only_if_sized) = ty.ptr_metadata_ty(*self.tcx, normalize);
- assert!(
- !only_if_sized,
- "there should be no more 'maybe has that metadata' types during interpretation"
- );
- meta
+ ty.ptr_metadata_ty(*self.tcx, normalize)
};
return Ok(meta_ty(caller) == meta_ty(callee));
}
diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs
index 58823ea30ce57..f21de1609cb7f 100644
--- a/compiler/rustc_hir_typeck/src/cast.rs
+++ b/compiler/rustc_hir_typeck/src/cast.rs
@@ -448,13 +448,35 @@ impl<'a, 'tcx> CastCheck<'tcx> {
);
}
}
- let msg = "an `as` expression can only be used to convert between primitive \
- types or to coerce to a specific trait object";
+
+ let (msg, note) = if let ty::Adt(adt, _) = self.expr_ty.kind()
+ && adt.is_enum()
+ && self.cast_ty.is_numeric()
+ {
+ (
+ "an `as` expression can be used to convert enum types to numeric \
+ types only if the enum type is unit-only or field-less",
+ Some(
+ "see https://doc.rust-lang.org/reference/items/enumerations.html#casting for more information",
+ ),
+ )
+ } else {
+ (
+ "an `as` expression can only be used to convert between primitive \
+ types or to coerce to a specific trait object",
+ None,
+ )
+ };
+
if label {
err.span_label(self.span, msg);
} else {
err.note(msg);
}
+
+ if let Some(note) = note {
+ err.note(note);
+ }
} else {
err.span_label(self.span, "invalid cast");
}
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index d6e3385c6008e..f592acd4b6ff5 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -2279,12 +2279,12 @@ impl<'tcx> Ty<'tcx> {
}
/// Returns the type of metadata for (potentially fat) pointers to this type,
- /// and a boolean signifying if this is conditional on this type being `Sized`.
- pub fn ptr_metadata_ty(
+ /// or the struct tail if the metadata type cannot be determined.
+ pub fn ptr_metadata_ty_or_tail(
self,
tcx: TyCtxt<'tcx>,
normalize: impl FnMut(Ty<'tcx>) -> Ty<'tcx>,
- ) -> (Ty<'tcx>, bool) {
+ ) -> Result, Ty<'tcx>> {
let tail = tcx.struct_tail_with_normalize(self, normalize, || {});
match tail.kind() {
// Sized types
@@ -2307,31 +2307,47 @@ impl<'tcx> Ty<'tcx> {
| ty::Error(_)
// Extern types have metadata = ().
| ty::Foreign(..)
- // `dyn*` has no metadata
+ // `dyn*` has metadata = ().
| ty::Dynamic(_, _, ty::DynStar)
- // If returned by `struct_tail_without_normalization` this is a unit struct
+ // If returned by `struct_tail_with_normalize` this is a unit struct
// without any fields, or not a struct, and therefore is Sized.
| ty::Adt(..)
- // If returned by `struct_tail_without_normalization` this is the empty tuple,
+ // If returned by `struct_tail_with_normalize` this is the empty tuple,
// a.k.a. unit type, which is Sized
- | ty::Tuple(..) => (tcx.types.unit, false),
+ | ty::Tuple(..) => Ok(tcx.types.unit),
+
+ ty::Str | ty::Slice(_) => Ok(tcx.types.usize),
- ty::Str | ty::Slice(_) => (tcx.types.usize, false),
ty::Dynamic(_, _, ty::Dyn) => {
let dyn_metadata = tcx.require_lang_item(LangItem::DynMetadata, None);
- (tcx.type_of(dyn_metadata).instantiate(tcx, &[tail.into()]), false)
- },
+ Ok(tcx.type_of(dyn_metadata).instantiate(tcx, &[tail.into()]))
+ }
- // type parameters only have unit metadata if they're sized, so return true
- // to make sure we double check this during confirmation
- ty::Param(_) | ty::Alias(..) => (tcx.types.unit, true),
+ // We don't know the metadata of `self`, but it must be equal to the
+ // metadata of `tail`.
+ ty::Param(_) | ty::Alias(..) => Err(tail),
ty::Infer(ty::TyVar(_))
| ty::Bound(..)
| ty::Placeholder(..)
- | ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
- bug!("`ptr_metadata_ty` applied to unexpected type: {:?} (tail = {:?})", self, tail)
- }
+ | ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => bug!(
+ "`ptr_metadata_ty_or_tail` applied to unexpected type: {self:?} (tail = {tail:?})"
+ ),
+ }
+ }
+
+ /// Returns the type of metadata for (potentially fat) pointers to this type.
+ /// Causes an ICE if the metadata type cannot be determined.
+ pub fn ptr_metadata_ty(
+ self,
+ tcx: TyCtxt<'tcx>,
+ normalize: impl FnMut(Ty<'tcx>) -> Ty<'tcx>,
+ ) -> Ty<'tcx> {
+ match self.ptr_metadata_ty_or_tail(tcx, normalize) {
+ Ok(metadata) => metadata,
+ Err(tail) => bug!(
+ "`ptr_metadata_ty` failed to get metadata for type: {self:?} (tail = {tail:?})"
+ ),
}
}
diff --git a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs
index 239072dfc8e0e..3b9515e16701a 100644
--- a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs
@@ -8,7 +8,7 @@ use rustc_infer::traits::query::NoSolution;
use rustc_infer::traits::Reveal;
use rustc_middle::traits::solve::inspect::ProbeKind;
use rustc_middle::traits::solve::{
- CandidateSource, CanonicalResponse, Certainty, Goal, QueryResult,
+ CandidateSource, CanonicalResponse, Certainty, Goal, MaybeCause, QueryResult,
};
use rustc_middle::traits::BuiltinImplSource;
use rustc_middle::ty::fast_reject::{SimplifiedType, TreatParams};
@@ -276,25 +276,16 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
&mut self,
goal: Goal<'tcx, G>,
) -> Vec> {
- let dummy_candidate = |this: &mut EvalCtxt<'_, 'tcx>, certainty| {
- let source = CandidateSource::BuiltinImpl(BuiltinImplSource::Misc);
- let result = this.evaluate_added_goals_and_make_canonical_response(certainty).unwrap();
- let mut dummy_probe = this.inspect.new_probe();
- dummy_probe.probe_kind(ProbeKind::TraitCandidate { source, result: Ok(result) });
- this.inspect.finish_probe(dummy_probe);
- vec![Candidate { source, result }]
- };
-
let Some(normalized_self_ty) =
self.try_normalize_ty(goal.param_env, goal.predicate.self_ty())
else {
debug!("overflow while evaluating self type");
- return dummy_candidate(self, Certainty::OVERFLOW);
+ return self.forced_ambiguity(MaybeCause::Overflow);
};
if normalized_self_ty.is_ty_var() {
debug!("self type has been normalized to infer");
- return dummy_candidate(self, Certainty::AMBIGUOUS);
+ return self.forced_ambiguity(MaybeCause::Ambiguity);
}
let goal =
@@ -315,11 +306,26 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
self.assemble_param_env_candidates(goal, &mut candidates);
- self.assemble_coherence_unknowable_candidates(goal, &mut candidates);
+ match self.solver_mode() {
+ SolverMode::Normal => self.discard_impls_shadowed_by_env(goal, &mut candidates),
+ SolverMode::Coherence => {
+ self.assemble_coherence_unknowable_candidates(goal, &mut candidates)
+ }
+ }
candidates
}
+ fn forced_ambiguity(&mut self, cause: MaybeCause) -> Vec> {
+ let source = CandidateSource::BuiltinImpl(BuiltinImplSource::Misc);
+ let certainty = Certainty::Maybe(cause);
+ let result = self.evaluate_added_goals_and_make_canonical_response(certainty).unwrap();
+ let mut dummy_probe = self.inspect.new_probe();
+ dummy_probe.probe_kind(ProbeKind::TraitCandidate { source, result: Ok(result) });
+ self.inspect.finish_probe(dummy_probe);
+ vec![Candidate { source, result }]
+ }
+
#[instrument(level = "debug", skip_all)]
fn assemble_non_blanket_impl_candidates>(
&mut self,
@@ -779,6 +785,12 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
}
}
+ /// In coherence we have to not only care about all impls we know about, but
+ /// also consider impls which may get added in a downstream or sibling crate
+ /// or which an upstream impl may add in a minor release.
+ ///
+ /// To do so we add an ambiguous candidate in case such an unknown impl could
+ /// apply to the current goal.
#[instrument(level = "debug", skip_all)]
fn assemble_coherence_unknowable_candidates>(
&mut self,
@@ -786,11 +798,6 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
candidates: &mut Vec>,
) {
let tcx = self.tcx();
- match self.solver_mode() {
- SolverMode::Normal => return,
- SolverMode::Coherence => {}
- };
-
let result = self.probe_misc_candidate("coherence unknowable").enter(|ecx| {
let trait_ref = goal.predicate.trait_ref(tcx);
#[derive(Debug)]
@@ -820,6 +827,51 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
}
}
+ /// If there's a where-bound for the current goal, do not use any impl candidates
+ /// to prove the current goal. Most importantly, if there is a where-bound which does
+ /// not specify any associated types, we do not allow normalizing the associated type
+ /// by using an impl, even if it would apply.
+ ///
+ ///
+ // FIXME(@lcnr): The current structure here makes me unhappy and feels ugly. idk how
+ // to improve this however. However, this should make it fairly straightforward to refine
+ // the filtering going forward, so it seems alright-ish for now.
+ fn discard_impls_shadowed_by_env>(
+ &mut self,
+ goal: Goal<'tcx, G>,
+ candidates: &mut Vec>,
+ ) {
+ let tcx = self.tcx();
+ let trait_goal: Goal<'tcx, ty::TraitPredicate<'tcx>> =
+ goal.with(tcx, goal.predicate.trait_ref(tcx));
+ let mut trait_candidates_from_env = Vec::new();
+ self.assemble_param_env_candidates(trait_goal, &mut trait_candidates_from_env);
+ self.assemble_alias_bound_candidates(trait_goal, &mut trait_candidates_from_env);
+ if !trait_candidates_from_env.is_empty() {
+ let trait_env_result = self.merge_candidates(trait_candidates_from_env);
+ match trait_env_result.unwrap().value.certainty {
+ // If proving the trait goal succeeds by using the env,
+ // we freely drop all impl candidates.
+ //
+ // FIXME(@lcnr): It feels like this could easily hide
+ // a forced ambiguity candidate added earlier.
+ // This feels dangerous.
+ Certainty::Yes => {
+ candidates.retain(|c| match c.source {
+ CandidateSource::Impl(_) | CandidateSource::BuiltinImpl(_) => false,
+ CandidateSource::ParamEnv(_) | CandidateSource::AliasBound => true,
+ });
+ }
+ // If it is still ambiguous we instead just force the whole goal
+ // to be ambig and wait for inference constraints. See
+ // tests/ui/traits/next-solver/env-shadows-impls/ambig-env-no-shadow.rs
+ Certainty::Maybe(cause) => {
+ *candidates = self.forced_ambiguity(cause);
+ }
+ }
+ }
+ }
+
/// If there are multiple ways to prove a trait or projection goal, we have
/// to somehow try to merge the candidates into one. If that fails, we return
/// ambiguity.
@@ -832,34 +884,8 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
let responses = candidates.iter().map(|c| c.result).collect::>();
if let Some(result) = self.try_merge_responses(&responses) {
return Ok(result);
+ } else {
+ self.flounder(&responses)
}
-
- // We then check whether we should prioritize `ParamEnv` candidates.
- //
- // Doing so is incomplete and would therefore be unsound during coherence.
- match self.solver_mode() {
- SolverMode::Coherence => (),
- // Prioritize `ParamEnv` candidates only if they do not guide inference.
- //
- // This is still incomplete as we may add incorrect region bounds.
- SolverMode::Normal => {
- let param_env_responses = candidates
- .iter()
- .filter(|c| {
- matches!(
- c.source,
- CandidateSource::ParamEnv(_) | CandidateSource::AliasBound
- )
- })
- .map(|c| c.result)
- .collect::>();
- if let Some(result) = self.try_merge_responses(¶m_env_responses) {
- // We strongly prefer alias and param-env bounds here, even if they affect inference.
- // See https://github.com/rust-lang/trait-system-refactor-initiative/issues/11.
- return Ok(result);
- }
- }
- }
- self.flounder(&responses)
}
}
diff --git a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs b/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs
index 47ba549022d9b..d177109c42046 100644
--- a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs
@@ -491,6 +491,8 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
goal: Goal<'tcx, Self>,
) -> QueryResult<'tcx> {
let tcx = ecx.tcx();
+ let metadata_def_id = tcx.require_lang_item(LangItem::Metadata, None);
+ assert_eq!(metadata_def_id, goal.predicate.def_id());
ecx.probe_misc_candidate("builtin pointee").enter(|ecx| {
let metadata_ty = match goal.predicate.self_ty().kind() {
ty::Bool
@@ -522,7 +524,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
}
ty::Alias(_, _) | ty::Param(_) | ty::Placeholder(..) => {
- // FIXME(ptr_metadata): It would also be possible to return a `Ok(Ambig)` with no constraints.
+ // This is the "fallback impl" for type parameters, unnormalizable projections
+ // and opaque types: If the `self_ty` is `Sized`, then the metadata is `()`.
+ // FIXME(ptr_metadata): This impl overlaps with the other impls and shouldn't
+ // exist. Instead, `Pointee` should be a supertrait of `Sized`.
let sized_predicate = ty::TraitRef::from_lang_item(
tcx,
LangItem::Sized,
@@ -536,30 +541,16 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
ty::Adt(def, args) if def.is_struct() => match def.non_enum_variant().tail_opt() {
None => tcx.types.unit,
- Some(field_def) => {
- let self_ty = field_def.ty(tcx, args);
- // FIXME(-Znext-solver=coinductive): Should this be `GoalSource::ImplWhereBound`?
- ecx.add_goal(
- GoalSource::Misc,
- goal.with(tcx, goal.predicate.with_self_ty(tcx, self_ty)),
- );
- return ecx
- .evaluate_added_goals_and_make_canonical_response(Certainty::Yes);
+ Some(tail_def) => {
+ let tail_ty = tail_def.ty(tcx, args);
+ Ty::new_projection(tcx, metadata_def_id, [tail_ty])
}
},
ty::Adt(_, _) => tcx.types.unit,
ty::Tuple(elements) => match elements.last() {
None => tcx.types.unit,
- Some(&self_ty) => {
- // FIXME(-Znext-solver=coinductive): Should this be `GoalSource::ImplWhereBound`?
- ecx.add_goal(
- GoalSource::Misc,
- goal.with(tcx, goal.predicate.with_self_ty(tcx, self_ty)),
- );
- return ecx
- .evaluate_added_goals_and_make_canonical_response(Certainty::Yes);
- }
+ Some(&tail_ty) => Ty::new_projection(tcx, metadata_def_id, [tail_ty]),
},
ty::Infer(
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index fd8306bbc0b69..d271a0ea33be8 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -1935,10 +1935,11 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
// Integers and floats are always Sized, and so have unit type metadata.
| ty::Infer(ty::InferTy::IntVar(_) | ty::InferTy::FloatVar(..)) => true,
- // type parameters, opaques, and unnormalized projections have pointer
- // metadata if they're known (e.g. by the param_env) to be sized
+ // We normalize from `Wrapper::Metadata` to `Tail::Metadata` if able.
+ // Otherwise, type parameters, opaques, and unnormalized projections have
+ // unit metadata if they're known (e.g. by the param_env) to be sized.
ty::Param(_) | ty::Alias(..)
- if selcx.infcx.predicate_must_hold_modulo_regions(
+ if self_ty != tail || selcx.infcx.predicate_must_hold_modulo_regions(
&obligation.with(
selcx.tcx(),
ty::TraitRef::from_lang_item(selcx.tcx(), LangItem::Sized, obligation.cause.span(),[self_ty]),
@@ -2312,7 +2313,7 @@ fn confirm_builtin_candidate<'cx, 'tcx>(
assert_eq!(metadata_def_id, item_def_id);
let mut obligations = Vec::new();
- let (metadata_ty, check_is_sized) = self_ty.ptr_metadata_ty(tcx, |ty| {
+ let normalize = |ty| {
normalize_with_depth_to(
selcx,
obligation.param_env,
@@ -2321,16 +2322,27 @@ fn confirm_builtin_candidate<'cx, 'tcx>(
ty,
&mut obligations,
)
+ };
+ let metadata_ty = self_ty.ptr_metadata_ty_or_tail(tcx, normalize).unwrap_or_else(|tail| {
+ if tail == self_ty {
+ // This is the "fallback impl" for type parameters, unnormalizable projections
+ // and opaque types: If the `self_ty` is `Sized`, then the metadata is `()`.
+ // FIXME(ptr_metadata): This impl overlaps with the other impls and shouldn't
+ // exist. Instead, `Pointee` should be a supertrait of `Sized`.
+ let sized_predicate = ty::TraitRef::from_lang_item(
+ tcx,
+ LangItem::Sized,
+ obligation.cause.span(),
+ [self_ty],
+ );
+ obligations.push(obligation.with(tcx, sized_predicate));
+ tcx.types.unit
+ } else {
+ // We know that `self_ty` has the same metadata as `tail`. This allows us
+ // to prove predicates like `Wrapper::Metadata == Tail::Metadata`.
+ Ty::new_projection(tcx, metadata_def_id, [tail])
+ }
});
- if check_is_sized {
- let sized_predicate = ty::TraitRef::from_lang_item(
- tcx,
- LangItem::Sized,
- obligation.cause.span(),
- [self_ty],
- );
- obligations.push(obligation.with(tcx, sized_predicate));
- }
(metadata_ty.into(), obligations)
} else {
bug!("unexpected builtin trait with associated type: {:?}", obligation.predicate);
diff --git a/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs b/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs
index 4c0c57377e02a..a050b30317a05 100644
--- a/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs
@@ -41,7 +41,28 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
/// not entirely accurate if inference variables are involved.
///
/// This version may conservatively fail when outlives obligations
- /// are required.
+ /// are required. Therefore, this version should only be used for
+ /// optimizations or diagnostics and be treated as if it can always
+ /// return `false`.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// # #![allow(dead_code)]
+ /// trait Trait {}
+ ///
+ /// fn check() {}
+ ///
+ /// fn foo()
+ /// where
+ /// &'static T: Trait,
+ /// {
+ /// // Evaluating `&'?0 T: Trait` adds a `'?0: 'static` outlives obligation,
+ /// // which means that `predicate_must_hold_considering_regions` will return
+ /// // `false`.
+ /// check::<&'_ T>();
+ /// }
+ /// ```
fn predicate_must_hold_considering_regions(
&self,
obligation: &PredicateObligation<'tcx>,
diff --git a/library/core/src/option.rs b/library/core/src/option.rs
index 901fb962a7899..d4c40c49934ed 100644
--- a/library/core/src/option.rs
+++ b/library/core/src/option.rs
@@ -1073,18 +1073,23 @@ impl Option {
}
}
- /// Calls the provided closure with a reference to the contained value (if [`Some`]).
+ /// Calls a function with a reference to the contained value if [`Some`].
+ ///
+ /// Returns the original option.
///
/// # Examples
///
/// ```
- /// let v = vec![1, 2, 3, 4, 5];
+ /// let list = vec![1, 2, 3];
///
- /// // prints "got: 4"
- /// let x: Option<&usize> = v.get(3).inspect(|x| println!("got: {x}"));
+ /// // prints "got: 2"
+ /// let x = list
+ /// .get(1)
+ /// .inspect(|x| println!("got: {x}"))
+ /// .expect("list should be long enough");
///
/// // prints nothing
- /// let x: Option<&usize> = v.get(5).inspect(|x| println!("got: {x}"));
+ /// list.get(5).inspect(|x| println!("got: {x}"));
/// ```
#[inline]
#[stable(feature = "result_option_inspect", since = "1.76.0")]
diff --git a/library/core/src/result.rs b/library/core/src/result.rs
index 1f448984e531c..80f7fe75e8230 100644
--- a/library/core/src/result.rs
+++ b/library/core/src/result.rs
@@ -830,7 +830,9 @@ impl Result {
}
}
- /// Calls the provided closure with a reference to the contained value (if [`Ok`]).
+ /// Calls a function with a reference to the contained value if [`Ok`].
+ ///
+ /// Returns the original result.
///
/// # Examples
///
@@ -851,7 +853,9 @@ impl Result {
self
}
- /// Calls the provided closure with a reference to the contained error (if [`Err`]).
+ /// Calls a function with a reference to the contained value if [`Err`].
+ ///
+ /// Returns the original result.
///
/// # Examples
///
diff --git a/library/std/src/sys/mod.rs b/library/std/src/sys/mod.rs
index e03e98b18d29f..fae21636897b8 100644
--- a/library/std/src/sys/mod.rs
+++ b/library/std/src/sys/mod.rs
@@ -7,6 +7,7 @@ mod personality;
pub mod cmath;
pub mod os_str;
+pub mod path;
// FIXME(117276): remove this, move feature implementations into individual
// submodules.
diff --git a/library/std/src/sys/pal/hermit/mod.rs b/library/std/src/sys/pal/hermit/mod.rs
index 3c83afa280be5..57cc656e266a1 100644
--- a/library/std/src/sys/pal/hermit/mod.rs
+++ b/library/std/src/sys/pal/hermit/mod.rs
@@ -28,8 +28,6 @@ pub mod io;
pub mod memchr;
pub mod net;
pub mod os;
-#[path = "../unix/path.rs"]
-pub mod path;
#[path = "../unsupported/pipe.rs"]
pub mod pipe;
#[path = "../unsupported/process.rs"]
diff --git a/library/std/src/sys/pal/sgx/mod.rs b/library/std/src/sys/pal/sgx/mod.rs
index a769fc1ef5932..46f3e5b401da5 100644
--- a/library/std/src/sys/pal/sgx/mod.rs
+++ b/library/std/src/sys/pal/sgx/mod.rs
@@ -22,7 +22,6 @@ pub mod io;
pub mod memchr;
pub mod net;
pub mod os;
-pub mod path;
#[path = "../unsupported/pipe.rs"]
pub mod pipe;
#[path = "../unsupported/process.rs"]
diff --git a/library/std/src/sys/pal/solid/mod.rs b/library/std/src/sys/pal/solid/mod.rs
index 46699e64169f5..be8e00339021f 100644
--- a/library/std/src/sys/pal/solid/mod.rs
+++ b/library/std/src/sys/pal/solid/mod.rs
@@ -29,7 +29,6 @@ pub mod fs;
pub mod io;
pub mod net;
pub mod os;
-pub mod path;
#[path = "../unsupported/pipe.rs"]
pub mod pipe;
#[path = "../unsupported/process.rs"]
diff --git a/library/std/src/sys/pal/teeos/mod.rs b/library/std/src/sys/pal/teeos/mod.rs
index 95a5b97ea4237..7953104486c56 100644
--- a/library/std/src/sys/pal/teeos/mod.rs
+++ b/library/std/src/sys/pal/teeos/mod.rs
@@ -25,8 +25,6 @@ pub mod net;
#[path = "../unsupported/once.rs"]
pub mod once;
pub mod os;
-#[path = "../unix/path.rs"]
-pub mod path;
#[path = "../unsupported/pipe.rs"]
pub mod pipe;
#[path = "../unsupported/process.rs"]
diff --git a/library/std/src/sys/pal/uefi/helpers.rs b/library/std/src/sys/pal/uefi/helpers.rs
index 9837cc89f2d39..ba53ed88f3765 100644
--- a/library/std/src/sys/pal/uefi/helpers.rs
+++ b/library/std/src/sys/pal/uefi/helpers.rs
@@ -146,3 +146,11 @@ pub(crate) fn image_handle_protocol(protocol_guid: Guid) -> Option
let system_handle = uefi::env::try_image_handle()?;
open_protocol(system_handle, protocol_guid).ok()
}
+
+/// Get RuntimeServices
+pub(crate) fn runtime_services() -> Option> {
+ let system_table: NonNull =
+ crate::os::uefi::env::try_system_table()?.cast();
+ let runtime_services = unsafe { (*system_table.as_ptr()).runtime_services };
+ NonNull::new(runtime_services)
+}
diff --git a/library/std/src/sys/pal/uefi/mod.rs b/library/std/src/sys/pal/uefi/mod.rs
index 9ee753aa1a0c1..efa4ed67c50ca 100644
--- a/library/std/src/sys/pal/uefi/mod.rs
+++ b/library/std/src/sys/pal/uefi/mod.rs
@@ -26,7 +26,6 @@ pub mod net;
#[path = "../unsupported/once.rs"]
pub mod once;
pub mod os;
-pub mod path;
#[path = "../unsupported/pipe.rs"]
pub mod pipe;
#[path = "../unsupported/process.rs"]
@@ -38,7 +37,6 @@ pub mod thread;
pub mod thread_local_key;
#[path = "../unsupported/thread_parking.rs"]
pub mod thread_parking;
-#[path = "../unsupported/time.rs"]
pub mod time;
mod helpers;
diff --git a/library/std/src/sys/pal/uefi/path.rs b/library/std/src/sys/pal/uefi/path.rs
deleted file mode 100644
index 106682eee56b6..0000000000000
--- a/library/std/src/sys/pal/uefi/path.rs
+++ /dev/null
@@ -1,25 +0,0 @@
-use super::unsupported;
-use crate::ffi::OsStr;
-use crate::io;
-use crate::path::{Path, PathBuf, Prefix};
-
-pub const MAIN_SEP_STR: &str = "\\";
-pub const MAIN_SEP: char = '\\';
-
-#[inline]
-pub fn is_sep_byte(b: u8) -> bool {
- b == b'\\'
-}
-
-#[inline]
-pub fn is_verbatim_sep(b: u8) -> bool {
- b == b'\\'
-}
-
-pub fn parse_prefix(_p: &OsStr) -> Option> {
- None
-}
-
-pub(crate) fn absolute(_path: &Path) -> io::Result {
- unsupported()
-}
diff --git a/library/std/src/sys/pal/uefi/tests.rs b/library/std/src/sys/pal/uefi/tests.rs
index 8806eda3ac0a6..5eb36da922b54 100644
--- a/library/std/src/sys/pal/uefi/tests.rs
+++ b/library/std/src/sys/pal/uefi/tests.rs
@@ -1,4 +1,6 @@
use super::alloc::*;
+use super::time::*;
+use crate::time::Duration;
#[test]
fn align() {
@@ -19,3 +21,21 @@ fn align() {
}
}
}
+
+#[test]
+fn epoch() {
+ let t = r_efi::system::Time {
+ year: 1970,
+ month: 1,
+ day: 1,
+ hour: 0,
+ minute: 0,
+ second: 0,
+ nanosecond: 0,
+ timezone: r_efi::efi::UNSPECIFIED_TIMEZONE,
+ daylight: 0,
+ pad1: 0,
+ pad2: 0,
+ };
+ assert_eq!(system_time_internal::uefi_time_to_duration(t), Duration::new(0, 0));
+}
diff --git a/library/std/src/sys/pal/uefi/time.rs b/library/std/src/sys/pal/uefi/time.rs
new file mode 100644
index 0000000000000..68f428c38fbb3
--- /dev/null
+++ b/library/std/src/sys/pal/uefi/time.rs
@@ -0,0 +1,105 @@
+use crate::time::Duration;
+
+const SECS_IN_MINUTE: u64 = 60;
+const SECS_IN_HOUR: u64 = SECS_IN_MINUTE * 60;
+const SECS_IN_DAY: u64 = SECS_IN_HOUR * 24;
+
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
+pub struct Instant(Duration);
+
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
+pub struct SystemTime(Duration);
+
+pub const UNIX_EPOCH: SystemTime = SystemTime(Duration::from_secs(0));
+
+impl Instant {
+ pub fn now() -> Instant {
+ panic!("time not implemented on this platform")
+ }
+
+ pub fn checked_sub_instant(&self, other: &Instant) -> Option {
+ self.0.checked_sub(other.0)
+ }
+
+ pub fn checked_add_duration(&self, other: &Duration) -> Option {
+ Some(Instant(self.0.checked_add(*other)?))
+ }
+
+ pub fn checked_sub_duration(&self, other: &Duration) -> Option {
+ Some(Instant(self.0.checked_sub(*other)?))
+ }
+}
+
+impl SystemTime {
+ pub fn now() -> SystemTime {
+ system_time_internal::now()
+ .unwrap_or_else(|| panic!("time not implemented on this platform"))
+ }
+
+ pub fn sub_time(&self, other: &SystemTime) -> Result {
+ self.0.checked_sub(other.0).ok_or_else(|| other.0 - self.0)
+ }
+
+ pub fn checked_add_duration(&self, other: &Duration) -> Option {
+ Some(SystemTime(self.0.checked_add(*other)?))
+ }
+
+ pub fn checked_sub_duration(&self, other: &Duration) -> Option {
+ Some(SystemTime(self.0.checked_sub(*other)?))
+ }
+}
+
+pub(crate) mod system_time_internal {
+ use super::super::helpers;
+ use super::*;
+ use crate::mem::MaybeUninit;
+ use crate::ptr::NonNull;
+ use r_efi::efi::{RuntimeServices, Time};
+
+ pub fn now() -> Option {
+ let runtime_services: NonNull = helpers::runtime_services()?;
+ let mut t: MaybeUninit