Skip to content
Merged
3 changes: 2 additions & 1 deletion compiler/rustc_error_codes/src/error_codes/E0691.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ struct ForceAlign32;

#[repr(transparent)]
struct Wrapper(f32, ForceAlign32); // error: zero-sized field in transparent
// struct has alignment larger than 1
// struct has alignment of 32, which
// is larger than 1
```

A transparent struct, enum, or union is supposed to be represented exactly like
Expand Down
29 changes: 19 additions & 10 deletions compiler/rustc_hir_analysis/src/check/check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1078,9 +1078,9 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>)
// We are currently checking the type this field came from, so it must be local
let span = tcx.hir().span_if_local(field.did).unwrap();
let zst = layout.is_ok_and(|layout| layout.is_zst());
let align1 = layout.is_ok_and(|layout| layout.align.abi.bytes() == 1);
let align = layout.ok().map(|layout| layout.align.abi.bytes());
if !zst {
return (span, zst, align1, None);
return (span, zst, align, None);
}

fn check_non_exhaustive<'tcx>(
Expand Down Expand Up @@ -1115,30 +1115,39 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>)
}
}

(span, zst, align1, check_non_exhaustive(tcx, ty).break_value())
(span, zst, align, check_non_exhaustive(tcx, ty).break_value())
});

let non_zst_fields = field_infos
.clone()
.filter_map(|(span, zst, _align1, _non_exhaustive)| if !zst { Some(span) } else { None });
.filter_map(|(span, zst, _align, _non_exhaustive)| if !zst { Some(span) } else { None });
let non_zst_count = non_zst_fields.clone().count();
if non_zst_count >= 2 {
bad_non_zero_sized_fields(tcx, adt, non_zst_count, non_zst_fields, tcx.def_span(adt.did()));
}
let incompatible_zst_fields =
field_infos.clone().filter(|(_, _, _, opt)| opt.is_some()).count();
let incompat = incompatible_zst_fields + non_zst_count >= 2 && non_zst_count < 2;
for (span, zst, align1, non_exhaustive) in field_infos {
if zst && !align1 {
struct_span_err!(
for (span, zst, align, non_exhaustive) in field_infos {
if zst && align != Some(1) {
let mut err = struct_span_err!(
tcx.sess,
span,
E0691,
"zero-sized field in transparent {} has alignment larger than 1",
adt.descr(),
)
.span_label(span, "has alignment larger than 1")
.emit();
);

if let Some(align_bytes) = align {
err.span_label(
span,
format!("has alignment of {align_bytes}, which is larger than 1"),
);
} else {
err.span_label(span, "may have alignment larger than 1");
}

err.emit();
}
if incompat && let Some((descr, def_id, args, non_exhaustive)) = non_exhaustive {
tcx.struct_span_lint_hir(
Expand Down
12 changes: 8 additions & 4 deletions compiler/rustc_middle/src/ty/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -569,6 +569,7 @@ pub struct GlobalCtxt<'tcx> {

/// Caches the results of goal evaluation in the new solver.
pub new_solver_evaluation_cache: solve::EvaluationCache<'tcx>,
pub new_solver_coherence_evaluation_cache: solve::EvaluationCache<'tcx>,

/// Data layout specification for the current target.
pub data_layout: TargetDataLayout,
Expand Down Expand Up @@ -680,10 +681,12 @@ impl<'tcx> TyCtxt<'tcx> {
value.lift_to_tcx(self)
}

/// Creates a type context and call the closure with a `TyCtxt` reference
/// to the context. The closure enforces that the type context and any interned
/// value (types, args, etc.) can only be used while `ty::tls` has a valid
/// reference to the context, to allow formatting values that need it.
/// Creates a type context. To use the context call `fn enter` which
/// provides a `TyCtxt`.
///
/// By only providing the `TyCtxt` inside of the closure we enforce that the type
/// context and any interned alue (types, args, etc.) can only be used while `ty::tls`
/// has a valid reference to the context, to allow formatting values that need it.
pub fn create_global_ctxt(
s: &'tcx Session,
lint_store: Lrc<dyn Any + sync::DynSend + sync::DynSync>,
Expand Down Expand Up @@ -721,6 +724,7 @@ impl<'tcx> TyCtxt<'tcx> {
selection_cache: Default::default(),
evaluation_cache: Default::default(),
new_solver_evaluation_cache: Default::default(),
new_solver_coherence_evaluation_cache: Default::default(),
data_layout,
alloc_map: Lock::new(interpret::AllocMap::new()),
}
Expand Down
16 changes: 16 additions & 0 deletions compiler/rustc_smir/src/rustc_internal/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,14 @@ pub fn generator_def(did: DefId) -> stable_mir::ty::GeneratorDef {
with_tables(|t| t.generator_def(did))
}

pub fn param_def(did: DefId) -> stable_mir::ty::ParamDef {
with_tables(|t| t.param_def(did))
}

pub fn br_named_def(did: DefId) -> stable_mir::ty::BrNamedDef {
with_tables(|t| t.br_named_def(did))
}

impl<'tcx> Tables<'tcx> {
pub fn item_def_id(&self, item: &stable_mir::CrateItem) -> DefId {
self.def_ids[item.0]
Expand Down Expand Up @@ -76,6 +84,14 @@ impl<'tcx> Tables<'tcx> {
stable_mir::ty::GeneratorDef(self.create_def_id(did))
}

pub fn param_def(&mut self, did: DefId) -> stable_mir::ty::ParamDef {
stable_mir::ty::ParamDef(self.create_def_id(did))
}

pub fn br_named_def(&mut self, did: DefId) -> stable_mir::ty::BrNamedDef {
stable_mir::ty::BrNamedDef(self.create_def_id(did))
}

fn create_def_id(&mut self, did: DefId) -> stable_mir::DefId {
// FIXME: this becomes inefficient when we have too many ids
for (i, &d) in self.def_ids.iter().enumerate() {
Expand Down
Loading