diff options
| author | Ralf Jung <post@ralfj.de> | 2023-07-12 14:15:25 +0200 |
|---|---|---|
| committer | Ralf Jung <post@ralfj.de> | 2023-07-12 14:15:25 +0200 |
| commit | 4481569b2885e2d71285960e8b6b88a942f052d5 (patch) | |
| tree | 40bc220748430e2e69a0678d408024bd00f47e11 /src | |
| parent | 7624d33fccea45c8deabfcbd1aa702103ac63294 (diff) | |
| parent | fb5efd7008c698a821e9c50c3f3a04d48abd8295 (diff) | |
| download | rust-4481569b2885e2d71285960e8b6b88a942f052d5.tar.gz rust-4481569b2885e2d71285960e8b6b88a942f052d5.zip | |
Merge from rustc
Diffstat (limited to 'src')
58 files changed, 608 insertions, 377 deletions
diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index c9bd329d430..c0c749552e6 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -13,7 +13,7 @@ use std::process::Command; use std::time::{Duration, Instant}; use crate::cache::{Cache, Interned, INTERNER}; -use crate::config::{SplitDebuginfo, TargetSelection}; +use crate::config::{DryRun, SplitDebuginfo, TargetSelection}; use crate::doc; use crate::flags::{Color, Subcommand}; use crate::install; @@ -281,11 +281,15 @@ impl StepDescription { fn is_excluded(&self, builder: &Builder<'_>, pathset: &PathSet) -> bool { if builder.config.exclude.iter().any(|e| pathset.has(&e, builder.kind)) { - println!("Skipping {:?} because it is excluded", pathset); + if !matches!(builder.config.dry_run, DryRun::SelfCheck) { + println!("Skipping {:?} because it is excluded", pathset); + } return true; } - if !builder.config.exclude.is_empty() { + if !builder.config.exclude.is_empty() + && !matches!(builder.config.dry_run, DryRun::SelfCheck) + { builder.verbose(&format!( "{:?} not skipped for {:?} -- not in {:?}", pathset, self.name, builder.config.exclude diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index efe621bdb7d..caa7417011e 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -688,8 +688,8 @@ fn cp_rustc_component_to_ci_sysroot( contents: Vec<String>, ) { let sysroot = builder.ensure(Sysroot { compiler, force_recompile: false }); + let ci_rustc_dir = builder.config.ci_rustc_dir(); - let ci_rustc_dir = builder.out.join(&*builder.build.build.triple).join("ci-rustc"); for file in contents { let src = ci_rustc_dir.join(&file); let dst = sysroot.join(file); @@ -1424,7 +1424,7 @@ impl Step for Sysroot { // FIXME: this is wrong when compiler.host != build, but we don't support that today OsStr::new(std::env::consts::DLL_EXTENSION), ]; - let ci_rustc_dir = builder.ci_rustc_dir(builder.config.build); + let ci_rustc_dir = builder.config.ci_rustc_dir(); builder.cp_filtered(&ci_rustc_dir, &sysroot, &|path| { if path.extension().map_or(true, |ext| !filtered_extensions.contains(&ext)) { return true; diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 28ae46efefe..34853743323 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -1375,6 +1375,25 @@ impl Config { let mut omit_git_hash = None; if let Some(rust) = toml.rust { + set(&mut config.channel, rust.channel); + + config.download_rustc_commit = config.download_ci_rustc_commit(rust.download_rustc); + // This list is incomplete, please help by expanding it! + if config.download_rustc_commit.is_some() { + // We need the channel used by the downloaded compiler to match the one we set for rustdoc; + // otherwise rustdoc-ui tests break. + let ci_channel = t!(fs::read_to_string(config.src.join("src/ci/channel"))); + let ci_channel = ci_channel.trim_end(); + if config.channel != ci_channel + && !(config.channel == "dev" && ci_channel == "nightly") + { + panic!( + "setting rust.channel={} is incompatible with download-rustc", + config.channel + ); + } + } + debug = rust.debug; debug_assertions = rust.debug_assertions; debug_assertions_std = rust.debug_assertions_std; @@ -1386,6 +1405,7 @@ impl Config { debuginfo_level_std = rust.debuginfo_level_std; debuginfo_level_tools = rust.debuginfo_level_tools; debuginfo_level_tests = rust.debuginfo_level_tests; + config.rust_split_debuginfo = rust .split_debuginfo .as_deref() @@ -1401,7 +1421,6 @@ impl Config { set(&mut config.jemalloc, rust.jemalloc); set(&mut config.test_compare_mode, rust.test_compare_mode); set(&mut config.backtrace, rust.backtrace); - set(&mut config.channel, rust.channel); config.description = rust.description; set(&mut config.rust_dist_src, rust.dist_src); set(&mut config.verbose_tests, rust.verbose_tests); @@ -1442,8 +1461,6 @@ impl Config { config.rust_codegen_units_std = rust.codegen_units_std.map(threads_from_config); config.rust_profile_use = flags.rust_profile_use.or(rust.profile_use); config.rust_profile_generate = flags.rust_profile_generate.or(rust.profile_generate); - config.download_rustc_commit = config.download_ci_rustc_commit(rust.download_rustc); - config.rust_lto = rust .lto .as_deref() @@ -1555,6 +1572,11 @@ impl Config { let mut target = Target::from_triple(&triple); if let Some(ref s) = cfg.llvm_config { + if config.download_rustc_commit.is_some() && triple == &*config.build.triple { + panic!( + "setting llvm_config for the host is incompatible with download-rustc" + ); + } target.llvm_config = Some(config.src.join(s)); } target.llvm_has_rust_patches = cfg.llvm_has_rust_patches; @@ -1825,6 +1847,12 @@ impl Config { self.out.join(&*self.build.triple).join("ci-llvm") } + /// Directory where the extracted `rustc-dev` component is stored. + pub(crate) fn ci_rustc_dir(&self) -> PathBuf { + assert!(self.download_rustc()); + self.out.join(self.build.triple).join("ci-rustc") + } + /// Determine whether llvm should be linked dynamically. /// /// If `false`, llvm should be linked statically. @@ -1860,11 +1888,11 @@ impl Config { self.download_rustc_commit().is_some() } - pub(crate) fn download_rustc_commit(&self) -> Option<&'static str> { + pub(crate) fn download_rustc_commit(&self) -> Option<&str> { static DOWNLOAD_RUSTC: OnceCell<Option<String>> = OnceCell::new(); if self.dry_run() && DOWNLOAD_RUSTC.get().is_none() { // avoid trying to actually download the commit - return None; + return self.download_rustc_commit.as_deref(); } DOWNLOAD_RUSTC diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index 4522819f996..b34a4b2dc63 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -1074,11 +1074,7 @@ impl Step for Cargo { tarball.add_file(&cargo, "bin", 0o755); tarball.add_file(etc.join("_cargo"), "share/zsh/site-functions", 0o644); - tarball.add_renamed_file( - etc.join("cargo.bashcomp.sh"), - "src/etc/bash_completion.d", - "cargo", - ); + tarball.add_renamed_file(etc.join("cargo.bashcomp.sh"), "etc/bash_completion.d", "cargo"); tarball.add_dir(etc.join("man"), "share/man/man1"); tarball.add_legal_and_readme_to("share/doc/cargo"); diff --git a/src/bootstrap/download.rs b/src/bootstrap/download.rs index cb40521dda7..a081f6189d7 100644 --- a/src/bootstrap/download.rs +++ b/src/bootstrap/download.rs @@ -402,7 +402,11 @@ impl Config { fn ci_component_contents(&self, stamp_file: &str) -> Vec<String> { assert!(self.download_rustc()); - let ci_rustc_dir = self.out.join(&*self.build.triple).join("ci-rustc"); + if self.dry_run() { + return vec![]; + } + + let ci_rustc_dir = self.ci_rustc_dir(); let stamp_file = ci_rustc_dir.join(stamp_file); let contents_file = t!(File::open(&stamp_file), stamp_file.display().to_string()); t!(BufReader::new(contents_file).lines().collect()) @@ -419,7 +423,7 @@ impl Config { self.download_toolchain( &version, "ci-rustc", - commit, + &format!("{commit}-{}", self.llvm_assertions), &extra_components, Self::download_ci_component, ); @@ -495,8 +499,15 @@ impl Config { /// Download a single component of a CI-built toolchain (not necessarily a published nightly). // NOTE: intentionally takes an owned string to avoid downloading multiple times by accident - fn download_ci_component(&self, filename: String, prefix: &str, commit: &str) { - Self::download_component(self, DownloadSource::CI, filename, prefix, commit, "ci-rustc") + fn download_ci_component(&self, filename: String, prefix: &str, commit_with_assertions: &str) { + Self::download_component( + self, + DownloadSource::CI, + filename, + prefix, + commit_with_assertions, + "ci-rustc", + ) } fn download_component( @@ -516,11 +527,18 @@ impl Config { let bin_root = self.out.join(self.build.triple).join(destination); let tarball = cache_dir.join(&filename); let (base_url, url, should_verify) = match mode { - DownloadSource::CI => ( - self.stage0_metadata.config.artifacts_server.clone(), - format!("{key}/{filename}"), - false, - ), + DownloadSource::CI => { + let dist_server = if self.llvm_assertions { + self.stage0_metadata.config.artifacts_with_llvm_assertions_server.clone() + } else { + self.stage0_metadata.config.artifacts_server.clone() + }; + let url = format!( + "{}/{filename}", + key.strip_suffix(&format!("-{}", self.llvm_assertions)).unwrap() + ); + (dist_server, url, false) + } DownloadSource::Dist => { let dist_server = env::var("RUSTUP_DIST_SERVER") .unwrap_or(self.stage0_metadata.config.dist_server.to_string()); diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 0a7aff62257..0b509132043 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -822,11 +822,6 @@ impl Build { self.stage_out(compiler, mode).join(&*target.triple).join(self.cargo_dir()) } - /// Directory where the extracted `rustc-dev` component is stored. - fn ci_rustc_dir(&self, target: TargetSelection) -> PathBuf { - self.out.join(&*target.triple).join("ci-rustc") - } - /// Root output directory for LLVM compiled for `target` /// /// Note that if LLVM is configured externally then the directory returned diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index 0907291b54d..a34465ebffb 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -2348,7 +2348,7 @@ impl Step for Crate { // `std_cargo` actually does the wrong thing: it passes `--sysroot build/host/stage2`, // but we want to use the force-recompile std we just built in `build/host/stage2-test-sysroot`. // Override it. - if builder.download_rustc() { + if builder.download_rustc() && compiler.stage > 0 { let sysroot = builder .out .join(compiler.host.triple) diff --git a/src/ci/github-actions/ci.yml b/src/ci/github-actions/ci.yml index b5b478e60f4..55fd6cca85a 100644 --- a/src/ci/github-actions/ci.yml +++ b/src/ci/github-actions/ci.yml @@ -90,7 +90,7 @@ x--expand-yaml-anchors--remove: <<: *base-job - &job-macos-xl - os: macos-latest # We use the standard runner for now + os: macos-13 # We use the standard runner for now <<: *base-job - &job-windows-8c diff --git a/src/doc/book b/src/doc/book -Subproject 21cf840842bdf768a798869f06373c96c1cc512 +Subproject 668c64760b5c7ea654facb4ba5fe9faddfda27c diff --git a/src/doc/edition-guide b/src/doc/edition-guide -Subproject f63e578b92ff43e8cc38fcaa257b660f45c8a8c +Subproject 2751bdcef125468ea2ee006c11992cd1405aebe diff --git a/src/doc/embedded-book b/src/doc/embedded-book -Subproject f2aed2fe8e9f55508c86ba3aa4b6789b18a08a2 +Subproject 1e5556dd1b864109985d5871616ae6b9164bcea diff --git a/src/doc/nomicon b/src/doc/nomicon -Subproject c369e4b489332f8721fbae630354fa83385d457 +Subproject 302b995bcb24b70fd883980fd174738c3a10b70 diff --git a/src/doc/reference b/src/doc/reference -Subproject 5ca365eac678cb0d41a20b3204546d6ed70c717 +Subproject 1ea0178266b3f3f613b0fabdaf16a83961c99cd diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example -Subproject 57636d6926762861f34e030d52ca25a71e95e5b +Subproject 8a87926a985ce32ca1fad1be4008ee161a0b91e diff --git a/src/doc/rustc-dev-guide b/src/doc/rustc-dev-guide -Subproject 17fe3e948498c50e208047a750f17d6a8d89669 +Subproject b5a12d95e32ae53791cc6ab44417774667ed2ac diff --git a/src/doc/style-guide/src/expressions.md b/src/doc/style-guide/src/expressions.md index 143161da6cf..41a9eb82cb5 100644 --- a/src/doc/style-guide/src/expressions.md +++ b/src/doc/style-guide/src/expressions.md @@ -451,12 +451,11 @@ foo( #### Multi-line elements -If any element in a chain is formatted across multiple lines, then that element -and any later elements must be on their own line. Earlier elements may be kept -on a single line. E.g., +If any element in a chain is formatted across multiple lines, put that element +and any later elements on their own lines. ```rust -a.b.c()?.d +a.b.c()? .foo( an_expr, another_expr, @@ -803,6 +802,16 @@ foo(|param| { action(); foo(param) }) + +let x = combinable([ + an_expr, + another_expr, +]); + +let arr = [combinable( + an_expr, + another_expr, +)]; ``` Such behaviour should extend recursively, however, tools may choose to limit the diff --git a/src/librustdoc/formats/item_type.rs b/src/librustdoc/formats/item_type.rs index 452e14918fa..a3017201cb1 100644 --- a/src/librustdoc/formats/item_type.rs +++ b/src/librustdoc/formats/item_type.rs @@ -136,7 +136,6 @@ impl From<DefKind> for ItemType { | DefKind::AnonConst | DefKind::InlineConst | DefKind::OpaqueTy - | DefKind::ImplTraitPlaceholder | DefKind::Field | DefKind::LifetimeParam | DefKind::GlobalAsm diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 0dd9e590b9b..ca511d956b9 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -1860,8 +1860,8 @@ fn resolution_failure( } return; } - Trait | TyAlias | ForeignTy | OpaqueTy | ImplTraitPlaceholder - | TraitAlias | TyParam | Static(_) => "associated item", + Trait | TyAlias | ForeignTy | OpaqueTy | TraitAlias | TyParam + | Static(_) => "associated item", Impl { .. } | GlobalAsm => unreachable!("not a path"), } } else { diff --git a/src/tools/clippy/clippy_lints/src/declared_lints.rs b/src/tools/clippy/clippy_lints/src/declared_lints.rs index 9d9ee6ba307..b60f0738f64 100644 --- a/src/tools/clippy/clippy_lints/src/declared_lints.rs +++ b/src/tools/clippy/clippy_lints/src/declared_lints.rs @@ -171,7 +171,6 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::float_literal::LOSSY_FLOAT_LITERAL_INFO, crate::floating_point_arithmetic::IMPRECISE_FLOPS_INFO, crate::floating_point_arithmetic::SUBOPTIMAL_FLOPS_INFO, - crate::fn_null_check::FN_NULL_CHECK_INFO, crate::format::USELESS_FORMAT_INFO, crate::format_args::FORMAT_IN_FORMAT_ARGS_INFO, crate::format_args::TO_STRING_IN_FORMAT_ARGS_INFO, diff --git a/src/tools/clippy/clippy_lints/src/fn_null_check.rs b/src/tools/clippy/clippy_lints/src/fn_null_check.rs deleted file mode 100644 index 521045a9fed..00000000000 --- a/src/tools/clippy/clippy_lints/src/fn_null_check.rs +++ /dev/null @@ -1,102 +0,0 @@ -use clippy_utils::consts::{constant, Constant}; -use clippy_utils::diagnostics::span_lint_and_help; -use clippy_utils::{is_integer_literal, is_path_diagnostic_item}; -use rustc_hir::{BinOpKind, Expr, ExprKind, TyKind}; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::sym; - -declare_clippy_lint! { - /// ### What it does - /// Checks for comparing a function pointer to null. - /// - /// ### Why is this bad? - /// Function pointers are assumed to not be null. - /// - /// ### Example - /// ```rust,ignore - /// let fn_ptr: fn() = /* somehow obtained nullable function pointer */ - /// - /// if (fn_ptr as *const ()).is_null() { ... } - /// ``` - /// Use instead: - /// ```rust,ignore - /// let fn_ptr: Option<fn()> = /* somehow obtained nullable function pointer */ - /// - /// if fn_ptr.is_none() { ... } - /// ``` - #[clippy::version = "1.68.0"] - pub FN_NULL_CHECK, - correctness, - "`fn()` type assumed to be nullable" -} -declare_lint_pass!(FnNullCheck => [FN_NULL_CHECK]); - -fn lint_expr(cx: &LateContext<'_>, expr: &Expr<'_>) { - span_lint_and_help( - cx, - FN_NULL_CHECK, - expr.span, - "function pointer assumed to be nullable, even though it isn't", - None, - "try wrapping your function pointer type in `Option<T>` instead, and using `is_none` to check for null pointer value", - ); -} - -fn is_fn_ptr_cast(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { - if let ExprKind::Cast(cast_expr, cast_ty) = expr.kind - && let TyKind::Ptr(_) = cast_ty.kind - { - cx.typeck_results().expr_ty_adjusted(cast_expr).is_fn() - } else { - false - } -} - -impl<'tcx> LateLintPass<'tcx> for FnNullCheck { - fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - match expr.kind { - // Catching: - // (fn_ptr as *<const/mut> <ty>).is_null() - ExprKind::MethodCall(method_name, receiver, _, _) - if method_name.ident.as_str() == "is_null" && is_fn_ptr_cast(cx, receiver) => - { - lint_expr(cx, expr); - }, - - ExprKind::Binary(op, left, right) if matches!(op.node, BinOpKind::Eq) => { - let to_check: &Expr<'_>; - if is_fn_ptr_cast(cx, left) { - to_check = right; - } else if is_fn_ptr_cast(cx, right) { - to_check = left; - } else { - return; - } - - match to_check.kind { - // Catching: - // (fn_ptr as *<const/mut> <ty>) == (0 as <ty>) - ExprKind::Cast(cast_expr, _) if is_integer_literal(cast_expr, 0) => { - lint_expr(cx, expr); - }, - - // Catching: - // (fn_ptr as *<const/mut> <ty>) == std::ptr::null() - ExprKind::Call(func, []) if is_path_diagnostic_item(cx, func, sym::ptr_null) => { - lint_expr(cx, expr); - }, - - // Catching: - // (fn_ptr as *<const/mut> <ty>) == <const that evaluates to null_ptr> - _ if matches!(constant(cx, cx.typeck_results(), to_check), Some(Constant::RawPtr(0))) => { - lint_expr(cx, expr); - }, - - _ => {}, - } - }, - _ => {}, - } - } -} diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs index 87329ee5e14..365cc4c59ad 100644 --- a/src/tools/clippy/clippy_lints/src/lib.rs +++ b/src/tools/clippy/clippy_lints/src/lib.rs @@ -131,7 +131,6 @@ mod extra_unused_type_parameters; mod fallible_impl_from; mod float_literal; mod floating_point_arithmetic; -mod fn_null_check; mod format; mod format_args; mod format_impl; @@ -1003,7 +1002,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: semicolon_outside_block_ignore_multiline, )) }); - store.register_late_pass(|_| Box::new(fn_null_check::FnNullCheck)); store.register_late_pass(|_| Box::new(permissions_set_readonly_false::PermissionsSetReadonlyFalse)); store.register_late_pass(|_| Box::new(size_of_ref::SizeOfRef)); store.register_late_pass(|_| Box::new(multiple_unsafe_ops_per_block::MultipleUnsafeOpsPerBlock)); diff --git a/src/tools/clippy/clippy_lints/src/renamed_lints.rs b/src/tools/clippy/clippy_lints/src/renamed_lints.rs index cbcd11debfd..d24215c2292 100644 --- a/src/tools/clippy/clippy_lints/src/renamed_lints.rs +++ b/src/tools/clippy/clippy_lints/src/renamed_lints.rs @@ -42,6 +42,7 @@ pub static RENAMED_LINTS: &[(&str, &str)] = &[ ("clippy::for_loops_over_fallibles", "for_loops_over_fallibles"), ("clippy::forget_copy", "forgetting_copy_types"), ("clippy::forget_ref", "forgetting_references"), + ("clippy::fn_null_check", "incorrect_fn_null_checks"), ("clippy::into_iter_on_array", "array_into_iter"), ("clippy::invalid_atomic_ordering", "invalid_atomic_ordering"), ("clippy::invalid_ref", "invalid_value"), diff --git a/src/tools/clippy/tests/ui/empty_line_after_doc_comments.rs b/src/tools/clippy/tests/ui/empty_line_after_doc_comments.rs index 83db2a07d33..cc36ce5f487 100644 --- a/src/tools/clippy/tests/ui/empty_line_after_doc_comments.rs +++ b/src/tools/clippy/tests/ui/empty_line_after_doc_comments.rs @@ -1,4 +1,7 @@ //@aux-build:proc_macro_attr.rs:proc-macro +// Flaky test, see https://github.com/rust-lang/rust/issues/113585. +//@ignore-32bit +//@ignore-64bit #![warn(clippy::empty_line_after_doc_comments)] #![allow(clippy::assertions_on_constants)] #![feature(custom_inner_attributes)] diff --git a/src/tools/clippy/tests/ui/empty_line_after_outer_attribute.rs b/src/tools/clippy/tests/ui/empty_line_after_outer_attribute.rs index b2d7ddae427..bc54e0fd2de 100644 --- a/src/tools/clippy/tests/ui/empty_line_after_outer_attribute.rs +++ b/src/tools/clippy/tests/ui/empty_line_after_outer_attribute.rs @@ -1,4 +1,7 @@ //@aux-build:proc_macro_attr.rs:proc-macro +// Flaky test, see https://github.com/rust-lang/rust/issues/113585. +//@ignore-32bit +//@ignore-64bit #![warn(clippy::empty_line_after_outer_attr)] #![allow(clippy::assertions_on_constants)] #![feature(custom_inner_attributes)] diff --git a/src/tools/clippy/tests/ui/fn_null_check.rs b/src/tools/clippy/tests/ui/fn_null_check.rs deleted file mode 100644 index dfdea100c8f..00000000000 --- a/src/tools/clippy/tests/ui/fn_null_check.rs +++ /dev/null @@ -1,22 +0,0 @@ -#![allow(unused)] -#![warn(clippy::fn_null_check)] -#![allow(clippy::cmp_null)] -#![allow(clippy::needless_if)] -#![allow(clippy::ptr_eq)] -#![allow(clippy::zero_ptr)] - -pub const ZPTR: *const () = 0 as *const _; -pub const NOT_ZPTR: *const () = 1 as *const _; - -fn main() { - let fn_ptr = main; - - if (fn_ptr as *mut ()).is_null() {} - if (fn_ptr as *const u8).is_null() {} - if (fn_ptr as *const ()) == std::ptr::null() {} - if (fn_ptr as *const ()) == (0 as *const ()) {} - if (fn_ptr as *const ()) == ZPTR {} - - // no lint - if (fn_ptr as *const ()) == NOT_ZPTR {} -} diff --git a/src/tools/clippy/tests/ui/fn_null_check.stderr b/src/tools/clippy/tests/ui/fn_null_check.stderr deleted file mode 100644 index 5b9f48a961c..00000000000 --- a/src/tools/clippy/tests/ui/fn_null_check.stderr +++ /dev/null @@ -1,43 +0,0 @@ -error: function pointer assumed to be nullable, even though it isn't - --> $DIR/fn_null_check.rs:14:8 - | -LL | if (fn_ptr as *mut ()).is_null() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: try wrapping your function pointer type in `Option<T>` instead, and using `is_none` to check for null pointer value - = note: `-D clippy::fn-null-check` implied by `-D warnings` - -error: function pointer assumed to be nullable, even though it isn't - --> $DIR/fn_null_check.rs:15:8 - | -LL | if (fn_ptr as *const u8).is_null() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: try wrapping your function pointer type in `Option<T>` instead, and using `is_none` to check for null pointer value - -error: function pointer assumed to be nullable, even though it isn't - --> $DIR/fn_null_check.rs:16:8 - | -LL | if (fn_ptr as *const ()) == std::ptr::null() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: try wrapping your function pointer type in `Option<T>` instead, and using `is_none` to check for null pointer value - -error: function pointer assumed to be nullable, even though it isn't - --> $DIR/fn_null_check.rs:17:8 - | -LL | if (fn_ptr as *const ()) == (0 as *const ()) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: try wrapping your function pointer type in `Option<T>` instead, and using `is_none` to check for null pointer value - -error: function pointer assumed to be nullable, even though it isn't - --> $DIR/fn_null_check.rs:18:8 - | -LL | if (fn_ptr as *const ()) == ZPTR {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: try wrapping your function pointer type in `Option<T>` instead, and using `is_none` to check for null pointer value - -error: aborting due to 5 previous errors - diff --git a/src/tools/clippy/tests/ui/needless_arbitrary_self_type_unfixable.rs b/src/tools/clippy/tests/ui/needless_arbitrary_self_type_unfixable.rs index 876f16a3854..321aa69a1a5 100644 --- a/src/tools/clippy/tests/ui/needless_arbitrary_self_type_unfixable.rs +++ b/src/tools/clippy/tests/ui/needless_arbitrary_self_type_unfixable.rs @@ -1,4 +1,7 @@ //@aux-build:proc_macro_attr.rs:proc-macro +// Flaky test, see https://github.com/rust-lang/rust/issues/113585. +//@ignore-32bit +//@ignore-64bit #![warn(clippy::needless_arbitrary_self_type)] diff --git a/src/tools/clippy/tests/ui/rename.fixed b/src/tools/clippy/tests/ui/rename.fixed index b24c83d9a0d..cab02bb93c9 100644 --- a/src/tools/clippy/tests/ui/rename.fixed +++ b/src/tools/clippy/tests/ui/rename.fixed @@ -37,6 +37,7 @@ #![allow(for_loops_over_fallibles)] #![allow(forgetting_copy_types)] #![allow(forgetting_references)] +#![allow(incorrect_fn_null_checks)] #![allow(array_into_iter)] #![allow(invalid_atomic_ordering)] #![allow(invalid_value)] @@ -89,6 +90,7 @@ #![warn(for_loops_over_fallibles)] #![warn(forgetting_copy_types)] #![warn(forgetting_references)] +#![warn(incorrect_fn_null_checks)] #![warn(array_into_iter)] #![warn(invalid_atomic_ordering)] #![warn(invalid_value)] diff --git a/src/tools/clippy/tests/ui/rename.rs b/src/tools/clippy/tests/ui/rename.rs index baa6345a64f..e5e31452149 100644 --- a/src/tools/clippy/tests/ui/rename.rs +++ b/src/tools/clippy/tests/ui/rename.rs @@ -37,6 +37,7 @@ #![allow(for_loops_over_fallibles)] #![allow(forgetting_copy_types)] #![allow(forgetting_references)] +#![allow(incorrect_fn_null_checks)] #![allow(array_into_iter)] #![allow(invalid_atomic_ordering)] #![allow(invalid_value)] @@ -89,6 +90,7 @@ #![warn(clippy::for_loops_over_fallibles)] #![warn(clippy::forget_copy)] #![warn(clippy::forget_ref)] +#![warn(clippy::fn_null_check)] #![warn(clippy::into_iter_on_array)] #![warn(clippy::invalid_atomic_ordering)] #![warn(clippy::invalid_ref)] diff --git a/src/tools/clippy/tests/ui/rename.stderr b/src/tools/clippy/tests/ui/rename.stderr index ae25c3b46bd..783608a0841 100644 --- a/src/tools/clippy/tests/ui/rename.stderr +++ b/src/tools/clippy/tests/ui/rename.stderr @@ -1,5 +1,5 @@ error: lint `clippy::almost_complete_letter_range` has been renamed to `clippy::almost_complete_range` - --> $DIR/rename.rs:52:9 + --> $DIR/rename.rs:53:9 | LL | #![warn(clippy::almost_complete_letter_range)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::almost_complete_range` @@ -7,310 +7,316 @@ LL | #![warn(clippy::almost_complete_letter_range)] = note: `-D renamed-and-removed-lints` implied by `-D warnings` error: lint `clippy::blacklisted_name` has been renamed to `clippy::disallowed_names` - --> $DIR/rename.rs:53:9 + --> $DIR/rename.rs:54:9 | LL | #![warn(clippy::blacklisted_name)] | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_names` error: lint `clippy::block_in_if_condition_expr` has been renamed to `clippy::blocks_in_if_conditions` - --> $DIR/rename.rs:54:9 + --> $DIR/rename.rs:55:9 | LL | #![warn(clippy::block_in_if_condition_expr)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_if_conditions` error: lint `clippy::block_in_if_condition_stmt` has been renamed to `clippy::blocks_in_if_conditions` - --> $DIR/rename.rs:55:9 + --> $DIR/rename.rs:56:9 | LL | #![warn(clippy::block_in_if_condition_stmt)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_if_conditions` error: lint `clippy::box_vec` has been renamed to `clippy::box_collection` - --> $DIR/rename.rs:56:9 + --> $DIR/rename.rs:57:9 | LL | #![warn(clippy::box_vec)] | ^^^^^^^^^^^^^^^ help: use the new name: `clippy::box_collection` error: lint `clippy::const_static_lifetime` has been renamed to `clippy::redundant_static_lifetimes` - --> $DIR/rename.rs:57:9 + --> $DIR/rename.rs:58:9 | LL | #![warn(clippy::const_static_lifetime)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::redundant_static_lifetimes` error: lint `clippy::cyclomatic_complexity` has been renamed to `clippy::cognitive_complexity` - --> $DIR/rename.rs:58:9 + --> $DIR/rename.rs:59:9 | LL | #![warn(clippy::cyclomatic_complexity)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::cognitive_complexity` error: lint `clippy::derive_hash_xor_eq` has been renamed to `clippy::derived_hash_with_manual_eq` - --> $DIR/rename.rs:59:9 + --> $DIR/rename.rs:60:9 | LL | #![warn(clippy::derive_hash_xor_eq)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::derived_hash_with_manual_eq` error: lint `clippy::disallowed_method` has been renamed to `clippy::disallowed_methods` - --> $DIR/rename.rs:60:9 + --> $DIR/rename.rs:61:9 | LL | #![warn(clippy::disallowed_method)] | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_methods` error: lint `clippy::disallowed_type` has been renamed to `clippy::disallowed_types` - --> $DIR/rename.rs:61:9 + --> $DIR/rename.rs:62:9 | LL | #![warn(clippy::disallowed_type)] | ^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_types` error: lint `clippy::eval_order_dependence` has been renamed to `clippy::mixed_read_write_in_expression` - --> $DIR/rename.rs:62:9 + --> $DIR/rename.rs:63:9 | LL | #![warn(clippy::eval_order_dependence)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::mixed_read_write_in_expression` error: lint `clippy::identity_conversion` has been renamed to `clippy::useless_conversion` - --> $DIR/rename.rs:63:9 + --> $DIR/rename.rs:64:9 | LL | #![warn(clippy::identity_conversion)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::useless_conversion` error: lint `clippy::if_let_some_result` has been renamed to `clippy::match_result_ok` - --> $DIR/rename.rs:64:9 + --> $DIR/rename.rs:65:9 | LL | #![warn(clippy::if_let_some_result)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::match_result_ok` error: lint `clippy::integer_arithmetic` has been renamed to `clippy::arithmetic_side_effects` - --> $DIR/rename.rs:65:9 + --> $DIR/rename.rs:66:9 | LL | #![warn(clippy::integer_arithmetic)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::arithmetic_side_effects` error: lint `clippy::logic_bug` has been renamed to `clippy::overly_complex_bool_expr` - --> $DIR/rename.rs:66:9 + --> $DIR/rename.rs:67:9 | LL | #![warn(clippy::logic_bug)] | ^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::overly_complex_bool_expr` error: lint `clippy::new_without_default_derive` has been renamed to `clippy::new_without_default` - --> $DIR/rename.rs:67:9 + --> $DIR/rename.rs:68:9 | LL | #![warn(clippy::new_without_default_derive)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::new_without_default` error: lint `clippy::option_and_then_some` has been renamed to `clippy::bind_instead_of_map` - --> $DIR/rename.rs:68:9 + --> $DIR/rename.rs:69:9 | LL | #![warn(clippy::option_and_then_some)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::bind_instead_of_map` error: lint `clippy::option_expect_used` has been renamed to `clippy::expect_used` - --> $DIR/rename.rs:69:9 + --> $DIR/rename.rs:70:9 | LL | #![warn(clippy::option_expect_used)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used` error: lint `clippy::option_map_unwrap_or` has been renamed to `clippy::map_unwrap_or` - --> $DIR/rename.rs:70:9 + --> $DIR/rename.rs:71:9 | LL | #![warn(clippy::option_map_unwrap_or)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or` error: lint `clippy::option_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or` - --> $DIR/rename.rs:71:9 + --> $DIR/rename.rs:72:9 | LL | #![warn(clippy::option_map_unwrap_or_else)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or` error: lint `clippy::option_unwrap_used` has been renamed to `clippy::unwrap_used` - --> $DIR/rename.rs:72:9 + --> $DIR/rename.rs:73:9 | LL | #![warn(clippy::option_unwrap_used)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used` error: lint `clippy::ref_in_deref` has been renamed to `clippy::needless_borrow` - --> $DIR/rename.rs:73:9 + --> $DIR/rename.rs:74:9 | LL | #![warn(clippy::ref_in_deref)] | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::needless_borrow` error: lint `clippy::result_expect_used` has been renamed to `clippy::expect_used` - --> $DIR/rename.rs:74:9 + --> $DIR/rename.rs:75:9 | LL | #![warn(clippy::result_expect_used)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used` error: lint `clippy::result_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or` - --> $DIR/rename.rs:75:9 + --> $DIR/rename.rs:76:9 | LL | #![warn(clippy::result_map_unwrap_or_else)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or` error: lint `clippy::result_unwrap_used` has been renamed to `clippy::unwrap_used` - --> $DIR/rename.rs:76:9 + --> $DIR/rename.rs:77:9 | LL | #![warn(clippy::result_unwrap_used)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used` error: lint `clippy::single_char_push_str` has been renamed to `clippy::single_char_add_str` - --> $DIR/rename.rs:77:9 + --> $DIR/rename.rs:78:9 | LL | #![warn(clippy::single_char_push_str)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::single_char_add_str` error: lint `clippy::stutter` has been renamed to `clippy::module_name_repetitions` - --> $DIR/rename.rs:78:9 + --> $DIR/rename.rs:79:9 | LL | #![warn(clippy::stutter)] | ^^^^^^^^^^^^^^^ help: use the new name: `clippy::module_name_repetitions` error: lint `clippy::to_string_in_display` has been renamed to `clippy::recursive_format_impl` - --> $DIR/rename.rs:79:9 + --> $DIR/rename.rs:80:9 | LL | #![warn(clippy::to_string_in_display)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::recursive_format_impl` error: lint `clippy::zero_width_space` has been renamed to `clippy::invisible_characters` - --> $DIR/rename.rs:80:9 + --> $DIR/rename.rs:81:9 | LL | #![warn(clippy::zero_width_space)] | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::invisible_characters` error: lint `clippy::cast_ref_to_mut` has been renamed to `cast_ref_to_mut` - --> $DIR/rename.rs:81:9 + --> $DIR/rename.rs:82:9 | LL | #![warn(clippy::cast_ref_to_mut)] | ^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `cast_ref_to_mut` error: lint `clippy::clone_double_ref` has been renamed to `suspicious_double_ref_op` - --> $DIR/rename.rs:82:9 + --> $DIR/rename.rs:83:9 | LL | #![warn(clippy::clone_double_ref)] | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `suspicious_double_ref_op` error: lint `clippy::cmp_nan` has been renamed to `invalid_nan_comparisons` - --> $DIR/rename.rs:83:9 + --> $DIR/rename.rs:84:9 | LL | #![warn(clippy::cmp_nan)] | ^^^^^^^^^^^^^^^ help: use the new name: `invalid_nan_comparisons` error: lint `clippy::drop_bounds` has been renamed to `drop_bounds` - --> $DIR/rename.rs:84:9 + --> $DIR/rename.rs:85:9 | LL | #![warn(clippy::drop_bounds)] | ^^^^^^^^^^^^^^^^^^^ help: use the new name: `drop_bounds` error: lint `clippy::drop_copy` has been renamed to `dropping_copy_types` - --> $DIR/rename.rs:85:9 + --> $DIR/rename.rs:86:9 | LL | #![warn(clippy::drop_copy)] | ^^^^^^^^^^^^^^^^^ help: use the new name: `dropping_copy_types` error: lint `clippy::drop_ref` has been renamed to `dropping_references` - --> $DIR/rename.rs:86:9 + --> $DIR/rename.rs:87:9 | LL | #![warn(clippy::drop_ref)] | ^^^^^^^^^^^^^^^^ help: use the new name: `dropping_references` error: lint `clippy::for_loop_over_option` has been renamed to `for_loops_over_fallibles` - --> $DIR/rename.rs:87:9 + --> $DIR/rename.rs:88:9 | LL | #![warn(clippy::for_loop_over_option)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles` error: lint `clippy::for_loop_over_result` has been renamed to `for_loops_over_fallibles` - --> $DIR/rename.rs:88:9 + --> $DIR/rename.rs:89:9 | LL | #![warn(clippy::for_loop_over_result)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles` error: lint `clippy::for_loops_over_fallibles` has been renamed to `for_loops_over_fallibles` - --> $DIR/rename.rs:89:9 + --> $DIR/rename.rs:90:9 | LL | #![warn(clippy::for_loops_over_fallibles)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles` error: lint `clippy::forget_copy` has been renamed to `forgetting_copy_types` - --> $DIR/rename.rs:90:9 + --> $DIR/rename.rs:91:9 | LL | #![warn(clippy::forget_copy)] | ^^^^^^^^^^^^^^^^^^^ help: use the new name: `forgetting_copy_types` error: lint `clippy::forget_ref` has been renamed to `forgetting_references` - --> $DIR/rename.rs:91:9 + --> $DIR/rename.rs:92:9 | LL | #![warn(clippy::forget_ref)] | ^^^^^^^^^^^^^^^^^^ help: use the new name: `forgetting_references` +error: lint `clippy::fn_null_check` has been renamed to `incorrect_fn_null_checks` + --> $DIR/rename.rs:93:9 + | +LL | #![warn(clippy::fn_null_check)] + | ^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `incorrect_fn_null_checks` + error: lint `clippy::into_iter_on_array` has been renamed to `array_into_iter` - --> $DIR/rename.rs:92:9 + --> $DIR/rename.rs:94:9 | LL | #![warn(clippy::into_iter_on_array)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `array_into_iter` error: lint `clippy::invalid_atomic_ordering` has been renamed to `invalid_atomic_ordering` - --> $DIR/rename.rs:93:9 + --> $DIR/rename.rs:95:9 | LL | #![warn(clippy::invalid_atomic_ordering)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_atomic_ordering` error: lint `clippy::invalid_ref` has been renamed to `invalid_value` - --> $DIR/rename.rs:94:9 + --> $DIR/rename.rs:96:9 | LL | #![warn(clippy::invalid_ref)] | ^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_value` error: lint `clippy::invalid_utf8_in_unchecked` has been renamed to `invalid_from_utf8_unchecked` - --> $DIR/rename.rs:95:9 + --> $DIR/rename.rs:97:9 | LL | #![warn(clippy::invalid_utf8_in_unchecked)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_from_utf8_unchecked` error: lint `clippy::let_underscore_drop` has been renamed to `let_underscore_drop` - --> $DIR/rename.rs:96:9 + --> $DIR/rename.rs:98:9 | LL | #![warn(clippy::let_underscore_drop)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `let_underscore_drop` error: lint `clippy::mem_discriminant_non_enum` has been renamed to `enum_intrinsics_non_enums` - --> $DIR/rename.rs:97:9 + --> $DIR/rename.rs:99:9 | LL | #![warn(clippy::mem_discriminant_non_enum)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `enum_intrinsics_non_enums` error: lint `clippy::panic_params` has been renamed to `non_fmt_panics` - --> $DIR/rename.rs:98:9 + --> $DIR/rename.rs:100:9 | LL | #![warn(clippy::panic_params)] | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `non_fmt_panics` error: lint `clippy::positional_named_format_parameters` has been renamed to `named_arguments_used_positionally` - --> $DIR/rename.rs:99:9 + --> $DIR/rename.rs:101:9 | LL | #![warn(clippy::positional_named_format_parameters)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `named_arguments_used_positionally` error: lint `clippy::temporary_cstring_as_ptr` has been renamed to `temporary_cstring_as_ptr` - --> $DIR/rename.rs:100:9 + --> $DIR/rename.rs:102:9 | LL | #![warn(clippy::temporary_cstring_as_ptr)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `temporary_cstring_as_ptr` error: lint `clippy::undropped_manually_drops` has been renamed to `undropped_manually_drops` - --> $DIR/rename.rs:101:9 + --> $DIR/rename.rs:103:9 | LL | #![warn(clippy::undropped_manually_drops)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `undropped_manually_drops` error: lint `clippy::unknown_clippy_lints` has been renamed to `unknown_lints` - --> $DIR/rename.rs:102:9 + --> $DIR/rename.rs:104:9 | LL | #![warn(clippy::unknown_clippy_lints)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unknown_lints` error: lint `clippy::unused_label` has been renamed to `unused_labels` - --> $DIR/rename.rs:103:9 + --> $DIR/rename.rs:105:9 | LL | #![warn(clippy::unused_label)] | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unused_labels` -error: aborting due to 52 previous errors +error: aborting due to 53 previous errors diff --git a/src/tools/lint-docs/src/groups.rs b/src/tools/lint-docs/src/groups.rs index b11fb287cf4..5be8ef7996b 100644 --- a/src/tools/lint-docs/src/groups.rs +++ b/src/tools/lint-docs/src/groups.rs @@ -39,7 +39,6 @@ impl<'a> LintExtractor<'a> { fn collect_groups(&self) -> Result<LintGroups, Box<dyn Error>> { let mut result = BTreeMap::new(); let mut cmd = Command::new(self.rustc_path); - cmd.env_remove("LD_LIBRARY_PATH"); cmd.arg("-Whelp"); let output = cmd.output().map_err(|e| format!("failed to run command {:?}\n{}", cmd, e))?; if !output.status.success() { diff --git a/src/tools/lint-docs/src/lib.rs b/src/tools/lint-docs/src/lib.rs index fe29b9abda3..b7c8b9ed2e3 100644 --- a/src/tools/lint-docs/src/lib.rs +++ b/src/tools/lint-docs/src/lib.rs @@ -403,12 +403,6 @@ impl<'a> LintExtractor<'a> { fs::write(&tempfile, source) .map_err(|e| format!("failed to write {}: {}", tempfile.display(), e))?; let mut cmd = Command::new(self.rustc_path); - // NOTE: bootstrap sets `LD_LIBRARY_PATH` for building lint-docs itself. - // Unfortunately, lint-docs is a bootstrap tool while rustc is built from source, - // and sometimes the paths conflict. In particular, when using `download-rustc`, - // the LLVM versions can differ between `ci-llvm` and `ci-rustc-sysroot`. - // Unset LD_LIBRARY_PATH here so it doesn't interfere with running the compiler. - cmd.env_remove("LD_LIBRARY_PATH"); if options.contains(&"edition2015") { cmd.arg("--edition=2015"); } else { diff --git a/src/tools/miri/src/borrow_tracker/mod.rs b/src/tools/miri/src/borrow_tracker/mod.rs index faa23fd2620..a2cf7c80950 100644 --- a/src/tools/miri/src/borrow_tracker/mod.rs +++ b/src/tools/miri/src/borrow_tracker/mod.rs @@ -302,12 +302,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { } } - fn retag_return_place(&mut self) -> InterpResult<'tcx> { + fn protect_place(&mut self, place: &MPlaceTy<'tcx, Provenance>) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let method = this.machine.borrow_tracker.as_ref().unwrap().borrow().borrow_tracker_method; match method { - BorrowTrackerMethod::StackedBorrows => this.sb_retag_return_place(), - BorrowTrackerMethod::TreeBorrows => this.tb_retag_return_place(), + BorrowTrackerMethod::StackedBorrows => this.sb_protect_place(place), + BorrowTrackerMethod::TreeBorrows => this.tb_protect_place(place), } } diff --git a/src/tools/miri/src/borrow_tracker/stacked_borrows/diagnostics.rs b/src/tools/miri/src/borrow_tracker/stacked_borrows/diagnostics.rs index de307a3c5f5..5ec8d80fb32 100644 --- a/src/tools/miri/src/borrow_tracker/stacked_borrows/diagnostics.rs +++ b/src/tools/miri/src/borrow_tracker/stacked_borrows/diagnostics.rs @@ -189,7 +189,7 @@ struct RetagOp { #[derive(Debug, Clone, Copy, PartialEq)] pub enum RetagCause { Normal, - FnReturnPlace, + InPlaceFnPassing, FnEntry, TwoPhase, } @@ -501,7 +501,7 @@ impl RetagCause { match self { RetagCause::Normal => "retag", RetagCause::FnEntry => "function-entry retag", - RetagCause::FnReturnPlace => "return-place retag", + RetagCause::InPlaceFnPassing => "in-place function argument/return passing protection", RetagCause::TwoPhase => "two-phase retag", } .to_string() 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 ca0f69450c9..e22b352e740 100644 --- a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs +++ b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs @@ -994,35 +994,25 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { } } - /// After a stack frame got pushed, retag the return place so that we are sure - /// it does not alias with anything. - /// - /// This is a HACK because there is nothing in MIR that would make the retag - /// explicit. Also see <https://github.com/rust-lang/rust/issues/71117>. - fn sb_retag_return_place(&mut self) -> InterpResult<'tcx> { + /// Protect a place so that it cannot be used any more for the duration of the current function + /// call. + /// + /// This is used to ensure soundness of in-place function argument/return passing. + fn sb_protect_place(&mut self, place: &MPlaceTy<'tcx, Provenance>) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - let return_place = &this.frame().return_place; - if return_place.layout.is_zst() { - // There may not be any memory here, nothing to do. - return Ok(()); - } - // We need this to be in-memory to use tagged pointers. - let return_place = this.force_allocation(&return_place.clone())?; - // We have to turn the place into a pointer to use the existing code. + // We have to turn the place into a pointer to use the usual retagging logic. // (The pointer type does not matter, so we use a raw pointer.) - let ptr_layout = this.layout_of(Ty::new_mut_ptr(this.tcx.tcx, return_place.layout.ty))?; - let val = ImmTy::from_immediate(return_place.to_ref(this), ptr_layout); - // Reborrow it. With protection! That is part of the point. + let ptr_layout = this.layout_of(Ty::new_mut_ptr(this.tcx.tcx, place.layout.ty))?; + let ptr = ImmTy::from_immediate(place.to_ref(this), ptr_layout); + // Reborrow it. With protection! That is the entire point. let new_perm = NewPermission::Uniform { perm: Permission::Unique, access: Some(AccessKind::Write), protector: Some(ProtectorKind::StrongProtector), }; - let val = this.sb_retag_reference(&val, new_perm, RetagCause::FnReturnPlace)?; - // And use reborrowed pointer for return place. - let return_place = this.ref_to_mplace(&val)?; - this.frame_mut().return_place = return_place.into(); + let _new_ptr = this.sb_retag_reference(&ptr, new_perm, RetagCause::InPlaceFnPassing)?; + // We just throw away `new_ptr`, so nobody can access this memory while it is protected. Ok(()) } diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs index 3bb38a249ff..274a4a0aaba 100644 --- a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs +++ b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs @@ -178,7 +178,7 @@ trait EvalContextPrivExt<'mir: 'ecx, 'tcx: 'mir, 'ecx>: crate::MiriInterpCxExt<' &mut self, place: &MPlaceTy<'tcx, Provenance>, // parent tag extracted from here ptr_size: Size, - new_perm: Option<NewPermission>, + new_perm: NewPermission, new_tag: BorTag, ) -> InterpResult<'tcx, Option<(AllocId, BorTag)>> { let this = self.eval_context_mut(); @@ -256,10 +256,6 @@ trait EvalContextPrivExt<'mir: 'ecx, 'tcx: 'mir, 'ecx>: crate::MiriInterpCxExt<' ptr_size.bytes() ); - let Some(new_perm) = new_perm else { - return Ok(Some((alloc_id, orig_tag))); - }; - if let Some(protect) = new_perm.protector { // We register the protection in two different places. // This makes creating a protector slower, but checking whether a tag @@ -305,7 +301,7 @@ trait EvalContextPrivExt<'mir: 'ecx, 'tcx: 'mir, 'ecx>: crate::MiriInterpCxExt<' fn tb_retag_reference( &mut self, val: &ImmTy<'tcx, Provenance>, - new_perm: Option<NewPermission>, + new_perm: NewPermission, ) -> InterpResult<'tcx, ImmTy<'tcx, Provenance>> { let this = self.eval_context_mut(); // We want a place for where the ptr *points to*, so we get one. @@ -317,7 +313,7 @@ trait EvalContextPrivExt<'mir: 'ecx, 'tcx: 'mir, 'ecx>: crate::MiriInterpCxExt<' // - if the pointer is not reborrowed (raw pointer) or if `zero_size` is set // then we override the size to do a zero-length reborrow. let reborrow_size = match new_perm { - Some(NewPermission { zero_size: false, .. }) => + NewPermission { zero_size: false, .. } => this.size_and_align_of_mplace(&place)? .map(|(size, _)| size) .unwrap_or(place.layout.size), @@ -374,7 +370,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { NewPermission::from_ref_ty(pointee, mutability, kind, this), _ => None, }; - this.tb_retag_reference(val, new_perm) + if let Some(new_perm) = new_perm { + this.tb_retag_reference(val, new_perm) + } else { + Ok(val.clone()) + } } /// Retag all pointers that are stored in this place. @@ -405,9 +405,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { place: &PlaceTy<'tcx, Provenance>, new_perm: Option<NewPermission>, ) -> InterpResult<'tcx> { - let val = self.ecx.read_immediate(&self.ecx.place_to_op(place)?)?; - let val = self.ecx.tb_retag_reference(&val, new_perm)?; - self.ecx.write_immediate(*val, place)?; + if let Some(new_perm) = new_perm { + let val = self.ecx.read_immediate(&self.ecx.place_to_op(place)?)?; + let val = self.ecx.tb_retag_reference(&val, new_perm)?; + self.ecx.write_immediate(*val, place)?; + } Ok(()) } } @@ -493,36 +495,25 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { } } - /// After a stack frame got pushed, retag the return place so that we are sure - /// it does not alias with anything. - /// - /// This is a HACK because there is nothing in MIR that would make the retag - /// explicit. Also see <https://github.com/rust-lang/rust/issues/71117>. - fn tb_retag_return_place(&mut self) -> InterpResult<'tcx> { + /// Protect a place so that it cannot be used any more for the duration of the current function + /// call. + /// + /// This is used to ensure soundness of in-place function argument/return passing. + fn tb_protect_place(&mut self, place: &MPlaceTy<'tcx, Provenance>) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - //this.debug_hint_location(); - let return_place = &this.frame().return_place; - if return_place.layout.is_zst() { - // There may not be any memory here, nothing to do. - return Ok(()); - } - // We need this to be in-memory to use tagged pointers. - let return_place = this.force_allocation(&return_place.clone())?; - // We have to turn the place into a pointer to use the existing code. + // We have to turn the place into a pointer to use the usual retagging logic. // (The pointer type does not matter, so we use a raw pointer.) - let ptr_layout = this.layout_of(Ty::new_mut_ptr(this.tcx.tcx, return_place.layout.ty))?; - let val = ImmTy::from_immediate(return_place.to_ref(this), ptr_layout); - // Reborrow it. With protection! That is part of the point. - let new_perm = Some(NewPermission { + let ptr_layout = this.layout_of(Ty::new_mut_ptr(this.tcx.tcx, place.layout.ty))?; + let ptr = ImmTy::from_immediate(place.to_ref(this), ptr_layout); + // Reborrow it. With protection! That is the entire point. + let new_perm = NewPermission { initial_state: Permission::new_active(), zero_size: false, protector: Some(ProtectorKind::StrongProtector), - }); - let val = this.tb_retag_reference(&val, new_perm)?; - // And use reborrowed pointer for return place. - let return_place = this.ref_to_mplace(&val)?; - this.frame_mut().return_place = return_place.into(); + }; + let _new_ptr = this.tb_retag_reference(&ptr, new_perm)?; + // We just throw away `new_ptr`, so nobody can access this memory while it is protected. Ok(()) } diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs index 7e92dc7a0c7..4a093d7bcc6 100644 --- a/src/tools/miri/src/lib.rs +++ b/src/tools/miri/src/lib.rs @@ -55,6 +55,7 @@ extern crate rustc_index; extern crate rustc_session; extern crate rustc_span; extern crate rustc_target; +extern crate either; // the one from rustc // Necessary to pull in object code as the rest of the rustc crates are shipped only as rmeta // files. diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs index ac2bad22119..5510e3f94b7 100644 --- a/src/tools/miri/src/machine.rs +++ b/src/tools/miri/src/machine.rs @@ -7,6 +7,7 @@ use std::fmt; use std::path::Path; use std::process; +use either::Either; use rand::rngs::StdRng; use rand::SeedableRng; @@ -533,7 +534,7 @@ impl<'mir, 'tcx> MiriMachine<'mir, 'tcx> { let target = &tcx.sess.target; match target.arch.as_ref() { "wasm32" | "wasm64" => 64 * 1024, // https://webassembly.github.io/spec/core/exec/runtime.html#memory-instances - "aarch64" => + "aarch64" => { if target.options.vendor.as_ref() == "apple" { // No "definitive" source, but see: // https://www.wwdcnotes.com/notes/wwdc20/10214/ @@ -541,7 +542,8 @@ impl<'mir, 'tcx> MiriMachine<'mir, 'tcx> { 16 * 1024 } else { 4 * 1024 - }, + } + } _ => 4 * 1024, } }; @@ -892,7 +894,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> { ecx: &mut MiriInterpCx<'mir, 'tcx>, instance: ty::Instance<'tcx>, abi: Abi, - args: &[OpTy<'tcx, Provenance>], + args: &[FnArg<'tcx, Provenance>], dest: &PlaceTy<'tcx, Provenance>, ret: Option<mir::BasicBlock>, unwind: mir::UnwindAction, @@ -905,12 +907,13 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> { ecx: &mut MiriInterpCx<'mir, 'tcx>, fn_val: Dlsym, abi: Abi, - args: &[OpTy<'tcx, Provenance>], + args: &[FnArg<'tcx, Provenance>], dest: &PlaceTy<'tcx, Provenance>, ret: Option<mir::BasicBlock>, _unwind: mir::UnwindAction, ) -> InterpResult<'tcx> { - ecx.call_dlsym(fn_val, abi, args, dest, ret) + let args = ecx.copy_fn_args(args)?; // FIXME: Should `InPlace` arguments be reset to uninit? + ecx.call_dlsym(fn_val, abi, &args, dest, ret) } #[inline(always)] @@ -1094,8 +1097,9 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> { ptr: Pointer<Self::Provenance>, ) -> InterpResult<'tcx> { match ptr.provenance { - Provenance::Concrete { alloc_id, tag } => - intptrcast::GlobalStateInner::expose_ptr(ecx, alloc_id, tag), + Provenance::Concrete { alloc_id, tag } => { + intptrcast::GlobalStateInner::expose_ptr(ecx, alloc_id, tag) + } Provenance::Wildcard => { // No need to do anything for wildcard pointers as // their provenances have already been previously exposed. @@ -1206,6 +1210,25 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> { Ok(()) } + fn protect_in_place_function_argument( + ecx: &mut InterpCx<'mir, 'tcx, Self>, + place: &PlaceTy<'tcx, Provenance>, + ) -> InterpResult<'tcx> { + // We do need to write `uninit` so that even after the call ends, the former contents of + // this place cannot be observed any more. + ecx.write_uninit(place)?; + // If we have a borrow tracker, we also have it set up protection so that all reads *and + // writes* during this call are insta-UB. + if ecx.machine.borrow_tracker.is_some() { + if let Either::Left(place) = place.as_mplace_or_local() { + ecx.protect_place(&place)?; + } else { + // Locals that don't have their address taken are as protected as they can ever be. + } + } + Ok(()) + } + #[inline(always)] fn init_frame_extra( ecx: &mut InterpCx<'mir, 'tcx, Self>, @@ -1288,8 +1311,17 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> { let stack_len = ecx.active_thread_stack().len(); ecx.active_thread_mut().set_top_user_relevant_frame(stack_len - 1); } - if ecx.machine.borrow_tracker.is_some() { - ecx.retag_return_place()?; + Ok(()) + } + + fn before_stack_pop( + ecx: &InterpCx<'mir, 'tcx, Self>, + frame: &Frame<'mir, 'tcx, Self::Provenance, Self::FrameExtra>, + ) -> InterpResult<'tcx> { + // We want this *before* the return value copy, because the return place itself is protected + // until we do `end_call` here. + if let Some(borrow_tracker) = &ecx.machine.borrow_tracker { + borrow_tracker.borrow_mut().end_call(&frame.extra); } Ok(()) } @@ -1308,9 +1340,6 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> { ecx.active_thread_mut().recompute_top_user_relevant_frame(); } let timing = frame.extra.timing.take(); - if let Some(borrow_tracker) = &ecx.machine.borrow_tracker { - borrow_tracker.borrow_mut().end_call(&frame.extra); - } let res = ecx.handle_stack_pop_unwind(frame.extra, unwinding); if let Some(profiler) = ecx.machine.profiler.as_ref() { profiler.finish_recording_interval_event(timing.unwrap()); diff --git a/src/tools/miri/src/shims/mod.rs b/src/tools/miri/src/shims/mod.rs index a423a0786b7..1027b24e301 100644 --- a/src/tools/miri/src/shims/mod.rs +++ b/src/tools/miri/src/shims/mod.rs @@ -31,7 +31,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { &mut self, instance: ty::Instance<'tcx>, abi: Abi, - args: &[OpTy<'tcx, Provenance>], + args: &[FnArg<'tcx, Provenance>], dest: &PlaceTy<'tcx, Provenance>, ret: Option<mir::BasicBlock>, unwind: mir::UnwindAction, @@ -41,7 +41,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { // There are some more lang items we want to hook that CTFE does not hook (yet). if this.tcx.lang_items().align_offset_fn() == Some(instance.def.def_id()) { - let [ptr, align] = check_arg_count(args)?; + let args = this.copy_fn_args(args)?; + let [ptr, align] = check_arg_count(&args)?; if this.align_offset(ptr, align, dest, ret, unwind)? { return Ok(None); } @@ -55,7 +56,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { // to run extra MIR), and Ok(Some(body)) if we found MIR to run for the // foreign function // Any needed call to `goto_block` will be performed by `emulate_foreign_item`. - return this.emulate_foreign_item(instance.def_id(), abi, args, dest, ret, unwind); + let args = this.copy_fn_args(args)?; // FIXME: Should `InPlace` arguments be reset to uninit? + return this.emulate_foreign_item(instance.def_id(), abi, &args, dest, ret, unwind); } // Otherwise, load the MIR. diff --git a/src/tools/miri/tests/fail/function_calls/arg_inplace_mutate.rs b/src/tools/miri/tests/fail/function_calls/arg_inplace_mutate.rs new file mode 100644 index 00000000000..625a8bda8af --- /dev/null +++ b/src/tools/miri/tests/fail/function_calls/arg_inplace_mutate.rs @@ -0,0 +1,34 @@ +//@revisions: stack tree +//@[tree]compile-flags: -Zmiri-tree-borrows +#![feature(custom_mir, core_intrinsics)] +use std::intrinsics::mir::*; + +pub struct S(i32); + +#[custom_mir(dialect = "runtime", phase = "optimized")] +fn main() { + mir! { + let unit: (); + { + let non_copy = S(42); + let ptr = std::ptr::addr_of_mut!(non_copy); + // Inside `callee`, the first argument and `*ptr` are basically + // aliasing places! + Call(unit, after_call, callee(Move(*ptr), ptr)) + } + after_call = { + Return() + } + + } +} + +pub fn callee(x: S, ptr: *mut S) { + // With the setup above, if `x` is indeed moved in + // (i.e. we actually just get a pointer to the underlying storage), + // then writing to `ptr` will change the value stored in `x`! + unsafe { ptr.write(S(0)) }; + //~[stack]^ ERROR: not granting access + //~[tree]| ERROR: /write access .* forbidden/ + assert_eq!(x.0, 42); +} diff --git a/src/tools/miri/tests/fail/function_calls/arg_inplace_mutate.stack.stderr b/src/tools/miri/tests/fail/function_calls/arg_inplace_mutate.stack.stderr new file mode 100644 index 00000000000..471dc1dd6dd --- /dev/null +++ b/src/tools/miri/tests/fail/function_calls/arg_inplace_mutate.stack.stderr @@ -0,0 +1,37 @@ +error: Undefined Behavior: not granting access to tag <TAG> because that would remove [Unique for <TAG>] which is strongly protected because it is an argument of call ID + --> $DIR/arg_inplace_mutate.rs:LL:CC + | +LL | unsafe { ptr.write(S(0)) }; + | ^^^^^^^^^^^^^^^ not granting access to tag <TAG> because that would remove [Unique for <TAG>] which is strongly protected because it is an argument of call ID + | + = 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: <TAG> was created by a SharedReadWrite retag at offsets [0x0..0x4] + --> $DIR/arg_inplace_mutate.rs:LL:CC + | +LL | / mir! { +LL | | let unit: (); +LL | | { +LL | | let non_copy = S(42); +... | +LL | | +LL | | } + | |_____^ +help: <TAG> is this argument + --> $DIR/arg_inplace_mutate.rs:LL:CC + | +LL | unsafe { ptr.write(S(0)) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: BACKTRACE (of the first span): + = note: inside `callee` at $DIR/arg_inplace_mutate.rs:LL:CC +note: inside `main` + --> $DIR/arg_inplace_mutate.rs:LL:CC + | +LL | Call(unit, after_call, callee(Move(*ptr), ptr)) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: this error originates in the macro `::core::intrinsics::mir::__internal_remove_let` which comes from the expansion of the macro `mir` (in Nightly builds, run with -Z macro-backtrace for more info) + +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/fail/function_calls/arg_inplace_mutate.tree.stderr b/src/tools/miri/tests/fail/function_calls/arg_inplace_mutate.tree.stderr new file mode 100644 index 00000000000..35c02cc2ebd --- /dev/null +++ b/src/tools/miri/tests/fail/function_calls/arg_inplace_mutate.tree.stderr @@ -0,0 +1,39 @@ +error: Undefined Behavior: write access through <TAG> (root of the allocation) is forbidden + --> $DIR/arg_inplace_mutate.rs:LL:CC + | +LL | unsafe { ptr.write(S(0)) }; + | ^^^^^^^^^^^^^^^ write access through <TAG> (root of the allocation) is forbidden + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental + = help: the accessed tag <TAG> (root of the allocation) is foreign to the protected tag <TAG> (i.e., it is not a child) + = help: this foreign write access would cause the protected tag <TAG> to transition from Active to Disabled + = help: this transition would be a loss of read and write permissions, which is not allowed for protected tags +help: the accessed tag <TAG> was created here + --> $DIR/arg_inplace_mutate.rs:LL:CC + | +LL | / mir! { +LL | | let unit: (); +LL | | { +LL | | let non_copy = S(42); +... | +LL | | +LL | | } + | |_____^ +help: the protected tag <TAG> was created here, in the initial state Active + --> $DIR/arg_inplace_mutate.rs:LL:CC + | +LL | unsafe { ptr.write(S(0)) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: BACKTRACE (of the first span): + = note: inside `callee` at $DIR/arg_inplace_mutate.rs:LL:CC +note: inside `main` + --> $DIR/arg_inplace_mutate.rs:LL:CC + | +LL | Call(unit, after_call, callee(Move(*ptr), ptr)) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: this error originates in the macro `::core::intrinsics::mir::__internal_remove_let` which comes from the expansion of the macro `mir` (in Nightly builds, run with -Z macro-backtrace for more info) + +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/fail/function_calls/arg_inplace_observe_after.rs b/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_after.rs new file mode 100644 index 00000000000..8eda913feb4 --- /dev/null +++ b/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_after.rs @@ -0,0 +1,27 @@ +#![feature(custom_mir, core_intrinsics)] +use std::intrinsics::mir::*; + +pub struct S(i32); + +#[custom_mir(dialect = "runtime", phase = "optimized")] +fn main() { + // FIXME: the span is not great (probably caused by custom MIR) + mir! { //~ERROR: uninitialized + let unit: (); + { + let non_copy = S(42); + // This could change `non_copy` in-place + Call(unit, after_call, change_arg(Move(non_copy))) + } + after_call = { + // So now we must not be allowed to observe non-copy again. + let _observe = non_copy.0; + Return() + } + + } +} + +pub fn change_arg(mut x: S) { + x.0 = 0; +} diff --git a/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_after.stderr b/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_after.stderr new file mode 100644 index 00000000000..3ff7976c70b --- /dev/null +++ b/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_after.stderr @@ -0,0 +1,22 @@ +error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory + --> $DIR/arg_inplace_observe_after.rs:LL:CC + | +LL | / mir! { +LL | | let unit: (); +LL | | { +LL | | let non_copy = S(42); +... | +LL | | +LL | | } + | |_____^ using uninitialized data, but this operation requires initialized memory + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: BACKTRACE: + = note: inside `main` at RUSTLIB/core/src/intrinsics/mir.rs:LL:CC + = note: this error originates in the macro `::core::intrinsics::mir::__internal_remove_let` which comes from the expansion of the macro `mir` (in Nightly builds, run with -Z macro-backtrace for more info) + +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/fail/function_calls/arg_inplace_observe_during.none.stderr b/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_during.none.stderr new file mode 100644 index 00000000000..baa91484793 --- /dev/null +++ b/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_during.none.stderr @@ -0,0 +1,20 @@ +error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory + --> $DIR/arg_inplace_observe_during.rs:LL:CC + | +LL | unsafe { ptr.read() }; + | ^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: BACKTRACE: + = note: inside `change_arg` at $DIR/arg_inplace_observe_during.rs:LL:CC +note: inside `main` + --> $DIR/arg_inplace_observe_during.rs:LL:CC + | +LL | Call(unit, after_call, change_arg(Move(*ptr), ptr)) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +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/fail/function_calls/arg_inplace_observe_during.rs b/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_during.rs new file mode 100644 index 00000000000..2e57872db96 --- /dev/null +++ b/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_during.rs @@ -0,0 +1,34 @@ +//@revisions: stack tree none +//@[tree]compile-flags: -Zmiri-tree-borrows +//@[none]compile-flags: -Zmiri-disable-stacked-borrows +#![feature(custom_mir, core_intrinsics)] +use std::intrinsics::mir::*; + +pub struct S(i32); + +#[custom_mir(dialect = "runtime", phase = "optimized")] +fn main() { + mir! { + let unit: (); + { + let non_copy = S(42); + let ptr = std::ptr::addr_of_mut!(non_copy); + // This could change `non_copy` in-place + Call(unit, after_call, change_arg(Move(*ptr), ptr)) + } + after_call = { + Return() + } + + } +} + +pub fn change_arg(mut x: S, ptr: *mut S) { + x.0 = 0; + // If `x` got passed in-place, we'd see the write through `ptr`! + // Make sure we are not allowed to do that read. + unsafe { ptr.read() }; + //~[stack]^ ERROR: not granting access + //~[tree]| ERROR: /read access .* forbidden/ + //~[none]| ERROR: uninitialized +} diff --git a/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_during.stack.stderr b/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_during.stack.stderr new file mode 100644 index 00000000000..a842d3a8044 --- /dev/null +++ b/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_during.stack.stderr @@ -0,0 +1,37 @@ +error: Undefined Behavior: not granting access to tag <TAG> because that would remove [Unique for <TAG>] which is strongly protected because it is an argument of call ID + --> $DIR/arg_inplace_observe_during.rs:LL:CC + | +LL | unsafe { ptr.read() }; + | ^^^^^^^^^^ not granting access to tag <TAG> because that would remove [Unique for <TAG>] which is strongly protected because it is an argument of call ID + | + = 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: <TAG> was created by a SharedReadWrite retag at offsets [0x0..0x4] + --> $DIR/arg_inplace_observe_during.rs:LL:CC + | +LL | / mir! { +LL | | let unit: (); +LL | | { +LL | | let non_copy = S(42); +... | +LL | | +LL | | } + | |_____^ +help: <TAG> is this argument + --> $DIR/arg_inplace_observe_during.rs:LL:CC + | +LL | x.0 = 0; + | ^^^^^^^ + = note: BACKTRACE (of the first span): + = note: inside `change_arg` at $DIR/arg_inplace_observe_during.rs:LL:CC +note: inside `main` + --> $DIR/arg_inplace_observe_during.rs:LL:CC + | +LL | Call(unit, after_call, change_arg(Move(*ptr), ptr)) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: this error originates in the macro `::core::intrinsics::mir::__internal_remove_let` which comes from the expansion of the macro `mir` (in Nightly builds, run with -Z macro-backtrace for more info) + +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/fail/function_calls/arg_inplace_observe_during.tree.stderr b/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_during.tree.stderr new file mode 100644 index 00000000000..cbd76c38f62 --- /dev/null +++ b/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_during.tree.stderr @@ -0,0 +1,39 @@ +error: Undefined Behavior: read access through <TAG> (root of the allocation) is forbidden + --> $DIR/arg_inplace_observe_during.rs:LL:CC + | +LL | unsafe { ptr.read() }; + | ^^^^^^^^^^ read access through <TAG> (root of the allocation) is forbidden + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental + = help: the accessed tag <TAG> (root of the allocation) is foreign to the protected tag <TAG> (i.e., it is not a child) + = help: this foreign read access would cause the protected tag <TAG> to transition from Active to Frozen + = help: this transition would be a loss of write permissions, which is not allowed for protected tags +help: the accessed tag <TAG> was created here + --> $DIR/arg_inplace_observe_during.rs:LL:CC + | +LL | / mir! { +LL | | let unit: (); +LL | | { +LL | | let non_copy = S(42); +... | +LL | | +LL | | } + | |_____^ +help: the protected tag <TAG> was created here, in the initial state Active + --> $DIR/arg_inplace_observe_during.rs:LL:CC + | +LL | x.0 = 0; + | ^^^^^^^ + = note: BACKTRACE (of the first span): + = note: inside `change_arg` at $DIR/arg_inplace_observe_during.rs:LL:CC +note: inside `main` + --> $DIR/arg_inplace_observe_during.rs:LL:CC + | +LL | Call(unit, after_call, change_arg(Move(*ptr), ptr)) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: this error originates in the macro `::core::intrinsics::mir::__internal_remove_let` which comes from the expansion of the macro `mir` (in Nightly builds, run with -Z macro-backtrace for more info) + +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/fail/function_calls/return_pointer_aliasing.none.stderr b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing.none.stderr new file mode 100644 index 00000000000..9d9dfc89f89 --- /dev/null +++ b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing.none.stderr @@ -0,0 +1,20 @@ +error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory + --> $DIR/return_pointer_aliasing.rs:LL:CC + | +LL | unsafe { ptr.read() }; + | ^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: BACKTRACE: + = note: inside `myfun` at $DIR/return_pointer_aliasing.rs:LL:CC +note: inside `main` + --> $DIR/return_pointer_aliasing.rs:LL:CC + | +LL | Call(*ptr, after_call, myfun(ptr)) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +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/fail/both_borrows/return_pointer_aliasing.rs b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing.rs index 03886e7874d..829809102fa 100644 --- a/src/tools/miri/tests/fail/both_borrows/return_pointer_aliasing.rs +++ b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing.rs @@ -1,11 +1,11 @@ -//@revisions: stack tree +//@revisions: stack tree none //@[tree]compile-flags: -Zmiri-tree-borrows +//@[none]compile-flags: -Zmiri-disable-stacked-borrows #![feature(raw_ref_op)] #![feature(core_intrinsics)] #![feature(custom_mir)] use std::intrinsics::mir::*; -use std::mem::MaybeUninit; #[custom_mir(dialect = "runtime", phase = "optimized")] pub fn main() { @@ -25,8 +25,10 @@ pub fn main() { } fn myfun(ptr: *mut i32) -> i32 { - unsafe { ptr.cast::<MaybeUninit<i32>>().read() }; - //~[stack]^ ERROR: /not granting access/ + unsafe { ptr.read() }; + //~[stack]^ ERROR: not granting access //~[tree]| ERROR: /read access .* forbidden/ + //~[none]| ERROR: uninitialized + // Without an aliasing model, reads are "fine" but at least they return uninit data. 13 } diff --git a/src/tools/miri/tests/fail/both_borrows/return_pointer_aliasing.stack.stderr b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing.stack.stderr index 5bdddf5e49c..d486dcb95df 100644 --- a/src/tools/miri/tests/fail/both_borrows/return_pointer_aliasing.stack.stderr +++ b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing.stack.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: not granting access to tag <TAG> because that would remove [Unique for <TAG>] which is strongly protected because it is an argument of call ID --> $DIR/return_pointer_aliasing.rs:LL:CC | -LL | unsafe { ptr.cast::<MaybeUninit<i32>>().read() }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not granting access to tag <TAG> because that would remove [Unique for <TAG>] which is strongly protected because it is an argument of call ID +LL | unsafe { ptr.read() }; + | ^^^^^^^^^^ not granting access to tag <TAG> because that would remove [Unique for <TAG>] which is strongly protected because it is an argument of call ID | = 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 @@ -20,13 +20,8 @@ LL | | } help: <TAG> is this argument --> $DIR/return_pointer_aliasing.rs:LL:CC | -LL | / fn myfun(ptr: *mut i32) -> i32 { -LL | | unsafe { ptr.cast::<MaybeUninit<i32>>().read() }; -LL | | -LL | | -LL | | 13 -LL | | } - | |_^ +LL | unsafe { ptr.read() }; + | ^^^^^^^^^^^^^^^^^^^^^ = note: BACKTRACE (of the first span): = note: inside `myfun` at $DIR/return_pointer_aliasing.rs:LL:CC note: inside `main` diff --git a/src/tools/miri/tests/fail/both_borrows/return_pointer_aliasing.tree.stderr b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing.tree.stderr index dd76d65c7ca..c2c9de3f4ee 100644 --- a/src/tools/miri/tests/fail/both_borrows/return_pointer_aliasing.tree.stderr +++ b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing.tree.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: read access through <TAG> (root of the allocation) is forbidden --> $DIR/return_pointer_aliasing.rs:LL:CC | -LL | unsafe { ptr.cast::<MaybeUninit<i32>>().read() }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ read access through <TAG> (root of the allocation) is forbidden +LL | unsafe { ptr.read() }; + | ^^^^^^^^^^ read access through <TAG> (root of the allocation) is forbidden | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental = help: the accessed tag <TAG> (root of the allocation) is foreign to the protected tag <TAG> (i.e., it is not a child) @@ -22,13 +22,8 @@ LL | | } help: the protected tag <TAG> was created here, in the initial state Active --> $DIR/return_pointer_aliasing.rs:LL:CC | -LL | / fn myfun(ptr: *mut i32) -> i32 { -LL | | unsafe { ptr.cast::<MaybeUninit<i32>>().read() }; -LL | | -LL | | -LL | | 13 -LL | | } - | |_^ +LL | unsafe { ptr.read() }; + | ^^^^^^^^^^^^^^^^^^^^^ = note: BACKTRACE (of the first span): = note: inside `myfun` at $DIR/return_pointer_aliasing.rs:LL:CC note: inside `main` diff --git a/src/tools/miri/tests/fail/unaligned_pointers/dyn_alignment.rs b/src/tools/miri/tests/fail/unaligned_pointers/dyn_alignment.rs index 6d31ded75c6..555aa57de30 100644 --- a/src/tools/miri/tests/fail/unaligned_pointers/dyn_alignment.rs +++ b/src/tools/miri/tests/fail/unaligned_pointers/dyn_alignment.rs @@ -1,5 +1,6 @@ -// should find the bug even without validation and stacked borrows, but gets masked by optimizations -//@compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows -Zmir-opt-level=0 -Cdebug-assertions=no +// should find the bug even without, but gets masked by optimizations +//@compile-flags: -Zmiri-disable-stacked-borrows -Zmir-opt-level=0 -Cdebug-assertions=no +//@normalize-stderr-test: "but found [0-9]+" -> "but found $$ALIGN" #[repr(align(256))] #[derive(Debug)] @@ -19,6 +20,6 @@ fn main() { (&mut ptr as *mut _ as *mut *const u8).write(&buf as *const _ as *const u8); } // Re-borrow that. This should be UB. - let _ptr = &*ptr; //~ERROR: alignment 256 is required + let _ptr = &*ptr; //~ERROR: required 256 byte alignment } } diff --git a/src/tools/miri/tests/fail/unaligned_pointers/dyn_alignment.stderr b/src/tools/miri/tests/fail/unaligned_pointers/dyn_alignment.stderr index a900b46612b..503721b9551 100644 --- a/src/tools/miri/tests/fail/unaligned_pointers/dyn_alignment.stderr +++ b/src/tools/miri/tests/fail/unaligned_pointers/dyn_alignment.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: accessing memory with alignment ALIGN, but alignment ALIGN is required +error: Undefined Behavior: constructing invalid value: encountered an unaligned reference (required 256 byte alignment but found $ALIGN) --> $DIR/dyn_alignment.rs:LL:CC | LL | let _ptr = &*ptr; - | ^^^^^ accessing memory with alignment ALIGN, but alignment ALIGN is required + | ^^^^^ constructing invalid value: encountered an unaligned reference (required 256 byte alignment but found $ALIGN) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/pass/function_calls/return_place_on_heap.rs b/src/tools/miri/tests/pass/function_calls/return_place_on_heap.rs new file mode 100644 index 00000000000..dcfebd0f82b --- /dev/null +++ b/src/tools/miri/tests/pass/function_calls/return_place_on_heap.rs @@ -0,0 +1,25 @@ +#![feature(raw_ref_op)] +#![feature(core_intrinsics)] +#![feature(custom_mir)] + +use std::intrinsics::mir::*; + +// Make sure calls with the return place "on the heap" work. +#[custom_mir(dialect = "runtime", phase = "optimized")] +pub fn main() { + mir! { + { + let x = 0; + let ptr = &raw mut x; + Call(*ptr, after_call, myfun()) + } + + after_call = { + Return() + } + } +} + +fn myfun() -> i32 { + 13 +} diff --git a/src/tools/rls/Cargo.toml b/src/tools/rls/Cargo.toml index b84647eb332..b7aa659c25a 100644 --- a/src/tools/rls/Cargo.toml +++ b/src/tools/rls/Cargo.toml @@ -5,5 +5,4 @@ edition = "2021" license = "Apache-2.0/MIT" [dependencies] -serde = { version = "1.0.143", features = ["derive"] } serde_json = "1.0.83" diff --git a/src/tools/rls/src/main.rs b/src/tools/rls/src/main.rs index f96f1325d96..d7be108e89c 100644 --- a/src/tools/rls/src/main.rs +++ b/src/tools/rls/src/main.rs @@ -3,7 +3,7 @@ //! This is a small stub that replaces RLS to alert the user that RLS is no //! longer available. -use serde::Deserialize; +use serde_json::Value; use std::error::Error; use std::io::BufRead; use std::io::Write; @@ -21,7 +21,6 @@ fn main() { } } -#[derive(Deserialize)] struct Message { method: Option<String>, } @@ -88,8 +87,10 @@ fn read_message_raw<R: BufRead>(reader: &mut R) -> Result<String, Box<dyn Error> fn read_message<R: BufRead>(reader: &mut R) -> Result<Message, Box<dyn Error>> { let m = read_message_raw(reader)?; - match serde_json::from_str(&m) { - Ok(m) => Ok(m), + match serde_json::from_str::<Value>(&m) { + Ok(message) => Ok(Message { + method: message.get("method").and_then(|value| value.as_str().map(String::from)), + }), Err(e) => Err(format!("failed to parse message {m}\n{e}").into()), } } diff --git a/src/tools/tidy/src/pal.rs b/src/tools/tidy/src/pal.rs index 62c070221dc..b386b000bef 100644 --- a/src/tools/tidy/src/pal.rs +++ b/src/tools/tidy/src/pal.rs @@ -39,7 +39,6 @@ const EXCEPTION_PATHS: &[&str] = &[ "library/panic_unwind", "library/unwind", "library/rtstartup", // Not sure what to do about this. magic stuff for mingw - "library/term", // Not sure how to make this crate portable, but test crate needs it. "library/test", // Probably should defer to unstable `std::sys` APIs. // The `VaList` implementation must have platform specific code. // The Windows implementation of a `va_list` is always a character |
