Skip to content

Commit 5af16c1

Browse files
authored
Rollup merge of rust-lang#108505 - Nilstrieb:further-unify-validity-intrinsics, r=michaelwoerister
Further unify validity intrinsics Also merges the inhabitedness check into the query to further unify the code paths. Depends on rust-lang#108364
2 parents 1c3cc8b + 5f593da commit 5af16c1

File tree

11 files changed

+119
-163
lines changed

11 files changed

+119
-163
lines changed

compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs

+31-49
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ pub(crate) use cpuid::codegen_cpuid_call;
2222
pub(crate) use llvm::codegen_llvm_intrinsic_call;
2323

2424
use rustc_middle::ty;
25-
use rustc_middle::ty::layout::{HasParamEnv, InitKind};
25+
use rustc_middle::ty::layout::{HasParamEnv, ValidityRequirement};
2626
use rustc_middle::ty::print::with_no_trimmed_paths;
2727
use rustc_middle::ty::subst::SubstsRef;
2828
use rustc_span::symbol::{kw, sym, Symbol};
@@ -628,57 +628,39 @@ fn codegen_regular_intrinsic_call<'tcx>(
628628
intrinsic_args!(fx, args => (); intrinsic);
629629

630630
let ty = substs.type_at(0);
631-
let layout = fx.layout_of(ty);
632-
if layout.abi.is_uninhabited() {
633-
with_no_trimmed_paths!({
634-
crate::base::codegen_panic_nounwind(
635-
fx,
636-
&format!("attempted to instantiate uninhabited type `{}`", layout.ty),
637-
source_info,
638-
)
639-
});
640-
return;
641-
}
642631

643-
if intrinsic == sym::assert_zero_valid
644-
&& !fx
645-
.tcx
646-
.check_validity_of_init((InitKind::Zero, fx.param_env().and(ty)))
647-
.expect("expected to have layout during codegen")
648-
{
649-
with_no_trimmed_paths!({
650-
crate::base::codegen_panic_nounwind(
651-
fx,
652-
&format!(
653-
"attempted to zero-initialize type `{}`, which is invalid",
654-
layout.ty
655-
),
656-
source_info,
657-
);
658-
});
659-
return;
660-
}
632+
let requirement = ValidityRequirement::from_intrinsic(intrinsic);
661633

662-
if intrinsic == sym::assert_mem_uninitialized_valid
663-
&& !fx
634+
if let Some(requirement) = requirement {
635+
let do_panic = !fx
664636
.tcx
665-
.check_validity_of_init((
666-
InitKind::UninitMitigated0x01Fill,
667-
fx.param_env().and(ty),
668-
))
669-
.expect("expected to have layout during codegen")
670-
{
671-
with_no_trimmed_paths!({
672-
crate::base::codegen_panic_nounwind(
673-
fx,
674-
&format!(
675-
"attempted to leave type `{}` uninitialized, which is invalid",
676-
layout.ty
677-
),
678-
source_info,
679-
)
680-
});
681-
return;
637+
.check_validity_requirement((requirement, fx.param_env().and(ty)))
638+
.expect("expect to have layout during codegen");
639+
640+
if do_panic {
641+
let layout = fx.layout_of(ty);
642+
643+
with_no_trimmed_paths!({
644+
crate::base::codegen_panic_nounwind(
645+
fx,
646+
&if layout.abi.is_uninhabited() {
647+
format!("attempted to instantiate uninhabited type `{}`", layout.ty)
648+
} else if requirement == ValidityRequirement::Zero {
649+
format!(
650+
"attempted to zero-initialize type `{}`, which is invalid",
651+
layout.ty
652+
)
653+
} else {
654+
format!(
655+
"attempted to leave type `{}` uninitialized, which is invalid",
656+
layout.ty
657+
)
658+
},
659+
source_info,
660+
)
661+
});
662+
return;
663+
}
682664
}
683665
}
684666

compiler/rustc_codegen_ssa/src/mir/block.rs

