Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
11 changes: 11 additions & 0 deletions compiler/rustc_resolve/src/diagnostics/impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1436,6 +1436,17 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
ResolutionError::BindingInNeverPattern => {
self.dcx().create_err(diagnostics::BindingInNeverPattern { span })
}
ResolutionError::CannotUseInnerLocalInMoveExpr {
move_expr_span,
ident,
scope_span,
} => self.dcx().create_err(diagnostics::CannotUseInnerLocalInMoveExpr {
span,
ident,
binding_span: ident.span,
move_expr_span,
scope_span,
}),
}
}

Expand Down
14 changes: 14 additions & 0 deletions compiler/rustc_resolve/src/diagnostics/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -525,6 +525,20 @@ pub(crate) struct BindingInNeverPattern {
pub(crate) span: Span,
}

#[derive(Diagnostic)]
#[diag("cannot use `{$ident}` in this move expression")]
pub(crate) struct CannotUseInnerLocalInMoveExpr {
#[primary_span]
pub(crate) span: Span,
pub(crate) ident: Ident,
#[label("`{$ident}` is defined here")]
pub(crate) binding_span: Span,
#[label("this expression is evaluated outside that scope")]
pub(crate) move_expr_span: Span,
#[label("`{$ident}` is defined within this scope")]
pub(crate) scope_span: Span,
}

