Auto merge of #123322 - matthewjasper:remove-mir-unsafeck, r=lcnr,compiler-errors

Remove MIR unsafe check

Now that THIR unsafeck is enabled by default in stable I think we can remove MIR unsafeck entirely. This PR also removes safety information from MIR.
This commit is contained in:
bors 2024-04-03 10:30:34 +00:00
commit 99c42d2340
194 changed files with 667 additions and 2238 deletions

View file

@ -748,9 +748,6 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> {
sess.time("MIR_effect_checking", || {
for def_id in tcx.hir().body_owners() {
if !tcx.sess.opts.unstable_opts.thir_unsafeck {
rustc_mir_transform::check_unsafety::check_unsafety(tcx, def_id);
}
tcx.ensure().has_ffi_unwind_calls(def_id);
// If we need to codegen, ensure that we emit all errors from

View file

@ -840,7 +840,6 @@ macro_rules! tracked {
tracked!(stack_protector, StackProtector::All);
tracked!(teach, true);
tracked!(thinlto, Some(true));
tracked!(thir_unsafeck, false);
tracked!(tiny_const_eval_limit, true);
tracked!(tls_model, Some(TlsModel::GeneralDynamic));
tracked!(translate_remapped_path_to_local_path, false);

View file

@ -35,7 +35,6 @@ macro_rules! arena_types {
)>,
[] crate_for_resolver: rustc_data_structures::steal::Steal<(rustc_ast::Crate, rustc_ast::AttrVec)>,
[] resolutions: rustc_middle::ty::ResolverGlobalCtxt,
[decode] unsafety_check_result: rustc_middle::mir::UnsafetyCheckResult,
[decode] code_region: rustc_middle::mir::coverage::CodeRegion,
[] const_allocs: rustc_middle::mir::interpret::Allocation,
[] region_scope_tree: rustc_middle::middle::region::ScopeTree,

View file

@ -845,17 +845,6 @@ pub fn caller_location_span<T>(
}
}
#[derive(Copy, Clone, PartialEq, Eq, Debug, TyEncodable, TyDecodable, HashStable)]
pub enum Safety {
Safe,
/// Unsafe because of compiler-generated unsafe code, like `await` desugaring
BuiltinUnsafe,
/// Unsafe because of an unsafe fn
FnUnsafe,
/// Unsafe because of an `unsafe` block
ExplicitUnsafe(hir::HirId),
}
impl<'tcx> Index<BasicBlock> for Body<'tcx> {
type Output = BasicBlockData<'tcx>;
@ -1611,8 +1600,6 @@ pub struct SourceScopeData<'tcx> {
pub struct SourceScopeLocalData {
/// An `HirId` with lint levels equivalent to this scope's lint levels.
pub lint_root: hir::HirId,
/// The unsafe block that contains this node.
pub safety: Safety,
}
/// A collection of projections into user types.
@ -1888,7 +1875,7 @@ mod size_asserts {
// tidy-alphabetical-start
static_assert_size!(BasicBlockData<'_>, 144);
static_assert_size!(LocalDecl<'_>, 40);
static_assert_size!(SourceScopeData<'_>, 72);
static_assert_size!(SourceScopeData<'_>, 64);
static_assert_size!(Statement<'_>, 32);
static_assert_size!(StatementKind<'_>, 16);
static_assert_size!(Terminator<'_>, 112);

View file

@ -3,9 +3,7 @@
use crate::mir;
use crate::ty::{self, OpaqueHiddenType, Ty, TyCtxt};
use rustc_data_structures::fx::FxIndexMap;
use rustc_data_structures::unord::UnordSet;
use rustc_errors::ErrorGuaranteed;
use rustc_hir as hir;
use rustc_hir::def_id::LocalDefId;
use rustc_index::bit_set::BitMatrix;
use rustc_index::{Idx, IndexVec};
@ -18,67 +16,6 @@
use super::{ConstValue, SourceInfo};
#[derive(Copy, Clone, PartialEq, TyEncodable, TyDecodable, HashStable, Debug)]
pub enum UnsafetyViolationKind {
/// Unsafe operation outside `unsafe`.
General,
/// Unsafe operation in an `unsafe fn` but outside an `unsafe` block.
/// Has to be handled as a lint for backwards compatibility.
UnsafeFn,
}
#[derive(Clone, PartialEq, TyEncodable, TyDecodable, HashStable, Debug)]
pub enum UnsafetyViolationDetails {
CallToUnsafeFunction,
UseOfInlineAssembly,
InitializingTypeWith,
CastOfPointerToInt,
UseOfMutableStatic,
UseOfExternStatic,
DerefOfRawPointer,
AccessToUnionField,
MutationOfLayoutConstrainedField,
BorrowOfLayoutConstrainedField,
CallToFunctionWith {
/// Target features enabled in callee's `#[target_feature]` but missing in
/// caller's `#[target_feature]`.
missing: Vec<Symbol>,
/// Target features in `missing` that are enabled at compile time
/// (e.g., with `-C target-feature`).
build_enabled: Vec<Symbol>,
},
}
#[derive(Clone, PartialEq, TyEncodable, TyDecodable, HashStable, Debug)]
pub struct UnsafetyViolation {
pub source_info: SourceInfo,
pub lint_root: hir::HirId,
pub kind: UnsafetyViolationKind,
pub details: UnsafetyViolationDetails,
}
#[derive(Copy, Clone, PartialEq, TyEncodable, TyDecodable, HashStable, Debug)]
pub enum UnusedUnsafe {
/// `unsafe` block contains no unsafe operations
/// > ``unnecessary `unsafe` block``
Unused,
/// `unsafe` block nested under another (used) `unsafe` block
/// > ``… because it's nested under this `unsafe` block``
InUnsafeBlock(hir::HirId),
}
#[derive(TyEncodable, TyDecodable, HashStable, Debug)]
pub struct UnsafetyCheckResult {
/// Violations that are propagated *upwards* from this function.
pub violations: Vec<UnsafetyViolation>,
/// Used `unsafe` blocks in this function. This is used for the "unused_unsafe" lint.
pub used_unsafe_blocks: UnordSet<hir::HirId>,
/// This is `Some` iff the item is not a closure.
pub unused_unsafes: Option<Vec<(hir::HirId, UnusedUnsafe)>>,
}
rustc_index::newtype_index! {
#[derive(HashStable)]
#[encodable]

View file

@ -877,12 +877,6 @@
desc { |tcx| "collecting all inherent impls for `{:?}`", key }
}
/// The result of unsafety-checking this `LocalDefId` with the old checker.
query mir_unsafety_check_result(key: LocalDefId) -> &'tcx mir::UnsafetyCheckResult {
desc { |tcx| "unsafety-checking `{}`", tcx.def_path_str(key) }
cache_on_disk_if { true }
}
/// Unsafety-check this `LocalDefId`.
query check_unsafety(key: LocalDefId) {
desc { |tcx| "unsafety-checking `{}`", tcx.def_path_str(key) }

View file

@ -458,7 +458,6 @@ fn decode(decoder: &mut D) -> &'tcx Self {
&'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
&'tcx traits::ImplSource<'tcx, ()>,
&'tcx mir::Body<'tcx>,
&'tcx mir::UnsafetyCheckResult,
&'tcx mir::BorrowCheckResult<'tcx>,
&'tcx mir::coverage::CodeRegion,
&'tcx ty::List<ty::BoundVariableKind>,

View file

@ -13,31 +13,15 @@ pub(crate) fn ast_block(
ast_block: BlockId,
source_info: SourceInfo,
) -> BlockAnd<()> {
let Block { region_scope, span, ref stmts, expr, targeted_by_break, safety_mode } =
let Block { region_scope, span, ref stmts, expr, targeted_by_break, safety_mode: _ } =
self.thir[ast_block];
self.in_scope((region_scope, source_info), LintLevel::Inherited, move |this| {
if targeted_by_break {
this.in_breakable_scope(None, destination, span, |this| {
Some(this.ast_block_stmts(
destination,
block,
span,
stmts,
expr,
safety_mode,
region_scope,
))
Some(this.ast_block_stmts(destination, block, span, stmts, expr, region_scope))
})
} else {
this.ast_block_stmts(
destination,
block,
span,
stmts,
expr,
safety_mode,
region_scope,
)
this.ast_block_stmts(destination, block, span, stmts, expr, region_scope)
}
})
}
@ -49,7 +33,6 @@ fn ast_block_stmts(
span: Span,
stmts: &[StmtId],
expr: Option<ExprId>,
safety_mode: BlockSafety,
region_scope: Scope,
) -> BlockAnd<()> {
let this = self;
@ -72,13 +55,11 @@ fn ast_block_stmts(
// First we build all the statements in the block.
let mut let_scope_stack = Vec::with_capacity(8);
let outer_source_scope = this.source_scope;
let outer_in_scope_unsafe = this.in_scope_unsafe;
// This scope information is kept for breaking out of the parent remainder scope in case
// one let-else pattern matching fails.
// By doing so, we can be sure that even temporaries that receive extended lifetime
// assignments are dropped, too.
let mut last_remainder_scope = region_scope;
this.update_source_scope_for_safety_mode(span, safety_mode);
let source_info = this.source_info(span);
for stmt in stmts {
@ -202,7 +183,7 @@ fn ast_block_stmts(
let_scope_stack.push(remainder_scope);
let visibility_scope =
Some(this.new_source_scope(remainder_span, LintLevel::Inherited, None));
Some(this.new_source_scope(remainder_span, LintLevel::Inherited));
let initializer_span = this.thir[*initializer].span;
let scope = (*init_scope, source_info);
@ -271,7 +252,7 @@ fn ast_block_stmts(
let remainder_span = remainder_scope.span(this.tcx, this.region_scope_tree);
let visibility_scope =
Some(this.new_source_scope(remainder_span, LintLevel::Inherited, None));
Some(this.new_source_scope(remainder_span, LintLevel::Inherited));
// Evaluate the initializer, if present.
if let Some(init) = *initializer {
@ -364,22 +345,6 @@ fn ast_block_stmts(
}
// Restore the original source scope.
this.source_scope = outer_source_scope;
this.in_scope_unsafe = outer_in_scope_unsafe;
block.unit()
}
/// If we are entering an unsafe block, create a new source scope
fn update_source_scope_for_safety_mode(&mut self, span: Span, safety_mode: BlockSafety) {
debug!("update_source_scope_for({:?}, {:?})", span, safety_mode);
let new_unsafety = match safety_mode {
BlockSafety::Safe => return,
BlockSafety::BuiltinUnsafe => Safety::BuiltinUnsafe,
BlockSafety::ExplicitUnsafe(hir_id) => {
self.in_scope_unsafe = Safety::ExplicitUnsafe(hir_id);
Safety::ExplicitUnsafe(hir_id)
}
};
self.source_scope = self.new_source_scope(span, LintLevel::Inherited, Some(new_unsafety));
}
}

View file

@ -72,10 +72,7 @@ pub(super) fn build_custom_mir<'tcx>(
parent_scope: None,
inlined: None,
inlined_parent_scope: None,
local_data: ClearCrossCrate::Set(SourceScopeLocalData {
lint_root: hir_id,
safety: Safety::Safe,
}),
local_data: ClearCrossCrate::Set(SourceScopeLocalData { lint_root: hir_id }),
});
body.injection_phase = Some(parse_attribute(attr));

View file

@ -118,19 +118,12 @@ pub(crate) fn as_rvalue(
ExprKind::Box { value } => {
let value_ty = this.thir[value].ty;
let tcx = this.tcx;
// `exchange_malloc` is unsafe but box is safe, so need a new scope.
let synth_scope = this.new_source_scope(
expr_span,
LintLevel::Inherited,
Some(Safety::BuiltinUnsafe),
);
let synth_info = SourceInfo { span: expr_span, scope: synth_scope };
let source_info = this.source_info(expr_span);
let size = this.temp(tcx.types.usize, expr_span);
this.cfg.push_assign(
block,
synth_info,
source_info,
size,
Rvalue::NullaryOp(NullOp::SizeOf, value_ty),
);
@ -138,7 +131,7 @@ pub(crate) fn as_rvalue(
let align = this.temp(tcx.types.usize, expr_span);
this.cfg.push_assign(
block,
synth_info,
source_info,
align,
Rvalue::NullaryOp(NullOp::AlignOf, value_ty),
);
@ -154,7 +147,7 @@ pub(crate) fn as_rvalue(
let success = this.cfg.start_new_block();
this.cfg.terminate(
block,
synth_info,
source_info,
TerminatorKind::Call {
func: exchange_malloc,
args: vec![

View file

@ -69,7 +69,7 @@ pub(crate) fn expr_into_dest(
// FIXME: Does this need extra logic to handle let-chains?
let source_info = if this.is_let(cond) {
let variable_scope =
this.new_source_scope(then_span, LintLevel::Inherited, None);
this.new_source_scope(then_span, LintLevel::Inherited);
this.source_scope = variable_scope;
SourceInfo { span: then_span, scope: variable_scope }
} else {

View file

@ -732,7 +732,7 @@ pub(crate) fn declare_bindings(
&mut |this, name, mode, var, span, ty, user_ty| {
if visibility_scope.is_none() {
visibility_scope =
Some(this.new_source_scope(scope_span, LintLevel::Inherited, None));
Some(this.new_source_scope(scope_span, LintLevel::Inherited));
}
let source_info = SourceInfo { span, scope: this.source_scope };
let visibility_scope = visibility_scope.unwrap();

View file

@ -66,17 +66,10 @@ pub(crate) fn mir_build<'tcx>(tcx: TyCtxtAt<'tcx>, def: LocalDefId) -> Body<'tcx
// maybe move the check to a MIR pass?
tcx.ensure().check_liveness(def);
if tcx.sess.opts.unstable_opts.thir_unsafeck {
// Don't steal here if THIR unsafeck is being used. Instead
// steal in unsafeck. This is so that pattern inline constants
// can be evaluated as part of building the THIR of the parent
// function without a cycle.
build_mir(&thir.borrow())
} else {
// We ran all queries that depended on THIR at the beginning
// of `mir_build`, so now we can steal it
build_mir(&thir.steal())
}
// Don't steal here, instead steal in unsafeck. This is so that
// pattern inline constants can be evaluated as part of building the
// THIR of the parent function without a cycle.
build_mir(&thir.borrow())
}
};
@ -190,9 +183,6 @@ struct Builder<'a, 'tcx> {
/// `{ STMTS; EXPR1 } + EXPR2`.
block_context: BlockContext,
/// The current unsafe block in scope
in_scope_unsafe: Safety,
/// The vector of all scopes that we have created thus far;
/// we track this for debuginfo later.
source_scopes: IndexVec<SourceScope, SourceScopeData<'tcx>>,
@ -470,11 +460,6 @@ fn construct_fn<'tcx>(
.output
.span();
let safety = match fn_sig.unsafety {
hir::Unsafety::Normal => Safety::Safe,
hir::Unsafety::Unsafe => Safety::FnUnsafe,
};
let mut abi = fn_sig.abi;
if let DefKind::Closure = tcx.def_kind(fn_def) {
// HACK(eddyb) Avoid having RustCall on closures,
@ -520,7 +505,6 @@ fn construct_fn<'tcx>(
fn_id,
span_with_body,
arguments.len(),
safety,
return_ty,
return_ty_span,
coroutine,
@ -590,18 +574,8 @@ fn construct_const<'a, 'tcx>(
};
let infcx = tcx.infer_ctxt().build();
let mut builder = Builder::new(
thir,
infcx,
def,
hir_id,
span,
0,
Safety::Safe,
const_ty,
const_ty_span,
None,
);
let mut builder =
Builder::new(thir, infcx, def, hir_id, span, 0, const_ty, const_ty_span, None);
let mut block = START_BLOCK;
unpack!(block = builder.expr_into_dest(Place::return_place(), block, expr));
@ -723,10 +697,7 @@ fn construct_error(tcx: TyCtxt<'_>, def_id: LocalDefId, guar: ErrorGuaranteed) -
parent_scope: None,
inlined: None,
inlined_parent_scope: None,
local_data: ClearCrossCrate::Set(SourceScopeLocalData {
lint_root: hir_id,
safety: Safety::Safe,
}),
local_data: ClearCrossCrate::Set(SourceScopeLocalData { lint_root: hir_id }),
});
cfg.terminate(START_BLOCK, source_info, TerminatorKind::Unreachable);
@ -753,7 +724,6 @@ fn new(
hir_id: hir::HirId,
span: Span,
arg_count: usize,
safety: Safety,
return_ty: Ty<'tcx>,
return_span: Span,
coroutine: Option<Box<CoroutineInfo<'tcx>>>,
@ -795,7 +765,6 @@ fn new(
guard_context: vec![],
fixed_temps: Default::default(),
fixed_temps_scope: None,
in_scope_unsafe: safety,
local_decls: IndexVec::from_elem_n(LocalDecl::new(return_ty, return_span), 1),
canonical_user_type_annotations: IndexVec::new(),
upvars: CaptureMap::new(),
@ -807,10 +776,7 @@ fn new(
};
assert_eq!(builder.cfg.start_new_block(), START_BLOCK);
assert_eq!(
builder.new_source_scope(span, lint_level, Some(safety)),
OUTERMOST_SOURCE_SCOPE
);
assert_eq!(builder.new_source_scope(span, lint_level), OUTERMOST_SOURCE_SCOPE);
builder.source_scopes[OUTERMOST_SOURCE_SCOPE].parent_scope = None;
builder
@ -1024,7 +990,7 @@ fn set_correct_source_scope_for_arg(
.as_ref()
.assert_crate_local()
.lint_root;
self.maybe_new_source_scope(pattern_span, None, arg_hir_id, parent_id);
self.maybe_new_source_scope(pattern_span, arg_hir_id, parent_id);
}
fn get_unit_temp(&mut self) -> Place<'tcx> {

View file

@ -578,7 +578,7 @@ pub(crate) fn in_scope<F, R>(
if let LintLevel::Explicit(current_hir_id) = lint_level {
let parent_id =
self.source_scopes[source_scope].local_data.as_ref().assert_crate_local().lint_root;
self.maybe_new_source_scope(region_scope.1.span, None, current_hir_id, parent_id);
self.maybe_new_source_scope(region_scope.1.span, current_hir_id, parent_id);
}
self.push_scope(region_scope);
let mut block;
@ -767,7 +767,6 @@ fn leave_top_scope(&mut self, block: BasicBlock) -> BasicBlock {
pub(crate) fn maybe_new_source_scope(
&mut self,
span: Span,
safety: Option<Safety>,
current_id: HirId,
parent_id: HirId,
) {
@ -797,7 +796,7 @@ pub(crate) fn maybe_new_source_scope(
if current_root != parent_root {
let lint_level = LintLevel::Explicit(current_root);
self.source_scope = self.new_source_scope(span, lint_level, safety);
self.source_scope = self.new_source_scope(span, lint_level);
}
}
@ -846,18 +845,12 @@ fn maybe_lint_level_root_bounded(&mut self, orig_id: HirId) -> HirId {
}
/// Creates a new source scope, nested in the current one.
pub(crate) fn new_source_scope(
&mut self,
span: Span,
lint_level: LintLevel,
safety: Option<Safety>,
) -> SourceScope {
pub(crate) fn new_source_scope(&mut self, span: Span, lint_level: LintLevel) -> SourceScope {
let parent = self.source_scope;
debug!(
"new_source_scope({:?}, {:?}, {:?}) - parent({:?})={:?}",
"new_source_scope({:?}, {:?}) - parent({:?})={:?}",
span,
lint_level,
safety,
parent,
self.source_scopes.get(parent)
);
@ -867,9 +860,6 @@ pub(crate) fn new_source_scope(
} else {
self.source_scopes[parent].local_data.as_ref().assert_crate_local().lint_root
},
safety: safety.unwrap_or_else(|| {
self.source_scopes[parent].local_data.as_ref().assert_crate_local().safety
}),
};
self.source_scopes.push(SourceScopeData {
span,

View file

@ -909,11 +909,6 @@ pub fn emit_requires_unsafe_err(
}
pub fn check_unsafety(tcx: TyCtxt<'_>, def: LocalDefId) {
// THIR unsafeck can be disabled with `-Z thir-unsafeck=off`
if !tcx.sess.opts.unstable_opts.thir_unsafeck {
return;
}
// Closures and inline consts are handled by their owner, if it has a body
// Also, don't safety check custom MIR
if tcx.is_typeck_child(def.to_def_id()) || tcx.has_attr(def, sym::custom_mir) {

View file

@ -1,6 +1,4 @@
mir_transform_arithmetic_overflow = this arithmetic operation will overflow
mir_transform_call_to_unsafe_label = call to unsafe function
mir_transform_call_to_unsafe_note = consult the function's documentation for information on how to avoid undefined behavior
mir_transform_const_defined_here = `const` item defined here
mir_transform_const_modify = attempting to modify a `const` item
@ -11,10 +9,6 @@ mir_transform_const_mut_borrow = taking a mutable reference to a `const` item
.note2 = the mutable reference will refer to this temporary, not the original `const` item
.note3 = mutable reference created due to call to this method
mir_transform_const_ptr2int_label = cast of pointer to int
mir_transform_const_ptr2int_note = casting pointers to integers in constants
mir_transform_deref_ptr_label = dereference of raw pointer
mir_transform_deref_ptr_note = raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
mir_transform_ffi_unwind_call = call to {$foreign ->
[true] foreign function
*[false] function pointer
@ -23,56 +17,13 @@ mir_transform_ffi_unwind_call = call to {$foreign ->
mir_transform_fn_item_ref = taking a reference to a function item does not give a function pointer
.suggestion = cast `{$ident}` to obtain a function pointer
mir_transform_initializing_valid_range_label = initializing type with `rustc_layout_scalar_valid_range` attr
mir_transform_initializing_valid_range_note = initializing a layout restricted type's field with a value outside the valid range is undefined behavior
mir_transform_must_not_suspend = {$pre}`{$def_path}`{$post} held across a suspend point, but should not be
.label = the value is held across this suspend point
.note = {$reason}
.help = consider using a block (`{"{ ... }"}`) to shrink the value's scope, ending before the suspend point
mir_transform_mutation_layout_constrained_borrow_label = borrow of layout constrained field with interior mutability
mir_transform_mutation_layout_constrained_borrow_note = references to fields of layout constrained fields lose the constraints. Coupled with interior mutability, the field can be changed to invalid values
mir_transform_mutation_layout_constrained_label = mutation of layout constrained field
mir_transform_mutation_layout_constrained_note = mutating layout constrained fields cannot statically be checked for valid values
mir_transform_operation_will_panic = this operation will panic at runtime
mir_transform_requires_unsafe = {$details} is unsafe and requires unsafe {$op_in_unsafe_fn_allowed ->
[true] function or block
*[false] block
}
.not_inherited = items do not inherit unsafety from separate enclosing items
mir_transform_target_feature_call_help = in order for the call to be safe, the context requires the following additional target {$missing_target_features_count ->
[1] feature
*[count] features
}: {$missing_target_features}
mir_transform_target_feature_call_label = call to function with `#[target_feature]`
mir_transform_target_feature_call_note = the {$build_target_features} target {$build_target_features_count ->
[1] feature
*[count] features
} being enabled in the build configuration does not remove the requirement to list {$build_target_features_count ->
[1] it
*[count] them
} in `#[target_feature]`
mir_transform_unaligned_packed_ref = reference to packed field is unaligned
.note = packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses
.note_ub = creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
.help = copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
mir_transform_union_access_label = access to union field
mir_transform_union_access_note = the field may not be properly initialized: using uninitialized data will cause undefined behavior
mir_transform_unsafe_op_in_unsafe_fn = {$details} is unsafe and requires unsafe block (error E0133)
.suggestion = consider wrapping the function body in an unsafe block
.note = an unsafe function restricts its caller, but its body is safe by default
mir_transform_unused_unsafe = unnecessary `unsafe` block
.label = because it's nested under this `unsafe` block
mir_transform_use_of_asm_label = use of inline assembly
mir_transform_use_of_asm_note = inline assembly is entirely unchecked and can cause undefined behavior
mir_transform_use_of_extern_static_label = use of extern static
mir_transform_use_of_extern_static_note = extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior
mir_transform_use_of_static_mut_label = use of mutable static
mir_transform_use_of_static_mut_note = mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior

View file

@ -1,615 +0,0 @@
use rustc_data_structures::unord::{ExtendUnord, UnordItems, UnordSet};
use rustc_hir as hir;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::hir_id::HirId;
use rustc_hir::intravisit;
use rustc_hir::{BlockCheckMode, ExprKind, Node};
use rustc_middle::mir::visit::{MutatingUseContext, PlaceContext, Visitor};
use rustc_middle::mir::*;
use rustc_middle::query::Providers;
use rustc_middle::ty::{self, TyCtxt};
use rustc_session::lint::builtin::{UNSAFE_OP_IN_UNSAFE_FN, UNUSED_UNSAFE};
use rustc_session::lint::Level;
use std::ops::Bound;
use crate::errors;
pub struct UnsafetyChecker<'a, 'tcx> {
body: &'a Body<'tcx>,
body_did: LocalDefId,
violations: Vec<UnsafetyViolation>,
source_info: SourceInfo,
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
/// Used `unsafe` blocks in this function. This is used for the "unused_unsafe" lint.
used_unsafe_blocks: UnordSet<HirId>,
}
impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> {
fn new(
body: &'a Body<'tcx>,
body_did: LocalDefId,
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
) -> Self {
Self {
body,
body_did,
violations: vec![],
source_info: SourceInfo::outermost(body.span),
tcx,
param_env,
used_unsafe_blocks: Default::default(),
}
}
}
impl<'tcx> Visitor<'tcx> for UnsafetyChecker<'_, 'tcx> {
fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) {
self.source_info = terminator.source_info;
match terminator.kind {
TerminatorKind::Goto { .. }
| TerminatorKind::SwitchInt { .. }
| TerminatorKind::Drop { .. }
| TerminatorKind::Yield { .. }
| TerminatorKind::Assert { .. }
| TerminatorKind::CoroutineDrop
| TerminatorKind::UnwindResume
| TerminatorKind::UnwindTerminate(_)
| TerminatorKind::Return
| TerminatorKind::Unreachable
| TerminatorKind::FalseEdge { .. }
| TerminatorKind::FalseUnwind { .. } => {
// safe (at least as emitted during MIR construction)
}
TerminatorKind::Call { ref func, .. } => {
let func_ty = func.ty(self.body, self.tcx);
let func_id =
if let ty::FnDef(func_id, _) = func_ty.kind() { Some(func_id) } else { None };
let sig = func_ty.fn_sig(self.tcx);
if let hir::Unsafety::Unsafe = sig.unsafety() {
self.require_unsafe(
UnsafetyViolationKind::General,
UnsafetyViolationDetails::CallToUnsafeFunction,
)
}
if let Some(func_id) = func_id {
self.check_target_features(*func_id);
}
}
TerminatorKind::InlineAsm { .. } => self.require_unsafe(
UnsafetyViolationKind::General,
UnsafetyViolationDetails::UseOfInlineAssembly,
),
}
self.super_terminator(terminator, location);
}
fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
self.source_info = statement.source_info;
match statement.kind {
StatementKind::Assign(..)
| StatementKind::FakeRead(..)
| StatementKind::SetDiscriminant { .. }
| StatementKind::Deinit(..)
| StatementKind::StorageLive(..)
| StatementKind::StorageDead(..)
| StatementKind::Retag { .. }
| StatementKind::PlaceMention(..)
| StatementKind::Coverage(..)
| StatementKind::Intrinsic(..)
| StatementKind::ConstEvalCounter
| StatementKind::Nop => {
// safe (at least as emitted during MIR construction)
}
// `AscribeUserType` just exists to help MIR borrowck.
// It has no semantics, and everything is already reported by `PlaceMention`.
StatementKind::AscribeUserType(..) => return,
}
self.super_statement(statement, location);
}
fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
match rvalue {
Rvalue::Aggregate(box ref aggregate, _) => match aggregate {
&AggregateKind::Array(..) | &AggregateKind::Tuple => {}
&AggregateKind::Adt(adt_did, ..) => {
match self.tcx.layout_scalar_valid_range(adt_did) {
(Bound::Unbounded, Bound::Unbounded) => {}
_ => self.require_unsafe(
UnsafetyViolationKind::General,
UnsafetyViolationDetails::InitializingTypeWith,
),
}
}
&AggregateKind::Closure(def_id, _)
| &AggregateKind::CoroutineClosure(def_id, _)
| &AggregateKind::Coroutine(def_id, _) => {
let def_id = def_id.expect_local();
let UnsafetyCheckResult { violations, used_unsafe_blocks, .. } =
self.tcx.mir_unsafety_check_result(def_id);
self.register_violations(violations, used_unsafe_blocks.items().copied());
}
},
_ => {}
}
self.super_rvalue(rvalue, location);
}
fn visit_operand(&mut self, op: &Operand<'tcx>, location: Location) {
if let Operand::Constant(constant) = op {
let maybe_uneval = match constant.const_ {
Const::Val(..) | Const::Ty(_) => None,
Const::Unevaluated(uv, _) => Some(uv),
};
if let Some(uv) = maybe_uneval {
if uv.promoted.is_none() {
let def_id = uv.def;
if self.tcx.def_kind(def_id) == DefKind::InlineConst {
let local_def_id = def_id.expect_local();
let UnsafetyCheckResult { violations, used_unsafe_blocks, .. } =
self.tcx.mir_unsafety_check_result(local_def_id);
self.register_violations(violations, used_unsafe_blocks.items().copied());
}
}
}
}
self.super_operand(op, location);
}
fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, _location: Location) {
// On types with `scalar_valid_range`, prevent
// * `&mut x.field`
// * `x.field = y;`
// * `&x.field` if `field`'s type has interior mutability
// because either of these would allow modifying the layout constrained field and
// insert values that violate the layout constraints.
if context.is_mutating_use() || context.is_borrow() {
self.check_mut_borrowing_layout_constrained_field(*place, context.is_mutating_use());
}
// Some checks below need the extra meta info of the local declaration.
let decl = &self.body.local_decls[place.local];
// Check the base local: it might be an unsafe-to-access static. We only check derefs of the
// temporary holding the static pointer to avoid duplicate errors
// <https://github.com/rust-lang/rust/pull/78068#issuecomment-731753506>.
if place.projection.first() == Some(&ProjectionElem::Deref) {
// If the projection root is an artificial local that we introduced when
// desugaring `static`, give a more specific error message
// (avoid the general "raw pointer" clause below, that would only be confusing).
if let LocalInfo::StaticRef { def_id, .. } = *decl.local_info() {
if self.tcx.is_mutable_static(def_id) {
self.require_unsafe(
UnsafetyViolationKind::General,
UnsafetyViolationDetails::UseOfMutableStatic,
);
return;
} else if self.tcx.is_foreign_item(def_id) {
self.require_unsafe(
UnsafetyViolationKind::General,
UnsafetyViolationDetails::UseOfExternStatic,
);
return;
}
}
}
// Check for raw pointer `Deref`.
for (base, proj) in place.iter_projections() {
if proj == ProjectionElem::Deref {
let base_ty = base.ty(self.body, self.tcx).ty;
if base_ty.is_unsafe_ptr() {
self.require_unsafe(
UnsafetyViolationKind::General,
UnsafetyViolationDetails::DerefOfRawPointer,
)
}
}
}
// Check for union fields. For this we traverse right-to-left, as the last `Deref` changes
// whether we *read* the union field or potentially *write* to it (if this place is being assigned to).
let mut saw_deref = false;
for (base, proj) in place.iter_projections().rev() {
if proj == ProjectionElem::Deref {
saw_deref = true;
continue;
}
let base_ty = base.ty(self.body, self.tcx).ty;
if base_ty.is_union() {
// If we did not hit a `Deref` yet and the overall place use is an assignment, the
// rules are different.
let assign_to_field = !saw_deref
&& matches!(
context,
PlaceContext::MutatingUse(
MutatingUseContext::Store
| MutatingUseContext::Drop
| MutatingUseContext::AsmOutput
)
);
// If this is just an assignment, determine if the assigned type needs dropping.
if assign_to_field {
// We have to check the actual type of the assignment, as that determines if the
// old value is being dropped.
let assigned_ty = place.ty(&self.body.local_decls, self.tcx).ty;
if assigned_ty.needs_drop(self.tcx, self.param_env) {
// This would be unsafe, but should be outright impossible since we reject
// such unions.
assert!(
self.tcx.dcx().has_errors().is_some(),
"union fields that need dropping should be impossible: {assigned_ty}"
);
}
} else {
self.require_unsafe(
UnsafetyViolationKind::General,
UnsafetyViolationDetails::AccessToUnionField,
)
}
}
}
}
}
impl<'tcx> UnsafetyChecker<'_, 'tcx> {
fn require_unsafe(&mut self, kind: UnsafetyViolationKind, details: UnsafetyViolationDetails) {
// Violations can turn out to be `UnsafeFn` during analysis, but they should not start out as such.
assert_ne!(kind, UnsafetyViolationKind::UnsafeFn);
let source_info = self.source_info;
let lint_root = self.body.source_scopes[self.source_info.scope]
.local_data
.as_ref()
.assert_crate_local()
.lint_root;
self.register_violations(
[&UnsafetyViolation { source_info, lint_root, kind, details }],
UnordItems::empty(),
);
}
fn register_violations<'a>(
&mut self,
violations: impl IntoIterator<Item = &'a UnsafetyViolation>,
new_used_unsafe_blocks: UnordItems<HirId, impl Iterator<Item = HirId>>,
) {
let safety = self.body.source_scopes[self.source_info.scope]
.local_data
.as_ref()
.assert_crate_local()
.safety;
match safety {
// `unsafe` blocks are required in safe code
Safety::Safe => violations.into_iter().for_each(|violation| {
match violation.kind {
UnsafetyViolationKind::General => {}
UnsafetyViolationKind::UnsafeFn => {
bug!("`UnsafetyViolationKind::UnsafeFn` in an `Safe` context")
}
}
if !self.violations.contains(violation) {
self.violations.push(violation.clone())
}
}),
// With the RFC 2585, no longer allow `unsafe` operations in `unsafe fn`s
Safety::FnUnsafe => violations.into_iter().for_each(|violation| {
let mut violation = violation.clone();
violation.kind = UnsafetyViolationKind::UnsafeFn;
if !self.violations.contains(&violation) {
self.violations.push(violation)
}
}),
Safety::BuiltinUnsafe => {}
Safety::ExplicitUnsafe(hir_id) => violations.into_iter().for_each(|_violation| {
self.used_unsafe_blocks.insert(hir_id);
}),
};
self.used_unsafe_blocks.extend_unord(new_used_unsafe_blocks);
}
fn check_mut_borrowing_layout_constrained_field(
&mut self,
place: Place<'tcx>,
is_mut_use: bool,
) {
for (place_base, elem) in place.iter_projections().rev() {
match elem {
// Modifications behind a dereference don't affect the value of
// the pointer.
ProjectionElem::Deref => return,
ProjectionElem::Field(..) => {
let ty = place_base.ty(&self.body.local_decls, self.tcx).ty;
if let ty::Adt(def, _) = ty.kind() {
if self.tcx.layout_scalar_valid_range(def.did())
!= (Bound::Unbounded, Bound::Unbounded)
{
let details = if is_mut_use {
UnsafetyViolationDetails::MutationOfLayoutConstrainedField
// Check `is_freeze` as late as possible to avoid cycle errors
// with opaque types.
} else if !place
.ty(self.body, self.tcx)
.ty
.is_freeze(self.tcx, self.param_env)
{
UnsafetyViolationDetails::BorrowOfLayoutConstrainedField
} else {
continue;
};
self.require_unsafe(UnsafetyViolationKind::General, details);
}
}
}
_ => {}
}
}
}
/// Checks whether calling `func_did` needs an `unsafe` context or not, i.e. whether
/// the called function has target features the calling function hasn't.
fn check_target_features(&mut self, func_did: DefId) {
// Unsafety isn't required on wasm targets. For more information see
// the corresponding check in typeck/src/collect.rs
if self.tcx.sess.target.options.is_like_wasm {
return;
}
let callee_features = &self.tcx.codegen_fn_attrs(func_did).target_features;
// The body might be a constant, so it doesn't have codegen attributes.
let self_features = &self.tcx.body_codegen_attrs(self.body_did.to_def_id()).target_features;
// Is `callee_features` a subset of `calling_features`?
if !callee_features.iter().all(|feature| self_features.contains(feature)) {
let missing: Vec<_> = callee_features
.iter()
.copied()
.filter(|feature| !self_features.contains(feature))
.collect();
let build_enabled = self
.tcx
.sess
.target_features
.iter()
.copied()
.filter(|feature| missing.contains(feature))
.collect();
self.require_unsafe(
UnsafetyViolationKind::General,
UnsafetyViolationDetails::CallToFunctionWith { missing, build_enabled },
)
}
}
}
pub(crate) fn provide(providers: &mut Providers) {
*providers = Providers { mir_unsafety_check_result, ..*providers };
}
/// Context information for [`UnusedUnsafeVisitor`] traversal,
/// saves (innermost) relevant context
#[derive(Copy, Clone, Debug)]
enum Context {
Safe,
/// in an `unsafe fn`
UnsafeFn,
/// in a *used* `unsafe` block
/// (i.e. a block without unused-unsafe warning)
UnsafeBlock(HirId),
}
struct UnusedUnsafeVisitor<'a, 'tcx> {
tcx: TyCtxt<'tcx>,
used_unsafe_blocks: &'a UnordSet<HirId>,
context: Context,
unused_unsafes: &'a mut Vec<(HirId, UnusedUnsafe)>,
}
impl<'tcx> intravisit::Visitor<'tcx> for UnusedUnsafeVisitor<'_, 'tcx> {
fn visit_block(&mut self, block: &'tcx hir::Block<'tcx>) {
if let hir::BlockCheckMode::UnsafeBlock(hir::UnsafeSource::UserProvided) = block.rules {
let used = match self.tcx.lint_level_at_node(UNUSED_UNSAFE, block.hir_id) {
(Level::Allow, _) => true,
_ => self.used_unsafe_blocks.contains(&block.hir_id),
};
let unused_unsafe = match (self.context, used) {
(_, false) => UnusedUnsafe::Unused,
(Context::Safe, true) | (Context::UnsafeFn, true) => {
let previous_context = self.context;
self.context = Context::UnsafeBlock(block.hir_id);
intravisit::walk_block(self, block);
self.context = previous_context;
return;
}
(Context::UnsafeBlock(hir_id), true) => UnusedUnsafe::InUnsafeBlock(hir_id),
};
self.unused_unsafes.push((block.hir_id, unused_unsafe));
}
intravisit::walk_block(self, block);
}
fn visit_inline_const(&mut self, c: &'tcx hir::ConstBlock) {
self.visit_body(self.tcx.hir().body(c.body))
}
fn visit_fn(
&mut self,
fk: intravisit::FnKind<'tcx>,
_fd: &'tcx hir::FnDecl<'tcx>,
b: hir::BodyId,
_s: rustc_span::Span,
_id: LocalDefId,
) {
if matches!(fk, intravisit::FnKind::Closure) {
self.visit_body(self.tcx.hir().body(b))
}
}
}
fn check_unused_unsafe(
tcx: TyCtxt<'_>,
def_id: LocalDefId,
used_unsafe_blocks: &UnordSet<HirId>,
) -> Vec<(HirId, UnusedUnsafe)> {
let body_id = tcx.hir().maybe_body_owned_by(def_id);
let Some(body_id) = body_id else {
debug!("check_unused_unsafe({:?}) - no body found", def_id);
return vec![];
};
let body = tcx.hir().body(body_id);
let hir_id = tcx.local_def_id_to_hir_id(def_id);
let context = match tcx.hir().fn_sig_by_hir_id(hir_id) {
Some(sig) if sig.header.unsafety == hir::Unsafety::Unsafe => Context::UnsafeFn,
_ => Context::Safe,
};
debug!(
"check_unused_unsafe({:?}, context={:?}, body={:?}, used_unsafe_blocks={:?})",
def_id, body, context, used_unsafe_blocks
);
let mut unused_unsafes = vec![];
let mut visitor = UnusedUnsafeVisitor {
tcx,
used_unsafe_blocks,
context,
unused_unsafes: &mut unused_unsafes,
};
intravisit::Visitor::visit_body(&mut visitor, body);
unused_unsafes
}
fn mir_unsafety_check_result(tcx: TyCtxt<'_>, def: LocalDefId) -> &UnsafetyCheckResult {
debug!("unsafety_violations({:?})", def);
// N.B., this borrow is valid because all the consumers of
// `mir_built` force this.
let body = &tcx.mir_built(def).borrow();
if body.is_custom_mir() || body.tainted_by_errors.is_some() {
return tcx.arena.alloc(UnsafetyCheckResult {
violations: Vec::new(),
used_unsafe_blocks: Default::default(),
unused_unsafes: Some(Vec::new()),
});
}
let param_env = tcx.param_env(def);
let mut checker = UnsafetyChecker::new(body, def, tcx, param_env);
checker.visit_body(body);
let unused_unsafes = (!tcx.is_typeck_child(def.to_def_id()))
.then(|| check_unused_unsafe(tcx, def, &checker.used_unsafe_blocks));
tcx.arena.alloc(UnsafetyCheckResult {
violations: checker.violations,
used_unsafe_blocks: checker.used_unsafe_blocks,
unused_unsafes,
})
}
fn report_unused_unsafe(tcx: TyCtxt<'_>, kind: UnusedUnsafe, id: HirId) {
let span = tcx.sess.source_map().guess_head_span(tcx.hir().span(id));
let nested_parent = if let UnusedUnsafe::InUnsafeBlock(id) = kind {
Some(tcx.sess.source_map().guess_head_span(tcx.hir().span(id)))
} else {
None
};
tcx.emit_node_span_lint(UNUSED_UNSAFE, id, span, errors::UnusedUnsafe { span, nested_parent });
}
pub fn check_unsafety(tcx: TyCtxt<'_>, def_id: LocalDefId) {
debug!("check_unsafety({:?})", def_id);
// closures and inline consts are handled by their parent fn.
if tcx.is_typeck_child(def_id.to_def_id()) {
return;
}
let UnsafetyCheckResult { violations, unused_unsafes, .. } =
tcx.mir_unsafety_check_result(def_id);
// Only suggest wrapping the entire function body in an unsafe block once
let mut suggest_unsafe_block = true;
for &UnsafetyViolation { source_info, lint_root, kind, ref details } in violations.iter() {
let details =
errors::RequiresUnsafeDetail { violation: details.clone(), span: source_info.span };
match kind {
UnsafetyViolationKind::General => {
let op_in_unsafe_fn_allowed = unsafe_op_in_unsafe_fn_allowed(tcx, lint_root);
let note_non_inherited = tcx.hir().parent_iter(lint_root).find(|(id, node)| {
if let Node::Expr(block) = node
&& let ExprKind::Block(block, _) = block.kind
&& let BlockCheckMode::UnsafeBlock(_) = block.rules
{
true
} else if let Some(sig) = tcx.hir().fn_sig_by_hir_id(*id)
&& sig.header.is_unsafe()
{
true
} else {
false
}
});
let enclosing = if let Some((id, _)) = note_non_inherited {
Some(tcx.sess.source_map().guess_head_span(tcx.hir().span(id)))
} else {
None
};
tcx.dcx().emit_err(errors::RequiresUnsafe {
span: source_info.span,
enclosing,
details,
op_in_unsafe_fn_allowed,
});
}
UnsafetyViolationKind::UnsafeFn => {
tcx.emit_node_span_lint(
UNSAFE_OP_IN_UNSAFE_FN,
lint_root,
source_info.span,
errors::UnsafeOpInUnsafeFn {
details,
suggest_unsafe_block: suggest_unsafe_block.then(|| {
let hir_id = tcx.local_def_id_to_hir_id(def_id);
let fn_sig = tcx
.hir()
.fn_sig_by_hir_id(hir_id)
.expect("this violation only occurs in fn");
let body = tcx.hir().body_owned_by(def_id);
let body_span = tcx.hir().body(body).value.span;
let start = tcx.sess.source_map().start_point(body_span).shrink_to_hi();
let end = tcx.sess.source_map().end_point(body_span).shrink_to_lo();
(start, end, fn_sig.span)
}),
},
);
suggest_unsafe_block = false;
}
}
}
for &(block_id, kind) in unused_unsafes.as_ref().unwrap() {
report_unused_unsafe(tcx, kind, block_id);
}
}
fn unsafe_op_in_unsafe_fn_allowed(tcx: TyCtxt<'_>, id: HirId) -> bool {
tcx.lint_level_at_node(UNSAFE_OP_IN_UNSAFE_FN, id).0 == Level::Allow
}

View file

@ -1,11 +1,6 @@
use std::borrow::Cow;
use rustc_errors::{
codes::*, Applicability, Diag, DiagArgValue, DiagCtxt, DiagMessage, Diagnostic,
EmissionGuarantee, Level, LintDiagnostic,
};
use rustc_errors::{codes::*, Diag, DiagMessage, LintDiagnostic};
use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
use rustc_middle::mir::{AssertKind, UnsafetyViolationDetails};
use rustc_middle::mir::AssertKind;
use rustc_middle::ty::TyCtxt;
use rustc_session::lint::{self, Lint};
use rustc_span::def_id::DefId;
@ -42,168 +37,6 @@ pub(crate) struct UnalignedPackedRef {
pub span: Span,
}
#[derive(LintDiagnostic)]
#[diag(mir_transform_unused_unsafe)]
pub(crate) struct UnusedUnsafe {
#[label(mir_transform_unused_unsafe)]
pub span: Span,
#[label]
pub nested_parent: Option<Span>,
}
pub(crate) struct RequiresUnsafe {
pub span: Span,
pub details: RequiresUnsafeDetail,
pub enclosing: Option<Span>,
pub op_in_unsafe_fn_allowed: bool,
}
// The primary message for this diagnostic should be '{$label} is unsafe and...',
// so we need to eagerly translate the label here, which isn't supported by the derive API
// We could also exhaustively list out the primary messages for all unsafe violations,
// but this would result in a lot of duplication.
impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for RequiresUnsafe {
#[track_caller]
fn into_diag(self, dcx: &'a DiagCtxt, level: Level) -> Diag<'a, G> {
let mut diag = Diag::new(dcx, level, fluent::mir_transform_requires_unsafe);
diag.code(E0133);
diag.span(self.span);
diag.span_label(self.span, self.details.label());
let desc = dcx.eagerly_translate_to_string(self.details.label(), [].into_iter());
diag.arg("details", desc);
diag.arg("op_in_unsafe_fn_allowed", self.op_in_unsafe_fn_allowed);
self.details.add_subdiagnostics(&mut diag);
if let Some(sp) = self.enclosing {
diag.span_label(sp, fluent::mir_transform_not_inherited);
}
diag
}
}
#[derive(Clone)]
pub(crate) struct RequiresUnsafeDetail {
pub span: Span,
pub violation: UnsafetyViolationDetails,
}
impl RequiresUnsafeDetail {
// FIXME: make this translatable
#[allow(rustc::diagnostic_outside_of_impl)]
#[allow(rustc::untranslatable_diagnostic)]
fn add_subdiagnostics<G: EmissionGuarantee>(&self, diag: &mut Diag<'_, G>) {
use UnsafetyViolationDetails::*;
match self.violation {
CallToUnsafeFunction => {
diag.note(fluent::mir_transform_call_to_unsafe_note);
}
UseOfInlineAssembly => {
diag.note(fluent::mir_transform_use_of_asm_note);
}
InitializingTypeWith => {
diag.note(fluent::mir_transform_initializing_valid_range_note);
}
CastOfPointerToInt => {
diag.note(fluent::mir_transform_const_ptr2int_note);
}
UseOfMutableStatic => {
diag.note(fluent::mir_transform_use_of_static_mut_note);
}
UseOfExternStatic => {
diag.note(fluent::mir_transform_use_of_extern_static_note);
}
DerefOfRawPointer => {
diag.note(fluent::mir_transform_deref_ptr_note);
}
AccessToUnionField => {
diag.note(fluent::mir_transform_union_access_note);
}
MutationOfLayoutConstrainedField => {
diag.note(fluent::mir_transform_mutation_layout_constrained_note);
}
BorrowOfLayoutConstrainedField => {
diag.note(fluent::mir_transform_mutation_layout_constrained_borrow_note);
}
CallToFunctionWith { ref missing, ref build_enabled } => {
diag.help(fluent::mir_transform_target_feature_call_help);
diag.arg(
"missing_target_features",
DiagArgValue::StrListSepByAnd(
missing.iter().map(|feature| Cow::from(feature.to_string())).collect(),
),
);
diag.arg("missing_target_features_count", missing.len());
if !build_enabled.is_empty() {
diag.note(fluent::mir_transform_target_feature_call_note);
diag.arg(
"build_target_features",
DiagArgValue::StrListSepByAnd(
build_enabled
.iter()
.map(|feature| Cow::from(feature.to_string()))
.collect(),
),
);
diag.arg("build_target_features_count", build_enabled.len());
}
}
}
}
fn label(&self) -> DiagMessage {
use UnsafetyViolationDetails::*;
match self.violation {
CallToUnsafeFunction => fluent::mir_transform_call_to_unsafe_label,
UseOfInlineAssembly => fluent::mir_transform_use_of_asm_label,
InitializingTypeWith => fluent::mir_transform_initializing_valid_range_label,
CastOfPointerToInt => fluent::mir_transform_const_ptr2int_label,
UseOfMutableStatic => fluent::mir_transform_use_of_static_mut_label,
UseOfExternStatic => fluent::mir_transform_use_of_extern_static_label,
DerefOfRawPointer => fluent::mir_transform_deref_ptr_label,
AccessToUnionField => fluent::mir_transform_union_access_label,
MutationOfLayoutConstrainedField => {
fluent::mir_transform_mutation_layout_constrained_label
}
BorrowOfLayoutConstrainedField => {
fluent::mir_transform_mutation_layout_constrained_borrow_label
}
CallToFunctionWith { .. } => fluent::mir_transform_target_feature_call_label,
}
}
}
pub(crate) struct UnsafeOpInUnsafeFn {
pub details: RequiresUnsafeDetail,
/// These spans point to:
/// 1. the start of the function body
/// 2. the end of the function body
/// 3. the function signature
pub suggest_unsafe_block: Option<(Span, Span, Span)>,
}
impl<'a> LintDiagnostic<'a, ()> for UnsafeOpInUnsafeFn {
#[track_caller]
fn decorate_lint<'b>(self, diag: &'b mut Diag<'a, ()>) {
let desc = diag.dcx.eagerly_translate_to_string(self.details.label(), [].into_iter());
diag.arg("details", desc);
diag.span_label(self.details.span, self.details.label());
self.details.add_subdiagnostics(diag);
if let Some((start, end, fn_sig)) = self.suggest_unsafe_block {
diag.span_note(fn_sig, fluent::mir_transform_note);
diag.tool_only_multipart_suggestion(
fluent::mir_transform_suggestion,
vec![(start, " unsafe {".into()), (end, "}".into())],
Applicability::MaybeIncorrect,
);
}
}
fn msg(&self) -> DiagMessage {
fluent::mir_transform_unsafe_op_in_unsafe_fn
}
}
pub(crate) struct AssertLint<P> {
pub span: Span,
pub assert_kind: AssertKind<P>,

View file

@ -53,7 +53,6 @@
mod add_retag;
mod check_const_item_mutation;
mod check_packed_ref;
pub mod check_unsafety;
mod remove_place_mention;
// This pass is public to allow external drivers to perform MIR cleanup
mod add_subtyping_projections;
@ -120,7 +119,6 @@
rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
pub fn provide(providers: &mut Providers) {
check_unsafety::provide(providers);
coverage::query::provide(providers);
ffi_unwind_calls::provide(providers);
shim::provide(providers);
@ -280,11 +278,6 @@ fn mir_const_qualif(tcx: TyCtxt<'_>, def: LocalDefId) -> ConstQualifs {
}
fn mir_built(tcx: TyCtxt<'_>, def: LocalDefId) -> &Steal<Body<'_>> {
// MIR unsafety check uses the raw mir, so make sure it is run.
if !tcx.sess.opts.unstable_opts.thir_unsafeck {
tcx.ensure_with_value().mir_unsafety_check_result(def);
}
let mut body = tcx.build_mir(def);
pass_manager::dump_mir_for_phase_change(tcx, &body);

View file

@ -1950,8 +1950,6 @@ pub(crate) fn parse_function_return(slot: &mut FunctionReturn, v: Option<&str>)
#[rustc_lint_opt_deny_field_access("use `Session::lto` instead of this field")]
thinlto: Option<bool> = (None, parse_opt_bool, [TRACKED],
"enable ThinLTO when possible"),
thir_unsafeck: bool = (true, parse_bool, [TRACKED],
"use the THIR unsafety checker (default: yes)"),
/// We default to 1 here since we want to behave like
/// a sequential compiler for now. This'll likely be adjusted
/// in the future. Note that -Zthreads=0 is the way to get

View file

@ -104,17 +104,17 @@ pub fn order_of_parameters(p2: i64, p1: i32) {}
// Unsafe ----------------------------------------------------------------------
#[cfg(any(cfail1,cfail4))]
pub fn make_unsafe() {}
pub fn make_unsafe() {}
#[cfg(not(any(cfail1,cfail4)))]
#[rustc_clean(
cfg = "cfail2",
except = "opt_hir_owner_nodes, optimized_mir, typeck, fn_sig"
except = "opt_hir_owner_nodes, typeck, fn_sig"
)]
#[rustc_clean(cfg = "cfail3")]
#[rustc_clean(
cfg = "cfail5",
except = "opt_hir_owner_nodes, optimized_mir, typeck, fn_sig"
except = "opt_hir_owner_nodes, typeck, fn_sig"
)]
#[rustc_clean(cfg = "cfail6")]
pub unsafe fn make_unsafe() {}

View file

@ -348,9 +348,9 @@ pub fn change_method_parameter_order(&self, b: i64, a: i64) { }
// Make method unsafe ----------------------------------------------------------
#[cfg(any(cfail1,cfail4))]
impl Foo {
//------------------------------------------------------------------------------------
//----------------------------------------------------------------------
//--------------------------
//------------------------------------------------------------------------------------
//----------------------------------------------------------------------
//--------------------------
pub fn make_method_unsafe(&self) { }
}
@ -361,9 +361,9 @@ pub fn make_method_unsafe(&self) { }
#[rustc_clean(cfg="cfail5")]
#[rustc_clean(cfg="cfail6")]
impl Foo {
#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,fn_sig,typeck,optimized_mir")]
#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,fn_sig,typeck")]
#[rustc_clean(cfg="cfail3")]
#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes,fn_sig,typeck,optimized_mir")]
#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes,fn_sig,typeck")]
#[rustc_clean(cfg="cfail6")]
pub unsafe fn make_method_unsafe(&self) { }
}

View file

@ -17,8 +17,6 @@ fn main() -> () {
let _3: *mut usize;
scope 3 {
debug z => _3;
scope 4 {
}
}
}
}

View file

@ -17,8 +17,6 @@ fn main() -> () {
let _3: *mut usize;
scope 3 {
debug z => _3;
scope 4 {
}
}
}
}

View file

@ -3,8 +3,6 @@
fn main() -> () {
let mut _0: ();
let _1: ();
scope 1 {
}
bb0: {
StorageLive(_1);

View file

@ -15,8 +15,6 @@
scope 1 {
debug x => _1;
}
scope 2 {
}
bb0: {
StorageLive(_1);

View file

@ -93,17 +93,13 @@ fn b::{closure#0}(_1: Pin<&mut {async fn body of b()}>, _2: &mut Context<'_>) ->
debug __awaitee => (((*(_1.0: &mut {async fn body of b()})) as variant#3).0: {async fn body of a()});
let _17: ();
scope 2 {
}
scope 3 {
debug result => _17;
}
}
scope 4 {
scope 3 {
debug __awaitee => (((*(_1.0: &mut {async fn body of b()})) as variant#4).0: {async fn body of a()});
let _33: ();
scope 5 {
}
scope 6 {
scope 4 {
debug result => _33;
}
}

View file

@ -16,14 +16,10 @@ fn move_out_by_subslice() -> () {
scope 1 {
debug a => _1;
let _12: [std::boxed::Box<i32>; 2];
scope 4 {
scope 2 {
debug _y => _12;
}
}
scope 2 {
}
scope 3 {
}
bb0: {
StorageLive(_1);

View file

@ -16,14 +16,10 @@ fn move_out_from_end() -> () {
scope 1 {
debug a => _1;
let _12: std::boxed::Box<i32>;
scope 4 {
scope 2 {
debug _y => _12;
}
}
scope 2 {
}
scope 3 {
}
bb0: {
StorageLive(_1);

View file

@ -9,8 +9,6 @@
let mut _4: &i32;
let _5: *const i32;
+ let mut _6: &[&i32; 1];
scope 1 {
}
bb0: {
StorageLive(_1);

View file

@ -14,8 +14,6 @@
debug ptr => _3;
let _5: bool;
scope 3 {
}
scope 4 {
debug ret => _5;
}
}

View file

@ -13,11 +13,9 @@
let mut _9: &[i32; 3];
scope 1 {
debug a => _1;
let _5: i32;
scope 2 {
let _5: i32;
scope 3 {
debug _b => _5;
}
debug _b => _5;
}
}

View file

@ -13,11 +13,9 @@
let mut _9: &[i32; 3];
scope 1 {
debug a => _1;
let _5: i32;
scope 2 {
let _5: i32;
scope 3 {
debug _b => _5;
}
debug _b => _5;
}
}

View file

@ -13,11 +13,9 @@
let mut _9: &[i32; 3];
scope 1 {
debug a => _1;
let _5: i32;
scope 2 {
let _5: i32;
scope 3 {
debug _b => _5;
}
debug _b => _5;
}
}

View file

@ -13,11 +13,9 @@
let mut _9: &[i32; 3];
scope 1 {
debug a => _1;
let _5: i32;
scope 2 {
let _5: i32;
scope 3 {
debug _b => _5;
}
debug _b => _5;
}
}

View file

@ -15,8 +15,6 @@
scope 1 {
debug x => _1;
}
scope 2 {
}
bb0: {
StorageLive(_1);

View file

@ -15,8 +15,6 @@
scope 1 {
debug x => _1;
}
scope 2 {
}
bb0: {
StorageLive(_1);

View file

@ -11,8 +11,6 @@
debug v => _1;
let _4: bool;
scope 2 {
}
scope 3 {
debug y => _4;
}
}

View file

@ -12,23 +12,17 @@
scope 1 {
debug _invalid_char => _1;
let _3: [E; 1];
scope 3 {
scope 2 {
debug _invalid_tag => _3;
let _6: [Empty; 1];
scope 5 {
scope 3 {
debug _enum_without_variants => const [ZeroSized: Empty];
let _9: main::Str<"<22><><EFBFBD>">;
scope 7 {
scope 4 {
debug _non_utf8_str => const Str::<"<22><><EFBFBD>">;
}
}
scope 6 {
}
}
scope 4 {
}
}
scope 2 {
}
bb0: {

View file

@ -12,25 +12,19 @@
scope 1 {
debug _invalid_char => _1;
let _3: [E; 1];
scope 3 {
scope 2 {
debug _invalid_tag => _3;
let _6: [Empty; 1];
scope 5 {
scope 3 {
- debug _enum_without_variants => _6;
+ debug _enum_without_variants => const [ZeroSized: Empty];
let _9: main::Str<"<22><><EFBFBD>">;
scope 7 {
scope 4 {
- debug _non_utf8_str => _9;
+ debug _non_utf8_str => const Str::<"<22><><EFBFBD>">;
}
}
scope 6 {
}
}
scope 4 {
}
}
scope 2 {
}
bb0: {

View file

@ -11,8 +11,6 @@
debug x => _1;
let _5: u32;
scope 2 {
}
scope 3 {
debug y => _5;
}
}

View file

@ -3,8 +3,6 @@
fn from_char() -> i32 {
let mut _0: i32;
scope 1 {
}
bb0: {
- _0 = const 'R' as i32 (Transmute);

View file

@ -3,8 +3,6 @@
fn from_char() -> i32 {
let mut _0: i32;
scope 1 {
}
bb0: {
- _0 = const 'R' as i32 (Transmute);

View file

@ -3,8 +3,6 @@
fn invalid_bool() -> bool {
let mut _0: bool;
scope 1 {
}
bb0: {
- _0 = const -1_i8 as bool (Transmute);

View file

@ -3,8 +3,6 @@
fn invalid_bool() -> bool {
let mut _0: bool;
scope 1 {
}
bb0: {
- _0 = const -1_i8 as bool (Transmute);

View file

@ -3,8 +3,6 @@
fn invalid_char() -> char {
let mut _0: char;
scope 1 {
}
bb0: {
- _0 = const core::num::<impl i32>::MAX as char (Transmute);

View file

@ -3,8 +3,6 @@
fn invalid_char() -> char {
let mut _0: char;
scope 1 {
}
bb0: {
- _0 = const core::num::<impl i32>::MAX as char (Transmute);

View file

@ -4,8 +4,6 @@
fn less_as_i8() -> i8 {
let mut _0: i8;
let mut _1: std::cmp::Ordering;
scope 1 {
}
bb0: {
StorageLive(_1);

View file

@ -4,8 +4,6 @@
fn less_as_i8() -> i8 {
let mut _0: i8;
let mut _1: std::cmp::Ordering;
scope 1 {
}
bb0: {
StorageLive(_1);

View file

@ -5,8 +5,6 @@
let mut _0: u32;
let mut _1: undef_union_as_integer::Union32;
let mut _2: ();
scope 1 {
}
bb0: {
StorageLive(_1);

View file

@ -5,8 +5,6 @@
let mut _0: u32;
let mut _1: undef_union_as_integer::Union32;
let mut _2: ();
scope 1 {
}
bb0: {
StorageLive(_1);

View file

@ -8,8 +8,6 @@
scope 1 {
debug x => _1;
}
scope 2 {
}
bb0: {
StorageLive(_1);

View file

@ -8,8 +8,6 @@
scope 1 {
debug x => _1;
}
scope 2 {
}
bb0: {
StorageLive(_1);

View file

@ -8,8 +8,6 @@
scope 1 {
debug x => _1;
}
scope 2 {
}
bb0: {
StorageLive(_1);

View file

@ -8,8 +8,6 @@
scope 1 {
debug x => _1;
}
scope 2 {
}
bb0: {
StorageLive(_1);

View file

@ -8,8 +8,6 @@
scope 1 {
debug x => _1;
}
scope 2 {
}
bb0: {
StorageLive(_1);

View file

@ -8,8 +8,6 @@
scope 1 {
debug x => _1;
}
scope 2 {
}
bb0: {
StorageLive(_1);

View file

@ -7,8 +7,6 @@
scope 1 {
debug x => _1;
}
scope 2 {
}
bb0: {
StorageLive(_1);

View file

@ -7,8 +7,6 @@
scope 1 {
debug x => _1;
}
scope 2 {
}
bb0: {
StorageLive(_1);

View file

@ -3,8 +3,6 @@
fn valid_char() -> char {
let mut _0: char;
scope 1 {
}
bb0: {
- _0 = const 82_u32 as char (Transmute);

View file

@ -3,8 +3,6 @@
fn valid_char() -> char {
let mut _0: char;
scope 1 {
}
bb0: {
- _0 = const 82_u32 as char (Transmute);

View file

@ -14,13 +14,11 @@
scope 2 {
debug b => _3;
let _5: *mut u8;
scope 4 {
scope 3 {
- debug c => _5;
+ debug c => _2;
}
}
scope 3 {
}
}
bb0: {

View file

@ -14,13 +14,11 @@
scope 2 {
debug b => _3;
let _5: *mut u8;
scope 4 {
scope 3 {
- debug c => _5;
+ debug c => _2;
}
}
scope 3 {
}
}
bb0: {

View file

@ -13,13 +13,11 @@
scope 2 {
debug b => _3;
let _4: *mut u8;
scope 4 {
scope 3 {
- debug c => _4;
+ debug c => _2;
}
}
scope 3 {
}
}
bb0: {

View file

@ -13,13 +13,11 @@
scope 2 {
debug b => _3;
let _4: *mut u8;
scope 4 {
scope 3 {
- debug c => _4;
+ debug c => _2;
}
}
scope 3 {
}
}
bb0: {

View file

@ -17,33 +17,27 @@
scope 4 (inlined Unique::<[bool; 0]>::dangling) {
let mut _5: std::ptr::NonNull<[bool; 0]>;
scope 5 (inlined NonNull::<[bool; 0]>::dangling) {
let _6: *mut [bool; 0];
scope 6 {
let _6: *mut [bool; 0];
scope 7 {
debug ptr => _6;
scope 10 (inlined NonNull::<[bool; 0]>::new_unchecked) {
debug ptr => _6;
scope 12 (inlined NonNull::<[bool; 0]>::new_unchecked) {
debug ptr => _6;
let mut _8: bool;
let _9: ();
let mut _10: *mut ();
let mut _11: *const [bool; 0];
scope 13 {
scope 14 (inlined core::ub_checks::check_language_ub) {
scope 15 (inlined core::ub_checks::check_language_ub::runtime) {
}
}
let mut _8: bool;
let _9: ();
let mut _10: *mut ();
let mut _11: *const [bool; 0];
scope 11 (inlined core::ub_checks::check_language_ub) {
scope 12 (inlined core::ub_checks::check_language_ub::runtime) {
}
}
}
scope 8 (inlined dangling_mut::<[bool; 0]>) {
let mut _7: usize;
scope 9 (inlined align_of::<[bool; 0]>) {
}
scope 10 (inlined without_provenance_mut::<[bool; 0]>) {
debug addr => _7;
scope 11 {
}
}
}
scope 7 (inlined dangling_mut::<[bool; 0]>) {
let mut _7: usize;
scope 8 (inlined align_of::<[bool; 0]>) {
}
scope 9 (inlined without_provenance_mut::<[bool; 0]>) {
debug addr => _7;
}
}
}

View file

@ -17,33 +17,27 @@
scope 4 (inlined Unique::<[bool; 0]>::dangling) {
let mut _5: std::ptr::NonNull<[bool; 0]>;
scope 5 (inlined NonNull::<[bool; 0]>::dangling) {
let _6: *mut [bool; 0];
scope 6 {
let _6: *mut [bool; 0];
scope 7 {
debug ptr => _6;
scope 10 (inlined NonNull::<[bool; 0]>::new_unchecked) {
debug ptr => _6;
scope 12 (inlined NonNull::<[bool; 0]>::new_unchecked) {
debug ptr => _6;
let mut _8: bool;
let _9: ();
let mut _10: *mut ();
let mut _11: *const [bool; 0];
scope 13 {
scope 14 (inlined core::ub_checks::check_language_ub) {
scope 15 (inlined core::ub_checks::check_language_ub::runtime) {
}
}
let mut _8: bool;
let _9: ();
let mut _10: *mut ();
let mut _11: *const [bool; 0];
scope 11 (inlined core::ub_checks::check_language_ub) {
scope 12 (inlined core::ub_checks::check_language_ub::runtime) {
}
}
}
scope 8 (inlined dangling_mut::<[bool; 0]>) {
let mut _7: usize;
scope 9 (inlined align_of::<[bool; 0]>) {
}
scope 10 (inlined without_provenance_mut::<[bool; 0]>) {
debug addr => _7;
scope 11 {
}
}
}
scope 7 (inlined dangling_mut::<[bool; 0]>) {
let mut _7: usize;
scope 8 (inlined align_of::<[bool; 0]>) {
}
scope 9 (inlined without_provenance_mut::<[bool; 0]>) {
debug addr => _7;
}
}
}

View file

@ -17,33 +17,27 @@
scope 4 (inlined Unique::<[bool; 0]>::dangling) {
let mut _5: std::ptr::NonNull<[bool; 0]>;
scope 5 (inlined NonNull::<[bool; 0]>::dangling) {
let _6: *mut [bool; 0];
scope 6 {
let _6: *mut [bool; 0];
scope 7 {
debug ptr => _6;
scope 10 (inlined NonNull::<[bool; 0]>::new_unchecked) {
debug ptr => _6;
scope 12 (inlined NonNull::<[bool; 0]>::new_unchecked) {
debug ptr => _6;
let mut _8: bool;
let _9: ();
let mut _10: *mut ();
let mut _11: *const [bool; 0];
scope 13 {
scope 14 (inlined core::ub_checks::check_language_ub) {
scope 15 (inlined core::ub_checks::check_language_ub::runtime) {
}
}
let mut _8: bool;
let _9: ();
let mut _10: *mut ();
let mut _11: *const [bool; 0];
scope 11 (inlined core::ub_checks::check_language_ub) {
scope 12 (inlined core::ub_checks::check_language_ub::runtime) {
}
}
}
scope 8 (inlined dangling_mut::<[bool; 0]>) {
let mut _7: usize;
scope 9 (inlined align_of::<[bool; 0]>) {
}
scope 10 (inlined without_provenance_mut::<[bool; 0]>) {
debug addr => _7;
scope 11 {
}
}
}
scope 7 (inlined dangling_mut::<[bool; 0]>) {
let mut _7: usize;
scope 8 (inlined align_of::<[bool; 0]>) {
}
scope 9 (inlined without_provenance_mut::<[bool; 0]>) {
debug addr => _7;
}
}
}

View file

@ -17,33 +17,27 @@
scope 4 (inlined Unique::<[bool; 0]>::dangling) {
let mut _5: std::ptr::NonNull<[bool; 0]>;
scope 5 (inlined NonNull::<[bool; 0]>::dangling) {
let _6: *mut [bool; 0];
scope 6 {
let _6: *mut [bool; 0];
scope 7 {
debug ptr => _6;
scope 10 (inlined NonNull::<[bool; 0]>::new_unchecked) {
debug ptr => _6;
scope 12 (inlined NonNull::<[bool; 0]>::new_unchecked) {
debug ptr => _6;
let mut _8: bool;
let _9: ();
let mut _10: *mut ();
let mut _11: *const [bool; 0];
scope 13 {
scope 14 (inlined core::ub_checks::check_language_ub) {
scope 15 (inlined core::ub_checks::check_language_ub::runtime) {
}
}
let mut _8: bool;
let _9: ();
let mut _10: *mut ();
let mut _11: *const [bool; 0];
scope 11 (inlined core::ub_checks::check_language_ub) {
scope 12 (inlined core::ub_checks::check_language_ub::runtime) {
}
}
}
scope 8 (inlined dangling_mut::<[bool; 0]>) {
let mut _7: usize;
scope 9 (inlined align_of::<[bool; 0]>) {
}
scope 10 (inlined without_provenance_mut::<[bool; 0]>) {
debug addr => _7;
scope 11 {
}
}
}
scope 7 (inlined dangling_mut::<[bool; 0]>) {
let mut _7: usize;
scope 8 (inlined align_of::<[bool; 0]>) {
}
scope 9 (inlined without_provenance_mut::<[bool; 0]>) {
debug addr => _7;
}
}
}

View file

@ -17,33 +17,27 @@
scope 4 (inlined Unique::<[bool; 0]>::dangling) {
let mut _5: std::ptr::NonNull<[bool; 0]>;
scope 5 (inlined NonNull::<[bool; 0]>::dangling) {
let _6: *mut [bool; 0];
scope 6 {
let _6: *mut [bool; 0];
scope 7 {
debug ptr => _6;
scope 10 (inlined NonNull::<[bool; 0]>::new_unchecked) {
debug ptr => _6;
scope 12 (inlined NonNull::<[bool; 0]>::new_unchecked) {
debug ptr => _6;
let mut _8: bool;
let _9: ();
let mut _10: *mut ();
let mut _11: *const [bool; 0];
scope 13 {
scope 14 (inlined core::ub_checks::check_language_ub) {
scope 15 (inlined core::ub_checks::check_language_ub::runtime) {
}
}
let mut _8: bool;
let _9: ();
let mut _10: *mut ();
let mut _11: *const [bool; 0];
scope 11 (inlined core::ub_checks::check_language_ub) {
scope 12 (inlined core::ub_checks::check_language_ub::runtime) {
}
}
}
scope 8 (inlined dangling_mut::<[bool; 0]>) {
let mut _7: usize;
scope 9 (inlined align_of::<[bool; 0]>) {
}
scope 10 (inlined without_provenance_mut::<[bool; 0]>) {
debug addr => _7;
scope 11 {
}
}
}
scope 7 (inlined dangling_mut::<[bool; 0]>) {
let mut _7: usize;
scope 8 (inlined align_of::<[bool; 0]>) {
}
scope 9 (inlined without_provenance_mut::<[bool; 0]>) {
debug addr => _7;
}
}
}

View file

@ -17,33 +17,27 @@
scope 4 (inlined Unique::<[bool; 0]>::dangling) {
let mut _5: std::ptr::NonNull<[bool; 0]>;
scope 5 (inlined NonNull::<[bool; 0]>::dangling) {
let _6: *mut [bool; 0];
scope 6 {
let _6: *mut [bool; 0];
scope 7 {
debug ptr => _6;
scope 10 (inlined NonNull::<[bool; 0]>::new_unchecked) {
debug ptr => _6;
scope 12 (inlined NonNull::<[bool; 0]>::new_unchecked) {
debug ptr => _6;
let mut _8: bool;
let _9: ();
let mut _10: *mut ();
let mut _11: *const [bool; 0];
scope 13 {
scope 14 (inlined core::ub_checks::check_language_ub) {
scope 15 (inlined core::ub_checks::check_language_ub::runtime) {
}
}
let mut _8: bool;
let _9: ();
let mut _10: *mut ();
let mut _11: *const [bool; 0];
scope 11 (inlined core::ub_checks::check_language_ub) {
scope 12 (inlined core::ub_checks::check_language_ub::runtime) {
}
}
}
scope 8 (inlined dangling_mut::<[bool; 0]>) {
let mut _7: usize;
scope 9 (inlined align_of::<[bool; 0]>) {
}
scope 10 (inlined without_provenance_mut::<[bool; 0]>) {
debug addr => _7;
scope 11 {
}
}
}
scope 7 (inlined dangling_mut::<[bool; 0]>) {
let mut _7: usize;
scope 8 (inlined align_of::<[bool; 0]>) {
}
scope 9 (inlined without_provenance_mut::<[bool; 0]>) {
debug addr => _7;
}
}
}

View file

@ -17,33 +17,27 @@
scope 4 (inlined Unique::<[bool; 0]>::dangling) {
let mut _5: std::ptr::NonNull<[bool; 0]>;
scope 5 (inlined NonNull::<[bool; 0]>::dangling) {
let _6: *mut [bool; 0];
scope 6 {
let _6: *mut [bool; 0];
scope 7 {
debug ptr => _6;
scope 10 (inlined NonNull::<[bool; 0]>::new_unchecked) {
debug ptr => _6;
scope 12 (inlined NonNull::<[bool; 0]>::new_unchecked) {
debug ptr => _6;
let mut _8: bool;
let _9: ();
let mut _10: *mut ();
let mut _11: *const [bool; 0];
scope 13 {
scope 14 (inlined core::ub_checks::check_language_ub) {
scope 15 (inlined core::ub_checks::check_language_ub::runtime) {
}
}
let mut _8: bool;
let _9: ();
let mut _10: *mut ();
let mut _11: *const [bool; 0];
scope 11 (inlined core::ub_checks::check_language_ub) {
scope 12 (inlined core::ub_checks::check_language_ub::runtime) {
}
}
}
scope 8 (inlined dangling_mut::<[bool; 0]>) {
let mut _7: usize;
scope 9 (inlined align_of::<[bool; 0]>) {
}
scope 10 (inlined without_provenance_mut::<[bool; 0]>) {
debug addr => _7;
scope 11 {
}
}
}
scope 7 (inlined dangling_mut::<[bool; 0]>) {
let mut _7: usize;
scope 8 (inlined align_of::<[bool; 0]>) {
}
scope 9 (inlined without_provenance_mut::<[bool; 0]>) {
debug addr => _7;
}
}
}

View file

@ -17,33 +17,27 @@
scope 4 (inlined Unique::<[bool; 0]>::dangling) {
let mut _5: std::ptr::NonNull<[bool; 0]>;
scope 5 (inlined NonNull::<[bool; 0]>::dangling) {
let _6: *mut [bool; 0];
scope 6 {
let _6: *mut [bool; 0];
scope 7 {
debug ptr => _6;
scope 10 (inlined NonNull::<[bool; 0]>::new_unchecked) {
debug ptr => _6;
scope 12 (inlined NonNull::<[bool; 0]>::new_unchecked) {
debug ptr => _6;
let mut _8: bool;
let _9: ();
let mut _10: *mut ();
let mut _11: *const [bool; 0];
scope 13 {
scope 14 (inlined core::ub_checks::check_language_ub) {
scope 15 (inlined core::ub_checks::check_language_ub::runtime) {
}
}
let mut _8: bool;
let _9: ();
let mut _10: *mut ();
let mut _11: *const [bool; 0];
scope 11 (inlined core::ub_checks::check_language_ub) {
scope 12 (inlined core::ub_checks::check_language_ub::runtime) {
}
}
}
scope 8 (inlined dangling_mut::<[bool; 0]>) {
let mut _7: usize;
scope 9 (inlined align_of::<[bool; 0]>) {
}
scope 10 (inlined without_provenance_mut::<[bool; 0]>) {
debug addr => _7;
scope 11 {
}
}
}
scope 7 (inlined dangling_mut::<[bool; 0]>) {
let mut _7: usize;
scope 8 (inlined align_of::<[bool; 0]>) {
}
scope 9 (inlined without_provenance_mut::<[bool; 0]>) {
debug addr => _7;
}
}
}

View file

@ -9,14 +9,12 @@
let mut _5: *mut u8;
scope 1 {
debug x => _1;
let _3: *mut u8;
let _6: u8;
scope 2 {
let _3: *mut u8;
scope 3 {
debug p => _3;
}
debug p => _3;
}
scope 4 {
scope 3 {
debug x1 => _6;
}
}

View file

@ -9,14 +9,12 @@
let mut _5: *mut u8;
scope 1 {
debug x => _1;
let _3: *mut u8;
let _6: u8;
scope 2 {
let _3: *mut u8;
scope 3 {
debug p => _3;
}
debug p => _3;
}
scope 4 {
scope 3 {
debug x1 => _6;
}
}

View file

@ -3,8 +3,6 @@
fn from_char() -> i32 {
let mut _0: i32;
scope 1 {
}
bb0: {
- _0 = const 'R' as i32 (Transmute);

View file

@ -3,8 +3,6 @@
fn from_char() -> i32 {
let mut _0: i32;
scope 1 {
}
bb0: {
- _0 = const 'R' as i32 (Transmute);

View file

@ -3,8 +3,6 @@
fn invalid_bool() -> bool {
let mut _0: bool;
scope 1 {
}
bb0: {
- _0 = const -1_i8 as bool (Transmute);

View file

@ -3,8 +3,6 @@
fn invalid_bool() -> bool {
let mut _0: bool;
scope 1 {
}
bb0: {
- _0 = const -1_i8 as bool (Transmute);

View file

@ -3,8 +3,6 @@
fn invalid_char() -> char {
let mut _0: char;
scope 1 {
}
bb0: {
- _0 = const core::num::<impl i32>::MAX as char (Transmute);

View file

@ -3,8 +3,6 @@
fn invalid_char() -> char {
let mut _0: char;
scope 1 {
}
bb0: {
- _0 = const core::num::<impl i32>::MAX as char (Transmute);

View file

@ -4,8 +4,6 @@
fn less_as_i8() -> i8 {
let mut _0: i8;
let mut _1: std::cmp::Ordering;
scope 1 {
}
bb0: {
StorageLive(_1);

View file

@ -4,8 +4,6 @@
fn less_as_i8() -> i8 {
let mut _0: i8;
let mut _1: std::cmp::Ordering;
scope 1 {
}
bb0: {
StorageLive(_1);

View file

@ -5,8 +5,6 @@
let mut _0: u32;
let mut _1: undef_union_as_integer::Union32;
let mut _2: ();
scope 1 {
}
bb0: {
StorageLive(_1);

View file

@ -5,8 +5,6 @@
let mut _0: u32;
let mut _1: undef_union_as_integer::Union32;
let mut _2: ();
scope 1 {
}
bb0: {
StorageLive(_1);

View file

@ -8,8 +8,6 @@
scope 1 {
debug x => _1;
}
scope 2 {
}
bb0: {
StorageLive(_1);

View file

@ -8,8 +8,6 @@
scope 1 {
debug x => _1;
}
scope 2 {
}
bb0: {
StorageLive(_1);

View file

@ -8,8 +8,6 @@
scope 1 {
debug x => _1;
}
scope 2 {
}
bb0: {
StorageLive(_1);

View file

@ -8,8 +8,6 @@
scope 1 {
debug x => _1;
}
scope 2 {
}
bb0: {
StorageLive(_1);

View file

@ -8,8 +8,6 @@
scope 1 {
debug x => _1;
}
scope 2 {
}
bb0: {
StorageLive(_1);

View file

@ -8,8 +8,6 @@
scope 1 {
debug x => _1;
}
scope 2 {
}
bb0: {
StorageLive(_1);

View file

@ -7,8 +7,6 @@
scope 1 {
debug x => _1;
}
scope 2 {
}
bb0: {
StorageLive(_1);

View file

@ -7,8 +7,6 @@
scope 1 {
debug x => _1;
}
scope 2 {
}
bb0: {
StorageLive(_1);

View file

@ -3,8 +3,6 @@
fn valid_char() -> char {
let mut _0: char;
scope 1 {
}
bb0: {
- _0 = const 82_u32 as char (Transmute);

View file

@ -3,8 +3,6 @@
fn valid_char() -> char {
let mut _0: char;
scope 1 {
}
bb0: {
- _0 = const 82_u32 as char (Transmute);

View file

@ -8,13 +8,11 @@
let mut _3: u32;
scope 1 {
debug un => _1;
scope 2 {
}
scope 4 (inlined std::mem::drop::<u32>) {
scope 3 (inlined std::mem::drop::<u32>) {
debug _x => _3;
}
}
scope 3 (inlined val) {
scope 2 (inlined val) {
}
bb0: {

View file

@ -8,13 +8,11 @@
let mut _3: u32;
scope 1 {
debug un => _1;
scope 2 {
}
scope 4 (inlined std::mem::drop::<u32>) {
scope 3 (inlined std::mem::drop::<u32>) {
debug _x => _3;
}
}
scope 3 (inlined val) {
scope 2 (inlined val) {
}
bb0: {

View file

@ -37,17 +37,9 @@
debug z => _8;
let _13: *mut u32;
scope 2 {
}
scope 3 {
}
scope 4 {
debug z => _13;
let _18: &u32;
scope 5 {
}
scope 6 {
}
scope 7 {
scope 3 {
debug z => _18;
}
}

View file

@ -37,17 +37,9 @@
debug z => _8;
let _13: *mut u32;
scope 2 {
}
scope 3 {
}
scope 4 {
debug z => _13;
let _18: &u32;
scope 5 {
}
scope 6 {
}
scope 7 {
scope 3 {
debug z => _18;
}
}

View file

@ -69,17 +69,15 @@
debug u => _29;
let _41: &*const u8;
let _42: &*const u8;
scope 7 {
scope 6 {
debug left_val => _41;
debug right_val => _42;
let _47: core::panicking::AssertKind;
scope 8 {
scope 7 {
debug kind => _47;
}
}
}
scope 6 {
}
}
}

Some files were not shown because too many files have changed in this diff Show more