Skip to content

Commit

Permalink
Merge pull request #149 from jacob-hughes/fsa_unions
Browse files Browse the repository at this point in the history
Emit FSA error for unions with manually drop fields
  • Loading branch information
ltratt authored Nov 26, 2024
2 parents 8847dcf + 58e276a commit b9ee8dd
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 0 deletions.
20 changes: 20 additions & 0 deletions compiler/rustc_mir_transform/src/check_finalizers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ enum FinalizerErrorKind<'tcx> {
UnsoundReference(FnInfo<'tcx>, ProjInfo<'tcx>),
/// Uses a trait object whose concrete type is unknown
UnknownTraitObject(FnInfo<'tcx>),
/// Uses a union with a drop method.
Union(FnInfo<'tcx>),
/// Calls a function whose definition is unavailable, so we can't be certain it's safe.
MissingFnDef(FnInfo<'tcx>),
/// The drop glue contains an unsound drop method from an external crate. This will have been
Expand Down Expand Up @@ -217,6 +219,9 @@ impl<'tcx> FSAEntryPointCtxt<'tcx> {
tys.push(f)
}
}
ty::Adt(def, ..) if def.is_union() && def.has_dtor(self.tcx) => {
errors.push(FinalizerErrorKind::Union(FnInfo::new(rustc_span::DUMMY_SP, ty)));
}
ty::Adt(def, substs) if !ty.is_copy_modulo_regions(self.tcx, self.param_env) => {
if def.is_box() {
// This is a special case because Box has an empty drop
Expand Down Expand Up @@ -249,6 +254,11 @@ impl<'tcx> FSAEntryPointCtxt<'tcx> {
_ => (),
}
}
if def.is_union() {
// By definition, a union's fields can never have drop glue, so we don't need
// to add them.
continue;
}

for field in def.all_fields() {
let field_ty = self.tcx.type_of(field.did).instantiate(self.tcx, substs);
Expand Down Expand Up @@ -368,6 +378,16 @@ impl<'tcx> FSAEntryPointCtxt<'tcx> {
"contains a trait object whose implementation is unknown.",
);
}
FinalizerErrorKind::Union(fi) => {
err = self.tcx.sess.psess.dcx.struct_span_err(
self.arg_span,
format!("The drop method for `{0}` cannot be safely finalized.", fi.drop_ty),
);
err.span_label(
self.arg_span,
"contains a union whose drop glue cannot be known at compile-time.",
);
}
FinalizerErrorKind::UnsoundExternalDropGlue(fi) => {
err = self.tcx.sess.psess.dcx.struct_span_err(
self.arg_span,
Expand Down
43 changes: 43 additions & 0 deletions tests/ui/static/gc/fsa/unions.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#![feature(gc)]
#![feature(negative_impls)]
#![feature(rustc_private)]
#![allow(dead_code)]
#![allow(unused_variables)]

use std::gc::Gc;
use std::mem::ManuallyDrop;

struct S(u8);
struct T(u8);

impl Drop for S {
fn drop(&mut self) {
}
}


impl Drop for T {
fn drop(&mut self) {
}
}

union U {
a: ManuallyDrop<S>,
b: ManuallyDrop<T>,
}

impl Drop for U {
fn drop(&mut self) {
let x = unsafe { &self.a };
}
}

impl !Send for U {}
impl !Send for S {}
impl !Send for T {}

fn main() {
let u = U { a: ManuallyDrop::new(S(1)) };
Gc::new(u);
//~^ ERROR: The drop method for `U` cannot be safely finalized.
}
11 changes: 11 additions & 0 deletions tests/ui/static/gc/fsa/unions.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
error: The drop method for `U` cannot be safely finalized.
--> $DIR/unions.rs:41:13
|
LL | Gc::new(u);
| --------^-
| | |
| | contains a union whose drop glue cannot be known at compile-time.
| caused by trying to construct a `Gc<U>` here.

error: aborting due to 1 previous error

0 comments on commit b9ee8dd

Please sign in to comment.