Skip to content

Commit 25e2a49

Browse files
Hack RefOrMut to allow use in closures.
1 parent 4b3ba58 commit 25e2a49

File tree

3 files changed

+27
-18
lines changed

3 files changed

+27
-18
lines changed

compiler/rustc_resolve/src/ident.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
4949
parent_scope: &ParentScope<'ra>,
5050
ctxt: SyntaxContext,
5151
derive_fallback_lint_id: Option<NodeId>,
52-
mut visitor: impl FnMut(
53-
&mut CmResolver<'r, 'ra, 'tcx>,
52+
mut visitor: impl for<'a> FnMut(
53+
CmResolver<'a, 'ra, 'tcx>,
5454
Scope<'ra>,
5555
UsePrelude,
5656
SyntaxContext,
@@ -154,7 +154,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
154154

155155
if visit {
156156
let use_prelude = if use_prelude { UsePrelude::Yes } else { UsePrelude::No };
157-
if let break_result @ Some(..) = visitor(&mut self, scope, use_prelude, ctxt) {
157+
if let break_result @ Some(..) = visitor(self.reborrow(), scope, use_prelude, ctxt)
158+
{
158159
return break_result;
159160
}
160161
}
@@ -438,7 +439,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
438439
parent_scope,
439440
orig_ident.span.ctxt(),
440441
derive_fallback_lint_id,
441-
|this, scope, use_prelude, ctxt| {
442+
|mut this, scope, use_prelude, ctxt| {
442443
let ident = Ident::new(orig_ident.name, orig_ident.span.with_ctxt(ctxt));
443444
let result = match scope {
444445
Scope::DeriveHelpers(expn_id) => {

compiler/rustc_resolve/src/imports.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -873,7 +873,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
873873
};
874874

875875
let mut indeterminate_count = 0;
876-
self.per_ns_cm(|this, ns| {
876+
self.per_ns_cm(|mut this, ns| {
877877
if !type_ns_only || ns == TypeNS {
878878
if bindings[ns].get() != PendingBinding::Pending {
879879
return;

compiler/rustc_resolve/src/lib.rs

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1835,13 +1835,13 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
18351835
f(self, MacroNS);
18361836
}
18371837

1838-
fn per_ns_cm<'r, F: FnMut(&mut CmResolver<'r, 'ra, 'tcx>, Namespace)>(
1838+
fn per_ns_cm<'r, F: FnMut(CmResolver<'_, 'ra, 'tcx>, Namespace)>(
18391839
mut self: CmResolver<'r, 'ra, 'tcx>,
18401840
mut f: F,
18411841
) {
1842-
f(&mut self, TypeNS);
1843-
f(&mut self, ValueNS);
1844-
f(&mut self, MacroNS);
1842+
f(self.reborrow(), TypeNS);
1843+
f(self.reborrow(), ValueNS);
1844+
f(self.reborrow(), MacroNS);
18451845
}
18461846

18471847
fn is_builtin_macro(&self, res: Res) -> bool {
@@ -1898,7 +1898,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
18981898
}
18991899

19001900
let scope_set = ScopeSet::All(TypeNS);
1901-
self.cm().visit_scopes(scope_set, parent_scope, ctxt, None, |this, scope, _, _| {
1901+
self.cm().visit_scopes(scope_set, parent_scope, ctxt, None, |mut this, scope, _, _| {
19021902
match scope {
19031903
Scope::Module(module, _) => {
19041904
this.get_mut().traits_in_module(module, assoc_item, &mut found_traits);
@@ -2536,38 +2536,44 @@ use std::cell::{Cell as CacheCell, RefCell as CacheRefCell};
25362536
mod ref_mut {
25372537
use std::cell::{BorrowMutError, Cell, Ref, RefCell, RefMut};
25382538
use std::fmt;
2539+
use std::marker::PhantomData;
25392540
use std::ops::Deref;
25402541

25412542
use crate::Resolver;
25422543

25432544
/// A wrapper around a mutable reference that conditionally allows mutable access.
25442545
pub(crate) struct RefOrMut<'a, T> {
2545-
p: &'a mut T,
2546+
// You can't actually create 2 `RefOrMut`s through `RefOrMut::new` because of the `&mut T`
2547+
// You can't alias it through `reborrow`, because reborrow requires a `&mut Self`
2548+
// You can't alias the underlying mutable reference through `get_mut` because it requires a `&mut Self`
2549+
// FIXME: still unsure if this is actually sound, I can't seem to create an example.
2550+
p: *const T,
25462551
mutable: bool,
2552+
_marker: PhantomData<&'a mut ()>,
25472553
}
25482554

25492555
impl<'a, T> Deref for RefOrMut<'a, T> {
25502556
type Target = T;
25512557

2552-
fn deref(&self) -> &Self::Target {
2553-
self.p
2558+
fn deref(&self) -> &T {
2559+
unsafe { self.p.as_ref_unchecked() }
25542560
}
25552561
}
25562562

25572563
impl<'a, T> AsRef<T> for RefOrMut<'a, T> {
25582564
fn as_ref(&self) -> &T {
2559-
self.p
2565+
unsafe { self.p.as_ref_unchecked() }
25602566
}
25612567
}
25622568

25632569
impl<'a, T> RefOrMut<'a, T> {
25642570
pub(crate) fn new(p: &'a mut T, mutable: bool) -> Self {
2565-
RefOrMut { p, mutable }
2571+
RefOrMut { p, mutable, _marker: PhantomData }
25662572
}
25672573

25682574
/// This is needed because this wraps a `&mut T` and is therefore not `Copy`.
25692575
pub(crate) fn reborrow(&mut self) -> RefOrMut<'_, T> {
2570-
RefOrMut { p: self.p, mutable: self.mutable }
2576+
RefOrMut { p: self.p, mutable: self.mutable, _marker: PhantomData }
25712577
}
25722578

25732579
/// Returns a mutable reference to the inner value if allowed.
@@ -2578,14 +2584,16 @@ mod ref_mut {
25782584
pub(crate) fn get_mut(&mut self) -> &mut T {
25792585
match self.mutable {
25802586
false => panic!("Can't mutably borrow speculative resolver"),
2581-
true => self.p,
2587+
// SAFETY: you can only create a `RefOrMut` with a `&mut T`
2588+
true => unsafe { self.p.cast_mut().as_mut_unchecked() },
25822589
}
25832590
}
25842591

25852592
/// Returns a mutable reference to the inner value without checking if
25862593
/// it's in a mutable state.
25872594
pub(crate) fn get_mut_unchecked(&mut self) -> &mut T {
2588-
self.p
2595+
// SAFETY: you can only create a `RefOrMut` with a `&mut T`
2596+
unsafe { self.p.cast_mut().as_mut_unchecked() }
25892597
}
25902598
}
25912599

0 commit comments

Comments
 (0)