Auto merge of #119767 - GuillaumeGomez:rollup-fbp26yb, r=GuillaumeGomez
Rollup of 9 pull requests Successful merges: - #117556 (Disallow reference to `static mut` and adding `static_mut_ref` lint) - #118748 (std: getrandom simplification for freebsd.) - #119282 (Rework and improve the unstable documentation of check-cfg) - #119527 (don't reexport atomic::ordering via rustc_data_structures, use std import) - #119668 (Simplify implementation of MIR promotion) - #119699 (Merge dead bb pruning and unreachable bb deduplication.) - #119723 (Remove `-Zdont-buffer-diagnostics`.) - #119756 (rustdoc-search: reuse individual types in function signatures) - #119758 (GNU/Hurd: unconditionally use inline stack probes) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
5876c8cdfd
107 changed files with 1975 additions and 802 deletions
|
@ -3876,6 +3876,7 @@ dependencies = [
|
|||
"rustc_feature",
|
||||
"rustc_fluent_macro",
|
||||
"rustc_hir",
|
||||
"rustc_hir_pretty",
|
||||
"rustc_index",
|
||||
"rustc_infer",
|
||||
"rustc_lint_defs",
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -1,3 +1,2 @@
|
|||
pub mod check_consts;
|
||||
pub mod promote_consts;
|
||||
pub mod validate;
|
||||
|
|
|
@ -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 {}
|
||||
|
|
|
@ -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)
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
22
compiler/rustc_error_codes/src/error_codes/E0796.md
Normal file
22
compiler/rustc_error_codes/src/error_codes/E0796.md
Normal file
|
@ -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.
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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" }
|
||||
|
|
|
@ -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
|
||||
|
|
97
compiler/rustc_hir_analysis/src/check/errs.rs
Normal file
97
compiler/rustc_hir_analysis/src/check/errs.rs
Normal file
|
@ -0,0 +1,97 @@
|
|||
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,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// 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
|
||||
&& 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 },
|
||||
);
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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, maybe_stmt_static_mut};
|
||||
|
||||
use std::mem;
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
|
@ -224,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
|
||||
|
@ -242,6 +246,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);
|
||||
|
||||
|
|
|
@ -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,
|
||||
},
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -88,6 +88,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,
|
||||
|
@ -1766,6 +1767,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`,
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)]
|
||||
|
@ -94,6 +95,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;
|
||||
|
@ -115,7 +117,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;
|
||||
|
||||
|
|
|
@ -174,7 +174,7 @@ impl<'tcx> MirPass<'tcx> for MatchBranchSimplification {
|
|||
}
|
||||
|
||||
if should_cleanup {
|
||||
simplify_cfg(tcx, body);
|
||||
simplify_cfg(body);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,10 +23,11 @@ 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};
|
||||
|
||||
use crate::transform::check_consts::{qualifs, ConstCx};
|
||||
use rustc_const_eval::transform::check_consts::{qualifs, ConstCx};
|
||||
|
||||
/// A `MirPass` for promotion.
|
||||
///
|
||||
|
@ -64,7 +66,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 +80,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,
|
||||
}
|
||||
|
||||
|
@ -123,46 +118,43 @@ 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 | TempState::PromotedOut => 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 });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
|
@ -196,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)?;
|
||||
let Left(statement) = self.body.stmt_at(candidate.location) else { bug!() };
|
||||
let Some((_, Rvalue::Ref(_, kind, place))) = statement.kind.as_assign() else { bug!() };
|
||||
|
||||
// The reference operation itself must be promotable.
|
||||
// (Needs to come after `validate_local` to avoid ICEs.)
|
||||
self.validate_ref(*kind, place)?;
|
||||
// We can only promote interior borrows of promotable temps (non-temps
|
||||
// don't get promoted anyway).
|
||||
self.validate_local(place.local)?;
|
||||
|
||||
// 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);
|
||||
}
|
||||
// The reference operation itself must be promotable.
|
||||
// (Needs to come after `validate_local` to avoid ICEs.)
|
||||
self.validate_ref(*kind, place)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
_ => 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);
|
||||
}
|
||||
|
||||
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();
|
||||
let TempState::Defined { location: loc, .. } = self.temps[local] else {
|
||||
return false;
|
||||
};
|
||||
|
||||
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,
|
||||
),
|
||||
_ => {
|
||||
span_bug!(
|
||||
statement.source_info.span,
|
||||
"{:?} is not an assignment",
|
||||
statement
|
||||
);
|
||||
}
|
||||
}
|
||||
} 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)
|
||||
}
|
||||
kind => {
|
||||
span_bug!(terminator.source_info.span, "{:?} not promotable", kind);
|
||||
}
|
||||
}
|
||||
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)
|
||||
}
|
||||
} 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();
|
||||
let TempState::Defined { location: loc, uses, valid } = self.temps[local] else {
|
||||
return Err(Unpromotable);
|
||||
};
|
||||
|
||||
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)
|
||||
// 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)
|
||||
}
|
||||
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);
|
||||
}
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
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.
|
||||
let Some((place_base, elem)) = place.last_projection() else {
|
||||
return self.validate_local(place.local);
|
||||
};
|
||||
|
||||
// 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);
|
||||
}
|
||||
// Validate topmost projection, then recurse.
|
||||
match elem {
|
||||
// Recurse directly.
|
||||
ProjectionElem::ConstantIndex { .. }
|
||||
| ProjectionElem::Subtype(_)
|
||||
| ProjectionElem::Subslice { .. } => {}
|
||||
|
||||
ProjectionElem::ConstantIndex { .. }
|
||||
| ProjectionElem::Subtype(_)
|
||||
| ProjectionElem::Subslice { .. } => {}
|
||||
// Never recurse.
|
||||
ProjectionElem::OpaqueCast(..) | ProjectionElem::Downcast(..) => {
|
||||
return Err(Unpromotable);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
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.
|
||||
|
||||
self.validate_local(local)?;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
// 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> {
|
||||
|
@ -676,7 +603,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 +857,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>,
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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>,
|
||||
}
|
||||
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
|
||||
};
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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<_>>();
|
||||
.filter(|(bb, bbdata)| should_deduplicate_unreachable(bbdata) && reachable.contains(*bb))
|
||||
.count();
|
||||
|
||||
if unreachable_blocks.len() > 1 {
|
||||
OptApplier { tcx, duplicates: unreachable_blocks }.visit_body(body);
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
|
|
|
@ -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(),
|
||||
)
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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],
|
||||
|
|
|
@ -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`.
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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};
|
||||
|
|
|
@ -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> {
|
||||
|
|
|
@ -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> {
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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)
|
||||
() => {};
|
||||
|
|
|
@ -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.
|
||||
|
||||
Well known names checking is always enable as long as a `--check-cfg` argument is present
|
||||
**unless** any `cfg(any())` argument is passed.
|
||||
As of `2024-01-09T`, the list of known names is as follows:
|
||||
|
||||
To disable checking of well known names, use this form:
|
||||
<!--- See CheckCfg::fill_well_known in compiler/rustc_session/src/config.rs -->
|
||||
|
||||
```bash
|
||||
rustc --check-cfg 'cfg(any())'
|
||||
```
|
||||
- `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`
|
||||
|
||||
NOTE: If one want to enable values and names checking without having any cfg to declare, one
|
||||
can use an empty `cfg()` argument.
|
||||
Like with `values(any())`, well known names checking can be disabled by passing `cfg(any())`
|
||||
as argument to `--check-cfg`.
|
||||
|
||||
## Examples
|
||||
|
||||
### Equivalence table
|
||||
|
||||
This table describe the equivalence of a `--cfg` argument to a `--check-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"))` |
|
||||
|
||||
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
|
||||
```
|
||||
|
||||
```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(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_mumble_frotz)] // This is UNEXPECTED because names checking is enable and
|
||||
// "has_mumble_frotz" was not provided in cfg()
|
||||
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
|
||||
fn shoot_lasers() {}
|
||||
|
||||
#[cfg(feature = "monkeys")] // This is UNEXPECTED, because "monkeys" is not in the
|
||||
// cfg(feature) list
|
||||
fn write_shakespeare() {}
|
||||
```
|
||||
|
||||
### Example: Checking both condition names and feature 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
|
||||
```
|
||||
|
||||
```rust
|
||||
#[cfg(is_embedded)] // This is expected because "is_embedded" was provided in cfg()
|
||||
#[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)] // This is expected because "has_feathers" was provided in cfg()
|
||||
fn do_features() {} // and deosn't take any value
|
||||
#[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 "has_mumble_frotz" was never provided
|
||||
#[cfg(has_mumble_frotz)] // This condition is UNEXPECTED, as 'has_mumble_frotz' was NEVER provided
|
||||
// in any --check-cfg arguments
|
||||
fn do_mumble_frotz() {}
|
||||
|
||||
#[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: Condition names without values
|
||||
|
||||
```bash
|
||||
rustc --check-cfg 'cfg(is_embedded, has_feathers, values(any()))' \
|
||||
--cfg has_feathers -Z unstable-options
|
||||
```
|
||||
|
||||
```rust
|
||||
#[cfg(is_embedded)] // This condition is expected, as 'is_embedded' was provided in --check-cfg
|
||||
// as condition name
|
||||
fn do_embedded() {}
|
||||
|
||||
#[cfg(has_feathers)] // This condition is expected, as "has_feathers" was provided in --check-cfg
|
||||
// as condition name
|
||||
fn do_features() {}
|
||||
|
||||
#[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(has_mumble_frotz)] // This condition is UNEXPECTED, as 'has_mumble_frotz' was not provided
|
||||
// in any --check-cfg arguments
|
||||
fn do_mumble_frotz() {}
|
||||
```
|
||||
|
|
|
@ -2717,9 +2717,33 @@ ${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<number, 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 = [];
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
|
@ -2732,15 +2756,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,38 +2783,83 @@ ${item.displayPath}<span class="${type}">${name}</span>\
|
|||
];
|
||||
}));
|
||||
} else {
|
||||
bindings = new Map();
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2801,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,
|
||||
|
@ -2970,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;
|
||||
|
@ -3199,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();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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>>;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)]
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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?)
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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,12 +73,16 @@
|
|||
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];
|
||||
}
|
||||
|
||||
bb4: {
|
||||
_5 = Result::<NonNull<[u8]>, std::alloc::AllocError>::unwrap(move _6) -> [return: bb1, unwind continue];
|
||||
}
|
||||
|
||||
bb5: {
|
||||
_5 = Result::<NonNull<[u8]>, std::alloc::AllocError>::unwrap(move _6) -> [return: bb1, unwind continue];
|
||||
unreachable;
|
||||
}
|
||||
}
|
||||
+
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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,12 +73,16 @@
|
|||
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];
|
||||
}
|
||||
|
||||
bb4: {
|
||||
_5 = Result::<NonNull<[u8]>, std::alloc::AllocError>::unwrap(move _6) -> [return: bb1, unwind continue];
|
||||
}
|
||||
|
||||
bb5: {
|
||||
_5 = Result::<NonNull<[u8]>, std::alloc::AllocError>::unwrap(move _6) -> [return: bb1, unwind continue];
|
||||
unreachable;
|
||||
}
|
||||
}
|
||||
+
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
bb5: {
|
||||
_10 = ((_1 as Ok).0: i32);
|
||||
_3 = ControlFlow::<Result<Infallible, i32>, i32>::Continue(move _10);
|
||||
goto -> bb3;
|
||||
}
|
||||
|
||||
bb6: {
|
||||
_10 = ((_1 as Ok).0: i32);
|
||||
_3 = ControlFlow::<Result<Infallible, i32>, i32>::Continue(move _10);
|
||||
goto -> bb4;
|
||||
unreachable;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
_4 = ((_1 as Ok).0: i32);
|
||||
_2 = ControlFlow::<usize, i32>::Continue(_4);
|
||||
goto -> bb3;
|
||||
}
|
||||
|
||||
bb3: {
|
||||
_4 = ((_1 as Ok).0: i32);
|
||||
_2 = ControlFlow::<usize, i32>::Continue(_4);
|
||||
goto -> bb4;
|
||||
_8 = discriminant(_2);
|
||||
switchInt(move _8) -> [0: bb5, 1: bb4, otherwise: bb7];
|
||||
}
|
||||
|
||||
bb4: {
|
||||
_8 = discriminant(_2);
|
||||
switchInt(move _8) -> [0: bb6, 1: bb5, otherwise: bb2];
|
||||
}
|
||||
|
||||
bb5: {
|
||||
StorageLive(_11);
|
||||
_11 = ((_2 as Break).0: usize);
|
||||
_0 = Option::<i32>::None;
|
||||
StorageDead(_11);
|
||||
goto -> bb7;
|
||||
goto -> bb6;
|
||||
}
|
||||
|
||||
bb5: {
|
||||
_9 = ((_2 as Continue).0: i32);
|
||||
_0 = Option::<i32>::Some(_9);
|
||||
goto -> bb6;
|
||||
}
|
||||
|
||||
bb6: {
|
||||
_9 = ((_2 as Continue).0: i32);
|
||||
_0 = Option::<i32>::Some(_9);
|
||||
goto -> bb7;
|
||||
}
|
||||
|
||||
bb7: {
|
||||
StorageDead(_2);
|
||||
return;
|
||||
}
|
||||
|
||||
bb7: {
|
||||
unreachable;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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() {
|
||||
|
|
31
tests/ui/abi/statics/static-mut-foreign.stderr
Normal file
31
tests/ui/abi/statics/static-mut-foreign.stderr
Normal file
|
@ -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
|
||||
|
|
@ -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]
|
||||
|
|
|
@ -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`.
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
@ -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 {
|
||||
|
|
|
@ -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`.
|
||||
|
|
|
@ -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,));
|
||||
|
|
|
@ -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`.
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
17
tests/ui/consts/const_let_assign2.stderr
Normal file
17
tests/ui/consts/const_let_assign2.stderr
Normal file
|
@ -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
|
||||
|
|
@ -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() {}
|
||||
|
|
|
@ -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`.
|
||||
|
|
|
@ -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`.
|
||||
|
|
|
@ -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`.
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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() {}
|
||||
|
|
17
tests/ui/consts/static_mut_containing_mut_ref.stderr
Normal file
17
tests/ui/consts/static_mut_containing_mut_ref.stderr
Normal file
|
@ -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
|
||||
|
|
@ -1,9 +1,24 @@
|
|||
error[E0080]: could not evaluate static initializer
|
||||
--> $DIR/static_mut_containing_mut_ref2.rs:7:45
|
||||
warning: mutable reference of mutable static is discouraged
|
||||
--> $DIR/static_mut_containing_mut_ref2.rs:8:6
|
||||
|
|
||||
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;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ 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: aborting due to 1 previous error
|
||||
error[E0080]: could not evaluate static initializer
|
||||
--> $DIR/static_mut_containing_mut_ref2.rs:8:5
|
||||
|
|
||||
LL | *(&mut STDERR_BUFFER_SPACE) = 42;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ modifying a static's initial value from another static's initializer
|
||||
|
||||
error: aborting due to 1 previous error; 1 warning emitted
|
||||
|
||||
For more information about this error, try `rustc --explain E0080`.
|
||||
|
|
|
@ -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() {}
|
||||
|
|
|
@ -1,12 +1,27 @@
|
|||
error[E0658]: mutable references are not allowed in statics
|
||||
--> $DIR/static_mut_containing_mut_ref2.rs:7:46
|
||||
warning: mutable reference of mutable static is discouraged
|
||||
--> $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;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ 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:8:6
|
||||
|
|
||||
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`.
|
||||
|
|
|
@ -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, "");
|
||||
|
|
17
tests/ui/drop/issue-23338-ensure-param-drop-order.stderr
Normal file
17
tests/ui/drop/issue-23338-ensure-param-drop-order.stderr
Normal file
|
@ -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
|
||||
|
|
@ -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() {}
|
||||
|
|
|
@ -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`.
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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, "");
|
||||
|
|
17
tests/ui/issues/issue-23611-enum-swap-in-drop.stderr
Normal file
17
tests/ui/issues/issue-23611-enum-swap-in-drop.stderr
Normal file
|
@ -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
|
||||
|
|
@ -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]
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
26
tests/ui/static/reference-of-mut-static-safe.e2021.stderr
Normal file
26
tests/ui/static/reference-of-mut-static-safe.e2021.stderr
Normal file
|
@ -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:15
|
||||
|
|
||||
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`.
|
15
tests/ui/static/reference-of-mut-static-safe.e2024.stderr
Normal file
15
tests/ui/static/reference-of-mut-static-safe.e2024.stderr
Normal file
|
@ -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`.
|
13
tests/ui/static/reference-of-mut-static-safe.rs
Normal file
13
tests/ui/static/reference-of-mut-static-safe.rs
Normal file
|
@ -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]
|
||||
}
|
23
tests/ui/static/reference-of-mut-static-unsafe-fn.rs
Normal file
23
tests/ui/static/reference-of-mut-static-unsafe-fn.rs
Normal file
|
@ -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) {}
|
63
tests/ui/static/reference-of-mut-static-unsafe-fn.stderr
Normal file
63
tests/ui/static/reference-of-mut-static-unsafe-fn.stderr
Normal file
|
@ -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`.
|
91
tests/ui/static/reference-of-mut-static.e2021.stderr
Normal file
91
tests/ui/static/reference-of-mut-static.e2021.stderr
Normal file
|
@ -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
|
||||
|
75
tests/ui/static/reference-of-mut-static.e2024.stderr
Normal file
75
tests/ui/static/reference-of-mut-static.e2024.stderr
Normal file
|
@ -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`.
|
50
tests/ui/static/reference-of-mut-static.rs
Normal file
50
tests/ui/static/reference-of-mut-static.rs
Normal file
|
@ -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) {}
|
|
@ -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]
|
||||
}
|
||||
|
|
|
@ -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`.
|
||||
|
|
|
@ -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() {}
|
||||
|
|
17
tests/ui/statics/issue-15261.stderr
Normal file
17
tests/ui/statics/issue-15261.stderr
Normal file
|
@ -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
|
||||
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue