Skip to content

Rollup of 8 pull requests #105308

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 24 commits into from
Closed
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
34de257
PERs are homogeneous
RalfJung Nov 25, 2022
71fd3ab
Don't update submodules for `x setup`
jyn514 Nov 26, 2022
86251da
Refactor `setup_config_toml` into a function
jyn514 Nov 26, 2022
b771d90
Revamp the order `setup` executes
jyn514 Nov 26, 2022
ab89c17
Ensure required submodules at the same time as updating existing subm…
jyn514 Nov 26, 2022
51ac2af
interpret: clobber return place when calling function
RalfJung Dec 3, 2022
3b4cbe9
add test for self-referential future
RalfJung Dec 3, 2022
3fa692c
for now, do not do fake reads on non-Unpin mutable references
RalfJung Dec 3, 2022
faec289
Auto merge of #2713 - RalfJung:not-unpin-fake-read, r=RalfJung
bors Dec 3, 2022
35c00a9
suggest parenthesis around ExprWithBlock BinOp ExprWithBlock
Dec 3, 2022
c808d0b
more comments
Dec 3, 2022
6cc86db
Add small comment explaining what `method-margins.goml` test is about
GuillaumeGomez Dec 4, 2022
5811057
fix dupe word typos
Rageking8 Dec 5, 2022
16a9fdf
Preparing for merge from rustc
RalfJung Dec 5, 2022
7481ba7
Merge from rustc
RalfJung Dec 5, 2022
552b63c
Auto merge of #2715 - RalfJung:rustup, r=RalfJung
bors Dec 5, 2022
9ad58d0
Rollup merge of #104912 - RalfJung:per, r=Mark-Simulacrum
matthiaskrgr Dec 5, 2022
3a25327
Rollup merge of #104952 - jyn514:setup, r=Mark-Simulacrum
matthiaskrgr Dec 5, 2022
5c0e0ce
Rollup merge of #104953 - jyn514:fewer-submodule-updates, r=Mark-Simu…
matthiaskrgr Dec 5, 2022
9539059
Rollup merge of #105207 - RalfJung:interpret-clobber-return, r=oli-obk
matthiaskrgr Dec 5, 2022
9a438dc
Rollup merge of #105223 - lukas-code:(ExprWithBlock), r=petrochenkov
matthiaskrgr Dec 5, 2022
1847671
Rollup merge of #105256 - GuillaumeGomez:comment-method-margins, r=no…
matthiaskrgr Dec 5, 2022
4c0166f
Rollup merge of #105289 - Rageking8:fix-dupe-word-typos, r=cjgillot
matthiaskrgr Dec 5, 2022
2a030bb
Rollup merge of #105301 - RalfJung:miri, r=oli-obk
matthiaskrgr Dec 5, 2022
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
2 changes: 1 addition & 1 deletion compiler/rustc_const_eval/src/const_eval/machine.rs
Original file line number Diff line number Diff line change
@@ -240,7 +240,7 @@ impl<'mir, 'tcx: 'mir> CompileTimeEvalContext<'mir, 'tcx> {
let align = ImmTy::from_uint(target_align, args[1].layout).into();
let fn_abi = self.fn_abi_of_instance(instance, ty::List::empty())?;

// We replace the entire entire function call with a "tail call".
// We replace the entire function call with a "tail call".
// Note that this happens before the frame of the original function
// is pushed on the stack.
self.eval_fn_call(
4 changes: 4 additions & 0 deletions compiler/rustc_const_eval/src/interpret/eval_context.rs
Original file line number Diff line number Diff line change
@@ -676,6 +676,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
return_to_block: StackPopCleanup,
) -> InterpResult<'tcx> {
trace!("body: {:#?}", body);
// Clobber previous return place contents, nobody is supposed to be able to see them any more
// This also checks dereferenceable, but not align. We rely on all constructed places being
// sufficiently aligned (in particular we rely on `deref_operand` checking alignment).
self.write_uninit(return_place)?;
// first push a stack frame so we have access to the local substs
let pre_frame = Frame {
body,
4 changes: 3 additions & 1 deletion compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
Original file line number Diff line number Diff line change
@@ -32,11 +32,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}