+11-31
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
1414
use rustc_hir::lang_items::LangItem;
1515
use rustc_index::vec::Idx;
1616
use rustc_middle::mir::{self, AssertKind, SwitchTargets};
17-
use rustc_middle::ty::layout::{HasTyCtxt, InitKind, LayoutOf};
17+
use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, ValidityRequirement};
1818
use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths};
1919
use rustc_middle::ty::{self, Instance, Ty, TypeVisitableExt};
2020
use rustc_session::config::OptLevel;
@@ -655,44 +655,24 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
655655
// Emit a panic or a no-op for `assert_*` intrinsics.
656656
// These are intrinsics that compile to panics so that we can get a message
657657
// which mentions the offending type, even from a const context.
658-
#[derive(Debug, PartialEq)]
659-
enum AssertIntrinsic {
660-
Inhabited,
661-
ZeroValid,
662-
MemUninitializedValid,
663-
}
664-
let panic_intrinsic = intrinsic.and_then(|i| match i {
665-
sym::assert_inhabited => Some(AssertIntrinsic::Inhabited),
666-
sym::assert_zero_valid => Some(AssertIntrinsic::ZeroValid),
667-
sym::assert_mem_uninitialized_valid => Some(AssertIntrinsic::MemUninitializedValid),
668-
_ => None,
669-
});
670-
if let Some(intrinsic) = panic_intrinsic {
671-
use AssertIntrinsic::*;
672-
658+
let panic_intrinsic = intrinsic.and_then(|s| ValidityRequirement::from_intrinsic(s));
659+
if let Some(requirement) = panic_intrinsic {
673660
let ty = instance.unwrap().substs.type_at(0);
661+
662+
let do_panic = !bx
663+
.tcx()
664+
.check_validity_requirement((requirement, bx.param_env().and(ty)))
665+
.expect("expect to have layout during codegen");
666+
674667
let layout = bx.layout_of(ty);
675-
let do_panic = match intrinsic {
676-
Inhabited => layout.abi.is_uninhabited(),
677-
ZeroValid => !bx
678-
.tcx()
679-
.check_validity_of_init((InitKind::Zero, bx.param_env().and(ty)))
680-
.expect("expected to have layout during codegen"),
681-
MemUninitializedValid => !bx
682-
.tcx()
683-
.check_validity_of_init((
684-
InitKind::UninitMitigated0x01Fill,
685-
bx.param_env().and(ty),
686-
))
687-
.expect("expected to have layout during codegen"),
688-
};
668+
689669
Some(if do_panic {
690670
let msg_str = with_no_visible_paths!({
691671
with_no_trimmed_paths!({
692672
if layout.abi.is_uninhabited() {
693673
// Use this error even for the other intrinsics as it is more precise.
694674
format!("attempted to instantiate uninhabited type `{}`", ty)
695-
} else if intrinsic == ZeroValid {
675+
} else if requirement == ValidityRequirement::Zero {
696676
format!("attempted to zero-initialize type `{}`, which is invalid", ty)
697677
} else {
698678
format!(

compiler/rustc_const_eval/src/interpret/intrinsics.rs

+26-48
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use rustc_middle::mir::{
1111
BinOp, NonDivergingIntrinsic,
1212
};
1313
use rustc_middle::ty;
14-
use rustc_middle::ty::layout::{InitKind, LayoutOf as _};
14+
use rustc_middle::ty::layout::{LayoutOf as _, ValidityRequirement};
1515
use rustc_middle::ty::subst::SubstsRef;
1616
use rustc_middle::ty::{Ty, TyCtxt};
1717
use rustc_span::symbol::{sym, Symbol};
@@ -418,57 +418,35 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
418418
| sym::assert_zero_valid
419419
| sym::assert_mem_uninitialized_valid => {
420420
let ty = instance.substs.type_at(0);
421-
let layout = self.layout_of(ty)?;
422-
423-
// For *all* intrinsics we first check `is_uninhabited` to give a more specific
424-
// error message.
425-
if layout.abi.is_uninhabited() {
426-
// The run-time intrinsic panics just to get a good backtrace; here we abort
427-
// since there is no problem showing a backtrace even for aborts.
428-
M::abort(
429-
self,
430-
format!(
421+
let requirement = ValidityRequirement::from_intrinsic(intrinsic_name).unwrap();
422+
423+
let should_panic = !self
424+
.tcx
425+
.check_validity_requirement((requirement, self.param_env.and(ty)))
426+
.map_err(|_| err_inval!(TooGeneric))?;
427+
428+
if should_panic {
429+
let layout = self.layout_of(ty)?;
430+
431+
let msg = match requirement {
432+
// For *all* intrinsics we first check `is_uninhabited` to give a more specific
433+
// error message.
434+
_ if layout.abi.is_uninhabited() => format!(
431435
"aborted execution: attempted to instantiate uninhabited type `{}`",
432436
ty
433437
),
434-
)?;
435-
}
436-
437-
if intrinsic_name == sym::assert_zero_valid {
438-
let should_panic = !self
439-
.tcx
440-
.check_validity_of_init((InitKind::Zero, self.param_env.and(ty)))
441-
.map_err(|_| err_inval!(TooGeneric))?;
442-
443-
if should_panic {
444-
M::abort(
445-
self,
446-
format!(
447-
"aborted execution: attempted to zero-initialize type `{}`, which is invalid",
448-
ty
449-
),
450-
)?;
451-
}
452-
}
438+
ValidityRequirement::Inhabited => bug!("handled earlier"),
439+
ValidityRequirement::Zero => format!(
440+
"aborted execution: attempted to zero-initialize type `{}`, which is invalid",
441+
ty
442+
),
443+
ValidityRequirement::UninitMitigated0x01Fill => format!(
444+
"aborted execution: attempted to leave type `{}` uninitialized, which is invalid",
445+
ty
446+
),
447+
};
453448

454-
if intrinsic_name == sym::assert_mem_uninitialized_valid {
455-
let should_panic = !self
456-
.tcx
457-
.check_validity_of_init((
458-
InitKind::UninitMitigated0x01Fill,
459-
self.param_env.and(ty),
460-
))
461-
.map_err(|_| err_inval!(TooGeneric))?;
462-
463-
if should_panic {
464-
M::abort(
465-
self,
466-
format!(
467-
"aborted execution: attempted to leave type `{}` uninitialized, which is invalid",
468-
ty
469-
),
470-
)?;
471-
}
449+
M::abort(self, msg)?;
472450
}
473451
}
474452
sym::simd_insert => {

compiler/rustc_const_eval/src/lib.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ pub fn provide(providers: &mut Providers) {
6161
let (param_env, value) = param_env_and_value.into_parts();
6262
const_eval::deref_mir_constant(tcx, param_env, value)
6363
};
64-
providers.check_validity_of_init = |tcx, (init_kind, param_env_and_ty)| {
65-
util::might_permit_raw_init(tcx, init_kind, param_env_and_ty)
64+
providers.check_validity_requirement = |tcx, (init_kind, param_env_and_ty)| {
65+
util::check_validity_requirement(tcx, init_kind, param_env_and_ty)
6666
};
6767
}

compiler/rustc_const_eval/src/util/might_permit_raw_init.rs compiler/rustc_const_eval/src/util/check_validity_requirement.rs

+20-10
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use rustc_middle::ty::layout::{InitKind, LayoutCx, LayoutError, LayoutOf, TyAndLayout};
1+
use rustc_middle::ty::layout::{LayoutCx, LayoutError, LayoutOf, TyAndLayout, ValidityRequirement};
22
use rustc_middle::ty::{ParamEnv, ParamEnvAnd, Ty, TyCtxt};
33
use rustc_session::Limit;
44
use rustc_target::abi::{Abi, FieldsShape, Scalar, Variants};
@@ -18,16 +18,23 @@ use crate::interpret::{InterpCx, MemoryKind, OpTy};
1818
/// Rust UB as long as there is no risk of miscompilations. The `strict_init_checks` can be set to
1919
/// do a full check against Rust UB instead (in which case we will also ignore the 0x01-filling and
2020
/// to the full uninit check).
21-
pub fn might_permit_raw_init<'tcx>(
21+
pub fn check_validity_requirement<'tcx>(
2222
tcx: TyCtxt<'tcx>,
23-
kind: InitKind,
23+
kind: ValidityRequirement,
2424
param_env_and_ty: ParamEnvAnd<'tcx, Ty<'tcx>>,
2525
) -> Result<bool, LayoutError<'tcx>> {
26+
let layout = tcx.layout_of(param_env_and_ty)?;
27+
28+
// There is nothing strict or lax about inhabitedness.
29+
if kind == ValidityRequirement::Inhabited {
30+
return Ok(!layout.abi.is_uninhabited());
31+
}
32+
2633
if tcx.sess.opts.unstable_opts.strict_init_checks {
27-
might_permit_raw_init_strict(tcx.layout_of(param_env_and_ty)?, tcx, kind)
34+
might_permit_raw_init_strict(layout, tcx, kind)
2835
} else {
2936
let layout_cx = LayoutCx { tcx, param_env: param_env_and_ty.param_env };
30-
might_permit_raw_init_lax(tcx.layout_of(param_env_and_ty)?, &layout_cx, kind)
37+
might_permit_raw_init_lax(layout, &layout_cx, kind)
3138
}
3239
}
3340

@@ -36,7 +43,7 @@ pub fn might_permit_raw_init<'tcx>(
3643
fn might_permit_raw_init_strict<'tcx>(
3744
ty: TyAndLayout<'tcx>,
3845
tcx: TyCtxt<'tcx>,
39-
kind: InitKind,
46+
kind: ValidityRequirement,
4047
) -> Result<bool, LayoutError<'tcx>> {
4148
let machine = CompileTimeInterpreter::new(
4249
Limit::new(0),
@@ -50,7 +57,7 @@ fn might_permit_raw_init_strict<'tcx>(
5057
.allocate(ty, MemoryKind::Machine(crate::const_eval::MemoryKind::Heap))
5158
.expect("OOM: failed to allocate for uninit check");
5259

53-
if kind == InitKind::Zero {
60+
if kind == ValidityRequirement::Zero {
5461
cx.write_bytes_ptr(
5562
allocated.ptr,
5663
std::iter::repeat(0_u8).take(ty.layout.size().bytes_usize()),
@@ -72,15 +79,18 @@ fn might_permit_raw_init_strict<'tcx>(
7279
fn might_permit_raw_init_lax<'tcx>(
7380
this: TyAndLayout<'tcx>,
7481
cx: &LayoutCx<'tcx, TyCtxt<'tcx>>,
75-
init_kind: InitKind,
82+
init_kind: ValidityRequirement,
7683
) -> Result<bool, LayoutError<'tcx>> {
7784
let scalar_allows_raw_init = move |s: Scalar| -> bool {
7885
match init_kind {
79-
InitKind::Zero => {
86+
ValidityRequirement::Inhabited => {
87+
bug!("ValidityRequirement::Inhabited should have been handled above")
88+
}
89+
ValidityRequirement::Zero => {
8090
// The range must contain 0.
8191
s.valid_range(cx).contains(0)
8292
}
83-
InitKind::UninitMitigated0x01Fill => {
93+
ValidityRequirement::UninitMitigated0x01Fill => {
8494
// The range must include an 0x01-filled buffer.
8595
let mut val: u128 = 0x01;
8696
for _ in 1..s.size(cx).bytes() {
+2-2
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
mod alignment;
22
mod call_kind;
3+
mod check_validity_requirement;
34
pub mod collect_writes;
45
mod compare_types;
56
mod find_self_call;
6-
mod might_permit_raw_init;
77
mod type_name;
88

99
pub use self::alignment::is_disaligned;
1010
pub use self::call_kind::{call_kind, CallDesugaringKind, CallKind};
11+
pub use self::check_validity_requirement::check_validity_requirement;
1112
pub use self::compare_types::{is_equal_up_to_subtyping, is_subtype};
1213
pub use self::find_self_call::find_self_call;
13-
pub use self::might_permit_raw_init::might_permit_raw_init;
1414
pub use self::type_name::type_name;

compiler/rustc_middle/src/query/keys.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use crate::infer::canonical::Canonical;
44
use crate::mir;
55
use crate::traits;
66
use crate::ty::fast_reject::SimplifiedType;
7-
use crate::ty::layout::{InitKind, TyAndLayout};
7+
use crate::ty::layout::{TyAndLayout, ValidityRequirement};
88
use crate::ty::subst::{GenericArg, SubstsRef};
99
use crate::ty::{self, Ty, TyCtxt};
1010
use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE};
@@ -698,7 +698,7 @@ impl Key for HirId {
698698
}
699699
}
700700

701-
impl<'tcx> Key for (InitKind, ty::ParamEnvAnd<'tcx, Ty<'tcx>>) {
701+
impl<'tcx> Key for (ValidityRequirement, ty::ParamEnvAnd<'tcx, Ty<'tcx>>) {
702702
type CacheSelector = DefaultCacheSelector<Self>;
703703

704704
// Just forward to `Ty<'tcx>`

compiler/rustc_middle/src/query/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -2166,8 +2166,8 @@ rustc_queries! {
21662166
separate_provide_extern
21672167
}
21682168

2169-
query check_validity_of_init(key: (InitKind, ty::ParamEnvAnd<'tcx, Ty<'tcx>>)) -> Result<bool, ty::layout::LayoutError<'tcx>> {
2170-
desc { "checking to see if `{}` permits being left {}", key.1.value, key.0 }
2169+
query check_validity_requirement(key: (ValidityRequirement, ty::ParamEnvAnd<'tcx, Ty<'tcx>>)) -> Result<bool, ty::layout::LayoutError<'tcx>> {
2170+
desc { "checking validity requirement for `{}`: {}", key.1.value, key.0 }
21712171
}
21722172

21732173
query compare_impl_const(

0 commit comments

Comments
 (0)