From bc6a5c71b635a9a5ea52c0b5f4ff297b0f611ac7 Mon Sep 17 00:00:00 2001 From: David Carlier <devnexen@gmail.com> Date: Fri, 8 Dec 2023 15:26:16 +0000 Subject: [PATCH 01/17] std: getrandom simplification for freebsd. it is in the libcs' crate too now. --- library/std/src/sys/unix/rand.rs | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/library/std/src/sys/unix/rand.rs b/library/std/src/sys/unix/rand.rs index 2825d16774272..cf0fe0f47c53f 100644 --- a/library/std/src/sys/unix/rand.rs +++ b/library/std/src/sys/unix/rand.rs @@ -64,17 +64,7 @@ mod imp { #[cfg(any(target_os = "espidf", target_os = "horizon", target_os = "freebsd"))] fn getrandom(buf: &mut [u8]) -> libc::ssize_t { - #[cfg(not(target_os = "freebsd"))] - use libc::getrandom; - #[cfg(target_os = "freebsd")] - extern "C" { - fn getrandom( - buf: *mut libc::c_void, - buflen: libc::size_t, - flags: libc::c_uint, - ) -> libc::ssize_t; - } - unsafe { getrandom(buf.as_mut_ptr().cast(), buf.len(), 0) } + unsafe { libc::getrandom(buf.as_mut_ptr().cast(), buf.len(), 0) } } #[cfg(not(any( From 2c088f95202400084987ed874822b4969f678d20 Mon Sep 17 00:00:00 2001 From: Obei Sideg <obei.sideg@gmail.com> Date: Fri, 22 Dec 2023 14:56:20 +0300 Subject: [PATCH 02/17] Disallow reference to `static mut` for expressions Add `E0796` error code. Add `static_mut_ref` lint. This is the idea for the 2024 edition. --- Cargo.lock | 1 + compiler/rustc_error_codes/src/error_codes.rs | 1 + .../src/error_codes/E0796.md | 22 +++++ compiler/rustc_hir_analysis/Cargo.toml | 1 + compiler/rustc_hir_analysis/messages.ftl | 14 +++ compiler/rustc_hir_analysis/src/check/errs.rs | 78 ++++++++++++++++ compiler/rustc_hir_analysis/src/check/mod.rs | 1 + compiler/rustc_hir_analysis/src/errors.rs | 91 +++++++++++++++++++ compiler/rustc_lint_defs/src/builtin.rs | 52 +++++++++++ 9 files changed, 261 insertions(+) create mode 100644 compiler/rustc_error_codes/src/error_codes/E0796.md create mode 100644 compiler/rustc_hir_analysis/src/check/errs.rs diff --git a/Cargo.lock b/Cargo.lock index b8192e333fe91..1d6f7ea1e27ce 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3877,6 +3877,7 @@ dependencies = [ "rustc_feature", "rustc_fluent_macro", "rustc_hir", + "rustc_hir_pretty", "rustc_index", "rustc_infer", "rustc_lint_defs", diff --git a/compiler/rustc_error_codes/src/error_codes.rs b/compiler/rustc_error_codes/src/error_codes.rs index 1028d43f9c5ba..a1391cceb7128 100644 --- a/compiler/rustc_error_codes/src/error_codes.rs +++ b/compiler/rustc_error_codes/src/error_codes.rs @@ -515,6 +515,7 @@ E0792: include_str!("./error_codes/E0792.md"), E0793: include_str!("./error_codes/E0793.md"), E0794: include_str!("./error_codes/E0794.md"), E0795: include_str!("./error_codes/E0795.md"), +E0796: include_str!("./error_codes/E0796.md"), } // Undocumented removed error codes. Note that many removed error codes are kept in the list above diff --git a/compiler/rustc_error_codes/src/error_codes/E0796.md b/compiler/rustc_error_codes/src/error_codes/E0796.md new file mode 100644 index 0000000000000..cea18f8db851f --- /dev/null +++ b/compiler/rustc_error_codes/src/error_codes/E0796.md @@ -0,0 +1,22 @@ +Reference of mutable static. + +Erroneous code example: + +```compile_fail,edition2024,E0796 +static mut X: i32 = 23; +static mut Y: i32 = 24; + +unsafe { + let y = &X; + let ref x = X; + let (x, y) = (&X, &Y); + foo(&X); +} + +fn foo<'a>(_x: &'a i32) {} +``` + +Mutable statics can be written to by multiple threads: aliasing violations or +data races will cause undefined behavior. + +Reference of mutable static is a hard error from 2024 edition. diff --git a/compiler/rustc_hir_analysis/Cargo.toml b/compiler/rustc_hir_analysis/Cargo.toml index b671bebeb0503..b5ebc1fab765d 100644 --- a/compiler/rustc_hir_analysis/Cargo.toml +++ b/compiler/rustc_hir_analysis/Cargo.toml @@ -17,6 +17,7 @@ rustc_errors = { path = "../rustc_errors" } rustc_feature = { path = "../rustc_feature" } rustc_fluent_macro = { path = "../rustc_fluent_macro" } rustc_hir = { path = "../rustc_hir" } +rustc_hir_pretty = { path = "../rustc_hir_pretty" } rustc_index = { path = "../rustc_index" } rustc_infer = { path = "../rustc_infer" } rustc_lint_defs = { path = "../rustc_lint_defs" } diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index d8b6b9a1272fb..6a17668ad17f8 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -346,6 +346,20 @@ hir_analysis_start_not_target_feature = `#[start]` function is not allowed to ha hir_analysis_start_not_track_caller = `#[start]` function is not allowed to be `#[track_caller]` .label = `#[start]` function is not allowed to be `#[track_caller]` +hir_analysis_static_mut_ref = reference of mutable static is disallowed + .label = reference of mutable static + .note = mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior + .suggestion = shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer + .suggestion_mut = mutable references are dangerous since if there's any other pointer or reference used for that static while the reference lives, that's UB; use `addr_of_mut!` instead to create a raw pointer + +hir_analysis_static_mut_ref_lint = {$shared}reference of mutable static is discouraged + .label = shared reference of mutable static + .label_mut = mutable reference of mutable static + .suggestion = shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer + .suggestion_mut = mutable references are dangerous since if there's any other pointer or reference used for that static while the reference lives, that's UB; use `addr_of_mut!` instead to create a raw pointer + .note = reference of mutable static is a hard error from 2024 edition + .why_note = mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior + hir_analysis_static_specialize = cannot specialize on `'static` lifetime hir_analysis_substs_on_overridden_impl = could not resolve substs on overridden impl diff --git a/compiler/rustc_hir_analysis/src/check/errs.rs b/compiler/rustc_hir_analysis/src/check/errs.rs new file mode 100644 index 0000000000000..5862643c42f80 --- /dev/null +++ b/compiler/rustc_hir_analysis/src/check/errs.rs @@ -0,0 +1,78 @@ +use rustc_hir as hir; +use rustc_hir_pretty::qpath_to_string; +use rustc_lint_defs::builtin::STATIC_MUT_REF; +use rustc_middle::ty::TyCtxt; +use rustc_span::Span; +use rustc_type_ir::Mutability; + +use crate::errors; + +/// Check for shared or mutable references of `static mut` inside expression +pub fn maybe_expr_static_mut(tcx: TyCtxt<'_>, expr: hir::Expr<'_>) { + let span = expr.span; + let hir_id = expr.hir_id; + if let hir::ExprKind::AddrOf(borrow_kind, m, expr) = expr.kind + && matches!(borrow_kind, hir::BorrowKind::Ref) + && let Some(var) = is_path_static_mut(*expr) + { + handle_static_mut_ref( + tcx, + span, + var, + span.edition().at_least_rust_2024(), + matches!(m, Mutability::Mut), + hir_id, + ); + } +} + +fn is_path_static_mut(expr: hir::Expr<'_>) -> Option<String> { + if let hir::ExprKind::Path(qpath) = expr.kind + && let hir::QPath::Resolved(_, path) = qpath + && let hir::def::Res::Def(def_kind, _) = path.res + && let hir::def::DefKind::Static(mt) = def_kind + && matches!(mt, Mutability::Mut) + { + return Some(qpath_to_string(&qpath)); + } + None +} + +fn handle_static_mut_ref( + tcx: TyCtxt<'_>, + span: Span, + var: String, + e2024: bool, + mutable: bool, + hir_id: hir::HirId, +) { + if e2024 { + let sugg = if mutable { + errors::StaticMutRefSugg::Mut { span, var } + } else { + errors::StaticMutRefSugg::Shared { span, var } + }; + tcx.sess.parse_sess.dcx.emit_err(errors::StaticMutRef { span, sugg }); + return; + } + + let (label, sugg, shared) = if mutable { + ( + errors::RefOfMutStaticLabel::Mut { span }, + errors::RefOfMutStaticSugg::Mut { span, var }, + "mutable ", + ) + } else { + ( + errors::RefOfMutStaticLabel::Shared { span }, + errors::RefOfMutStaticSugg::Shared { span, var }, + "shared ", + ) + }; + tcx.emit_spanned_lint( + STATIC_MUT_REF, + hir_id, + span, + errors::RefOfMutStatic { shared, why_note: (), label, sugg }, + ); +} diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index f60d6950670d9..ac0c715c6b308 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -66,6 +66,7 @@ mod check; mod compare_impl_item; pub mod dropck; mod entry; +mod errs; pub mod intrinsic; pub mod intrinsicck; mod region; diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index 9124d50211056..4f22da4ba3b98 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -1410,3 +1410,94 @@ pub struct OnlyCurrentTraitsPointerSugg<'a> { pub mut_key: &'a str, pub ptr_ty: Ty<'a>, } + +#[derive(Diagnostic)] +#[diag(hir_analysis_static_mut_ref, code = "E0796")] +#[note] +pub struct StaticMutRef { + #[primary_span] + #[label] + pub span: Span, + #[subdiagnostic] + pub sugg: StaticMutRefSugg, +} + +#[derive(Subdiagnostic)] +pub enum StaticMutRefSugg { + #[suggestion( + hir_analysis_suggestion, + style = "verbose", + code = "addr_of!({var})", + applicability = "maybe-incorrect" + )] + Shared { + #[primary_span] + span: Span, + var: String, + }, + #[suggestion( + hir_analysis_suggestion_mut, + style = "verbose", + code = "addr_of_mut!({var})", + applicability = "maybe-incorrect" + )] + Mut { + #[primary_span] + span: Span, + var: String, + }, +} + +// STATIC_MUT_REF lint +#[derive(LintDiagnostic)] +#[diag(hir_analysis_static_mut_ref_lint)] +#[note] +pub struct RefOfMutStatic<'a> { + pub shared: &'a str, + #[note(hir_analysis_why_note)] + pub why_note: (), + #[subdiagnostic] + pub label: RefOfMutStaticLabel, + #[subdiagnostic] + pub sugg: RefOfMutStaticSugg, +} + +#[derive(Subdiagnostic)] +pub enum RefOfMutStaticLabel { + #[label(hir_analysis_label)] + Shared { + #[primary_span] + span: Span, + }, + #[label(hir_analysis_label_mut)] + Mut { + #[primary_span] + span: Span, + }, +} + +#[derive(Subdiagnostic)] +pub enum RefOfMutStaticSugg { + #[suggestion( + hir_analysis_suggestion, + style = "verbose", + code = "addr_of!({var})", + applicability = "maybe-incorrect" + )] + Shared { + #[primary_span] + span: Span, + var: String, + }, + #[suggestion( + hir_analysis_suggestion_mut, + style = "verbose", + code = "addr_of_mut!({var})", + applicability = "maybe-incorrect" + )] + Mut { + #[primary_span] + span: Span, + var: String, + }, +} diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 19da51b7dcfa3..cfba6780a66fa 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -89,6 +89,7 @@ declare_lint_pass! { SINGLE_USE_LIFETIMES, SOFT_UNSTABLE, STABLE_FEATURES, + STATIC_MUT_REF, SUSPICIOUS_AUTO_TRAIT_IMPLS, TEST_UNSTABLE_LINT, TEXT_DIRECTION_CODEPOINT_IN_COMMENT, @@ -1767,6 +1768,57 @@ declare_lint! { }; } +declare_lint! { + /// The `static_mut_ref` lint checks for shared or mutable references + /// of mutable static inside `unsafe` blocks and `unsafe` functions. + /// + /// ### Example + /// + /// ```rust,edition2021 + /// fn main() { + /// static mut X: i32 = 23; + /// static mut Y: i32 = 24; + /// + /// unsafe { + /// let y = &X; + /// let ref x = X; + /// let (x, y) = (&X, &Y); + /// foo(&X); + /// } + /// } + /// + /// unsafe fn _foo() { + /// static mut X: i32 = 23; + /// static mut Y: i32 = 24; + /// + /// let y = &X; + /// let ref x = X; + /// let (x, y) = (&X, &Y); + /// foo(&X); + /// } + /// + /// fn foo<'a>(_x: &'a i32) {} + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Shared or mutable references of mutable static are almost always a mistake and + /// can lead to undefined behavior and various other problems in your code. + /// + /// This lint is "warn" by default on editions up to 2021, from 2024 there is + /// a hard error instead. + pub STATIC_MUT_REF, + Warn, + "shared references or mutable references of mutable static is discouraged", + @future_incompatible = FutureIncompatibleInfo { + reason: FutureIncompatibilityReason::EditionError(Edition::Edition2024), + reference: "issue #114447 <https://github.com/rust-lang/rust/issues/114447>", + explain_reason: false, + }; +} + declare_lint! { /// The `absolute_paths_not_starting_with_crate` lint detects fully /// qualified paths that start with a module name instead of `crate`, From 70ba4d14b3d1f81d27ad7b7bab81aac19e412c20 Mon Sep 17 00:00:00 2001 From: Obei Sideg <obei.sideg@gmail.com> Date: Fri, 22 Dec 2023 15:00:25 +0300 Subject: [PATCH 03/17] Disallow reference to `static mut` for statements --- compiler/rustc_hir_analysis/src/check/errs.rs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/compiler/rustc_hir_analysis/src/check/errs.rs b/compiler/rustc_hir_analysis/src/check/errs.rs index 5862643c42f80..27bb2c57a5cb7 100644 --- a/compiler/rustc_hir_analysis/src/check/errs.rs +++ b/compiler/rustc_hir_analysis/src/check/errs.rs @@ -26,6 +26,25 @@ pub fn maybe_expr_static_mut(tcx: TyCtxt<'_>, expr: hir::Expr<'_>) { } } +/// Check for shared or mutable references of `static mut` inside statement +pub fn maybe_stmt_static_mut(tcx: TyCtxt<'_>, stmt: hir::Stmt<'_>) { + if let hir::StmtKind::Local(loc) = stmt.kind + && let hir::PatKind::Binding(ba, _, _, _) = loc.pat.kind + && matches!(ba.0, rustc_ast::ByRef::Yes) + && let Some(init) = loc.init + && let Some(var) = is_path_static_mut(*init) + { + handle_static_mut_ref( + tcx, + init.span, + var, + loc.span.edition().at_least_rust_2024(), + matches!(ba.1, Mutability::Mut), + stmt.hir_id, + ); + } +} + fn is_path_static_mut(expr: hir::Expr<'_>) -> Option<String> { if let hir::ExprKind::Path(qpath) = expr.kind && let hir::QPath::Resolved(_, path) = qpath From a82fd2bc7cf15b8aa9ffbd7752999a3bc9cb8cea Mon Sep 17 00:00:00 2001 From: Obei Sideg <obei.sideg@gmail.com> Date: Fri, 22 Dec 2023 15:03:45 +0300 Subject: [PATCH 04/17] Call `maybe_expr_static_mut` inside `resolve_expr` --- compiler/rustc_hir_analysis/src/check/region.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/compiler/rustc_hir_analysis/src/check/region.rs b/compiler/rustc_hir_analysis/src/check/region.rs index 542e69a6c34de..1abdc7b21df9d 100644 --- a/compiler/rustc_hir_analysis/src/check/region.rs +++ b/compiler/rustc_hir_analysis/src/check/region.rs @@ -18,6 +18,8 @@ use rustc_middle::ty::TyCtxt; use rustc_span::source_map; use rustc_span::Span; +use super::errs::maybe_expr_static_mut; + use std::mem; #[derive(Debug, Copy, Clone)] @@ -242,6 +244,8 @@ fn resolve_stmt<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, stmt: &'tcx h fn resolve_expr<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, expr: &'tcx hir::Expr<'tcx>) { debug!("resolve_expr - pre-increment {} expr = {:?}", visitor.expr_and_pat_count, expr); + maybe_expr_static_mut(visitor.tcx, *expr); + let prev_cx = visitor.cx; visitor.enter_node_scope_with_dtor(expr.hir_id.local_id); From e36f7b7a5cacd9bfac9e7679ce6de26c03eb5795 Mon Sep 17 00:00:00 2001 From: Obei Sideg <obei.sideg@gmail.com> Date: Fri, 22 Dec 2023 15:09:10 +0300 Subject: [PATCH 05/17] Call `maybe_stmt_static_mut` inside `resolve_stmt` --- compiler/rustc_hir_analysis/src/check/region.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_hir_analysis/src/check/region.rs b/compiler/rustc_hir_analysis/src/check/region.rs index 1abdc7b21df9d..5d5a4789734a7 100644 --- a/compiler/rustc_hir_analysis/src/check/region.rs +++ b/compiler/rustc_hir_analysis/src/check/region.rs @@ -18,7 +18,7 @@ use rustc_middle::ty::TyCtxt; use rustc_span::source_map; use rustc_span::Span; -use super::errs::maybe_expr_static_mut; +use super::errs::{maybe_expr_static_mut, maybe_stmt_static_mut}; use std::mem; @@ -226,6 +226,8 @@ fn resolve_stmt<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, stmt: &'tcx h let stmt_id = stmt.hir_id.local_id; debug!("resolve_stmt(stmt.id={:?})", stmt_id); + maybe_stmt_static_mut(visitor.tcx, *stmt); + // Every statement will clean up the temporaries created during // execution of that statement. Therefore each statement has an // associated destruction scope that represents the scope of the From 18edf9a64e8d84e72a6be67df3822e57dea8d34a Mon Sep 17 00:00:00 2001 From: Obei Sideg <obei.sideg@gmail.com> Date: Fri, 22 Dec 2023 15:10:47 +0300 Subject: [PATCH 06/17] Add test for `E0796` and `static_mut_ref` lint --- .../reference-of-mut-static-safe.e2021.stderr | 26 ++++++ .../reference-of-mut-static-safe.e2024.stderr | 15 +++ .../ui/static/reference-of-mut-static-safe.rs | 13 +++ .../reference-of-mut-static-unsafe-fn.rs | 23 +++++ .../reference-of-mut-static-unsafe-fn.stderr | 63 +++++++++++++ .../reference-of-mut-static.e2021.stderr | 91 +++++++++++++++++++ .../reference-of-mut-static.e2024.stderr | 75 +++++++++++++++ tests/ui/static/reference-of-mut-static.rs | 50 ++++++++++ 8 files changed, 356 insertions(+) create mode 100644 tests/ui/static/reference-of-mut-static-safe.e2021.stderr create mode 100644 tests/ui/static/reference-of-mut-static-safe.e2024.stderr create mode 100644 tests/ui/static/reference-of-mut-static-safe.rs create mode 100644 tests/ui/static/reference-of-mut-static-unsafe-fn.rs create mode 100644 tests/ui/static/reference-of-mut-static-unsafe-fn.stderr create mode 100644 tests/ui/static/reference-of-mut-static.e2021.stderr create mode 100644 tests/ui/static/reference-of-mut-static.e2024.stderr create mode 100644 tests/ui/static/reference-of-mut-static.rs diff --git a/tests/ui/static/reference-of-mut-static-safe.e2021.stderr b/tests/ui/static/reference-of-mut-static-safe.e2021.stderr new file mode 100644 index 0000000000000..c38fe8790637e --- /dev/null +++ b/tests/ui/static/reference-of-mut-static-safe.e2021.stderr @@ -0,0 +1,26 @@ +warning: shared reference of mutable static is discouraged + --> $DIR/reference-of-mut-static-safe.rs:9:14 + | +LL | let _x = &X; + | ^^ shared reference of mutable static + | + = note: for more information, see issue #114447 <https://github.com/rust-lang/rust/issues/114447> + = note: reference of mutable static is a hard error from 2024 edition + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior + = note: `#[warn(static_mut_ref)]` on by default +help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer + | +LL | let _x = addr_of!(X); + | ~~~~~~~~~~~ + +error[E0133]: use of mutable static is unsafe and requires unsafe function or block + --> $DIR/reference-of-mut-static-safe.rs:9:14 + | +LL | let _x = &X; + | ^^ use of mutable static + | + = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior + +error: aborting due to 1 previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0133`. diff --git a/tests/ui/static/reference-of-mut-static-safe.e2024.stderr b/tests/ui/static/reference-of-mut-static-safe.e2024.stderr new file mode 100644 index 0000000000000..53f81179de55a --- /dev/null +++ b/tests/ui/static/reference-of-mut-static-safe.e2024.stderr @@ -0,0 +1,15 @@ +error[E0796]: reference of mutable static is disallowed + --> $DIR/reference-of-mut-static-safe.rs:9:14 + | +LL | let _x = &X; + | ^^ reference of mutable static + | + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior +help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer + | +LL | let _x = addr_of!(X); + | ~~~~~~~~~~~ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0796`. diff --git a/tests/ui/static/reference-of-mut-static-safe.rs b/tests/ui/static/reference-of-mut-static-safe.rs new file mode 100644 index 0000000000000..5cb1a03bef512 --- /dev/null +++ b/tests/ui/static/reference-of-mut-static-safe.rs @@ -0,0 +1,13 @@ +// revisions: e2021 e2024 + +// [e2021] edition:2021 +// [e2024] compile-flags: --edition 2024 -Z unstable-options + +fn main() { + static mut X: i32 = 1; + + let _x = &X; + //[e2024]~^ reference of mutable static is disallowed [E0796] + //[e2021]~^^ use of mutable static is unsafe and requires unsafe function or block [E0133] + //[e2021]~^^^ shared reference of mutable static is discouraged [static_mut_ref] +} diff --git a/tests/ui/static/reference-of-mut-static-unsafe-fn.rs b/tests/ui/static/reference-of-mut-static-unsafe-fn.rs new file mode 100644 index 0000000000000..6b1e77850e50d --- /dev/null +++ b/tests/ui/static/reference-of-mut-static-unsafe-fn.rs @@ -0,0 +1,23 @@ +// compile-flags: --edition 2024 -Z unstable-options + +fn main() {} + +unsafe fn _foo() { + static mut X: i32 = 1; + static mut Y: i32 = 1; + + let _y = &X; + //~^ ERROR reference of mutable static is disallowed + + let ref _a = X; + //~^ ERROR reference of mutable static is disallowed + + let (_b, _c) = (&X, &Y); + //~^ ERROR reference of mutable static is disallowed + //~^^ ERROR reference of mutable static is disallowed + + foo(&X); + //~^ ERROR reference of mutable static is disallowed +} + +fn foo<'a>(_x: &'a i32) {} diff --git a/tests/ui/static/reference-of-mut-static-unsafe-fn.stderr b/tests/ui/static/reference-of-mut-static-unsafe-fn.stderr new file mode 100644 index 0000000000000..5c6fdedfa96f7 --- /dev/null +++ b/tests/ui/static/reference-of-mut-static-unsafe-fn.stderr @@ -0,0 +1,63 @@ +error[E0796]: reference of mutable static is disallowed + --> $DIR/reference-of-mut-static-unsafe-fn.rs:9:14 + | +LL | let _y = &X; + | ^^ reference of mutable static + | + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior +help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer + | +LL | let _y = addr_of!(X); + | ~~~~~~~~~~~ + +error[E0796]: reference of mutable static is disallowed + --> $DIR/reference-of-mut-static-unsafe-fn.rs:12:18 + | +LL | let ref _a = X; + | ^ reference of mutable static + | + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior +help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer + | +LL | let ref _a = addr_of!(X); + | ~~~~~~~~~~~ + +error[E0796]: reference of mutable static is disallowed + --> $DIR/reference-of-mut-static-unsafe-fn.rs:15:21 + | +LL | let (_b, _c) = (&X, &Y); + | ^^ reference of mutable static + | + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior +help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer + | +LL | let (_b, _c) = (addr_of!(X), &Y); + | ~~~~~~~~~~~ + +error[E0796]: reference of mutable static is disallowed + --> $DIR/reference-of-mut-static-unsafe-fn.rs:15:25 + | +LL | let (_b, _c) = (&X, &Y); + | ^^ reference of mutable static + | + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior +help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer + | +LL | let (_b, _c) = (&X, addr_of!(Y)); + | ~~~~~~~~~~~ + +error[E0796]: reference of mutable static is disallowed + --> $DIR/reference-of-mut-static-unsafe-fn.rs:19:9 + | +LL | foo(&X); + | ^^ reference of mutable static + | + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior +help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer + | +LL | foo(addr_of!(X)); + | ~~~~~~~~~~~ + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0796`. diff --git a/tests/ui/static/reference-of-mut-static.e2021.stderr b/tests/ui/static/reference-of-mut-static.e2021.stderr new file mode 100644 index 0000000000000..77a6b3d304bdb --- /dev/null +++ b/tests/ui/static/reference-of-mut-static.e2021.stderr @@ -0,0 +1,91 @@ +error: shared reference of mutable static is discouraged + --> $DIR/reference-of-mut-static.rs:16:18 + | +LL | let _y = &X; + | ^^ shared reference of mutable static + | + = note: for more information, see issue #114447 <https://github.com/rust-lang/rust/issues/114447> + = note: reference of mutable static is a hard error from 2024 edition + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior +note: the lint level is defined here + --> $DIR/reference-of-mut-static.rs:6:9 + | +LL | #![deny(static_mut_ref)] + | ^^^^^^^^^^^^^^ +help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer + | +LL | let _y = addr_of!(X); + | ~~~~~~~~~~~ + +error: mutable reference of mutable static is discouraged + --> $DIR/reference-of-mut-static.rs:20:18 + | +LL | let _y = &mut X; + | ^^^^^^ mutable reference of mutable static + | + = note: for more information, see issue #114447 <https://github.com/rust-lang/rust/issues/114447> + = note: reference of mutable static is a hard error from 2024 edition + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior +help: mutable references are dangerous since if there's any other pointer or reference used for that static while the reference lives, that's UB; use `addr_of_mut!` instead to create a raw pointer + | +LL | let _y = addr_of_mut!(X); + | ~~~~~~~~~~~~~~~ + +error: shared reference of mutable static is discouraged + --> $DIR/reference-of-mut-static.rs:28:22 + | +LL | let ref _a = X; + | ^ shared reference of mutable static + | + = note: for more information, see issue #114447 <https://github.com/rust-lang/rust/issues/114447> + = note: reference of mutable static is a hard error from 2024 edition + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior +help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer + | +LL | let ref _a = addr_of!(X); + | ~~~~~~~~~~~ + +error: shared reference of mutable static is discouraged + --> $DIR/reference-of-mut-static.rs:32:25 + | +LL | let (_b, _c) = (&X, &Y); + | ^^ shared reference of mutable static + | + = note: for more information, see issue #114447 <https://github.com/rust-lang/rust/issues/114447> + = note: reference of mutable static is a hard error from 2024 edition + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior +help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer + | +LL | let (_b, _c) = (addr_of!(X), &Y); + | ~~~~~~~~~~~ + +error: shared reference of mutable static is discouraged + --> $DIR/reference-of-mut-static.rs:32:29 + | +LL | let (_b, _c) = (&X, &Y); + | ^^ shared reference of mutable static + | + = note: for more information, see issue #114447 <https://github.com/rust-lang/rust/issues/114447> + = note: reference of mutable static is a hard error from 2024 edition + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior +help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer + | +LL | let (_b, _c) = (&X, addr_of!(Y)); + | ~~~~~~~~~~~ + +error: shared reference of mutable static is discouraged + --> $DIR/reference-of-mut-static.rs:38:13 + | +LL | foo(&X); + | ^^ shared reference of mutable static + | + = note: for more information, see issue #114447 <https://github.com/rust-lang/rust/issues/114447> + = note: reference of mutable static is a hard error from 2024 edition + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior +help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer + | +LL | foo(addr_of!(X)); + | ~~~~~~~~~~~ + +error: aborting due to 6 previous errors + diff --git a/tests/ui/static/reference-of-mut-static.e2024.stderr b/tests/ui/static/reference-of-mut-static.e2024.stderr new file mode 100644 index 0000000000000..f445ec65a5d24 --- /dev/null +++ b/tests/ui/static/reference-of-mut-static.e2024.stderr @@ -0,0 +1,75 @@ +error[E0796]: reference of mutable static is disallowed + --> $DIR/reference-of-mut-static.rs:16:18 + | +LL | let _y = &X; + | ^^ reference of mutable static + | + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior +help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer + | +LL | let _y = addr_of!(X); + | ~~~~~~~~~~~ + +error[E0796]: reference of mutable static is disallowed + --> $DIR/reference-of-mut-static.rs:20:18 + | +LL | let _y = &mut X; + | ^^^^^^ reference of mutable static + | + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior +help: mutable references are dangerous since if there's any other pointer or reference used for that static while the reference lives, that's UB; use `addr_of_mut!` instead to create a raw pointer + | +LL | let _y = addr_of_mut!(X); + | ~~~~~~~~~~~~~~~ + +error[E0796]: reference of mutable static is disallowed + --> $DIR/reference-of-mut-static.rs:28:22 + | +LL | let ref _a = X; + | ^ reference of mutable static + | + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior +help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer + | +LL | let ref _a = addr_of!(X); + | ~~~~~~~~~~~ + +error[E0796]: reference of mutable static is disallowed + --> $DIR/reference-of-mut-static.rs:32:25 + | +LL | let (_b, _c) = (&X, &Y); + | ^^ reference of mutable static + | + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior +help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer + | +LL | let (_b, _c) = (addr_of!(X), &Y); + | ~~~~~~~~~~~ + +error[E0796]: reference of mutable static is disallowed + --> $DIR/reference-of-mut-static.rs:32:29 + | +LL | let (_b, _c) = (&X, &Y); + | ^^ reference of mutable static + | + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior +help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer + | +LL | let (_b, _c) = (&X, addr_of!(Y)); + | ~~~~~~~~~~~ + +error[E0796]: reference of mutable static is disallowed + --> $DIR/reference-of-mut-static.rs:38:13 + | +LL | foo(&X); + | ^^ reference of mutable static + | + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior +help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer + | +LL | foo(addr_of!(X)); + | ~~~~~~~~~~~ + +error: aborting due to 6 previous errors + +For more information about this error, try `rustc --explain E0796`. diff --git a/tests/ui/static/reference-of-mut-static.rs b/tests/ui/static/reference-of-mut-static.rs new file mode 100644 index 0000000000000..01a3b1fbd9b51 --- /dev/null +++ b/tests/ui/static/reference-of-mut-static.rs @@ -0,0 +1,50 @@ +// revisions: e2021 e2024 + +// [e2021] edition:2021 +// [e2024] compile-flags: --edition 2024 -Z unstable-options + +#![deny(static_mut_ref)] + +use std::ptr::{addr_of, addr_of_mut}; + +fn main() { + static mut X: i32 = 1; + + static mut Y: i32 = 1; + + unsafe { + let _y = &X; + //[e2024]~^ ERROR reference of mutable static is disallowed + //[e2021]~^^ ERROR shared reference of mutable static is discouraged [static_mut_ref] + + let _y = &mut X; + //[e2024]~^ ERROR reference of mutable static is disallowed + //[e2021]~^^ ERROR mutable reference of mutable static is discouraged [static_mut_ref] + + let _z = addr_of_mut!(X); + + let _p = addr_of!(X); + + let ref _a = X; + //[e2024]~^ ERROR reference of mutable static is disallowed + //[e2021]~^^ ERROR shared reference of mutable static is discouraged [static_mut_ref] + + let (_b, _c) = (&X, &Y); + //[e2024]~^ ERROR reference of mutable static is disallowed + //[e2021]~^^ ERROR shared reference of mutable static is discouraged [static_mut_ref] + //[e2024]~^^^ ERROR reference of mutable static is disallowed + //[e2021]~^^^^ ERROR shared reference of mutable static is discouraged [static_mut_ref] + + foo(&X); + //[e2024]~^ ERROR reference of mutable static is disallowed + //[e2021]~^^ ERROR shared reference of mutable static is discouraged [static_mut_ref] + + static mut Z: &[i32; 3] = &[0, 1, 2]; + + let _ = Z.len(); + let _ = Z[0]; + let _ = format!("{:?}", Z); + } +} + +fn foo<'a>(_x: &'a i32) {} From 56173611d65bae5eacef80d15799ba89161cd38b Mon Sep 17 00:00:00 2001 From: klensy <klensy@users.noreply.github.com> Date: Tue, 2 Jan 2024 22:36:01 +0300 Subject: [PATCH 07/17] don't reexport atomic::ordering via rustc_data_structures, use std import --- compiler/rustc_data_structures/src/sync.rs | 7 ++----- compiler/rustc_driver_impl/src/lib.rs | 3 +-- compiler/rustc_query_impl/src/plumbing.rs | 2 +- compiler/rustc_query_system/src/dep_graph/graph.rs | 14 +++++++------- compiler/rustc_session/src/session.rs | 6 ++---- 5 files changed, 13 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_data_structures/src/sync.rs b/compiler/rustc_data_structures/src/sync.rs index 43221d70e21cf..48edfba8da082 100644 --- a/compiler/rustc_data_structures/src/sync.rs +++ b/compiler/rustc_data_structures/src/sync.rs @@ -56,9 +56,6 @@ mod parallel; pub use parallel::scope; pub use parallel::{join, par_for_each_in, par_map, parallel_guard, try_par_for_each_in}; -pub use std::sync::atomic::Ordering; -pub use std::sync::atomic::Ordering::SeqCst; - pub use vec::{AppendOnlyIndexVec, AppendOnlyVec}; mod vec; @@ -67,8 +64,7 @@ mod freeze; pub use freeze::{FreezeLock, FreezeReadGuard, FreezeWriteGuard}; mod mode { - use super::Ordering; - use std::sync::atomic::AtomicU8; + use std::sync::atomic::{AtomicU8, Ordering}; const UNINITIALIZED: u8 = 0; const DYN_NOT_THREAD_SAFE: u8 = 1; @@ -113,6 +109,7 @@ cfg_match! { cfg(not(parallel_compiler)) => { use std::ops::Add; use std::cell::Cell; + use std::sync::atomic::Ordering; pub unsafe auto trait Send {} pub unsafe auto trait Sync {} diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index fd925b62702af..3add7e3c643ee 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -25,7 +25,6 @@ use rustc_codegen_ssa::{traits::CodegenBackend, CodegenErrors, CodegenResults}; use rustc_data_structures::profiling::{ get_resident_set_size, print_time_passes_entry, TimePassesFormat, }; -use rustc_data_structures::sync::SeqCst; use rustc_errors::registry::{InvalidErrorCode, Registry}; use rustc_errors::{markdown, ColorConfig}; use rustc_errors::{DiagCtxt, ErrorGuaranteed, PResult}; @@ -476,7 +475,7 @@ fn run_compiler( eprintln!( "Fuel used by {}: {}", sess.opts.unstable_opts.print_fuel.as_ref().unwrap(), - sess.print_fuel.load(SeqCst) + sess.print_fuel.load(Ordering::SeqCst) ); } diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs index f131a0f759320..fd7f1669ba456 100644 --- a/compiler/rustc_query_impl/src/plumbing.rs +++ b/compiler/rustc_query_impl/src/plumbing.rs @@ -69,7 +69,7 @@ impl QueryContext for QueryCtxt<'_> { fn next_job_id(self) -> QueryJobId { QueryJobId( NonZeroU64::new( - self.query_system.jobs.fetch_add(1, rustc_data_structures::sync::Ordering::Relaxed), + self.query_system.jobs.fetch_add(1, std::sync::atomic::Ordering::Relaxed), ) .unwrap(), ) diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs index 9b06823dfbafb..1f09de0ed70c7 100644 --- a/compiler/rustc_query_system/src/dep_graph/graph.rs +++ b/compiler/rustc_query_system/src/dep_graph/graph.rs @@ -4,7 +4,7 @@ use rustc_data_structures::profiling::{EventId, QueryInvocationId, SelfProfilerR use rustc_data_structures::sharded::{self, Sharded}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::steal::Steal; -use rustc_data_structures::sync::{AtomicU32, AtomicU64, Lock, Lrc, Ordering}; +use rustc_data_structures::sync::{AtomicU32, AtomicU64, Lock, Lrc}; use rustc_data_structures::unord::UnordMap; use rustc_index::IndexVec; use rustc_serialize::opaque::{FileEncodeResult, FileEncoder}; @@ -13,7 +13,7 @@ use std::collections::hash_map::Entry; use std::fmt::Debug; use std::hash::Hash; use std::marker::PhantomData; -use std::sync::atomic::Ordering::Relaxed; +use std::sync::atomic::Ordering; use super::query::DepGraphQuery; use super::serialized::{GraphEncoder, SerializedDepGraph, SerializedDepNodeIndex}; @@ -476,7 +476,7 @@ impl<D: Deps> DepGraph<D> { let task_deps = &mut *task_deps; if cfg!(debug_assertions) { - data.current.total_read_count.fetch_add(1, Relaxed); + data.current.total_read_count.fetch_add(1, Ordering::Relaxed); } // As long as we only have a low number of reads we can avoid doing a hash @@ -506,7 +506,7 @@ impl<D: Deps> DepGraph<D> { } } } else if cfg!(debug_assertions) { - data.current.total_duplicate_read_count.fetch_add(1, Relaxed); + data.current.total_duplicate_read_count.fetch_add(1, Ordering::Relaxed); } }) } @@ -976,8 +976,8 @@ impl<D: Deps> DepGraph<D> { pub fn print_incremental_info(&self) { if let Some(data) = &self.data { data.current.encoder.borrow().print_incremental_info( - data.current.total_read_count.load(Relaxed), - data.current.total_duplicate_read_count.load(Relaxed), + data.current.total_read_count.load(Ordering::Relaxed), + data.current.total_duplicate_read_count.load(Ordering::Relaxed), ) } } @@ -992,7 +992,7 @@ impl<D: Deps> DepGraph<D> { pub(crate) fn next_virtual_depnode_index(&self) -> DepNodeIndex { debug_assert!(self.data.is_none()); - let index = self.virtual_dep_node_index.fetch_add(1, Relaxed); + let index = self.virtual_dep_node_index.fetch_add(1, Ordering::Relaxed); DepNodeIndex::from_u32(index) } } diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index ce166ae352fd7..0ada48986349e 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -14,9 +14,7 @@ use rustc_data_structures::flock; use rustc_data_structures::fx::{FxHashMap, FxIndexSet}; use rustc_data_structures::jobserver::{self, Client}; use rustc_data_structures::profiling::{SelfProfiler, SelfProfilerRef}; -use rustc_data_structures::sync::{ - AtomicU64, DynSend, DynSync, Lock, Lrc, OneThread, Ordering::SeqCst, -}; +use rustc_data_structures::sync::{AtomicU64, DynSend, DynSync, Lock, Lrc, OneThread}; use rustc_errors::annotate_snippet_emitter_writer::AnnotateSnippetEmitter; use rustc_errors::emitter::{DynEmitter, HumanEmitter, HumanReadableErrorType}; use rustc_errors::json::JsonEmitter; @@ -44,7 +42,7 @@ use std::fmt; use std::ops::{Div, Mul}; use std::path::{Path, PathBuf}; use std::str::FromStr; -use std::sync::{atomic::AtomicBool, Arc}; +use std::sync::{atomic::AtomicBool, atomic::Ordering::SeqCst, Arc}; struct OptimizationFuel { /// If `-zfuel=crate=n` is specified, initially set to `n`, otherwise `0`. From a8aa6878f63e53a9b0cfee542e9765407e1ca0d6 Mon Sep 17 00:00:00 2001 From: Obei Sideg <obei.sideg@gmail.com> Date: Fri, 22 Dec 2023 15:12:01 +0300 Subject: [PATCH 08/17] Update test for `E0796` and `static_mut_ref` lint --- .../example/mini_core_hello_world.rs | 3 + .../example/mini_core_hello_world.rs | 3 + library/panic_unwind/src/seh.rs | 4 + library/std/src/panicking.rs | 2 + .../src/sys/common/thread_local/fast_local.rs | 2 + .../sys/common/thread_local/static_local.rs | 2 + library/std/src/thread/local.rs | 2 + src/tools/lint-docs/src/groups.rs | 1 + .../miri/tests/fail/tls/tls_static_dealloc.rs | 2 + src/tools/miri/tests/pass/static_mut.rs | 3 + src/tools/miri/tests/pass/tls/tls_static.rs | 2 + tests/ui/abi/statics/static-mut-foreign.rs | 2 + .../ui/abi/statics/static-mut-foreign.stderr | 31 +++++++ .../borrowck/borrowck-access-permissions.rs | 36 +++++--- .../borrowck-access-permissions.stderr | 33 +++++-- .../borrowck-unsafe-static-mutable-borrows.rs | 9 +- ...rowck-unsafe-static-mutable-borrows.stderr | 17 ++++ tests/ui/borrowck/issue-20801.rs | 1 + tests/ui/borrowck/issue-20801.stderr | 25 ++++-- ...ue-55492-borrowck-migrate-scans-parents.rs | 41 ++++++--- ...5492-borrowck-migrate-scans-parents.stderr | 75 +++++++++++++--- tests/ui/consts/const_let_assign2.rs | 1 + tests/ui/consts/const_let_assign2.stderr | 17 ++++ .../ui/consts/issue-17718-const-bad-values.rs | 3 +- .../issue-17718-const-bad-values.stderr | 17 +++- ..._refers_to_static_cross_crate.32bit.stderr | 77 +++++++++------- ..._refers_to_static_cross_crate.64bit.stderr | 77 +++++++++------- .../const_refers_to_static_cross_crate.rs | 22 +++-- .../consts/static_mut_containing_mut_ref.rs | 1 + .../static_mut_containing_mut_ref.stderr | 17 ++++ ...ic_mut_containing_mut_ref2.mut_refs.stderr | 23 ++++- .../consts/static_mut_containing_mut_ref2.rs | 10 ++- ...tatic_mut_containing_mut_ref2.stock.stderr | 23 ++++- .../issue-23338-ensure-param-drop-order.rs | 90 ++++++++++--------- ...issue-23338-ensure-param-drop-order.stderr | 17 ++++ tests/ui/error-codes/E0017.rs | 12 ++- tests/ui/error-codes/E0017.stderr | 29 ++++-- .../bare_type.rs} | 9 +- .../issues/issue-23611-enum-swap-in-drop.rs | 44 ++++----- .../issue-23611-enum-swap-in-drop.stderr | 17 ++++ ...ead-local-static-mut-borrow-outlives-fn.rs | 5 +- ...local-static-mut-borrow-outlives-fn.stderr | 17 ++++ .../reference-of-mut-static-safe.e2021.stderr | 4 +- tests/ui/static/safe-extern-statics-mut.rs | 2 + .../ui/static/safe-extern-statics-mut.stderr | 35 +++++++- tests/ui/statics/issue-15261.rs | 3 +- tests/ui/statics/issue-15261.stderr | 17 ++++ tests/ui/statics/static-mut-xc.rs | 3 +- tests/ui/statics/static-mut-xc.stderr | 31 +++++++ tests/ui/statics/static-recursive.rs | 27 +++--- tests/ui/statics/static-recursive.stderr | 17 ++++ tests/ui/thread-local/thread-local-static.rs | 3 +- .../thread-local/thread-local-static.stderr | 17 +++- .../thread-local-static.thir.stderr | 59 ++++++++++++ 54 files changed, 805 insertions(+), 237 deletions(-) create mode 100644 tests/ui/abi/statics/static-mut-foreign.stderr create mode 100644 tests/ui/borrowck/borrowck-unsafe-static-mutable-borrows.stderr create mode 100644 tests/ui/consts/const_let_assign2.stderr create mode 100644 tests/ui/consts/static_mut_containing_mut_ref.stderr create mode 100644 tests/ui/drop/issue-23338-ensure-param-drop-order.stderr rename tests/ui/{issues/issue-20616.rs => impl-header-lifetime-elision/bare_type.rs} (82%) create mode 100644 tests/ui/issues/issue-23611-enum-swap-in-drop.stderr create mode 100644 tests/ui/nll/borrowck-thread-local-static-mut-borrow-outlives-fn.stderr create mode 100644 tests/ui/statics/issue-15261.stderr create mode 100644 tests/ui/statics/static-mut-xc.stderr create mode 100644 tests/ui/statics/static-recursive.stderr create mode 100644 tests/ui/thread-local/thread-local-static.thir.stderr diff --git a/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs b/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs index a1cdf31c68a00..2a7b1107ffcaa 100644 --- a/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs +++ b/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs @@ -111,6 +111,9 @@ fn start<T: Termination + 'static>( } static mut NUM: u8 = 6 * 7; + +// FIXME: Use `SyncUnsafeCell` instead of allowing `static_mut_ref` lint +#[allow(static_mut_ref)] static NUM_REF: &'static u8 = unsafe { &NUM }; unsafe fn zeroed<T>() -> T { diff --git a/compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs b/compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs index 40a1ad22c0e13..9827e299f2a31 100644 --- a/compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs +++ b/compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs @@ -98,6 +98,9 @@ fn start<T: Termination + 'static>( } static mut NUM: u8 = 6 * 7; + +// FIXME: Use `SyncUnsafeCell` instead of allowing `static_mut_ref` lint +#[allow(static_mut_ref)] static NUM_REF: &'static u8 = unsafe { &NUM }; macro_rules! assert { diff --git a/library/panic_unwind/src/seh.rs b/library/panic_unwind/src/seh.rs index 99db00e549066..ccae406cc286c 100644 --- a/library/panic_unwind/src/seh.rs +++ b/library/panic_unwind/src/seh.rs @@ -261,6 +261,8 @@ cfg_if::cfg_if! { } } +// FIXME: Use `SyncUnsafeCell` instead of allowing `static_mut_ref` lint +#[cfg_attr(not(bootstrap), allow(static_mut_ref))] pub unsafe fn panic(data: Box<dyn Any + Send>) -> u32 { use core::intrinsics::atomic_store_seqcst; @@ -322,6 +324,8 @@ pub unsafe fn panic(data: Box<dyn Any + Send>) -> u32 { _CxxThrowException(throw_ptr, &mut THROW_INFO as *mut _ as *mut _); } +// FIXME: Use `SyncUnsafeCell` instead of allowing `static_mut_ref` lint +#[cfg_attr(not(bootstrap), allow(static_mut_ref))] pub unsafe fn cleanup(payload: *mut u8) -> Box<dyn Any + Send> { // A null payload here means that we got here from the catch (...) of // __rust_try. This happens when a non-Rust foreign exception is caught. diff --git a/library/std/src/panicking.rs b/library/std/src/panicking.rs index 66b4ec37c8ec5..c80f15d8a611b 100644 --- a/library/std/src/panicking.rs +++ b/library/std/src/panicking.rs @@ -337,6 +337,8 @@ pub mod panic_count { #[doc(hidden)] #[cfg(not(feature = "panic_immediate_abort"))] #[unstable(feature = "update_panic_count", issue = "none")] +// FIXME: Use `SyncUnsafeCell` instead of allowing `static_mut_ref` lint +#[cfg_attr(not(bootstrap), allow(static_mut_ref))] pub mod panic_count { use crate::cell::Cell; use crate::sync::atomic::{AtomicUsize, Ordering}; diff --git a/library/std/src/sys/common/thread_local/fast_local.rs b/library/std/src/sys/common/thread_local/fast_local.rs index c0a9619bf7bfa..9206588be064e 100644 --- a/library/std/src/sys/common/thread_local/fast_local.rs +++ b/library/std/src/sys/common/thread_local/fast_local.rs @@ -13,6 +13,8 @@ pub macro thread_local_inner { (@key $t:ty, const $init:expr) => {{ #[inline] #[deny(unsafe_op_in_unsafe_fn)] + // FIXME: Use `SyncUnsafeCell` instead of allowing `static_mut_ref` lint + #[cfg_attr(not(bootstrap), allow(static_mut_ref))] unsafe fn __getit( _init: $crate::option::Option<&mut $crate::option::Option<$t>>, ) -> $crate::option::Option<&'static $t> { diff --git a/library/std/src/sys/common/thread_local/static_local.rs b/library/std/src/sys/common/thread_local/static_local.rs index 5cb6c541a0ec5..51cba66fad76d 100644 --- a/library/std/src/sys/common/thread_local/static_local.rs +++ b/library/std/src/sys/common/thread_local/static_local.rs @@ -11,6 +11,8 @@ pub macro thread_local_inner { (@key $t:ty, const $init:expr) => {{ #[inline] // see comments below #[deny(unsafe_op_in_unsafe_fn)] + // FIXME: Use `SyncUnsafeCell` instead of allowing `static_mut_ref` lint + #[cfg_attr(not(bootstrap), allow(static_mut_ref))] unsafe fn __getit( _init: $crate::option::Option<&mut $crate::option::Option<$t>>, ) -> $crate::option::Option<&'static $t> { diff --git a/library/std/src/thread/local.rs b/library/std/src/thread/local.rs index 9cf37b0e6347c..338567777f753 100644 --- a/library/std/src/thread/local.rs +++ b/library/std/src/thread/local.rs @@ -180,6 +180,8 @@ impl<T: 'static> fmt::Debug for LocalKey<T> { #[stable(feature = "rust1", since = "1.0.0")] #[cfg_attr(not(test), rustc_diagnostic_item = "thread_local_macro")] #[allow_internal_unstable(thread_local_internals)] +// FIXME: Use `SyncUnsafeCell` instead of allowing `static_mut_ref` lint +#[cfg_attr(not(bootstrap), allow(static_mut_ref))] macro_rules! thread_local { // empty (base case for the recursion) () => {}; diff --git a/src/tools/lint-docs/src/groups.rs b/src/tools/lint-docs/src/groups.rs index 5be8ef7996bb2..c5cd30ccc3437 100644 --- a/src/tools/lint-docs/src/groups.rs +++ b/src/tools/lint-docs/src/groups.rs @@ -15,6 +15,7 @@ static GROUP_DESCRIPTIONS: &[(&str, &str)] = &[ ("future-incompatible", "Lints that detect code that has future-compatibility problems"), ("rust-2018-compatibility", "Lints used to transition code from the 2015 edition to 2018"), ("rust-2021-compatibility", "Lints used to transition code from the 2018 edition to 2021"), + ("rust-2024-compatibility", "Lints used to transition code from the 2021 edition to 2024"), ]; type LintGroups = BTreeMap<String, BTreeSet<String>>; diff --git a/src/tools/miri/tests/fail/tls/tls_static_dealloc.rs b/src/tools/miri/tests/fail/tls/tls_static_dealloc.rs index d5e6d37226ab3..762a8d85314f2 100644 --- a/src/tools/miri/tests/fail/tls/tls_static_dealloc.rs +++ b/src/tools/miri/tests/fail/tls/tls_static_dealloc.rs @@ -1,6 +1,8 @@ //! Ensure that thread-local statics get deallocated when the thread dies. #![feature(thread_local)] +// FIXME: Use `SyncUnsafeCell` instead of allowing `static_mut_ref` lint +#![allow(static_mut_ref)] #[thread_local] static mut TLS: u8 = 0; diff --git a/src/tools/miri/tests/pass/static_mut.rs b/src/tools/miri/tests/pass/static_mut.rs index 218b02525bd55..c1e58b70adb0b 100644 --- a/src/tools/miri/tests/pass/static_mut.rs +++ b/src/tools/miri/tests/pass/static_mut.rs @@ -1,4 +1,7 @@ static mut FOO: i32 = 42; + +// FIXME: Use `SyncUnsafeCell` instead of allowing `static_mut_ref` lint +#[allow(static_mut_ref)] static BAR: Foo = Foo(unsafe { &FOO as *const _ }); #[allow(dead_code)] diff --git a/src/tools/miri/tests/pass/tls/tls_static.rs b/src/tools/miri/tests/pass/tls/tls_static.rs index fc4c8a283ddb2..9be00af47aa35 100644 --- a/src/tools/miri/tests/pass/tls/tls_static.rs +++ b/src/tools/miri/tests/pass/tls/tls_static.rs @@ -8,6 +8,8 @@ //! test, we also check that thread-locals act as per-thread statics. #![feature(thread_local)] +// FIXME: Use `SyncUnsafeCell` instead of allowing `static_mut_ref` lint +#![allow(static_mut_ref)] use std::thread; diff --git a/tests/ui/abi/statics/static-mut-foreign.rs b/tests/ui/abi/statics/static-mut-foreign.rs index ecd8ee94a01e3..eb732e7c2c31f 100644 --- a/tests/ui/abi/statics/static-mut-foreign.rs +++ b/tests/ui/abi/statics/static-mut-foreign.rs @@ -33,7 +33,9 @@ unsafe fn run() { rust_dbg_static_mut = -3; assert_eq!(rust_dbg_static_mut, -3); static_bound(&rust_dbg_static_mut); + //~^ WARN shared reference of mutable static is discouraged [static_mut_ref] static_bound_set(&mut rust_dbg_static_mut); + //~^ WARN mutable reference of mutable static is discouraged [static_mut_ref] } pub fn main() { diff --git a/tests/ui/abi/statics/static-mut-foreign.stderr b/tests/ui/abi/statics/static-mut-foreign.stderr new file mode 100644 index 0000000000000..144ac056f87e4 --- /dev/null +++ b/tests/ui/abi/statics/static-mut-foreign.stderr @@ -0,0 +1,31 @@ +warning: shared reference of mutable static is discouraged + --> $DIR/static-mut-foreign.rs:35:18 + | +LL | static_bound(&rust_dbg_static_mut); + | ^^^^^^^^^^^^^^^^^^^^ shared reference of mutable static + | + = note: for more information, see issue #114447 <https://github.com/rust-lang/rust/issues/114447> + = note: reference of mutable static is a hard error from 2024 edition + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior + = note: `#[warn(static_mut_ref)]` on by default +help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer + | +LL | static_bound(addr_of!(rust_dbg_static_mut)); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +warning: mutable reference of mutable static is discouraged + --> $DIR/static-mut-foreign.rs:37:22 + | +LL | static_bound_set(&mut rust_dbg_static_mut); + | ^^^^^^^^^^^^^^^^^^^^^^^^ mutable reference of mutable static + | + = note: for more information, see issue #114447 <https://github.com/rust-lang/rust/issues/114447> + = note: reference of mutable static is a hard error from 2024 edition + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior +help: mutable references are dangerous since if there's any other pointer or reference used for that static while the reference lives, that's UB; use `addr_of_mut!` instead to create a raw pointer + | +LL | static_bound_set(addr_of_mut!(rust_dbg_static_mut)); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +warning: 2 warnings emitted + diff --git a/tests/ui/borrowck/borrowck-access-permissions.rs b/tests/ui/borrowck/borrowck-access-permissions.rs index 469ad508b0e77..1638644103ba4 100644 --- a/tests/ui/borrowck/borrowck-access-permissions.rs +++ b/tests/ui/borrowck/borrowck-access-permissions.rs @@ -1,21 +1,27 @@ -static static_x : i32 = 1; -static mut static_x_mut : i32 = 1; +static static_x: i32 = 1; +static mut static_x_mut: i32 = 1; fn main() { let x = 1; let mut x_mut = 1; - { // borrow of local + { + // borrow of local let _y1 = &mut x; //~ ERROR [E0596] let _y2 = &mut x_mut; // No error } - { // borrow of static + { + // borrow of static let _y1 = &mut static_x; //~ ERROR [E0596] - unsafe { let _y2 = &mut static_x_mut; } // No error + unsafe { + let _y2 = &mut static_x_mut; + //~^ WARN mutable reference of mutable static is discouraged [static_mut_ref] + } } - { // borrow of deref to box + { + // borrow of deref to box let box_x = Box::new(1); let mut box_x_mut = Box::new(1); @@ -23,7 +29,8 @@ fn main() { let _y2 = &mut *box_x_mut; // No error } - { // borrow of deref to reference + { + // borrow of deref to reference let ref_x = &x; let ref_x_mut = &mut x_mut; @@ -31,9 +38,10 @@ fn main() { let _y2 = &mut *ref_x_mut; // No error } - { // borrow of deref to pointer - let ptr_x : *const _ = &x; - let ptr_mut_x : *mut _ = &mut x_mut; + { + // borrow of deref to pointer + let ptr_x: *const _ = &x; + let ptr_mut_x: *mut _ = &mut x_mut; unsafe { let _y1 = &mut *ptr_x; //~ ERROR [E0596] @@ -41,8 +49,12 @@ fn main() { } } - { // borrowing mutably through an immutable reference - struct Foo<'a> { f: &'a mut i32, g: &'a i32 }; + { + // borrowing mutably through an immutable reference + struct Foo<'a> { + f: &'a mut i32, + g: &'a i32, + }; let mut foo = Foo { f: &mut x_mut, g: &x }; let foo_ref = &foo; let _y = &mut *foo_ref.f; //~ ERROR [E0596] diff --git a/tests/ui/borrowck/borrowck-access-permissions.stderr b/tests/ui/borrowck/borrowck-access-permissions.stderr index c161e2d95b43a..93d92295dd9b6 100644 --- a/tests/ui/borrowck/borrowck-access-permissions.stderr +++ b/tests/ui/borrowck/borrowck-access-permissions.stderr @@ -1,5 +1,20 @@ +warning: mutable reference of mutable static is discouraged + --> $DIR/borrowck-access-permissions.rs:18:23 + | +LL | let _y2 = &mut static_x_mut; + | ^^^^^^^^^^^^^^^^^ mutable reference of mutable static + | + = note: for more information, see issue #114447 <https://github.com/rust-lang/rust/issues/114447> + = note: reference of mutable static is a hard error from 2024 edition + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior + = note: `#[warn(static_mut_ref)]` on by default +help: mutable references are dangerous since if there's any other pointer or reference used for that static while the reference lives, that's UB; use `addr_of_mut!` instead to create a raw pointer + | +LL | let _y2 = addr_of_mut!(static_x_mut); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~ + error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable - --> $DIR/borrowck-access-permissions.rs:9:19 + --> $DIR/borrowck-access-permissions.rs:10:19 | LL | let _y1 = &mut x; | ^^^^^^ cannot borrow as mutable @@ -10,13 +25,13 @@ LL | let mut x = 1; | +++ error[E0596]: cannot borrow immutable static item `static_x` as mutable - --> $DIR/borrowck-access-permissions.rs:14:19 + --> $DIR/borrowck-access-permissions.rs:16:19 | LL | let _y1 = &mut static_x; | ^^^^^^^^^^^^^ cannot borrow as mutable error[E0596]: cannot borrow `*box_x` as mutable, as `box_x` is not declared as mutable - --> $DIR/borrowck-access-permissions.rs:22:19 + --> $DIR/borrowck-access-permissions.rs:28:19 | LL | let _y1 = &mut *box_x; | ^^^^^^^^^^^ cannot borrow as mutable @@ -27,7 +42,7 @@ LL | let mut box_x = Box::new(1); | +++ error[E0596]: cannot borrow `*ref_x` as mutable, as it is behind a `&` reference - --> $DIR/borrowck-access-permissions.rs:30:19 + --> $DIR/borrowck-access-permissions.rs:37:19 | LL | let _y1 = &mut *ref_x; | ^^^^^^^^^^^ `ref_x` is a `&` reference, so the data it refers to cannot be borrowed as mutable @@ -38,18 +53,18 @@ LL | let ref_x = &mut x; | +++ error[E0596]: cannot borrow `*ptr_x` as mutable, as it is behind a `*const` pointer - --> $DIR/borrowck-access-permissions.rs:39:23 + --> $DIR/borrowck-access-permissions.rs:47:23 | LL | let _y1 = &mut *ptr_x; | ^^^^^^^^^^^ `ptr_x` is a `*const` pointer, so the data it refers to cannot be borrowed as mutable | help: consider changing this to be a mutable pointer | -LL | let ptr_x : *const _ = &mut x; - | +++ +LL | let ptr_x: *const _ = &mut x; + | +++ error[E0596]: cannot borrow `*foo_ref.f` as mutable, as it is behind a `&` reference - --> $DIR/borrowck-access-permissions.rs:48:18 + --> $DIR/borrowck-access-permissions.rs:60:18 | LL | let _y = &mut *foo_ref.f; | ^^^^^^^^^^^^^^^ `foo_ref` is a `&` reference, so the data it refers to cannot be borrowed as mutable @@ -59,6 +74,6 @@ help: consider changing this to be a mutable reference LL | let foo_ref = &mut foo; | +++ -error: aborting due to 6 previous errors +error: aborting due to 6 previous errors; 1 warning emitted For more information about this error, try `rustc --explain E0596`. diff --git a/tests/ui/borrowck/borrowck-unsafe-static-mutable-borrows.rs b/tests/ui/borrowck/borrowck-unsafe-static-mutable-borrows.rs index adc7dfd541f48..1bf079e24cae4 100644 --- a/tests/ui/borrowck/borrowck-unsafe-static-mutable-borrows.rs +++ b/tests/ui/borrowck/borrowck-unsafe-static-mutable-borrows.rs @@ -2,17 +2,22 @@ // Test file taken from issue 45129 (https://github.com/rust-lang/rust/issues/45129) -struct Foo { x: [usize; 2] } +struct Foo { + x: [usize; 2], +} static mut SFOO: Foo = Foo { x: [23, 32] }; impl Foo { - fn x(&mut self) -> &mut usize { &mut self.x[0] } + fn x(&mut self) -> &mut usize { + &mut self.x[0] + } } fn main() { unsafe { let sfoo: *mut Foo = &mut SFOO; + //~^ WARN mutable reference of mutable static is discouraged [static_mut_ref] let x = (*sfoo).x(); (*sfoo).x[1] += 1; *x += 1; diff --git a/tests/ui/borrowck/borrowck-unsafe-static-mutable-borrows.stderr b/tests/ui/borrowck/borrowck-unsafe-static-mutable-borrows.stderr new file mode 100644 index 0000000000000..7a3824f79a4c2 --- /dev/null +++ b/tests/ui/borrowck/borrowck-unsafe-static-mutable-borrows.stderr @@ -0,0 +1,17 @@ +warning: mutable reference of mutable static is discouraged + --> $DIR/borrowck-unsafe-static-mutable-borrows.rs:19:30 + | +LL | let sfoo: *mut Foo = &mut SFOO; + | ^^^^^^^^^ mutable reference of mutable static + | + = note: for more information, see issue #114447 <https://github.com/rust-lang/rust/issues/114447> + = note: reference of mutable static is a hard error from 2024 edition + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior + = note: `#[warn(static_mut_ref)]` on by default +help: mutable references are dangerous since if there's any other pointer or reference used for that static while the reference lives, that's UB; use `addr_of_mut!` instead to create a raw pointer + | +LL | let sfoo: *mut Foo = addr_of_mut!(SFOO); + | ~~~~~~~~~~~~~~~~~~ + +warning: 1 warning emitted + diff --git a/tests/ui/borrowck/issue-20801.rs b/tests/ui/borrowck/issue-20801.rs index c3f136f2876b6..ec83af5d5dfc6 100644 --- a/tests/ui/borrowck/issue-20801.rs +++ b/tests/ui/borrowck/issue-20801.rs @@ -12,6 +12,7 @@ fn imm_ref() -> &'static T { fn mut_ref() -> &'static mut T { unsafe { &mut GLOBAL_MUT_T } + //~^ WARN mutable reference of mutable static is discouraged [static_mut_ref] } fn mut_ptr() -> *mut T { diff --git a/tests/ui/borrowck/issue-20801.stderr b/tests/ui/borrowck/issue-20801.stderr index 215bf01006369..b2bee2d880394 100644 --- a/tests/ui/borrowck/issue-20801.stderr +++ b/tests/ui/borrowck/issue-20801.stderr @@ -1,5 +1,20 @@ +warning: mutable reference of mutable static is discouraged + --> $DIR/issue-20801.rs:14:14 + | +LL | unsafe { &mut GLOBAL_MUT_T } + | ^^^^^^^^^^^^^^^^^ mutable reference of mutable static + | + = note: for more information, see issue #114447 <https://github.com/rust-lang/rust/issues/114447> + = note: reference of mutable static is a hard error from 2024 edition + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior + = note: `#[warn(static_mut_ref)]` on by default +help: mutable references are dangerous since if there's any other pointer or reference used for that static while the reference lives, that's UB; use `addr_of_mut!` instead to create a raw pointer + | +LL | unsafe { addr_of_mut!(GLOBAL_MUT_T) } + | ~~~~~~~~~~~~~~~~~~~~~~~~~~ + error[E0507]: cannot move out of a mutable reference - --> $DIR/issue-20801.rs:26:22 + --> $DIR/issue-20801.rs:27:22 | LL | let a = unsafe { *mut_ref() }; | ^^^^^^^^^^ move occurs because value has type `T`, which does not implement the `Copy` trait @@ -11,7 +26,7 @@ LL + let a = unsafe { mut_ref() }; | error[E0507]: cannot move out of a shared reference - --> $DIR/issue-20801.rs:29:22 + --> $DIR/issue-20801.rs:30:22 | LL | let b = unsafe { *imm_ref() }; | ^^^^^^^^^^ move occurs because value has type `T`, which does not implement the `Copy` trait @@ -23,7 +38,7 @@ LL + let b = unsafe { imm_ref() }; | error[E0507]: cannot move out of a raw pointer - --> $DIR/issue-20801.rs:32:22 + --> $DIR/issue-20801.rs:33:22 | LL | let c = unsafe { *mut_ptr() }; | ^^^^^^^^^^ move occurs because value has type `T`, which does not implement the `Copy` trait @@ -35,7 +50,7 @@ LL + let c = unsafe { mut_ptr() }; | error[E0507]: cannot move out of a raw pointer - --> $DIR/issue-20801.rs:35:22 + --> $DIR/issue-20801.rs:36:22 | LL | let d = unsafe { *const_ptr() }; | ^^^^^^^^^^^^ move occurs because value has type `T`, which does not implement the `Copy` trait @@ -46,6 +61,6 @@ LL - let d = unsafe { *const_ptr() }; LL + let d = unsafe { const_ptr() }; | -error: aborting due to 4 previous errors +error: aborting due to 4 previous errors; 1 warning emitted For more information about this error, try `rustc --explain E0507`. diff --git a/tests/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.rs b/tests/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.rs index b3cce1b3a0611..9b172b4131911 100644 --- a/tests/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.rs +++ b/tests/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.rs @@ -8,7 +8,10 @@ mod borrowck_closures_unique { static mut Y: isize = 3; let mut c1 = |y: &'static mut isize| x = y; //~^ ERROR is not declared as mutable - unsafe { c1(&mut Y); } + unsafe { + c1(&mut Y); + //~^ WARN mutable reference of mutable static is discouraged [static_mut_ref] + } } } @@ -17,36 +20,50 @@ mod borrowck_closures_unique_grandparent { static mut Z: isize = 3; let mut c1 = |z: &'static mut isize| { let mut c2 = |y: &'static mut isize| x = y; - //~^ ERROR is not declared as mutable + //~^ ERROR is not declared as mutable c2(z); }; - unsafe { c1(&mut Z); } + unsafe { + c1(&mut Z); + //~^ WARN mutable reference of mutable static is discouraged [static_mut_ref] + } } } // adapted from mutability_errors.rs mod mutability_errors { pub fn capture_assign_whole(x: (i32,)) { - || { x = (1,); }; - //~^ ERROR is not declared as mutable + || { + x = (1,); + //~^ ERROR is not declared as mutable + }; } pub fn capture_assign_part(x: (i32,)) { - || { x.0 = 1; }; - //~^ ERROR is not declared as mutable + || { + x.0 = 1; + //~^ ERROR is not declared as mutable + }; } pub fn capture_reborrow_whole(x: (i32,)) { - || { &mut x; }; - //~^ ERROR is not declared as mutable + || { + &mut x; + //~^ ERROR is not declared as mutable + }; } pub fn capture_reborrow_part(x: (i32,)) { - || { &mut x.0; }; - //~^ ERROR is not declared as mutable + || { + &mut x.0; + //~^ ERROR is not declared as mutable + }; } } fn main() { static mut X: isize = 2; - unsafe { borrowck_closures_unique::e(&mut X); } + unsafe { + borrowck_closures_unique::e(&mut X); + //~^ WARN mutable reference of mutable static is discouraged [static_mut_ref] + } mutability_errors::capture_assign_whole((1000,)); mutability_errors::capture_assign_part((2000,)); diff --git a/tests/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.stderr b/tests/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.stderr index 4c299cdc455ac..e4e4947fce1c1 100644 --- a/tests/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.stderr +++ b/tests/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.stderr @@ -1,3 +1,46 @@ +warning: mutable reference of mutable static is discouraged + --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:12:16 + | +LL | c1(&mut Y); + | ^^^^^^ mutable reference of mutable static + | + = note: for more information, see issue #114447 <https://github.com/rust-lang/rust/issues/114447> + = note: reference of mutable static is a hard error from 2024 edition + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior + = note: `#[warn(static_mut_ref)]` on by default +help: mutable references are dangerous since if there's any other pointer or reference used for that static while the reference lives, that's UB; use `addr_of_mut!` instead to create a raw pointer + | +LL | c1(addr_of_mut!(Y)); + | ~~~~~~~~~~~~~~~ + +warning: mutable reference of mutable static is discouraged + --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:27:16 + | +LL | c1(&mut Z); + | ^^^^^^ mutable reference of mutable static + | + = note: for more information, see issue #114447 <https://github.com/rust-lang/rust/issues/114447> + = note: reference of mutable static is a hard error from 2024 edition + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior +help: mutable references are dangerous since if there's any other pointer or reference used for that static while the reference lives, that's UB; use `addr_of_mut!` instead to create a raw pointer + | +LL | c1(addr_of_mut!(Z)); + | ~~~~~~~~~~~~~~~ + +warning: mutable reference of mutable static is discouraged + --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:64:37 + | +LL | borrowck_closures_unique::e(&mut X); + | ^^^^^^ mutable reference of mutable static + | + = note: for more information, see issue #114447 <https://github.com/rust-lang/rust/issues/114447> + = note: reference of mutable static is a hard error from 2024 edition + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior +help: mutable references are dangerous since if there's any other pointer or reference used for that static while the reference lives, that's UB; use `addr_of_mut!` instead to create a raw pointer + | +LL | borrowck_closures_unique::e(addr_of_mut!(X)); + | ~~~~~~~~~~~~~~~ + error[E0594]: cannot assign to `x`, as it is not declared as mutable --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:9:46 | @@ -8,7 +51,7 @@ LL | let mut c1 = |y: &'static mut isize| x = y; | ^^^^^ cannot assign error[E0594]: cannot assign to `x`, as it is not declared as mutable - --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:19:50 + --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:22:50 | LL | pub fn ee(x: &'static mut isize) { | - help: consider changing this to be mutable: `mut x` @@ -17,38 +60,42 @@ LL | let mut c2 = |y: &'static mut isize| x = y; | ^^^^^ cannot assign error[E0594]: cannot assign to `x`, as it is not declared as mutable - --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:30:14 + --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:37:13 | LL | pub fn capture_assign_whole(x: (i32,)) { | - help: consider changing this to be mutable: `mut x` -LL | || { x = (1,); }; - | ^^^^^^^^ cannot assign +LL | || { +LL | x = (1,); + | ^^^^^^^^ cannot assign error[E0594]: cannot assign to `x.0`, as `x` is not declared as mutable - --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:34:14 + --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:43:13 | LL | pub fn capture_assign_part(x: (i32,)) { | - help: consider changing this to be mutable: `mut x` -LL | || { x.0 = 1; }; - | ^^^^^^^ cannot assign +LL | || { +LL | x.0 = 1; + | ^^^^^^^ cannot assign error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable - --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:38:14 + --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:49:13 | LL | pub fn capture_reborrow_whole(x: (i32,)) { | - help: consider changing this to be mutable: `mut x` -LL | || { &mut x; }; - | ^^^^^^ cannot borrow as mutable +LL | || { +LL | &mut x; + | ^^^^^^ cannot borrow as mutable error[E0596]: cannot borrow `x.0` as mutable, as `x` is not declared as mutable - --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:42:14 + --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:55:13 | LL | pub fn capture_reborrow_part(x: (i32,)) { | - help: consider changing this to be mutable: `mut x` -LL | || { &mut x.0; }; - | ^^^^^^^^ cannot borrow as mutable +LL | || { +LL | &mut x.0; + | ^^^^^^^^ cannot borrow as mutable -error: aborting due to 6 previous errors +error: aborting due to 6 previous errors; 3 warnings emitted Some errors have detailed explanations: E0594, E0596. For more information about an error, try `rustc --explain E0594`. diff --git a/tests/ui/consts/const_let_assign2.rs b/tests/ui/consts/const_let_assign2.rs index 28265c85dd1f1..1c7afe0e3d6cb 100644 --- a/tests/ui/consts/const_let_assign2.rs +++ b/tests/ui/consts/const_let_assign2.rs @@ -16,6 +16,7 @@ static mut BB: AA = AA::new(); fn main() { let ptr = unsafe { &mut BB }; + //~^ WARN mutable reference of mutable static is discouraged [static_mut_ref] for a in ptr.data.iter() { println!("{}", a); } diff --git a/tests/ui/consts/const_let_assign2.stderr b/tests/ui/consts/const_let_assign2.stderr new file mode 100644 index 0000000000000..2764153a8a590 --- /dev/null +++ b/tests/ui/consts/const_let_assign2.stderr @@ -0,0 +1,17 @@ +warning: mutable reference of mutable static is discouraged + --> $DIR/const_let_assign2.rs:18:24 + | +LL | let ptr = unsafe { &mut BB }; + | ^^^^^^^ mutable reference of mutable static + | + = note: for more information, see issue #114447 <https://github.com/rust-lang/rust/issues/114447> + = note: reference of mutable static is a hard error from 2024 edition + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior + = note: `#[warn(static_mut_ref)]` on by default +help: mutable references are dangerous since if there's any other pointer or reference used for that static while the reference lives, that's UB; use `addr_of_mut!` instead to create a raw pointer + | +LL | let ptr = unsafe { addr_of_mut!(BB) }; + | ~~~~~~~~~~~~~~~~ + +warning: 1 warning emitted + diff --git a/tests/ui/consts/issue-17718-const-bad-values.rs b/tests/ui/consts/issue-17718-const-bad-values.rs index 62bbb3b569c37..4fedc48452bec 100644 --- a/tests/ui/consts/issue-17718-const-bad-values.rs +++ b/tests/ui/consts/issue-17718-const-bad-values.rs @@ -3,7 +3,8 @@ const C1: &'static mut [usize] = &mut []; static mut S: usize = 3; const C2: &'static mut usize = unsafe { &mut S }; -//~^ ERROR: constants cannot refer to statics +//~^ WARN mutable reference of mutable static is discouraged [static_mut_ref] +//~^^ ERROR: constants cannot refer to statics //~| ERROR: constants cannot refer to statics fn main() {} diff --git a/tests/ui/consts/issue-17718-const-bad-values.stderr b/tests/ui/consts/issue-17718-const-bad-values.stderr index 405c2195dec4f..2dc91f52669e7 100644 --- a/tests/ui/consts/issue-17718-const-bad-values.stderr +++ b/tests/ui/consts/issue-17718-const-bad-values.stderr @@ -1,3 +1,18 @@ +warning: mutable reference of mutable static is discouraged + --> $DIR/issue-17718-const-bad-values.rs:5:41 + | +LL | const C2: &'static mut usize = unsafe { &mut S }; + | ^^^^^^ mutable reference of mutable static + | + = note: for more information, see issue #114447 <https://github.com/rust-lang/rust/issues/114447> + = note: reference of mutable static is a hard error from 2024 edition + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior + = note: `#[warn(static_mut_ref)]` on by default +help: mutable references are dangerous since if there's any other pointer or reference used for that static while the reference lives, that's UB; use `addr_of_mut!` instead to create a raw pointer + | +LL | const C2: &'static mut usize = unsafe { addr_of_mut!(S) }; + | ~~~~~~~~~~~~~~~ + error[E0764]: mutable references are not allowed in the final value of constants --> $DIR/issue-17718-const-bad-values.rs:1:34 | @@ -21,7 +36,7 @@ LL | const C2: &'static mut usize = unsafe { &mut S }; = help: consider extracting the value of the `static` to a `const`, and referring to that = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error: aborting due to 3 previous errors +error: aborting due to 3 previous errors; 1 warning emitted Some errors have detailed explanations: E0013, E0764. For more information about an error, try `rustc --explain E0013`. diff --git a/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.32bit.stderr b/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.32bit.stderr index 7960648ce3a19..ed9db67542641 100644 --- a/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.32bit.stderr +++ b/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.32bit.stderr @@ -1,3 +1,18 @@ +warning: shared reference of mutable static is discouraged + --> $DIR/const_refers_to_static_cross_crate.rs:13:14 + | +LL | unsafe { &static_cross_crate::ZERO } + | ^^^^^^^^^^^^^^^^^^^^^^^^^ shared reference of mutable static + | + = note: for more information, see issue #114447 <https://github.com/rust-lang/rust/issues/114447> + = note: reference of mutable static is a hard error from 2024 edition + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior + = note: `#[warn(static_mut_ref)]` on by default +help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer + | +LL | unsafe { addr_of!(static_cross_crate::ZERO) } + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + error[E0080]: it is undefined behavior to use this value --> $DIR/const_refers_to_static_cross_crate.rs:10:1 | @@ -10,13 +25,13 @@ LL | const SLICE_MUT: &[u8; 1] = { } error: could not evaluate constant pattern - --> $DIR/const_refers_to_static_cross_crate.rs:34:9 + --> $DIR/const_refers_to_static_cross_crate.rs:42:9 | LL | SLICE_MUT => true, | ^^^^^^^^^ error[E0080]: it is undefined behavior to use this value - --> $DIR/const_refers_to_static_cross_crate.rs:15:1 + --> $DIR/const_refers_to_static_cross_crate.rs:17:1 | LL | const U8_MUT: &u8 = { | ^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a reference pointing to a static variable in a constant @@ -27,31 +42,31 @@ LL | const U8_MUT: &u8 = { } error: could not evaluate constant pattern - --> $DIR/const_refers_to_static_cross_crate.rs:42:9 + --> $DIR/const_refers_to_static_cross_crate.rs:50:9 | LL | U8_MUT => true, | ^^^^^^ error[E0080]: evaluation of constant value failed - --> $DIR/const_refers_to_static_cross_crate.rs:22:15 + --> $DIR/const_refers_to_static_cross_crate.rs:25:15 | LL | unsafe { &(*static_cross_crate::ZERO_REF)[0] } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constant accesses static error: could not evaluate constant pattern - --> $DIR/const_refers_to_static_cross_crate.rs:52:9 + --> $DIR/const_refers_to_static_cross_crate.rs:60:9 | LL | U8_MUT2 => true, | ^^^^^^^ error[E0080]: evaluation of constant value failed - --> $DIR/const_refers_to_static_cross_crate.rs:27:20 + --> $DIR/const_refers_to_static_cross_crate.rs:31:15 | -LL | unsafe { match static_cross_crate::OPT_ZERO { Some(ref u) => u, None => panic!() } } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constant accesses static +LL | match static_cross_crate::OPT_ZERO { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constant accesses static error: could not evaluate constant pattern - --> $DIR/const_refers_to_static_cross_crate.rs:59:9 + --> $DIR/const_refers_to_static_cross_crate.rs:67:9 | LL | U8_MUT3 => true, | ^^^^^^^ @@ -59,61 +74,61 @@ LL | U8_MUT3 => true, warning: skipping const checks | help: skipping check that does not even have a feature gate - --> $DIR/const_refers_to_static_cross_crate.rs:12:15 + --> $DIR/const_refers_to_static_cross_crate.rs:13:15 | LL | unsafe { &static_cross_crate::ZERO } | ^^^^^^^^^^^^^^^^^^^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/const_refers_to_static_cross_crate.rs:12:15 + --> $DIR/const_refers_to_static_cross_crate.rs:13:15 | LL | unsafe { &static_cross_crate::ZERO } | ^^^^^^^^^^^^^^^^^^^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/const_refers_to_static_cross_crate.rs:17:15 + --> $DIR/const_refers_to_static_cross_crate.rs:20:15 | LL | unsafe { &static_cross_crate::ZERO[0] } | ^^^^^^^^^^^^^^^^^^^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/const_refers_to_static_cross_crate.rs:17:15 + --> $DIR/const_refers_to_static_cross_crate.rs:20:15 | LL | unsafe { &static_cross_crate::ZERO[0] } | ^^^^^^^^^^^^^^^^^^^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/const_refers_to_static_cross_crate.rs:17:15 + --> $DIR/const_refers_to_static_cross_crate.rs:20:15 | LL | unsafe { &static_cross_crate::ZERO[0] } | ^^^^^^^^^^^^^^^^^^^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/const_refers_to_static_cross_crate.rs:22:17 + --> $DIR/const_refers_to_static_cross_crate.rs:25:17 | LL | unsafe { &(*static_cross_crate::ZERO_REF)[0] } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/const_refers_to_static_cross_crate.rs:27:20 + --> $DIR/const_refers_to_static_cross_crate.rs:31:15 | -LL | unsafe { match static_cross_crate::OPT_ZERO { Some(ref u) => u, None => panic!() } } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | match static_cross_crate::OPT_ZERO { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/const_refers_to_static_cross_crate.rs:27:20 + --> $DIR/const_refers_to_static_cross_crate.rs:31:15 | -LL | unsafe { match static_cross_crate::OPT_ZERO { Some(ref u) => u, None => panic!() } } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | match static_cross_crate::OPT_ZERO { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/const_refers_to_static_cross_crate.rs:27:20 + --> $DIR/const_refers_to_static_cross_crate.rs:31:15 | -LL | unsafe { match static_cross_crate::OPT_ZERO { Some(ref u) => u, None => panic!() } } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | match static_cross_crate::OPT_ZERO { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/const_refers_to_static_cross_crate.rs:27:20 + --> $DIR/const_refers_to_static_cross_crate.rs:31:15 | -LL | unsafe { match static_cross_crate::OPT_ZERO { Some(ref u) => u, None => panic!() } } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | match static_cross_crate::OPT_ZERO { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/const_refers_to_static_cross_crate.rs:27:20 + --> $DIR/const_refers_to_static_cross_crate.rs:31:15 | -LL | unsafe { match static_cross_crate::OPT_ZERO { Some(ref u) => u, None => panic!() } } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | match static_cross_crate::OPT_ZERO { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 8 previous errors; 1 warning emitted +error: aborting due to 8 previous errors; 2 warnings emitted For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.64bit.stderr b/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.64bit.stderr index 6ae0b2d1bfef7..275323bc286c0 100644 --- a/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.64bit.stderr +++ b/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.64bit.stderr @@ -1,3 +1,18 @@ +warning: shared reference of mutable static is discouraged + --> $DIR/const_refers_to_static_cross_crate.rs:13:14 + | +LL | unsafe { &static_cross_crate::ZERO } + | ^^^^^^^^^^^^^^^^^^^^^^^^^ shared reference of mutable static + | + = note: for more information, see issue #114447 <https://github.com/rust-lang/rust/issues/114447> + = note: reference of mutable static is a hard error from 2024 edition + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior + = note: `#[warn(static_mut_ref)]` on by default +help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer + | +LL | unsafe { addr_of!(static_cross_crate::ZERO) } + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + error[E0080]: it is undefined behavior to use this value --> $DIR/const_refers_to_static_cross_crate.rs:10:1 | @@ -10,13 +25,13 @@ LL | const SLICE_MUT: &[u8; 1] = { } error: could not evaluate constant pattern - --> $DIR/const_refers_to_static_cross_crate.rs:34:9 + --> $DIR/const_refers_to_static_cross_crate.rs:42:9 | LL | SLICE_MUT => true, | ^^^^^^^^^ error[E0080]: it is undefined behavior to use this value - --> $DIR/const_refers_to_static_cross_crate.rs:15:1 + --> $DIR/const_refers_to_static_cross_crate.rs:17:1 | LL | const U8_MUT: &u8 = { | ^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a reference pointing to a static variable in a constant @@ -27,31 +42,31 @@ LL | const U8_MUT: &u8 = { } error: could not evaluate constant pattern - --> $DIR/const_refers_to_static_cross_crate.rs:42:9 + --> $DIR/const_refers_to_static_cross_crate.rs:50:9 | LL | U8_MUT => true, | ^^^^^^ error[E0080]: evaluation of constant value failed - --> $DIR/const_refers_to_static_cross_crate.rs:22:15 + --> $DIR/const_refers_to_static_cross_crate.rs:25:15 | LL | unsafe { &(*static_cross_crate::ZERO_REF)[0] } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constant accesses static error: could not evaluate constant pattern - --> $DIR/const_refers_to_static_cross_crate.rs:52:9 + --> $DIR/const_refers_to_static_cross_crate.rs:60:9 | LL | U8_MUT2 => true, | ^^^^^^^ error[E0080]: evaluation of constant value failed - --> $DIR/const_refers_to_static_cross_crate.rs:27:20 + --> $DIR/const_refers_to_static_cross_crate.rs:31:15 | -LL | unsafe { match static_cross_crate::OPT_ZERO { Some(ref u) => u, None => panic!() } } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constant accesses static +LL | match static_cross_crate::OPT_ZERO { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constant accesses static error: could not evaluate constant pattern - --> $DIR/const_refers_to_static_cross_crate.rs:59:9 + --> $DIR/const_refers_to_static_cross_crate.rs:67:9 | LL | U8_MUT3 => true, | ^^^^^^^ @@ -59,61 +74,61 @@ LL | U8_MUT3 => true, warning: skipping const checks | help: skipping check that does not even have a feature gate - --> $DIR/const_refers_to_static_cross_crate.rs:12:15 + --> $DIR/const_refers_to_static_cross_crate.rs:13:15 | LL | unsafe { &static_cross_crate::ZERO } | ^^^^^^^^^^^^^^^^^^^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/const_refers_to_static_cross_crate.rs:12:15 + --> $DIR/const_refers_to_static_cross_crate.rs:13:15 | LL | unsafe { &static_cross_crate::ZERO } | ^^^^^^^^^^^^^^^^^^^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/const_refers_to_static_cross_crate.rs:17:15 + --> $DIR/const_refers_to_static_cross_crate.rs:20:15 | LL | unsafe { &static_cross_crate::ZERO[0] } | ^^^^^^^^^^^^^^^^^^^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/const_refers_to_static_cross_crate.rs:17:15 + --> $DIR/const_refers_to_static_cross_crate.rs:20:15 | LL | unsafe { &static_cross_crate::ZERO[0] } | ^^^^^^^^^^^^^^^^^^^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/const_refers_to_static_cross_crate.rs:17:15 + --> $DIR/const_refers_to_static_cross_crate.rs:20:15 | LL | unsafe { &static_cross_crate::ZERO[0] } | ^^^^^^^^^^^^^^^^^^^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/const_refers_to_static_cross_crate.rs:22:17 + --> $DIR/const_refers_to_static_cross_crate.rs:25:17 | LL | unsafe { &(*static_cross_crate::ZERO_REF)[0] } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/const_refers_to_static_cross_crate.rs:27:20 + --> $DIR/const_refers_to_static_cross_crate.rs:31:15 | -LL | unsafe { match static_cross_crate::OPT_ZERO { Some(ref u) => u, None => panic!() } } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | match static_cross_crate::OPT_ZERO { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/const_refers_to_static_cross_crate.rs:27:20 + --> $DIR/const_refers_to_static_cross_crate.rs:31:15 | -LL | unsafe { match static_cross_crate::OPT_ZERO { Some(ref u) => u, None => panic!() } } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | match static_cross_crate::OPT_ZERO { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/const_refers_to_static_cross_crate.rs:27:20 + --> $DIR/const_refers_to_static_cross_crate.rs:31:15 | -LL | unsafe { match static_cross_crate::OPT_ZERO { Some(ref u) => u, None => panic!() } } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | match static_cross_crate::OPT_ZERO { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/const_refers_to_static_cross_crate.rs:27:20 + --> $DIR/const_refers_to_static_cross_crate.rs:31:15 | -LL | unsafe { match static_cross_crate::OPT_ZERO { Some(ref u) => u, None => panic!() } } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | match static_cross_crate::OPT_ZERO { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/const_refers_to_static_cross_crate.rs:27:20 + --> $DIR/const_refers_to_static_cross_crate.rs:31:15 | -LL | unsafe { match static_cross_crate::OPT_ZERO { Some(ref u) => u, None => panic!() } } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | match static_cross_crate::OPT_ZERO { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 8 previous errors; 1 warning emitted +error: aborting due to 8 previous errors; 2 warnings emitted For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.rs b/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.rs index bbaa32ddfd1bd..3eafa58d9f9fd 100644 --- a/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.rs +++ b/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.rs @@ -7,13 +7,16 @@ extern crate static_cross_crate; // Sneaky: reference to a mutable static. // Allowing this would be a disaster for pattern matching, we could violate exhaustiveness checking! -const SLICE_MUT: &[u8; 1] = { //~ ERROR undefined behavior to use this value -//~| encountered a reference pointing to a static variable +const SLICE_MUT: &[u8; 1] = { + //~^ ERROR undefined behavior to use this value + //~| encountered a reference pointing to a static variable unsafe { &static_cross_crate::ZERO } + //~^ WARN shared reference of mutable static is discouraged [static_mut_ref] }; -const U8_MUT: &u8 = { //~ ERROR undefined behavior to use this value -//~| encountered a reference pointing to a static variable +const U8_MUT: &u8 = { + //~^ ERROR undefined behavior to use this value + //~| encountered a reference pointing to a static variable unsafe { &static_cross_crate::ZERO[0] } }; @@ -24,9 +27,14 @@ const U8_MUT2: &u8 = { //~| constant accesses static }; const U8_MUT3: &u8 = { - unsafe { match static_cross_crate::OPT_ZERO { Some(ref u) => u, None => panic!() } } - //~^ ERROR evaluation of constant value failed - //~| constant accesses static + unsafe { + match static_cross_crate::OPT_ZERO { + //~^ ERROR evaluation of constant value failed + //~| constant accesses static + Some(ref u) => u, + None => panic!(), + } + } }; pub fn test(x: &[u8; 1]) -> bool { diff --git a/tests/ui/consts/static_mut_containing_mut_ref.rs b/tests/ui/consts/static_mut_containing_mut_ref.rs index df09c76c5584d..874aa59df0bb6 100644 --- a/tests/ui/consts/static_mut_containing_mut_ref.rs +++ b/tests/ui/consts/static_mut_containing_mut_ref.rs @@ -3,5 +3,6 @@ static mut STDERR_BUFFER_SPACE: [u8; 42] = [0u8; 42]; pub static mut STDERR_BUFFER: *mut [u8] = unsafe { &mut STDERR_BUFFER_SPACE }; +//~^ WARN mutable reference of mutable static is discouraged [static_mut_ref] fn main() {} diff --git a/tests/ui/consts/static_mut_containing_mut_ref.stderr b/tests/ui/consts/static_mut_containing_mut_ref.stderr new file mode 100644 index 0000000000000..56ceba41cf88c --- /dev/null +++ b/tests/ui/consts/static_mut_containing_mut_ref.stderr @@ -0,0 +1,17 @@ +warning: mutable reference of mutable static is discouraged + --> $DIR/static_mut_containing_mut_ref.rs:5:52 + | +LL | pub static mut STDERR_BUFFER: *mut [u8] = unsafe { &mut STDERR_BUFFER_SPACE }; + | ^^^^^^^^^^^^^^^^^^^^^^^^ mutable reference of mutable static + | + = note: for more information, see issue #114447 <https://github.com/rust-lang/rust/issues/114447> + = note: reference of mutable static is a hard error from 2024 edition + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior + = note: `#[warn(static_mut_ref)]` on by default +help: mutable references are dangerous since if there's any other pointer or reference used for that static while the reference lives, that's UB; use `addr_of_mut!` instead to create a raw pointer + | +LL | pub static mut STDERR_BUFFER: *mut [u8] = unsafe { addr_of_mut!(STDERR_BUFFER_SPACE) }; + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +warning: 1 warning emitted + diff --git a/tests/ui/consts/static_mut_containing_mut_ref2.mut_refs.stderr b/tests/ui/consts/static_mut_containing_mut_ref2.mut_refs.stderr index 3d0de233569c9..bc32ecc2c35ff 100644 --- a/tests/ui/consts/static_mut_containing_mut_ref2.mut_refs.stderr +++ b/tests/ui/consts/static_mut_containing_mut_ref2.mut_refs.stderr @@ -1,9 +1,24 @@ +warning: mutable reference of mutable static is discouraged + --> $DIR/static_mut_containing_mut_ref2.rs:8:6 + | +LL | *(&mut STDERR_BUFFER_SPACE) = 42; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ mutable reference of mutable static + | + = note: for more information, see issue #114447 <https://github.com/rust-lang/rust/issues/114447> + = note: reference of mutable static is a hard error from 2024 edition + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior + = note: `#[warn(static_mut_ref)]` on by default +help: mutable references are dangerous since if there's any other pointer or reference used for that static while the reference lives, that's UB; use `addr_of_mut!` instead to create a raw pointer + | +LL | *addr_of_mut!(STDERR_BUFFER_SPACE) = 42; + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + error[E0080]: could not evaluate static initializer - --> $DIR/static_mut_containing_mut_ref2.rs:7:45 + --> $DIR/static_mut_containing_mut_ref2.rs:8:5 | -LL | pub static mut STDERR_BUFFER: () = unsafe { *(&mut STDERR_BUFFER_SPACE) = 42; }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ modifying a static's initial value from another static's initializer +LL | *(&mut STDERR_BUFFER_SPACE) = 42; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ modifying a static's initial value from another static's initializer -error: aborting due to 1 previous error +error: aborting due to 1 previous error; 1 warning emitted For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/static_mut_containing_mut_ref2.rs b/tests/ui/consts/static_mut_containing_mut_ref2.rs index 61368546083db..fa79a78eab424 100644 --- a/tests/ui/consts/static_mut_containing_mut_ref2.rs +++ b/tests/ui/consts/static_mut_containing_mut_ref2.rs @@ -4,8 +4,12 @@ static mut STDERR_BUFFER_SPACE: u8 = 0; -pub static mut STDERR_BUFFER: () = unsafe { *(&mut STDERR_BUFFER_SPACE) = 42; }; -//[mut_refs]~^ ERROR could not evaluate static initializer -//[stock]~^^ ERROR mutable references are not allowed in statics +pub static mut STDERR_BUFFER: () = unsafe { + *(&mut STDERR_BUFFER_SPACE) = 42; + //[mut_refs]~^ ERROR could not evaluate static initializer + //[stock]~^^ ERROR mutable references are not allowed in statics + //[mut_refs]~^^^ WARN mutable reference of mutable static is discouraged [static_mut_ref] + //[stock]~^^^^ WARN mutable reference of mutable static is discouraged [static_mut_ref] +}; fn main() {} diff --git a/tests/ui/consts/static_mut_containing_mut_ref2.stock.stderr b/tests/ui/consts/static_mut_containing_mut_ref2.stock.stderr index 3d5b012d42f37..c6e5b07e3b70a 100644 --- a/tests/ui/consts/static_mut_containing_mut_ref2.stock.stderr +++ b/tests/ui/consts/static_mut_containing_mut_ref2.stock.stderr @@ -1,12 +1,27 @@ +warning: mutable reference of mutable static is discouraged + --> $DIR/static_mut_containing_mut_ref2.rs:8:6 + | +LL | *(&mut STDERR_BUFFER_SPACE) = 42; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ mutable reference of mutable static + | + = note: for more information, see issue #114447 <https://github.com/rust-lang/rust/issues/114447> + = note: reference of mutable static is a hard error from 2024 edition + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior + = note: `#[warn(static_mut_ref)]` on by default +help: mutable references are dangerous since if there's any other pointer or reference used for that static while the reference lives, that's UB; use `addr_of_mut!` instead to create a raw pointer + | +LL | *addr_of_mut!(STDERR_BUFFER_SPACE) = 42; + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + error[E0658]: mutable references are not allowed in statics - --> $DIR/static_mut_containing_mut_ref2.rs:7:46 + --> $DIR/static_mut_containing_mut_ref2.rs:8:6 | -LL | pub static mut STDERR_BUFFER: () = unsafe { *(&mut STDERR_BUFFER_SPACE) = 42; }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | *(&mut STDERR_BUFFER_SPACE) = 42; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable -error: aborting due to 1 previous error +error: aborting due to 1 previous error; 1 warning emitted For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/drop/issue-23338-ensure-param-drop-order.rs b/tests/ui/drop/issue-23338-ensure-param-drop-order.rs index a99f260dde3b2..52603744c45fc 100644 --- a/tests/ui/drop/issue-23338-ensure-param-drop-order.rs +++ b/tests/ui/drop/issue-23338-ensure-param-drop-order.rs @@ -13,38 +13,39 @@ pub fn main() { d::println("created empty log"); test(&log); - assert_eq!(&log.borrow()[..], - [ - // created empty log - // +-- Make D(da_0, 0) - // | +-- Make D(de_1, 1) - // | | calling foo - // | | entered foo - // | | +-- Make D(de_2, 2) - // | | | +-- Make D(da_1, 3) - // | | | | +-- Make D(de_3, 4) - // | | | | | +-- Make D(de_4, 5) - 3, // | | | +-- Drop D(da_1, 3) - // | | | | | - 4, // | | | +-- Drop D(de_3, 4) - // | | | | - // | | | | eval tail of foo - // | | | +-- Make D(de_5, 6) - // | | | | +-- Make D(de_6, 7) - 5, // | | | | | +-- Drop D(de_4, 5) - // | | | | | - 2, // | | +-- Drop D(de_2, 2) - // | | | | - 6, // | | +-- Drop D(de_5, 6) - // | | | - 1, // | +-- Drop D(de_1, 1) - // | | - 0, // +-- Drop D(da_0, 0) - // | - // | result D(de_6, 7) - 7 // +-- Drop D(de_6, 7) - - ]); + assert_eq!( + &log.borrow()[..], + [ + // created empty log + // +-- Make D(da_0, 0) + // | +-- Make D(de_1, 1) + // | | calling foo + // | | entered foo + // | | +-- Make D(de_2, 2) + // | | | +-- Make D(da_1, 3) + // | | | | +-- Make D(de_3, 4) + // | | | | | +-- Make D(de_4, 5) + 3, // | | | +-- Drop D(da_1, 3) + // | | | | | + 4, // | | | +-- Drop D(de_3, 4) + // | | | | + // | | | | eval tail of foo + // | | | +-- Make D(de_5, 6) + // | | | | +-- Make D(de_6, 7) + 5, // | | | | | +-- Drop D(de_4, 5) + // | | | | | + 2, // | | +-- Drop D(de_2, 2) + // | | | | + 6, // | | +-- Drop D(de_5, 6) + // | | | + 1, // | +-- Drop D(de_1, 1) + // | | + 0, // +-- Drop D(da_0, 0) + // | + // | result D(de_6, 7) + 7 // +-- Drop D(de_6, 7) + ] + ); } fn test<'a>(log: d::Log<'a>) { @@ -57,13 +58,13 @@ fn test<'a>(log: d::Log<'a>) { fn foo<'a>(da0: D<'a>, de1: D<'a>) -> D<'a> { d::println("entered foo"); - let de2 = de1.incr(); // creates D(de_2, 2) + let de2 = de1.incr(); // creates D(de_2, 2) let de4 = { let _da1 = da0.incr(); // creates D(da_1, 3) - de2.incr().incr() // creates D(de_3, 4) and D(de_4, 5) + de2.incr().incr() // creates D(de_3, 4) and D(de_4, 5) }; d::println("eval tail of foo"); - de4.incr().incr() // creates D(de_5, 6) and D(de_6, 7) + de4.incr().incr() // creates D(de_5, 6) and D(de_6, 7) } // This module provides simultaneous printouts of the dynamic extents @@ -74,9 +75,9 @@ const PREF_INDENT: u32 = 16; pub mod d { #![allow(unused_parens)] + use std::cell::RefCell; use std::fmt; use std::mem; - use std::cell::RefCell; static mut counter: u32 = 0; static mut trails: u64 = 0; @@ -89,7 +90,8 @@ pub mod d { pub fn max_width() -> u32 { unsafe { - (mem::size_of_val(&trails)*8) as u32 + (mem::size_of_val(&trails) * 8) as u32 + //~^ WARN shared reference of mutable static is discouraged [static_mut_ref] } } @@ -123,7 +125,11 @@ pub mod d { } pub struct D<'a> { - name: &'static str, i: u32, uid: u32, trail: u32, log: Log<'a> + name: &'static str, + i: u32, + uid: u32, + trail: u32, + log: Log<'a>, } impl<'a> fmt::Display for D<'a> { @@ -139,9 +145,7 @@ pub mod d { let ctr = counter; counter += 1; trails |= (1 << trail); - let ret = D { - name: name, i: i, log: log, uid: ctr, trail: trail - }; + let ret = D { name: name, i: i, log: log, uid: ctr, trail: trail }; indent_println(trail, &format!("+-- Make {}", ret)); ret } @@ -153,7 +157,9 @@ pub mod d { impl<'a> Drop for D<'a> { fn drop(&mut self) { - unsafe { trails &= !(1 << self.trail); }; + unsafe { + trails &= !(1 << self.trail); + }; self.log.borrow_mut().push(self.uid); indent_println(self.trail, &format!("+-- Drop {}", self)); indent_println(::PREF_INDENT, ""); diff --git a/tests/ui/drop/issue-23338-ensure-param-drop-order.stderr b/tests/ui/drop/issue-23338-ensure-param-drop-order.stderr new file mode 100644 index 0000000000000..fd36ccbcbee47 --- /dev/null +++ b/tests/ui/drop/issue-23338-ensure-param-drop-order.stderr @@ -0,0 +1,17 @@ +warning: shared reference of mutable static is discouraged + --> $DIR/issue-23338-ensure-param-drop-order.rs:93:31 + | +LL | (mem::size_of_val(&trails) * 8) as u32 + | ^^^^^^^ shared reference of mutable static + | + = note: for more information, see issue #114447 <https://github.com/rust-lang/rust/issues/114447> + = note: reference of mutable static is a hard error from 2024 edition + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior + = note: `#[warn(static_mut_ref)]` on by default +help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer + | +LL | (mem::size_of_val(addr_of!(trails)) * 8) as u32 + | ~~~~~~~~~~~~~~~~ + +warning: 1 warning emitted + diff --git a/tests/ui/error-codes/E0017.rs b/tests/ui/error-codes/E0017.rs index c211ad1a2f8f6..9d3433fa543fd 100644 --- a/tests/ui/error-codes/E0017.rs +++ b/tests/ui/error-codes/E0017.rs @@ -3,12 +3,16 @@ const C: i32 = 2; static mut M: i32 = 3; const CR: &'static mut i32 = &mut C; //~ ERROR mutable references are not allowed - //~| WARN taking a mutable +//~| WARN taking a mutable + static STATIC_REF: &'static mut i32 = &mut X; //~ ERROR E0658 - //~| ERROR cannot borrow - //~| ERROR mutable references are not allowed +//~| ERROR cannot borrow +//~| ERROR mutable references are not allowed static CONST_REF: &'static mut i32 = &mut C; //~ ERROR mutable references are not allowed - //~| WARN taking a mutable +//~| WARN taking a mutable + static STATIC_MUT_REF: &'static mut i32 = unsafe { &mut M }; //~ ERROR mutable references are not +//~^ WARN mutable reference of mutable static is discouraged [static_mut_ref] + fn main() {} diff --git a/tests/ui/error-codes/E0017.stderr b/tests/ui/error-codes/E0017.stderr index 6e48f9582f1c0..ea6055da1c1fe 100644 --- a/tests/ui/error-codes/E0017.stderr +++ b/tests/ui/error-codes/E0017.stderr @@ -1,3 +1,18 @@ +warning: mutable reference of mutable static is discouraged + --> $DIR/E0017.rs:15:52 + | +LL | static STATIC_MUT_REF: &'static mut i32 = unsafe { &mut M }; + | ^^^^^^ mutable reference of mutable static + | + = note: for more information, see issue #114447 <https://github.com/rust-lang/rust/issues/114447> + = note: reference of mutable static is a hard error from 2024 edition + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior + = note: `#[warn(static_mut_ref)]` on by default +help: mutable references are dangerous since if there's any other pointer or reference used for that static while the reference lives, that's UB; use `addr_of_mut!` instead to create a raw pointer + | +LL | static STATIC_MUT_REF: &'static mut i32 = unsafe { addr_of_mut!(M) }; + | ~~~~~~~~~~~~~~~ + warning: taking a mutable reference to a `const` item --> $DIR/E0017.rs:5:30 | @@ -20,7 +35,7 @@ LL | const CR: &'static mut i32 = &mut C; | ^^^^^^ error[E0658]: mutation through a reference is not allowed in statics - --> $DIR/E0017.rs:7:39 + --> $DIR/E0017.rs:8:39 | LL | static STATIC_REF: &'static mut i32 = &mut X; | ^^^^^^ @@ -29,19 +44,19 @@ LL | static STATIC_REF: &'static mut i32 = &mut X; = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable error[E0764]: mutable references are not allowed in the final value of statics - --> $DIR/E0017.rs:7:39 + --> $DIR/E0017.rs:8:39 | LL | static STATIC_REF: &'static mut i32 = &mut X; | ^^^^^^ error[E0596]: cannot borrow immutable static item `X` as mutable - --> $DIR/E0017.rs:7:39 + --> $DIR/E0017.rs:8:39 | LL | static STATIC_REF: &'static mut i32 = &mut X; | ^^^^^^ cannot borrow as mutable warning: taking a mutable reference to a `const` item - --> $DIR/E0017.rs:11:38 + --> $DIR/E0017.rs:12:38 | LL | static CONST_REF: &'static mut i32 = &mut C; | ^^^^^^ @@ -55,18 +70,18 @@ LL | const C: i32 = 2; | ^^^^^^^^^^^^ error[E0764]: mutable references are not allowed in the final value of statics - --> $DIR/E0017.rs:11:38 + --> $DIR/E0017.rs:12:38 | LL | static CONST_REF: &'static mut i32 = &mut C; | ^^^^^^ error[E0764]: mutable references are not allowed in the final value of statics - --> $DIR/E0017.rs:13:52 + --> $DIR/E0017.rs:15:52 | LL | static STATIC_MUT_REF: &'static mut i32 = unsafe { &mut M }; | ^^^^^^ -error: aborting due to 6 previous errors; 2 warnings emitted +error: aborting due to 6 previous errors; 3 warnings emitted Some errors have detailed explanations: E0596, E0658, E0764. For more information about an error, try `rustc --explain E0596`. diff --git a/tests/ui/issues/issue-20616.rs b/tests/ui/impl-header-lifetime-elision/bare_type.rs similarity index 82% rename from tests/ui/issues/issue-20616.rs rename to tests/ui/impl-header-lifetime-elision/bare_type.rs index 6c24d437272e4..9af98f870d2d5 100644 --- a/tests/ui/issues/issue-20616.rs +++ b/tests/ui/impl-header-lifetime-elision/bare_type.rs @@ -33,12 +33,11 @@ type TypeI<T,> = T; static STATIC: () = (); fn main() { - // ensure token `>=` works fine - let _: TypeA<'static>= &STATIC; - let _: TypeA<'static,>= &STATIC; + let _: TypeA<'static> = &STATIC; + let _: TypeA<'static,> = &STATIC; // ensure token `>>=` works fine - let _: Box<TypeA<'static>>= Box::new(&STATIC); - let _: Box<TypeA<'static,>>= Box::new(&STATIC); + let _: Box<TypeA<'static>> = Box::new(&STATIC); + let _: Box<TypeA<'static,>> = Box::new(&STATIC); } diff --git a/tests/ui/issues/issue-23611-enum-swap-in-drop.rs b/tests/ui/issues/issue-23611-enum-swap-in-drop.rs index cdb130d600c5e..b967e6aecdd43 100644 --- a/tests/ui/issues/issue-23611-enum-swap-in-drop.rs +++ b/tests/ui/issues/issue-23611-enum-swap-in-drop.rs @@ -37,11 +37,9 @@ pub fn main() { // | | | +-- Make D(g_b_5, 50000005) // | | | | in g_B(b4b2) from GaspB::drop // | | | +-- Drop D(g_b_5, 50000005) - 50000005, - // | | | + 50000005, // | | | // | | +-- Drop D(GaspB::drop_3, 30000004) - 30000004, - // | | + 30000004, // | | // +-- Drop D(test_1, 10000000) 10000000, // | @@ -49,15 +47,13 @@ pub fn main() { // | | +-- Make D(f_a_4, 40000007) // | | | in f_A(a3a0) from GaspA::drop // | | +-- Drop D(f_a_4, 40000007) - 40000007, - // | | + 40000007, // | | // +-- Drop D(GaspA::drop_2, 20000006) - 20000006, - // | + 20000006, // | // +-- Drop D(drop_6, 60000002) - 60000002 - // - ]); + 60000002 // + ] + ); // For reference purposes, the old (incorrect) behavior would produce the following // output, which you can compare to the above: @@ -106,8 +102,8 @@ fn test<'a>(log: d::Log<'a>) { let _e = E::B(GaspB(g_b, 0xB4B0, log, D::new("test", 1, log)), true); } -struct GaspA<'a>(for <'b> fn(u32, &'b str, d::Log<'a>), u32, d::Log<'a>, d::D<'a>); -struct GaspB<'a>(for <'b> fn(u32, &'b str, d::Log<'a>), u32, d::Log<'a>, d::D<'a>); +struct GaspA<'a>(for<'b> fn(u32, &'b str, d::Log<'a>), u32, d::Log<'a>, d::D<'a>); +struct GaspB<'a>(for<'b> fn(u32, &'b str, d::Log<'a>), u32, d::Log<'a>, d::D<'a>); impl<'a> Drop for GaspA<'a> { fn drop(&mut self) { @@ -124,7 +120,8 @@ impl<'a> Drop for GaspB<'a> { } enum E<'a> { - A(GaspA<'a>, bool), B(GaspB<'a>, bool), + A(GaspA<'a>, bool), + B(GaspB<'a>, bool), } fn f_a(x: u32, ctxt: &str, log: d::Log) { @@ -174,9 +171,9 @@ const PREF_INDENT: u32 = 20; pub mod d { #![allow(unused_parens)] + use std::cell::RefCell; use std::fmt; use std::mem; - use std::cell::RefCell; static mut counter: u16 = 0; static mut trails: u64 = 0; @@ -189,7 +186,8 @@ pub mod d { pub fn max_width() -> u32 { unsafe { - (mem::size_of_val(&trails)*8) as u32 + (mem::size_of_val(&trails) * 8) as u32 + //~^ WARN shared reference of mutable static is discouraged [static_mut_ref] } } @@ -223,7 +221,11 @@ pub mod d { } pub struct D<'a> { - name: &'static str, i: u8, uid: u32, trail: u32, log: Log<'a> + name: &'static str, + i: u8, + uid: u32, + trail: u32, + log: Log<'a>, } impl<'a> fmt::Display for D<'a> { @@ -239,9 +241,7 @@ pub mod d { let ctr = ((i as u32) * 10_000_000) + (counter as u32); counter += 1; trails |= (1 << trail); - let ret = D { - name: name, i: i, log: log, uid: ctr, trail: trail - }; + let ret = D { name: name, i: i, log: log, uid: ctr, trail: trail }; indent_println(trail, &format!("+-- Make {}", ret)); ret } @@ -250,7 +250,9 @@ pub mod d { impl<'a> Drop for D<'a> { fn drop(&mut self) { - unsafe { trails &= !(1 << self.trail); }; + unsafe { + trails &= !(1 << self.trail); + }; self.log.borrow_mut().push(self.uid); indent_println(self.trail, &format!("+-- Drop {}", self)); indent_println(::PREF_INDENT, ""); diff --git a/tests/ui/issues/issue-23611-enum-swap-in-drop.stderr b/tests/ui/issues/issue-23611-enum-swap-in-drop.stderr new file mode 100644 index 0000000000000..14a986a333264 --- /dev/null +++ b/tests/ui/issues/issue-23611-enum-swap-in-drop.stderr @@ -0,0 +1,17 @@ +warning: shared reference of mutable static is discouraged + --> $DIR/issue-23611-enum-swap-in-drop.rs:189:31 + | +LL | (mem::size_of_val(&trails) * 8) as u32 + | ^^^^^^^ shared reference of mutable static + | + = note: for more information, see issue #114447 <https://github.com/rust-lang/rust/issues/114447> + = note: reference of mutable static is a hard error from 2024 edition + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior + = note: `#[warn(static_mut_ref)]` on by default +help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer + | +LL | (mem::size_of_val(addr_of!(trails)) * 8) as u32 + | ~~~~~~~~~~~~~~~~ + +warning: 1 warning emitted + diff --git a/tests/ui/nll/borrowck-thread-local-static-mut-borrow-outlives-fn.rs b/tests/ui/nll/borrowck-thread-local-static-mut-borrow-outlives-fn.rs index 7d3b00dfc7163..8eb544e8ab9d2 100644 --- a/tests/ui/nll/borrowck-thread-local-static-mut-borrow-outlives-fn.rs +++ b/tests/ui/nll/borrowck-thread-local-static-mut-borrow-outlives-fn.rs @@ -14,9 +14,8 @@ struct S1 { impl S1 { fn new(_x: u64) -> S1 { - S1 { - a: unsafe { &mut X1 }, - } + S1 { a: unsafe { &mut X1 } } + //~^ WARN mutable reference of mutable static is discouraged [static_mut_ref] } } diff --git a/tests/ui/nll/borrowck-thread-local-static-mut-borrow-outlives-fn.stderr b/tests/ui/nll/borrowck-thread-local-static-mut-borrow-outlives-fn.stderr new file mode 100644 index 0000000000000..17217cd5859d0 --- /dev/null +++ b/tests/ui/nll/borrowck-thread-local-static-mut-borrow-outlives-fn.stderr @@ -0,0 +1,17 @@ +warning: mutable reference of mutable static is discouraged + --> $DIR/borrowck-thread-local-static-mut-borrow-outlives-fn.rs:17:26 + | +LL | S1 { a: unsafe { &mut X1 } } + | ^^^^^^^ mutable reference of mutable static + | + = note: for more information, see issue #114447 <https://github.com/rust-lang/rust/issues/114447> + = note: reference of mutable static is a hard error from 2024 edition + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior + = note: `#[warn(static_mut_ref)]` on by default +help: mutable references are dangerous since if there's any other pointer or reference used for that static while the reference lives, that's UB; use `addr_of_mut!` instead to create a raw pointer + | +LL | S1 { a: unsafe { addr_of_mut!(X1) } } + | ~~~~~~~~~~~~~~~~ + +warning: 1 warning emitted + diff --git a/tests/ui/static/reference-of-mut-static-safe.e2021.stderr b/tests/ui/static/reference-of-mut-static-safe.e2021.stderr index c38fe8790637e..16f47ace3a930 100644 --- a/tests/ui/static/reference-of-mut-static-safe.e2021.stderr +++ b/tests/ui/static/reference-of-mut-static-safe.e2021.stderr @@ -14,10 +14,10 @@ LL | let _x = addr_of!(X); | ~~~~~~~~~~~ error[E0133]: use of mutable static is unsafe and requires unsafe function or block - --> $DIR/reference-of-mut-static-safe.rs:9:14 + --> $DIR/reference-of-mut-static-safe.rs:9:15 | LL | let _x = &X; - | ^^ use of mutable static + | ^ use of mutable static | = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior diff --git a/tests/ui/static/safe-extern-statics-mut.rs b/tests/ui/static/safe-extern-statics-mut.rs index 324fa443aa50e..1c0662e0a6cec 100644 --- a/tests/ui/static/safe-extern-statics-mut.rs +++ b/tests/ui/static/safe-extern-statics-mut.rs @@ -10,6 +10,8 @@ extern "C" { fn main() { let b = B; //~ ERROR use of mutable static is unsafe let rb = &B; //~ ERROR use of mutable static is unsafe + //~^ WARN shared reference of mutable static is discouraged [static_mut_ref] let xb = XB; //~ ERROR use of mutable static is unsafe let xrb = &XB; //~ ERROR use of mutable static is unsafe + //~^ WARN shared reference of mutable static is discouraged [static_mut_ref] } diff --git a/tests/ui/static/safe-extern-statics-mut.stderr b/tests/ui/static/safe-extern-statics-mut.stderr index e390625f20a98..eda353ce6736f 100644 --- a/tests/ui/static/safe-extern-statics-mut.stderr +++ b/tests/ui/static/safe-extern-statics-mut.stderr @@ -1,3 +1,32 @@ +warning: shared reference of mutable static is discouraged + --> $DIR/safe-extern-statics-mut.rs:12:14 + | +LL | let rb = &B; + | ^^ shared reference of mutable static + | + = note: for more information, see issue #114447 <https://github.com/rust-lang/rust/issues/114447> + = note: reference of mutable static is a hard error from 2024 edition + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior + = note: `#[warn(static_mut_ref)]` on by default +help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer + | +LL | let rb = addr_of!(B); + | ~~~~~~~~~~~ + +warning: shared reference of mutable static is discouraged + --> $DIR/safe-extern-statics-mut.rs:15:15 + | +LL | let xrb = &XB; + | ^^^ shared reference of mutable static + | + = note: for more information, see issue #114447 <https://github.com/rust-lang/rust/issues/114447> + = note: reference of mutable static is a hard error from 2024 edition + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior +help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer + | +LL | let xrb = addr_of!(XB); + | ~~~~~~~~~~~~ + error[E0133]: use of mutable static is unsafe and requires unsafe function or block --> $DIR/safe-extern-statics-mut.rs:11:13 | @@ -15,7 +44,7 @@ LL | let rb = &B; = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior error[E0133]: use of mutable static is unsafe and requires unsafe function or block - --> $DIR/safe-extern-statics-mut.rs:13:14 + --> $DIR/safe-extern-statics-mut.rs:14:14 | LL | let xb = XB; | ^^ use of mutable static @@ -23,13 +52,13 @@ LL | let xb = XB; = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior error[E0133]: use of mutable static is unsafe and requires unsafe function or block - --> $DIR/safe-extern-statics-mut.rs:14:16 + --> $DIR/safe-extern-statics-mut.rs:15:16 | LL | let xrb = &XB; | ^^ use of mutable static | = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior -error: aborting due to 4 previous errors +error: aborting due to 4 previous errors; 2 warnings emitted For more information about this error, try `rustc --explain E0133`. diff --git a/tests/ui/statics/issue-15261.rs b/tests/ui/statics/issue-15261.rs index ec413f6d1d2be..14422329b7dc8 100644 --- a/tests/ui/statics/issue-15261.rs +++ b/tests/ui/statics/issue-15261.rs @@ -6,6 +6,7 @@ static mut n_mut: usize = 0; -static n: &'static usize = unsafe{ &n_mut }; +static n: &'static usize = unsafe { &n_mut }; +//~^ WARN shared reference of mutable static is discouraged [static_mut_ref] fn main() {} diff --git a/tests/ui/statics/issue-15261.stderr b/tests/ui/statics/issue-15261.stderr new file mode 100644 index 0000000000000..72d88ce1b3832 --- /dev/null +++ b/tests/ui/statics/issue-15261.stderr @@ -0,0 +1,17 @@ +warning: shared reference of mutable static is discouraged + --> $DIR/issue-15261.rs:9:37 + | +LL | static n: &'static usize = unsafe { &n_mut }; + | ^^^^^^ shared reference of mutable static + | + = note: for more information, see issue #114447 <https://github.com/rust-lang/rust/issues/114447> + = note: reference of mutable static is a hard error from 2024 edition + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior + = note: `#[warn(static_mut_ref)]` on by default +help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer + | +LL | static n: &'static usize = unsafe { addr_of!(n_mut) }; + | ~~~~~~~~~~~~~~~ + +warning: 1 warning emitted + diff --git a/tests/ui/statics/static-mut-xc.rs b/tests/ui/statics/static-mut-xc.rs index 1d172d26a5949..2fc265e02eaa3 100644 --- a/tests/ui/statics/static-mut-xc.rs +++ b/tests/ui/statics/static-mut-xc.rs @@ -7,7 +7,6 @@ // aux-build:static_mut_xc.rs - extern crate static_mut_xc; unsafe fn static_bound(_: &'static isize) {} @@ -27,7 +26,9 @@ unsafe fn run() { static_mut_xc::a = -3; assert_eq!(static_mut_xc::a, -3); static_bound(&static_mut_xc::a); + //~^ WARN shared reference of mutable static is discouraged [static_mut_ref] static_bound_set(&mut static_mut_xc::a); + //~^ WARN mutable reference of mutable static is discouraged [static_mut_ref] } pub fn main() { diff --git a/tests/ui/statics/static-mut-xc.stderr b/tests/ui/statics/static-mut-xc.stderr new file mode 100644 index 0000000000000..37aa336bc50f7 --- /dev/null +++ b/tests/ui/statics/static-mut-xc.stderr @@ -0,0 +1,31 @@ +warning: shared reference of mutable static is discouraged + --> $DIR/static-mut-xc.rs:28:18 + | +LL | static_bound(&static_mut_xc::a); + | ^^^^^^^^^^^^^^^^^ shared reference of mutable static + | + = note: for more information, see issue #114447 <https://github.com/rust-lang/rust/issues/114447> + = note: reference of mutable static is a hard error from 2024 edition + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior + = note: `#[warn(static_mut_ref)]` on by default +help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer + | +LL | static_bound(addr_of!(static_mut_xc::a)); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~ + +warning: mutable reference of mutable static is discouraged + --> $DIR/static-mut-xc.rs:30:22 + | +LL | static_bound_set(&mut static_mut_xc::a); + | ^^^^^^^^^^^^^^^^^^^^^ mutable reference of mutable static + | + = note: for more information, see issue #114447 <https://github.com/rust-lang/rust/issues/114447> + = note: reference of mutable static is a hard error from 2024 edition + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior +help: mutable references are dangerous since if there's any other pointer or reference used for that static while the reference lives, that's UB; use `addr_of_mut!` instead to create a raw pointer + | +LL | static_bound_set(addr_of_mut!(static_mut_xc::a)); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +warning: 2 warnings emitted + diff --git a/tests/ui/statics/static-recursive.rs b/tests/ui/statics/static-recursive.rs index 95dadc81f811d..216beb0206d9c 100644 --- a/tests/ui/statics/static-recursive.rs +++ b/tests/ui/statics/static-recursive.rs @@ -1,36 +1,43 @@ // run-pass + static mut S: *const u8 = unsafe { &S as *const *const u8 as *const u8 }; +//~^ WARN shared reference of mutable static is discouraged [static_mut_ref] struct StaticDoubleLinked { prev: &'static StaticDoubleLinked, next: &'static StaticDoubleLinked, data: i32, - head: bool + head: bool, } -static L1: StaticDoubleLinked = StaticDoubleLinked{prev: &L3, next: &L2, data: 1, head: true}; -static L2: StaticDoubleLinked = StaticDoubleLinked{prev: &L1, next: &L3, data: 2, head: false}; -static L3: StaticDoubleLinked = StaticDoubleLinked{prev: &L2, next: &L1, data: 3, head: false}; - +static L1: StaticDoubleLinked = StaticDoubleLinked { prev: &L3, next: &L2, data: 1, head: true }; +static L2: StaticDoubleLinked = StaticDoubleLinked { prev: &L1, next: &L3, data: 2, head: false }; +static L3: StaticDoubleLinked = StaticDoubleLinked { prev: &L2, next: &L1, data: 3, head: false }; pub fn main() { - unsafe { assert_eq!(S, *(S as *const *const u8)); } + unsafe { + assert_eq!(S, *(S as *const *const u8)); + } let mut test_vec = Vec::new(); let mut cur = &L1; loop { test_vec.push(cur.data); cur = cur.next; - if cur.head { break } + if cur.head { + break; + } } - assert_eq!(&test_vec, &[1,2,3]); + assert_eq!(&test_vec, &[1, 2, 3]); let mut test_vec = Vec::new(); let mut cur = &L1; loop { cur = cur.prev; test_vec.push(cur.data); - if cur.head { break } + if cur.head { + break; + } } - assert_eq!(&test_vec, &[3,2,1]); + assert_eq!(&test_vec, &[3, 2, 1]); } diff --git a/tests/ui/statics/static-recursive.stderr b/tests/ui/statics/static-recursive.stderr new file mode 100644 index 0000000000000..15888e5c68d84 --- /dev/null +++ b/tests/ui/statics/static-recursive.stderr @@ -0,0 +1,17 @@ +warning: shared reference of mutable static is discouraged + --> $DIR/static-recursive.rs:3:36 + | +LL | static mut S: *const u8 = unsafe { &S as *const *const u8 as *const u8 }; + | ^^ shared reference of mutable static + | + = note: for more information, see issue #114447 <https://github.com/rust-lang/rust/issues/114447> + = note: reference of mutable static is a hard error from 2024 edition + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior + = note: `#[warn(static_mut_ref)]` on by default +help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer + | +LL | static mut S: *const u8 = unsafe { addr_of!(S) as *const *const u8 as *const u8 }; + | ~~~~~~~~~~~ + +warning: 1 warning emitted + diff --git a/tests/ui/thread-local/thread-local-static.rs b/tests/ui/thread-local/thread-local-static.rs index e6cd4839dda7e..f5fb098489746 100644 --- a/tests/ui/thread-local/thread-local-static.rs +++ b/tests/ui/thread-local/thread-local-static.rs @@ -8,7 +8,8 @@ static mut STATIC_VAR_2: [u32; 8] = [4; 8]; const fn g(x: &mut [u32; 8]) { //~^ ERROR mutable references are not allowed std::mem::swap(x, &mut STATIC_VAR_2) - //~^ ERROR thread-local statics cannot be accessed + //~^ WARN mutable reference of mutable static is discouraged [static_mut_ref] + //~^^ ERROR thread-local statics cannot be accessed //~| ERROR mutable references are not allowed //~| ERROR use of mutable static is unsafe //~| constant functions cannot refer to statics diff --git a/tests/ui/thread-local/thread-local-static.stderr b/tests/ui/thread-local/thread-local-static.stderr index c1777dd60db68..b03f4580c2cf1 100644 --- a/tests/ui/thread-local/thread-local-static.stderr +++ b/tests/ui/thread-local/thread-local-static.stderr @@ -1,3 +1,18 @@ +warning: mutable reference of mutable static is discouraged + --> $DIR/thread-local-static.rs:10:23 + | +LL | std::mem::swap(x, &mut STATIC_VAR_2) + | ^^^^^^^^^^^^^^^^^ mutable reference of mutable static + | + = note: for more information, see issue #114447 <https://github.com/rust-lang/rust/issues/114447> + = note: reference of mutable static is a hard error from 2024 edition + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior + = note: `#[warn(static_mut_ref)]` on by default +help: mutable references are dangerous since if there's any other pointer or reference used for that static while the reference lives, that's UB; use `addr_of_mut!` instead to create a raw pointer + | +LL | std::mem::swap(x, addr_of_mut!(STATIC_VAR_2)) + | ~~~~~~~~~~~~~~~~~~~~~~~~~~ + error[E0133]: use of mutable static is unsafe and requires unsafe function or block --> $DIR/thread-local-static.rs:10:28 | @@ -38,7 +53,7 @@ LL | std::mem::swap(x, &mut STATIC_VAR_2) = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable -error: aborting due to 5 previous errors +error: aborting due to 5 previous errors; 1 warning emitted Some errors have detailed explanations: E0013, E0133, E0625, E0658. For more information about an error, try `rustc --explain E0013`. diff --git a/tests/ui/thread-local/thread-local-static.thir.stderr b/tests/ui/thread-local/thread-local-static.thir.stderr new file mode 100644 index 0000000000000..2043b268c090c --- /dev/null +++ b/tests/ui/thread-local/thread-local-static.thir.stderr @@ -0,0 +1,59 @@ +warning: mutable reference of mutable static is discouraged + --> $DIR/thread-local-static.rs:12:23 + | +LL | std::mem::swap(x, &mut STATIC_VAR_2) + | ^^^^^^^^^^^^^^^^^ mutable reference of mutable static + | + = note: for more information, see issue #114447 <https://github.com/rust-lang/rust/issues/114447> + = note: reference of mutable static is a hard error from 2024 edition + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior + = note: `#[warn(static_mut_ref)]` on by default +help: mutable references are dangerous since if there's any other pointer or reference used for that static while the reference lives, that's UB; use `addr_of_mut!` instead to create a raw pointer + | +LL | std::mem::swap(x, addr_of_mut!(STATIC_VAR_2)) + | ~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error[E0658]: mutable references are not allowed in constant functions + --> $DIR/thread-local-static.rs:10:12 + | +LL | const fn g(x: &mut [u32; 8]) { + | ^ + | + = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable + +error[E0625]: thread-local statics cannot be accessed at compile-time + --> $DIR/thread-local-static.rs:12:28 + | +LL | std::mem::swap(x, &mut STATIC_VAR_2) + | ^^^^^^^^^^^^ + +error[E0013]: constant functions cannot refer to statics + --> $DIR/thread-local-static.rs:12:28 + | +LL | std::mem::swap(x, &mut STATIC_VAR_2) + | ^^^^^^^^^^^^ + | + = help: consider extracting the value of the `static` to a `const`, and referring to that + +error[E0658]: mutable references are not allowed in constant functions + --> $DIR/thread-local-static.rs:12:23 + | +LL | std::mem::swap(x, &mut STATIC_VAR_2) + | ^^^^^^^^^^^^^^^^^ + | + = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable + +error[E0133]: use of mutable static is unsafe and requires unsafe function or block + --> $DIR/thread-local-static.rs:12:23 + | +LL | std::mem::swap(x, &mut STATIC_VAR_2) + | ^^^^^^^^^^^^^^^^^ use of mutable static + | + = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior + +error: aborting due to 5 previous errors; 1 warning emitted + +Some errors have detailed explanations: E0013, E0133, E0625, E0658. +For more information about an error, try `rustc --explain E0013`. From 4071572cb416a1740e5530130b0454f9ce2db869 Mon Sep 17 00:00:00 2001 From: Camille GILLOT <gillot.camille@gmail.com> Date: Sun, 7 Jan 2024 14:59:59 +0000 Subject: [PATCH 09/17] Merge dead bb pruning and unreachable bb deduplication. --- compiler/rustc_middle/src/mir/mod.rs | 1 + .../rustc_mir_transform/src/const_goto.rs | 2 +- .../src/deduplicate_blocks.rs | 2 +- .../src/early_otherwise_branch.rs | 2 +- compiler/rustc_mir_transform/src/inline.rs | 5 +- .../rustc_mir_transform/src/match_branches.rs | 2 +- .../src/remove_unneeded_drops.rs | 2 +- .../src/separate_const_switch.rs | 4 +- compiler/rustc_mir_transform/src/simplify.rs | 92 ++++++++----------- ...await.b-{closure#0}.coroutine_resume.0.mir | 6 +- ...ng.identity.JumpThreading.panic-abort.diff | 10 +- ...g.identity.JumpThreading.panic-unwind.diff | 10 +- tests/mir-opt/jump_threading.rs | 8 +- ...d_constant.main.GVN.32bit.panic-abort.diff | 24 ++--- ..._constant.main.GVN.32bit.panic-unwind.diff | 18 ++-- ...d_constant.main.GVN.64bit.panic-abort.diff | 24 ++--- ..._constant.main.GVN.64bit.panic-unwind.diff | 18 ++-- ...t_switch.identity.SeparateConstSwitch.diff | 22 ++--- ...witch.too_complex.SeparateConstSwitch.diff | 28 +++--- 19 files changed, 124 insertions(+), 156 deletions(-) diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index d426f6d8969ac..36f5ba161d5f1 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -1316,6 +1316,7 @@ impl<'tcx> BasicBlockData<'tcx> { } /// Does the block have no statements and an unreachable terminator? + #[inline] pub fn is_empty_unreachable(&self) -> bool { self.statements.is_empty() && matches!(self.terminator().kind, TerminatorKind::Unreachable) } diff --git a/compiler/rustc_mir_transform/src/const_goto.rs b/compiler/rustc_mir_transform/src/const_goto.rs index 3884346076eea..cb5b66b314d69 100644 --- a/compiler/rustc_mir_transform/src/const_goto.rs +++ b/compiler/rustc_mir_transform/src/const_goto.rs @@ -51,7 +51,7 @@ impl<'tcx> MirPass<'tcx> for ConstGoto { // if we applied optimizations, we potentially have some cfg to cleanup to // make it easier for further passes if should_simplify { - simplify_cfg(tcx, body); + simplify_cfg(body); simplify_locals(body, tcx); } } diff --git a/compiler/rustc_mir_transform/src/deduplicate_blocks.rs b/compiler/rustc_mir_transform/src/deduplicate_blocks.rs index b40b2ec8bfdc4..824974970bb3f 100644 --- a/compiler/rustc_mir_transform/src/deduplicate_blocks.rs +++ b/compiler/rustc_mir_transform/src/deduplicate_blocks.rs @@ -25,7 +25,7 @@ impl<'tcx> MirPass<'tcx> for DeduplicateBlocks { if has_opts_to_apply { let mut opt_applier = OptApplier { tcx, duplicates }; opt_applier.visit_body(body); - simplify_cfg(tcx, body); + simplify_cfg(body); } } } diff --git a/compiler/rustc_mir_transform/src/early_otherwise_branch.rs b/compiler/rustc_mir_transform/src/early_otherwise_branch.rs index 6eb6cb069fec0..0d600f0f937de 100644 --- a/compiler/rustc_mir_transform/src/early_otherwise_branch.rs +++ b/compiler/rustc_mir_transform/src/early_otherwise_branch.rs @@ -212,7 +212,7 @@ impl<'tcx> MirPass<'tcx> for EarlyOtherwiseBranch { // Since this optimization adds new basic blocks and invalidates others, // clean up the cfg to make it nicer for other passes if should_cleanup { - simplify_cfg(tcx, body); + simplify_cfg(body); } } } diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs index 8ad804bf3e7aa..ebefc3b47cc4f 100644 --- a/compiler/rustc_mir_transform/src/inline.rs +++ b/compiler/rustc_mir_transform/src/inline.rs @@ -15,7 +15,7 @@ use rustc_target::abi::FieldIdx; use rustc_target::spec::abi::Abi; use crate::cost_checker::CostChecker; -use crate::simplify::{remove_dead_blocks, CfgSimplifier}; +use crate::simplify::simplify_cfg; use crate::util; use std::iter; use std::ops::{Range, RangeFrom}; @@ -56,8 +56,7 @@ impl<'tcx> MirPass<'tcx> for Inline { let _guard = span.enter(); if inline(tcx, body) { debug!("running simplify cfg on {:?}", body.source); - CfgSimplifier::new(body).simplify(); - remove_dead_blocks(body); + simplify_cfg(body); deref_finder(tcx, body); } } diff --git a/compiler/rustc_mir_transform/src/match_branches.rs b/compiler/rustc_mir_transform/src/match_branches.rs index 1c4aa37d57ff5..6d4332793af31 100644 --- a/compiler/rustc_mir_transform/src/match_branches.rs +++ b/compiler/rustc_mir_transform/src/match_branches.rs @@ -174,7 +174,7 @@ impl<'tcx> MirPass<'tcx> for MatchBranchSimplification { } if should_cleanup { - simplify_cfg(tcx, body); + simplify_cfg(body); } } } diff --git a/compiler/rustc_mir_transform/src/remove_unneeded_drops.rs b/compiler/rustc_mir_transform/src/remove_unneeded_drops.rs index 5d528bed35647..2778d91e17b99 100644 --- a/compiler/rustc_mir_transform/src/remove_unneeded_drops.rs +++ b/compiler/rustc_mir_transform/src/remove_unneeded_drops.rs @@ -38,7 +38,7 @@ impl<'tcx> MirPass<'tcx> for RemoveUnneededDrops { // if we applied optimizations, we potentially have some cfg to cleanup to // make it easier for further passes if should_simplify { - simplify_cfg(tcx, body); + simplify_cfg(body); } } } diff --git a/compiler/rustc_mir_transform/src/separate_const_switch.rs b/compiler/rustc_mir_transform/src/separate_const_switch.rs index 6e22690d8dad5..7120ef7214271 100644 --- a/compiler/rustc_mir_transform/src/separate_const_switch.rs +++ b/compiler/rustc_mir_transform/src/separate_const_switch.rs @@ -50,11 +50,11 @@ impl<'tcx> MirPass<'tcx> for SeparateConstSwitch { sess.mir_opt_level() >= 2 && sess.opts.unstable_opts.unsound_mir_opts } - fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + fn run_pass(&self, _: TyCtxt<'tcx>, body: &mut Body<'tcx>) { // If execution did something, applying a simplification layer // helps later passes optimize the copy away. if separate_const_switch(body) > 0 { - super::simplify::simplify_cfg(tcx, body); + super::simplify::simplify_cfg(body); } } } diff --git a/compiler/rustc_mir_transform/src/simplify.rs b/compiler/rustc_mir_transform/src/simplify.rs index 856a0f227714d..8c8818bd68e6f 100644 --- a/compiler/rustc_mir_transform/src/simplify.rs +++ b/compiler/rustc_mir_transform/src/simplify.rs @@ -27,7 +27,6 @@ //! naively generate still contains the `_a = ()` write in the unreachable block "after" the //! return. -use rustc_data_structures::fx::FxIndexSet; use rustc_index::{Idx, IndexSlice, IndexVec}; use rustc_middle::mir::visit::{MutVisitor, MutatingUseContext, PlaceContext, Visitor}; use rustc_middle::mir::*; @@ -62,9 +61,8 @@ impl SimplifyCfg { } } -pub fn simplify_cfg<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { +pub(crate) fn simplify_cfg(body: &mut Body<'_>) { CfgSimplifier::new(body).simplify(); - remove_duplicate_unreachable_blocks(tcx, body); remove_dead_blocks(body); // FIXME: Should probably be moved into some kind of pass manager @@ -76,9 +74,9 @@ impl<'tcx> MirPass<'tcx> for SimplifyCfg { self.name() } - fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + fn run_pass(&self, _: TyCtxt<'tcx>, body: &mut Body<'tcx>) { debug!("SimplifyCfg({:?}) - simplifying {:?}", self.name(), body.source); - simplify_cfg(tcx, body); + simplify_cfg(body); } } @@ -289,55 +287,25 @@ pub fn simplify_duplicate_switch_targets(terminator: &mut Terminator<'_>) { } } -pub fn remove_duplicate_unreachable_blocks<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - struct OptApplier<'tcx> { - tcx: TyCtxt<'tcx>, - duplicates: FxIndexSet<BasicBlock>, - } - - impl<'tcx> MutVisitor<'tcx> for OptApplier<'tcx> { - fn tcx(&self) -> TyCtxt<'tcx> { - self.tcx - } - - fn visit_terminator(&mut self, terminator: &mut Terminator<'tcx>, location: Location) { - for target in terminator.successors_mut() { - // We don't have to check whether `target` is a cleanup block, because have - // entirely excluded cleanup blocks in building the set of duplicates. - if self.duplicates.contains(target) { - *target = self.duplicates[0]; - } - } - - simplify_duplicate_switch_targets(terminator); - - self.super_terminator(terminator, location); - } - } +pub(crate) fn remove_dead_blocks(body: &mut Body<'_>) { + let should_deduplicate_unreachable = |bbdata: &BasicBlockData<'_>| { + // CfgSimplifier::simplify leaves behind some unreachable basic blocks without a + // terminator. Those blocks will be deleted by remove_dead_blocks, but we run just + // before then so we need to handle missing terminators. + // We also need to prevent confusing cleanup and non-cleanup blocks. In practice we + // don't emit empty unreachable cleanup blocks, so this simple check suffices. + bbdata.terminator.is_some() && bbdata.is_empty_unreachable() && !bbdata.is_cleanup + }; - let unreachable_blocks = body + let reachable = traversal::reachable_as_bitset(body); + let empty_unreachable_blocks = body .basic_blocks .iter_enumerated() - .filter(|(_, bb)| { - // CfgSimplifier::simplify leaves behind some unreachable basic blocks without a - // terminator. Those blocks will be deleted by remove_dead_blocks, but we run just - // before then so we need to handle missing terminators. - // We also need to prevent confusing cleanup and non-cleanup blocks. In practice we - // don't emit empty unreachable cleanup blocks, so this simple check suffices. - bb.terminator.is_some() && bb.is_empty_unreachable() && !bb.is_cleanup - }) - .map(|(block, _)| block) - .collect::<FxIndexSet<_>>(); - - if unreachable_blocks.len() > 1 { - OptApplier { tcx, duplicates: unreachable_blocks }.visit_body(body); - } -} + .filter(|(bb, bbdata)| should_deduplicate_unreachable(bbdata) && reachable.contains(*bb)) + .count(); -pub fn remove_dead_blocks(body: &mut Body<'_>) { - let reachable = traversal::reachable_as_bitset(body); let num_blocks = body.basic_blocks.len(); - if num_blocks == reachable.count() { + if num_blocks == reachable.count() && empty_unreachable_blocks <= 1 { return; } @@ -346,14 +314,28 @@ pub fn remove_dead_blocks(body: &mut Body<'_>) { let mut replacements: Vec<_> = (0..num_blocks).map(BasicBlock::new).collect(); let mut orig_index = 0; let mut used_index = 0; - basic_blocks.raw.retain(|_| { - let keep = reachable.contains(BasicBlock::new(orig_index)); - if keep { - replacements[orig_index] = BasicBlock::new(used_index); - used_index += 1; + let mut kept_unreachable = None; + basic_blocks.raw.retain(|bbdata| { + let orig_bb = BasicBlock::new(orig_index); + if !reachable.contains(orig_bb) { + orig_index += 1; + return false; + } + + let used_bb = BasicBlock::new(used_index); + if should_deduplicate_unreachable(bbdata) { + let kept_unreachable = *kept_unreachable.get_or_insert(used_bb); + if kept_unreachable != used_bb { + replacements[orig_index] = kept_unreachable; + orig_index += 1; + return false; + } } + + replacements[orig_index] = used_bb; + used_index += 1; orig_index += 1; - keep + true }); for block in basic_blocks { diff --git a/tests/mir-opt/building/async_await.b-{closure#0}.coroutine_resume.0.mir b/tests/mir-opt/building/async_await.b-{closure#0}.coroutine_resume.0.mir index 3a9c80caa1e64..3c0d4008c9018 100644 --- a/tests/mir-opt/building/async_await.b-{closure#0}.coroutine_resume.0.mir +++ b/tests/mir-opt/building/async_await.b-{closure#0}.coroutine_resume.0.mir @@ -108,7 +108,7 @@ fn b::{closure#0}(_1: Pin<&mut {async fn body@$DIR/async_await.rs:15:18: 18:2}>, bb0: { _39 = discriminant((*(_1.0: &mut {async fn body@$DIR/async_await.rs:15:18: 18:2}))); - switchInt(move _39) -> [0: bb1, 1: bb29, 3: bb27, 4: bb28, otherwise: bb30]; + switchInt(move _39) -> [0: bb1, 1: bb29, 3: bb27, 4: bb28, otherwise: bb9]; } bb1: { @@ -345,8 +345,4 @@ fn b::{closure#0}(_1: Pin<&mut {async fn body@$DIR/async_await.rs:15:18: 18:2}>, bb29: { assert(const false, "`async fn` resumed after completion") -> [success: bb29, unwind unreachable]; } - - bb30: { - unreachable; - } } diff --git a/tests/mir-opt/jump_threading.identity.JumpThreading.panic-abort.diff b/tests/mir-opt/jump_threading.identity.JumpThreading.panic-abort.diff index f50603a66a56f..f04ca72dd6d97 100644 --- a/tests/mir-opt/jump_threading.identity.JumpThreading.panic-abort.diff +++ b/tests/mir-opt/jump_threading.identity.JumpThreading.panic-abort.diff @@ -56,7 +56,7 @@ StorageLive(_11); StorageLive(_12); _10 = discriminant(_4); - switchInt(move _10) -> [0: bb8, 1: bb6, otherwise: bb7]; + switchInt(move _10) -> [0: bb7, 1: bb6, otherwise: bb2]; } bb1: { @@ -114,20 +114,16 @@ _3 = ControlFlow::<Result<Infallible, i32>, i32>::Break(move _13); StorageDead(_13); - goto -> bb5; -+ goto -> bb9; ++ goto -> bb8; } bb7: { - unreachable; - } - - bb8: { _11 = move ((_4 as Ok).0: i32); _3 = ControlFlow::<Result<Infallible, i32>, i32>::Continue(move _11); goto -> bb5; + } + -+ bb9: { ++ bb8: { + StorageDead(_12); + StorageDead(_11); + StorageDead(_10); diff --git a/tests/mir-opt/jump_threading.identity.JumpThreading.panic-unwind.diff b/tests/mir-opt/jump_threading.identity.JumpThreading.panic-unwind.diff index f50603a66a56f..f04ca72dd6d97 100644 --- a/tests/mir-opt/jump_threading.identity.JumpThreading.panic-unwind.diff +++ b/tests/mir-opt/jump_threading.identity.JumpThreading.panic-unwind.diff @@ -56,7 +56,7 @@ StorageLive(_11); StorageLive(_12); _10 = discriminant(_4); - switchInt(move _10) -> [0: bb8, 1: bb6, otherwise: bb7]; + switchInt(move _10) -> [0: bb7, 1: bb6, otherwise: bb2]; } bb1: { @@ -114,20 +114,16 @@ _3 = ControlFlow::<Result<Infallible, i32>, i32>::Break(move _13); StorageDead(_13); - goto -> bb5; -+ goto -> bb9; ++ goto -> bb8; } bb7: { - unreachable; - } - - bb8: { _11 = move ((_4 as Ok).0: i32); _3 = ControlFlow::<Result<Infallible, i32>, i32>::Continue(move _11); goto -> bb5; + } + -+ bb9: { ++ bb8: { + StorageDead(_12); + StorageDead(_11); + StorageDead(_10); diff --git a/tests/mir-opt/jump_threading.rs b/tests/mir-opt/jump_threading.rs index 66e5c5d3c11cb..0cbdaa085bc97 100644 --- a/tests/mir-opt/jump_threading.rs +++ b/tests/mir-opt/jump_threading.rs @@ -50,7 +50,7 @@ fn identity(x: Result<i32, i32>) -> Result<i32, i32> { // CHECK-LABEL: fn identity( // CHECK: bb0: { // CHECK: [[x:_.*]] = _1; - // CHECK: switchInt(move {{_.*}}) -> [0: bb8, 1: bb6, otherwise: bb7]; + // CHECK: switchInt(move {{_.*}}) -> [0: bb7, 1: bb6, otherwise: bb2]; // CHECK: bb1: { // CHECK: {{_.*}} = (([[controlflow:_.*]] as Continue).0: i32); // CHECK: _0 = Result::<i32, i32>::Ok( @@ -68,14 +68,12 @@ fn identity(x: Result<i32, i32>) -> Result<i32, i32> { // CHECK: bb6: { // CHECK: {{_.*}} = move (([[x]] as Err).0: i32); // CHECK: [[controlflow]] = ControlFlow::<Result<Infallible, i32>, i32>::Break( - // CHECK: goto -> bb9; + // CHECK: goto -> bb8; // CHECK: bb7: { - // CHECK: unreachable; - // CHECK: bb8: { // CHECK: {{_.*}} = move (([[x]] as Ok).0: i32); // CHECK: [[controlflow]] = ControlFlow::<Result<Infallible, i32>, i32>::Continue( // CHECK: goto -> bb5; - // CHECK: bb9: { + // CHECK: bb8: { // CHECK: goto -> bb3; Ok(x?) } diff --git a/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.32bit.panic-abort.diff b/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.32bit.panic-abort.diff index 5cb528c0d5f9d..47e0d402347d3 100644 --- a/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.32bit.panic-abort.diff +++ b/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.32bit.panic-abort.diff @@ -56,9 +56,9 @@ + _2 = const Option::<Layout>::None; StorageLive(_10); - _10 = discriminant(_2); -- switchInt(move _10) -> [0: bb1, 1: bb3, otherwise: bb2]; +- switchInt(move _10) -> [0: bb1, 1: bb2, otherwise: bb6]; + _10 = const 0_isize; -+ switchInt(const 0_isize) -> [0: bb1, 1: bb3, otherwise: bb2]; ++ switchInt(const 0_isize) -> [0: bb1, 1: bb2, otherwise: bb6]; } bb1: { @@ -66,10 +66,6 @@ } bb2: { - unreachable; - } - - bb3: { - _1 = move ((_2 as Some).0: std::alloc::Layout); + _1 = const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(4 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x00000000): std::ptr::alignment::AlignmentEnum32) }}; StorageDead(_10); @@ -79,18 +75,18 @@ StorageLive(_5); StorageLive(_6); _9 = const _; -- _6 = std::alloc::Global::alloc_impl(_9, _1, const false) -> [return: bb4, unwind unreachable]; -+ _6 = std::alloc::Global::alloc_impl(const {ALLOC1<imm>: &std::alloc::Global}, const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(4 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x00000000): std::ptr::alignment::AlignmentEnum32) }}, const false) -> [return: bb4, unwind unreachable]; +- _6 = std::alloc::Global::alloc_impl(_9, _1, const false) -> [return: bb3, unwind unreachable]; ++ _6 = std::alloc::Global::alloc_impl(const {ALLOC1<imm>: &std::alloc::Global}, const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(4 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x00000000): std::ptr::alignment::AlignmentEnum32) }}, const false) -> [return: bb3, unwind unreachable]; } - bb4: { + bb3: { StorageLive(_12); StorageLive(_15); _12 = discriminant(_6); - switchInt(move _12) -> [0: bb6, 1: bb5, otherwise: bb2]; + switchInt(move _12) -> [0: bb5, 1: bb4, otherwise: bb6]; } - bb5: { + bb4: { _15 = const "called `Result::unwrap()` on an `Err` value"; StorageLive(_16); StorageLive(_17); @@ -100,7 +96,7 @@ _14 = result::unwrap_failed(move _15, move _16) -> unwind unreachable; } - bb6: { + bb5: { _5 = move ((_6 as Ok).0: std::ptr::NonNull<[u8]>); StorageDead(_15); StorageDead(_12); @@ -115,6 +111,10 @@ StorageDead(_3); return; } + + bb6: { + unreachable; + } } + + ALLOC0 (size: 8, align: 4) { diff --git a/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.32bit.panic-unwind.diff b/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.32bit.panic-unwind.diff index 1e1585f20aefa..dee57ce6c27bb 100644 --- a/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.32bit.panic-unwind.diff +++ b/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.32bit.panic-unwind.diff @@ -41,9 +41,9 @@ + _2 = const Option::<Layout>::None; StorageLive(_10); - _10 = discriminant(_2); -- switchInt(move _10) -> [0: bb2, 1: bb4, otherwise: bb3]; +- switchInt(move _10) -> [0: bb2, 1: bb3, otherwise: bb5]; + _10 = const 0_isize; -+ switchInt(const 0_isize) -> [0: bb2, 1: bb4, otherwise: bb3]; ++ switchInt(const 0_isize) -> [0: bb2, 1: bb3, otherwise: bb5]; } bb1: { @@ -64,10 +64,6 @@ } bb3: { - unreachable; - } - - bb4: { - _1 = move ((_2 as Some).0: std::alloc::Layout); + _1 = const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(4 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x00000000): std::ptr::alignment::AlignmentEnum32) }}; StorageDead(_10); @@ -77,13 +73,17 @@ StorageLive(_5); StorageLive(_6); _9 = const _; -- _6 = std::alloc::Global::alloc_impl(_9, _1, const false) -> [return: bb5, unwind continue]; -+ _6 = std::alloc::Global::alloc_impl(const {ALLOC1<imm>: &std::alloc::Global}, const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(4 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x00000000): std::ptr::alignment::AlignmentEnum32) }}, const false) -> [return: bb5, unwind continue]; +- _6 = std::alloc::Global::alloc_impl(_9, _1, const false) -> [return: bb4, unwind continue]; ++ _6 = std::alloc::Global::alloc_impl(const {ALLOC1<imm>: &std::alloc::Global}, const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(4 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x00000000): std::ptr::alignment::AlignmentEnum32) }}, const false) -> [return: bb4, unwind continue]; } - bb5: { + bb4: { _5 = Result::<NonNull<[u8]>, std::alloc::AllocError>::unwrap(move _6) -> [return: bb1, unwind continue]; } + + bb5: { + unreachable; + } } + + ALLOC0 (size: 8, align: 4) { diff --git a/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.64bit.panic-abort.diff b/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.64bit.panic-abort.diff index e655af559a18a..a255b15920cba 100644 --- a/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.64bit.panic-abort.diff +++ b/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.64bit.panic-abort.diff @@ -56,9 +56,9 @@ + _2 = const Option::<Layout>::None; StorageLive(_10); - _10 = discriminant(_2); -- switchInt(move _10) -> [0: bb1, 1: bb3, otherwise: bb2]; +- switchInt(move _10) -> [0: bb1, 1: bb2, otherwise: bb6]; + _10 = const 0_isize; -+ switchInt(const 0_isize) -> [0: bb1, 1: bb3, otherwise: bb2]; ++ switchInt(const 0_isize) -> [0: bb1, 1: bb2, otherwise: bb6]; } bb1: { @@ -66,10 +66,6 @@ } bb2: { - unreachable; - } - - bb3: { - _1 = move ((_2 as Some).0: std::alloc::Layout); + _1 = const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(8 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x0000000000000000): std::ptr::alignment::AlignmentEnum64) }}; StorageDead(_10); @@ -79,18 +75,18 @@ StorageLive(_5); StorageLive(_6); _9 = const _; -- _6 = std::alloc::Global::alloc_impl(_9, _1, const false) -> [return: bb4, unwind unreachable]; -+ _6 = std::alloc::Global::alloc_impl(const {ALLOC1<imm>: &std::alloc::Global}, const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(8 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x0000000000000000): std::ptr::alignment::AlignmentEnum64) }}, const false) -> [return: bb4, unwind unreachable]; +- _6 = std::alloc::Global::alloc_impl(_9, _1, const false) -> [return: bb3, unwind unreachable]; ++ _6 = std::alloc::Global::alloc_impl(const {ALLOC1<imm>: &std::alloc::Global}, const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(8 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x0000000000000000): std::ptr::alignment::AlignmentEnum64) }}, const false) -> [return: bb3, unwind unreachable]; } - bb4: { + bb3: { StorageLive(_12); StorageLive(_15); _12 = discriminant(_6); - switchInt(move _12) -> [0: bb6, 1: bb5, otherwise: bb2]; + switchInt(move _12) -> [0: bb5, 1: bb4, otherwise: bb6]; } - bb5: { + bb4: { _15 = const "called `Result::unwrap()` on an `Err` value"; StorageLive(_16); StorageLive(_17); @@ -100,7 +96,7 @@ _14 = result::unwrap_failed(move _15, move _16) -> unwind unreachable; } - bb6: { + bb5: { _5 = move ((_6 as Ok).0: std::ptr::NonNull<[u8]>); StorageDead(_15); StorageDead(_12); @@ -115,6 +111,10 @@ StorageDead(_3); return; } + + bb6: { + unreachable; + } } + + ALLOC0 (size: 16, align: 8) { diff --git a/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.64bit.panic-unwind.diff b/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.64bit.panic-unwind.diff index a6658713a026b..192ffea259157 100644 --- a/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.64bit.panic-unwind.diff +++ b/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.64bit.panic-unwind.diff @@ -41,9 +41,9 @@ + _2 = const Option::<Layout>::None; StorageLive(_10); - _10 = discriminant(_2); -- switchInt(move _10) -> [0: bb2, 1: bb4, otherwise: bb3]; +- switchInt(move _10) -> [0: bb2, 1: bb3, otherwise: bb5]; + _10 = const 0_isize; -+ switchInt(const 0_isize) -> [0: bb2, 1: bb4, otherwise: bb3]; ++ switchInt(const 0_isize) -> [0: bb2, 1: bb3, otherwise: bb5]; } bb1: { @@ -64,10 +64,6 @@ } bb3: { - unreachable; - } - - bb4: { - _1 = move ((_2 as Some).0: std::alloc::Layout); + _1 = const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(8 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x0000000000000000): std::ptr::alignment::AlignmentEnum64) }}; StorageDead(_10); @@ -77,13 +73,17 @@ StorageLive(_5); StorageLive(_6); _9 = const _; -- _6 = std::alloc::Global::alloc_impl(_9, _1, const false) -> [return: bb5, unwind continue]; -+ _6 = std::alloc::Global::alloc_impl(const {ALLOC1<imm>: &std::alloc::Global}, const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(8 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x0000000000000000): std::ptr::alignment::AlignmentEnum64) }}, const false) -> [return: bb5, unwind continue]; +- _6 = std::alloc::Global::alloc_impl(_9, _1, const false) -> [return: bb4, unwind continue]; ++ _6 = std::alloc::Global::alloc_impl(const {ALLOC1<imm>: &std::alloc::Global}, const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(8 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x0000000000000000): std::ptr::alignment::AlignmentEnum64) }}, const false) -> [return: bb4, unwind continue]; } - bb5: { + bb4: { _5 = Result::<NonNull<[u8]>, std::alloc::AllocError>::unwrap(move _6) -> [return: bb1, unwind continue]; } + + bb5: { + unreachable; + } } + + ALLOC0 (size: 16, align: 8) { diff --git a/tests/mir-opt/separate_const_switch.identity.SeparateConstSwitch.diff b/tests/mir-opt/separate_const_switch.identity.SeparateConstSwitch.diff index d287b20c4ead0..a12db0a730c57 100644 --- a/tests/mir-opt/separate_const_switch.identity.SeparateConstSwitch.diff +++ b/tests/mir-opt/separate_const_switch.identity.SeparateConstSwitch.diff @@ -52,7 +52,7 @@ StorageLive(_10); StorageLive(_11); _9 = discriminant(_1); - switchInt(move _9) -> [0: bb6, 1: bb5, otherwise: bb2]; + switchInt(move _9) -> [0: bb5, 1: bb4, otherwise: bb6]; } bb1: { @@ -63,10 +63,6 @@ } bb2: { - unreachable; - } - - bb3: { _6 = ((_3 as Break).0: std::result::Result<std::convert::Infallible, i32>); _13 = ((_6 as Err).0: i32); _0 = Result::<i32, i32>::Err(move _13); @@ -74,27 +70,31 @@ return; } - bb4: { + bb3: { StorageDead(_11); StorageDead(_10); StorageDead(_9); _5 = discriminant(_3); - switchInt(move _5) -> [0: bb1, 1: bb3, otherwise: bb2]; + switchInt(move _5) -> [0: bb1, 1: bb2, otherwise: bb6]; } - bb5: { + bb4: { _11 = ((_1 as Err).0: i32); StorageLive(_12); _12 = Result::<Infallible, i32>::Err(move _11); _3 = ControlFlow::<Result<Infallible, i32>, i32>::Break(move _12); StorageDead(_12); - goto -> bb4; + goto -> bb3; } - bb6: { + bb5: { _10 = ((_1 as Ok).0: i32); _3 = ControlFlow::<Result<Infallible, i32>, i32>::Continue(move _10); - goto -> bb4; + goto -> bb3; + } + + bb6: { + unreachable; } } diff --git a/tests/mir-opt/separate_const_switch.too_complex.SeparateConstSwitch.diff b/tests/mir-opt/separate_const_switch.too_complex.SeparateConstSwitch.diff index e2bf33f7fbcc0..80f40b86919eb 100644 --- a/tests/mir-opt/separate_const_switch.too_complex.SeparateConstSwitch.diff +++ b/tests/mir-opt/separate_const_switch.too_complex.SeparateConstSwitch.diff @@ -30,47 +30,47 @@ bb0: { StorageLive(_2); _3 = discriminant(_1); - switchInt(move _3) -> [0: bb3, 1: bb1, otherwise: bb2]; + switchInt(move _3) -> [0: bb2, 1: bb1, otherwise: bb7]; } bb1: { _6 = ((_1 as Err).0: usize); _2 = ControlFlow::<usize, i32>::Break(_6); - goto -> bb4; + goto -> bb3; } bb2: { - unreachable; - } - - bb3: { _4 = ((_1 as Ok).0: i32); _2 = ControlFlow::<usize, i32>::Continue(_4); - goto -> bb4; + goto -> bb3; } - bb4: { + bb3: { _8 = discriminant(_2); - switchInt(move _8) -> [0: bb6, 1: bb5, otherwise: bb2]; + switchInt(move _8) -> [0: bb5, 1: bb4, otherwise: bb7]; } - bb5: { + bb4: { StorageLive(_11); _11 = ((_2 as Break).0: usize); _0 = Option::<i32>::None; StorageDead(_11); - goto -> bb7; + goto -> bb6; } - bb6: { + bb5: { _9 = ((_2 as Continue).0: i32); _0 = Option::<i32>::Some(_9); - goto -> bb7; + goto -> bb6; } - bb7: { + bb6: { StorageDead(_2); return; } + + bb7: { + unreachable; + } } From e61be1bfae982b991828d3edd64a0eaea8bc2d55 Mon Sep 17 00:00:00 2001 From: Michael Howell <michael@notriddle.com> Date: Mon, 8 Jan 2024 12:00:40 -0700 Subject: [PATCH 10/17] rustdoc-search: reuse empty map/array in function signatures Map is implemented as a pointer to a mutable object. Rustdoc never mutates function signatures after constructing them, but the JS engine doesn't know that. To save a bunch of memory, use a single immutable map for every decoded type object with no bindings or generics. --- src/librustdoc/html/static/js/search.js | 26 ++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js index a5e2bc1c7afd0..5bd375a86a787 100644 --- a/src/librustdoc/html/static/js/search.js +++ b/src/librustdoc/html/static/js/search.js @@ -2717,9 +2717,25 @@ ${item.displayPath}<span class="${type}">${name}</span>\ * @return {Array<FunctionSearchType>} */ function buildItemSearchTypeAll(types, lowercasePaths) { - return types.map(type => buildItemSearchType(type, lowercasePaths)); + return types.length > 0 ? + types.map(type => buildItemSearchType(type, lowercasePaths)) : + EMPTY_GENERICS_ARRAY; } + /** + * Empty, immutable map used in item search types with no bindings. + * + * @type {Map<integer, Array<Functiontype>>} + */ + const EMPTY_BINDINGS_MAP = new Map(); + + /** + * Empty, immutable map used in item search types with no bindings. + * + * @type {Array<Functiontype>} + */ + const EMPTY_GENERICS_ARRAY = []; + /** * Converts a single type. * @@ -2732,15 +2748,15 @@ ${item.displayPath}<span class="${type}">${name}</span>\ let pathIndex, generics, bindings; if (typeof type === "number") { pathIndex = type; - generics = []; - bindings = new Map(); + generics = EMPTY_GENERICS_ARRAY; + bindings = EMPTY_BINDINGS_MAP; } else { pathIndex = type[PATH_INDEX_DATA]; generics = buildItemSearchTypeAll( type[GENERICS_DATA], lowercasePaths ); - if (type.length > BINDINGS_DATA) { + if (type.length > BINDINGS_DATA && type[BINDINGS_DATA].length > 0) { bindings = new Map(type[BINDINGS_DATA].map(binding => { const [assocType, constraints] = binding; // Associated type constructors are represented sloppily in rustdoc's @@ -2759,7 +2775,7 @@ ${item.displayPath}<span class="${type}">${name}</span>\ ]; })); } else { - bindings = new Map(); + bindings = EMPTY_BINDINGS_MAP; } } if (pathIndex < 0) { From 835680286207b633f4727310829a709b585f7b56 Mon Sep 17 00:00:00 2001 From: Camille GILLOT <gillot.camille@gmail.com> Date: Sat, 20 May 2023 08:21:56 +0000 Subject: [PATCH 11/17] Move promote_consts back to rustc_mir_transform. --- .../rustc_const_eval/src/transform/mod.rs | 1 - compiler/rustc_mir_transform/src/lib.rs | 2 +- .../src}/promote_consts.rs | 19 ++++++------------- 3 files changed, 7 insertions(+), 15 deletions(-) rename compiler/{rustc_const_eval/src/transform => rustc_mir_transform/src}/promote_consts.rs (99%) diff --git a/compiler/rustc_const_eval/src/transform/mod.rs b/compiler/rustc_const_eval/src/transform/mod.rs index a2928bdf51b83..e3582c7d31746 100644 --- a/compiler/rustc_const_eval/src/transform/mod.rs +++ b/compiler/rustc_const_eval/src/transform/mod.rs @@ -1,3 +1,2 @@ pub mod check_consts; -pub mod promote_consts; pub mod validate; diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index f5f51c0ec8ad1..dfc4ff3b7a353 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -93,6 +93,7 @@ mod multiple_return_terminators; mod normalize_array_len; mod nrvo; mod prettify; +mod promote_consts; mod ref_prop; mod remove_noop_landing_pads; mod remove_storage_markers; @@ -114,7 +115,6 @@ mod uninhabited_enum_branching; mod unreachable_prop; use rustc_const_eval::transform::check_consts::{self, ConstCx}; -use rustc_const_eval::transform::promote_consts; use rustc_const_eval::transform::validate; use rustc_mir_dataflow::rustc_peek; diff --git a/compiler/rustc_const_eval/src/transform/promote_consts.rs b/compiler/rustc_mir_transform/src/promote_consts.rs similarity index 99% rename from compiler/rustc_const_eval/src/transform/promote_consts.rs rename to compiler/rustc_mir_transform/src/promote_consts.rs index 155cf4ff9e2c7..9a60e83d322f6 100644 --- a/compiler/rustc_const_eval/src/transform/promote_consts.rs +++ b/compiler/rustc_mir_transform/src/promote_consts.rs @@ -25,7 +25,7 @@ use rustc_index::{Idx, IndexSlice, IndexVec}; use std::cell::Cell; use std::{cmp, iter, mem}; -use crate::transform::check_consts::{qualifs, ConstCx}; +use rustc_const_eval::transform::check_consts::{qualifs, ConstCx}; /// A `MirPass` for promotion. /// @@ -64,7 +64,7 @@ impl<'tcx> MirPass<'tcx> for PromoteTemps<'tcx> { /// State of a temporary during collection and promotion. #[derive(Copy, Clone, PartialEq, Eq, Debug)] -pub enum TempState { +enum TempState { /// No references to this temp. Undefined, /// One direct assignment and any number of direct uses. @@ -78,18 +78,11 @@ pub enum TempState { PromotedOut, } -impl TempState { - pub fn is_promotable(&self) -> bool { - debug!("is_promotable: self={:?}", self); - matches!(self, TempState::Defined { .. }) - } -} - /// A "root candidate" for promotion, which will become the /// returned value in a promoted MIR, unless it's a subset /// of a larger candidate. #[derive(Copy, Clone, PartialEq, Eq, Debug)] -pub struct Candidate { +struct Candidate { location: Location, } @@ -162,7 +155,7 @@ impl<'tcx> Visitor<'tcx> for Collector<'_, 'tcx> { } } -pub fn collect_temps_and_candidates<'tcx>( +fn collect_temps_and_candidates<'tcx>( ccx: &ConstCx<'_, 'tcx>, ) -> (IndexVec<Local, TempState>, Vec<Candidate>) { let mut collector = Collector { @@ -676,7 +669,7 @@ impl<'tcx> Validator<'_, 'tcx> { } // FIXME(eddyb) remove the differences for promotability in `static`, `const`, `const fn`. -pub fn validate_candidates( +fn validate_candidates( ccx: &ConstCx<'_, '_>, temps: &mut IndexSlice<Local, TempState>, candidates: &[Candidate], @@ -930,7 +923,7 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Promoter<'a, 'tcx> { } } -pub fn promote_candidates<'tcx>( +fn promote_candidates<'tcx>( body: &mut Body<'tcx>, tcx: TyCtxt<'tcx>, mut temps: IndexVec<Local, TempState>, From cae0dc28332065dfa3fa168fdc1f2818bcbdf0c3 Mon Sep 17 00:00:00 2001 From: Camille GILLOT <gillot.camille@gmail.com> Date: Sat, 20 May 2023 08:54:16 +0000 Subject: [PATCH 12/17] Simplify code flow. --- compiler/rustc_mir_transform/src/lib.rs | 1 + .../rustc_mir_transform/src/promote_consts.rs | 378 ++++++++---------- 2 files changed, 157 insertions(+), 222 deletions(-) diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index dfc4ff3b7a353..915ddcb2775dc 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -1,5 +1,6 @@ #![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::diagnostic_outside_of_impl)] +#![feature(assert_matches)] #![feature(box_patterns)] #![feature(cow_is_borrowed)] #![feature(decl_macro)] diff --git a/compiler/rustc_mir_transform/src/promote_consts.rs b/compiler/rustc_mir_transform/src/promote_consts.rs index 9a60e83d322f6..9b9c9aae88bfd 100644 --- a/compiler/rustc_mir_transform/src/promote_consts.rs +++ b/compiler/rustc_mir_transform/src/promote_consts.rs @@ -12,6 +12,7 @@ //! initialization and can otherwise silence errors, if //! move analysis runs after promotion on broken MIR. +use either::{Left, Right}; use rustc_hir as hir; use rustc_middle::mir; use rustc_middle::mir::visit::{MutVisitor, MutatingUseContext, PlaceContext, Visitor}; @@ -22,6 +23,7 @@ use rustc_span::Span; use rustc_index::{Idx, IndexSlice, IndexVec}; +use std::assert_matches::assert_matches; use std::cell::Cell; use std::{cmp, iter, mem}; @@ -116,41 +118,38 @@ impl<'tcx> Visitor<'tcx> for Collector<'_, 'tcx> { let temp = &mut self.temps[index]; debug!("visit_local: temp={:?}", temp); - if *temp == TempState::Undefined { - match context { + *temp = match *temp { + TempState::Undefined => match context { PlaceContext::MutatingUse(MutatingUseContext::Store) | PlaceContext::MutatingUse(MutatingUseContext::Call) => { - *temp = TempState::Defined { location, uses: 0, valid: Err(()) }; + TempState::Defined { location, uses: 0, valid: Err(()) } + } + _ => TempState::Unpromotable, + }, + TempState::Defined { ref mut uses, .. } => { + // We always allow borrows, even mutable ones, as we need + // to promote mutable borrows of some ZSTs e.g., `&mut []`. + let allowed_use = match context { + PlaceContext::MutatingUse(MutatingUseContext::Borrow) + | PlaceContext::NonMutatingUse(_) => true, + PlaceContext::MutatingUse(_) | PlaceContext::NonUse(_) => false, + }; + debug!("visit_local: allowed_use={:?}", allowed_use); + if allowed_use { + *uses += 1; return; } - _ => { /* mark as unpromotable below */ } + TempState::Unpromotable } - } else if let TempState::Defined { uses, .. } = temp { - // We always allow borrows, even mutable ones, as we need - // to promote mutable borrows of some ZSTs e.g., `&mut []`. - let allowed_use = match context { - PlaceContext::MutatingUse(MutatingUseContext::Borrow) - | PlaceContext::NonMutatingUse(_) => true, - PlaceContext::MutatingUse(_) | PlaceContext::NonUse(_) => false, - }; - debug!("visit_local: allowed_use={:?}", allowed_use); - if allowed_use { - *uses += 1; - return; - } - /* mark as unpromotable below */ - } - *temp = TempState::Unpromotable; + _ => TempState::Unpromotable, + }; } fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) { self.super_rvalue(rvalue, location); - match *rvalue { - Rvalue::Ref(..) => { - self.candidates.push(Candidate { location }); - } - _ => {} + if let Rvalue::Ref(..) = *rvalue { + self.candidates.push(Candidate { location }); } } } @@ -189,230 +188,165 @@ struct Unpromotable; impl<'tcx> Validator<'_, 'tcx> { fn validate_candidate(&mut self, candidate: Candidate) -> Result<(), Unpromotable> { - let loc = candidate.location; - let statement = &self.body[loc.block].statements[loc.statement_index]; - match &statement.kind { - StatementKind::Assign(box (_, Rvalue::Ref(_, kind, place))) => { - // We can only promote interior borrows of promotable temps (non-temps - // don't get promoted anyway). - self.validate_local(place.local)?; - - // The reference operation itself must be promotable. - // (Needs to come after `validate_local` to avoid ICEs.) - self.validate_ref(*kind, place)?; + let Left(statement) = self.body.stmt_at(candidate.location) else { bug!() }; + let Some((_, Rvalue::Ref(_, kind, place))) = statement.kind.as_assign() else { bug!() }; - // We do not check all the projections (they do not get promoted anyway), - // but we do stay away from promoting anything involving a dereference. - if place.projection.contains(&ProjectionElem::Deref) { - return Err(Unpromotable); - } + // We can only promote interior borrows of promotable temps (non-temps + // don't get promoted anyway). + self.validate_local(place.local)?; - Ok(()) - } - _ => bug!(), + // The reference operation itself must be promotable. + // (Needs to come after `validate_local` to avoid ICEs.) + self.validate_ref(*kind, place)?; + + // We do not check all the projections (they do not get promoted anyway), + // but we do stay away from promoting anything involving a dereference. + if place.projection.contains(&ProjectionElem::Deref) { + return Err(Unpromotable); } + + Ok(()) } // FIXME(eddyb) maybe cache this? fn qualif_local<Q: qualifs::Qualif>(&mut self, local: Local) -> bool { - if let TempState::Defined { location: loc, .. } = self.temps[local] { - let num_stmts = self.body[loc.block].statements.len(); - - if loc.statement_index < num_stmts { - let statement = &self.body[loc.block].statements[loc.statement_index]; - match &statement.kind { - StatementKind::Assign(box (_, rhs)) => qualifs::in_rvalue::<Q, _>( - self.ccx, - &mut |l| self.qualif_local::<Q>(l), - rhs, - ), - _ => { + let TempState::Defined { location: loc, .. } = self.temps[local] else { + return false; + }; + + let stmt_or_term = self.body.stmt_at(loc); + match stmt_or_term { + Left(statement) => { + let Some((_, rhs)) = statement.kind.as_assign() else { + span_bug!(statement.source_info.span, "{:?} is not an assignment", statement) + }; + qualifs::in_rvalue::<Q, _>(self.ccx, &mut |l| self.qualif_local::<Q>(l), rhs) + } + Right(terminator) => { + assert_matches!(terminator.kind, TerminatorKind::Call { .. }); + let return_ty = self.body.local_decls[local].ty; + Q::in_any_value_of_ty(self.ccx, return_ty) + } + } + } + + fn validate_local(&mut self, local: Local) -> Result<(), Unpromotable> { + let TempState::Defined { location: loc, uses, valid } = self.temps[local] else { + return Err(Unpromotable); + }; + + // We cannot promote things that need dropping, since the promoted value would not get + // dropped. + if self.qualif_local::<qualifs::NeedsDrop>(local) { + return Err(Unpromotable); + } + + if valid.is_ok() { + return Ok(()); + } + + let ok = { + let stmt_or_term = self.body.stmt_at(loc); + match stmt_or_term { + Left(statement) => { + let Some((_, rhs)) = statement.kind.as_assign() else { span_bug!( statement.source_info.span, "{:?} is not an assignment", statement - ); - } + ) + }; + self.validate_rvalue(rhs) } - } else { - let terminator = self.body[loc.block].terminator(); - match &terminator.kind { - TerminatorKind::Call { .. } => { - let return_ty = self.body.local_decls[local].ty; - Q::in_any_value_of_ty(self.ccx, return_ty) - } + Right(terminator) => match &terminator.kind { + TerminatorKind::Call { func, args, .. } => self.validate_call(func, args), + TerminatorKind::Yield { .. } => Err(Unpromotable), kind => { span_bug!(terminator.source_info.span, "{:?} not promotable", kind); } - } + }, } - } else { - false - } - } + }; - fn validate_local(&mut self, local: Local) -> Result<(), Unpromotable> { - if let TempState::Defined { location: loc, uses, valid } = self.temps[local] { - // We cannot promote things that need dropping, since the promoted value - // would not get dropped. - if self.qualif_local::<qualifs::NeedsDrop>(local) { - return Err(Unpromotable); - } - valid.or_else(|_| { - let ok = { - let block = &self.body[loc.block]; - let num_stmts = block.statements.len(); - - if loc.statement_index < num_stmts { - let statement = &block.statements[loc.statement_index]; - match &statement.kind { - StatementKind::Assign(box (_, rhs)) => self.validate_rvalue(rhs), - _ => { - span_bug!( - statement.source_info.span, - "{:?} is not an assignment", - statement - ); - } - } - } else { - let terminator = block.terminator(); - match &terminator.kind { - TerminatorKind::Call { func, args, .. } => { - self.validate_call(func, args) - } - TerminatorKind::Yield { .. } => Err(Unpromotable), - kind => { - span_bug!(terminator.source_info.span, "{:?} not promotable", kind); - } - } - } - }; - self.temps[local] = match ok { - Ok(()) => TempState::Defined { location: loc, uses, valid: Ok(()) }, - Err(_) => TempState::Unpromotable, - }; - ok - }) - } else { - Err(Unpromotable) - } + self.temps[local] = match ok { + Ok(()) => TempState::Defined { location: loc, uses, valid: Ok(()) }, + Err(_) => TempState::Unpromotable, + }; + + ok } fn validate_place(&mut self, place: PlaceRef<'tcx>) -> Result<(), Unpromotable> { - match place.last_projection() { - None => self.validate_local(place.local), - Some((place_base, elem)) => { - // Validate topmost projection, then recurse. - match elem { - ProjectionElem::Deref => { - let mut promotable = false; - // When a static is used by-value, that gets desugared to `*STATIC_ADDR`, - // and we need to be able to promote this. So check if this deref matches - // that specific pattern. - - // We need to make sure this is a `Deref` of a local with no further projections. - // Discussion can be found at - // https://github.com/rust-lang/rust/pull/74945#discussion_r463063247 - if let Some(local) = place_base.as_local() { - if let TempState::Defined { location, .. } = self.temps[local] { - let def_stmt = self.body[location.block] - .statements - .get(location.statement_index); - if let Some(Statement { - kind: - StatementKind::Assign(box ( - _, - Rvalue::Use(Operand::Constant(c)), - )), - .. - }) = def_stmt - { - if let Some(did) = c.check_static_ptr(self.tcx) { - // Evaluating a promoted may not read statics except if it got - // promoted from a static (this is a CTFE check). So we - // can only promote static accesses inside statics. - if let Some(hir::ConstContext::Static(..)) = self.const_kind - { - if !self.tcx.is_thread_local_static(did) { - promotable = true; - } - } - } - } - } - } - if !promotable { - return Err(Unpromotable); - } - } - ProjectionElem::OpaqueCast(..) | ProjectionElem::Downcast(..) => { - return Err(Unpromotable); - } + let Some((place_base, elem)) = place.last_projection() else { + return self.validate_local(place.local); + }; - ProjectionElem::ConstantIndex { .. } - | ProjectionElem::Subtype(_) - | ProjectionElem::Subslice { .. } => {} - - ProjectionElem::Index(local) => { - let mut promotable = false; - // Only accept if we can predict the index and are indexing an array. - let val = if let TempState::Defined { location: loc, .. } = - self.temps[local] - { - let block = &self.body[loc.block]; - if loc.statement_index < block.statements.len() { - let statement = &block.statements[loc.statement_index]; - match &statement.kind { - StatementKind::Assign(box ( - _, - Rvalue::Use(Operand::Constant(c)), - )) => c.const_.try_eval_target_usize(self.tcx, self.param_env), - _ => None, - } - } else { - None - } - } else { - None - }; - if let Some(idx) = val { - // Determine the type of the thing we are indexing. - let ty = place_base.ty(self.body, self.tcx).ty; - match ty.kind() { - ty::Array(_, len) => { - // It's an array; determine its length. - if let Some(len) = - len.try_eval_target_usize(self.tcx, self.param_env) - { - // If the index is in-bounds, go ahead. - if idx < len { - promotable = true; - } - } - } - _ => {} - } - } - if !promotable { - return Err(Unpromotable); - } + // Validate topmost projection, then recurse. + match elem { + // Recurse directly. + ProjectionElem::ConstantIndex { .. } + | ProjectionElem::Subtype(_) + | ProjectionElem::Subslice { .. } => {} - self.validate_local(local)?; - } + // Never recurse. + ProjectionElem::OpaqueCast(..) | ProjectionElem::Downcast(..) => { + return Err(Unpromotable); + } - ProjectionElem::Field(..) => { - let base_ty = place_base.ty(self.body, self.tcx).ty; - if base_ty.is_union() { - // No promotion of union field accesses. - return Err(Unpromotable); - } - } + ProjectionElem::Deref => { + // When a static is used by-value, that gets desugared to `*STATIC_ADDR`, + // and we need to be able to promote this. So check if this deref matches + // that specific pattern. + + // We need to make sure this is a `Deref` of a local with no further projections. + // Discussion can be found at + // https://github.com/rust-lang/rust/pull/74945#discussion_r463063247 + if let Some(local) = place_base.as_local() + && let TempState::Defined { location, .. } = self.temps[local] + && let Left(def_stmt) = self.body.stmt_at(location) + && let Some((_, Rvalue::Use(Operand::Constant(c)))) = def_stmt.kind.as_assign() + && let Some(did) = c.check_static_ptr(self.tcx) + // Evaluating a promoted may not read statics except if it got + // promoted from a static (this is a CTFE check). So we + // can only promote static accesses inside statics. + && let Some(hir::ConstContext::Static(..)) = self.const_kind + && !self.tcx.is_thread_local_static(did) + { + // Recurse. + } else { + return Err(Unpromotable); } + } + ProjectionElem::Index(local) => { + // Only accept if we can predict the index and are indexing an array. + if let TempState::Defined { location: loc, .. } = self.temps[local] + && let Left(statement) = self.body.stmt_at(loc) + && let Some((_, Rvalue::Use(Operand::Constant(c)))) = statement.kind.as_assign() + && let Some(idx) = c.const_.try_eval_target_usize(self.tcx, self.param_env) + // Determine the type of the thing we are indexing. + && let ty::Array(_, len) = place_base.ty(self.body, self.tcx).ty.kind() + // It's an array; determine its length. + && let Some(len) = len.try_eval_target_usize(self.tcx, self.param_env) + // If the index is in-bounds, go ahead. + && idx < len + { + self.validate_local(local)?; + // Recurse. + } else { + return Err(Unpromotable); + } + } - self.validate_place(place_base) + ProjectionElem::Field(..) => { + let base_ty = place_base.ty(self.body, self.tcx).ty; + if base_ty.is_union() { + // No promotion of union field accesses. + return Err(Unpromotable); + } } } + + self.validate_place(place_base) } fn validate_operand(&mut self, operand: &Operand<'tcx>) -> Result<(), Unpromotable> { From 5d6463c26c0f20f855da4ca54caa583c2258fb2f Mon Sep 17 00:00:00 2001 From: Camille GILLOT <gillot.camille@gmail.com> Date: Mon, 8 Jan 2024 22:40:32 +0000 Subject: [PATCH 13/17] Make match exhaustive. --- compiler/rustc_mir_transform/src/promote_consts.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_mir_transform/src/promote_consts.rs b/compiler/rustc_mir_transform/src/promote_consts.rs index 9b9c9aae88bfd..841b86fed4548 100644 --- a/compiler/rustc_mir_transform/src/promote_consts.rs +++ b/compiler/rustc_mir_transform/src/promote_consts.rs @@ -141,7 +141,7 @@ impl<'tcx> Visitor<'tcx> for Collector<'_, 'tcx> { } TempState::Unpromotable } - _ => TempState::Unpromotable, + TempState::Unpromotable | TempState::PromotedOut => TempState::Unpromotable, }; } From a2b765fc37e2de38502912aea051d3fdde42357c Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote <n.nethercote@gmail.com> Date: Mon, 8 Jan 2024 09:43:58 +1100 Subject: [PATCH 14/17] Remove `-Zdont-buffer-diagnostics`. It was added in #54232. It seems like it was aimed at NLL development, which is well in the past. Also, it looks like `-Ztreat-err-as-bug` can be used to achieve the same effect. So it doesn't seem necessary. --- compiler/rustc_errors/src/diagnostic_builder.rs | 3 +-- compiler/rustc_errors/src/lib.rs | 3 --- compiler/rustc_interface/src/tests.rs | 1 - compiler/rustc_session/src/config.rs | 1 - compiler/rustc_session/src/options.rs | 3 --- 5 files changed, 1 insertion(+), 10 deletions(-) diff --git a/compiler/rustc_errors/src/diagnostic_builder.rs b/compiler/rustc_errors/src/diagnostic_builder.rs index e72791d89a292..3789cdaf354aa 100644 --- a/compiler/rustc_errors/src/diagnostic_builder.rs +++ b/compiler/rustc_errors/src/diagnostic_builder.rs @@ -266,8 +266,7 @@ impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> { /// Converts the builder to a `Diagnostic` for later emission, /// unless dcx has disabled such buffering. pub fn into_diagnostic(mut self) -> Option<(Diagnostic, &'a DiagCtxt)> { - let flags = self.dcx.inner.lock().flags; - if flags.dont_buffer_diagnostics || flags.treat_err_as_bug.is_some() { + if self.dcx.inner.lock().flags.treat_err_as_bug.is_some() { self.emit(); return None; } diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index b97ec02675a60..76b7e0d79a98c 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -524,9 +524,6 @@ pub struct DiagCtxtFlags { /// If Some, the Nth error-level diagnostic is upgraded to bug-level. /// (rustc: see `-Z treat-err-as-bug`) pub treat_err_as_bug: Option<NonZeroUsize>, - /// If true, immediately emit diagnostics that would otherwise be buffered. - /// (rustc: see `-Z dont-buffer-diagnostics` and `-Z treat-err-as-bug`) - pub dont_buffer_diagnostics: bool, /// Show macro backtraces. /// (rustc: see `-Z macro-backtrace`) pub macro_backtrace: bool, diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index f3f59b05682db..444e3700cf772 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -659,7 +659,6 @@ fn test_unstable_options_tracking_hash() { // tidy-alphabetical-start untracked!(assert_incr_state, Some(String::from("loaded"))); untracked!(deduplicate_diagnostics, false); - untracked!(dont_buffer_diagnostics, true); untracked!(dump_dep_graph, true); untracked!(dump_mir, Some(String::from("abc"))); untracked!(dump_mir_dataflow, true); diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 12d8293ecd2f6..61796d7a6cafc 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -1146,7 +1146,6 @@ impl UnstableOptions { DiagCtxtFlags { can_emit_warnings, treat_err_as_bug: self.treat_err_as_bug, - dont_buffer_diagnostics: self.dont_buffer_diagnostics, macro_backtrace: self.macro_backtrace, deduplicate_diagnostics: self.deduplicate_diagnostics, track_diagnostics: self.track_diagnostics, diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 842bf1d60f66d..6d96ec4d6f67d 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -1553,9 +1553,6 @@ options! { dep_info_omit_d_target: bool = (false, parse_bool, [TRACKED], "in dep-info output, omit targets for tracking dependencies of the dep-info files \ themselves (default: no)"), - dont_buffer_diagnostics: bool = (false, parse_bool, [UNTRACKED], - "emit diagnostics rather than buffering (breaks NLL error downgrading, sorting) \ - (default: no)"), dual_proc_macros: bool = (false, parse_bool, [TRACKED], "load proc macros for both target and host, but only link to the target (default: no)"), dump_dep_graph: bool = (false, parse_bool, [UNTRACKED], From c3cd657210403b9b8b0e8557bc1604d1890e6821 Mon Sep 17 00:00:00 2001 From: Michael Howell <michael@notriddle.com> Date: Mon, 8 Jan 2024 14:29:55 -0700 Subject: [PATCH 15/17] rustdoc-search: intern function search types This takes advantage of more reuse opportunities. Along with the empty object commit, they bringing memory usage down about 20% over the original. --- src/librustdoc/html/static/js/search.js | 89 ++++++++++++++++++++----- 1 file changed, 72 insertions(+), 17 deletions(-) diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js index 5bd375a86a787..7995a33f09f9b 100644 --- a/src/librustdoc/html/static/js/search.js +++ b/src/librustdoc/html/static/js/search.js @@ -2725,17 +2725,25 @@ ${item.displayPath}<span class="${type}">${name}</span>\ /** * Empty, immutable map used in item search types with no bindings. * - * @type {Map<integer, Array<Functiontype>>} + * @type {Map<number, Array<FunctionType>>} */ const EMPTY_BINDINGS_MAP = new Map(); /** * Empty, immutable map used in item search types with no bindings. * - * @type {Array<Functiontype>} + * @type {Array<FunctionType>} */ const EMPTY_GENERICS_ARRAY = []; + /** + * Object pool for function types with no bindings or generics. + * This is reset after loading the index. + * + * @type {Map<number|null, FunctionType>} + */ + let TYPES_POOL = new Map(); + /** * Converts a single type. * @@ -2778,35 +2786,80 @@ ${item.displayPath}<span class="${type}">${name}</span>\ bindings = EMPTY_BINDINGS_MAP; } } + /** + * @type {FunctionType} + */ + let result; if (pathIndex < 0) { // types less than 0 are generic parameters // the actual names of generic parameters aren't stored, since they aren't API - return { + result = { id: pathIndex, ty: TY_GENERIC, path: null, generics, bindings, }; - } - if (pathIndex === 0) { + } else if (pathIndex === 0) { // `0` is used as a sentinel because it's fewer bytes than `null` - return { + result = { id: null, ty: null, path: null, generics, bindings, }; + } else { + const item = lowercasePaths[pathIndex - 1]; + result = { + id: buildTypeMapIndex(item.name, isAssocType), + ty: item.ty, + path: item.path, + generics, + bindings, + }; } - const item = lowercasePaths[pathIndex - 1]; - return { - id: buildTypeMapIndex(item.name, isAssocType), - ty: item.ty, - path: item.path, - generics, - bindings, - }; + const cr = TYPES_POOL.get(result.id); + if (cr) { + // Shallow equality check. Since this function is used + // to construct every type object, this should be mostly + // equivalent to a deep equality check, except if there's + // a conflict, we don't keep the old one around, so it's + // not a fully precise implementation of hashcons. + if (cr.generics.length === result.generics.length && + cr.generics !== result.generics && + cr.generics.every((x, i) => result.generics[i] === x) + ) { + result.generics = cr.generics; + } + if (cr.bindings.size === result.bindings.size && cr.bindings !== result.bindings) { + let ok = true; + for (const [k, v] of cr.bindings.entries()) { + const v2 = result.bindings.get(v); + if (!v2) { + ok = false; + break; + } + if (v !== v2 && v.length === v2.length && v.every((x, i) => v2[i] === x)) { + result.bindings.set(k, v); + } else if (v !== v2) { + ok = false; + break; + } + } + if (ok) { + result.bindings = cr.bindings; + } + } + if (cr.ty === result.ty && cr.path === result.path + && cr.bindings === result.bindings && cr.generics === result.generics + && cr.ty === result.ty + ) { + return cr; + } + } + TYPES_POOL.set(result.id, result); + return result; } /** @@ -2817,7 +2870,7 @@ ${item.displayPath}<span class="${type}">${name}</span>\ * object-based encoding so that the actual search code is more readable and easier to debug. * * The raw function search type format is generated using serde in - * librustdoc/html/render/mod.rs: impl Serialize for IndexItemFunctionType + * librustdoc/html/render/mod.rs: IndexItemFunctionType::write_to_string * * @param {{ * string: string, @@ -2986,8 +3039,8 @@ ${item.displayPath}<span class="${type}">${name}</span>\ const fb = { id: null, ty: 0, - generics: [], - bindings: new Map(), + generics: EMPTY_GENERICS_ARRAY, + bindings: EMPTY_BINDINGS_MAP, }; for (const [k, v] of type.bindings.entries()) { fb.id = k; @@ -3215,6 +3268,8 @@ ${item.displayPath}<span class="${type}">${name}</span>\ } currentIndex += itemTypes.length; } + // Drop the (rather large) hash table used for reusing function items + TYPES_POOL = new Map(); } /** From c8ded5260176495ee8012e8f162766897dfc611b Mon Sep 17 00:00:00 2001 From: Erik Desjardins <erikdesjardins@users.noreply.github.com> Date: Mon, 8 Jan 2024 21:36:02 -0500 Subject: [PATCH 16/17] GNU/Hurd: unconditionally use inline stack probes LLVM 11 has been unsupported since 45591408b18e7f93fcf8c09210c9a5a102d84b37, so this doesn't need to be conditional on the LLVM version. --- compiler/rustc_target/src/spec/targets/i686_unknown_hurd_gnu.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_target/src/spec/targets/i686_unknown_hurd_gnu.rs b/compiler/rustc_target/src/spec/targets/i686_unknown_hurd_gnu.rs index 9102673ef7791..6884e078c27e5 100644 --- a/compiler/rustc_target/src/spec/targets/i686_unknown_hurd_gnu.rs +++ b/compiler/rustc_target/src/spec/targets/i686_unknown_hurd_gnu.rs @@ -5,7 +5,7 @@ pub fn target() -> Target { base.cpu = "pentiumpro".into(); base.max_atomic_width = Some(64); base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m32"]); - base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) }; + base.stack_probes = StackProbeType::Inline; Target { llvm_target: "i686-unknown-hurd-gnu".into(), From 36110147229f49024187df6b17175dd5810a26bc Mon Sep 17 00:00:00 2001 From: Urgau <urgau@numericable.fr> Date: Fri, 22 Dec 2023 19:25:15 +0100 Subject: [PATCH 17/17] Rework and improve unstable documentation of check-cfg --- .../src/compiler-flags/check-cfg.md | 224 ++++++++++-------- 1 file changed, 123 insertions(+), 101 deletions(-) diff --git a/src/doc/unstable-book/src/compiler-flags/check-cfg.md b/src/doc/unstable-book/src/compiler-flags/check-cfg.md index 8ab6e83d99e79..e8fc2fe986e22 100644 --- a/src/doc/unstable-book/src/compiler-flags/check-cfg.md +++ b/src/doc/unstable-book/src/compiler-flags/check-cfg.md @@ -4,18 +4,16 @@ The tracking issue for this feature is: [#82450](https://github.com/rust-lang/ru ------------------------ -This feature allows you to enable complete or partial checking of configuration. +This feature enables checking of conditional configuration. `rustc` accepts the `--check-cfg` option, which specifies whether to check conditions and how to -check them. The `--check-cfg` option takes a value, called the _check cfg specification_. The -check cfg specification is parsed using the Rust metadata syntax, just as the `--cfg` option is. +check them. The `--check-cfg` option takes a value, called the _check cfg specification_. +This specification has one form: -`--check-cfg` option take one form: +1. `--check-cfg cfg(...)` mark a configuration and it's expected values as expected. -1. `--check-cfg cfg(...)` enables checking the values within list-valued conditions. - -NOTE: No implicit expectation is added when using `--cfg` for both forms. Users are expected to -pass all expected names and values using `cfg(...)`. +*No implicit expectation is added when using `--cfg`. Users are expected to +pass all expected names and values using the _check cfg specification_.* ## The `cfg(...)` form @@ -23,7 +21,7 @@ The `cfg(...)` form enables checking the values within list-valued conditions. I basic form: ```bash -rustc --check-cfg 'cfg(name1, ..., nameN, values("value1", "value2", ... "valueN"))' +rustc --check-cfg 'cfg(name, values("value1", "value2", ... "valueN"))' ``` where `name` is a bare identifier (has no quotes) and each `"value"` term is a quoted literal @@ -31,162 +29,186 @@ string. `name` specifies the name of the condition, such as `feature` or `my_cfg When the `cfg(...)` option is specified, `rustc` will check every `#[cfg(name = "value")]` attribute, `#[cfg_attr(name = "value")]` attribute, `#[link(name = "a", cfg(name = "value"))]` -and `cfg!(name = "value")` call. It will check that the `"value"` specified is present in the -list of expected values. If `"value"` is not in it, then `rustc` will report an `unexpected_cfgs` -lint diagnostic. The default diagnostic level for this lint is `Warn`. +attribute and `cfg!(name = "value")` macro call. It will check that the `"value"` specified is +present in the list of expected values. If `"value"` is not in it, then `rustc` will report an +`unexpected_cfgs` lint diagnostic. The default diagnostic level for this lint is `Warn`. -The command line `--cfg` arguments are currently *NOT* checked but may very well be checked in -the future. +*The command line `--cfg` arguments are currently *NOT* checked but may very well be checked in +the future.* -To enable checking of values, but to provide an empty set of expected values, use these forms: +To enable checking of values, but to provide an *none*/empty set of expected values +(ie. expect `#[cfg(name)]`), use these forms: ```bash -rustc --check-cfg 'cfg(name1, ..., nameN)' -rustc --check-cfg 'cfg(name1, ..., nameN, values())' +rustc --check-cfg 'cfg(name)' +rustc --check-cfg 'cfg(name, values())' ``` To enable checking of name but not values (i.e. unknown expected values), use this form: ```bash -rustc --check-cfg 'cfg(name1, ..., nameN, values(any()))' +rustc --check-cfg 'cfg(name, values(any()))' +``` + +To avoid repeating the same set of values, use this form: + +```bash +rustc --check-cfg 'cfg(name1, ..., nameN, values("value1", "value2", ... "valueN"))' ``` The `--check-cfg cfg(...)` option can be repeated, both for the same condition name and for different names. If it is repeated for the same condition name, then the sets of values for that -condition are merged together (presedence is given to `any()`). +condition are merged together (precedence is given to `values(any())`). ## Well known names and values `rustc` has a internal list of well known names and their corresponding values. Those well known names and values follows the same stability as what they refer to. -Well known values checking is always enabled as long as a `--check-cfg` argument is present. +Well known names and values checking is always enabled as long as at least one +`--check-cfg` argument is present. + +As of `2024-01-09T`, the list of known names is as follows: + +<!--- See CheckCfg::fill_well_known in compiler/rustc_session/src/config.rs --> + + - `debug_assertions` + - `doc` + - `doctest` + - `miri` + - `overflow_checks` + - `panic` + - `proc_macro` + - `relocation_model` + - `sanitize` + - `sanitizer_cfi_generalize_pointers` + - `sanitizer_cfi_normalize_integers` + - `target_abi` + - `target_arch` + - `target_endian` + - `target_env` + - `target_family` + - `target_feature` + - `target_has_atomic` + - `target_has_atomic_equal_alignment` + - `target_has_atomic_load_store` + - `target_os` + - `target_pointer_width` + - `target_thread_local` + - `target_vendor` + - `test` + - `unix` + - `windows` + +Like with `values(any())`, well known names checking can be disabled by passing `cfg(any())` +as argument to `--check-cfg`. -Well known names checking is always enable as long as a `--check-cfg` argument is present -**unless** any `cfg(any())` argument is passed. +## Examples -To disable checking of well known names, use this form: +### Equivalence table -```bash -rustc --check-cfg 'cfg(any())' -``` +This table describe the equivalence of a `--cfg` argument to a `--check-cfg` argument. -NOTE: If one want to enable values and names checking without having any cfg to declare, one -can use an empty `cfg()` argument. +| `--cfg` | `--check-cfg` | +|-----------------------------|----------------------------------------------------------| +| *nothing* | *nothing* or `--check-cfg=cfg()` (to enable the checking) | +| `--cfg foo` | `--check-cfg=cfg(foo) or --check-cfg=cfg(foo, values())` | +| `--cfg foo=""` | `--check-cfg=cfg(foo, values(""))` | +| `--cfg foo="bar"` | `--check-cfg=cfg(foo, values("bar"))` | +| `--cfg foo="1" --cfg foo="2"` | `--check-cfg=cfg(foo, values("1", "2"))` | +| `--cfg foo="1" --cfg bar="2"` | `--check-cfg=cfg(foo, values("1")) --check-cfg=cfg(bar, values("2"))` | +| `--cfg foo --cfg foo="bar"` | `--check-cfg=cfg(foo) --check-cfg=cfg(foo, values("bar"))` | -## Examples +NOTE: There is (currently) no way to express that a condition name is expected but no (!= none) +values are expected. Passing an empty `values()` means *(none)* in the sense of `#[cfg(foo)]` +with no value. Users are expected to NOT pass a `--check-cfg` with that condition name. + +### Example: Cargo-like `feature` example Consider this command line: ```bash rustc --check-cfg 'cfg(feature, values("lion", "zebra"))' \ - --cfg 'feature="lion"' -Z unstable-options \ - example.rs + --cfg 'feature="lion"' -Z unstable-options example.rs ``` This command line indicates that this crate has two features: `lion` and `zebra`. The `lion` -feature is enabled, while the `zebra` feature is disabled. Exhaustive checking of names and -values are enabled by default. Consider compiling this code: +feature is enabled, while the `zebra` feature is disabled. +Given the `--check-cfg` arguments, exhaustive checking of names and +values are enabled. +`example.rs`: ```rust -// This is expected, and tame_lion() will be compiled -#[cfg(feature = "lion")] +#[cfg(feature = "lion")] // This condition is expected, as "lion" is an expected value of `feature` fn tame_lion(lion: Lion) {} -// This is expected, and ride_zebra() will NOT be compiled. -#[cfg(feature = "zebra")] -fn ride_zebra(zebra: Zebra) {} +#[cfg(feature = "zebra")] // This condition is expected, as "zebra" is an expected value of `feature` + // but the condition will still evaluate to false + // since only --cfg feature="lion" was passed +fn ride_zebra(z: Zebra) {} -// This is UNEXPECTED, and will cause a compiler warning (by default). -#[cfg(feature = "platypus")] +#[cfg(feature = "platypus")] // This condition is UNEXPECTED, as "platypus" is NOT an expected value of + // `feature` and will cause a compiler warning (by default). fn poke_platypus() {} -// This is UNEXPECTED, because 'feechure' is not a known condition name, -// and will cause a compiler warning (by default). -#[cfg(feechure = "lion")] +#[cfg(feechure = "lion")] // This condition is UNEXPECTED, as 'feechure' is NOT a expected condition + // name, no `cfg(feechure, ...)` was passed in `--check-cfg` fn tame_lion() {} -// This is UNEXPECTED, because 'windows' is a well known condition name, -// and because 'windows' doesn't take any values, -// and will cause a compiler warning (by default). -#[cfg(windows = "unix")] +#[cfg(windows = "unix")] // This condition is UNEXPECTED, as while 'windows' is a well known + // condition name, it doens't expect any values fn tame_windows() {} ``` -### Example: Checking condition names, but not values +### Example: Multiple names and values ```bash -# This turns on checking for condition names, but not values, such as 'feature' values. -rustc --check-cfg 'cfg(is_embedded, has_feathers, values(any()))' \ - --cfg has_feathers -Z unstable-options +rustc --check-cfg 'cfg(is_embedded, has_feathers)' \ + --check-cfg 'cfg(feature, values("zapping", "lasers"))' \ + --cfg has_feathers --cfg 'feature="zapping"' -Z unstable-options ``` ```rust -#[cfg(is_embedded)] // This is expected as "is_embedded" was provided in cfg() -fn do_embedded() {} // and because names exhaustiveness was not disabled - -#[cfg(has_feathers)] // This is expected as "has_feathers" was provided in cfg() -fn do_features() {} // and because names exhaustiveness was not disabled +#[cfg(is_embedded)] // This condition is expected, as 'is_embedded' was provided in --check-cfg +fn do_embedded() {} // and doesn't take any value -#[cfg(has_feathers = "zapping")] // This is expected as "has_feathers" was provided in cfg() - // and because no value checking was enable for "has_feathers" - // no warning is emitted for the value "zapping" -fn do_zapping() {} +#[cfg(has_feathers)] // This condition is expected, as 'has_feathers' was provided in --check-cfg +fn do_features() {} // and doesn't take any value -#[cfg(has_mumble_frotz)] // This is UNEXPECTED because names checking is enable and - // "has_mumble_frotz" was not provided in cfg() +#[cfg(has_mumble_frotz)] // This condition is UNEXPECTED, as 'has_mumble_frotz' was NEVER provided + // in any --check-cfg arguments fn do_mumble_frotz() {} -``` - -### Example: Checking feature values, but not condition names -```bash -# This turns on checking for feature values, but not for condition names. -rustc --check-cfg 'cfg(feature, values("zapping", "lasers"))' \ - --check-cfg 'cfg(any())' \ - --cfg 'feature="zapping"' -Z unstable-options -``` - -```rust -#[cfg(is_embedded)] // This is doesn't raise a warning, because names checking was - // disabled by 'cfg(any())' -fn do_embedded() {} - -#[cfg(has_feathers)] // Same as above, 'cfg(any())' was provided so no name - // checking is performed -fn do_features() {} - -#[cfg(feature = "lasers")] // This is expected, "lasers" is in the cfg(feature) list +#[cfg(feature = "lasers")] // This condition is expected, as "lasers" is an expected value of `feature` fn shoot_lasers() {} -#[cfg(feature = "monkeys")] // This is UNEXPECTED, because "monkeys" is not in the - // cfg(feature) list +#[cfg(feature = "monkeys")] // This condition is UNEXPECTED, as "monkeys" is NOT an expected value of + // `feature` fn write_shakespeare() {} ``` -### Example: Checking both condition names and feature values +### Example: Condition names without values ```bash -# This turns on checking for feature values and for condition names. -rustc --check-cfg 'cfg(is_embedded, has_feathers)' \ - --check-cfg 'cfg(feature, values("zapping", "lasers"))' \ - --cfg has_feathers --cfg 'feature="zapping"' -Z unstable-options +rustc --check-cfg 'cfg(is_embedded, has_feathers, values(any()))' \ + --cfg has_feathers -Z unstable-options ``` ```rust -#[cfg(is_embedded)] // This is expected because "is_embedded" was provided in cfg() -fn do_embedded() {} // and doesn't take any value - -#[cfg(has_feathers)] // This is expected because "has_feathers" was provided in cfg() -fn do_features() {} // and deosn't take any value +#[cfg(is_embedded)] // This condition is expected, as 'is_embedded' was provided in --check-cfg + // as condition name +fn do_embedded() {} -#[cfg(has_mumble_frotz)] // This is UNEXPECTED, because "has_mumble_frotz" was never provided -fn do_mumble_frotz() {} +#[cfg(has_feathers)] // This condition is expected, as "has_feathers" was provided in --check-cfg + // as condition name +fn do_features() {} -#[cfg(feature = "lasers")] // This is expected, "lasers" is in the cfg(feature) list -fn shoot_lasers() {} +#[cfg(has_feathers = "zapping")] // This condition is expected, as "has_feathers" was provided in + // and because *any* values is expected for 'has_feathers' no + // warning is emitted for the value "zapping" +fn do_zapping() {} -#[cfg(feature = "monkeys")] // This is UNEXPECTED, because "monkeys" is not in - // the cfg(feature) list -fn write_shakespeare() {} +#[cfg(has_mumble_frotz)] // This condition is UNEXPECTED, as 'has_mumble_frotz' was not provided + // in any --check-cfg arguments +fn do_mumble_frotz() {} ```