#[derive(Diagnostic)]
#[diag("duplicate definitions with name `{$name}`:", code = E0201)]
pub(crate) struct TraitImplDuplicate {
Expand Down
21 changes: 21 additions & 0 deletions compiler/rustc_resolve/src/ident.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1511,9 +1511,28 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {

for rib in ribs {
match rib.kind {
// `first_rib` marks the start of the closure or coroutine scope.
// The initializer is evaluated outside that scope, so bindings defined
// inside it are unavailable, while outer bindings remain accessible.
RibKind::MoveExpr { first_rib, move_expr_span, scope_span }
if rib_index >= first_rib =>
{
if let Some(span) = finalize {
self.report_error(
span,
CannotUseInnerLocalInMoveExpr {
move_expr_span,
ident: original_rib_ident_def,
scope_span,
},
);
}
return Res::Err;
}
RibKind::Normal
| RibKind::Block(..)
| RibKind::FnOrCoroutine
| RibKind::MoveExpr { .. }
| RibKind::Module(..)
| RibKind::MacroDefinition(..)
| RibKind::ForwardGenericParamBan(_) => {
Expand Down Expand Up @@ -1610,6 +1629,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
RibKind::Normal
| RibKind::Block(..)
| RibKind::FnOrCoroutine
| RibKind::MoveExpr { .. }
| RibKind::Module(..)
| RibKind::MacroDefinition(..)
| RibKind::InlineAsmSym
Expand Down Expand Up @@ -1717,6 +1737,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
RibKind::Normal
| RibKind::Block(..)
| RibKind::FnOrCoroutine
| RibKind::MoveExpr { .. }
| RibKind::Module(..)
| RibKind::MacroDefinition(..)
| RibKind::InlineAsmSym
Expand Down
87 changes: 74 additions & 13 deletions compiler/rustc_resolve/src/late.rs
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,12 @@ pub(crate) enum RibKind<'ra> {
/// We passed through a function, closure or coroutine signature. Disallow labels.
FnOrCoroutine,

MoveExpr {
first_rib: usize,
move_expr_span: Span,
scope_span: Span,
},

/// We passed through an item scope. Disallow upvars.
Item(HasGenericParams, DefKind),

Expand Down Expand Up @@ -264,6 +270,7 @@ impl RibKind<'_> {
RibKind::Normal
| RibKind::Block(..)
| RibKind::FnOrCoroutine
| RibKind::MoveExpr { .. }
| RibKind::ConstantItem(..)
| RibKind::Module(_)
| RibKind::MacroDefinition(_)
Expand Down Expand Up @@ -840,6 +847,8 @@ struct LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
/// The current set of local scopes for types and values.
ribs: PerNS<Vec<Rib<'ra>>>,

move_expr_scopes: Vec<Option<(usize, Span)>>,

/// Previous popped `rib`, only used for diagnostic.
last_block_rib: Option<Rib<'ra>>,

Expand Down Expand Up @@ -901,7 +910,9 @@ impl<'ast, 'ra, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'ra, 'tc
// Always report errors in items we just entered.
let old_ignore = replace(&mut self.in_func_body, false);
with_owner(self, item.id, |this| {
this.with_lifetime_rib(LifetimeRibKind::Item, |this| this.resolve_item(item))
this.with_move_expr_scope(None, |this| {
this.with_lifetime_rib(LifetimeRibKind::Item, |this| this.resolve_item(item))
})
});
self.in_func_body = old_ignore;
self.diag_metadata.current_item = prev;
Expand Down Expand Up @@ -1617,6 +1628,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
type_ns: vec![Rib::new(start_rib_kind)],
macro_ns: vec![Rib::new(start_rib_kind)],
},
move_expr_scopes: Vec::new(),
last_block_rib: None,
label_ribs: Vec::new(),
lifetime_ribs: Vec::new(),
Expand Down Expand Up @@ -1728,6 +1740,39 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
}
}

fn with_move_expr_scope<T>(
&mut self,
scope_span: Option<Span>,
work: impl FnOnce(&mut Self) -> T,
) -> T {
if !self.r.features.move_expr() {
return work(self);
}
let scope = scope_span.map(|span| (self.ribs[ValueNS].len(), span));
self.move_expr_scopes.push(scope);
let result = work(self);
self.move_expr_scopes.pop();
result
}

fn with_move_expr_initializer<T>(
&mut self,
move_expr_span: Span,
work: impl FnOnce(&mut Self) -> T,
) -> T {
let Some(Some((first_rib, scope_span))) = self.move_expr_scopes.last().copied() else {
return work(self);
};
self.move_expr_scopes.pop();
let result = self.with_rib(
ValueNS,
RibKind::MoveExpr { first_rib, move_expr_span, scope_span },
work,
);
self.move_expr_scopes.push(Some((first_rib, scope_span)));
result
}

fn visit_generic_params(&mut self, params: &'ast [GenericParam], add_self_upper: bool) {
// For type parameter defaults, we have to ban access
// to following type parameters, as the GenericArgs can only
Expand Down Expand Up @@ -5566,30 +5611,46 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
ExprKind::Type(ref _type_expr, ref _ty) => {
visit::walk_expr(self, expr);
}
ExprKind::Move(..) => {
self.with_move_expr_initializer(expr.span, |this| visit::walk_expr(this, expr));
}
// For closures, RibKind::FnOrCoroutine is added in visit_fn
ExprKind::Closure(ast::Closure {
binder: ClosureBinder::For { ref generic_params, span },
fn_decl_span,
..
}) => {
self.with_generic_param_rib(
generic_params,
RibKind::Normal,
expr.id,
LifetimeBinderKind::Closure,
span,
|this| visit::walk_expr(this, expr),
);
self.with_move_expr_scope(Some(fn_decl_span), |this| {
this.with_generic_param_rib(
generic_params,
RibKind::Normal,
expr.id,
LifetimeBinderKind::Closure,
span,
|this| visit::walk_expr(this, expr),
);
});
}
ExprKind::Closure(ref closure) => {
self.with_move_expr_scope(Some(closure.fn_decl_span), |this| {
visit::walk_expr(this, expr)
});
}
ExprKind::Closure(..) => visit::walk_expr(self, expr),
ExprKind::Gen(..) => {
self.with_label_rib(RibKind::FnOrCoroutine, |this| visit::walk_expr(this, expr));
ExprKind::Gen(_, _, _, decl_span) => {
self.with_move_expr_scope(Some(decl_span), |this| {
this.with_label_rib(RibKind::FnOrCoroutine, |this| {
visit::walk_expr(this, expr)
});
});
}
ExprKind::Repeat(ref elem, ref ct) => {
self.visit_expr(elem);
self.resolve_anon_const(ct, AnonConstKind::ConstArg(IsRepeatExpr::Yes));
}
ExprKind::ConstBlock(ref ct) => {
self.resolve_anon_const(ct, AnonConstKind::InlineConst);
self.with_move_expr_scope(None, |this| {
this.resolve_anon_const(ct, AnonConstKind::InlineConst);
});
}
ExprKind::Index(ref elem, ref idx, _) => {
self.resolve_expr(elem, Some(expr));
Expand Down
29 changes: 24 additions & 5 deletions compiler/rustc_resolve/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,10 @@ enum ResolutionError<'ra> {
/// Error E0416: identifier is bound more than once in the same pattern.
IdentifierBoundMoreThanOnceInSamePattern(Ident),
/// Error E0426: use of undeclared label.
UndeclaredLabel { name: Symbol, suggestion: Option<LabelSuggestion> },
UndeclaredLabel {
name: Symbol,
suggestion: Option<LabelSuggestion>,
},
/// Error E0433: failed to resolve.
FailedToResolve {
segment: Symbol,
Expand All @@ -273,7 +276,9 @@ enum ResolutionError<'ra> {
message: String,
},
/// Error E0434: can't capture dynamic environment in a fn item.
CannotCaptureDynamicEnvironmentInFnItem { suggest_closure: bool },
CannotCaptureDynamicEnvironmentInFnItem {
suggest_closure: bool,
},
/// Error E0435: attempt to use a non-constant value in a constant.
AttemptToUseNonConstantValueInConstant {
ident: Ident,
Expand All @@ -296,7 +301,9 @@ enum ResolutionError<'ra> {
// FIXME(generic_const_parameter_types): This should give custom output specifying it's only
// problematic to use *forward declared* parameters when the feature is enabled.
/// ERROR E0770: the type of const parameters must not depend on other generic parameters.
ParamInTyOfConstParam { name: Symbol },
ParamInTyOfConstParam {
name: Symbol,
},
/// cannot use self in const param
SelfInConstParam,
/// generic parameters must not be used inside const evaluations.
Expand All @@ -310,11 +317,18 @@ enum ResolutionError<'ra> {
/// generic parameters must not be used inside enum discriminants.
///
/// This error is emitted even with `generic_const_exprs`.
ParamInEnumDiscriminant { name: Symbol, param_kind: ParamKindInEnumDiscriminant },
ParamInEnumDiscriminant {
name: Symbol,
param_kind: ParamKindInEnumDiscriminant,
},
/// Error E0735: generic parameters with a default cannot use `Self`
ForwardDeclaredSelf(ForwardGenericParamBanReason),
/// Error E0767: use of unreachable label
UnreachableLabel { name: Symbol, definition_span: Span, suggestion: Option<LabelSuggestion> },
UnreachableLabel {
name: Symbol,
definition_span: Span,
suggestion: Option<LabelSuggestion>,
},
/// Error E0323, E0324, E0325: mismatch between trait item and impl item.
TraitImplMismatch {
name: Ident,
Expand All @@ -339,6 +353,11 @@ enum ResolutionError<'ra> {
LowercaseSelf,
/// A never pattern has a binding.
BindingInNeverPattern,
CannotUseInnerLocalInMoveExpr {
move_expr_span: Span,
ident: Ident,
scope_span: Span,
},
}

#[derive(Debug)]
Expand Down
77 changes: 77 additions & 0 deletions tests/ui/move-expr/closure-local-bindings.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
//@ check-fail
//@ edition: 2024

#![allow(incomplete_features)]
#![feature(gen_blocks, move_expr)]

macro_rules! move_value {
($value:expr) => { move($value) };
}

fn main() {
let _ = |x: i32| move(x);
//~^ ERROR cannot use `x` in this move expression

let _ = |(x, _): (i32, i32)| move(x);
//~^ ERROR cannot use `x` in this move expression

let x = 1;
let _ = || {
let x = 2;
move(x);
//~^ ERROR cannot use `x` in this move expression
};

let _ = || {
for x in [1] {
move(x);
//~^ ERROR cannot use `x` in this move expression
}
};

let _ = || {
if let Some(x) = Some(1) {
move(x);
//~^ ERROR cannot use `x` in this move expression
}
};

let _ = || {
let x = 1;
|| move(move(x))
//~^ ERROR cannot use `x` in this move expression
};

let _ = || || move({
let x = 1;
move(x)
//~^ ERROR cannot use `x` in this move expression
});

let _ = || {
let x = 1;
move_value!(x);
//~^ ERROR cannot use `x` in this move expression
};

let _ = async |x: i32| move(x);
//~^ ERROR cannot use `x` in this move expression

let _ = async {
let x = 1;
move(x);
//~^ ERROR cannot use `x` in this move expression
};

let _ = gen {
let x = 1;
yield move(x);
//~^ ERROR cannot use `x` in this move expression
};

let _ = || {
let x = 1;
move(|| x)
//~^ ERROR cannot use `x` in this move expression
};
}
Loading
Loading