diff --git a/Cargo.lock b/Cargo.lock index b8192e333fe91..1d6f7ea1e27ce 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3877,6 +3877,7 @@ dependencies = [ "rustc_feature", "rustc_fluent_macro", "rustc_hir", + "rustc_hir_pretty", "rustc_index", "rustc_infer", "rustc_lint_defs", diff --git a/compiler/rustc_ast_passes/messages.ftl b/compiler/rustc_ast_passes/messages.ftl index feea02c679ce1..a10797626f1b2 100644 --- a/compiler/rustc_ast_passes/messages.ftl +++ b/compiler/rustc_ast_passes/messages.ftl @@ -188,6 +188,9 @@ ast_passes_module_nonascii = trying to load file for module `{$name}` with non-a ast_passes_negative_bound_not_supported = negative bounds are not supported +ast_passes_negative_bound_with_parenthetical_notation = + parenthetical notation may not be used for negative bounds + ast_passes_nested_impl_trait = nested `impl Trait` is not allowed .outer = outer `impl Trait` .inner = nested `impl Trait` here diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index b69d4cccaf04f..7f78f6870552f 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -1312,13 +1312,24 @@ impl<'a> Visitor<'a> for AstValidator<'a> { if let GenericBound::Trait(trait_ref, modifiers) = bound && let BoundPolarity::Negative(_) = modifiers.polarity && let Some(segment) = trait_ref.trait_ref.path.segments.last() - && let Some(ast::GenericArgs::AngleBracketed(args)) = segment.args.as_deref() { - for arg in &args.args { - if let ast::AngleBracketedArg::Constraint(constraint) = arg { - self.dcx() - .emit_err(errors::ConstraintOnNegativeBound { span: constraint.span }); + match segment.args.as_deref() { + Some(ast::GenericArgs::AngleBracketed(args)) => { + for arg in &args.args { + if let ast::AngleBracketedArg::Constraint(constraint) = arg { + self.dcx().emit_err(errors::ConstraintOnNegativeBound { + span: constraint.span, + }); + } + } + } + // The lowered form of parenthesized generic args contains a type binding. + Some(ast::GenericArgs::Parenthesized(args)) => { + self.dcx().emit_err(errors::NegativeBoundWithParentheticalNotation { + span: args.span, + }); } + None => {} } } diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs index 42ada39f51589..6d7c72d80f981 100644 --- a/compiler/rustc_ast_passes/src/errors.rs +++ b/compiler/rustc_ast_passes/src/errors.rs @@ -763,6 +763,13 @@ pub struct ConstraintOnNegativeBound { pub span: Span, } +#[derive(Diagnostic)] +#[diag(ast_passes_negative_bound_with_parenthetical_notation)] +pub struct NegativeBoundWithParentheticalNotation { + #[primary_span] + pub span: Span, +} + #[derive(Diagnostic)] #[diag(ast_passes_invalid_unnamed_field_ty)] pub struct InvalidUnnamedFieldTy { diff --git a/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs b/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs index a1cdf31c68a00..2a7b1107ffcaa 100644 --- a/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs +++ b/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs @@ -111,6 +111,9 @@ fn start( } 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 { diff --git a/compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs b/compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs index 40a1ad22c0e13..9827e299f2a31 100644 --- a/compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs +++ b/compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs @@ -98,6 +98,9 @@ fn start( } static mut NUM: u8 = 6 * 7; + +// FIXME: Use `SyncUnsafeCell` instead of allowing `static_mut_ref` lint +#[allow(static_mut_ref)] static NUM_REF: &'static u8 = unsafe { &NUM }; macro_rules! assert { diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs index b249ffb84b3a8..0b73691204d53 100644 --- a/compiler/rustc_const_eval/src/transform/validate.rs +++ b/compiler/rustc_const_eval/src/transform/validate.rs @@ -74,7 +74,6 @@ impl<'tcx> MirPass<'tcx> for Validator { mir_phase, unwind_edge_count: 0, reachable_blocks: traversal::reachable_as_bitset(body), - place_cache: FxHashSet::default(), value_cache: FxHashSet::default(), can_unwind, }; @@ -106,7 +105,6 @@ struct CfgChecker<'a, 'tcx> { mir_phase: MirPhase, unwind_edge_count: usize, reachable_blocks: BitSet, - place_cache: FxHashSet>, value_cache: FxHashSet, // If `false`, then the MIR must not contain `UnwindAction::Continue` or // `TerminatorKind::Resume`. @@ -294,19 +292,6 @@ impl<'a, 'tcx> Visitor<'tcx> for CfgChecker<'a, 'tcx> { fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) { match &statement.kind { - StatementKind::Assign(box (dest, rvalue)) => { - // FIXME(JakobDegen): Check this for all rvalues, not just this one. - if let Rvalue::Use(Operand::Copy(src) | Operand::Move(src)) = rvalue { - // The sides of an assignment must not alias. Currently this just checks whether - // the places are identical. - if dest == src { - self.fail( - location, - "encountered `Assign` statement with overlapping memory", - ); - } - } - } StatementKind::AscribeUserType(..) => { if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial) { self.fail( @@ -341,7 +326,8 @@ impl<'a, 'tcx> Visitor<'tcx> for CfgChecker<'a, 'tcx> { self.fail(location, format!("explicit `{kind:?}` is forbidden")); } } - StatementKind::StorageLive(_) + StatementKind::Assign(..) + | StatementKind::StorageLive(_) | StatementKind::StorageDead(_) | StatementKind::Intrinsic(_) | StatementKind::Coverage(_) @@ -404,10 +390,7 @@ impl<'a, 'tcx> Visitor<'tcx> for CfgChecker<'a, 'tcx> { } // The call destination place and Operand::Move place used as an argument might be - // passed by a reference to the callee. Consequently they must be non-overlapping - // and cannot be packed. Currently this simply checks for duplicate places. - self.place_cache.clear(); - self.place_cache.insert(destination.as_ref()); + // passed by a reference to the callee. Consequently they cannot be packed. if is_within_packed(self.tcx, &self.body.local_decls, *destination).is_some() { // This is bad! The callee will expect the memory to be aligned. self.fail( @@ -418,10 +401,8 @@ impl<'a, 'tcx> Visitor<'tcx> for CfgChecker<'a, 'tcx> { ), ); } - let mut has_duplicates = false; for arg in args { if let Operand::Move(place) = arg { - has_duplicates |= !self.place_cache.insert(place.as_ref()); if is_within_packed(self.tcx, &self.body.local_decls, *place).is_some() { // This is bad! The callee will expect the memory to be aligned. self.fail( @@ -434,16 +415,6 @@ impl<'a, 'tcx> Visitor<'tcx> for CfgChecker<'a, 'tcx> { } } } - - if has_duplicates { - self.fail( - location, - format!( - "encountered overlapping memory in `Move` arguments to `Call` terminator: {:?}", - terminator.kind, - ), - ); - } } TerminatorKind::Assert { target, unwind, .. } => { self.check_edge(location, *target, EdgeKind::Normal); @@ -1112,17 +1083,6 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { ) } } - // FIXME(JakobDegen): Check this for all rvalues, not just this one. - if let Rvalue::Use(Operand::Copy(src) | Operand::Move(src)) = rvalue { - // The sides of an assignment must not alias. Currently this just checks whether - // the places are identical. - if dest == src { - self.fail( - location, - "encountered `Assign` statement with overlapping memory", - ); - } - } } StatementKind::AscribeUserType(..) => { if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial) { diff --git a/compiler/rustc_error_codes/src/error_codes.rs b/compiler/rustc_error_codes/src/error_codes.rs index 1028d43f9c5ba..a1391cceb7128 100644 --- a/compiler/rustc_error_codes/src/error_codes.rs +++ b/compiler/rustc_error_codes/src/error_codes.rs @@ -515,6 +515,7 @@ E0792: include_str!("./error_codes/E0792.md"), E0793: include_str!("./error_codes/E0793.md"), E0794: include_str!("./error_codes/E0794.md"), E0795: include_str!("./error_codes/E0795.md"), +E0796: include_str!("./error_codes/E0796.md"), } // Undocumented removed error codes. Note that many removed error codes are kept in the list above diff --git a/compiler/rustc_error_codes/src/error_codes/E0796.md b/compiler/rustc_error_codes/src/error_codes/E0796.md new file mode 100644 index 0000000000000..cea18f8db851f --- /dev/null +++ b/compiler/rustc_error_codes/src/error_codes/E0796.md @@ -0,0 +1,22 @@ +Reference of mutable static. + +Erroneous code example: + +```compile_fail,edition2024,E0796 +static mut X: i32 = 23; +static mut Y: i32 = 24; + +unsafe { + let y = &X; + let ref x = X; + let (x, y) = (&X, &Y); + foo(&X); +} + +fn foo<'a>(_x: &'a i32) {} +``` + +Mutable statics can be written to by multiple threads: aliasing violations or +data races will cause undefined behavior. + +Reference of mutable static is a hard error from 2024 edition. diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 6707e17e90f4a..894f9d1a3224c 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -525,9 +525,6 @@ pub struct DiagCtxtFlags { /// 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, - /// If true, immediately print bugs registered with `span_delayed_bug`. - /// (rustc: see `-Z report-delayed-bugs`) - pub report_delayed_bugs: bool, /// Show macro backtraces. /// (rustc: see `-Z macro-backtrace`) pub macro_backtrace: bool, @@ -1004,7 +1001,6 @@ impl DiagCtxt { ) -> ErrorGuaranteed { let treat_next_err_as_bug = self.inner.borrow().treat_next_err_as_bug(); if treat_next_err_as_bug { - // FIXME: don't abort here if report_delayed_bugs is off self.span_bug(sp, msg); } let mut diagnostic = Diagnostic::new(DelayedBug, msg); @@ -1016,11 +1012,7 @@ impl DiagCtxt { // where the explanation of what "good path" is (also, it should be renamed). pub fn good_path_delayed_bug(&self, msg: impl Into) { let mut inner = self.inner.borrow_mut(); - - let mut diagnostic = Diagnostic::new(DelayedBug, msg); - if inner.flags.report_delayed_bugs { - inner.emit_diagnostic_without_consuming(&mut diagnostic); - } + let diagnostic = Diagnostic::new(DelayedBug, msg); let backtrace = std::backtrace::Backtrace::capture(); inner.good_path_delayed_bugs.push(DelayedDiagnostic::with_backtrace(diagnostic, backtrace)); } @@ -1430,10 +1422,8 @@ impl DiagCtxtInner { self.span_delayed_bugs .push(DelayedDiagnostic::with_backtrace(diagnostic.clone(), backtrace)); - if !self.flags.report_delayed_bugs { - #[allow(deprecated)] - return Some(ErrorGuaranteed::unchecked_claim_error_was_emitted()); - } + #[allow(deprecated)] + return Some(ErrorGuaranteed::unchecked_claim_error_was_emitted()); } if diagnostic.has_future_breakage() { diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index e6faad7438457..59ea828440f5b 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -210,7 +210,7 @@ declare_features! ( /// Allows the `multiple_supertrait_upcastable` lint. (unstable, multiple_supertrait_upcastable, "1.69.0", None), /// Allow negative trait bounds. This is an internal-only feature for testing the trait solver! - (incomplete, negative_bounds, "1.71.0", None), + (internal, negative_bounds, "1.71.0", None), /// Allows using `#[omit_gdb_pretty_printer_section]`. (internal, omit_gdb_pretty_printer_section, "1.5.0", None), /// Allows using `#[prelude_import]` on glob `use` items. diff --git a/compiler/rustc_hir_analysis/Cargo.toml b/compiler/rustc_hir_analysis/Cargo.toml index b671bebeb0503..b5ebc1fab765d 100644 --- a/compiler/rustc_hir_analysis/Cargo.toml +++ b/compiler/rustc_hir_analysis/Cargo.toml @@ -17,6 +17,7 @@ rustc_errors = { path = "../rustc_errors" } rustc_feature = { path = "../rustc_feature" } rustc_fluent_macro = { path = "../rustc_fluent_macro" } rustc_hir = { path = "../rustc_hir" } +rustc_hir_pretty = { path = "../rustc_hir_pretty" } rustc_index = { path = "../rustc_index" } rustc_infer = { path = "../rustc_infer" } rustc_lint_defs = { path = "../rustc_lint_defs" } diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index d8b6b9a1272fb..6a17668ad17f8 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -346,6 +346,20 @@ hir_analysis_start_not_target_feature = `#[start]` function is not allowed to ha hir_analysis_start_not_track_caller = `#[start]` function is not allowed to be `#[track_caller]` .label = `#[start]` function is not allowed to be `#[track_caller]` +hir_analysis_static_mut_ref = reference of mutable static is disallowed + .label = reference of mutable static + .note = mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior + .suggestion = shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer + .suggestion_mut = mutable references are dangerous since if there's any other pointer or reference used for that static while the reference lives, that's UB; use `addr_of_mut!` instead to create a raw pointer + +hir_analysis_static_mut_ref_lint = {$shared}reference of mutable static is discouraged + .label = shared reference of mutable static + .label_mut = mutable reference of mutable static + .suggestion = shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer + .suggestion_mut = mutable references are dangerous since if there's any other pointer or reference used for that static while the reference lives, that's UB; use `addr_of_mut!` instead to create a raw pointer + .note = reference of mutable static is a hard error from 2024 edition + .why_note = mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior + hir_analysis_static_specialize = cannot specialize on `'static` lifetime hir_analysis_substs_on_overridden_impl = could not resolve substs on overridden impl diff --git a/compiler/rustc_hir_analysis/src/astconv/bounds.rs b/compiler/rustc_hir_analysis/src/astconv/bounds.rs index 91b3807d74462..d403f1a850d9c 100644 --- a/compiler/rustc_hir_analysis/src/astconv/bounds.rs +++ b/compiler/rustc_hir_analysis/src/astconv/bounds.rs @@ -26,23 +26,36 @@ impl<'tcx> dyn AstConv<'tcx> + '_ { span: Span, ) { let tcx = self.tcx(); + let sized_def_id = tcx.lang_items().sized_trait(); + let mut seen_negative_sized_bound = false; // Try to find an unbound in bounds. let mut unbounds: SmallVec<[_; 1]> = SmallVec::new(); let mut search_bounds = |ast_bounds: &'tcx [hir::GenericBound<'tcx>]| { for ab in ast_bounds { - if let hir::GenericBound::Trait(ptr, hir::TraitBoundModifier::Maybe) = ab { - unbounds.push(ptr) + let hir::GenericBound::Trait(ptr, modifier) = ab else { + continue; + }; + match modifier { + hir::TraitBoundModifier::Maybe => unbounds.push(ptr), + hir::TraitBoundModifier::Negative => { + if let Some(sized_def_id) = sized_def_id + && ptr.trait_ref.path.res == Res::Def(DefKind::Trait, sized_def_id) + { + seen_negative_sized_bound = true; + } + } + _ => {} } } }; search_bounds(ast_bounds); if let Some((self_ty, where_clause)) = self_ty_where_predicates { for clause in where_clause { - if let hir::WherePredicate::BoundPredicate(pred) = clause { - if pred.is_param_bound(self_ty.to_def_id()) { - search_bounds(pred.bounds); - } + if let hir::WherePredicate::BoundPredicate(pred) = clause + && pred.is_param_bound(self_ty.to_def_id()) + { + search_bounds(pred.bounds); } } } @@ -53,15 +66,13 @@ impl<'tcx> dyn AstConv<'tcx> + '_ { }); } - let sized_def_id = tcx.lang_items().sized_trait(); - let mut seen_sized_unbound = false; for unbound in unbounds { - if let Some(sized_def_id) = sized_def_id { - if unbound.trait_ref.path.res == Res::Def(DefKind::Trait, sized_def_id) { - seen_sized_unbound = true; - continue; - } + if let Some(sized_def_id) = sized_def_id + && unbound.trait_ref.path.res == Res::Def(DefKind::Trait, sized_def_id) + { + seen_sized_unbound = true; + continue; } // There was a `?Trait` bound, but it was not `?Sized`; warn. tcx.dcx().span_warn( @@ -71,15 +82,12 @@ impl<'tcx> dyn AstConv<'tcx> + '_ { ); } - // If the above loop finished there was no `?Sized` bound; add implicitly sized if `Sized` is available. - if sized_def_id.is_none() { - // No lang item for `Sized`, so we can't add it as a bound. - return; - } - if seen_sized_unbound { - // There was in fact a `?Sized` bound, return without doing anything - } else { - // There was no `?Sized` bound; add implicitly sized if `Sized` is available. + if seen_sized_unbound || seen_negative_sized_bound { + // There was in fact a `?Sized` or `!Sized` bound; + // we don't need to do anything. + } else if sized_def_id.is_some() { + // There was no `?Sized` or `!Sized` bound; + // add `Sized` if it's available. bounds.push_sized(tcx, self_ty, span); } } diff --git a/compiler/rustc_hir_analysis/src/check/errs.rs b/compiler/rustc_hir_analysis/src/check/errs.rs new file mode 100644 index 0000000000000..27bb2c57a5cb7 --- /dev/null +++ b/compiler/rustc_hir_analysis/src/check/errs.rs @@ -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 { + if let hir::ExprKind::Path(qpath) = expr.kind + && let hir::QPath::Resolved(_, path) = qpath + && let hir::def::Res::Def(def_kind, _) = path.res + && let hir::def::DefKind::Static(mt) = def_kind + && matches!(mt, Mutability::Mut) + { + return Some(qpath_to_string(&qpath)); + } + None +} + +fn handle_static_mut_ref( + tcx: TyCtxt<'_>, + span: Span, + var: String, + e2024: bool, + mutable: bool, + hir_id: hir::HirId, +) { + if e2024 { + let sugg = if mutable { + errors::StaticMutRefSugg::Mut { span, var } + } else { + errors::StaticMutRefSugg::Shared { span, var } + }; + tcx.sess.parse_sess.dcx.emit_err(errors::StaticMutRef { span, sugg }); + return; + } + + let (label, sugg, shared) = if mutable { + ( + errors::RefOfMutStaticLabel::Mut { span }, + errors::RefOfMutStaticSugg::Mut { span, var }, + "mutable ", + ) + } else { + ( + errors::RefOfMutStaticLabel::Shared { span }, + errors::RefOfMutStaticSugg::Shared { span, var }, + "shared ", + ) + }; + tcx.emit_spanned_lint( + STATIC_MUT_REF, + hir_id, + span, + errors::RefOfMutStatic { shared, why_note: (), label, sugg }, + ); +} diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index f60d6950670d9..ac0c715c6b308 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -66,6 +66,7 @@ mod check; mod compare_impl_item; pub mod dropck; mod entry; +mod errs; pub mod intrinsic; pub mod intrinsicck; mod region; diff --git a/compiler/rustc_hir_analysis/src/check/region.rs b/compiler/rustc_hir_analysis/src/check/region.rs index eab83c7a25467..666cbed3cdc68 100644 --- a/compiler/rustc_hir_analysis/src/check/region.rs +++ b/compiler/rustc_hir_analysis/src/check/region.rs @@ -18,6 +18,8 @@ use rustc_middle::ty::TyCtxt; use rustc_span::source_map; use rustc_span::Span; +use super::errs::{maybe_expr_static_mut, maybe_stmt_static_mut}; + use std::mem; #[derive(Debug, Copy, Clone)] @@ -214,6 +216,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 @@ -232,6 +236,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); diff --git a/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs b/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs index 5a73097b0f6b3..da7279967dac1 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs @@ -69,6 +69,7 @@ pub(super) fn find_opaque_ty_constraints_for_tait(tcx: TyCtxt<'_>, def_id: Local Node::Item(it) => locator.visit_item(it), Node::ImplItem(it) => locator.visit_impl_item(it), Node::TraitItem(it) => locator.visit_trait_item(it), + Node::ForeignItem(it) => locator.visit_foreign_item(it), other => bug!("{:?} is not a valid scope for an opaque type item", other), } } @@ -240,6 +241,12 @@ impl<'tcx> intravisit::Visitor<'tcx> for TaitConstraintLocator<'tcx> { self.check(it.owner_id.def_id); intravisit::walk_trait_item(self, it); } + fn visit_foreign_item(&mut self, it: &'tcx hir::ForeignItem<'tcx>) { + trace!(?it.owner_id); + assert_ne!(it.owner_id.def_id, self.def_id); + // No need to call `check`, as we do not run borrowck on foreign items. + intravisit::walk_foreign_item(self, it); + } } pub(super) fn find_opaque_ty_constraints_for_rpit<'tcx>( diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index 75e7a5524a744..1801acb1bcc03 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -1410,3 +1410,94 @@ pub struct OnlyCurrentTraitsPointerSugg<'a> { pub mut_key: &'a str, pub ptr_ty: Ty<'a>, } + +#[derive(Diagnostic)] +#[diag(hir_analysis_static_mut_ref, code = "E0796")] +#[note] +pub struct StaticMutRef { + #[primary_span] + #[label] + pub span: Span, + #[subdiagnostic] + pub sugg: StaticMutRefSugg, +} + +#[derive(Subdiagnostic)] +pub enum StaticMutRefSugg { + #[suggestion( + hir_analysis_suggestion, + style = "verbose", + code = "addr_of!({var})", + applicability = "maybe-incorrect" + )] + Shared { + #[primary_span] + span: Span, + var: String, + }, + #[suggestion( + hir_analysis_suggestion_mut, + style = "verbose", + code = "addr_of_mut!({var})", + applicability = "maybe-incorrect" + )] + Mut { + #[primary_span] + span: Span, + var: String, + }, +} + +// STATIC_MUT_REF lint +#[derive(LintDiagnostic)] +#[diag(hir_analysis_static_mut_ref_lint)] +#[note] +pub struct RefOfMutStatic<'a> { + pub shared: &'a str, + #[note(hir_analysis_why_note)] + pub why_note: (), + #[subdiagnostic] + pub label: RefOfMutStaticLabel, + #[subdiagnostic] + pub sugg: RefOfMutStaticSugg, +} + +#[derive(Subdiagnostic)] +pub enum RefOfMutStaticLabel { + #[label(hir_analysis_label)] + Shared { + #[primary_span] + span: Span, + }, + #[label(hir_analysis_label_mut)] + Mut { + #[primary_span] + span: Span, + }, +} + +#[derive(Subdiagnostic)] +pub enum RefOfMutStaticSugg { + #[suggestion( + hir_analysis_suggestion, + style = "verbose", + code = "addr_of!({var})", + applicability = "maybe-incorrect" + )] + Shared { + #[primary_span] + span: Span, + var: String, + }, + #[suggestion( + hir_analysis_suggestion_mut, + style = "verbose", + code = "addr_of_mut!({var})", + applicability = "maybe-incorrect" + )] + Mut { + #[primary_span] + span: Span, + var: String, + }, +} diff --git a/compiler/rustc_infer/src/traits/error_reporting/mod.rs b/compiler/rustc_infer/src/traits/error_reporting/mod.rs index d89c205da3f52..34163111d3c78 100644 --- a/compiler/rustc_infer/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/traits/error_reporting/mod.rs @@ -132,7 +132,10 @@ pub fn report_object_safety_error<'tcx>( }; let externally_visible = if !impls.is_empty() && let Some(def_id) = trait_def_id.as_local() - && tcx.effective_visibilities(()).is_exported(def_id) + // We may be executing this during typeck, which would result in cycle + // if we used effective_visibilities query, which looks into opaque types + // (and therefore calls typeck). + && tcx.resolutions(()).effective_visibilities.is_exported(def_id) { true } else { diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index c4a1f3a0e510b..023acd5781302 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -6,8 +6,8 @@ use rustc_session::config::{ build_configuration, build_session_options, rustc_optgroups, BranchProtection, CFGuard, Cfg, DebugInfo, DumpMonoStatsFormat, ErrorOutputType, ExternEntry, ExternLocation, Externs, FunctionReturn, InliningThreshold, Input, InstrumentCoverage, InstrumentXRay, - LinkSelfContained, LinkerPluginLto, LocationDetail, LtoCli, MirSpanview, NextSolverConfig, - OomStrategy, Options, OutFileName, OutputType, OutputTypes, PAuthKey, PacRet, Passes, Polonius, + LinkSelfContained, LinkerPluginLto, LocationDetail, LtoCli, NextSolverConfig, OomStrategy, + Options, OutFileName, OutputType, OutputTypes, PAuthKey, PacRet, Passes, Polonius, ProcMacroExecutionStrategy, Strip, SwitchWithOptPath, SymbolManglingVersion, WasiExecModel, }; use rustc_session::lint::Level; @@ -666,7 +666,6 @@ fn test_unstable_options_tracking_hash() { untracked!(dump_mir_dir, String::from("abc")); untracked!(dump_mir_exclude_pass_number, true); untracked!(dump_mir_graphviz, true); - untracked!(dump_mir_spanview, Some(MirSpanview::Statement)); untracked!(dump_mono_stats, SwitchWithOptPath::Enabled(Some("mono-items-dir/".into()))); untracked!(dump_mono_stats_format, DumpMonoStatsFormat::Json); untracked!(dylib_lto, true); @@ -806,7 +805,6 @@ fn test_unstable_options_tracking_hash() { tracked!(relax_elf_relocations, Some(true)); tracked!(relro_level, Some(RelroLevel::Full)); tracked!(remap_cwd_prefix, Some(PathBuf::from("abc"))); - tracked!(report_delayed_bugs, true); tracked!(sanitizer, SanitizerSet::ADDRESS); tracked!(sanitizer_cfi_canonical_jump_tables, None); tracked!(sanitizer_cfi_generalize_pointers, Some(true)); diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 19da51b7dcfa3..cfba6780a66fa 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -89,6 +89,7 @@ declare_lint_pass! { SINGLE_USE_LIFETIMES, SOFT_UNSTABLE, STABLE_FEATURES, + STATIC_MUT_REF, SUSPICIOUS_AUTO_TRAIT_IMPLS, TEST_UNSTABLE_LINT, TEXT_DIRECTION_CODEPOINT_IN_COMMENT, @@ -1767,6 +1768,57 @@ declare_lint! { }; } +declare_lint! { + /// The `static_mut_ref` lint checks for shared or mutable references + /// of mutable static inside `unsafe` blocks and `unsafe` functions. + /// + /// ### Example + /// + /// ```rust,edition2021 + /// fn main() { + /// static mut X: i32 = 23; + /// static mut Y: i32 = 24; + /// + /// unsafe { + /// let y = &X; + /// let ref x = X; + /// let (x, y) = (&X, &Y); + /// foo(&X); + /// } + /// } + /// + /// unsafe fn _foo() { + /// static mut X: i32 = 23; + /// static mut Y: i32 = 24; + /// + /// let y = &X; + /// let ref x = X; + /// let (x, y) = (&X, &Y); + /// foo(&X); + /// } + /// + /// fn foo<'a>(_x: &'a i32) {} + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Shared or mutable references of mutable static are almost always a mistake and + /// can lead to undefined behavior and various other problems in your code. + /// + /// This lint is "warn" by default on editions up to 2021, from 2024 there is + /// a hard error instead. + pub STATIC_MUT_REF, + Warn, + "shared references or mutable references of mutable static is discouraged", + @future_incompatible = FutureIncompatibleInfo { + reason: FutureIncompatibilityReason::EditionError(Edition::Edition2024), + reference: "issue #114447 ", + 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`, diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 5c425fef27ebc..903da8374cd3b 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -55,7 +55,6 @@ pub mod mono; pub mod patch; pub mod pretty; mod query; -pub mod spanview; mod statement; mod syntax; pub mod tcx; diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index 0b487eae36dbd..a1e5d73a0fdb1 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -5,7 +5,6 @@ use std::io::{self, Write as _}; use std::path::{Path, PathBuf}; use super::graphviz::write_mir_fn_graphviz; -use super::spanview::write_mir_fn_spanview; use rustc_ast::InlineAsmTemplatePiece; use rustc_middle::mir::interpret::{ alloc_range, read_target_uint, AllocBytes, AllocId, Allocation, GlobalAlloc, Pointer, @@ -141,16 +140,6 @@ fn dump_matched_mir_node<'tcx, F>( write_mir_fn_graphviz(tcx, body, false, &mut file)?; }; } - - if let Some(spanview) = tcx.sess.opts.unstable_opts.dump_mir_spanview { - let _: io::Result<()> = try { - let file_basename = dump_file_basename(tcx, pass_num, pass_name, disambiguator, body); - let mut file = create_dump_file_with_basename(tcx, &file_basename, "html")?; - if body.source.def_id().is_local() { - write_mir_fn_spanview(tcx, body, spanview, &file_basename, &mut file)?; - } - }; - } } /// Returns the file basename portion (without extension) of a filename path diff --git a/compiler/rustc_middle/src/mir/spanview.rs b/compiler/rustc_middle/src/mir/spanview.rs deleted file mode 100644 index cb9fc0d37f2e0..0000000000000 --- a/compiler/rustc_middle/src/mir/spanview.rs +++ /dev/null @@ -1,642 +0,0 @@ -use rustc_middle::hir; -use rustc_middle::mir::*; -use rustc_session::config::MirSpanview; -use rustc_span::{BytePos, Pos}; - -use std::cmp; -use std::io::{self, Write}; - -pub const TOOLTIP_INDENT: &str = " "; - -const CARET: char = '\u{2038}'; // Unicode `CARET` -const ANNOTATION_LEFT_BRACKET: char = '\u{298a}'; // Unicode `Z NOTATION RIGHT BINDING BRACKET` -const ANNOTATION_RIGHT_BRACKET: char = '\u{2989}'; // Unicode `Z NOTATION LEFT BINDING BRACKET` -const NEW_LINE_SPAN: &str = "\n"; -const HEADER: &str = r#" - - -"#; -const START_BODY: &str = r#" -"#; -const FOOTER: &str = r#" -"#; - -const STYLE_SECTION: &str = r#""#; - -/// Metadata to highlight the span of a MIR BasicBlock, Statement, or Terminator. -#[derive(Clone, Debug)] -pub struct SpanViewable { - pub bb: BasicBlock, - pub span: Span, - pub id: String, - pub tooltip: String, -} - -/// Write a spanview HTML+CSS file to analyze MIR element spans. -pub fn write_mir_fn_spanview<'tcx, W>( - tcx: TyCtxt<'tcx>, - body: &Body<'tcx>, - spanview: MirSpanview, - title: &str, - w: &mut W, -) -> io::Result<()> -where - W: Write, -{ - let def_id = body.source.def_id(); - let hir_body = hir_body(tcx, def_id); - if hir_body.is_none() { - return Ok(()); - } - let body_span = hir_body.unwrap().value.span; - let mut span_viewables = Vec::new(); - for (bb, data) in body.basic_blocks.iter_enumerated() { - match spanview { - MirSpanview::Statement => { - for (i, statement) in data.statements.iter().enumerate() { - if let Some(span_viewable) = - statement_span_viewable(tcx, body_span, bb, i, statement) - { - span_viewables.push(span_viewable); - } - } - if let Some(span_viewable) = terminator_span_viewable(tcx, body_span, bb, data) { - span_viewables.push(span_viewable); - } - } - MirSpanview::Terminator => { - if let Some(span_viewable) = terminator_span_viewable(tcx, body_span, bb, data) { - span_viewables.push(span_viewable); - } - } - MirSpanview::Block => { - if let Some(span_viewable) = block_span_viewable(tcx, body_span, bb, data) { - span_viewables.push(span_viewable); - } - } - } - } - write_document(tcx, fn_span(tcx, def_id), span_viewables, title, w)?; - Ok(()) -} - -/// Generate a spanview HTML+CSS document for the given local function `def_id`, and a pre-generated -/// list `SpanViewable`s. -pub fn write_document<'tcx, W>( - tcx: TyCtxt<'tcx>, - spanview_span: Span, - mut span_viewables: Vec, - title: &str, - w: &mut W, -) -> io::Result<()> -where - W: Write, -{ - let mut from_pos = spanview_span.lo(); - let end_pos = spanview_span.hi(); - let source_map = tcx.sess.source_map(); - let start = source_map.lookup_char_pos(from_pos); - let indent_to_initial_start_col = " ".repeat(start.col.to_usize()); - debug!( - "spanview_span={:?}; source is:\n{}{}", - spanview_span, - indent_to_initial_start_col, - source_map.span_to_snippet(spanview_span).expect("function should have printable source") - ); - writeln!(w, "{HEADER}")?; - writeln!(w, "{title}")?; - writeln!(w, "{STYLE_SECTION}")?; - writeln!(w, "{START_BODY}")?; - write!( - w, - r#"
{}"#, - start.line - 1, - indent_to_initial_start_col, - )?; - span_viewables.sort_unstable_by(|a, b| { - let a = a.span; - let b = b.span; - if a.lo() == b.lo() { - // Sort hi() in reverse order so shorter spans are attempted after longer spans. - // This should give shorter spans a higher "layer", so they are not covered by - // the longer spans. - b.hi().partial_cmp(&a.hi()) - } else { - a.lo().partial_cmp(&b.lo()) - } - .unwrap() - }); - let mut ordered_viewables = &span_viewables[..]; - const LOWEST_VIEWABLE_LAYER: usize = 1; - let mut alt = false; - while ordered_viewables.len() > 0 { - debug!( - "calling write_next_viewable with from_pos={}, end_pos={}, and viewables len={}", - from_pos.to_usize(), - end_pos.to_usize(), - ordered_viewables.len() - ); - let curr_id = &ordered_viewables[0].id; - let (next_from_pos, next_ordered_viewables) = write_next_viewable_with_overlaps( - tcx, - from_pos, - end_pos, - ordered_viewables, - alt, - LOWEST_VIEWABLE_LAYER, - w, - )?; - debug!( - "DONE calling write_next_viewable, with new from_pos={}, \ - and remaining viewables len={}", - next_from_pos.to_usize(), - next_ordered_viewables.len() - ); - assert!( - from_pos != next_from_pos || ordered_viewables.len() != next_ordered_viewables.len(), - "write_next_viewable_with_overlaps() must make a state change" - ); - from_pos = next_from_pos; - if next_ordered_viewables.len() != ordered_viewables.len() { - ordered_viewables = next_ordered_viewables; - if let Some(next_ordered_viewable) = ordered_viewables.first() { - if &next_ordered_viewable.id != curr_id { - alt = !alt; - } - } - } - } - if from_pos < end_pos { - write_coverage_gap(tcx, from_pos, end_pos, w)?; - } - writeln!(w, r#"
"#)?; - writeln!(w, "{FOOTER}")?; - Ok(()) -} - -/// Format a string showing the start line and column, and end line and column within a file. -pub fn source_range_no_file(tcx: TyCtxt<'_>, span: Span) -> String { - let source_map = tcx.sess.source_map(); - let start = source_map.lookup_char_pos(span.lo()); - let end = source_map.lookup_char_pos(span.hi()); - format!("{}:{}-{}:{}", start.line, start.col.to_usize() + 1, end.line, end.col.to_usize() + 1) -} - -fn statement_span_viewable<'tcx>( - tcx: TyCtxt<'tcx>, - body_span: Span, - bb: BasicBlock, - i: usize, - statement: &Statement<'tcx>, -) -> Option { - let span = statement.source_info.span; - if !body_span.contains(span) { - return None; - } - let id = format!("{}[{}]", bb.index(), i); - let tooltip = tooltip(tcx, &id, span, vec![statement.clone()], &None); - Some(SpanViewable { bb, span, id, tooltip }) -} - -fn terminator_span_viewable<'tcx>( - tcx: TyCtxt<'tcx>, - body_span: Span, - bb: BasicBlock, - data: &BasicBlockData<'tcx>, -) -> Option { - let term = data.terminator(); - let span = term.source_info.span; - if !body_span.contains(span) { - return None; - } - let id = format!("{}:{}", bb.index(), term.kind.name()); - let tooltip = tooltip(tcx, &id, span, vec![], &data.terminator); - Some(SpanViewable { bb, span, id, tooltip }) -} - -fn block_span_viewable<'tcx>( - tcx: TyCtxt<'tcx>, - body_span: Span, - bb: BasicBlock, - data: &BasicBlockData<'tcx>, -) -> Option { - let span = compute_block_span(data, body_span); - if !body_span.contains(span) { - return None; - } - let id = format!("{}", bb.index()); - let tooltip = tooltip(tcx, &id, span, data.statements.clone(), &data.terminator); - Some(SpanViewable { bb, span, id, tooltip }) -} - -fn compute_block_span(data: &BasicBlockData<'_>, body_span: Span) -> Span { - let mut span = data.terminator().source_info.span; - for statement_span in data.statements.iter().map(|statement| statement.source_info.span) { - // Only combine Spans from the root context, and within the function's body_span. - if statement_span.ctxt().is_root() && body_span.contains(statement_span) { - span = span.to(statement_span); - } - } - span -} - -/// Recursively process each ordered span. Spans that overlap will have progressively varying -/// styles, such as increased padding for each overlap. Non-overlapping adjacent spans will -/// have alternating style choices, to help distinguish between them if, visually adjacent. -/// The `layer` is incremented for each overlap, and the `alt` bool alternates between true -/// and false, for each adjacent non-overlapping span. Source code between the spans (code -/// that is not in any coverage region) has neutral styling. -fn write_next_viewable_with_overlaps<'tcx, 'b, W>( - tcx: TyCtxt<'tcx>, - mut from_pos: BytePos, - mut to_pos: BytePos, - ordered_viewables: &'b [SpanViewable], - alt: bool, - layer: usize, - w: &mut W, -) -> io::Result<(BytePos, &'b [SpanViewable])> -where - W: Write, -{ - let debug_indent = " ".repeat(layer); - let (viewable, mut remaining_viewables) = - ordered_viewables.split_first().expect("ordered_viewables should have some"); - - if from_pos < viewable.span.lo() { - debug!( - "{}advance from_pos to next SpanViewable (from from_pos={} to viewable.span.lo()={} \ - of {:?}), with to_pos={}", - debug_indent, - from_pos.to_usize(), - viewable.span.lo().to_usize(), - viewable.span, - to_pos.to_usize() - ); - let hi = cmp::min(viewable.span.lo(), to_pos); - write_coverage_gap(tcx, from_pos, hi, w)?; - from_pos = hi; - if from_pos < viewable.span.lo() { - debug!( - "{}EARLY RETURN: stopped before getting to next SpanViewable, at {}", - debug_indent, - from_pos.to_usize() - ); - return Ok((from_pos, ordered_viewables)); - } - } - - if from_pos < viewable.span.hi() { - // Set to_pos to the end of this `viewable` to ensure the recursive calls stop writing - // with room to print the tail. - to_pos = cmp::min(viewable.span.hi(), to_pos); - debug!( - "{}update to_pos (if not closer) to viewable.span.hi()={}; to_pos is now {}", - debug_indent, - viewable.span.hi().to_usize(), - to_pos.to_usize() - ); - } - - let mut subalt = false; - while remaining_viewables.len() > 0 && remaining_viewables[0].span.overlaps(viewable.span) { - let overlapping_viewable = &remaining_viewables[0]; - debug!("{}overlapping_viewable.span={:?}", debug_indent, overlapping_viewable.span); - - let span = - trim_span(viewable.span, from_pos, cmp::min(overlapping_viewable.span.lo(), to_pos)); - let mut some_html_snippet = if from_pos <= viewable.span.hi() || viewable.span.is_empty() { - // `viewable` is not yet fully rendered, so start writing the span, up to either the - // `to_pos` or the next `overlapping_viewable`, whichever comes first. - debug!( - "{}make html_snippet (may not write it if early exit) for partial span {:?} \ - of viewable.span {:?}", - debug_indent, span, viewable.span - ); - from_pos = span.hi(); - make_html_snippet(tcx, span, Some(viewable)) - } else { - None - }; - - // Defer writing the HTML snippet (until after early return checks) ONLY for empty spans. - // An empty Span with Some(html_snippet) is probably a tail marker. If there is an early - // exit, there should be another opportunity to write the tail marker. - if !span.is_empty() { - if let Some(ref html_snippet) = some_html_snippet { - debug!( - "{}write html_snippet for that partial span of viewable.span {:?}", - debug_indent, viewable.span - ); - write_span(html_snippet, &viewable.tooltip, alt, layer, w)?; - } - some_html_snippet = None; - } - - if from_pos < overlapping_viewable.span.lo() { - debug!( - "{}EARLY RETURN: from_pos={} has not yet reached the \ - overlapping_viewable.span {:?}", - debug_indent, - from_pos.to_usize(), - overlapping_viewable.span - ); - // must have reached `to_pos` before reaching the start of the - // `overlapping_viewable.span` - return Ok((from_pos, ordered_viewables)); - } - - if from_pos == to_pos - && !(from_pos == overlapping_viewable.span.lo() && overlapping_viewable.span.is_empty()) - { - debug!( - "{}EARLY RETURN: from_pos=to_pos={} and overlapping_viewable.span {:?} is not \ - empty, or not from_pos", - debug_indent, - to_pos.to_usize(), - overlapping_viewable.span - ); - // `to_pos` must have occurred before the overlapping viewable. Return - // `ordered_viewables` so we can continue rendering the `viewable`, from after the - // `to_pos`. - return Ok((from_pos, ordered_viewables)); - } - - if let Some(ref html_snippet) = some_html_snippet { - debug!( - "{}write html_snippet for that partial span of viewable.span {:?}", - debug_indent, viewable.span - ); - write_span(html_snippet, &viewable.tooltip, alt, layer, w)?; - } - - debug!( - "{}recursively calling write_next_viewable with from_pos={}, to_pos={}, \ - and viewables len={}", - debug_indent, - from_pos.to_usize(), - to_pos.to_usize(), - remaining_viewables.len() - ); - // Write the overlaps (and the overlaps' overlaps, if any) up to `to_pos`. - let curr_id = &remaining_viewables[0].id; - let (next_from_pos, next_remaining_viewables) = write_next_viewable_with_overlaps( - tcx, - from_pos, - to_pos, - remaining_viewables, - subalt, - layer + 1, - w, - )?; - debug!( - "{}DONE recursively calling write_next_viewable, with new from_pos={}, and remaining \ - viewables len={}", - debug_indent, - next_from_pos.to_usize(), - next_remaining_viewables.len() - ); - assert!( - from_pos != next_from_pos - || remaining_viewables.len() != next_remaining_viewables.len(), - "write_next_viewable_with_overlaps() must make a state change" - ); - from_pos = next_from_pos; - if next_remaining_viewables.len() != remaining_viewables.len() { - remaining_viewables = next_remaining_viewables; - if let Some(next_ordered_viewable) = remaining_viewables.first() { - if &next_ordered_viewable.id != curr_id { - subalt = !subalt; - } - } - } - } - if from_pos <= viewable.span.hi() { - let span = trim_span(viewable.span, from_pos, to_pos); - debug!( - "{}After overlaps, writing (end span?) {:?} of viewable.span {:?}", - debug_indent, span, viewable.span - ); - if let Some(ref html_snippet) = make_html_snippet(tcx, span, Some(viewable)) { - from_pos = span.hi(); - write_span(html_snippet, &viewable.tooltip, alt, layer, w)?; - } - } - debug!("{}RETURN: No more overlap", debug_indent); - Ok(( - from_pos, - if from_pos < viewable.span.hi() { ordered_viewables } else { remaining_viewables }, - )) -} - -#[inline(always)] -fn write_coverage_gap(tcx: TyCtxt<'_>, lo: BytePos, hi: BytePos, w: &mut W) -> io::Result<()> -where - W: Write, -{ - let span = Span::with_root_ctxt(lo, hi); - if let Some(ref html_snippet) = make_html_snippet(tcx, span, None) { - write_span(html_snippet, "", false, 0, w) - } else { - Ok(()) - } -} - -fn write_span( - html_snippet: &str, - tooltip: &str, - alt: bool, - layer: usize, - w: &mut W, -) -> io::Result<()> -where - W: Write, -{ - let maybe_alt_class = if layer > 0 { if alt { " odd" } else { " even" } } else { "" }; - let maybe_title_attr = if !tooltip.is_empty() { - format!(" title=\"{}\"", escape_attr(tooltip)) - } else { - "".to_owned() - }; - if layer == 1 { - write!(w, "")?; - } - for (i, line) in html_snippet.lines().enumerate() { - if i > 0 { - write!(w, "{NEW_LINE_SPAN}")?; - } - write!( - w, - r#"{line}"# - )?; - } - // Check for and translate trailing newlines, because `str::lines()` ignores them - if html_snippet.ends_with('\n') { - write!(w, "{NEW_LINE_SPAN}")?; - } - if layer == 1 { - write!(w, "")?; - } - Ok(()) -} - -fn make_html_snippet( - tcx: TyCtxt<'_>, - span: Span, - some_viewable: Option<&SpanViewable>, -) -> Option { - let source_map = tcx.sess.source_map(); - let snippet = source_map - .span_to_snippet(span) - .unwrap_or_else(|err| bug!("span_to_snippet error for span {:?}: {:?}", span, err)); - let html_snippet = if let Some(viewable) = some_viewable { - let is_head = span.lo() == viewable.span.lo(); - let is_tail = span.hi() == viewable.span.hi(); - let mut labeled_snippet = if is_head { - format!(r#"{}{}"#, viewable.id, ANNOTATION_LEFT_BRACKET) - } else { - "".to_owned() - }; - if span.is_empty() { - if is_head && is_tail { - labeled_snippet.push(CARET); - } - } else { - labeled_snippet.push_str(&escape_html(&snippet)); - }; - if is_tail { - labeled_snippet.push_str(&format!( - r#"{}{}"#, - ANNOTATION_RIGHT_BRACKET, viewable.id - )); - } - labeled_snippet - } else { - escape_html(&snippet) - }; - if html_snippet.is_empty() { None } else { Some(html_snippet) } -} - -fn tooltip<'tcx>( - tcx: TyCtxt<'tcx>, - spanview_id: &str, - span: Span, - statements: Vec>, - terminator: &Option>, -) -> String { - let source_map = tcx.sess.source_map(); - let mut text = Vec::new(); - text.push(format!("{}: {}:", spanview_id, &source_map.span_to_embeddable_string(span))); - for statement in statements { - let source_range = source_range_no_file(tcx, statement.source_info.span); - text.push(format!( - "\n{}{}: {}: {:?}", - TOOLTIP_INDENT, - source_range, - statement.kind.name(), - statement - )); - } - if let Some(term) = terminator { - let source_range = source_range_no_file(tcx, term.source_info.span); - text.push(format!( - "\n{}{}: {}: {:?}", - TOOLTIP_INDENT, - source_range, - term.kind.name(), - term.kind - )); - } - text.join("") -} - -fn trim_span(span: Span, from_pos: BytePos, to_pos: BytePos) -> Span { - trim_span_hi(trim_span_lo(span, from_pos), to_pos) -} - -fn trim_span_lo(span: Span, from_pos: BytePos) -> Span { - if from_pos <= span.lo() { span } else { span.with_lo(cmp::min(span.hi(), from_pos)) } -} - -fn trim_span_hi(span: Span, to_pos: BytePos) -> Span { - if to_pos >= span.hi() { span } else { span.with_hi(cmp::max(span.lo(), to_pos)) } -} - -fn fn_span(tcx: TyCtxt<'_>, def_id: DefId) -> Span { - let fn_decl_span = tcx.def_span(def_id); - if let Some(body_span) = hir_body(tcx, def_id).map(|hir_body| hir_body.value.span) { - if fn_decl_span.eq_ctxt(body_span) { fn_decl_span.to(body_span) } else { body_span } - } else { - fn_decl_span - } -} - -fn hir_body(tcx: TyCtxt<'_>, def_id: DefId) -> Option<&rustc_hir::Body<'_>> { - let hir_node = tcx.hir().get_if_local(def_id).expect("expected DefId is local"); - hir::map::associated_body(hir_node).map(|(_, fn_body_id)| tcx.hir().body(fn_body_id)) -} - -fn escape_html(s: &str) -> String { - s.replace('&', "&").replace('<', "<").replace('>', ">") -} - -fn escape_attr(s: &str) -> String { - s.replace('&', "&") - .replace('\"', """) - .replace('\'', "'") - .replace('<', "<") - .replace('>', ">") -} diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index ebbd02e01bf33..dadd4de2bf97a 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -912,7 +912,8 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { let mut traits = FxIndexMap::default(); let mut fn_traits = FxIndexMap::default(); - let mut is_sized = false; + let mut has_sized_bound = false; + let mut has_negative_sized_bound = false; let mut lifetimes = SmallVec::<[ty::Region<'tcx>; 1]>::new(); for (predicate, _) in bounds.iter_instantiated_copied(tcx, args) { @@ -922,13 +923,24 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { ty::ClauseKind::Trait(pred) => { let trait_ref = bound_predicate.rebind(pred.trait_ref); - // Don't print + Sized, but rather + ?Sized if absent. + // Don't print `+ Sized`, but rather `+ ?Sized` if absent. if Some(trait_ref.def_id()) == tcx.lang_items().sized_trait() { - is_sized = true; - continue; + match pred.polarity { + ty::ImplPolarity::Positive | ty::ImplPolarity::Reservation => { + has_sized_bound = true; + continue; + } + ty::ImplPolarity::Negative => has_negative_sized_bound = true, + } } - self.insert_trait_and_projection(trait_ref, None, &mut traits, &mut fn_traits); + self.insert_trait_and_projection( + trait_ref, + pred.polarity, + None, + &mut traits, + &mut fn_traits, + ); } ty::ClauseKind::Projection(pred) => { let proj_ref = bound_predicate.rebind(pred); @@ -939,6 +951,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { self.insert_trait_and_projection( trait_ref, + ty::ImplPolarity::Positive, Some(proj_ty), &mut traits, &mut fn_traits, @@ -955,7 +968,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { let mut first = true; // Insert parenthesis around (Fn(A, B) -> C) if the opaque ty has more than one other trait - let paren_needed = fn_traits.len() > 1 || traits.len() > 0 || !is_sized; + let paren_needed = fn_traits.len() > 1 || traits.len() > 0 || !has_sized_bound; for (fn_once_trait_ref, entry) in fn_traits { write!(self, "{}", if first { "" } else { " + " })?; @@ -1002,18 +1015,21 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { // trait_refs we collected in the OpaqueFnEntry as normal trait refs. _ => { if entry.has_fn_once { - traits.entry(fn_once_trait_ref).or_default().extend( - // Group the return ty with its def id, if we had one. - entry - .return_ty - .map(|ty| (tcx.require_lang_item(LangItem::FnOnce, None), ty)), - ); + traits + .entry((fn_once_trait_ref, ty::ImplPolarity::Positive)) + .or_default() + .extend( + // Group the return ty with its def id, if we had one. + entry.return_ty.map(|ty| { + (tcx.require_lang_item(LangItem::FnOnce, None), ty) + }), + ); } if let Some(trait_ref) = entry.fn_mut_trait_ref { - traits.entry(trait_ref).or_default(); + traits.entry((trait_ref, ty::ImplPolarity::Positive)).or_default(); } if let Some(trait_ref) = entry.fn_trait_ref { - traits.entry(trait_ref).or_default(); + traits.entry((trait_ref, ty::ImplPolarity::Positive)).or_default(); } } } @@ -1023,11 +1039,15 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { } // Print the rest of the trait types (that aren't Fn* family of traits) - for (trait_ref, assoc_items) in traits { + for ((trait_ref, polarity), assoc_items) in traits { write!(self, "{}", if first { "" } else { " + " })?; self.wrap_binder(&trait_ref, |trait_ref, cx| { define_scoped_cx!(cx); + + if polarity == ty::ImplPolarity::Negative { + p!("!"); + } p!(print(trait_ref.print_only_trait_name())); let generics = tcx.generics_of(trait_ref.def_id); @@ -1094,9 +1114,15 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { })?; } - if !is_sized { - write!(self, "{}?Sized", if first { "" } else { " + " })?; - } else if first { + let add_sized = has_sized_bound && (first || has_negative_sized_bound); + let add_maybe_sized = !has_sized_bound && !has_negative_sized_bound; + if add_sized || add_maybe_sized { + if !first { + write!(self, " + ")?; + } + if add_maybe_sized { + write!(self, "?")?; + } write!(self, "Sized")?; } @@ -1128,9 +1154,10 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { fn insert_trait_and_projection( &mut self, trait_ref: ty::PolyTraitRef<'tcx>, + polarity: ty::ImplPolarity, proj_ty: Option<(DefId, ty::Binder<'tcx, Term<'tcx>>)>, traits: &mut FxIndexMap< - ty::PolyTraitRef<'tcx>, + (ty::PolyTraitRef<'tcx>, ty::ImplPolarity), FxIndexMap>>, >, fn_traits: &mut FxIndexMap, OpaqueFnEntry<'tcx>>, @@ -1139,7 +1166,10 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { // If our trait_ref is FnOnce or any of its children, project it onto the parent FnOnce // super-trait ref and record it there. - if let Some(fn_once_trait) = self.tcx().lang_items().fn_once_trait() { + // We skip negative Fn* bounds since they can't use parenthetical notation anyway. + if polarity == ty::ImplPolarity::Positive + && let Some(fn_once_trait) = self.tcx().lang_items().fn_once_trait() + { // If we have a FnOnce, then insert it into if trait_def_id == fn_once_trait { let entry = fn_traits.entry(trait_ref).or_default(); @@ -1167,7 +1197,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { } // Otherwise, just group our traits and projection types. - traits.entry(trait_ref).or_default().extend(proj_ty); + traits.entry((trait_ref, polarity)).or_default().extend(proj_ty); } fn pretty_print_inherent_projection( diff --git a/compiler/rustc_mir_transform/src/dest_prop.rs b/compiler/rustc_mir_transform/src/dest_prop.rs index 15502adfb5aad..cd80f423466bc 100644 --- a/compiler/rustc_mir_transform/src/dest_prop.rs +++ b/compiler/rustc_mir_transform/src/dest_prop.rs @@ -133,7 +133,6 @@ use std::collections::hash_map::{Entry, OccupiedEntry}; -use crate::simplify::remove_dead_blocks; use crate::MirPass; use rustc_data_structures::fx::FxHashMap; use rustc_index::bit_set::BitSet; @@ -241,12 +240,6 @@ impl<'tcx> MirPass<'tcx> for DestinationPropagation { apply_merges(body, tcx, &merges, &merged_locals); } - if round_count != 0 { - // Merging can introduce overlap between moved arguments and/or call destination in an - // unreachable code, which validator considers to be ill-formed. - remove_dead_blocks(body); - } - trace!(round_count); } } diff --git a/compiler/rustc_mir_transform/src/lint.rs b/compiler/rustc_mir_transform/src/lint.rs index 3940d0ddbf344..c0c0a3f5ee649 100644 --- a/compiler/rustc_mir_transform/src/lint.rs +++ b/compiler/rustc_mir_transform/src/lint.rs @@ -1,6 +1,7 @@ //! This pass statically detects code which has undefined behaviour or is likely to be erroneous. //! It can be used to locate problems in MIR building or optimizations. It assumes that all code //! can be executed, so it has false positives. +use rustc_data_structures::fx::FxHashSet; use rustc_index::bit_set::BitSet; use rustc_middle::mir::visit::{PlaceContext, Visitor}; use rustc_middle::mir::*; @@ -11,7 +12,6 @@ use rustc_mir_dataflow::{Analysis, ResultsCursor}; use std::borrow::Cow; pub fn lint_body<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, when: String) { - let reachable_blocks = traversal::reachable_as_bitset(body); let always_live_locals = &always_storage_live_locals(body); let maybe_storage_live = MaybeStorageLive::new(Cow::Borrowed(always_live_locals)) @@ -24,17 +24,19 @@ pub fn lint_body<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, when: String) { .iterate_to_fixpoint() .into_results_cursor(body); - Lint { + let mut lint = Lint { tcx, when, body, is_fn_like: tcx.def_kind(body.source.def_id()).is_fn_like(), always_live_locals, - reachable_blocks, maybe_storage_live, maybe_storage_dead, + places: Default::default(), + }; + for (bb, data) in traversal::reachable(body) { + lint.visit_basic_block_data(bb, data); } - .visit_body(body); } struct Lint<'a, 'tcx> { @@ -43,9 +45,9 @@ struct Lint<'a, 'tcx> { body: &'a Body<'tcx>, is_fn_like: bool, always_live_locals: &'a BitSet, - reachable_blocks: BitSet, maybe_storage_live: ResultsCursor<'a, 'tcx, MaybeStorageLive<'a>>, maybe_storage_dead: ResultsCursor<'a, 'tcx, MaybeStorageDead<'a>>, + places: FxHashSet>, } impl<'a, 'tcx> Lint<'a, 'tcx> { @@ -67,7 +69,7 @@ impl<'a, 'tcx> Lint<'a, 'tcx> { impl<'a, 'tcx> Visitor<'tcx> for Lint<'a, 'tcx> { fn visit_local(&mut self, local: Local, context: PlaceContext, location: Location) { - if self.reachable_blocks.contains(location.block) && context.is_use() { + if context.is_use() { self.maybe_storage_dead.seek_after_primary_effect(location); if self.maybe_storage_dead.get().contains(local) { self.fail(location, format!("use of local {local:?}, which has no storage here")); @@ -76,18 +78,28 @@ impl<'a, 'tcx> Visitor<'tcx> for Lint<'a, 'tcx> { } fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) { - match statement.kind { - StatementKind::StorageLive(local) => { - if self.reachable_blocks.contains(location.block) { - self.maybe_storage_live.seek_before_primary_effect(location); - if self.maybe_storage_live.get().contains(local) { + match &statement.kind { + StatementKind::Assign(box (dest, rvalue)) => { + if let Rvalue::Use(Operand::Copy(src) | Operand::Move(src)) = rvalue { + // The sides of an assignment must not alias. Currently this just checks whether + // the places are identical. + if dest == src { self.fail( location, - format!("StorageLive({local:?}) which already has storage here"), + "encountered `Assign` statement with overlapping memory", ); } } } + StatementKind::StorageLive(local) => { + self.maybe_storage_live.seek_before_primary_effect(location); + if self.maybe_storage_live.get().contains(*local) { + self.fail( + location, + format!("StorageLive({local:?}) which already has storage here"), + ); + } + } _ => {} } @@ -95,9 +107,9 @@ impl<'a, 'tcx> Visitor<'tcx> for Lint<'a, 'tcx> { } fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) { - match terminator.kind { + match &terminator.kind { TerminatorKind::Return => { - if self.is_fn_like && self.reachable_blocks.contains(location.block) { + if self.is_fn_like { self.maybe_storage_live.seek_after_primary_effect(location); for local in self.maybe_storage_live.get().iter() { if !self.always_live_locals.contains(local) { @@ -111,6 +123,28 @@ impl<'a, 'tcx> Visitor<'tcx> for Lint<'a, 'tcx> { } } } + TerminatorKind::Call { args, destination, .. } => { + // The call destination place and Operand::Move place used as an argument might be + // passed by a reference to the callee. Consequently they must be non-overlapping. + // Currently this simply checks for duplicate places. + self.places.clear(); + self.places.insert(destination.as_ref()); + let mut has_duplicates = false; + for arg in args { + if let Operand::Move(place) = arg { + has_duplicates |= !self.places.insert(place.as_ref()); + } + } + if has_duplicates { + self.fail( + location, + format!( + "encountered overlapping memory in `Move` arguments to `Call` terminator: {:?}", + terminator.kind, + ), + ); + } + } _ => {} } diff --git a/compiler/rustc_mir_transform/src/pass_manager.rs b/compiler/rustc_mir_transform/src/pass_manager.rs index 82074f1960d25..f4c572aec128a 100644 --- a/compiler/rustc_mir_transform/src/pass_manager.rs +++ b/compiler/rustc_mir_transform/src/pass_manager.rs @@ -109,14 +109,15 @@ fn run_passes_inner<'tcx>( phase_change: Option, validate_each: bool, ) { - let lint = tcx.sess.opts.unstable_opts.lint_mir & !body.should_skip(); - let validate = validate_each & tcx.sess.opts.unstable_opts.validate_mir & !body.should_skip(); let overridden_passes = &tcx.sess.opts.unstable_opts.mir_enable_passes; trace!(?overridden_passes); let prof_arg = tcx.sess.prof.enabled().then(|| format!("{:?}", body.source.def_id())); if !body.should_skip() { + let validate = validate_each & tcx.sess.opts.unstable_opts.validate_mir; + let lint = tcx.sess.opts.unstable_opts.lint_mir; + for pass in passes { let name = pass.name(); @@ -162,7 +163,12 @@ fn run_passes_inner<'tcx>( body.pass_count = 0; dump_mir_for_phase_change(tcx, body); - if validate || new_phase == MirPhase::Runtime(RuntimePhase::Optimized) { + + let validate = + (validate_each & tcx.sess.opts.unstable_opts.validate_mir & !body.should_skip()) + || new_phase == MirPhase::Runtime(RuntimePhase::Optimized); + let lint = tcx.sess.opts.unstable_opts.lint_mir & !body.should_skip(); + if validate { validate_body(tcx, body, format!("after phase change to {}", new_phase.name())); } if lint { diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 89508c77639aa..bff4f027a8704 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -125,21 +125,6 @@ pub enum LtoCli { Unspecified, } -/// The different settings that the `-Z dump_mir_spanview` flag can have. `Statement` generates a -/// document highlighting each span of every statement (including terminators). `Terminator` and -/// `Block` highlight a single span per `BasicBlock`: the span of the block's `Terminator`, or a -/// computed span for the block, representing the entire range, covering the block's terminator and -/// all of its statements. -#[derive(Clone, Copy, PartialEq, Hash, Debug)] -pub enum MirSpanview { - /// Default `-Z dump_mir_spanview` or `-Z dump_mir_spanview=statement` - Statement, - /// `-Z dump_mir_spanview=terminator` - Terminator, - /// `-Z dump_mir_spanview=block` - Block, -} - /// The different settings that the `-C instrument-coverage` flag can have. /// /// Coverage instrumentation now supports combining `-C instrument-coverage` @@ -1162,7 +1147,6 @@ impl UnstableOptions { can_emit_warnings, treat_err_as_bug: self.treat_err_as_bug, dont_buffer_diagnostics: self.dont_buffer_diagnostics, - report_delayed_bugs: self.report_delayed_bugs, macro_backtrace: self.macro_backtrace, deduplicate_diagnostics: self.deduplicate_diagnostics, track_diagnostics: self.track_diagnostics, diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 8274fd05bc057..3a095093583f8 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -391,7 +391,6 @@ mod desc { pub const parse_strip: &str = "either `none`, `debuginfo`, or `symbols`"; pub const parse_linker_flavor: &str = ::rustc_target::spec::LinkerFlavorCli::one_of(); pub const parse_optimization_fuel: &str = "crate=integer"; - pub const parse_mir_spanview: &str = "`statement` (default), `terminator`, or `block`"; pub const parse_dump_mono_stats: &str = "`markdown` (default) or `json`"; pub const parse_instrument_coverage: &str = "`all` (default), `branch`, `except-unused-generics`, `except-unused-functions`, or `off`"; @@ -866,29 +865,6 @@ mod parse { } } - pub(crate) fn parse_mir_spanview(slot: &mut Option, v: Option<&str>) -> bool { - if v.is_some() { - let mut bool_arg = None; - if parse_opt_bool(&mut bool_arg, v) { - *slot = bool_arg.unwrap().then_some(MirSpanview::Statement); - return true; - } - } - - let Some(v) = v else { - *slot = Some(MirSpanview::Statement); - return true; - }; - - *slot = Some(match v.trim_end_matches('s') { - "statement" | "stmt" => MirSpanview::Statement, - "terminator" | "term" => MirSpanview::Terminator, - "block" | "basicblock" => MirSpanview::Block, - _ => return false, - }); - true - } - pub(crate) fn parse_time_passes_format(slot: &mut TimePassesFormat, v: Option<&str>) -> bool { match v { None => true, @@ -1601,11 +1577,6 @@ options! { "exclude the pass number when dumping MIR (used in tests) (default: no)"), dump_mir_graphviz: bool = (false, parse_bool, [UNTRACKED], "in addition to `.mir` files, create graphviz `.dot` files (default: no)"), - dump_mir_spanview: Option = (None, parse_mir_spanview, [UNTRACKED], - "in addition to `.mir` files, create `.html` files to view spans for \ - all `statement`s (including terminators), only `terminator` spans, or \ - computed `block` spans (one span encompassing a block's terminator and \ - all statements)."), dump_mono_stats: SwitchWithOptPath = (SwitchWithOptPath::Disabled, parse_switch_with_opt_path, [UNTRACKED], "output statistics about monomorphization collection"), @@ -1841,8 +1812,6 @@ options! { remark_dir: Option = (None, parse_opt_pathbuf, [UNTRACKED], "directory into which to write optimization remarks (if not specified, they will be \ written to standard error output)"), - report_delayed_bugs: bool = (false, parse_bool, [TRACKED], - "immediately print bugs registered with `span_delayed_bug` (default: no)"), sanitizer: SanitizerSet = (SanitizerSet::empty(), parse_sanitizers, [TRACKED], "use a sanitizer"), sanitizer_cfi_canonical_jump_tables: Option = (Some(true), parse_opt_bool, [TRACKED], diff --git a/library/panic_unwind/src/seh.rs b/library/panic_unwind/src/seh.rs index 99db00e549066..ccae406cc286c 100644 --- a/library/panic_unwind/src/seh.rs +++ b/library/panic_unwind/src/seh.rs @@ -261,6 +261,8 @@ cfg_if::cfg_if! { } } +// FIXME: Use `SyncUnsafeCell` instead of allowing `static_mut_ref` lint +#[cfg_attr(not(bootstrap), allow(static_mut_ref))] pub unsafe fn panic(data: Box) -> u32 { use core::intrinsics::atomic_store_seqcst; @@ -322,6 +324,8 @@ pub unsafe fn panic(data: Box) -> 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 { // A null payload here means that we got here from the catch (...) of // __rust_try. This happens when a non-Rust foreign exception is caught. diff --git a/library/std/src/sys/common/thread_local/fast_local.rs b/library/std/src/sys/common/thread_local/fast_local.rs index c0a9619bf7bfa..9206588be064e 100644 --- a/library/std/src/sys/common/thread_local/fast_local.rs +++ b/library/std/src/sys/common/thread_local/fast_local.rs @@ -13,6 +13,8 @@ pub macro thread_local_inner { (@key $t:ty, const $init:expr) => {{ #[inline] #[deny(unsafe_op_in_unsafe_fn)] + // FIXME: Use `SyncUnsafeCell` instead of allowing `static_mut_ref` lint + #[cfg_attr(not(bootstrap), allow(static_mut_ref))] unsafe fn __getit( _init: $crate::option::Option<&mut $crate::option::Option<$t>>, ) -> $crate::option::Option<&'static $t> { diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index 0d8213f048d94..33a678a31d6a3 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -151,7 +151,6 @@ target | std | notes `i586-pc-windows-msvc` | * | 32-bit Windows w/o SSE [^x86_32-floats-x87] `i586-unknown-linux-gnu` | ✓ | 32-bit Linux w/o SSE (kernel 3.2, glibc 2.17) [^x86_32-floats-x87] `i586-unknown-linux-musl` | ✓ | 32-bit Linux w/o SSE, MUSL [^x86_32-floats-x87] -[`i586-unknown-netbsd`](platform-support/netbsd.md) | ✓ | 32-bit x86, restricted to Pentium [`i686-linux-android`](platform-support/android.md) | ✓ | 32-bit x86 Android [^x86_32-floats-return-ABI] `i686-unknown-freebsd` | ✓ | 32-bit FreeBSD [^x86_32-floats-return-ABI] `i686-unknown-linux-musl` | ✓ | 32-bit Linux with MUSL [^x86_32-floats-return-ABI] @@ -272,6 +271,7 @@ target | std | host | notes `hexagon-unknown-linux-musl` | ? | | `i386-apple-ios` | ✓ | | 32-bit x86 iOS [^x86_32-floats-return-ABI] [`i586-pc-nto-qnx700`](platform-support/nto-qnx.md) | * | | 32-bit x86 QNX Neutrino 7.0 RTOS [^x86_32-floats-return-ABI] +[`i586-unknown-netbsd`](platform-support/netbsd.md) | ✓ | | 32-bit x86, restricted to Pentium `i686-apple-darwin` | ✓ | ✓ | 32-bit macOS (10.12+, Sierra+) [^x86_32-floats-return-ABI] `i686-pc-windows-msvc` | * | | 32-bit Windows XP support [^x86_32-floats-return-ABI] [`i686-pc-windows-gnullvm`](platform-support/pc-windows-gnullvm.md) | ✓ | ✓ | [^x86_32-floats-return-ABI] diff --git a/src/librustdoc/html/render/span_map.rs b/src/librustdoc/html/render/span_map.rs index d1ece73374dc3..b055e355b788a 100644 --- a/src/librustdoc/html/render/span_map.rs +++ b/src/librustdoc/html/render/span_map.rs @@ -154,6 +154,28 @@ impl<'tcx> SpanMapVisitor<'tcx> { self.matches.insert(new_span, link_from_src); true } + + fn handle_call(&mut self, hir_id: HirId, expr_hir_id: Option, span: Span) { + let hir = self.tcx.hir(); + let body_id = hir.enclosing_body_owner(hir_id); + // FIXME: this is showing error messages for parts of the code that are not + // compiled (because of cfg)! + // + // See discussion in https://github.com/rust-lang/rust/issues/69426#issuecomment-1019412352 + let typeck_results = self + .tcx + .typeck_body(hir.maybe_body_owned_by(body_id).expect("a body which isn't a body")); + // Interestingly enough, for method calls, we need the whole expression whereas for static + // method/function calls, we need the call expression specifically. + if let Some(def_id) = typeck_results.type_dependent_def_id(expr_hir_id.unwrap_or(hir_id)) { + let link = if def_id.as_local().is_some() { + LinkFromSrc::Local(rustc_span(def_id, self.tcx)) + } else { + LinkFromSrc::External(def_id) + }; + self.matches.insert(span, link); + } + } } impl<'tcx> Visitor<'tcx> for SpanMapVisitor<'tcx> { @@ -191,27 +213,17 @@ impl<'tcx> Visitor<'tcx> for SpanMapVisitor<'tcx> { } fn visit_expr(&mut self, expr: &'tcx rustc_hir::Expr<'tcx>) { - if let ExprKind::MethodCall(segment, ..) = expr.kind { - let hir = self.tcx.hir(); - let body_id = hir.enclosing_body_owner(segment.hir_id); - // FIXME: this is showing error messages for parts of the code that are not - // compiled (because of cfg)! - // - // See discussion in https://github.com/rust-lang/rust/issues/69426#issuecomment-1019412352 - let typeck_results = self - .tcx - .typeck_body(hir.maybe_body_owned_by(body_id).expect("a body which isn't a body")); - if let Some(def_id) = typeck_results.type_dependent_def_id(expr.hir_id) { - let link = if def_id.as_local().is_some() { - LinkFromSrc::Local(rustc_span(def_id, self.tcx)) - } else { - LinkFromSrc::External(def_id) - }; - self.matches.insert(segment.ident.span, link); + match expr.kind { + ExprKind::MethodCall(segment, ..) => { + self.handle_call(segment.hir_id, Some(expr.hir_id), segment.ident.span) + } + ExprKind::Call(call, ..) => self.handle_call(call.hir_id, None, call.span), + _ => { + if self.handle_macro(expr.span) { + // We don't want to go deeper into the macro. + return; + } } - } else if self.handle_macro(expr.span) { - // We don't want to go deeper into the macro. - return; } intravisit::walk_expr(self, expr); } diff --git a/src/tools/lint-docs/src/groups.rs b/src/tools/lint-docs/src/groups.rs index 5be8ef7996bb2..c5cd30ccc3437 100644 --- a/src/tools/lint-docs/src/groups.rs +++ b/src/tools/lint-docs/src/groups.rs @@ -15,6 +15,7 @@ static GROUP_DESCRIPTIONS: &[(&str, &str)] = &[ ("future-incompatible", "Lints that detect code that has future-compatibility problems"), ("rust-2018-compatibility", "Lints used to transition code from the 2015 edition to 2018"), ("rust-2021-compatibility", "Lints used to transition code from the 2018 edition to 2021"), + ("rust-2024-compatibility", "Lints used to transition code from the 2021 edition to 2024"), ]; type LintGroups = BTreeMap>; diff --git a/src/tools/miri/tests/fail/tls/tls_static_dealloc.rs b/src/tools/miri/tests/fail/tls/tls_static_dealloc.rs index d5e6d37226ab3..762a8d85314f2 100644 --- a/src/tools/miri/tests/fail/tls/tls_static_dealloc.rs +++ b/src/tools/miri/tests/fail/tls/tls_static_dealloc.rs @@ -1,6 +1,8 @@ //! Ensure that thread-local statics get deallocated when the thread dies. #![feature(thread_local)] +// FIXME: Use `SyncUnsafeCell` instead of allowing `static_mut_ref` lint +#![allow(static_mut_ref)] #[thread_local] static mut TLS: u8 = 0; diff --git a/src/tools/miri/tests/pass/static_mut.rs b/src/tools/miri/tests/pass/static_mut.rs index 218b02525bd55..c1e58b70adb0b 100644 --- a/src/tools/miri/tests/pass/static_mut.rs +++ b/src/tools/miri/tests/pass/static_mut.rs @@ -1,4 +1,7 @@ static mut FOO: i32 = 42; + +// FIXME: Use `SyncUnsafeCell` instead of allowing `static_mut_ref` lint +#[allow(static_mut_ref)] static BAR: Foo = Foo(unsafe { &FOO as *const _ }); #[allow(dead_code)] diff --git a/src/tools/miri/tests/pass/tls/tls_static.rs b/src/tools/miri/tests/pass/tls/tls_static.rs index fc4c8a283ddb2..9be00af47aa35 100644 --- a/src/tools/miri/tests/pass/tls/tls_static.rs +++ b/src/tools/miri/tests/pass/tls/tls_static.rs @@ -8,6 +8,8 @@ //! test, we also check that thread-locals act as per-thread statics. #![feature(thread_local)] +// FIXME: Use `SyncUnsafeCell` instead of allowing `static_mut_ref` lint +#![allow(static_mut_ref)] use std::thread; diff --git a/tests/mir-opt/copy-prop/custom_move_arg.f.CopyProp.panic-unwind.diff b/tests/mir-opt/copy-prop/custom_move_arg.f.CopyProp.panic-unwind.diff index eb40183c1c954..7ba8530105179 100644 --- a/tests/mir-opt/copy-prop/custom_move_arg.f.CopyProp.panic-unwind.diff +++ b/tests/mir-opt/copy-prop/custom_move_arg.f.CopyProp.panic-unwind.diff @@ -8,14 +8,14 @@ bb0: { - _2 = _1; -- _0 = opaque::(move _1) -> [return: bb1, unwind continue]; -+ _0 = opaque::(_1) -> [return: bb1, unwind continue]; +- _0 = opaque::(move _1) -> [return: bb1, unwind unreachable]; ++ _0 = opaque::(_1) -> [return: bb1, unwind unreachable]; } bb1: { - _3 = move _2; -- _0 = opaque::(_3) -> [return: bb2, unwind continue]; -+ _0 = opaque::(_1) -> [return: bb2, unwind continue]; +- _0 = opaque::(_3) -> [return: bb2, unwind unreachable]; ++ _0 = opaque::(_1) -> [return: bb2, unwind unreachable]; } bb2: { diff --git a/tests/mir-opt/copy-prop/custom_move_arg.rs b/tests/mir-opt/copy-prop/custom_move_arg.rs index 45913626a8fe5..1ee294fcfd917 100644 --- a/tests/mir-opt/copy-prop/custom_move_arg.rs +++ b/tests/mir-opt/copy-prop/custom_move_arg.rs @@ -10,15 +10,15 @@ use core::intrinsics::mir::*; struct NotCopy(bool); // EMIT_MIR custom_move_arg.f.CopyProp.diff -#[custom_mir(dialect = "analysis", phase = "post-cleanup")] +#[custom_mir(dialect = "runtime")] fn f(_1: NotCopy) { mir!({ let _2 = _1; - Call(RET = opaque(Move(_1)), ReturnTo(bb1), UnwindContinue()) + Call(RET = opaque(Move(_1)), ReturnTo(bb1), UnwindUnreachable()) } bb1 = { let _3 = Move(_2); - Call(RET = opaque(_3), ReturnTo(bb2), UnwindContinue()) + Call(RET = opaque(_3), ReturnTo(bb2), UnwindUnreachable()) } bb2 = { Return() diff --git a/tests/mir-opt/copy-prop/move_projection.f.CopyProp.panic-unwind.diff b/tests/mir-opt/copy-prop/move_projection.f.CopyProp.panic-unwind.diff index ad3889639e0cf..b2b89968d70b0 100644 --- a/tests/mir-opt/copy-prop/move_projection.f.CopyProp.panic-unwind.diff +++ b/tests/mir-opt/copy-prop/move_projection.f.CopyProp.panic-unwind.diff @@ -9,13 +9,13 @@ bb0: { - _2 = _1; - _3 = move (_2.0: u8); -- _0 = opaque::(move _1) -> [return: bb1, unwind continue]; +- _0 = opaque::(move _1) -> [return: bb1, unwind unreachable]; + _3 = (_1.0: u8); -+ _0 = opaque::(_1) -> [return: bb1, unwind continue]; ++ _0 = opaque::(_1) -> [return: bb1, unwind unreachable]; } bb1: { - _0 = opaque::(move _3) -> [return: bb2, unwind continue]; + _0 = opaque::(move _3) -> [return: bb2, unwind unreachable]; } bb2: { diff --git a/tests/mir-opt/copy-prop/move_projection.rs b/tests/mir-opt/copy-prop/move_projection.rs index f02867814ac0a..f31e82c1f0302 100644 --- a/tests/mir-opt/copy-prop/move_projection.rs +++ b/tests/mir-opt/copy-prop/move_projection.rs @@ -11,17 +11,17 @@ fn opaque(_: impl Sized) -> bool { true } struct Foo(u8); -#[custom_mir(dialect = "analysis", phase = "post-cleanup")] +#[custom_mir(dialect = "runtime")] fn f(a: Foo) -> bool { mir!( { let b = a; // This is a move out of a copy, so must become a copy of `a.0`. let c = Move(b.0); - Call(RET = opaque(Move(a)), ReturnTo(bb1), UnwindContinue()) + Call(RET = opaque(Move(a)), ReturnTo(bb1), UnwindUnreachable()) } bb1 = { - Call(RET = opaque(Move(c)), ReturnTo(ret), UnwindContinue()) + Call(RET = opaque(Move(c)), ReturnTo(ret), UnwindUnreachable()) } ret = { Return() diff --git a/tests/mir-opt/dest-prop/unreachable.f.DestinationPropagation.panic-abort.diff b/tests/mir-opt/dest-prop/unreachable.f.DestinationPropagation.panic-abort.diff deleted file mode 100644 index 80b5681ad062c..0000000000000 --- a/tests/mir-opt/dest-prop/unreachable.f.DestinationPropagation.panic-abort.diff +++ /dev/null @@ -1,82 +0,0 @@ -- // MIR for `f` before DestinationPropagation -+ // MIR for `f` after DestinationPropagation - - fn f(_1: T) -> () { - debug a => _1; - let mut _0: (); - let _2: T; - let mut _3: bool; - let _4: (); - let mut _5: T; - let mut _6: T; - let _7: (); - let mut _8: T; - let mut _9: T; - scope 1 { -- debug b => _2; -+ debug b => _1; - } - - bb0: { -- StorageLive(_2); -- _2 = _1; -+ nop; -+ nop; - StorageLive(_3); - _3 = const false; -- goto -> bb3; -+ goto -> bb1; - } - - bb1: { -- StorageLive(_4); -- StorageLive(_5); -- _5 = _1; -- StorageLive(_6); -- _6 = _1; -- _4 = g::(_1, _1) -> [return: bb2, unwind unreachable]; -- } -- -- bb2: { -- StorageDead(_6); -- StorageDead(_5); -- StorageDead(_4); -- _0 = const (); -- goto -> bb5; -- } -- -- bb3: { - StorageLive(_7); -- StorageLive(_8); -- _8 = _1; -- StorageLive(_9); -- _9 = _1; -- _7 = g::(_1, _1) -> [return: bb4, unwind unreachable]; -+ nop; -+ nop; -+ nop; -+ nop; -+ _7 = g::(_1, _1) -> [return: bb2, unwind unreachable]; - } - -- bb4: { -- StorageDead(_9); -- StorageDead(_8); -+ bb2: { -+ nop; -+ nop; - StorageDead(_7); - _0 = const (); -- goto -> bb5; -+ goto -> bb3; - } - -- bb5: { -+ bb3: { - StorageDead(_3); -- StorageDead(_2); -+ nop; - return; - } - } - diff --git a/tests/mir-opt/dest-prop/unreachable.f.DestinationPropagation.panic-unwind.diff b/tests/mir-opt/dest-prop/unreachable.f.DestinationPropagation.panic-unwind.diff deleted file mode 100644 index eae7dd17b4882..0000000000000 --- a/tests/mir-opt/dest-prop/unreachable.f.DestinationPropagation.panic-unwind.diff +++ /dev/null @@ -1,82 +0,0 @@ -- // MIR for `f` before DestinationPropagation -+ // MIR for `f` after DestinationPropagation - - fn f(_1: T) -> () { - debug a => _1; - let mut _0: (); - let _2: T; - let mut _3: bool; - let _4: (); - let mut _5: T; - let mut _6: T; - let _7: (); - let mut _8: T; - let mut _9: T; - scope 1 { -- debug b => _2; -+ debug b => _1; - } - - bb0: { -- StorageLive(_2); -- _2 = _1; -+ nop; -+ nop; - StorageLive(_3); - _3 = const false; -- goto -> bb3; -+ goto -> bb1; - } - - bb1: { -- StorageLive(_4); -- StorageLive(_5); -- _5 = _1; -- StorageLive(_6); -- _6 = _1; -- _4 = g::(_1, _1) -> [return: bb2, unwind continue]; -- } -- -- bb2: { -- StorageDead(_6); -- StorageDead(_5); -- StorageDead(_4); -- _0 = const (); -- goto -> bb5; -- } -- -- bb3: { - StorageLive(_7); -- StorageLive(_8); -- _8 = _1; -- StorageLive(_9); -- _9 = _1; -- _7 = g::(_1, _1) -> [return: bb4, unwind continue]; -+ nop; -+ nop; -+ nop; -+ nop; -+ _7 = g::(_1, _1) -> [return: bb2, unwind continue]; - } - -- bb4: { -- StorageDead(_9); -- StorageDead(_8); -+ bb2: { -+ nop; -+ nop; - StorageDead(_7); - _0 = const (); -- goto -> bb5; -+ goto -> bb3; - } - -- bb5: { -+ bb3: { - StorageDead(_3); -- StorageDead(_2); -+ nop; - return; - } - } - diff --git a/tests/mir-opt/dest-prop/unreachable.rs b/tests/mir-opt/dest-prop/unreachable.rs deleted file mode 100644 index 0bde157ff6185..0000000000000 --- a/tests/mir-opt/dest-prop/unreachable.rs +++ /dev/null @@ -1,20 +0,0 @@ -// skip-filecheck -// EMIT_MIR_FOR_EACH_PANIC_STRATEGY -// Check that unreachable code is removed after the destination propagation. -// Regression test for issue #105428. -// -// compile-flags: --crate-type=lib -Zmir-opt-level=0 -// compile-flags: -Zmir-enable-passes=+GVN,+SimplifyConstCondition-after-const-prop,+DestinationPropagation - -// EMIT_MIR unreachable.f.DestinationPropagation.diff -pub fn f(a: T) { - let b = a; - if false { - g(a, b); - } else { - g(b, b); - } -} - -#[inline(never)] -pub fn g(_: T, _: T) {} diff --git a/tests/mir-opt/spanview_block.main.built.after.html b/tests/mir-opt/spanview_block.main.built.after.html deleted file mode 100644 index 54ef00f56f3b8..0000000000000 --- a/tests/mir-opt/spanview_block.main.built.after.html +++ /dev/null @@ -1,67 +0,0 @@ - - - - -spanview_block.main.built.after - - - -
fn main() 0⦊{}⦉0
- - diff --git a/tests/mir-opt/spanview_block.rs b/tests/mir-opt/spanview_block.rs deleted file mode 100644 index e8bc3d16348a2..0000000000000 --- a/tests/mir-opt/spanview_block.rs +++ /dev/null @@ -1,6 +0,0 @@ -// skip-filecheck -// Test spanview block output -// compile-flags: -Z dump-mir-spanview=block - -// EMIT_MIR spanview_block.main.built.after.html -fn main() {} diff --git a/tests/mir-opt/spanview_statement.main.built.after.html b/tests/mir-opt/spanview_statement.main.built.after.html deleted file mode 100644 index 5e782b05f3b79..0000000000000 --- a/tests/mir-opt/spanview_statement.main.built.after.html +++ /dev/null @@ -1,67 +0,0 @@ - - - - -spanview_statement.main.built.after - - - -
fn main() 0[0]⦊{}⦉0[0]0:Return⦊‸⦉0:Return
- - diff --git a/tests/mir-opt/spanview_statement.rs b/tests/mir-opt/spanview_statement.rs deleted file mode 100644 index d547e6cb1e0b0..0000000000000 --- a/tests/mir-opt/spanview_statement.rs +++ /dev/null @@ -1,6 +0,0 @@ -// skip-filecheck -// Test spanview output (the default value for `-Z dump-mir-spanview` is "statement") -// compile-flags: -Z dump-mir-spanview - -// EMIT_MIR spanview_statement.main.built.after.html -fn main() {} diff --git a/tests/mir-opt/spanview_terminator.main.built.after.html b/tests/mir-opt/spanview_terminator.main.built.after.html deleted file mode 100644 index 2a651489e235f..0000000000000 --- a/tests/mir-opt/spanview_terminator.main.built.after.html +++ /dev/null @@ -1,66 +0,0 @@ - - - - -spanview_terminator.main.built.after - - - -
fn main() {}0:Return⦊‸⦉0:Return
- - diff --git a/tests/mir-opt/spanview_terminator.rs b/tests/mir-opt/spanview_terminator.rs deleted file mode 100644 index a2c68b98ef55b..0000000000000 --- a/tests/mir-opt/spanview_terminator.rs +++ /dev/null @@ -1,6 +0,0 @@ -// skip-filecheck -// Test spanview terminator output -// compile-flags: -Z dump-mir-spanview=terminator - -// EMIT_MIR spanview_terminator.main.built.after.html -fn main() {} diff --git a/tests/rustdoc/check-source-code-urls-to-def.rs b/tests/rustdoc/check-source-code-urls-to-def.rs index b803c7e9e86c7..c31c579030e0d 100644 --- a/tests/rustdoc/check-source-code-urls-to-def.rs +++ b/tests/rustdoc/check-source-code-urls-to-def.rs @@ -62,7 +62,7 @@ pub trait AnotherTrait2 {} // @has - '//pre[@class="rust"]//a[@href="#61"]' 'AnotherTrait2' pub fn foo4() { - let x: Vec = Vec::new(); + let x: Vec<&dyn AnotherTrait2> = Vec::new(); } // @has - '//pre[@class="rust"]//a[@href="../../foo/primitive.bool.html"]' 'bool' diff --git a/tests/rustdoc/jump-to-def-doc-links-calls.rs b/tests/rustdoc/jump-to-def-doc-links-calls.rs new file mode 100644 index 0000000000000..549d068528e25 --- /dev/null +++ b/tests/rustdoc/jump-to-def-doc-links-calls.rs @@ -0,0 +1,27 @@ +// compile-flags: -Zunstable-options --generate-link-to-definition + +#![crate_name = "foo"] + +// @has 'src/foo/jump-to-def-doc-links-calls.rs.html' + +// @has - '//a[@href="../../foo/struct.Bar.html"]' 'Bar' +pub struct Bar; + +impl std::default::Default for Bar { + // @has - '//a[@href="#20-22"]' 'Self::new' + fn default() -> Self { + Self::new() + } +} + +// @has - '//a[@href="#8"]' 'Bar' +impl Bar { + // @has - '//a[@href="#24-26"]' 'Self::bar' + pub fn new()-> Self { + Self::bar() + } + + pub fn bar() -> Self { + Self + } +} diff --git a/tests/ui/abi/statics/static-mut-foreign.rs b/tests/ui/abi/statics/static-mut-foreign.rs index ecd8ee94a01e3..eb732e7c2c31f 100644 --- a/tests/ui/abi/statics/static-mut-foreign.rs +++ b/tests/ui/abi/statics/static-mut-foreign.rs @@ -33,7 +33,9 @@ unsafe fn run() { rust_dbg_static_mut = -3; assert_eq!(rust_dbg_static_mut, -3); static_bound(&rust_dbg_static_mut); + //~^ WARN shared reference of mutable static is discouraged [static_mut_ref] static_bound_set(&mut rust_dbg_static_mut); + //~^ WARN mutable reference of mutable static is discouraged [static_mut_ref] } pub fn main() { diff --git a/tests/ui/abi/statics/static-mut-foreign.stderr b/tests/ui/abi/statics/static-mut-foreign.stderr new file mode 100644 index 0000000000000..144ac056f87e4 --- /dev/null +++ b/tests/ui/abi/statics/static-mut-foreign.stderr @@ -0,0 +1,31 @@ +warning: shared reference of mutable static is discouraged + --> $DIR/static-mut-foreign.rs:35:18 + | +LL | static_bound(&rust_dbg_static_mut); + | ^^^^^^^^^^^^^^^^^^^^ shared reference of mutable static + | + = note: for more information, see issue #114447 + = 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 + = note: reference of mutable static is a hard error from 2024 edition + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior +help: mutable references are dangerous since if there's any other pointer or reference used for that static while the reference lives, that's UB; use `addr_of_mut!` instead to create a raw pointer + | +LL | static_bound_set(addr_of_mut!(rust_dbg_static_mut)); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +warning: 2 warnings emitted + diff --git a/tests/ui/borrowck/borrowck-access-permissions.rs b/tests/ui/borrowck/borrowck-access-permissions.rs index 469ad508b0e77..1638644103ba4 100644 --- a/tests/ui/borrowck/borrowck-access-permissions.rs +++ b/tests/ui/borrowck/borrowck-access-permissions.rs @@ -1,21 +1,27 @@ -static static_x : i32 = 1; -static mut static_x_mut : i32 = 1; +static static_x: i32 = 1; +static mut static_x_mut: i32 = 1; fn main() { let x = 1; let mut x_mut = 1; - { // borrow of local + { + // borrow of local let _y1 = &mut x; //~ ERROR [E0596] let _y2 = &mut x_mut; // No error } - { // borrow of static + { + // borrow of static let _y1 = &mut static_x; //~ ERROR [E0596] - unsafe { let _y2 = &mut static_x_mut; } // No error + unsafe { + let _y2 = &mut static_x_mut; + //~^ WARN mutable reference of mutable static is discouraged [static_mut_ref] + } } - { // borrow of deref to box + { + // borrow of deref to box let box_x = Box::new(1); let mut box_x_mut = Box::new(1); @@ -23,7 +29,8 @@ fn main() { let _y2 = &mut *box_x_mut; // No error } - { // borrow of deref to reference + { + // borrow of deref to reference let ref_x = &x; let ref_x_mut = &mut x_mut; @@ -31,9 +38,10 @@ fn main() { let _y2 = &mut *ref_x_mut; // No error } - { // borrow of deref to pointer - let ptr_x : *const _ = &x; - let ptr_mut_x : *mut _ = &mut x_mut; + { + // borrow of deref to pointer + let ptr_x: *const _ = &x; + let ptr_mut_x: *mut _ = &mut x_mut; unsafe { let _y1 = &mut *ptr_x; //~ ERROR [E0596] @@ -41,8 +49,12 @@ fn main() { } } - { // borrowing mutably through an immutable reference - struct Foo<'a> { f: &'a mut i32, g: &'a i32 }; + { + // borrowing mutably through an immutable reference + struct Foo<'a> { + f: &'a mut i32, + g: &'a i32, + }; let mut foo = Foo { f: &mut x_mut, g: &x }; let foo_ref = &foo; let _y = &mut *foo_ref.f; //~ ERROR [E0596] diff --git a/tests/ui/borrowck/borrowck-access-permissions.stderr b/tests/ui/borrowck/borrowck-access-permissions.stderr index c161e2d95b43a..93d92295dd9b6 100644 --- a/tests/ui/borrowck/borrowck-access-permissions.stderr +++ b/tests/ui/borrowck/borrowck-access-permissions.stderr @@ -1,5 +1,20 @@ +warning: mutable reference of mutable static is discouraged + --> $DIR/borrowck-access-permissions.rs:18:23 + | +LL | let _y2 = &mut static_x_mut; + | ^^^^^^^^^^^^^^^^^ mutable reference of mutable static + | + = note: for more information, see issue #114447 + = note: reference of mutable static is a hard error from 2024 edition + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior + = note: `#[warn(static_mut_ref)]` on by default +help: mutable references are dangerous since if there's any other pointer or reference used for that static while the reference lives, that's UB; use `addr_of_mut!` instead to create a raw pointer + | +LL | let _y2 = addr_of_mut!(static_x_mut); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~ + error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable - --> $DIR/borrowck-access-permissions.rs:9:19 + --> $DIR/borrowck-access-permissions.rs:10:19 | LL | let _y1 = &mut x; | ^^^^^^ cannot borrow as mutable @@ -10,13 +25,13 @@ LL | let mut x = 1; | +++ error[E0596]: cannot borrow immutable static item `static_x` as mutable - --> $DIR/borrowck-access-permissions.rs:14:19 + --> $DIR/borrowck-access-permissions.rs:16:19 | LL | let _y1 = &mut static_x; | ^^^^^^^^^^^^^ cannot borrow as mutable error[E0596]: cannot borrow `*box_x` as mutable, as `box_x` is not declared as mutable - --> $DIR/borrowck-access-permissions.rs:22:19 + --> $DIR/borrowck-access-permissions.rs:28:19 | LL | let _y1 = &mut *box_x; | ^^^^^^^^^^^ cannot borrow as mutable @@ -27,7 +42,7 @@ LL | let mut box_x = Box::new(1); | +++ error[E0596]: cannot borrow `*ref_x` as mutable, as it is behind a `&` reference - --> $DIR/borrowck-access-permissions.rs:30:19 + --> $DIR/borrowck-access-permissions.rs:37:19 | LL | let _y1 = &mut *ref_x; | ^^^^^^^^^^^ `ref_x` is a `&` reference, so the data it refers to cannot be borrowed as mutable @@ -38,18 +53,18 @@ LL | let ref_x = &mut x; | +++ error[E0596]: cannot borrow `*ptr_x` as mutable, as it is behind a `*const` pointer - --> $DIR/borrowck-access-permissions.rs:39:23 + --> $DIR/borrowck-access-permissions.rs:47:23 | LL | let _y1 = &mut *ptr_x; | ^^^^^^^^^^^ `ptr_x` is a `*const` pointer, so the data it refers to cannot be borrowed as mutable | help: consider changing this to be a mutable pointer | -LL | let ptr_x : *const _ = &mut x; - | +++ +LL | let ptr_x: *const _ = &mut x; + | +++ error[E0596]: cannot borrow `*foo_ref.f` as mutable, as it is behind a `&` reference - --> $DIR/borrowck-access-permissions.rs:48:18 + --> $DIR/borrowck-access-permissions.rs:60:18 | LL | let _y = &mut *foo_ref.f; | ^^^^^^^^^^^^^^^ `foo_ref` is a `&` reference, so the data it refers to cannot be borrowed as mutable @@ -59,6 +74,6 @@ help: consider changing this to be a mutable reference LL | let foo_ref = &mut foo; | +++ -error: aborting due to 6 previous errors +error: aborting due to 6 previous errors; 1 warning emitted For more information about this error, try `rustc --explain E0596`. diff --git a/tests/ui/borrowck/borrowck-unsafe-static-mutable-borrows.rs b/tests/ui/borrowck/borrowck-unsafe-static-mutable-borrows.rs index adc7dfd541f48..1bf079e24cae4 100644 --- a/tests/ui/borrowck/borrowck-unsafe-static-mutable-borrows.rs +++ b/tests/ui/borrowck/borrowck-unsafe-static-mutable-borrows.rs @@ -2,17 +2,22 @@ // Test file taken from issue 45129 (https://github.com/rust-lang/rust/issues/45129) -struct Foo { x: [usize; 2] } +struct Foo { + x: [usize; 2], +} static mut SFOO: Foo = Foo { x: [23, 32] }; impl Foo { - fn x(&mut self) -> &mut usize { &mut self.x[0] } + fn x(&mut self) -> &mut usize { + &mut self.x[0] + } } fn main() { unsafe { let sfoo: *mut Foo = &mut SFOO; + //~^ WARN mutable reference of mutable static is discouraged [static_mut_ref] let x = (*sfoo).x(); (*sfoo).x[1] += 1; *x += 1; diff --git a/tests/ui/borrowck/borrowck-unsafe-static-mutable-borrows.stderr b/tests/ui/borrowck/borrowck-unsafe-static-mutable-borrows.stderr new file mode 100644 index 0000000000000..7a3824f79a4c2 --- /dev/null +++ b/tests/ui/borrowck/borrowck-unsafe-static-mutable-borrows.stderr @@ -0,0 +1,17 @@ +warning: mutable reference of mutable static is discouraged + --> $DIR/borrowck-unsafe-static-mutable-borrows.rs:19:30 + | +LL | let sfoo: *mut Foo = &mut SFOO; + | ^^^^^^^^^ mutable reference of mutable static + | + = note: for more information, see issue #114447 + = note: reference of mutable static is a hard error from 2024 edition + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior + = note: `#[warn(static_mut_ref)]` on by default +help: mutable references are dangerous since if there's any other pointer or reference used for that static while the reference lives, that's UB; use `addr_of_mut!` instead to create a raw pointer + | +LL | let sfoo: *mut Foo = addr_of_mut!(SFOO); + | ~~~~~~~~~~~~~~~~~~ + +warning: 1 warning emitted + diff --git a/tests/ui/borrowck/issue-20801.rs b/tests/ui/borrowck/issue-20801.rs index c3f136f2876b6..ec83af5d5dfc6 100644 --- a/tests/ui/borrowck/issue-20801.rs +++ b/tests/ui/borrowck/issue-20801.rs @@ -12,6 +12,7 @@ fn imm_ref() -> &'static T { fn mut_ref() -> &'static mut T { unsafe { &mut GLOBAL_MUT_T } + //~^ WARN mutable reference of mutable static is discouraged [static_mut_ref] } fn mut_ptr() -> *mut T { diff --git a/tests/ui/borrowck/issue-20801.stderr b/tests/ui/borrowck/issue-20801.stderr index 215bf01006369..b2bee2d880394 100644 --- a/tests/ui/borrowck/issue-20801.stderr +++ b/tests/ui/borrowck/issue-20801.stderr @@ -1,5 +1,20 @@ +warning: mutable reference of mutable static is discouraged + --> $DIR/issue-20801.rs:14:14 + | +LL | unsafe { &mut GLOBAL_MUT_T } + | ^^^^^^^^^^^^^^^^^ mutable reference of mutable static + | + = note: for more information, see issue #114447 + = note: reference of mutable static is a hard error from 2024 edition + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior + = note: `#[warn(static_mut_ref)]` on by default +help: mutable references are dangerous since if there's any other pointer or reference used for that static while the reference lives, that's UB; use `addr_of_mut!` instead to create a raw pointer + | +LL | unsafe { addr_of_mut!(GLOBAL_MUT_T) } + | ~~~~~~~~~~~~~~~~~~~~~~~~~~ + error[E0507]: cannot move out of a mutable reference - --> $DIR/issue-20801.rs:26:22 + --> $DIR/issue-20801.rs:27:22 | LL | let a = unsafe { *mut_ref() }; | ^^^^^^^^^^ move occurs because value has type `T`, which does not implement the `Copy` trait @@ -11,7 +26,7 @@ LL + let a = unsafe { mut_ref() }; | error[E0507]: cannot move out of a shared reference - --> $DIR/issue-20801.rs:29:22 + --> $DIR/issue-20801.rs:30:22 | LL | let b = unsafe { *imm_ref() }; | ^^^^^^^^^^ move occurs because value has type `T`, which does not implement the `Copy` trait @@ -23,7 +38,7 @@ LL + let b = unsafe { imm_ref() }; | error[E0507]: cannot move out of a raw pointer - --> $DIR/issue-20801.rs:32:22 + --> $DIR/issue-20801.rs:33:22 | LL | let c = unsafe { *mut_ptr() }; | ^^^^^^^^^^ move occurs because value has type `T`, which does not implement the `Copy` trait @@ -35,7 +50,7 @@ LL + let c = unsafe { mut_ptr() }; | error[E0507]: cannot move out of a raw pointer - --> $DIR/issue-20801.rs:35:22 + --> $DIR/issue-20801.rs:36:22 | LL | let d = unsafe { *const_ptr() }; | ^^^^^^^^^^^^ move occurs because value has type `T`, which does not implement the `Copy` trait @@ -46,6 +61,6 @@ LL - let d = unsafe { *const_ptr() }; LL + let d = unsafe { const_ptr() }; | -error: aborting due to 4 previous errors +error: aborting due to 4 previous errors; 1 warning emitted For more information about this error, try `rustc --explain E0507`. diff --git a/tests/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.rs b/tests/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.rs index b3cce1b3a0611..9b172b4131911 100644 --- a/tests/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.rs +++ b/tests/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.rs @@ -8,7 +8,10 @@ mod borrowck_closures_unique { static mut Y: isize = 3; let mut c1 = |y: &'static mut isize| x = y; //~^ ERROR is not declared as mutable - unsafe { c1(&mut Y); } + unsafe { + c1(&mut Y); + //~^ WARN mutable reference of mutable static is discouraged [static_mut_ref] + } } } @@ -17,36 +20,50 @@ mod borrowck_closures_unique_grandparent { static mut Z: isize = 3; let mut c1 = |z: &'static mut isize| { let mut c2 = |y: &'static mut isize| x = y; - //~^ ERROR is not declared as mutable + //~^ ERROR is not declared as mutable c2(z); }; - unsafe { c1(&mut Z); } + unsafe { + c1(&mut Z); + //~^ WARN mutable reference of mutable static is discouraged [static_mut_ref] + } } } // adapted from mutability_errors.rs mod mutability_errors { pub fn capture_assign_whole(x: (i32,)) { - || { x = (1,); }; - //~^ ERROR is not declared as mutable + || { + x = (1,); + //~^ ERROR is not declared as mutable + }; } pub fn capture_assign_part(x: (i32,)) { - || { x.0 = 1; }; - //~^ ERROR is not declared as mutable + || { + x.0 = 1; + //~^ ERROR is not declared as mutable + }; } pub fn capture_reborrow_whole(x: (i32,)) { - || { &mut x; }; - //~^ ERROR is not declared as mutable + || { + &mut x; + //~^ ERROR is not declared as mutable + }; } pub fn capture_reborrow_part(x: (i32,)) { - || { &mut x.0; }; - //~^ ERROR is not declared as mutable + || { + &mut x.0; + //~^ ERROR is not declared as mutable + }; } } fn main() { static mut X: isize = 2; - unsafe { borrowck_closures_unique::e(&mut X); } + unsafe { + borrowck_closures_unique::e(&mut X); + //~^ WARN mutable reference of mutable static is discouraged [static_mut_ref] + } mutability_errors::capture_assign_whole((1000,)); mutability_errors::capture_assign_part((2000,)); diff --git a/tests/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.stderr b/tests/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.stderr index 4c299cdc455ac..e4e4947fce1c1 100644 --- a/tests/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.stderr +++ b/tests/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.stderr @@ -1,3 +1,46 @@ +warning: mutable reference of mutable static is discouraged + --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:12:16 + | +LL | c1(&mut Y); + | ^^^^^^ mutable reference of mutable static + | + = note: for more information, see issue #114447 + = 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 + = 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 + = note: reference of mutable static is a hard error from 2024 edition + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior +help: mutable references are dangerous since if there's any other pointer or reference used for that static while the reference lives, that's UB; use `addr_of_mut!` instead to create a raw pointer + | +LL | borrowck_closures_unique::e(addr_of_mut!(X)); + | ~~~~~~~~~~~~~~~ + error[E0594]: cannot assign to `x`, as it is not declared as mutable --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:9:46 | @@ -8,7 +51,7 @@ LL | let mut c1 = |y: &'static mut isize| x = y; | ^^^^^ cannot assign error[E0594]: cannot assign to `x`, as it is not declared as mutable - --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:19:50 + --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:22:50 | LL | pub fn ee(x: &'static mut isize) { | - help: consider changing this to be mutable: `mut x` @@ -17,38 +60,42 @@ LL | let mut c2 = |y: &'static mut isize| x = y; | ^^^^^ cannot assign error[E0594]: cannot assign to `x`, as it is not declared as mutable - --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:30:14 + --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:37:13 | LL | pub fn capture_assign_whole(x: (i32,)) { | - help: consider changing this to be mutable: `mut x` -LL | || { x = (1,); }; - | ^^^^^^^^ cannot assign +LL | || { +LL | x = (1,); + | ^^^^^^^^ cannot assign error[E0594]: cannot assign to `x.0`, as `x` is not declared as mutable - --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:34:14 + --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:43:13 | LL | pub fn capture_assign_part(x: (i32,)) { | - help: consider changing this to be mutable: `mut x` -LL | || { x.0 = 1; }; - | ^^^^^^^ cannot assign +LL | || { +LL | x.0 = 1; + | ^^^^^^^ cannot assign error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable - --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:38:14 + --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:49:13 | LL | pub fn capture_reborrow_whole(x: (i32,)) { | - help: consider changing this to be mutable: `mut x` -LL | || { &mut x; }; - | ^^^^^^ cannot borrow as mutable +LL | || { +LL | &mut x; + | ^^^^^^ cannot borrow as mutable error[E0596]: cannot borrow `x.0` as mutable, as `x` is not declared as mutable - --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:42:14 + --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:55:13 | LL | pub fn capture_reborrow_part(x: (i32,)) { | - help: consider changing this to be mutable: `mut x` -LL | || { &mut x.0; }; - | ^^^^^^^^ cannot borrow as mutable +LL | || { +LL | &mut x.0; + | ^^^^^^^^ cannot borrow as mutable -error: aborting due to 6 previous errors +error: aborting due to 6 previous errors; 3 warnings emitted Some errors have detailed explanations: E0594, E0596. For more information about an error, try `rustc --explain E0594`. diff --git a/tests/ui/consts/const_let_assign2.rs b/tests/ui/consts/const_let_assign2.rs index 28265c85dd1f1..1c7afe0e3d6cb 100644 --- a/tests/ui/consts/const_let_assign2.rs +++ b/tests/ui/consts/const_let_assign2.rs @@ -16,6 +16,7 @@ static mut BB: AA = AA::new(); fn main() { let ptr = unsafe { &mut BB }; + //~^ WARN mutable reference of mutable static is discouraged [static_mut_ref] for a in ptr.data.iter() { println!("{}", a); } diff --git a/tests/ui/consts/const_let_assign2.stderr b/tests/ui/consts/const_let_assign2.stderr new file mode 100644 index 0000000000000..2764153a8a590 --- /dev/null +++ b/tests/ui/consts/const_let_assign2.stderr @@ -0,0 +1,17 @@ +warning: mutable reference of mutable static is discouraged + --> $DIR/const_let_assign2.rs:18:24 + | +LL | let ptr = unsafe { &mut BB }; + | ^^^^^^^ mutable reference of mutable static + | + = note: for more information, see issue #114447 + = note: reference of mutable static is a hard error from 2024 edition + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior + = note: `#[warn(static_mut_ref)]` on by default +help: mutable references are dangerous since if there's any other pointer or reference used for that static while the reference lives, that's UB; use `addr_of_mut!` instead to create a raw pointer + | +LL | let ptr = unsafe { addr_of_mut!(BB) }; + | ~~~~~~~~~~~~~~~~ + +warning: 1 warning emitted + diff --git a/tests/ui/consts/issue-17718-const-bad-values.rs b/tests/ui/consts/issue-17718-const-bad-values.rs index 62bbb3b569c37..4fedc48452bec 100644 --- a/tests/ui/consts/issue-17718-const-bad-values.rs +++ b/tests/ui/consts/issue-17718-const-bad-values.rs @@ -3,7 +3,8 @@ const C1: &'static mut [usize] = &mut []; static mut S: usize = 3; const C2: &'static mut usize = unsafe { &mut S }; -//~^ ERROR: constants cannot refer to statics +//~^ WARN mutable reference of mutable static is discouraged [static_mut_ref] +//~^^ ERROR: constants cannot refer to statics //~| ERROR: constants cannot refer to statics fn main() {} diff --git a/tests/ui/consts/issue-17718-const-bad-values.stderr b/tests/ui/consts/issue-17718-const-bad-values.stderr index 405c2195dec4f..2dc91f52669e7 100644 --- a/tests/ui/consts/issue-17718-const-bad-values.stderr +++ b/tests/ui/consts/issue-17718-const-bad-values.stderr @@ -1,3 +1,18 @@ +warning: mutable reference of mutable static is discouraged + --> $DIR/issue-17718-const-bad-values.rs:5:41 + | +LL | const C2: &'static mut usize = unsafe { &mut S }; + | ^^^^^^ mutable reference of mutable static + | + = note: for more information, see issue #114447 + = note: reference of mutable static is a hard error from 2024 edition + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior + = note: `#[warn(static_mut_ref)]` on by default +help: mutable references are dangerous since if there's any other pointer or reference used for that static while the reference lives, that's UB; use `addr_of_mut!` instead to create a raw pointer + | +LL | const C2: &'static mut usize = unsafe { addr_of_mut!(S) }; + | ~~~~~~~~~~~~~~~ + error[E0764]: mutable references are not allowed in the final value of constants --> $DIR/issue-17718-const-bad-values.rs:1:34 | @@ -21,7 +36,7 @@ LL | const C2: &'static mut usize = unsafe { &mut S }; = help: consider extracting the value of the `static` to a `const`, and referring to that = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error: aborting due to 3 previous errors +error: aborting due to 3 previous errors; 1 warning emitted Some errors have detailed explanations: E0013, E0764. For more information about an error, try `rustc --explain E0013`. diff --git a/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.32bit.stderr b/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.32bit.stderr index 7960648ce3a19..ed9db67542641 100644 --- a/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.32bit.stderr +++ b/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.32bit.stderr @@ -1,3 +1,18 @@ +warning: shared reference of mutable static is discouraged + --> $DIR/const_refers_to_static_cross_crate.rs:13:14 + | +LL | unsafe { &static_cross_crate::ZERO } + | ^^^^^^^^^^^^^^^^^^^^^^^^^ shared reference of mutable static + | + = note: for more information, see issue #114447 + = note: reference of mutable static is a hard error from 2024 edition + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior + = note: `#[warn(static_mut_ref)]` on by default +help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer + | +LL | unsafe { addr_of!(static_cross_crate::ZERO) } + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + error[E0080]: it is undefined behavior to use this value --> $DIR/const_refers_to_static_cross_crate.rs:10:1 | @@ -10,13 +25,13 @@ LL | const SLICE_MUT: &[u8; 1] = { } error: could not evaluate constant pattern - --> $DIR/const_refers_to_static_cross_crate.rs:34:9 + --> $DIR/const_refers_to_static_cross_crate.rs:42:9 | LL | SLICE_MUT => true, | ^^^^^^^^^ error[E0080]: it is undefined behavior to use this value - --> $DIR/const_refers_to_static_cross_crate.rs:15:1 + --> $DIR/const_refers_to_static_cross_crate.rs:17:1 | LL | const U8_MUT: &u8 = { | ^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a reference pointing to a static variable in a constant @@ -27,31 +42,31 @@ LL | const U8_MUT: &u8 = { } error: could not evaluate constant pattern - --> $DIR/const_refers_to_static_cross_crate.rs:42:9 + --> $DIR/const_refers_to_static_cross_crate.rs:50:9 | LL | U8_MUT => true, | ^^^^^^ error[E0080]: evaluation of constant value failed - --> $DIR/const_refers_to_static_cross_crate.rs:22:15 + --> $DIR/const_refers_to_static_cross_crate.rs:25:15 | LL | unsafe { &(*static_cross_crate::ZERO_REF)[0] } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constant accesses static error: could not evaluate constant pattern - --> $DIR/const_refers_to_static_cross_crate.rs:52:9 + --> $DIR/const_refers_to_static_cross_crate.rs:60:9 | LL | U8_MUT2 => true, | ^^^^^^^ error[E0080]: evaluation of constant value failed - --> $DIR/const_refers_to_static_cross_crate.rs:27:20 + --> $DIR/const_refers_to_static_cross_crate.rs:31:15 | -LL | unsafe { match static_cross_crate::OPT_ZERO { Some(ref u) => u, None => panic!() } } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constant accesses static +LL | match static_cross_crate::OPT_ZERO { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constant accesses static error: could not evaluate constant pattern - --> $DIR/const_refers_to_static_cross_crate.rs:59:9 + --> $DIR/const_refers_to_static_cross_crate.rs:67:9 | LL | U8_MUT3 => true, | ^^^^^^^ @@ -59,61 +74,61 @@ LL | U8_MUT3 => true, warning: skipping const checks | help: skipping check that does not even have a feature gate - --> $DIR/const_refers_to_static_cross_crate.rs:12:15 + --> $DIR/const_refers_to_static_cross_crate.rs:13:15 | LL | unsafe { &static_cross_crate::ZERO } | ^^^^^^^^^^^^^^^^^^^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/const_refers_to_static_cross_crate.rs:12:15 + --> $DIR/const_refers_to_static_cross_crate.rs:13:15 | LL | unsafe { &static_cross_crate::ZERO } | ^^^^^^^^^^^^^^^^^^^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/const_refers_to_static_cross_crate.rs:17:15 + --> $DIR/const_refers_to_static_cross_crate.rs:20:15 | LL | unsafe { &static_cross_crate::ZERO[0] } | ^^^^^^^^^^^^^^^^^^^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/const_refers_to_static_cross_crate.rs:17:15 + --> $DIR/const_refers_to_static_cross_crate.rs:20:15 | LL | unsafe { &static_cross_crate::ZERO[0] } | ^^^^^^^^^^^^^^^^^^^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/const_refers_to_static_cross_crate.rs:17:15 + --> $DIR/const_refers_to_static_cross_crate.rs:20:15 | LL | unsafe { &static_cross_crate::ZERO[0] } | ^^^^^^^^^^^^^^^^^^^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/const_refers_to_static_cross_crate.rs:22:17 + --> $DIR/const_refers_to_static_cross_crate.rs:25:17 | LL | unsafe { &(*static_cross_crate::ZERO_REF)[0] } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/const_refers_to_static_cross_crate.rs:27:20 + --> $DIR/const_refers_to_static_cross_crate.rs:31:15 | -LL | unsafe { match static_cross_crate::OPT_ZERO { Some(ref u) => u, None => panic!() } } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | match static_cross_crate::OPT_ZERO { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/const_refers_to_static_cross_crate.rs:27:20 + --> $DIR/const_refers_to_static_cross_crate.rs:31:15 | -LL | unsafe { match static_cross_crate::OPT_ZERO { Some(ref u) => u, None => panic!() } } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | match static_cross_crate::OPT_ZERO { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/const_refers_to_static_cross_crate.rs:27:20 + --> $DIR/const_refers_to_static_cross_crate.rs:31:15 | -LL | unsafe { match static_cross_crate::OPT_ZERO { Some(ref u) => u, None => panic!() } } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | match static_cross_crate::OPT_ZERO { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/const_refers_to_static_cross_crate.rs:27:20 + --> $DIR/const_refers_to_static_cross_crate.rs:31:15 | -LL | unsafe { match static_cross_crate::OPT_ZERO { Some(ref u) => u, None => panic!() } } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | match static_cross_crate::OPT_ZERO { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/const_refers_to_static_cross_crate.rs:27:20 + --> $DIR/const_refers_to_static_cross_crate.rs:31:15 | -LL | unsafe { match static_cross_crate::OPT_ZERO { Some(ref u) => u, None => panic!() } } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | match static_cross_crate::OPT_ZERO { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 8 previous errors; 1 warning emitted +error: aborting due to 8 previous errors; 2 warnings emitted For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.64bit.stderr b/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.64bit.stderr index 6ae0b2d1bfef7..275323bc286c0 100644 --- a/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.64bit.stderr +++ b/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.64bit.stderr @@ -1,3 +1,18 @@ +warning: shared reference of mutable static is discouraged + --> $DIR/const_refers_to_static_cross_crate.rs:13:14 + | +LL | unsafe { &static_cross_crate::ZERO } + | ^^^^^^^^^^^^^^^^^^^^^^^^^ shared reference of mutable static + | + = note: for more information, see issue #114447 + = note: reference of mutable static is a hard error from 2024 edition + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior + = note: `#[warn(static_mut_ref)]` on by default +help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer + | +LL | unsafe { addr_of!(static_cross_crate::ZERO) } + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + error[E0080]: it is undefined behavior to use this value --> $DIR/const_refers_to_static_cross_crate.rs:10:1 | @@ -10,13 +25,13 @@ LL | const SLICE_MUT: &[u8; 1] = { } error: could not evaluate constant pattern - --> $DIR/const_refers_to_static_cross_crate.rs:34:9 + --> $DIR/const_refers_to_static_cross_crate.rs:42:9 | LL | SLICE_MUT => true, | ^^^^^^^^^ error[E0080]: it is undefined behavior to use this value - --> $DIR/const_refers_to_static_cross_crate.rs:15:1 + --> $DIR/const_refers_to_static_cross_crate.rs:17:1 | LL | const U8_MUT: &u8 = { | ^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a reference pointing to a static variable in a constant @@ -27,31 +42,31 @@ LL | const U8_MUT: &u8 = { } error: could not evaluate constant pattern - --> $DIR/const_refers_to_static_cross_crate.rs:42:9 + --> $DIR/const_refers_to_static_cross_crate.rs:50:9 | LL | U8_MUT => true, | ^^^^^^ error[E0080]: evaluation of constant value failed - --> $DIR/const_refers_to_static_cross_crate.rs:22:15 + --> $DIR/const_refers_to_static_cross_crate.rs:25:15 | LL | unsafe { &(*static_cross_crate::ZERO_REF)[0] } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constant accesses static error: could not evaluate constant pattern - --> $DIR/const_refers_to_static_cross_crate.rs:52:9 + --> $DIR/const_refers_to_static_cross_crate.rs:60:9 | LL | U8_MUT2 => true, | ^^^^^^^ error[E0080]: evaluation of constant value failed - --> $DIR/const_refers_to_static_cross_crate.rs:27:20 + --> $DIR/const_refers_to_static_cross_crate.rs:31:15 | -LL | unsafe { match static_cross_crate::OPT_ZERO { Some(ref u) => u, None => panic!() } } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constant accesses static +LL | match static_cross_crate::OPT_ZERO { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constant accesses static error: could not evaluate constant pattern - --> $DIR/const_refers_to_static_cross_crate.rs:59:9 + --> $DIR/const_refers_to_static_cross_crate.rs:67:9 | LL | U8_MUT3 => true, | ^^^^^^^ @@ -59,61 +74,61 @@ LL | U8_MUT3 => true, warning: skipping const checks | help: skipping check that does not even have a feature gate - --> $DIR/const_refers_to_static_cross_crate.rs:12:15 + --> $DIR/const_refers_to_static_cross_crate.rs:13:15 | LL | unsafe { &static_cross_crate::ZERO } | ^^^^^^^^^^^^^^^^^^^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/const_refers_to_static_cross_crate.rs:12:15 + --> $DIR/const_refers_to_static_cross_crate.rs:13:15 | LL | unsafe { &static_cross_crate::ZERO } | ^^^^^^^^^^^^^^^^^^^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/const_refers_to_static_cross_crate.rs:17:15 + --> $DIR/const_refers_to_static_cross_crate.rs:20:15 | LL | unsafe { &static_cross_crate::ZERO[0] } | ^^^^^^^^^^^^^^^^^^^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/const_refers_to_static_cross_crate.rs:17:15 + --> $DIR/const_refers_to_static_cross_crate.rs:20:15 | LL | unsafe { &static_cross_crate::ZERO[0] } | ^^^^^^^^^^^^^^^^^^^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/const_refers_to_static_cross_crate.rs:17:15 + --> $DIR/const_refers_to_static_cross_crate.rs:20:15 | LL | unsafe { &static_cross_crate::ZERO[0] } | ^^^^^^^^^^^^^^^^^^^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/const_refers_to_static_cross_crate.rs:22:17 + --> $DIR/const_refers_to_static_cross_crate.rs:25:17 | LL | unsafe { &(*static_cross_crate::ZERO_REF)[0] } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/const_refers_to_static_cross_crate.rs:27:20 + --> $DIR/const_refers_to_static_cross_crate.rs:31:15 | -LL | unsafe { match static_cross_crate::OPT_ZERO { Some(ref u) => u, None => panic!() } } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | match static_cross_crate::OPT_ZERO { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/const_refers_to_static_cross_crate.rs:27:20 + --> $DIR/const_refers_to_static_cross_crate.rs:31:15 | -LL | unsafe { match static_cross_crate::OPT_ZERO { Some(ref u) => u, None => panic!() } } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | match static_cross_crate::OPT_ZERO { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/const_refers_to_static_cross_crate.rs:27:20 + --> $DIR/const_refers_to_static_cross_crate.rs:31:15 | -LL | unsafe { match static_cross_crate::OPT_ZERO { Some(ref u) => u, None => panic!() } } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | match static_cross_crate::OPT_ZERO { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/const_refers_to_static_cross_crate.rs:27:20 + --> $DIR/const_refers_to_static_cross_crate.rs:31:15 | -LL | unsafe { match static_cross_crate::OPT_ZERO { Some(ref u) => u, None => panic!() } } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | match static_cross_crate::OPT_ZERO { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/const_refers_to_static_cross_crate.rs:27:20 + --> $DIR/const_refers_to_static_cross_crate.rs:31:15 | -LL | unsafe { match static_cross_crate::OPT_ZERO { Some(ref u) => u, None => panic!() } } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | match static_cross_crate::OPT_ZERO { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 8 previous errors; 1 warning emitted +error: aborting due to 8 previous errors; 2 warnings emitted For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.rs b/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.rs index bbaa32ddfd1bd..3eafa58d9f9fd 100644 --- a/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.rs +++ b/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.rs @@ -7,13 +7,16 @@ extern crate static_cross_crate; // Sneaky: reference to a mutable static. // Allowing this would be a disaster for pattern matching, we could violate exhaustiveness checking! -const SLICE_MUT: &[u8; 1] = { //~ ERROR undefined behavior to use this value -//~| encountered a reference pointing to a static variable +const SLICE_MUT: &[u8; 1] = { + //~^ ERROR undefined behavior to use this value + //~| encountered a reference pointing to a static variable unsafe { &static_cross_crate::ZERO } + //~^ WARN shared reference of mutable static is discouraged [static_mut_ref] }; -const U8_MUT: &u8 = { //~ ERROR undefined behavior to use this value -//~| encountered a reference pointing to a static variable +const U8_MUT: &u8 = { + //~^ ERROR undefined behavior to use this value + //~| encountered a reference pointing to a static variable unsafe { &static_cross_crate::ZERO[0] } }; @@ -24,9 +27,14 @@ const U8_MUT2: &u8 = { //~| constant accesses static }; const U8_MUT3: &u8 = { - unsafe { match static_cross_crate::OPT_ZERO { Some(ref u) => u, None => panic!() } } - //~^ ERROR evaluation of constant value failed - //~| constant accesses static + unsafe { + match static_cross_crate::OPT_ZERO { + //~^ ERROR evaluation of constant value failed + //~| constant accesses static + Some(ref u) => u, + None => panic!(), + } + } }; pub fn test(x: &[u8; 1]) -> bool { diff --git a/tests/ui/consts/static_mut_containing_mut_ref.rs b/tests/ui/consts/static_mut_containing_mut_ref.rs index df09c76c5584d..874aa59df0bb6 100644 --- a/tests/ui/consts/static_mut_containing_mut_ref.rs +++ b/tests/ui/consts/static_mut_containing_mut_ref.rs @@ -3,5 +3,6 @@ static mut STDERR_BUFFER_SPACE: [u8; 42] = [0u8; 42]; pub static mut STDERR_BUFFER: *mut [u8] = unsafe { &mut STDERR_BUFFER_SPACE }; +//~^ WARN mutable reference of mutable static is discouraged [static_mut_ref] fn main() {} diff --git a/tests/ui/consts/static_mut_containing_mut_ref.stderr b/tests/ui/consts/static_mut_containing_mut_ref.stderr new file mode 100644 index 0000000000000..56ceba41cf88c --- /dev/null +++ b/tests/ui/consts/static_mut_containing_mut_ref.stderr @@ -0,0 +1,17 @@ +warning: mutable reference of mutable static is discouraged + --> $DIR/static_mut_containing_mut_ref.rs:5:52 + | +LL | pub static mut STDERR_BUFFER: *mut [u8] = unsafe { &mut STDERR_BUFFER_SPACE }; + | ^^^^^^^^^^^^^^^^^^^^^^^^ mutable reference of mutable static + | + = note: for more information, see issue #114447 + = note: reference of mutable static is a hard error from 2024 edition + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior + = note: `#[warn(static_mut_ref)]` on by default +help: mutable references are dangerous since if there's any other pointer or reference used for that static while the reference lives, that's UB; use `addr_of_mut!` instead to create a raw pointer + | +LL | pub static mut STDERR_BUFFER: *mut [u8] = unsafe { addr_of_mut!(STDERR_BUFFER_SPACE) }; + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +warning: 1 warning emitted + diff --git a/tests/ui/consts/static_mut_containing_mut_ref2.mut_refs.stderr b/tests/ui/consts/static_mut_containing_mut_ref2.mut_refs.stderr index 3d0de233569c9..bc32ecc2c35ff 100644 --- a/tests/ui/consts/static_mut_containing_mut_ref2.mut_refs.stderr +++ b/tests/ui/consts/static_mut_containing_mut_ref2.mut_refs.stderr @@ -1,9 +1,24 @@ +warning: mutable reference of mutable static is discouraged + --> $DIR/static_mut_containing_mut_ref2.rs:8:6 + | +LL | *(&mut STDERR_BUFFER_SPACE) = 42; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ mutable reference of mutable static + | + = note: for more information, see issue #114447 + = note: reference of mutable static is a hard error from 2024 edition + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior + = note: `#[warn(static_mut_ref)]` on by default +help: mutable references are dangerous since if there's any other pointer or reference used for that static while the reference lives, that's UB; use `addr_of_mut!` instead to create a raw pointer + | +LL | *addr_of_mut!(STDERR_BUFFER_SPACE) = 42; + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + error[E0080]: could not evaluate static initializer - --> $DIR/static_mut_containing_mut_ref2.rs:7:45 + --> $DIR/static_mut_containing_mut_ref2.rs:8:5 | -LL | pub static mut STDERR_BUFFER: () = unsafe { *(&mut STDERR_BUFFER_SPACE) = 42; }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ modifying a static's initial value from another static's initializer +LL | *(&mut STDERR_BUFFER_SPACE) = 42; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ modifying a static's initial value from another static's initializer -error: aborting due to 1 previous error +error: aborting due to 1 previous error; 1 warning emitted For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/static_mut_containing_mut_ref2.rs b/tests/ui/consts/static_mut_containing_mut_ref2.rs index 61368546083db..fa79a78eab424 100644 --- a/tests/ui/consts/static_mut_containing_mut_ref2.rs +++ b/tests/ui/consts/static_mut_containing_mut_ref2.rs @@ -4,8 +4,12 @@ static mut STDERR_BUFFER_SPACE: u8 = 0; -pub static mut STDERR_BUFFER: () = unsafe { *(&mut STDERR_BUFFER_SPACE) = 42; }; -//[mut_refs]~^ ERROR could not evaluate static initializer -//[stock]~^^ ERROR mutable references are not allowed in statics +pub static mut STDERR_BUFFER: () = unsafe { + *(&mut STDERR_BUFFER_SPACE) = 42; + //[mut_refs]~^ ERROR could not evaluate static initializer + //[stock]~^^ ERROR mutable references are not allowed in statics + //[mut_refs]~^^^ WARN mutable reference of mutable static is discouraged [static_mut_ref] + //[stock]~^^^^ WARN mutable reference of mutable static is discouraged [static_mut_ref] +}; fn main() {} diff --git a/tests/ui/consts/static_mut_containing_mut_ref2.stock.stderr b/tests/ui/consts/static_mut_containing_mut_ref2.stock.stderr index 3d5b012d42f37..c6e5b07e3b70a 100644 --- a/tests/ui/consts/static_mut_containing_mut_ref2.stock.stderr +++ b/tests/ui/consts/static_mut_containing_mut_ref2.stock.stderr @@ -1,12 +1,27 @@ +warning: mutable reference of mutable static is discouraged + --> $DIR/static_mut_containing_mut_ref2.rs:8:6 + | +LL | *(&mut STDERR_BUFFER_SPACE) = 42; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ mutable reference of mutable static + | + = note: for more information, see issue #114447 + = note: reference of mutable static is a hard error from 2024 edition + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior + = note: `#[warn(static_mut_ref)]` on by default +help: mutable references are dangerous since if there's any other pointer or reference used for that static while the reference lives, that's UB; use `addr_of_mut!` instead to create a raw pointer + | +LL | *addr_of_mut!(STDERR_BUFFER_SPACE) = 42; + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + error[E0658]: mutable references are not allowed in statics - --> $DIR/static_mut_containing_mut_ref2.rs:7:46 + --> $DIR/static_mut_containing_mut_ref2.rs:8:6 | -LL | pub static mut STDERR_BUFFER: () = unsafe { *(&mut STDERR_BUFFER_SPACE) = 42; }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | *(&mut STDERR_BUFFER_SPACE) = 42; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #57349 for more information = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable -error: aborting due to 1 previous error +error: aborting due to 1 previous error; 1 warning emitted For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/drop/issue-23338-ensure-param-drop-order.rs b/tests/ui/drop/issue-23338-ensure-param-drop-order.rs index a99f260dde3b2..52603744c45fc 100644 --- a/tests/ui/drop/issue-23338-ensure-param-drop-order.rs +++ b/tests/ui/drop/issue-23338-ensure-param-drop-order.rs @@ -13,38 +13,39 @@ pub fn main() { d::println("created empty log"); test(&log); - assert_eq!(&log.borrow()[..], - [ - // created empty log - // +-- Make D(da_0, 0) - // | +-- Make D(de_1, 1) - // | | calling foo - // | | entered foo - // | | +-- Make D(de_2, 2) - // | | | +-- Make D(da_1, 3) - // | | | | +-- Make D(de_3, 4) - // | | | | | +-- Make D(de_4, 5) - 3, // | | | +-- Drop D(da_1, 3) - // | | | | | - 4, // | | | +-- Drop D(de_3, 4) - // | | | | - // | | | | eval tail of foo - // | | | +-- Make D(de_5, 6) - // | | | | +-- Make D(de_6, 7) - 5, // | | | | | +-- Drop D(de_4, 5) - // | | | | | - 2, // | | +-- Drop D(de_2, 2) - // | | | | - 6, // | | +-- Drop D(de_5, 6) - // | | | - 1, // | +-- Drop D(de_1, 1) - // | | - 0, // +-- Drop D(da_0, 0) - // | - // | result D(de_6, 7) - 7 // +-- Drop D(de_6, 7) - - ]); + assert_eq!( + &log.borrow()[..], + [ + // created empty log + // +-- Make D(da_0, 0) + // | +-- Make D(de_1, 1) + // | | calling foo + // | | entered foo + // | | +-- Make D(de_2, 2) + // | | | +-- Make D(da_1, 3) + // | | | | +-- Make D(de_3, 4) + // | | | | | +-- Make D(de_4, 5) + 3, // | | | +-- Drop D(da_1, 3) + // | | | | | + 4, // | | | +-- Drop D(de_3, 4) + // | | | | + // | | | | eval tail of foo + // | | | +-- Make D(de_5, 6) + // | | | | +-- Make D(de_6, 7) + 5, // | | | | | +-- Drop D(de_4, 5) + // | | | | | + 2, // | | +-- Drop D(de_2, 2) + // | | | | + 6, // | | +-- Drop D(de_5, 6) + // | | | + 1, // | +-- Drop D(de_1, 1) + // | | + 0, // +-- Drop D(da_0, 0) + // | + // | result D(de_6, 7) + 7 // +-- Drop D(de_6, 7) + ] + ); } fn test<'a>(log: d::Log<'a>) { @@ -57,13 +58,13 @@ fn test<'a>(log: d::Log<'a>) { fn foo<'a>(da0: D<'a>, de1: D<'a>) -> D<'a> { d::println("entered foo"); - let de2 = de1.incr(); // creates D(de_2, 2) + let de2 = de1.incr(); // creates D(de_2, 2) let de4 = { let _da1 = da0.incr(); // creates D(da_1, 3) - de2.incr().incr() // creates D(de_3, 4) and D(de_4, 5) + de2.incr().incr() // creates D(de_3, 4) and D(de_4, 5) }; d::println("eval tail of foo"); - de4.incr().incr() // creates D(de_5, 6) and D(de_6, 7) + de4.incr().incr() // creates D(de_5, 6) and D(de_6, 7) } // This module provides simultaneous printouts of the dynamic extents @@ -74,9 +75,9 @@ const PREF_INDENT: u32 = 16; pub mod d { #![allow(unused_parens)] + use std::cell::RefCell; use std::fmt; use std::mem; - use std::cell::RefCell; static mut counter: u32 = 0; static mut trails: u64 = 0; @@ -89,7 +90,8 @@ pub mod d { pub fn max_width() -> u32 { unsafe { - (mem::size_of_val(&trails)*8) as u32 + (mem::size_of_val(&trails) * 8) as u32 + //~^ WARN shared reference of mutable static is discouraged [static_mut_ref] } } @@ -123,7 +125,11 @@ pub mod d { } pub struct D<'a> { - name: &'static str, i: u32, uid: u32, trail: u32, log: Log<'a> + name: &'static str, + i: u32, + uid: u32, + trail: u32, + log: Log<'a>, } impl<'a> fmt::Display for D<'a> { @@ -139,9 +145,7 @@ pub mod d { let ctr = counter; counter += 1; trails |= (1 << trail); - let ret = D { - name: name, i: i, log: log, uid: ctr, trail: trail - }; + let ret = D { name: name, i: i, log: log, uid: ctr, trail: trail }; indent_println(trail, &format!("+-- Make {}", ret)); ret } @@ -153,7 +157,9 @@ pub mod d { impl<'a> Drop for D<'a> { fn drop(&mut self) { - unsafe { trails &= !(1 << self.trail); }; + unsafe { + trails &= !(1 << self.trail); + }; self.log.borrow_mut().push(self.uid); indent_println(self.trail, &format!("+-- Drop {}", self)); indent_println(::PREF_INDENT, ""); diff --git a/tests/ui/drop/issue-23338-ensure-param-drop-order.stderr b/tests/ui/drop/issue-23338-ensure-param-drop-order.stderr new file mode 100644 index 0000000000000..fd36ccbcbee47 --- /dev/null +++ b/tests/ui/drop/issue-23338-ensure-param-drop-order.stderr @@ -0,0 +1,17 @@ +warning: shared reference of mutable static is discouraged + --> $DIR/issue-23338-ensure-param-drop-order.rs:93:31 + | +LL | (mem::size_of_val(&trails) * 8) as u32 + | ^^^^^^^ shared reference of mutable static + | + = note: for more information, see issue #114447 + = note: reference of mutable static is a hard error from 2024 edition + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior + = note: `#[warn(static_mut_ref)]` on by default +help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer + | +LL | (mem::size_of_val(addr_of!(trails)) * 8) as u32 + | ~~~~~~~~~~~~~~~~ + +warning: 1 warning emitted + diff --git a/tests/ui/error-codes/E0017.rs b/tests/ui/error-codes/E0017.rs index c211ad1a2f8f6..9d3433fa543fd 100644 --- a/tests/ui/error-codes/E0017.rs +++ b/tests/ui/error-codes/E0017.rs @@ -3,12 +3,16 @@ const C: i32 = 2; static mut M: i32 = 3; const CR: &'static mut i32 = &mut C; //~ ERROR mutable references are not allowed - //~| WARN taking a mutable +//~| WARN taking a mutable + static STATIC_REF: &'static mut i32 = &mut X; //~ ERROR E0658 - //~| ERROR cannot borrow - //~| ERROR mutable references are not allowed +//~| ERROR cannot borrow +//~| ERROR mutable references are not allowed static CONST_REF: &'static mut i32 = &mut C; //~ ERROR mutable references are not allowed - //~| WARN taking a mutable +//~| WARN taking a mutable + static STATIC_MUT_REF: &'static mut i32 = unsafe { &mut M }; //~ ERROR mutable references are not +//~^ WARN mutable reference of mutable static is discouraged [static_mut_ref] + fn main() {} diff --git a/tests/ui/error-codes/E0017.stderr b/tests/ui/error-codes/E0017.stderr index 6e48f9582f1c0..ea6055da1c1fe 100644 --- a/tests/ui/error-codes/E0017.stderr +++ b/tests/ui/error-codes/E0017.stderr @@ -1,3 +1,18 @@ +warning: mutable reference of mutable static is discouraged + --> $DIR/E0017.rs:15:52 + | +LL | static STATIC_MUT_REF: &'static mut i32 = unsafe { &mut M }; + | ^^^^^^ mutable reference of mutable static + | + = note: for more information, see issue #114447 + = note: reference of mutable static is a hard error from 2024 edition + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior + = note: `#[warn(static_mut_ref)]` on by default +help: mutable references are dangerous since if there's any other pointer or reference used for that static while the reference lives, that's UB; use `addr_of_mut!` instead to create a raw pointer + | +LL | static STATIC_MUT_REF: &'static mut i32 = unsafe { addr_of_mut!(M) }; + | ~~~~~~~~~~~~~~~ + warning: taking a mutable reference to a `const` item --> $DIR/E0017.rs:5:30 | @@ -20,7 +35,7 @@ LL | const CR: &'static mut i32 = &mut C; | ^^^^^^ error[E0658]: mutation through a reference is not allowed in statics - --> $DIR/E0017.rs:7:39 + --> $DIR/E0017.rs:8:39 | LL | static STATIC_REF: &'static mut i32 = &mut X; | ^^^^^^ @@ -29,19 +44,19 @@ LL | static STATIC_REF: &'static mut i32 = &mut X; = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable error[E0764]: mutable references are not allowed in the final value of statics - --> $DIR/E0017.rs:7:39 + --> $DIR/E0017.rs:8:39 | LL | static STATIC_REF: &'static mut i32 = &mut X; | ^^^^^^ error[E0596]: cannot borrow immutable static item `X` as mutable - --> $DIR/E0017.rs:7:39 + --> $DIR/E0017.rs:8:39 | LL | static STATIC_REF: &'static mut i32 = &mut X; | ^^^^^^ cannot borrow as mutable warning: taking a mutable reference to a `const` item - --> $DIR/E0017.rs:11:38 + --> $DIR/E0017.rs:12:38 | LL | static CONST_REF: &'static mut i32 = &mut C; | ^^^^^^ @@ -55,18 +70,18 @@ LL | const C: i32 = 2; | ^^^^^^^^^^^^ error[E0764]: mutable references are not allowed in the final value of statics - --> $DIR/E0017.rs:11:38 + --> $DIR/E0017.rs:12:38 | LL | static CONST_REF: &'static mut i32 = &mut C; | ^^^^^^ error[E0764]: mutable references are not allowed in the final value of statics - --> $DIR/E0017.rs:13:52 + --> $DIR/E0017.rs:15:52 | LL | static STATIC_MUT_REF: &'static mut i32 = unsafe { &mut M }; | ^^^^^^ -error: aborting due to 6 previous errors; 2 warnings emitted +error: aborting due to 6 previous errors; 3 warnings emitted Some errors have detailed explanations: E0596, E0658, E0764. For more information about an error, try `rustc --explain E0596`. diff --git a/tests/ui/issues/issue-20616.rs b/tests/ui/impl-header-lifetime-elision/bare_type.rs similarity index 82% rename from tests/ui/issues/issue-20616.rs rename to tests/ui/impl-header-lifetime-elision/bare_type.rs index 6c24d437272e4..9af98f870d2d5 100644 --- a/tests/ui/issues/issue-20616.rs +++ b/tests/ui/impl-header-lifetime-elision/bare_type.rs @@ -33,12 +33,11 @@ type TypeI = T; 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>= Box::new(&STATIC); - let _: Box>= Box::new(&STATIC); + let _: Box> = Box::new(&STATIC); + let _: Box> = Box::new(&STATIC); } diff --git a/tests/ui/impl-trait/in-trait/cycle-effective-visibilities-during-object-safety.rs b/tests/ui/impl-trait/in-trait/cycle-effective-visibilities-during-object-safety.rs new file mode 100644 index 0000000000000..650cb3870d581 --- /dev/null +++ b/tests/ui/impl-trait/in-trait/cycle-effective-visibilities-during-object-safety.rs @@ -0,0 +1,28 @@ +trait Marker {} +impl Marker for u32 {} + +trait MyTrait { + fn foo(&self) -> impl Marker; +} + +struct Outer; + +impl MyTrait for Outer { + fn foo(&self) -> impl Marker { + 42 + } +} + +impl dyn MyTrait { + //~^ ERROR the trait `MyTrait` cannot be made into an object + fn other(&self) -> impl Marker { + //~^ ERROR the trait `MyTrait` cannot be made into an object + MyTrait::foo(&self) + //~^ ERROR the trait bound `&dyn MyTrait: MyTrait` is not satisfied + //~| ERROR the trait bound `&dyn MyTrait: MyTrait` is not satisfied + //~| ERROR the trait bound `&dyn MyTrait: MyTrait` is not satisfied + //~| ERROR the trait `MyTrait` cannot be made into an object + } +} + +fn main() {} diff --git a/tests/ui/impl-trait/in-trait/cycle-effective-visibilities-during-object-safety.stderr b/tests/ui/impl-trait/in-trait/cycle-effective-visibilities-during-object-safety.stderr new file mode 100644 index 0000000000000..ceba7b4550db8 --- /dev/null +++ b/tests/ui/impl-trait/in-trait/cycle-effective-visibilities-during-object-safety.stderr @@ -0,0 +1,78 @@ +error[E0038]: the trait `MyTrait` cannot be made into an object + --> $DIR/cycle-effective-visibilities-during-object-safety.rs:16:6 + | +LL | impl dyn MyTrait { + | ^^^^^^^^^^^ `MyTrait` cannot be made into an object + | +note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit + --> $DIR/cycle-effective-visibilities-during-object-safety.rs:5:22 + | +LL | trait MyTrait { + | ------- this trait cannot be made into an object... +LL | fn foo(&self) -> impl Marker; + | ^^^^^^^^^^^ ...because method `foo` references an `impl Trait` type in its return type + = help: consider moving `foo` to another trait + = help: only type `Outer` implements the trait, consider using it directly instead + +error[E0038]: the trait `MyTrait` cannot be made into an object + --> $DIR/cycle-effective-visibilities-during-object-safety.rs:18:15 + | +LL | fn other(&self) -> impl Marker { + | ^^^^ `MyTrait` cannot be made into an object + | +note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit + --> $DIR/cycle-effective-visibilities-during-object-safety.rs:5:22 + | +LL | trait MyTrait { + | ------- this trait cannot be made into an object... +LL | fn foo(&self) -> impl Marker; + | ^^^^^^^^^^^ ...because method `foo` references an `impl Trait` type in its return type + = help: consider moving `foo` to another trait + = help: only type `Outer` implements the trait, consider using it directly instead + +error[E0277]: the trait bound `&dyn MyTrait: MyTrait` is not satisfied + --> $DIR/cycle-effective-visibilities-during-object-safety.rs:20:22 + | +LL | MyTrait::foo(&self) + | ------------ ^^^^^ the trait `MyTrait` is not implemented for `&dyn MyTrait` + | | + | required by a bound introduced by this call + | + = help: the trait `MyTrait` is implemented for `Outer` + +error[E0038]: the trait `MyTrait` cannot be made into an object + --> $DIR/cycle-effective-visibilities-during-object-safety.rs:20:9 + | +LL | MyTrait::foo(&self) + | ^^^^^^^^^^^^ `MyTrait` cannot be made into an object + | +note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit + --> $DIR/cycle-effective-visibilities-during-object-safety.rs:5:22 + | +LL | trait MyTrait { + | ------- this trait cannot be made into an object... +LL | fn foo(&self) -> impl Marker; + | ^^^^^^^^^^^ ...because method `foo` references an `impl Trait` type in its return type + = help: consider moving `foo` to another trait + = help: only type `Outer` implements the trait, consider using it directly instead + +error[E0277]: the trait bound `&dyn MyTrait: MyTrait` is not satisfied + --> $DIR/cycle-effective-visibilities-during-object-safety.rs:20:9 + | +LL | MyTrait::foo(&self) + | ^^^^^^^^^^^^^^^^^^^ the trait `MyTrait` is not implemented for `&dyn MyTrait` + | + = help: the trait `MyTrait` is implemented for `Outer` + +error[E0277]: the trait bound `&dyn MyTrait: MyTrait` is not satisfied + --> $DIR/cycle-effective-visibilities-during-object-safety.rs:20:9 + | +LL | MyTrait::foo(&self) + | ^^^^^^^^^^^^ the trait `MyTrait` is not implemented for `&dyn MyTrait` + | + = help: the trait `MyTrait` is implemented for `Outer` + +error: aborting due to 6 previous errors + +Some errors have detailed explanations: E0038, E0277. +For more information about an error, try `rustc --explain E0038`. diff --git a/tests/ui/issues/issue-23611-enum-swap-in-drop.rs b/tests/ui/issues/issue-23611-enum-swap-in-drop.rs index cdb130d600c5e..b967e6aecdd43 100644 --- a/tests/ui/issues/issue-23611-enum-swap-in-drop.rs +++ b/tests/ui/issues/issue-23611-enum-swap-in-drop.rs @@ -37,11 +37,9 @@ pub fn main() { // | | | +-- Make D(g_b_5, 50000005) // | | | | in g_B(b4b2) from GaspB::drop // | | | +-- Drop D(g_b_5, 50000005) - 50000005, - // | | | + 50000005, // | | | // | | +-- Drop D(GaspB::drop_3, 30000004) - 30000004, - // | | + 30000004, // | | // +-- Drop D(test_1, 10000000) 10000000, // | @@ -49,15 +47,13 @@ pub fn main() { // | | +-- Make D(f_a_4, 40000007) // | | | in f_A(a3a0) from GaspA::drop // | | +-- Drop D(f_a_4, 40000007) - 40000007, - // | | + 40000007, // | | // +-- Drop D(GaspA::drop_2, 20000006) - 20000006, - // | + 20000006, // | // +-- Drop D(drop_6, 60000002) - 60000002 - // - ]); + 60000002 // + ] + ); // For reference purposes, the old (incorrect) behavior would produce the following // output, which you can compare to the above: @@ -106,8 +102,8 @@ fn test<'a>(log: d::Log<'a>) { let _e = E::B(GaspB(g_b, 0xB4B0, log, D::new("test", 1, log)), true); } -struct GaspA<'a>(for <'b> fn(u32, &'b str, d::Log<'a>), u32, d::Log<'a>, d::D<'a>); -struct GaspB<'a>(for <'b> fn(u32, &'b str, d::Log<'a>), u32, d::Log<'a>, d::D<'a>); +struct GaspA<'a>(for<'b> fn(u32, &'b str, d::Log<'a>), u32, d::Log<'a>, d::D<'a>); +struct GaspB<'a>(for<'b> fn(u32, &'b str, d::Log<'a>), u32, d::Log<'a>, d::D<'a>); impl<'a> Drop for GaspA<'a> { fn drop(&mut self) { @@ -124,7 +120,8 @@ impl<'a> Drop for GaspB<'a> { } enum E<'a> { - A(GaspA<'a>, bool), B(GaspB<'a>, bool), + A(GaspA<'a>, bool), + B(GaspB<'a>, bool), } fn f_a(x: u32, ctxt: &str, log: d::Log) { @@ -174,9 +171,9 @@ const PREF_INDENT: u32 = 20; pub mod d { #![allow(unused_parens)] + use std::cell::RefCell; use std::fmt; use std::mem; - use std::cell::RefCell; static mut counter: u16 = 0; static mut trails: u64 = 0; @@ -189,7 +186,8 @@ pub mod d { pub fn max_width() -> u32 { unsafe { - (mem::size_of_val(&trails)*8) as u32 + (mem::size_of_val(&trails) * 8) as u32 + //~^ WARN shared reference of mutable static is discouraged [static_mut_ref] } } @@ -223,7 +221,11 @@ pub mod d { } pub struct D<'a> { - name: &'static str, i: u8, uid: u32, trail: u32, log: Log<'a> + name: &'static str, + i: u8, + uid: u32, + trail: u32, + log: Log<'a>, } impl<'a> fmt::Display for D<'a> { @@ -239,9 +241,7 @@ pub mod d { let ctr = ((i as u32) * 10_000_000) + (counter as u32); counter += 1; trails |= (1 << trail); - let ret = D { - name: name, i: i, log: log, uid: ctr, trail: trail - }; + let ret = D { name: name, i: i, log: log, uid: ctr, trail: trail }; indent_println(trail, &format!("+-- Make {}", ret)); ret } @@ -250,7 +250,9 @@ pub mod d { impl<'a> Drop for D<'a> { fn drop(&mut self) { - unsafe { trails &= !(1 << self.trail); }; + unsafe { + trails &= !(1 << self.trail); + }; self.log.borrow_mut().push(self.uid); indent_println(self.trail, &format!("+-- Drop {}", self)); indent_println(::PREF_INDENT, ""); diff --git a/tests/ui/issues/issue-23611-enum-swap-in-drop.stderr b/tests/ui/issues/issue-23611-enum-swap-in-drop.stderr new file mode 100644 index 0000000000000..14a986a333264 --- /dev/null +++ b/tests/ui/issues/issue-23611-enum-swap-in-drop.stderr @@ -0,0 +1,17 @@ +warning: shared reference of mutable static is discouraged + --> $DIR/issue-23611-enum-swap-in-drop.rs:189:31 + | +LL | (mem::size_of_val(&trails) * 8) as u32 + | ^^^^^^^ shared reference of mutable static + | + = note: for more information, see issue #114447 + = note: reference of mutable static is a hard error from 2024 edition + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior + = note: `#[warn(static_mut_ref)]` on by default +help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer + | +LL | (mem::size_of_val(addr_of!(trails)) * 8) as u32 + | ~~~~~~~~~~~~~~~~ + +warning: 1 warning emitted + diff --git a/tests/ui/mir/lint/assignment-overlap.rs b/tests/ui/mir/lint/assignment-overlap.rs new file mode 100644 index 0000000000000..0e4a11467dc8a --- /dev/null +++ b/tests/ui/mir/lint/assignment-overlap.rs @@ -0,0 +1,19 @@ +// compile-flags: --crate-type=lib -Zlint-mir -Ztreat-err-as-bug +// build-fail +// failure-status: 101 +// dont-check-compiler-stderr +// error-pattern: encountered `Assign` statement with overlapping memory +#![feature(custom_mir, core_intrinsics)] +extern crate core; +use core::intrinsics::mir::*; + +#[custom_mir(dialect = "runtime", phase = "optimized")] +pub fn main() { + mir!( + let a: [u8; 1024]; + { + a = a; + Return() + } + ) +} diff --git a/tests/ui/mir/lint/call-overlap.rs b/tests/ui/mir/lint/call-overlap.rs new file mode 100644 index 0000000000000..df38e901e7328 --- /dev/null +++ b/tests/ui/mir/lint/call-overlap.rs @@ -0,0 +1,23 @@ +// compile-flags: -Zlint-mir -Ztreat-err-as-bug +// build-fail +// failure-status: 101 +// dont-check-compiler-stderr +// error-pattern: encountered overlapping memory in `Move` arguments to `Call` +#![feature(custom_mir, core_intrinsics)] +extern crate core; +use core::intrinsics::mir::*; + +#[custom_mir(dialect = "runtime", phase = "optimized")] +pub fn main() { + mir!( + let a: [u8; 1024]; + { + Call(a = f(Move(a)), ReturnTo(bb1), UnwindUnreachable()) + } + bb1 = { + Return() + } + ) +} + +pub fn f(a: T) -> T { a } diff --git a/tests/ui/nll/borrowck-thread-local-static-mut-borrow-outlives-fn.rs b/tests/ui/nll/borrowck-thread-local-static-mut-borrow-outlives-fn.rs index 7d3b00dfc7163..8eb544e8ab9d2 100644 --- a/tests/ui/nll/borrowck-thread-local-static-mut-borrow-outlives-fn.rs +++ b/tests/ui/nll/borrowck-thread-local-static-mut-borrow-outlives-fn.rs @@ -14,9 +14,8 @@ struct S1 { impl S1 { fn new(_x: u64) -> S1 { - S1 { - a: unsafe { &mut X1 }, - } + S1 { a: unsafe { &mut X1 } } + //~^ WARN mutable reference of mutable static is discouraged [static_mut_ref] } } diff --git a/tests/ui/nll/borrowck-thread-local-static-mut-borrow-outlives-fn.stderr b/tests/ui/nll/borrowck-thread-local-static-mut-borrow-outlives-fn.stderr new file mode 100644 index 0000000000000..17217cd5859d0 --- /dev/null +++ b/tests/ui/nll/borrowck-thread-local-static-mut-borrow-outlives-fn.stderr @@ -0,0 +1,17 @@ +warning: mutable reference of mutable static is discouraged + --> $DIR/borrowck-thread-local-static-mut-borrow-outlives-fn.rs:17:26 + | +LL | S1 { a: unsafe { &mut X1 } } + | ^^^^^^^ mutable reference of mutable static + | + = note: for more information, see issue #114447 + = note: reference of mutable static is a hard error from 2024 edition + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior + = note: `#[warn(static_mut_ref)]` on by default +help: mutable references are dangerous since if there's any other pointer or reference used for that static while the reference lives, that's UB; use `addr_of_mut!` instead to create a raw pointer + | +LL | S1 { a: unsafe { addr_of_mut!(X1) } } + | ~~~~~~~~~~~~~~~~ + +warning: 1 warning emitted + diff --git a/tests/ui/static/reference-of-mut-static-safe.e2021.stderr b/tests/ui/static/reference-of-mut-static-safe.e2021.stderr new file mode 100644 index 0000000000000..c38fe8790637e --- /dev/null +++ b/tests/ui/static/reference-of-mut-static-safe.e2021.stderr @@ -0,0 +1,26 @@ +warning: shared reference of mutable static is discouraged + --> $DIR/reference-of-mut-static-safe.rs:9:14 + | +LL | let _x = &X; + | ^^ shared reference of mutable static + | + = note: for more information, see issue #114447 + = note: reference of mutable static is a hard error from 2024 edition + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior + = note: `#[warn(static_mut_ref)]` on by default +help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer + | +LL | let _x = addr_of!(X); + | ~~~~~~~~~~~ + +error[E0133]: use of mutable static is unsafe and requires unsafe function or block + --> $DIR/reference-of-mut-static-safe.rs:9:14 + | +LL | let _x = &X; + | ^^ use of mutable static + | + = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior + +error: aborting due to 1 previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0133`. diff --git a/tests/ui/static/reference-of-mut-static-safe.e2024.stderr b/tests/ui/static/reference-of-mut-static-safe.e2024.stderr new file mode 100644 index 0000000000000..53f81179de55a --- /dev/null +++ b/tests/ui/static/reference-of-mut-static-safe.e2024.stderr @@ -0,0 +1,15 @@ +error[E0796]: reference of mutable static is disallowed + --> $DIR/reference-of-mut-static-safe.rs:9:14 + | +LL | let _x = &X; + | ^^ reference of mutable static + | + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior +help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer + | +LL | let _x = addr_of!(X); + | ~~~~~~~~~~~ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0796`. diff --git a/tests/ui/static/reference-of-mut-static-safe.rs b/tests/ui/static/reference-of-mut-static-safe.rs new file mode 100644 index 0000000000000..5cb1a03bef512 --- /dev/null +++ b/tests/ui/static/reference-of-mut-static-safe.rs @@ -0,0 +1,13 @@ +// revisions: e2021 e2024 + +// [e2021] edition:2021 +// [e2024] compile-flags: --edition 2024 -Z unstable-options + +fn main() { + static mut X: i32 = 1; + + let _x = &X; + //[e2024]~^ reference of mutable static is disallowed [E0796] + //[e2021]~^^ use of mutable static is unsafe and requires unsafe function or block [E0133] + //[e2021]~^^^ shared reference of mutable static is discouraged [static_mut_ref] +} diff --git a/tests/ui/static/reference-of-mut-static-unsafe-fn.rs b/tests/ui/static/reference-of-mut-static-unsafe-fn.rs new file mode 100644 index 0000000000000..6b1e77850e50d --- /dev/null +++ b/tests/ui/static/reference-of-mut-static-unsafe-fn.rs @@ -0,0 +1,23 @@ +// compile-flags: --edition 2024 -Z unstable-options + +fn main() {} + +unsafe fn _foo() { + static mut X: i32 = 1; + static mut Y: i32 = 1; + + let _y = &X; + //~^ ERROR reference of mutable static is disallowed + + let ref _a = X; + //~^ ERROR reference of mutable static is disallowed + + let (_b, _c) = (&X, &Y); + //~^ ERROR reference of mutable static is disallowed + //~^^ ERROR reference of mutable static is disallowed + + foo(&X); + //~^ ERROR reference of mutable static is disallowed +} + +fn foo<'a>(_x: &'a i32) {} diff --git a/tests/ui/static/reference-of-mut-static-unsafe-fn.stderr b/tests/ui/static/reference-of-mut-static-unsafe-fn.stderr new file mode 100644 index 0000000000000..5c6fdedfa96f7 --- /dev/null +++ b/tests/ui/static/reference-of-mut-static-unsafe-fn.stderr @@ -0,0 +1,63 @@ +error[E0796]: reference of mutable static is disallowed + --> $DIR/reference-of-mut-static-unsafe-fn.rs:9:14 + | +LL | let _y = &X; + | ^^ reference of mutable static + | + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior +help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer + | +LL | let _y = addr_of!(X); + | ~~~~~~~~~~~ + +error[E0796]: reference of mutable static is disallowed + --> $DIR/reference-of-mut-static-unsafe-fn.rs:12:18 + | +LL | let ref _a = X; + | ^ reference of mutable static + | + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior +help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer + | +LL | let ref _a = addr_of!(X); + | ~~~~~~~~~~~ + +error[E0796]: reference of mutable static is disallowed + --> $DIR/reference-of-mut-static-unsafe-fn.rs:15:21 + | +LL | let (_b, _c) = (&X, &Y); + | ^^ reference of mutable static + | + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior +help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer + | +LL | let (_b, _c) = (addr_of!(X), &Y); + | ~~~~~~~~~~~ + +error[E0796]: reference of mutable static is disallowed + --> $DIR/reference-of-mut-static-unsafe-fn.rs:15:25 + | +LL | let (_b, _c) = (&X, &Y); + | ^^ reference of mutable static + | + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior +help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer + | +LL | let (_b, _c) = (&X, addr_of!(Y)); + | ~~~~~~~~~~~ + +error[E0796]: reference of mutable static is disallowed + --> $DIR/reference-of-mut-static-unsafe-fn.rs:19:9 + | +LL | foo(&X); + | ^^ reference of mutable static + | + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior +help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer + | +LL | foo(addr_of!(X)); + | ~~~~~~~~~~~ + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0796`. diff --git a/tests/ui/static/reference-of-mut-static.e2021.stderr b/tests/ui/static/reference-of-mut-static.e2021.stderr new file mode 100644 index 0000000000000..77a6b3d304bdb --- /dev/null +++ b/tests/ui/static/reference-of-mut-static.e2021.stderr @@ -0,0 +1,91 @@ +error: shared reference of mutable static is discouraged + --> $DIR/reference-of-mut-static.rs:16:18 + | +LL | let _y = &X; + | ^^ shared reference of mutable static + | + = note: for more information, see issue #114447 + = 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 + = 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 + = 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 + = 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 + = 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 + = note: reference of mutable static is a hard error from 2024 edition + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior +help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer + | +LL | foo(addr_of!(X)); + | ~~~~~~~~~~~ + +error: aborting due to 6 previous errors + diff --git a/tests/ui/static/reference-of-mut-static.e2024.stderr b/tests/ui/static/reference-of-mut-static.e2024.stderr new file mode 100644 index 0000000000000..f445ec65a5d24 --- /dev/null +++ b/tests/ui/static/reference-of-mut-static.e2024.stderr @@ -0,0 +1,75 @@ +error[E0796]: reference of mutable static is disallowed + --> $DIR/reference-of-mut-static.rs:16:18 + | +LL | let _y = &X; + | ^^ reference of mutable static + | + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior +help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer + | +LL | let _y = addr_of!(X); + | ~~~~~~~~~~~ + +error[E0796]: reference of mutable static is disallowed + --> $DIR/reference-of-mut-static.rs:20:18 + | +LL | let _y = &mut X; + | ^^^^^^ reference of mutable static + | + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior +help: mutable references are dangerous since if there's any other pointer or reference used for that static while the reference lives, that's UB; use `addr_of_mut!` instead to create a raw pointer + | +LL | let _y = addr_of_mut!(X); + | ~~~~~~~~~~~~~~~ + +error[E0796]: reference of mutable static is disallowed + --> $DIR/reference-of-mut-static.rs:28:22 + | +LL | let ref _a = X; + | ^ reference of mutable static + | + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior +help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer + | +LL | let ref _a = addr_of!(X); + | ~~~~~~~~~~~ + +error[E0796]: reference of mutable static is disallowed + --> $DIR/reference-of-mut-static.rs:32:25 + | +LL | let (_b, _c) = (&X, &Y); + | ^^ reference of mutable static + | + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior +help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer + | +LL | let (_b, _c) = (addr_of!(X), &Y); + | ~~~~~~~~~~~ + +error[E0796]: reference of mutable static is disallowed + --> $DIR/reference-of-mut-static.rs:32:29 + | +LL | let (_b, _c) = (&X, &Y); + | ^^ reference of mutable static + | + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior +help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer + | +LL | let (_b, _c) = (&X, addr_of!(Y)); + | ~~~~~~~~~~~ + +error[E0796]: reference of mutable static is disallowed + --> $DIR/reference-of-mut-static.rs:38:13 + | +LL | foo(&X); + | ^^ reference of mutable static + | + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior +help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer + | +LL | foo(addr_of!(X)); + | ~~~~~~~~~~~ + +error: aborting due to 6 previous errors + +For more information about this error, try `rustc --explain E0796`. diff --git a/tests/ui/static/reference-of-mut-static.rs b/tests/ui/static/reference-of-mut-static.rs new file mode 100644 index 0000000000000..01a3b1fbd9b51 --- /dev/null +++ b/tests/ui/static/reference-of-mut-static.rs @@ -0,0 +1,50 @@ +// revisions: e2021 e2024 + +// [e2021] edition:2021 +// [e2024] compile-flags: --edition 2024 -Z unstable-options + +#![deny(static_mut_ref)] + +use std::ptr::{addr_of, addr_of_mut}; + +fn main() { + static mut X: i32 = 1; + + static mut Y: i32 = 1; + + unsafe { + let _y = &X; + //[e2024]~^ ERROR reference of mutable static is disallowed + //[e2021]~^^ ERROR shared reference of mutable static is discouraged [static_mut_ref] + + let _y = &mut X; + //[e2024]~^ ERROR reference of mutable static is disallowed + //[e2021]~^^ ERROR mutable reference of mutable static is discouraged [static_mut_ref] + + let _z = addr_of_mut!(X); + + let _p = addr_of!(X); + + let ref _a = X; + //[e2024]~^ ERROR reference of mutable static is disallowed + //[e2021]~^^ ERROR shared reference of mutable static is discouraged [static_mut_ref] + + let (_b, _c) = (&X, &Y); + //[e2024]~^ ERROR reference of mutable static is disallowed + //[e2021]~^^ ERROR shared reference of mutable static is discouraged [static_mut_ref] + //[e2024]~^^^ ERROR reference of mutable static is disallowed + //[e2021]~^^^^ ERROR shared reference of mutable static is discouraged [static_mut_ref] + + foo(&X); + //[e2024]~^ ERROR reference of mutable static is disallowed + //[e2021]~^^ ERROR shared reference of mutable static is discouraged [static_mut_ref] + + static mut Z: &[i32; 3] = &[0, 1, 2]; + + let _ = Z.len(); + let _ = Z[0]; + let _ = format!("{:?}", Z); + } +} + +fn foo<'a>(_x: &'a i32) {} diff --git a/tests/ui/static/safe-extern-statics-mut.mir.stderr b/tests/ui/static/safe-extern-statics-mut.mir.stderr index cec5f9d9c9f93..7f419402e6ee8 100644 --- a/tests/ui/static/safe-extern-statics-mut.mir.stderr +++ b/tests/ui/static/safe-extern-statics-mut.mir.stderr @@ -1,3 +1,32 @@ +warning: shared reference of mutable static is discouraged + --> $DIR/safe-extern-statics-mut.rs:14:14 + | +LL | let rb = &B; + | ^^ shared reference of mutable static + | + = note: for more information, see issue #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:17:15 + | +LL | let xrb = &XB; + | ^^^ shared reference of mutable static + | + = note: for more information, see issue #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:13: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:15:14 + --> $DIR/safe-extern-statics-mut.rs:16: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:16:15 + --> $DIR/safe-extern-statics-mut.rs:17:15 | LL | let xrb = &XB; | ^^^ use of mutable static | = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior -error: aborting due to 4 previous errors +error: aborting due to 4 previous errors; 2 warnings emitted For more information about this error, try `rustc --explain E0133`. diff --git a/tests/ui/static/safe-extern-statics-mut.rs b/tests/ui/static/safe-extern-statics-mut.rs index 389a4589a7135..1943ed25035b7 100644 --- a/tests/ui/static/safe-extern-statics-mut.rs +++ b/tests/ui/static/safe-extern-statics-mut.rs @@ -12,6 +12,8 @@ extern "C" { fn main() { let b = B; //~ ERROR use of mutable static is unsafe let rb = &B; //~ ERROR use of mutable static is unsafe + //~^ WARN shared reference of mutable static is discouraged [static_mut_ref] let xb = XB; //~ ERROR use of mutable static is unsafe let xrb = &XB; //~ ERROR use of mutable static is unsafe + //~^ WARN shared reference of mutable static is discouraged [static_mut_ref] } diff --git a/tests/ui/static/safe-extern-statics-mut.thir.stderr b/tests/ui/static/safe-extern-statics-mut.thir.stderr index 8e6d2805a0ba4..f3b17fbd31843 100644 --- a/tests/ui/static/safe-extern-statics-mut.thir.stderr +++ b/tests/ui/static/safe-extern-statics-mut.thir.stderr @@ -1,3 +1,32 @@ +warning: shared reference of mutable static is discouraged + --> $DIR/safe-extern-statics-mut.rs:14:14 + | +LL | let rb = &B; + | ^^ shared reference of mutable static + | + = note: for more information, see issue #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:17:15 + | +LL | let xrb = &XB; + | ^^^ shared reference of mutable static + | + = note: for more information, see issue #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:13: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:15:14 + --> $DIR/safe-extern-statics-mut.rs:16: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:16:16 + --> $DIR/safe-extern-statics-mut.rs:17:16 | LL | let xrb = &XB; | ^^ use of mutable static | = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior -error: aborting due to 4 previous errors +error: aborting due to 4 previous errors; 2 warnings emitted For more information about this error, try `rustc --explain E0133`. diff --git a/tests/ui/statics/issue-15261.rs b/tests/ui/statics/issue-15261.rs index ec413f6d1d2be..14422329b7dc8 100644 --- a/tests/ui/statics/issue-15261.rs +++ b/tests/ui/statics/issue-15261.rs @@ -6,6 +6,7 @@ static mut n_mut: usize = 0; -static n: &'static usize = unsafe{ &n_mut }; +static n: &'static usize = unsafe { &n_mut }; +//~^ WARN shared reference of mutable static is discouraged [static_mut_ref] fn main() {} diff --git a/tests/ui/statics/issue-15261.stderr b/tests/ui/statics/issue-15261.stderr new file mode 100644 index 0000000000000..72d88ce1b3832 --- /dev/null +++ b/tests/ui/statics/issue-15261.stderr @@ -0,0 +1,17 @@ +warning: shared reference of mutable static is discouraged + --> $DIR/issue-15261.rs:9:37 + | +LL | static n: &'static usize = unsafe { &n_mut }; + | ^^^^^^ shared reference of mutable static + | + = note: for more information, see issue #114447 + = note: reference of mutable static is a hard error from 2024 edition + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior + = note: `#[warn(static_mut_ref)]` on by default +help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer + | +LL | static n: &'static usize = unsafe { addr_of!(n_mut) }; + | ~~~~~~~~~~~~~~~ + +warning: 1 warning emitted + diff --git a/tests/ui/statics/static-mut-xc.rs b/tests/ui/statics/static-mut-xc.rs index 1d172d26a5949..2fc265e02eaa3 100644 --- a/tests/ui/statics/static-mut-xc.rs +++ b/tests/ui/statics/static-mut-xc.rs @@ -7,7 +7,6 @@ // aux-build:static_mut_xc.rs - extern crate static_mut_xc; unsafe fn static_bound(_: &'static isize) {} @@ -27,7 +26,9 @@ unsafe fn run() { static_mut_xc::a = -3; assert_eq!(static_mut_xc::a, -3); static_bound(&static_mut_xc::a); + //~^ WARN shared reference of mutable static is discouraged [static_mut_ref] static_bound_set(&mut static_mut_xc::a); + //~^ WARN mutable reference of mutable static is discouraged [static_mut_ref] } pub fn main() { diff --git a/tests/ui/statics/static-mut-xc.stderr b/tests/ui/statics/static-mut-xc.stderr new file mode 100644 index 0000000000000..37aa336bc50f7 --- /dev/null +++ b/tests/ui/statics/static-mut-xc.stderr @@ -0,0 +1,31 @@ +warning: shared reference of mutable static is discouraged + --> $DIR/static-mut-xc.rs:28:18 + | +LL | static_bound(&static_mut_xc::a); + | ^^^^^^^^^^^^^^^^^ shared reference of mutable static + | + = note: for more information, see issue #114447 + = note: reference of mutable static is a hard error from 2024 edition + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior + = note: `#[warn(static_mut_ref)]` on by default +help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer + | +LL | static_bound(addr_of!(static_mut_xc::a)); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~ + +warning: mutable reference of mutable static is discouraged + --> $DIR/static-mut-xc.rs:30:22 + | +LL | static_bound_set(&mut static_mut_xc::a); + | ^^^^^^^^^^^^^^^^^^^^^ mutable reference of mutable static + | + = note: for more information, see issue #114447 + = note: reference of mutable static is a hard error from 2024 edition + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior +help: mutable references are dangerous since if there's any other pointer or reference used for that static while the reference lives, that's UB; use `addr_of_mut!` instead to create a raw pointer + | +LL | static_bound_set(addr_of_mut!(static_mut_xc::a)); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +warning: 2 warnings emitted + diff --git a/tests/ui/statics/static-recursive.rs b/tests/ui/statics/static-recursive.rs index 95dadc81f811d..216beb0206d9c 100644 --- a/tests/ui/statics/static-recursive.rs +++ b/tests/ui/statics/static-recursive.rs @@ -1,36 +1,43 @@ // run-pass + static mut S: *const u8 = unsafe { &S as *const *const u8 as *const u8 }; +//~^ WARN shared reference of mutable static is discouraged [static_mut_ref] struct StaticDoubleLinked { prev: &'static StaticDoubleLinked, next: &'static StaticDoubleLinked, data: i32, - head: bool + head: bool, } -static L1: StaticDoubleLinked = StaticDoubleLinked{prev: &L3, next: &L2, data: 1, head: true}; -static L2: StaticDoubleLinked = StaticDoubleLinked{prev: &L1, next: &L3, data: 2, head: false}; -static L3: StaticDoubleLinked = StaticDoubleLinked{prev: &L2, next: &L1, data: 3, head: false}; - +static L1: StaticDoubleLinked = StaticDoubleLinked { prev: &L3, next: &L2, data: 1, head: true }; +static L2: StaticDoubleLinked = StaticDoubleLinked { prev: &L1, next: &L3, data: 2, head: false }; +static L3: StaticDoubleLinked = StaticDoubleLinked { prev: &L2, next: &L1, data: 3, head: false }; pub fn main() { - unsafe { assert_eq!(S, *(S as *const *const u8)); } + unsafe { + assert_eq!(S, *(S as *const *const u8)); + } let mut test_vec = Vec::new(); let mut cur = &L1; loop { test_vec.push(cur.data); cur = cur.next; - if cur.head { break } + if cur.head { + break; + } } - assert_eq!(&test_vec, &[1,2,3]); + assert_eq!(&test_vec, &[1, 2, 3]); let mut test_vec = Vec::new(); let mut cur = &L1; loop { cur = cur.prev; test_vec.push(cur.data); - if cur.head { break } + if cur.head { + break; + } } - assert_eq!(&test_vec, &[3,2,1]); + assert_eq!(&test_vec, &[3, 2, 1]); } diff --git a/tests/ui/statics/static-recursive.stderr b/tests/ui/statics/static-recursive.stderr new file mode 100644 index 0000000000000..15888e5c68d84 --- /dev/null +++ b/tests/ui/statics/static-recursive.stderr @@ -0,0 +1,17 @@ +warning: shared reference of mutable static is discouraged + --> $DIR/static-recursive.rs:3:36 + | +LL | static mut S: *const u8 = unsafe { &S as *const *const u8 as *const u8 }; + | ^^ shared reference of mutable static + | + = note: for more information, see issue #114447 + = note: reference of mutable static is a hard error from 2024 edition + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior + = note: `#[warn(static_mut_ref)]` on by default +help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer + | +LL | static mut S: *const u8 = unsafe { addr_of!(S) as *const *const u8 as *const u8 }; + | ~~~~~~~~~~~ + +warning: 1 warning emitted + diff --git a/tests/ui/thread-local/thread-local-static.mir.stderr b/tests/ui/thread-local/thread-local-static.mir.stderr index 607d7ee902cb6..2043b268c090c 100644 --- a/tests/ui/thread-local/thread-local-static.mir.stderr +++ b/tests/ui/thread-local/thread-local-static.mir.stderr @@ -1,3 +1,18 @@ +warning: mutable reference of mutable static is discouraged + --> $DIR/thread-local-static.rs:12:23 + | +LL | std::mem::swap(x, &mut STATIC_VAR_2) + | ^^^^^^^^^^^^^^^^^ mutable reference of mutable static + | + = note: for more information, see issue #114447 + = note: reference of mutable static is a hard error from 2024 edition + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior + = note: `#[warn(static_mut_ref)]` on by default +help: mutable references are dangerous since if there's any other pointer or reference used for that static while the reference lives, that's UB; use `addr_of_mut!` instead to create a raw pointer + | +LL | std::mem::swap(x, addr_of_mut!(STATIC_VAR_2)) + | ~~~~~~~~~~~~~~~~~~~~~~~~~~ + error[E0658]: mutable references are not allowed in constant functions --> $DIR/thread-local-static.rs:10:12 | @@ -38,7 +53,7 @@ LL | std::mem::swap(x, &mut STATIC_VAR_2) | = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior -error: aborting due to 5 previous errors +error: aborting due to 5 previous errors; 1 warning emitted Some errors have detailed explanations: E0013, E0133, E0625, E0658. For more information about an error, try `rustc --explain E0013`. diff --git a/tests/ui/thread-local/thread-local-static.rs b/tests/ui/thread-local/thread-local-static.rs index afaffbb7e9bbf..9b5200fe5ba9f 100644 --- a/tests/ui/thread-local/thread-local-static.rs +++ b/tests/ui/thread-local/thread-local-static.rs @@ -10,7 +10,8 @@ static mut STATIC_VAR_2: [u32; 8] = [4; 8]; const fn g(x: &mut [u32; 8]) { //~^ ERROR mutable references are not allowed std::mem::swap(x, &mut STATIC_VAR_2) - //~^ ERROR thread-local statics cannot be accessed + //~^ WARN mutable reference of mutable static is discouraged [static_mut_ref] + //~^^ ERROR thread-local statics cannot be accessed //~| ERROR mutable references are not allowed //~| ERROR use of mutable static is unsafe //~| constant functions cannot refer to statics diff --git a/tests/ui/thread-local/thread-local-static.thir.stderr b/tests/ui/thread-local/thread-local-static.thir.stderr index 607d7ee902cb6..2043b268c090c 100644 --- a/tests/ui/thread-local/thread-local-static.thir.stderr +++ b/tests/ui/thread-local/thread-local-static.thir.stderr @@ -1,3 +1,18 @@ +warning: mutable reference of mutable static is discouraged + --> $DIR/thread-local-static.rs:12:23 + | +LL | std::mem::swap(x, &mut STATIC_VAR_2) + | ^^^^^^^^^^^^^^^^^ mutable reference of mutable static + | + = note: for more information, see issue #114447 + = note: reference of mutable static is a hard error from 2024 edition + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior + = note: `#[warn(static_mut_ref)]` on by default +help: mutable references are dangerous since if there's any other pointer or reference used for that static while the reference lives, that's UB; use `addr_of_mut!` instead to create a raw pointer + | +LL | std::mem::swap(x, addr_of_mut!(STATIC_VAR_2)) + | ~~~~~~~~~~~~~~~~~~~~~~~~~~ + error[E0658]: mutable references are not allowed in constant functions --> $DIR/thread-local-static.rs:10:12 | @@ -38,7 +53,7 @@ LL | std::mem::swap(x, &mut STATIC_VAR_2) | = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior -error: aborting due to 5 previous errors +error: aborting due to 5 previous errors; 1 warning emitted Some errors have detailed explanations: E0013, E0133, E0625, E0658. For more information about an error, try `rustc --explain E0013`. diff --git a/tests/ui/traits/negative-bounds/associated-constraints.rs b/tests/ui/traits/negative-bounds/associated-constraints.rs index bc1a0ef170837..4a7132ccde917 100644 --- a/tests/ui/traits/negative-bounds/associated-constraints.rs +++ b/tests/ui/traits/negative-bounds/associated-constraints.rs @@ -1,5 +1,4 @@ #![feature(negative_bounds, associated_type_bounds)] -//~^ WARN the feature `negative_bounds` is incomplete and may not be safe to use and/or cause compiler crashes trait Trait { type Assoc; @@ -17,4 +16,7 @@ fn test3>() {} fn test4() where T: !Trait {} //~^ ERROR associated type constraints not allowed on negative bounds +fn test5() where T: !Fn() -> i32 {} +//~^ ERROR parenthetical notation may not be used for negative bounds + fn main() {} diff --git a/tests/ui/traits/negative-bounds/associated-constraints.stderr b/tests/ui/traits/negative-bounds/associated-constraints.stderr index 335ac7e5ad903..c1a6d2ca6a2e2 100644 --- a/tests/ui/traits/negative-bounds/associated-constraints.stderr +++ b/tests/ui/traits/negative-bounds/associated-constraints.stderr @@ -1,34 +1,32 @@ error: associated type constraints not allowed on negative bounds - --> $DIR/associated-constraints.rs:8:19 + --> $DIR/associated-constraints.rs:7:19 | LL | fn test>() {} | ^^^^^^^^^^^ error: associated type constraints not allowed on negative bounds - --> $DIR/associated-constraints.rs:11:31 + --> $DIR/associated-constraints.rs:10:31 | LL | fn test2() where T: !Trait {} | ^^^^^^^^^^^ error: associated type constraints not allowed on negative bounds - --> $DIR/associated-constraints.rs:14:20 + --> $DIR/associated-constraints.rs:13:20 | LL | fn test3>() {} | ^^^^^^^^^^^ error: associated type constraints not allowed on negative bounds - --> $DIR/associated-constraints.rs:17:31 + --> $DIR/associated-constraints.rs:16:31 | LL | fn test4() where T: !Trait {} | ^^^^^^^^^^^ -warning: the feature `negative_bounds` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/associated-constraints.rs:1:12 +error: parenthetical notation may not be used for negative bounds + --> $DIR/associated-constraints.rs:19:25 | -LL | #![feature(negative_bounds, associated_type_bounds)] - | ^^^^^^^^^^^^^^^ - | - = note: `#[warn(incomplete_features)]` on by default +LL | fn test5() where T: !Fn() -> i32 {} + | ^^^^^^^^^^^ -error: aborting due to 4 previous errors; 1 warning emitted +error: aborting due to 5 previous errors diff --git a/tests/ui/traits/negative-bounds/opaque-type-unsatisfied-bound.rs b/tests/ui/traits/negative-bounds/opaque-type-unsatisfied-bound.rs new file mode 100644 index 0000000000000..e1e93f7992065 --- /dev/null +++ b/tests/ui/traits/negative-bounds/opaque-type-unsatisfied-bound.rs @@ -0,0 +1,23 @@ +// compile-flags: -Znext-solver + +#![feature(negative_bounds, negative_impls)] + +trait Trait {} +impl !Trait for () {} + +fn produce() -> impl !Trait {} +fn consume(_: impl Trait) {} + +fn main() { + consume(produce()); //~ ERROR the trait bound `impl !Trait: Trait` is not satisfied +} + +fn weird0() -> impl Sized + !Sized {} +//~^ ERROR mismatched types +//~| ERROR type mismatch resolving `() == impl !Sized + Sized` +fn weird1() -> impl !Sized + Sized {} +//~^ ERROR mismatched types +//~| ERROR type mismatch resolving `() == impl !Sized + Sized` +fn weird2() -> impl !Sized {} +//~^ ERROR mismatched types +//~| ERROR type mismatch resolving `() == impl !Sized` diff --git a/tests/ui/traits/negative-bounds/opaque-type-unsatisfied-bound.stderr b/tests/ui/traits/negative-bounds/opaque-type-unsatisfied-bound.stderr new file mode 100644 index 0000000000000..627927618707f --- /dev/null +++ b/tests/ui/traits/negative-bounds/opaque-type-unsatisfied-bound.stderr @@ -0,0 +1,69 @@ +error[E0308]: mismatched types + --> $DIR/opaque-type-unsatisfied-bound.rs:15:36 + | +LL | fn weird0() -> impl Sized + !Sized {} + | ------------------- ^^ types differ + | | + | the expected opaque type + | + = note: expected opaque type `impl !Sized + Sized` + found unit type `()` + +error[E0271]: type mismatch resolving `() == impl !Sized + Sized` + --> $DIR/opaque-type-unsatisfied-bound.rs:15:16 + | +LL | fn weird0() -> impl Sized + !Sized {} + | ^^^^^^^^^^^^^^^^^^^ types differ + +error[E0308]: mismatched types + --> $DIR/opaque-type-unsatisfied-bound.rs:18:36 + | +LL | fn weird1() -> impl !Sized + Sized {} + | ------------------- ^^ types differ + | | + | the expected opaque type + | + = note: expected opaque type `impl !Sized + Sized` + found unit type `()` + +error[E0271]: type mismatch resolving `() == impl !Sized + Sized` + --> $DIR/opaque-type-unsatisfied-bound.rs:18:16 + | +LL | fn weird1() -> impl !Sized + Sized {} + | ^^^^^^^^^^^^^^^^^^^ types differ + +error[E0308]: mismatched types + --> $DIR/opaque-type-unsatisfied-bound.rs:21:28 + | +LL | fn weird2() -> impl !Sized {} + | ----------- ^^ types differ + | | + | the expected opaque type + | + = note: expected opaque type `impl !Sized` + found unit type `()` + +error[E0271]: type mismatch resolving `() == impl !Sized` + --> $DIR/opaque-type-unsatisfied-bound.rs:21:16 + | +LL | fn weird2() -> impl !Sized {} + | ^^^^^^^^^^^ types differ + +error[E0277]: the trait bound `impl !Trait: Trait` is not satisfied + --> $DIR/opaque-type-unsatisfied-bound.rs:12:13 + | +LL | consume(produce()); + | ------- ^^^^^^^^^ the trait `Trait` is not implemented for `impl !Trait` + | | + | required by a bound introduced by this call + | +note: required by a bound in `consume` + --> $DIR/opaque-type-unsatisfied-bound.rs:9:20 + | +LL | fn consume(_: impl Trait) {} + | ^^^^^ required by this bound in `consume` + +error: aborting due to 7 previous errors + +Some errors have detailed explanations: E0271, E0277, E0308. +For more information about an error, try `rustc --explain E0271`. diff --git a/tests/ui/traits/negative-bounds/opaque-type-unsatisfied-fn-bound.rs b/tests/ui/traits/negative-bounds/opaque-type-unsatisfied-fn-bound.rs new file mode 100644 index 0000000000000..72bca1a8910b5 --- /dev/null +++ b/tests/ui/traits/negative-bounds/opaque-type-unsatisfied-fn-bound.rs @@ -0,0 +1,9 @@ +// compile-flags: -Znext-solver + +#![feature(negative_bounds, unboxed_closures)] + +fn produce() -> impl !Fn<(u32,)> {} +//~^ ERROR mismatched types +//~| ERROR type mismatch resolving `() == impl !Fn<(u32,)>` + +fn main() {} diff --git a/tests/ui/traits/negative-bounds/opaque-type-unsatisfied-fn-bound.stderr b/tests/ui/traits/negative-bounds/opaque-type-unsatisfied-fn-bound.stderr new file mode 100644 index 0000000000000..a4fb4b2b5c47f --- /dev/null +++ b/tests/ui/traits/negative-bounds/opaque-type-unsatisfied-fn-bound.stderr @@ -0,0 +1,21 @@ +error[E0308]: mismatched types + --> $DIR/opaque-type-unsatisfied-fn-bound.rs:5:34 + | +LL | fn produce() -> impl !Fn<(u32,)> {} + | ---------------- ^^ types differ + | | + | the expected opaque type + | + = note: expected opaque type `impl !Fn<(u32,)>` + found unit type `()` + +error[E0271]: type mismatch resolving `() == impl !Fn<(u32,)>` + --> $DIR/opaque-type-unsatisfied-fn-bound.rs:5:17 + | +LL | fn produce() -> impl !Fn<(u32,)> {} + | ^^^^^^^^^^^^^^^^ types differ + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0271, E0308. +For more information about an error, try `rustc --explain E0271`. diff --git a/tests/ui/traits/negative-bounds/simple.rs b/tests/ui/traits/negative-bounds/simple.rs index f6d1d5169c4fc..a2febf353f6d3 100644 --- a/tests/ui/traits/negative-bounds/simple.rs +++ b/tests/ui/traits/negative-bounds/simple.rs @@ -1,5 +1,4 @@ #![feature(negative_bounds, negative_impls)] -//~^ WARN the feature `negative_bounds` is incomplete and may not be safe to use and/or cause compiler crashes fn not_copy() {} diff --git a/tests/ui/traits/negative-bounds/simple.stderr b/tests/ui/traits/negative-bounds/simple.stderr index a3cab41a2ce0f..6d750739e197c 100644 --- a/tests/ui/traits/negative-bounds/simple.stderr +++ b/tests/ui/traits/negative-bounds/simple.stderr @@ -1,44 +1,36 @@ -warning: the feature `negative_bounds` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/simple.rs:1:12 - | -LL | #![feature(negative_bounds, negative_impls)] - | ^^^^^^^^^^^^^^^ - | - = note: `#[warn(incomplete_features)]` on by default - error[E0277]: the trait bound `T: !Copy` is not satisfied - --> $DIR/simple.rs:11:16 + --> $DIR/simple.rs:10:16 | LL | not_copy::(); | ^ the trait `!Copy` is not implemented for `T` | note: required by a bound in `not_copy` - --> $DIR/simple.rs:4:16 + --> $DIR/simple.rs:3:16 | LL | fn not_copy() {} | ^^^^^ required by this bound in `not_copy` error[E0277]: the trait bound `T: !Copy` is not satisfied - --> $DIR/simple.rs:16:16 + --> $DIR/simple.rs:15:16 | LL | not_copy::(); | ^ the trait `!Copy` is not implemented for `T` | note: required by a bound in `not_copy` - --> $DIR/simple.rs:4:16 + --> $DIR/simple.rs:3:16 | LL | fn not_copy() {} | ^^^^^ required by this bound in `not_copy` error[E0277]: the trait bound `Copyable: !Copy` is not satisfied - --> $DIR/simple.rs:31:16 + --> $DIR/simple.rs:30:16 | LL | not_copy::(); | ^^^^^^^^ the trait `!Copy` is not implemented for `Copyable` | = help: the trait `Copy` is implemented for `Copyable` note: required by a bound in `not_copy` - --> $DIR/simple.rs:4:16 + --> $DIR/simple.rs:3:16 | LL | fn not_copy() {} | ^^^^^ required by this bound in `not_copy` @@ -49,13 +41,13 @@ LL | struct Copyable; | error[E0277]: the trait bound `NotNecessarilyCopyable: !Copy` is not satisfied - --> $DIR/simple.rs:38:16 + --> $DIR/simple.rs:37:16 | LL | not_copy::(); | ^^^^^^^^^^^^^^^^^^^^^^ the trait `!Copy` is not implemented for `NotNecessarilyCopyable` | note: required by a bound in `not_copy` - --> $DIR/simple.rs:4:16 + --> $DIR/simple.rs:3:16 | LL | fn not_copy() {} | ^^^^^ required by this bound in `not_copy` @@ -65,6 +57,6 @@ LL + #[derive(Copy)] LL | struct NotNecessarilyCopyable; | -error: aborting due to 4 previous errors; 1 warning emitted +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/negative-bounds/supertrait.rs b/tests/ui/traits/negative-bounds/supertrait.rs index df0884b8b9f16..a66bc4a60a08e 100644 --- a/tests/ui/traits/negative-bounds/supertrait.rs +++ b/tests/ui/traits/negative-bounds/supertrait.rs @@ -1,7 +1,6 @@ // check-pass #![feature(negative_bounds)] -//~^ WARN the feature `negative_bounds` is incomplete trait A: !B {} trait B: !A {} diff --git a/tests/ui/traits/negative-bounds/supertrait.stderr b/tests/ui/traits/negative-bounds/supertrait.stderr deleted file mode 100644 index f44753b624e3f..0000000000000 --- a/tests/ui/traits/negative-bounds/supertrait.stderr +++ /dev/null @@ -1,10 +0,0 @@ -warning: the feature `negative_bounds` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/supertrait.rs:3:12 - | -LL | #![feature(negative_bounds)] - | ^^^^^^^^^^^^^^^ - | - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/type-alias-impl-trait/nested-in-anon-const.rs b/tests/ui/type-alias-impl-trait/nested-in-anon-const.rs new file mode 100644 index 0000000000000..e9d53c99d041b --- /dev/null +++ b/tests/ui/type-alias-impl-trait/nested-in-anon-const.rs @@ -0,0 +1,21 @@ +// Regression test for issue #119295. + +#![feature(type_alias_impl_trait)] + +type Bar = T; +type S = [i32; A]; + +extern "C" { + pub fn lint_me( + x: Bar< + S< + { //~ ERROR mismatched types + type B = impl Sized; + //~^ ERROR unconstrained opaque type + }, + >, + >, + ); +} + +fn main() {} diff --git a/tests/ui/type-alias-impl-trait/nested-in-anon-const.stderr b/tests/ui/type-alias-impl-trait/nested-in-anon-const.stderr new file mode 100644 index 0000000000000..aa0c1076117cc --- /dev/null +++ b/tests/ui/type-alias-impl-trait/nested-in-anon-const.stderr @@ -0,0 +1,20 @@ +error[E0308]: mismatched types + --> $DIR/nested-in-anon-const.rs:12:17 + | +LL | / { +LL | | type B = impl Sized; +LL | | +LL | | }, + | |_________________^ expected `usize`, found `()` + +error: unconstrained opaque type + --> $DIR/nested-in-anon-const.rs:13:33 + | +LL | type B = impl Sized; + | ^^^^^^^^^^ + | + = note: `B` must be used in combination with a concrete type within the same item + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`.