pub(in super::super) fn suggest_semicolon_at_end(&self, span: Span, err: &mut Diagnostic) {
// This suggestion is incorrect for
// fn foo() -> bool { match () { () => true } || match () { () => true } }
err.span_suggestion_short(
span.shrink_to_hi(),
"consider using a semicolon here",
";",
Applicability::MachineApplicable,
Applicability::MaybeIncorrect,
);
}

2 changes: 1 addition & 1 deletion compiler/rustc_mir_dataflow/src/value_analysis.rs
Original file line number Diff line number Diff line change
@@ -406,7 +406,7 @@ impl<V: Clone> Clone for StateData<V> {
/// The dataflow state for an instance of [`ValueAnalysis`].
///
/// Every instance specifies a lattice that represents the possible values of a single tracked
/// place. If we call this lattice `V` and set set of tracked places `P`, then a [`State`] is an
/// place. If we call this lattice `V` and set of tracked places `P`, then a [`State`] is an
/// element of `{unreachable} ∪ (P -> V)`. This again forms a lattice, where the bottom element is
/// `unreachable` and the top element is the mapping `p ↦ ⊤`. Note that the mapping `p ↦ ⊥` is not
/// the bottom element (because joining an unreachable and any other reachable state yields a
19 changes: 5 additions & 14 deletions compiler/rustc_parse/src/parser/expr.rs
Original file line number Diff line number Diff line change
@@ -390,20 +390,11 @@ impl<'a> Parser<'a> {
// want to keep their span info to improve diagnostics in these cases in a later stage.
(true, Some(AssocOp::Multiply)) | // `{ 42 } *foo = bar;` or `{ 42 } * 3`
(true, Some(AssocOp::Subtract)) | // `{ 42 } -5`
(true, Some(AssocOp::Add)) // `{ 42 } + 42
// If the next token is a keyword, then the tokens above *are* unambiguously incorrect:
// `if x { a } else { b } && if y { c } else { d }`
if !self.look_ahead(1, |t| t.is_used_keyword()) => {
// These cases are ambiguous and can't be identified in the parser alone.
let sp = self.sess.source_map().start_point(self.token.span);
self.sess.ambiguous_block_expr_parse.borrow_mut().insert(sp, lhs.span);
false
}
(true, Some(AssocOp::LAnd)) |
(true, Some(AssocOp::LOr)) |
(true, Some(AssocOp::BitOr)) => {
// `{ 42 } &&x` (#61475) or `{ 42 } && if x { 1 } else { 0 }`. Separated from the
// above due to #74233.
(true, Some(AssocOp::Add)) | // `{ 42 } + 42` (unary plus)
(true, Some(AssocOp::LAnd)) | // `{ 42 } &&x` (#61475) or `{ 42 } && if x { 1 } else { 0 }`
(true, Some(AssocOp::LOr)) | // `{ 42 } || 42` ("logical or" or closure)
(true, Some(AssocOp::BitOr)) // `{ 42 } | 42` or `{ 42 } |x| 42`
=> {
// These cases are ambiguous and can't be identified in the parser alone.
//
// Bitwise AND is left out because guessing intent is hard. We can make
2 changes: 1 addition & 1 deletion compiler/rustc_resolve/src/late.rs
Original file line number Diff line number Diff line change
@@ -1927,7 +1927,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
// We have a single lifetime => success.
elision_lifetime = Elision::Param(res)
} else {
// We have have multiple lifetimes => error.
// We have multiple lifetimes => error.
elision_lifetime = Elision::Err;
}
}
5 changes: 3 additions & 2 deletions library/core/src/cmp.rs
Original file line number Diff line number Diff line change
@@ -29,15 +29,16 @@ use crate::marker::StructuralPartialEq;

use self::Ordering::*;

/// Trait for equality comparisons which are [partial equivalence
/// relations](https://en.wikipedia.org/wiki/Partial_equivalence_relation).
/// Trait for equality comparisons.
///
/// `x.eq(y)` can also be written `x == y`, and `x.ne(y)` can be written `x != y`.
/// We use the easier-to-read infix notation in the remainder of this documentation.
///
/// This trait allows for partial equality, for types that do not have a full
/// equivalence relation. For example, in floating point numbers `NaN != NaN`,
/// so floating point types implement `PartialEq` but not [`trait@Eq`].
/// Formally speaking, when `Rhs == Self`, this trait corresponds to a [partial equivalence
/// relation](https://en.wikipedia.org/wiki/Partial_equivalence_relation).
///
/// Implementations must ensure that `eq` and `ne` are consistent with each other:
///
2 changes: 1 addition & 1 deletion library/core/src/iter/sources/repeat_n.rs
Original file line number Diff line number Diff line change
@@ -20,7 +20,7 @@ use crate::mem::ManuallyDrop;
/// #![feature(iter_repeat_n)]
/// use std::iter;
///
/// // four of the the number four:
/// // four of the number four:
/// let mut four_fours = iter::repeat_n(4, 4);
///
/// assert_eq!(Some(4), four_fours.next());
2 changes: 1 addition & 1 deletion library/core/src/str/pattern.rs
Original file line number Diff line number Diff line change
@@ -1894,7 +1894,7 @@ unsafe fn small_slice_eq(x: &[u8], y: &[u8]) -> bool {
// Thus, derefencing both `px` and `py` in the loop below is safe.
//
// Moreover, we set `pxend` and `pyend` to be 4 bytes before the actual
// end of of `px` and `py`. Thus, the final dereference outside of the
// end of `px` and `py`. Thus, the final dereference outside of the
// loop is guaranteed to be valid. (The final comparison will overlap with
// the last comparison done in the loop for lengths that aren't multiples
// of four.)
2 changes: 1 addition & 1 deletion library/std/src/sync/mpmc/array.rs
Original file line number Diff line number Diff line change
@@ -225,7 +225,7 @@ impl<T> Channel<T> {
let slot = unsafe { self.buffer.get_unchecked(index) };
let stamp = slot.stamp.load(Ordering::Acquire);

// If the the stamp is ahead of the head by 1, we may attempt to pop.
// If the stamp is ahead of the head by 1, we may attempt to pop.
if head + 1 == stamp {
let new = if index + 1 < self.cap {
// Same lap, incremented index.
2 changes: 1 addition & 1 deletion library/std/src/thread/scoped.rs
Original file line number Diff line number Diff line change
@@ -46,7 +46,7 @@ impl ScopeData {
// We check for 'overflow' with usize::MAX / 2, to make sure there's no
// chance it overflows to 0, which would result in unsoundness.
if self.num_running_threads.fetch_add(1, Ordering::Relaxed) > usize::MAX / 2 {
// This can only reasonably happen by mem::forget()'ing many many ScopedJoinHandles.
// This can only reasonably happen by mem::forget()'ing a lot of ScopedJoinHandles.
self.decrement_num_running_threads(false);
panic!("too many running threads in thread scope");
}
9 changes: 5 additions & 4 deletions src/bootstrap/flags.rs
Original file line number Diff line number Diff line change
@@ -143,7 +143,7 @@ pub enum Subcommand {
args: Vec<String>,
},
Setup {
profile: Profile,
profile: Option<Profile>,
},
}

@@ -628,14 +628,15 @@ Arguments:
|path| format!("{} is not a valid UTF8 string", path.to_string_lossy())
));

profile_string.parse().unwrap_or_else(|err| {
let profile = profile_string.parse().unwrap_or_else(|err| {
eprintln!("error: {}", err);
eprintln!("help: the available profiles are:");
eprint!("{}", Profile::all_for_help("- "));
crate::detail_exit(1);
})
});
Some(profile)
} else {
t!(crate::setup::interactive_path())
None
};
Subcommand::Setup { profile }
}
50 changes: 28 additions & 22 deletions src/bootstrap/lib.rs
Original file line number Diff line number Diff line change
@@ -542,16 +542,6 @@ impl Build {
metrics: metrics::BuildMetrics::init(),
};

build.verbose("finding compilers");
cc_detect::find(&mut build);
// When running `setup`, the profile is about to change, so any requirements we have now may
// be different on the next invocation. Don't check for them until the next time x.py is
// run. This is ok because `setup` never runs any build commands, so it won't fail if commands are missing.
if !matches!(build.config.cmd, Subcommand::Setup { .. }) {
build.verbose("running sanity check");
sanity::check(&mut build);
}

// If local-rust is the same major.minor as the current version, then force a
// local-rebuild
let local_version_verbose =
@@ -567,16 +557,34 @@ impl Build {
build.local_rebuild = true;
}

// Make sure we update these before gathering metadata so we don't get an error about missing
// Cargo.toml files.
let rust_submodules =
["src/tools/rust-installer", "src/tools/cargo", "library/backtrace", "library/stdarch"];
for s in rust_submodules {
build.update_submodule(Path::new(s));
}
build.verbose("finding compilers");
cc_detect::find(&mut build);
// When running `setup`, the profile is about to change, so any requirements we have now may
// be different on the next invocation. Don't check for them until the next time x.py is
// run. This is ok because `setup` never runs any build commands, so it won't fail if commands are missing.
//
// Similarly, for `setup` we don't actually need submodules or cargo metadata.
if !matches!(build.config.cmd, Subcommand::Setup { .. }) {
build.verbose("running sanity check");
sanity::check(&mut build);

// Make sure we update these before gathering metadata so we don't get an error about missing
// Cargo.toml files.
let rust_submodules = [
"src/tools/rust-installer",
"src/tools/cargo",
"library/backtrace",
"library/stdarch",
];
for s in rust_submodules {
build.update_submodule(Path::new(s));
}
// Now, update all existing submodules.
build.update_existing_submodules();

build.verbose("learning about cargo");
metadata::build(&mut build);
build.verbose("learning about cargo");
metadata::build(&mut build);
}

build
}
@@ -668,7 +676,7 @@ impl Build {

/// If any submodule has been initialized already, sync it unconditionally.
/// This avoids contributors checking in a submodule change by accident.
pub fn maybe_update_submodules(&self) {
pub fn update_existing_submodules(&self) {
// Avoid running git when there isn't a git checkout.
if !self.config.submodules(&self.rust_info()) {
return;
@@ -697,8 +705,6 @@ impl Build {
job::setup(self);
}

self.maybe_update_submodules();

if let Subcommand::Format { check, paths } = &self.config.cmd {
return format::format(&builder::Builder::new(&self), *check, &paths);
}
91 changes: 47 additions & 44 deletions src/bootstrap/setup.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
use crate::Config;
use crate::{t, VERSION};
use crate::{Config, TargetSelection};
use std::env::consts::EXE_SUFFIX;
use std::fmt::Write as _;
use std::fs::File;
use std::io::Write;
use std::path::{Path, PathBuf, MAIN_SEPARATOR};
use std::process::Command;
use std::str::FromStr;
use std::{
env, fmt, fs,
io::{self, Write},
};
use std::{fmt, fs, io};

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Profile {
@@ -81,38 +79,10 @@ impl fmt::Display for Profile {
}
}

pub fn setup(config: &Config, profile: Profile) {
let path = &config.config.clone().unwrap_or(PathBuf::from("config.toml"));

if path.exists() {
eprintln!(
"error: you asked `x.py` to setup a new config file, but one already exists at `{}`",
path.display()
);
eprintln!("help: try adding `profile = \"{}\"` at the top of {}", profile, path.display());
eprintln!(
"note: this will use the configuration in {}",
profile.include_path(&config.src).display()
);
crate::detail_exit(1);
}

let settings = format!(
"# Includes one of the default files in src/bootstrap/defaults\n\
profile = \"{}\"\n\
changelog-seen = {}\n",
profile, VERSION
);
t!(fs::write(path, settings));

let include_path = profile.include_path(&config.src);
println!("`x.py` will now use the configuration at {}", include_path.display());

let build = TargetSelection::from_user(&env!("BUILD_TRIPLE"));
pub fn setup(config: &Config, profile: Option<Profile>) {
let profile = profile.unwrap_or_else(|| t!(interactive_path()));
let stage_path =
["build", build.rustc_target_arg(), "stage1"].join(&MAIN_SEPARATOR.to_string());

println!();
["build", config.build.rustc_target_arg(), "stage1"].join(&MAIN_SEPARATOR.to_string());

if !rustup_installed() && profile != Profile::User {
eprintln!("`rustup` is not installed; cannot link `stage1` toolchain");
@@ -134,8 +104,6 @@ pub fn setup(config: &Config, profile: Profile) {
Profile::User => &["dist", "build"],
};

println!();

t!(install_git_hook_maybe(&config));

println!();
@@ -150,6 +118,36 @@ pub fn setup(config: &Config, profile: Profile) {
"For more suggestions, see https://rustc-dev-guide.rust-lang.org/building/suggested.html"
);
}

let path = &config.config.clone().unwrap_or(PathBuf::from("config.toml"));
setup_config_toml(path, profile, config);
}

fn setup_config_toml(path: &PathBuf, profile: Profile, config: &Config) {
if path.exists() {
eprintln!();
eprintln!(
"error: you asked `x.py` to setup a new config file, but one already exists at `{}`",
path.display()
);
eprintln!("help: try adding `profile = \"{}\"` at the top of {}", profile, path.display());
eprintln!(
"note: this will use the configuration in {}",
profile.include_path(&config.src).display()
);
crate::detail_exit(1);
}

let settings = format!(
"# Includes one of the default files in src/bootstrap/defaults\n\
profile = \"{}\"\n\
changelog-seen = {}\n",
profile, VERSION
);
t!(fs::write(path, settings));

let include_path = profile.include_path(&config.src);
println!("`x.py` will now use the configuration at {}", include_path.display());
}

fn rustup_installed() -> bool {
@@ -303,7 +301,18 @@ pub fn interactive_path() -> io::Result<Profile> {

// install a git hook to automatically run tidy --bless, if they want
fn install_git_hook_maybe(config: &Config) -> io::Result<()> {
let git = t!(config.git().args(&["rev-parse", "--git-common-dir"]).output().map(|output| {
assert!(output.status.success(), "failed to run `git`");
PathBuf::from(t!(String::from_utf8(output.stdout)).trim())
}));
let dst = git.join("hooks").join("pre-push");
if dst.exists() {
// The git hook has already been set up, or the user already has a custom hook.
return Ok(());
}

let mut input = String::new();
println!();
println!(
"Rust's CI will automatically fail if it doesn't pass `tidy`, the internal tool for ensuring code quality.
If you'd like, x.py can install a git hook for you that will automatically run `tidy --bless` before
@@ -329,12 +338,6 @@ undesirable, simply delete the `pre-push` file from .git/hooks."

if should_install {
let src = config.src.join("src").join("etc").join("pre-push.sh");
let git =
t!(config.git().args(&["rev-parse", "--git-common-dir"]).output().map(|output| {
assert!(output.status.success(), "failed to run `git`");
PathBuf::from(t!(String::from_utf8(output.stdout)).trim())
}));
let dst = git.join("hooks").join("pre-push");
match fs::hard_link(src, &dst) {
Err(e) => eprintln!(
"error: could not create hook {}: do you already have the git hook installed?\n{}",
1 change: 1 addition & 0 deletions src/test/rustdoc-gui/method-margins.goml
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// This test ensures that the margins on methods are coherent inside an impl block.
goto: "file://" + |DOC_PATH| + "/test_docs/trait_members/struct.HasTrait.html#impl-TraitMembers-for-HasTrait"

assert-count: ("#trait-implementations-list > .rustdoc-toggle", 1)
12 changes: 12 additions & 0 deletions src/test/ui/parser/expr-as-stmt.fixed
Original file line number Diff line number Diff line change
@@ -64,4 +64,16 @@ fn asteroids() -> impl FnOnce() -> bool {
{ foo(); } || { true } //~ ERROR E0308
}

// https://github.com/rust-lang/rust/issues/105179
fn r#match() -> i32 {
(match () { () => 1 }) + match () { () => 1 } //~ ERROR expected expression, found `+`
//~^ ERROR mismatched types
}

// https://github.com/rust-lang/rust/issues/102171
fn r#unsafe() -> i32 {
(unsafe { 1 }) + unsafe { 1 } //~ ERROR expected expression, found `+`
//~^ ERROR mismatched types
}

fn main() {}
12 changes: 12 additions & 0 deletions src/test/ui/parser/expr-as-stmt.rs
Original file line number Diff line number Diff line change
@@ -64,4 +64,16 @@ fn asteroids() -> impl FnOnce() -> bool {
{ foo() } || { true } //~ ERROR E0308
}

// https://github.com/rust-lang/rust/issues/105179
fn r#match() -> i32 {
match () { () => 1 } + match () { () => 1 } //~ ERROR expected expression, found `+`
//~^ ERROR mismatched types
}

// https://github.com/rust-lang/rust/issues/102171
fn r#unsafe() -> i32 {
unsafe { 1 } + unsafe { 1 } //~ ERROR expected expression, found `+`
//~^ ERROR mismatched types
}

fn main() {}
43 changes: 42 additions & 1 deletion src/test/ui/parser/expr-as-stmt.stderr
Original file line number Diff line number Diff line change
@@ -55,6 +55,28 @@ help: parentheses are required to parse this as an expression
LL | ({ true }) | { true }
| + +

error: expected expression, found `+`
--> $DIR/expr-as-stmt.rs:69:26
|
LL | match () { () => 1 } + match () { () => 1 }
| ^ expected expression
|
help: parentheses are required to parse this as an expression
|
LL | (match () { () => 1 }) + match () { () => 1 }
| + +

error: expected expression, found `+`
--> $DIR/expr-as-stmt.rs:75:18
|
LL | unsafe { 1 } + unsafe { 1 }
| ^ expected expression
|
help: parentheses are required to parse this as an expression
|
LL | (unsafe { 1 }) + unsafe { 1 }
| + +

error[E0308]: mismatched types
--> $DIR/expr-as-stmt.rs:64:7
|
@@ -201,7 +223,26 @@ help: parentheses are required to parse this as an expression
LL | ({ true }) || { true }
| + +

error: aborting due to 18 previous errors
error[E0308]: mismatched types
--> $DIR/expr-as-stmt.rs:69:5
|
LL | match () { () => 1 } + match () { () => 1 }
| ^^^^^^^^^^^^^^^^^^^^- help: consider using a semicolon here
| |
| expected `()`, found integer

error[E0308]: mismatched types
--> $DIR/expr-as-stmt.rs:75:14
|
LL | unsafe { 1 } + unsafe { 1 }
| ^ expected `()`, found integer
|
help: you might have meant to return this value
|
LL | unsafe { return 1; } + unsafe { 1 }
| ++++++ +

error: aborting due to 22 previous errors

Some errors have detailed explanations: E0308, E0600, E0614.
For more information about an error, try `rustc --explain E0308`.
Original file line number Diff line number Diff line change
@@ -5,7 +5,7 @@ struct Foo {

impl PartialEq for Foo {
fn eq(&self, _: &Foo) -> bool {
false // ha ha sucker!
false // ha ha!
}
}

2 changes: 1 addition & 1 deletion src/tools/miri/rust-version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
cef44f53034eac46be3a0e3eec7b2b3d4ef5140b
203c8765ea33c65d888febe0e8219c4bb11b0d89
23 changes: 14 additions & 9 deletions src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs
Original file line number Diff line number Diff line change
@@ -45,7 +45,9 @@ pub struct Stacks {
/// new pointer.
#[derive(Copy, Clone, Hash, PartialEq, Eq)]
enum RefKind {
/// `&mut` and `Box`.
/// `Box`.
Box,
/// `&mut`.
Unique { two_phase: bool },
/// `&` with or without interior mutability.
Shared,
@@ -56,6 +58,7 @@ enum RefKind {
impl fmt::Display for RefKind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
RefKind::Box => write!(f, "Box"),
RefKind::Unique { two_phase: false } => write!(f, "unique reference"),
RefKind::Unique { two_phase: true } => write!(f, "unique reference (two-phase)"),
RefKind::Shared => write!(f, "shared reference"),
@@ -654,15 +657,17 @@ trait EvalContextPrivExt<'mir: 'ecx, 'tcx: 'mir, 'ecx>: crate::MiriInterpCxExt<'
let (perm, access) = match kind {
RefKind::Unique { two_phase } => {
// Permission is Unique only if the type is `Unpin` and this is not twophase
let perm = if !two_phase && place.layout.ty.is_unpin(*this.tcx, this.param_env()) {
Permission::Unique
if !two_phase && place.layout.ty.is_unpin(*this.tcx, this.param_env()) {
(Permission::Unique, Some(AccessKind::Write))
} else {
Permission::SharedReadWrite
};
// We do an access for all full borrows, even if `!Unpin`.
let access = if !two_phase { Some(AccessKind::Write) } else { None };
(perm, access)
// FIXME: We emit `dereferenceable` for `!Unpin` mutable references, so we
// should do fake accesses here. But then we run into
// <https://github.com/rust-lang/unsafe-code-guidelines/issues/381>, so for now
// we don't do that.
(Permission::SharedReadWrite, None)
}
}
RefKind::Box => (Permission::Unique, Some(AccessKind::Write)),
RefKind::Raw { mutable: true } => {
// Creating a raw ptr does not count as an access
(Permission::SharedReadWrite, None)
@@ -853,7 +858,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
// Boxes get a weak protectors, since they may be deallocated.
self.retag_place(
place,
RefKind::Unique { two_phase: false },
RefKind::Box,
self.retag_cause,
/*protector*/
(self.kind == RetagKind::FnEntry).then_some(ProtectorKind::WeakProtector),

This file was deleted.

This file was deleted.

102 changes: 102 additions & 0 deletions src/tools/miri/tests/pass/stacked-borrows/future-self-referential.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
#![feature(pin_macro)]

use std::future::*;
use std::marker::PhantomPinned;
use std::pin::*;
use std::ptr;
use std::task::*;

struct Delay {
delay: usize,
}

impl Delay {
fn new(delay: usize) -> Self {
Delay { delay }
}
}

impl Future for Delay {
type Output = ();
fn poll(mut self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<()> {
if self.delay > 0 {
self.delay -= 1;
Poll::Pending
} else {
Poll::Ready(())
}
}
}

async fn do_stuff() {
(&mut Delay::new(1)).await;
}

// Same thing implemented by hand
struct DoStuff {
state: usize,
delay: Delay,
delay_ref: *mut Delay,
_marker: PhantomPinned,
}

impl DoStuff {
fn new() -> Self {
DoStuff {
state: 0,
delay: Delay::new(1),
delay_ref: ptr::null_mut(),
_marker: PhantomPinned,
}
}
}

impl Future for DoStuff {
type Output = ();
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> {
unsafe {
let this = self.get_unchecked_mut();
match this.state {
0 => {
// Set up self-ref.
this.delay_ref = &mut this.delay;
// Move to next state.
this.state = 1;
Poll::Pending
}
1 => {
let delay = &mut *this.delay_ref;
Pin::new_unchecked(delay).poll(cx)
}
_ => unreachable!(),
}
}
}
}

fn run_fut<T>(fut: impl Future<Output = T>) -> T {
use std::sync::Arc;

struct MyWaker;
impl Wake for MyWaker {
fn wake(self: Arc<Self>) {
unimplemented!()
}
}

let waker = Waker::from(Arc::new(MyWaker));
let mut context = Context::from_waker(&waker);

let mut pinned = pin!(fut);
loop {
match pinned.as_mut().poll(&mut context) {
Poll::Pending => continue,
Poll::Ready(v) => return v,
}
}
}

fn main() {
run_fut(do_stuff());
run_fut(DoStuff::new());
}