Skip to content

Rollup of 5 pull requests #99184

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 22 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
b361638
Use constant eval to do strict validity checks
5225225 Jul 7, 2022
c84cfa4
All init checks go through rustc_const_eval, cleanup
5225225 Jul 9, 2022
ab4a80e
Adjust docs on old might_permit_raw_init, cleanup
5225225 Jul 9, 2022
b398fa5
Cleanup, move might_permit_raw_init to own file
5225225 Jul 9, 2022
bfb3afe
Add some autolabels for A-bootstrap and T-infra
jyn514 Jul 10, 2022
b7c1868
Cleanup not needed arguments
5225225 Jul 11, 2022
236c7c0
Add test for uninit value with validity invariant in array
5225225 Jul 11, 2022
b608043
factor 'is this type allowed as union field on stable' into separate …
RalfJung Jun 11, 2022
55a1ccf
allow unions with mutable references and tuples of allowed types
RalfJung Jun 11, 2022
cafbd73
also allow arrays of allowed types
RalfJung Jun 19, 2022
1401396
remove untagged_union feature gate
RalfJung Jun 30, 2022
1cf6f5c
assigning to a union field can never drop now
RalfJung Jun 30, 2022
7a24f8e
add array tests, cleanup, tidy, and bless
RalfJung Jun 30, 2022
944c0e2
check non_exhaustive attr and private fields for transparent types
fee1-dead Jul 7, 2022
e652147
add more tests
fee1-dead Jul 10, 2022
d812850
fix documentation
fee1-dead Jul 12, 2022
697dfb5
:arrow_up: rust-analyzer
lnicola Jul 12, 2022
4ef94c9
Rollup merge of #97995 - RalfJung:union-more-nodrop, r=Mark-Simulacrum
Dylan-DPC Jul 12, 2022
70408a0
Rollup merge of #99020 - fee1-dead-contrib:repr_transparent_non_exhau…
Dylan-DPC Jul 12, 2022
224d9e5
Rollup merge of #99033 - 5225225:interpreter-validity-checks, r=oli-obk
Dylan-DPC Jul 12, 2022
7de56f0
Rollup merge of #99132 - jyn514:autolabel, r=Mark-Simulacrum
Dylan-DPC Jul 12, 2022
9ef556f
Rollup merge of #99176 - lnicola:rust-analyzer-2022-07-12, r=lnicola
Dylan-DPC Jul 12, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3664,6 +3664,7 @@ dependencies = [
"rustc_arena",
"rustc_ast",
"rustc_attr",
"rustc_const_eval",
"rustc_data_structures",
"rustc_errors",
"rustc_fs_util",
Expand Down
11 changes: 3 additions & 8 deletions compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ mod simd;
pub(crate) use cpuid::codegen_cpuid_call;
pub(crate) use llvm::codegen_llvm_intrinsic_call;

use rustc_const_eval::might_permit_raw_init::might_permit_raw_init;
use rustc_middle::ty::print::with_no_trimmed_paths;
use rustc_middle::ty::subst::SubstsRef;
use rustc_span::symbol::{kw, sym, Symbol};
Expand Down Expand Up @@ -673,10 +674,7 @@ fn codegen_regular_intrinsic_call<'tcx>(
}

