Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
fc27dd9
fallible type ops
nia-e Jun 15, 2026
563102b
move trait
nia-e Jun 15, 2026
0206044
Fix: removed Move from being printed at all
zannabianca1997 Aug 5, 2026
327c67f
Fix: assume Move when the `move_trait` feature is not added
zannabianca1997 Aug 16, 2026
6129f18
Fix: preferred printing of `?Move` instead of `Move`
zannabianca1997 Aug 21, 2026
e3e7fcd
Feat: removed Move from mangled symbols
zannabianca1997 Aug 22, 2026
e40f11a
Feat: mangling of `?Move` bounds
zannabianca1997 Aug 23, 2026
5983324
Fix: legacy mangler (Fn printer)
zannabianca1997 Aug 23, 2026
a219d21
Fix: normalized test
zannabianca1997 Aug 23, 2026
85069ae
Fix: correctly refusing trait objects that have only Move as a bound
zannabianca1997 Aug 23, 2026
578ed15
Fix: line number drift
zannabianca1997 Aug 23, 2026
31a0281
Fix: missing Move pattern
zannabianca1997 Aug 23, 2026
f8f401a
Fix: removed the move clause from explicit clauses when the feature is
zannabianca1997 Aug 24, 2026
b863159
Cleanup
zannabianca1997 Aug 28, 2026
ea37fbc
Fix: expanded boolean into a more comprehensible enum
zannabianca1997 Aug 28, 2026
ca24c6b
aligned to boolean values
zannabianca1997 Aug 28, 2026
61365a2
Fix: helper to avoid repeating printing pattern
zannabianca1997 Aug 29, 2026
4c3e3ab
Fix: missing prints
zannabianca1997 Aug 29, 2026
d49d6c9
reborrow! yay.
zannabianca1997 Aug 29, 2026
3ee08e2
Fix: documented error in feature gate test
zannabianca1997 Aug 30, 2026
e081655
Fix: documented test being fixed under the next solver
zannabianca1997 Aug 30, 2026
b16295e
Chore: new test use the debug too
zannabianca1997 Aug 30, 2026
dc6d371
Giving up for now on aligning winnowing of Move to Sized
zannabianca1997 Sep 2, 2026
492a0a9
Revert "Fix: removed the move clause from explicit clauses when the f…
zannabianca1997 Sep 2, 2026
2a9e007
Fix: addressed fixme
zannabianca1997 Sep 2, 2026
cf27735
Moooore enums
zannabianca1997 Sep 6, 2026
1b2a43e
cached move trait id to avoid refetch
zannabianca1997 Sep 6, 2026
38b990c
Fix: MVSC tests type printing
zannabianca1997 Sep 6, 2026
6073522
normalize hash and type id instead of reblessing ad nauseam
zannabianca1997 Sep 6, 2026
3a515d3
Added move to the type description
zannabianca1997 Sep 6, 2026
b240c2a
Fix: rustdoc printing of `move` bounds
zannabianca1997 Sep 6, 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 @@ -500,13 +500,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 @@ -53,6 +53,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 @@ -1752,6 +1752,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
20 changes: 19 additions & 1 deletion compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,18 @@ fn push_debuginfo_type_name<'tcx>(
}
}
ty::Dynamic(trait_data, ..) => {
let auto_traits: SmallVec<[DefId; 4]> = trait_data.auto_traits().collect();
let mut has_move_bound = false;
let auto_traits: SmallVec<[DefId; 4]> = trait_data
.auto_traits()
.filter(|def_id| {
if tcx.is_move_trait(*def_id) {
has_move_bound = true;
false
} else {
true
}
})
.collect();

let has_enclosing_parens = if cpp_like_debuginfo {
output.push_str("dyn$<");
Expand Down Expand Up @@ -312,6 +323,13 @@ fn push_debuginfo_type_name<'tcx>(
push_item_name(tcx, def_id, true, &mut name);
name
})
.chain((!has_move_bound).then(|| {
let move_trait = tcx.lang_items().move_trait().unwrap();
let mut name = String::with_capacity(21);
name.push('?');
push_item_name(tcx, move_trait, true, &mut name);
name
}))
.collect();
auto_traits.sort_unstable();

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 @@ -2094,12 +2094,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 @@ -2123,7 +2122,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
59 changes: 25 additions & 34 deletions compiler/rustc_hir_analysis/src/collect/clauses_of.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ use rustc_hir::def::DefKind;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::find_attr;
use rustc_middle::ty::{
self, GenericClauses, ImplTraitInTraitData, Ty, TyCtxt, TypeVisitable, TypeVisitor, Upcast,
self, ClausePolarity, GenericClauses, ImplTraitInTraitData, Ty, TyCtxt, TypeVisitable,
TypeVisitor, Upcast,
};
use rustc_middle::{bug, span_bug};
use rustc_span::{DUMMY_SP, Ident, Span};
Expand Down Expand Up @@ -73,12 +74,26 @@ pub(super) fn clauses_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericClauses<'
);
}

// Optimization:
// If `#[feature(move_trait)]` is disabled, remove all `T: Move` clauses as they are trivial
if !tcx.features().move_trait()
&& let Some(move_trait) = tcx.lang_items().move_trait()
&& !result.clauses.is_empty()
{
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 && p.def_id() == move_trait
})
}));
}

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 @@ -196,19 +211,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,
ty::IncludingSized::Yes,
);
clauses.extend(bounds);
}
Expand All @@ -235,19 +244,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,
ty::IncludingSized::Yes,
);
trace!(?bounds);
clauses.extend(bounds);
Expand Down Expand Up @@ -691,19 +694,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,
ty::IncludingSized::Yes,
);
}
//`ConstIfConst` is only interested in `[const]` bounds.
Expand Down Expand Up @@ -993,19 +990,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,
ty::IncludingSized::Yes,
);
}
hir::GenericParamKind::Lifetime { .. }
Expand Down
Loading
Loading