diff --git a/Cargo.lock b/Cargo.lock index dae79e5bc260c..970b1719aa120 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2085,9 +2085,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libc" -version = "0.2.135" +version = "0.2.138" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68783febc7782c6c5cb401fbda4de5a9898be1762314da0bb2c10ced61f18b0c" +checksum = "db6d7e329c562c5dfab7a46a2afabc8b987ab9a4834c9d1ca04dc54c1546cef8" dependencies = [ "rustc-std-workspace-core", ] diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 4260805f1dd1f..695ccec0b1cb1 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -147,6 +147,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ), ExprKind::Async(capture_clause, closure_node_id, block) => self.make_async_expr( *capture_clause, + None, *closure_node_id, None, e.span, @@ -584,6 +585,7 @@ impl<'hir> LoweringContext<'_, 'hir> { pub(super) fn make_async_expr( &mut self, capture_clause: CaptureBy, + outer_hir_id: Option, closure_node_id: NodeId, ret_ty: Option>, span: Span, @@ -651,18 +653,20 @@ impl<'hir> LoweringContext<'_, 'hir> { hir::ExprKind::Closure(c) }; - let parent_has_track_caller = self - .attrs - .values() - .find(|attrs| attrs.into_iter().find(|attr| attr.has_name(sym::track_caller)).is_some()) - .is_some(); - let unstable_span = - self.mark_span_with_reason(DesugaringKind::Async, span, self.allow_gen_future.clone()); - let hir_id = if parent_has_track_caller { - let generator_hir_id = self.lower_node_id(closure_node_id); + let track_caller = outer_hir_id + .and_then(|id| self.attrs.get(&id.local_id)) + .map_or(false, |attrs| attrs.into_iter().any(|attr| attr.has_name(sym::track_caller))); + + let hir_id = self.lower_node_id(closure_node_id); + if track_caller { + let unstable_span = self.mark_span_with_reason( + DesugaringKind::Async, + span, + self.allow_gen_future.clone(), + ); self.lower_attrs( - generator_hir_id, + hir_id, &[Attribute { kind: AttrKind::Normal(ptr::P(NormalAttr { item: AttrItem { @@ -677,10 +681,7 @@ impl<'hir> LoweringContext<'_, 'hir> { span: unstable_span, }], ); - generator_hir_id - } else { - self.lower_node_id(closure_node_id) - }; + } let generator = hir::Expr { hir_id, kind: generator_kind, span: self.lower_span(span) }; @@ -1019,6 +1020,9 @@ impl<'hir> LoweringContext<'_, 'hir> { let async_body = this.make_async_expr( capture_clause, + // FIXME(nbdd0121): This should also use a proper HIR id so `#[track_caller]` + // can be applied on async closures as well. + None, inner_closure_id, async_ret_ty, body.span, diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index f6275433fc51b..9eda48e93294b 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -253,8 +253,13 @@ impl<'hir> LoweringContext<'_, 'hir> { // only cares about the input argument patterns in the function // declaration (decl), not the return types. let asyncness = header.asyncness; - let body_id = - this.lower_maybe_async_body(span, &decl, asyncness, body.as_deref()); + let body_id = this.lower_maybe_async_body( + span, + hir_id, + &decl, + asyncness, + body.as_deref(), + ); let mut itctx = ImplTraitContext::Universal; let (generics, decl) = this.lower_generics(generics, id, &mut itctx, |this| { @@ -701,6 +706,7 @@ impl<'hir> LoweringContext<'_, 'hir> { fn lower_trait_item(&mut self, i: &AssocItem) -> &'hir hir::TraitItem<'hir> { let hir_id = self.lower_node_id(i.id); + self.lower_attrs(hir_id, &i.attrs); let trait_item_def_id = hir_id.expect_owner(); let (generics, kind, has_default) = match &i.kind { @@ -724,7 +730,7 @@ impl<'hir> LoweringContext<'_, 'hir> { AssocItemKind::Fn(box Fn { sig, generics, body: Some(body), .. }) => { let asyncness = sig.header.asyncness; let body_id = - self.lower_maybe_async_body(i.span, &sig.decl, asyncness, Some(&body)); + self.lower_maybe_async_body(i.span, hir_id, &sig.decl, asyncness, Some(&body)); let (generics, sig) = self.lower_method_sig( generics, sig, @@ -759,7 +765,6 @@ impl<'hir> LoweringContext<'_, 'hir> { AssocItemKind::MacCall(..) => panic!("macro item shouldn't exist at this point"), }; - self.lower_attrs(hir_id, &i.attrs); let item = hir::TraitItem { owner_id: trait_item_def_id, ident: self.lower_ident(i.ident), @@ -798,6 +803,8 @@ impl<'hir> LoweringContext<'_, 'hir> { // Since `default impl` is not yet implemented, this is always true in impls. let has_value = true; let (defaultness, _) = self.lower_defaultness(i.kind.defaultness(), has_value); + let hir_id = self.lower_node_id(i.id); + self.lower_attrs(hir_id, &i.attrs); let (generics, kind) = match &i.kind { AssocItemKind::Const(_, ty, expr) => { @@ -810,8 +817,13 @@ impl<'hir> LoweringContext<'_, 'hir> { AssocItemKind::Fn(box Fn { sig, generics, body, .. }) => { self.current_item = Some(i.span); let asyncness = sig.header.asyncness; - let body_id = - self.lower_maybe_async_body(i.span, &sig.decl, asyncness, body.as_deref()); + let body_id = self.lower_maybe_async_body( + i.span, + hir_id, + &sig.decl, + asyncness, + body.as_deref(), + ); let (generics, sig) = self.lower_method_sig( generics, sig, @@ -844,8 +856,6 @@ impl<'hir> LoweringContext<'_, 'hir> { AssocItemKind::MacCall(..) => panic!("`TyMac` should have been expanded by now"), }; - let hir_id = self.lower_node_id(i.id); - self.lower_attrs(hir_id, &i.attrs); let item = hir::ImplItem { owner_id: hir_id.expect_owner(), ident: self.lower_ident(i.ident), @@ -978,6 +988,7 @@ impl<'hir> LoweringContext<'_, 'hir> { fn lower_maybe_async_body( &mut self, span: Span, + fn_id: hir::HirId, decl: &FnDecl, asyncness: Async, body: Option<&Block>, @@ -1128,6 +1139,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let async_expr = this.make_async_expr( CaptureBy::Value, + Some(fn_id), closure_id, None, body.span, diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 1daca464b4772..4f92477b5d87e 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -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, ); } diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index fe3cfde2e6383..f6a6ed379a2b5 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -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 diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 51a53f7b37cc2..fc9c9334aea8c 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -2360,8 +2360,8 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { if let GenericParamKind::Lifetime = param.kind { // Record lifetime res, so lowering knows there is something fishy. self.record_lifetime_param(param.id, LifetimeRes::Error); - continue; } + continue; } Entry::Vacant(entry) => { entry.insert(param.ident.span); diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs index 5db5cbfc3dfdd..949896e574806 100644 --- a/library/core/src/cmp.rs +++ b/library/core/src/cmp.rs @@ -29,8 +29,7 @@ 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. @@ -38,6 +37,8 @@ use self::Ordering::*; /// 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: /// diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index c10bfde4ddf79..a7aefc26b97c7 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -15,7 +15,7 @@ cfg-if = { version = "1.0", features = ['rustc-dep-of-std'] } panic_unwind = { path = "../panic_unwind", optional = true } panic_abort = { path = "../panic_abort" } core = { path = "../core" } -libc = { version = "0.2.135", default-features = false, features = ['rustc-dep-of-std'] } +libc = { version = "0.2.138", default-features = false, features = ['rustc-dep-of-std'] } compiler_builtins = { version = "0.1.82" } profiler_builtins = { path = "../profiler_builtins", optional = true } unwind = { path = "../unwind" } diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs index 2001e29bd2ead..37a8eb884efb0 100644 --- a/src/bootstrap/flags.rs +++ b/src/bootstrap/flags.rs @@ -143,7 +143,7 @@ pub enum Subcommand { args: Vec, }, Setup { - profile: Profile, + profile: Option, }, } @@ -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 } } diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index d69bced0b28db..3ed53452309c7 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -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); } diff --git a/src/bootstrap/setup.rs b/src/bootstrap/setup.rs index 04480277fe047..c7f98a7d0d149 100644 --- a/src/bootstrap/setup.rs +++ b/src/bootstrap/setup.rs @@ -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) { + 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 { // 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{}", diff --git a/src/ci/docker/scripts/freebsd-toolchain.sh b/src/ci/docker/scripts/freebsd-toolchain.sh index 4a4cac1b723c7..17cd456b995a1 100755 --- a/src/ci/docker/scripts/freebsd-toolchain.sh +++ b/src/ci/docker/scripts/freebsd-toolchain.sh @@ -53,7 +53,7 @@ files_to_extract=( for lib in c cxxrt gcc_s m thr util; do files_to_extract=("${files_to_extract[@]}" "./lib/lib${lib}.*" "./usr/lib/lib${lib}.*") done -for lib in c++ c_nonshared compiler_rt execinfo gcc pthread rt ssp_nonshared procstat devstat kvm; do +for lib in c++ c_nonshared compiler_rt execinfo gcc pthread rt ssp_nonshared procstat devstat kvm memstat; do files_to_extract=("${files_to_extract[@]}" "./usr/lib/lib${lib}.*") done diff --git a/src/test/ui/async-await/track-caller/issue-105134.rs b/src/test/ui/async-await/track-caller/issue-105134.rs new file mode 100644 index 0000000000000..4e52b8e250b9f --- /dev/null +++ b/src/test/ui/async-await/track-caller/issue-105134.rs @@ -0,0 +1,11 @@ +// check-pass +// edition:2021 + +#[track_caller] +fn f() { + let _ = async {}; +} + +fn main() { + f(); +} diff --git a/src/test/ui/async-await/track-caller/panic-track-caller.rs b/src/test/ui/async-await/track-caller/panic-track-caller.rs index b113c56412ff6..5ebfeb3f36ac1 100644 --- a/src/test/ui/async-await/track-caller/panic-track-caller.rs +++ b/src/test/ui/async-await/track-caller/panic-track-caller.rs @@ -54,6 +54,19 @@ async fn foo_track_caller() { bar_track_caller().await } +struct Foo; + +impl Foo { + #[track_caller] + async fn bar_assoc() { + panic!(); + } +} + +async fn foo_assoc() { + Foo::bar_assoc().await +} + fn panicked_at(f: impl FnOnce() + panic::UnwindSafe) -> u32 { let loc = Arc::new(Mutex::new(None)); @@ -73,4 +86,5 @@ fn panicked_at(f: impl FnOnce() + panic::UnwindSafe) -> u32 { fn main() { assert_eq!(panicked_at(|| block_on(foo())), 41); assert_eq!(panicked_at(|| block_on(foo_track_caller())), 54); + assert_eq!(panicked_at(|| block_on(foo_assoc())), 67); } diff --git a/src/test/ui/const-generics/defaults/self-referential.rs b/src/test/ui/const-generics/defaults/self-referential.rs new file mode 100644 index 0000000000000..14a870dc39bf6 --- /dev/null +++ b/src/test/ui/const-generics/defaults/self-referential.rs @@ -0,0 +1,4 @@ +trait Foo {} +//~^ ERROR the name `M` is already used for a generic parameter in this item's generic parameters +impl Foo<2> for () {} +fn main() {} diff --git a/src/test/ui/const-generics/defaults/self-referential.stderr b/src/test/ui/const-generics/defaults/self-referential.stderr new file mode 100644 index 0000000000000..170c1f7f7b2ae --- /dev/null +++ b/src/test/ui/const-generics/defaults/self-referential.stderr @@ -0,0 +1,11 @@ +error[E0403]: the name `M` is already used for a generic parameter in this item's generic parameters + --> $DIR/self-referential.rs:1:30 + | +LL | trait Foo {} + | - ^ already used + | | + | first use of `M` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0403`. diff --git a/src/test/ui/duplicate/duplicate-type-parameter.stderr b/src/test/ui/duplicate/duplicate-type-parameter.stderr index 6754574f0b953..628f898d5c879 100644 --- a/src/test/ui/duplicate/duplicate-type-parameter.stderr +++ b/src/test/ui/duplicate/duplicate-type-parameter.stderr @@ -55,10 +55,10 @@ LL | impl Qux for Option {} | first use of `T` error[E0207]: the type parameter `T` is not constrained by the impl trait, self type, or predicates - --> $DIR/duplicate-type-parameter.rs:24:6 + --> $DIR/duplicate-type-parameter.rs:24:8 | LL | impl Qux for Option {} - | ^ unconstrained type parameter + | ^ unconstrained type parameter error: aborting due to 8 previous errors diff --git a/src/test/ui/parser/expr-as-stmt.fixed b/src/test/ui/parser/expr-as-stmt.fixed index 36709eea17c21..b06f62794c4e3 100644 --- a/src/test/ui/parser/expr-as-stmt.fixed +++ b/src/test/ui/parser/expr-as-stmt.fixed @@ -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() {} diff --git a/src/test/ui/parser/expr-as-stmt.rs b/src/test/ui/parser/expr-as-stmt.rs index 92bb972b24020..b39d2b88647c0 100644 --- a/src/test/ui/parser/expr-as-stmt.rs +++ b/src/test/ui/parser/expr-as-stmt.rs @@ -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() {} diff --git a/src/test/ui/parser/expr-as-stmt.stderr b/src/test/ui/parser/expr-as-stmt.stderr index 6da4ac34067e9..18c8b0b7c506b 100644 --- a/src/test/ui/parser/expr-as-stmt.stderr +++ b/src/test/ui/parser/expr-as-stmt.stderr @@ -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`. diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index 0a6b9417cc2e2..8dd18ae98e6d6 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -cef44f53034eac46be3a0e3eec7b2b3d4ef5140b +203c8765ea33c65d888febe0e8219c4bb11b0d89 diff --git a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs index 50c2ad75ca71e..bcac873251f58 100644 --- a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs +++ b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs @@ -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 + // , 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), diff --git a/src/tools/miri/tests/fail/stacked_borrows/notunpin_dereferenceable_fakeread.rs b/src/tools/miri/tests/fail/stacked_borrows/notunpin_dereferenceable_fakeread.rs deleted file mode 100644 index d660921bfe6e2..0000000000000 --- a/src/tools/miri/tests/fail/stacked_borrows/notunpin_dereferenceable_fakeread.rs +++ /dev/null @@ -1,17 +0,0 @@ -//! Reborrowing a `&mut !Unpin` must still act like a (fake) read. -use std::marker::PhantomPinned; - -struct NotUnpin(i32, PhantomPinned); - -fn main() { - unsafe { - let mut x = NotUnpin(0, PhantomPinned); - // Mutable borrow of `Unpin` field (with lifetime laundering) - let fieldref = &mut *(&mut x.0 as *mut i32); - // Mutable reborrow of the entire `x`, which is `!Unpin` but should - // still count as a read since we would add `dereferenceable`. - let _xref = &mut x; - // That read should have invalidated `fieldref`. - *fieldref = 0; //~ ERROR: /write access .* tag does not exist in the borrow stack/ - } -} diff --git a/src/tools/miri/tests/fail/stacked_borrows/notunpin_dereferenceable_fakeread.stderr b/src/tools/miri/tests/fail/stacked_borrows/notunpin_dereferenceable_fakeread.stderr deleted file mode 100644 index 3ef8a8e0e9c6a..0000000000000 --- a/src/tools/miri/tests/fail/stacked_borrows/notunpin_dereferenceable_fakeread.stderr +++ /dev/null @@ -1,28 +0,0 @@ -error: Undefined Behavior: attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location - --> $DIR/notunpin_dereferenceable_fakeread.rs:LL:CC - | -LL | *fieldref = 0; - | ^^^^^^^^^^^^^ - | | - | attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location - | this error occurs as part of an access at ALLOC[0x0..0x4] - | - = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental - = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: was created by a Unique retag at offsets [0x0..0x4] - --> $DIR/notunpin_dereferenceable_fakeread.rs:LL:CC - | -LL | let fieldref = &mut *(&mut x.0 as *mut i32); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -help: was later invalidated at offsets [0x0..0x4] by a SharedReadWrite retag - --> $DIR/notunpin_dereferenceable_fakeread.rs:LL:CC - | -LL | let _xref = &mut x; - | ^^^^^^ - = note: BACKTRACE: - = note: inside `main` at $DIR/notunpin_dereferenceable_fakeread.rs:LL:CC - -note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace - -error: aborting due to previous error - diff --git a/src/tools/miri/tests/pass/stacked-borrows/future-self-referential.rs b/src/tools/miri/tests/pass/stacked-borrows/future-self-referential.rs new file mode 100644 index 0000000000000..3ba21552fd362 --- /dev/null +++ b/src/tools/miri/tests/pass/stacked-borrows/future-self-referential.rs @@ -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(fut: impl Future) -> T { + use std::sync::Arc; + + struct MyWaker; + impl Wake for MyWaker { + fn wake(self: Arc) { + 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()); +}