if intrinsic == sym::assert_zero_valid
&& !layout.might_permit_raw_init(
fx,
InitKind::Zero,
fx.tcx.sess.opts.debugging_opts.strict_init_checks) {
&& !might_permit_raw_init(fx.tcx, layout, InitKind::Zero) {

with_no_trimmed_paths!({
crate::base::codegen_panic(
Expand All @@ -689,10 +687,7 @@ fn codegen_regular_intrinsic_call<'tcx>(
}

if intrinsic == sym::assert_uninit_valid
&& !layout.might_permit_raw_init(
fx,
InitKind::Uninit,
fx.tcx.sess.opts.debugging_opts.strict_init_checks) {
&& !might_permit_raw_init(fx.tcx, layout, InitKind::Uninit) {

with_no_trimmed_paths!({
crate::base::codegen_panic(
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_codegen_cranelift/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
extern crate rustc_middle;
extern crate rustc_ast;
extern crate rustc_codegen_ssa;
extern crate rustc_const_eval;
extern crate rustc_data_structures;
extern crate rustc_errors;
extern crate rustc_fs_util;
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_codegen_ssa/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ rustc_metadata = { path = "../rustc_metadata" }
rustc_query_system = { path = "../rustc_query_system" }
rustc_target = { path = "../rustc_target" }
rustc_session = { path = "../rustc_session" }
rustc_const_eval = { path = "../rustc_const_eval" }

[dependencies.object]
version = "0.29.0"
Expand Down
8 changes: 4 additions & 4 deletions compiler/rustc_codegen_ssa/src/mir/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -528,7 +528,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
source_info: mir::SourceInfo,
target: Option<mir::BasicBlock>,
cleanup: Option<mir::BasicBlock>,
strict_validity: bool,
) -> bool {
// Emit a panic or a no-op for `assert_*` intrinsics.
// These are intrinsics that compile to panics so that we can get a message
Expand All @@ -546,13 +545,15 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
_ => None,
});
if let Some(intrinsic) = panic_intrinsic {
use rustc_const_eval::might_permit_raw_init::might_permit_raw_init;
use AssertIntrinsic::*;

let ty = instance.unwrap().substs.type_at(0);
let layout = bx.layout_of(ty);
let do_panic = match intrinsic {
Inhabited => layout.abi.is_uninhabited(),
ZeroValid => !layout.might_permit_raw_init(bx, InitKind::Zero, strict_validity),
UninitValid => !layout.might_permit_raw_init(bx, InitKind::Uninit, strict_validity),
ZeroValid => !might_permit_raw_init(bx.tcx(), layout, InitKind::Zero),
UninitValid => !might_permit_raw_init(bx.tcx(), layout, InitKind::Uninit),
};
if do_panic {
let msg_str = with_no_visible_paths!({
Expand Down Expand Up @@ -687,7 +688,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
source_info,
target,
cleanup,
self.cx.tcx().sess.opts.debugging_opts.strict_init_checks,
) {
return;
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_const_eval/src/const_eval/machine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ pub struct CompileTimeInterpreter<'mir, 'tcx> {
}

impl<'mir, 'tcx> CompileTimeInterpreter<'mir, 'tcx> {
pub(super) fn new(const_eval_limit: Limit, can_access_statics: bool) -> Self {
pub(crate) fn new(const_eval_limit: Limit, can_access_statics: bool) -> Self {
CompileTimeInterpreter {
steps_remaining: const_eval_limit.0,
stack: Vec::new(),
Expand Down
56 changes: 28 additions & 28 deletions compiler/rustc_const_eval/src/interpret/intrinsics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ use super::{
Pointer,
};

use crate::might_permit_raw_init::might_permit_raw_init;

mod caller_location;
mod type_name;

Expand Down Expand Up @@ -413,35 +415,33 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
),
)?;
}
if intrinsic_name == sym::assert_zero_valid
&& !layout.might_permit_raw_init(
self,
InitKind::Zero,
self.tcx.sess.opts.debugging_opts.strict_init_checks,
)
{
M::abort(
self,
format!(
"aborted execution: attempted to zero-initialize type `{}`, which is invalid",
ty
),
)?;

if intrinsic_name == sym::assert_zero_valid {
let should_panic = !might_permit_raw_init(*self.tcx, layout, InitKind::Zero);

if should_panic {
M::abort(
self,
format!(
"aborted execution: attempted to zero-initialize type `{}`, which is invalid",
ty
),
)?;
}
}
if intrinsic_name == sym::assert_uninit_valid
&& !layout.might_permit_raw_init(
self,
InitKind::Uninit,
self.tcx.sess.opts.debugging_opts.strict_init_checks,
)
{
M::abort(
self,
format!(
"aborted execution: attempted to leave type `{}` uninitialized, which is invalid",
ty
),
)?;

if intrinsic_name == sym::assert_uninit_valid {
let should_panic = !might_permit_raw_init(*self.tcx, layout, InitKind::Uninit);

if should_panic {
M::abort(
self,
format!(
"aborted execution: attempted to leave type `{}` uninitialized, which is invalid",
ty
),
)?;
}
}
}
sym::simd_insert => {
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_const_eval/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ extern crate rustc_middle;
pub mod const_eval;
mod errors;
pub mod interpret;
pub mod might_permit_raw_init;
pub mod transform;
pub mod util;

Expand Down
44 changes: 44 additions & 0 deletions compiler/rustc_const_eval/src/might_permit_raw_init.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
use crate::const_eval::CompileTimeInterpreter;
use crate::interpret::{InterpCx, MemoryKind, OpTy};
use rustc_middle::ty::layout::LayoutCx;
use rustc_middle::ty::{layout::TyAndLayout, ParamEnv, TyCtxt};
use rustc_session::Limit;
use rustc_target::abi::InitKind;

pub fn might_permit_raw_init<'tcx>(
tcx: TyCtxt<'tcx>,
ty: TyAndLayout<'tcx>,
kind: InitKind,
) -> bool {
let strict = tcx.sess.opts.debugging_opts.strict_init_checks;

if strict {
let machine = CompileTimeInterpreter::new(Limit::new(0), false);

let mut cx = InterpCx::new(tcx, rustc_span::DUMMY_SP, ParamEnv::reveal_all(), machine);

// We could panic here... Or we could just return "yeah it's valid whatever". Or let
// codegen_panic_intrinsic return an error that halts compilation.
// I'm not exactly sure *when* this can fail. OOM?
let allocated = cx
.allocate(ty, MemoryKind::Machine(crate::const_eval::MemoryKind::Heap))
.expect("failed to allocate for uninit check");

if kind == InitKind::Zero {
// Again, unclear what to do here if it fails.
cx.write_bytes_ptr(
allocated.ptr,
std::iter::repeat(0_u8).take(ty.layout.size().bytes_usize()),
)
.expect("failed to write bytes for zero valid check");
}

let ot: OpTy<'_, _> = allocated.into();

// Assume that if it failed, it's a validation failure.
cx.validate_operand(&ot).is_ok()
} else {
let layout_cx = LayoutCx { tcx, param_env: ParamEnv::reveal_all() };
ty.might_permit_raw_init(&layout_cx, kind)
}
}
7 changes: 0 additions & 7 deletions compiler/rustc_feature/src/active.rs
Original file line number Diff line number Diff line change
Expand Up @@ -528,13 +528,6 @@ declare_features! (
(incomplete, unsized_locals, "1.30.0", Some(48055), None),
/// Allows unsized tuple coercion.
(active, unsized_tuple_coercion, "1.20.0", Some(42877), None),
/// Allows `union`s to implement `Drop`. Moreover, `union`s may now include fields
/// that don't implement `Copy` as long as they don't have any drop glue.
/// This is checked recursively. On encountering type variable where no progress can be made,
/// `T: Copy` is used as a substitute for "no drop glue".
///
/// NOTE: A limited form of `union U { ... }` was accepted in 1.19.0.
(active, untagged_unions, "1.13.0", Some(55149), None),
/// Allows using the `#[used(linker)]` (or `#[used(compiler)]`) attribute.
(active, used_with_arg, "1.60.0", Some(93798), None),
/// Allows `extern "wasm" fn`
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_feature/src/removed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,9 @@ declare_features! (
/// Allows using items which are missing stability attributes
(removed, unmarked_api, "1.0.0", None, None, None),
(removed, unsafe_no_drop_flag, "1.0.0", None, None, None),
/// Allows `union` fields that don't implement `Copy` as long as they don't have any drop glue.
(removed, untagged_unions, "1.13.0", Some(55149), None,
Some("unions with `Copy` and `ManuallyDrop` fields are stable; there is no intent to stabilize more")),
/// Allows `#[unwind(..)]`.
///
/// Permits specifying whether a function should permit unwinding or abort on unwind.
Expand Down
54 changes: 54 additions & 0 deletions compiler/rustc_lint_defs/src/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3132,6 +3132,59 @@ declare_lint! {
"detects unexpected names and values in `#[cfg]` conditions",
}

declare_lint! {
/// The `repr_transparent_external_private_fields` lint
/// detects types marked `#[repr(trasparent)]` that (transitively)
/// contain an external ZST type marked `#[non_exhaustive]`
///
/// ### Example
///
/// ```rust,ignore (needs external crate)
/// #![deny(repr_transparent_external_private_fields)]
/// use foo::NonExhaustiveZst;
///
/// #[repr(transparent)]
/// struct Bar(u32, ([u32; 0], NonExhaustiveZst));
/// ```
///
/// This will produce:
///
/// ```text
/// error: zero-sized fields in repr(transparent) cannot contain external non-exhaustive types
/// --> src/main.rs:5:28
/// |
/// 5 | struct Bar(u32, ([u32; 0], NonExhaustiveZst));
/// | ^^^^^^^^^^^^^^^^
/// |
/// note: the lint level is defined here
/// --> src/main.rs:1:9
/// |
/// 1 | #![deny(repr_transparent_external_private_fields)]
/// | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/// = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
/// = note: for more information, see issue #78586 <https://github.com/rust-lang/rust/issues/78586>
/// = note: this struct contains `NonExhaustiveZst`, which is marked with `#[non_exhaustive]`, and makes it not a breaking change to become non-zero-sized in the future.
/// ```
///
/// ### Explanation
///
/// Previous, Rust accepted fields that contain external private zero-sized types,
/// even though it should not be a breaking change to add a non-zero-sized field to
/// that private type.
///
/// This is a [future-incompatible] lint to transition this
/// to a hard error in the future. See [issue #78586] for more details.
///
/// [issue #78586]: https://github.com/rust-lang/rust/issues/78586
/// [future-incompatible]: ../index.md#future-incompatible-lints
pub REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS,
Warn,
"tranparent type contains an external ZST that is marked #[non_exhaustive] or contains private fields",
@future_incompatible = FutureIncompatibleInfo {
reference: "issue #78586 <https://github.com/rust-lang/rust/issues/78586>",
};
}

declare_lint_pass! {
/// Does nothing as a lint pass, but registers some `Lint`s
/// that are used by other parts of the compiler.
Expand Down Expand Up @@ -3237,6 +3290,7 @@ declare_lint_pass! {
DEPRECATED_WHERE_CLAUSE_LOCATION,
TEST_UNSTABLE_LINT,
FFI_UNWIND_CALLS,
REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS,
]
}

Expand Down
6 changes: 0 additions & 6 deletions compiler/rustc_middle/src/mir/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ pub enum UnsafetyViolationDetails {
UseOfMutableStatic,
UseOfExternStatic,
DerefOfRawPointer,
AssignToDroppingUnionField,
AccessToUnionField,
MutationOfLayoutConstrainedField,
BorrowOfLayoutConstrainedField,
Expand Down Expand Up @@ -78,11 +77,6 @@ impl UnsafetyViolationDetails {
"raw pointers may be null, dangling or unaligned; they can violate aliasing rules \
and cause data races: all of these are undefined behavior",
),
AssignToDroppingUnionField => (
"assignment to union field that might need dropping",
"the previous content of the field will be dropped, which causes undefined \
behavior if the field was not properly initialized",
),
AccessToUnionField => (
"access to union field",
"the field may not be properly initialized: using uninitialized data will cause \
Expand Down
20 changes: 3 additions & 17 deletions compiler/rustc_mir_build/src/check_unsafety.rs
Original file line number Diff line number Diff line change
Expand Up @@ -431,16 +431,9 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
let lhs = &self.thir[lhs];
if let ty::Adt(adt_def, _) = lhs.ty.kind() && adt_def.is_union() {
if let Some((assigned_ty, assignment_span)) = self.assignment_info {
// To avoid semver hazard, we only consider `Copy` and `ManuallyDrop` non-dropping.
if !(assigned_ty
.ty_adt_def()
.map_or(false, |adt| adt.is_manually_drop())
|| assigned_ty
.is_copy_modulo_regions(self.tcx.at(expr.span), self.param_env))
{
self.requires_unsafe(assignment_span, AssignToDroppingUnionField);
} else {
// write to non-drop union field, safe
if assigned_ty.needs_drop(self.tcx, self.tcx.param_env(adt_def.did())) {
// This would be unsafe, but should be outright impossible since we reject such unions.
self.tcx.sess.delay_span_bug(assignment_span, "union fields that need dropping should be impossible");
}
} else {
self.requires_unsafe(expr.span, AccessToUnionField);
Expand Down Expand Up @@ -537,7 +530,6 @@ enum UnsafeOpKind {
UseOfMutableStatic,
UseOfExternStatic,
DerefOfRawPointer,
AssignToDroppingUnionField,
AccessToUnionField,
MutationOfLayoutConstrainedField,
BorrowOfLayoutConstrainedField,
Expand All @@ -555,7 +547,6 @@ impl UnsafeOpKind {
UseOfMutableStatic => "use of mutable static",
UseOfExternStatic => "use of extern static",
DerefOfRawPointer => "dereference of raw pointer",
AssignToDroppingUnionField => "assignment to union field that might need dropping",
AccessToUnionField => "access to union field",
MutationOfLayoutConstrainedField => "mutation of layout constrained field",
BorrowOfLayoutConstrainedField => {
Expand Down Expand Up @@ -600,11 +591,6 @@ impl UnsafeOpKind {
"raw pointers may be null, dangling or unaligned; they can violate aliasing rules \
and cause data races: all of these are undefined behavior",
),
AssignToDroppingUnionField => (
Cow::Borrowed(self.simple_description()),
"the previous content of the field will be dropped, which causes undefined \
behavior if the field was not properly initialized",
),
AccessToUnionField => (
Cow::Borrowed(self.simple_description()),
"the field may not be properly initialized: using uninitialized data will cause \
Expand Down
Loading