Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
cc87a4e
fallible type ops
nia-e Jun 15, 2026
2a3042b
move trait
nia-e Jun 15, 2026
bde0cb3
Fix: removed Move from being printed at all
zannabianca1997 Aug 5, 2026
f5a5e65
Fix: assume Move when the `move_trait` feature is not added
zannabianca1997 Aug 16, 2026
acbf9e8
Fix: preferred printing of `?Move` instead of `Move`
zannabianca1997 Aug 21, 2026
f028f7b
Feat: removed Move from mangled symbols
zannabianca1997 Aug 22, 2026
d319d8e
Feat: mangling of `?Move` bounds
zannabianca1997 Aug 23, 2026
ab882e1
Fix: legacy mangler (Fn printer)
zannabianca1997 Aug 23, 2026
b2cb667
Fix: normalized test
zannabianca1997 Aug 23, 2026
e5b038d
Fix: correctly refusing trait objects that have only Move as a bound
zannabianca1997 Aug 23, 2026
ed155b9
Fix: line number drift
zannabianca1997 Aug 23, 2026
b22746a
Fix: missing Move pattern
zannabianca1997 Aug 23, 2026
eda1c34
Fix: removed the move clause from explicit clauses when the feature is
zannabianca1997 Aug 24, 2026
6d17593
Cleanup
zannabianca1997 Aug 28, 2026
dc150f7
Fix: expanded boolean into a more comprehensible enum
zannabianca1997 Aug 28, 2026
b1dec32
aligned to boolean values
zannabianca1997 Aug 28, 2026
6bcca4c
Fix: helper to avoid repeating printing pattern
zannabianca1997 Aug 29, 2026
b70a71b
Fix: missing prints
zannabianca1997 Aug 29, 2026
830a27b
reborrow! yay.
zannabianca1997 Aug 29, 2026
5e5cb73
Fix: documented error in feature gate test
zannabianca1997 Aug 30, 2026
19397e8
Fix: documented test being fixed under the next solver
zannabianca1997 Aug 30, 2026
309e68d
Chore: new test use the debug too
zannabianca1997 Aug 30, 2026
c51c5c0
Giving up for now on aligning winnowing of Move to Sized
zannabianca1997 Sep 2, 2026
2df83aa
Revert "Fix: removed the move clause from explicit clauses when the f…
zannabianca1997 Sep 2, 2026
c372a25
Fix: addressed fixme
zannabianca1997 Sep 2, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion compiler/rustc_ast_lowering/src/item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -501,13 +501,21 @@ impl<'hir> LoweringContext<'_, 'hir> {
let constness = self.lower_constness(attrs, *constness);
let impl_restriction = self.lower_impl_restriction(impl_restriction, hir_id);
let ident = self.lower_ident(*ident);
// FIXME(move_trait): We likely want to not add an implicit `Move` super trait
// at which point we shouldn't allow relaxed bounds here. Even if we do, we should
// make sure to only allow `?Move`.
let policy = if self.tcx.features().move_trait() {
RelaxedBoundPolicy::Allowed(&mut Default::default())
} else {
RelaxedBoundPolicy::Forbidden(RelaxedBoundForbiddenReason::SuperTrait)
};
let (generics, (safety, items, bounds)) = self.lower_generics(
generics,
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|this| {
let bounds = this.lower_param_bounds(
bounds,
RelaxedBoundPolicy::Forbidden(RelaxedBoundForbiddenReason::SuperTrait),
policy,
ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
);
let items = this.arena.alloc_from_iter(
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_attr_ir/src/lang_items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,8 @@ language_item_table! {
Unpin, sym::unpin, unpin_trait, Target::Trait, GenericRequirement::None;
Pin, kw::Pin, pin_type, Target::Struct, GenericRequirement::None;

Move, sym::move_trait, move_trait, Target::Trait, GenericRequirement::None;

OrderingEnum, sym::Ordering, ordering_enum, Target::Enum, GenericRequirement::Exact(0);
PartialEq, sym::eq, eq_trait, Target::Trait, GenericRequirement::Exact(1);
PartialOrd, sym::partial_ord, partial_ord_trait, Target::Trait, GenericRequirement::Exact(1);
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_borrowck/src/diagnostics/region_errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ impl<'tcx> ConstraintDescription for ConstraintCategory<'tcx> {
ConstraintCategory::TypeAnnotation(AnnotationSource::GenericArg) => "generic argument ",
ConstraintCategory::TypeAnnotation(_) => "type annotation ",
ConstraintCategory::SizedBound => "proving this value is `Sized` ",
ConstraintCategory::MoveBound => "proving this value is `Move` ",
ConstraintCategory::CopyBound => "copying this value ",
ConstraintCategory::OpaqueType => "opaque type ",
ConstraintCategory::ClosureUpvar(_) => "closure capture ",
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_borrowck/src/region_infer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1754,6 +1754,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
| ConstraintCategory::CallArgument(_)
| ConstraintCategory::CopyBound
| ConstraintCategory::SizedBound
| ConstraintCategory::MoveBound
| ConstraintCategory::Assignment
| ConstraintCategory::Usage
| ConstraintCategory::ClosureUpvar(_) => 2,
Expand Down
28 changes: 27 additions & 1 deletion compiler/rustc_borrowck/src/type_check/canonical.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@ use std::fmt;
use rustc_errors::ErrorGuaranteed;
use rustc_infer::infer::canonical::Canonical;
use rustc_infer::infer::outlives::env::RegionBoundPairs;
use rustc_infer::traits::{Obligation, ObligationCause};
use rustc_middle::bug;
use rustc_middle::mir::{Body, ConstraintCategory};
use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, Unnormalized, Upcast};
use rustc_span::Span;
use rustc_span::def_id::DefId;
use rustc_trait_selection::traits::ObligationCause;
use rustc_trait_selection::traits::query::type_op::custom::FallibleCustomTypeOp;
use rustc_trait_selection::traits::query::type_op::{self, TypeOpOutput};
use tracing::{debug, instrument};

Expand Down Expand Up @@ -185,6 +186,31 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
);
}

/// Certain proofs (e.g. `Move`) may error during MIR typeck, so handle them separately.
pub(super) fn prove_fallible_predicate(
&mut self,
predicate: impl Upcast<TyCtxt<'tcx>, ty::Predicate<'tcx>> + std::fmt::Debug,
locations: Locations,
category: ConstraintCategory<'tcx>,
) {
let span = self.last_span;
let predicate = predicate.upcast(self.tcx());
let op = FallibleCustomTypeOp::new(
|ocx| {
ocx.register_obligation(Obligation::new(
ocx.infcx.tcx,
ObligationCause::dummy_with_span(span),
self.infcx.param_env,
predicate,
));
Ok(())
},
"fallible type op",
);

let _: Result<_, ErrorGuaranteed> = self.fully_perform_op(locations, category, op);
}

pub(super) fn normalize<T>(
&mut self,
value: Unnormalized<'tcx, T>,
Expand Down
56 changes: 50 additions & 6 deletions compiler/rustc_borrowck/src/type_check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ use rustc_infer::infer::region_constraints::RegionConstraintData;
use rustc_infer::infer::{
BoundRegionConversionTime, InferCtxt, NllRegionVariableOrigin, RegionVariableOrigin,
};
use rustc_infer::traits::{Obligation, ObligationCause, PredicateObligations};
use rustc_infer::traits::{Obligation, ObligationCause, PredicateObligations, ScrubbedTraitError};
use rustc_middle::bug;
use rustc_middle::mir::visit::{NonMutatingUseContext, PlaceContext, Visitor};
use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor};
use rustc_middle::mir::*;
use rustc_middle::traits::query::NoSolution;
use rustc_middle::ty::adjustment::PointerCoercion;
Expand Down Expand Up @@ -1882,6 +1882,44 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
// it must.
self.prove_trait_ref(trait_ref, location.to_locations(), ConstraintCategory::CopyBound);
}

if tcx.features().move_trait() {
match context {
PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy)
| PlaceContext::NonMutatingUse(NonMutatingUseContext::Move) => {
let trait_ref = ty::TraitRef::new(
tcx,
tcx.require_lang_item(LangItem::Move, self.last_span),
[place_ty.ty],
);
self.prove_fallible_predicate(
trait_ref,
location.to_locations(),
ConstraintCategory::MoveBound,
);
}
PlaceContext::NonUse(_)
| PlaceContext::NonMutatingUse(
NonMutatingUseContext::FakeBorrow
| NonMutatingUseContext::Inspect
| NonMutatingUseContext::PlaceMention
| NonMutatingUseContext::Projection
| NonMutatingUseContext::RawBorrow
| NonMutatingUseContext::SharedBorrow,
)
| PlaceContext::MutatingUse(
MutatingUseContext::Store
| MutatingUseContext::SetDiscriminant
| MutatingUseContext::AsmOutput
| MutatingUseContext::Call
| MutatingUseContext::Yield
| MutatingUseContext::Drop
| MutatingUseContext::Borrow
| MutatingUseContext::RawBorrow
| MutatingUseContext::Projection,
) => {}
}
}
}

fn visit_projection_elem(
Expand Down Expand Up @@ -2801,10 +2839,16 @@ impl<'tcx> TypeOp<'tcx> for InstantiateOpaqueType<'tcx> {
span: Span,
) -> Result<TypeOpOutput<'tcx, Self>, ErrorGuaranteed> {
let (mut output, region_constraints) =
scrape_region_constraints(infcx, root_def_id, "InstantiateOpaqueType", span, |ocx| {
ocx.register_obligations(self.obligations.clone());
Ok(())
})?;
scrape_region_constraints::<_, _, ScrubbedTraitError<'tcx>>(
infcx,
root_def_id,
"InstantiateOpaqueType",
span,
|ocx| {
ocx.register_obligations(self.obligations.clone());
Ok(())
},
)?;
self.region_constraints = Some(region_constraints);
output.error_info = Some(self);
Ok(output)
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_feature/src/unstable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -625,6 +625,8 @@ declare_features! (
(unstable, more_qualified_paths, "1.54.0", Some(86935)),
/// Allows `move(expr)` in closures.
(incomplete, move_expr, "1.97.0", Some(155050)),
/// The `Move` autotrait.
(incomplete, move_trait, "CURRENT_RUSTC_VERSION", Some(149607)),
/// The `movrs` target feature on x86.
(unstable, movrs_target_feature, "1.88.0", Some(137976)),
/// Allows the `multiple_supertrait_upcastable` lint.
Expand Down
15 changes: 8 additions & 7 deletions compiler/rustc_hir_analysis/src/check/check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2097,12 +2097,11 @@ fn check_type_alias_type_params_are_used<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalD
None
}
})
// FIXME: This assumes that elaborated `Sized` bounds come first (which does hold at the
// time of writing). This is a bit fragile since we later use the span to detect elaborated
// `Sized` bounds. If they came last for example, this would break `Trait + /*elab*/Sized`
// since it would overwrite the span of the user-written bound. This could be fixed by
// folding the spans with `Span::to` which requires a bit of effort I think.
.collect::<FxIndexMap<_, _>>()
// keeping all values, we are in an error branch anyway
.fold(FxIndexMap::<_, Vec<_>>::default(), |mut map, (index, span)| {
map.entry(index).or_default().push(span);
map
})
});

