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:
bors 2024-01-09 14:50:14 +00:00
commit 5876c8cdfd
107 changed files with 1975 additions and 802 deletions

View file

@ -3876,6 +3876,7 @@ dependencies = [
"rustc_feature",
"rustc_fluent_macro",
"rustc_hir",
"rustc_hir_pretty",
"rustc_index",
"rustc_infer",
"rustc_lint_defs",

View file

@ -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 {

View file

@ -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 {

View file

@ -1,3 +1,2 @@
pub mod check_consts;
pub mod promote_consts;
pub mod validate;

View file

@ -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 {}

View file

@ -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)
);
}

View file

@ -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

View 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.

View file

@ -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;
}

View file

@ -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,

View file

@ -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" }

View file

@ -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

View 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 },
);
}

View file

@ -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;

View file

@ -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);

View file

@ -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,
},
}

View file

@ -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);

View file

@ -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`,

View file

@ -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)
}

View file

@ -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);
}
}

View file

@ -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);
}
}
}

View file

@ -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);
}
}
}

View file

@ -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);
}
}

View file

@ -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;

View file

@ -174,7 +174,7 @@ impl<'tcx> MirPass<'tcx> for MatchBranchSimplification {
}
if should_cleanup {
simplify_cfg(tcx, body);
simplify_cfg(body);
}
}
}

View file

@ -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>,

View file

@ -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);
}
}
}

View file

@ -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);
}
}
}

View file

@ -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 {

View file

@ -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(),
)

View file

@ -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)
}
}

View file

@ -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,

View file

@ -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],

View file

@ -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`.

View file

@ -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(),

View file

@ -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.

View file

@ -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};

View file

@ -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> {

View file

@ -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> {

View file

@ -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(

View file

@ -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)
() => {};

View file

@ -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() {}
```

View file

@ -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();
}
/**

View file

@ -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>>;

View file

@ -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;

View file

@ -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)]

View file

@ -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;

View file

@ -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;
}
}

View file

@ -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);

View file

@ -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);

View file

@ -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?)
}

View file

@ -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) {

View file

@ -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;
}
}
+

View file

@ -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) {

View file

@ -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;
}
}
+

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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() {

View 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

View file

@ -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]

View file

@ -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`.

View file

@ -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;

View file

@ -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

View file

@ -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 {

View file

@ -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`.

View file

@ -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,));

View file

@ -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`.

View file

@ -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);
}

View 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

View file

@ -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() {}

View file

@ -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`.

View file

@ -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`.

View file

@ -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`.

View file

@ -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 {

View file

@ -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() {}

View 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

View file

@ -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`.

View file

@ -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() {}

View file

@ -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`.

View file

@ -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, "");

View 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

View file

@ -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() {}

View file

@ -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`.

View file

@ -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);
}

View file

@ -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, "");

View 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

View file

@ -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]
}
}

View file

@ -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

View 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`.

View 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`.

View 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]
}

View 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) {}

View 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`.

View 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

View 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`.

View 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) {}

View file

@ -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]
}

View file

@ -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`.

View file

@ -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() {}

View 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