mirror of
https://github.com/rust-lang/rust
synced 2024-09-05 08:37:14 +00:00
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:
commit
99c42d2340
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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) }
|
||||
|
|
|
@ -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>,
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
|
||||
|
|
|
@ -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![
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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> {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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>,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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() {}
|
||||
|
|
|
@ -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) { }
|
||||
}
|
||||
|
|
|
@ -17,8 +17,6 @@ fn main() -> () {
|
|||
let _3: *mut usize;
|
||||
scope 3 {
|
||||
debug z => _3;
|
||||
scope 4 {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,8 +17,6 @@ fn main() -> () {
|
|||
let _3: *mut usize;
|
||||
scope 3 {
|
||||
debug z => _3;
|
||||
scope 4 {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,8 +3,6 @@
|
|||
fn main() -> () {
|
||||
let mut _0: ();
|
||||
let _1: ();
|
||||
scope 1 {
|
||||
}
|
||||
|
||||
bb0: {
|
||||
StorageLive(_1);
|
||||
|
|
|
@ -15,8 +15,6 @@
|
|||
scope 1 {
|
||||
debug x => _1;
|
||||
}
|
||||
scope 2 {
|
||||
}
|
||||
|
||||
bb0: {
|
||||
StorageLive(_1);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -9,8 +9,6 @@
|
|||
let mut _4: &i32;
|
||||
let _5: *const i32;
|
||||
+ let mut _6: &[&i32; 1];
|
||||
scope 1 {
|
||||
}
|
||||
|
||||
bb0: {
|
||||
StorageLive(_1);
|
||||
|
|
|
@ -14,8 +14,6 @@
|
|||
debug ptr => _3;
|
||||
let _5: bool;
|
||||
scope 3 {
|
||||
}
|
||||
scope 4 {
|
||||
debug ret => _5;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -15,8 +15,6 @@
|
|||
scope 1 {
|
||||
debug x => _1;
|
||||
}
|
||||
scope 2 {
|
||||
}
|
||||
|
||||
bb0: {
|
||||
StorageLive(_1);
|
||||
|
|
|
@ -15,8 +15,6 @@
|
|||
scope 1 {
|
||||
debug x => _1;
|
||||
}
|
||||
scope 2 {
|
||||
}
|
||||
|
||||
bb0: {
|
||||
StorageLive(_1);
|
||||
|
|
|
@ -11,8 +11,6 @@
|
|||
debug v => _1;
|
||||
let _4: bool;
|
||||
scope 2 {
|
||||
}
|
||||
scope 3 {
|
||||
debug y => _4;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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: {
|
||||
|
|
|
@ -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: {
|
||||
|
|
|
@ -11,8 +11,6 @@
|
|||
debug x => _1;
|
||||
let _5: u32;
|
||||
scope 2 {
|
||||
}
|
||||
scope 3 {
|
||||
debug y => _5;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,8 +3,6 @@
|
|||
|
||||
fn from_char() -> i32 {
|
||||
let mut _0: i32;
|
||||
scope 1 {
|
||||
}
|
||||
|
||||
bb0: {
|
||||
- _0 = const 'R' as i32 (Transmute);
|
||||
|
|
|
@ -3,8 +3,6 @@
|
|||
|
||||
fn from_char() -> i32 {
|
||||
let mut _0: i32;
|
||||
scope 1 {
|
||||
}
|
||||
|
||||
bb0: {
|
||||
- _0 = const 'R' as i32 (Transmute);
|
||||
|
|
|
@ -3,8 +3,6 @@
|
|||
|
||||
fn invalid_bool() -> bool {
|
||||
let mut _0: bool;
|
||||
scope 1 {
|
||||
}
|
||||
|
||||
bb0: {
|
||||
- _0 = const -1_i8 as bool (Transmute);
|
||||
|
|
|
@ -3,8 +3,6 @@
|
|||
|
||||
fn invalid_bool() -> bool {
|
||||
let mut _0: bool;
|
||||
scope 1 {
|
||||
}
|
||||
|
||||
bb0: {
|
||||
- _0 = const -1_i8 as bool (Transmute);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -4,8 +4,6 @@
|
|||
fn less_as_i8() -> i8 {
|
||||
let mut _0: i8;
|
||||
let mut _1: std::cmp::Ordering;
|
||||
scope 1 {
|
||||
}
|
||||
|
||||
bb0: {
|
||||
StorageLive(_1);
|
||||
|
|
|
@ -4,8 +4,6 @@
|
|||
fn less_as_i8() -> i8 {
|
||||
let mut _0: i8;
|
||||
let mut _1: std::cmp::Ordering;
|
||||
scope 1 {
|
||||
}
|
||||
|
||||
bb0: {
|
||||
StorageLive(_1);
|
||||
|
|
|
@ -5,8 +5,6 @@
|
|||
let mut _0: u32;
|
||||
let mut _1: undef_union_as_integer::Union32;
|
||||
let mut _2: ();
|
||||
scope 1 {
|
||||
}
|
||||
|
||||
bb0: {
|
||||
StorageLive(_1);
|
||||
|
|
|
@ -5,8 +5,6 @@
|
|||
let mut _0: u32;
|
||||
let mut _1: undef_union_as_integer::Union32;
|
||||
let mut _2: ();
|
||||
scope 1 {
|
||||
}
|
||||
|
||||
bb0: {
|
||||
StorageLive(_1);
|
||||
|
|
|
@ -8,8 +8,6 @@
|
|||
scope 1 {
|
||||
debug x => _1;
|
||||
}
|
||||
scope 2 {
|
||||
}
|
||||
|
||||
bb0: {
|
||||
StorageLive(_1);
|
||||
|
|
|
@ -8,8 +8,6 @@
|
|||
scope 1 {
|
||||
debug x => _1;
|
||||
}
|
||||
scope 2 {
|
||||
}
|
||||
|
||||
bb0: {
|
||||
StorageLive(_1);
|
||||
|
|
|
@ -8,8 +8,6 @@
|
|||
scope 1 {
|
||||
debug x => _1;
|
||||
}
|
||||
scope 2 {
|
||||
}
|
||||
|
||||
bb0: {
|
||||
StorageLive(_1);
|
||||
|
|
|
@ -8,8 +8,6 @@
|
|||
scope 1 {
|
||||
debug x => _1;
|
||||
}
|
||||
scope 2 {
|
||||
}
|
||||
|
||||
bb0: {
|
||||
StorageLive(_1);
|
||||
|
|
|
@ -8,8 +8,6 @@
|
|||
scope 1 {
|
||||
debug x => _1;
|
||||
}
|
||||
scope 2 {
|
||||
}
|
||||
|
||||
bb0: {
|
||||
StorageLive(_1);
|
||||
|
|
|
@ -8,8 +8,6 @@
|
|||
scope 1 {
|
||||
debug x => _1;
|
||||
}
|
||||
scope 2 {
|
||||
}
|
||||
|
||||
bb0: {
|
||||
StorageLive(_1);
|
||||
|
|
|
@ -7,8 +7,6 @@
|
|||
scope 1 {
|
||||
debug x => _1;
|
||||
}
|
||||
scope 2 {
|
||||
}
|
||||
|
||||
bb0: {
|
||||
StorageLive(_1);
|
||||
|
|
|
@ -7,8 +7,6 @@
|
|||
scope 1 {
|
||||
debug x => _1;
|
||||
}
|
||||
scope 2 {
|
||||
}
|
||||
|
||||
bb0: {
|
||||
StorageLive(_1);
|
||||
|
|
|
@ -3,8 +3,6 @@
|
|||
|
||||
fn valid_char() -> char {
|
||||
let mut _0: char;
|
||||
scope 1 {
|
||||
}
|
||||
|
||||
bb0: {
|
||||
- _0 = const 82_u32 as char (Transmute);
|
||||
|
|
|
@ -3,8 +3,6 @@
|
|||
|
||||
fn valid_char() -> char {
|
||||
let mut _0: char;
|
||||
scope 1 {
|
||||
}
|
||||
|
||||
bb0: {
|
||||
- _0 = const 82_u32 as char (Transmute);
|
||||
|
|
|
@ -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: {
|
||||
|
|
|
@ -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: {
|
||||
|
|
|
@ -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: {
|
||||
|
|
|
@ -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: {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,8 +3,6 @@
|
|||
|
||||
fn from_char() -> i32 {
|
||||
let mut _0: i32;
|
||||
scope 1 {
|
||||
}
|
||||
|
||||
bb0: {
|
||||
- _0 = const 'R' as i32 (Transmute);
|
||||
|
|
|
@ -3,8 +3,6 @@
|
|||
|
||||
fn from_char() -> i32 {
|
||||
let mut _0: i32;
|
||||
scope 1 {
|
||||
}
|
||||
|
||||
bb0: {
|
||||
- _0 = const 'R' as i32 (Transmute);
|
||||
|
|
|
@ -3,8 +3,6 @@
|
|||
|
||||
fn invalid_bool() -> bool {
|
||||
let mut _0: bool;
|
||||
scope 1 {
|
||||
}
|
||||
|
||||
bb0: {
|
||||
- _0 = const -1_i8 as bool (Transmute);
|
||||
|
|
|
@ -3,8 +3,6 @@
|
|||
|
||||
fn invalid_bool() -> bool {
|
||||
let mut _0: bool;
|
||||
scope 1 {
|
||||
}
|
||||
|
||||
bb0: {
|
||||
- _0 = const -1_i8 as bool (Transmute);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -4,8 +4,6 @@
|
|||
fn less_as_i8() -> i8 {
|
||||
let mut _0: i8;
|
||||
let mut _1: std::cmp::Ordering;
|
||||
scope 1 {
|
||||
}
|
||||
|
||||
bb0: {
|
||||
StorageLive(_1);
|
||||
|
|
|
@ -4,8 +4,6 @@
|
|||
fn less_as_i8() -> i8 {
|
||||
let mut _0: i8;
|
||||
let mut _1: std::cmp::Ordering;
|
||||
scope 1 {
|
||||
}
|
||||
|
||||
bb0: {
|
||||
StorageLive(_1);
|
||||
|
|
|
@ -5,8 +5,6 @@
|
|||
let mut _0: u32;
|
||||
let mut _1: undef_union_as_integer::Union32;
|
||||
let mut _2: ();
|
||||
scope 1 {
|
||||
}
|
||||
|
||||
bb0: {
|
||||
StorageLive(_1);
|
||||
|
|
|
@ -5,8 +5,6 @@
|
|||
let mut _0: u32;
|
||||
let mut _1: undef_union_as_integer::Union32;
|
||||
let mut _2: ();
|
||||
scope 1 {
|
||||
}
|
||||
|
||||
bb0: {
|
||||
StorageLive(_1);
|
||||
|
|
|
@ -8,8 +8,6 @@
|
|||
scope 1 {
|
||||
debug x => _1;
|
||||
}
|
||||
scope 2 {
|
||||
}
|
||||
|
||||
bb0: {
|
||||
StorageLive(_1);
|
||||
|
|
|
@ -8,8 +8,6 @@
|
|||
scope 1 {
|
||||
debug x => _1;
|
||||
}
|
||||
scope 2 {
|
||||
}
|
||||
|
||||
bb0: {
|
||||
StorageLive(_1);
|
||||
|
|
|
@ -8,8 +8,6 @@
|
|||
scope 1 {
|
||||
debug x => _1;
|
||||
}
|
||||
scope 2 {
|
||||
}
|
||||
|
||||
bb0: {
|
||||
StorageLive(_1);
|
||||
|
|
|
@ -8,8 +8,6 @@
|
|||
scope 1 {
|
||||
debug x => _1;
|
||||
}
|
||||
scope 2 {
|
||||
}
|
||||
|
||||
bb0: {
|
||||
StorageLive(_1);
|
||||
|
|
|
@ -8,8 +8,6 @@
|
|||
scope 1 {
|
||||
debug x => _1;
|
||||
}
|
||||
scope 2 {
|
||||
}
|
||||
|
||||
bb0: {
|
||||
StorageLive(_1);
|
||||
|
|
|
@ -8,8 +8,6 @@
|
|||
scope 1 {
|
||||
debug x => _1;
|
||||
}
|
||||
scope 2 {
|
||||
}
|
||||
|
||||
bb0: {
|
||||
StorageLive(_1);
|
||||
|
|
|
@ -7,8 +7,6 @@
|
|||
scope 1 {
|
||||
debug x => _1;
|
||||
}
|
||||
scope 2 {
|
||||
}
|
||||
|
||||
bb0: {
|
||||
StorageLive(_1);
|
||||
|
|
|
@ -7,8 +7,6 @@
|
|||
scope 1 {
|
||||
debug x => _1;
|
||||
}
|
||||
scope 2 {
|
||||
}
|
||||
|
||||
bb0: {
|
||||
StorageLive(_1);
|
||||
|
|
|
@ -3,8 +3,6 @@
|
|||
|
||||
fn valid_char() -> char {
|
||||
let mut _0: char;
|
||||
scope 1 {
|
||||
}
|
||||
|
||||
bb0: {
|
||||
- _0 = const 82_u32 as char (Transmute);
|
||||
|
|
|
@ -3,8 +3,6 @@
|
|||
|
||||
fn valid_char() -> char {
|
||||
let mut _0: char;
|
||||
scope 1 {
|
||||
}
|
||||
|
||||
bb0: {
|
||||
- _0 = const 82_u32 as char (Transmute);
|
||||
|
|
|
@ -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: {
|
||||
|
|
|
@ -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: {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
Loading…
Reference in a new issue