let mut params_used = DenseBitSet::new_empty(generics.own_params.len());
Expand All @@ -2126,7 +2125,9 @@ fn check_type_alias_type_params_are_used<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalD
// * check for emptiness to detect lone user-written `?Sized` bounds
// * compare the param span to the pred span to detect lone user-written `Sized` bounds
let has_explicit_bounds = bounded_params.is_empty()
|| (*bounded_params).get(&param.index).is_some_and(|&&pred_sp| pred_sp != span);
|| (*bounded_params)
.get(&param.index)
.is_some_and(|pred_spans| pred_spans.iter().any(|&&pred_sp| pred_sp != span));
let const_param_help = !has_explicit_bounds;

let mut diag = tcx.dcx().create_err(diagnostics::UnusedGenericParameter {
Expand Down
5 changes: 4 additions & 1 deletion compiler/rustc_hir_analysis/src/check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -405,7 +405,10 @@ fn bounds_from_generic_clauses<'tcx>(
ty::ClauseKind::Trait(trait_predicate) => {
let entry = types.entry(trait_predicate.self_ty()).or_default();
let def_id = trait_predicate.def_id();
if !tcx.is_default_trait(def_id) && !tcx.is_lang_item(def_id, LangItem::Sized) {
// nia: fixme: metasized
if !tcx.is_implicit_trait(def_id, ty::IncludingSized::No)
&& !tcx.is_lang_item(def_id, LangItem::Sized)
{
// Do not add that restriction to the list if it is a positive requirement.
entry.push(trait_predicate.def_id());
}
Expand Down
57 changes: 22 additions & 35 deletions compiler/rustc_hir_analysis/src/collect/clauses_of.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@ use std::assert_matches;
use hir::Node;
use rustc_data_structures::fx::FxIndexSet;
use rustc_hir as hir;
use rustc_hir::attrs::lang_items::LangItem;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::find_attr;
use rustc_middle::ty::{
self, GenericClauses, ImplTraitInTraitData, RegionExt, Ty, TyCtxt, TypeVisitable, TypeVisitor,
Upcast,
self, ClausePolarity, GenericClauses, ImplTraitInTraitData, RegionExt, Ty, TyCtxt,
TypeVisitable, TypeVisitor, Upcast,
};
use rustc_middle::{bug, span_bug};
use rustc_span::{DUMMY_SP, Ident, Span};
Expand Down Expand Up @@ -74,12 +75,22 @@ pub(super) fn clauses_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericClauses<'
);
}

if !tcx.features().move_trait() {
result.clauses = tcx.arena.alloc_from_iter(result.clauses.iter().copied().filter(|p| {
!p.0.as_trait_clause().is_some_and(|p| {
p.polarity() == ClausePolarity::Positive
&& matches!(tcx.as_lang_item(p.def_id()), Some(LangItem::Move))
})
}));
}

debug!("clauses_of({:?}) = {:?}", def_id, result);
result
}

/// Returns a list of user-specified type clauses for the definition with ID `def_id`.
/// N.B., this does not include any implied/inferred constraints.
/// N.B., this does not include any implied/inferred constraints,
/// including instead default bounds like `Move`
#[instrument(level = "trace", skip(tcx), ret)]
fn gather_explicit_clauses_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::GenericClauses<'_> {
use rustc_hir::*;
Expand Down Expand Up @@ -197,19 +208,13 @@ fn gather_explicit_clauses_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generi
PredicateFilter::All,
OverlappingAsssocItemConstraints::Allowed,
);
icx.lowerer().add_implicit_sizedness_bounds(
&mut bounds,
tcx.types.self_param,
self_bounds,
ImpliedBoundsContext::TraitDef(def_id),
span,
);
icx.lowerer().add_default_traits(
icx.lowerer().add_implicit_bounds(
&mut bounds,
tcx.types.self_param,
self_bounds,
ImpliedBoundsContext::TraitDef(def_id),
span,
true,
);
clauses.extend(bounds);
}
Expand All @@ -236,19 +241,13 @@ fn gather_explicit_clauses_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generi
let param_ty = icx.lowerer().lower_ty_param(param.hir_id);
let mut bounds = Vec::new();
// Implicit bounds are added to type params unless a `?Trait` bound is found
icx.lowerer().add_implicit_sizedness_bounds(
&mut bounds,
param_ty,
&[],
ImpliedBoundsContext::TyParam(param.def_id, hir_generics.predicates),
param.span,
);
icx.lowerer().add_default_traits(
icx.lowerer().add_implicit_bounds(
&mut bounds,
param_ty,
&[],
ImpliedBoundsContext::TyParam(param.def_id, hir_generics.predicates),
param.span,
true,
);
trace!(?bounds);
clauses.extend(bounds);
Expand Down Expand Up @@ -684,19 +683,13 @@ pub(super) fn implied_clauses_with_filter<'tcx>(
| PredicateFilter::SelfOnly
| PredicateFilter::SelfTraitThatDefines(_)
| PredicateFilter::SelfAndAssociatedTypeBounds => {
icx.lowerer().add_implicit_sizedness_bounds(
&mut bounds,
self_param_ty,
superbounds,
ImpliedBoundsContext::TraitDef(trait_def_id),
item.span,
);
icx.lowerer().add_default_traits(
icx.lowerer().add_implicit_bounds(
&mut bounds,
self_param_ty,
superbounds,
ImpliedBoundsContext::TraitDef(trait_def_id),
item.span,
true,
);
}
//`ConstIfConst` is only interested in `[const]` bounds.
Expand Down Expand Up @@ -986,19 +979,13 @@ impl<'tcx> ItemCtxt<'tcx> {
match param.kind {
hir::GenericParamKind::Type { .. } => {
let param_ty = self.lowerer().lower_ty_param(param.hir_id);
self.lowerer().add_implicit_sizedness_bounds(
&mut bounds,
param_ty,
&[],
ImpliedBoundsContext::TyParam(param.def_id, hir_generics.predicates),
param.span,
);
self.lowerer().add_default_traits(
self.lowerer().add_implicit_bounds(
&mut bounds,
param_ty,
&[],
ImpliedBoundsContext::TyParam(param.def_id, hir_generics.predicates),
param.span,
true,
);
}
hir::GenericParamKind::Lifetime { .. }
Expand Down
20 changes: 4 additions & 16 deletions compiler/rustc_hir_analysis/src/collect/item_bounds.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,19 +55,13 @@ fn associated_type_bounds<'tcx>(
| PredicateFilter::SelfTraitThatDefines(_)
| PredicateFilter::SelfAndAssociatedTypeBounds => {
// Implicit bounds are added to associated types unless a `?Trait` bound is found.
icx.lowerer().add_implicit_sizedness_bounds(
&mut bounds,
item_ty,
hir_bounds,
ImpliedBoundsContext::AssociatedTypeOrImplTrait,
span,
);
icx.lowerer().add_default_traits(
icx.lowerer().add_implicit_bounds(
&mut bounds,
item_ty,
hir_bounds,
ImpliedBoundsContext::AssociatedTypeOrImplTrait,
span,
true,
);

// Also collect `where Self::Assoc: Trait` from the parent trait's where clauses.
Expand Down Expand Up @@ -382,19 +376,13 @@ fn opaque_type_bounds<'tcx>(
| PredicateFilter::SelfOnly
| PredicateFilter::SelfTraitThatDefines(_)
| PredicateFilter::SelfAndAssociatedTypeBounds => {
icx.lowerer().add_implicit_sizedness_bounds(
&mut bounds,
item_ty,
hir_bounds,
ImpliedBoundsContext::AssociatedTypeOrImplTrait,
span,
);
icx.lowerer().add_default_traits(
icx.lowerer().add_implicit_bounds(
&mut bounds,
item_ty,
hir_bounds,
ImpliedBoundsContext::AssociatedTypeOrImplTrait,
span,
true,
);
}
//`ConstIfConst` is only interested in `[const]` bounds.
Expand Down
Loading
Loading