Skip to content

Commit d53f1e8

Browse files
committed
Auto merge of rust-lang#96891 - Dylan-DPC:rollup-echa4wg, r=Dylan-DPC
Rollup of 5 pull requests Successful merges: - rust-lang#93661 (Add missing rustc arg docs) - rust-lang#96674 (docs: add link explaining variance to NonNull docs) - rust-lang#96812 (Do not lint on explicit outlives requirements from external macros.) - rust-lang#96823 (Properly fix rust-lang#96638) - rust-lang#96872 (make sure ScalarPair enums have ScalarPair variants; add some layout sanity checks) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
2 parents 2226f19 + ec53c37 commit d53f1e8

File tree

14 files changed

+422
-119
lines changed

14 files changed

+422
-119
lines changed

compiler/rustc_lint/src/builtin.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ use rustc_hir::def::{DefKind, Res};
3838
use rustc_hir::def_id::{DefId, LocalDefId, LocalDefIdSet, CRATE_DEF_ID};
3939
use rustc_hir::{ForeignItemKind, GenericParamKind, HirId, PatKind, PredicateOrigin};
4040
use rustc_index::vec::Idx;
41-
use rustc_middle::lint::LintDiagnosticBuilder;
41+
use rustc_middle::lint::{in_external_macro, LintDiagnosticBuilder};
4242
use rustc_middle::ty::layout::{LayoutError, LayoutOf};
4343
use rustc_middle::ty::print::with_no_trimmed_paths;
4444
use rustc_middle::ty::subst::{GenericArgKind, Subst};
@@ -2115,6 +2115,7 @@ impl ExplicitOutlivesRequirements {
21152115
None
21162116
}
21172117
})
2118+
.filter(|(_, span)| !in_external_macro(tcx.sess, *span))
21182119
.collect()
21192120
}
21202121

compiler/rustc_middle/src/ty/layout.rs

+127-9
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,111 @@ impl<'tcx> fmt::Display for LayoutError<'tcx> {
221221
}
222222
}
223223

224+
/// Enforce some basic invariants on layouts.
225+
fn sanity_check_layout<'tcx>(
226+
tcx: TyCtxt<'tcx>,
227+
param_env: ty::ParamEnv<'tcx>,
228+
layout: &TyAndLayout<'tcx>,
229+
) {
230+
// Type-level uninhabitedness should always imply ABI uninhabitedness.
231+
if tcx.conservative_is_privately_uninhabited(param_env.and(layout.ty)) {
232+
assert!(layout.abi.is_uninhabited());
233+
}
234+
235+
if cfg!(debug_assertions) {
236+
fn check_layout_abi<'tcx>(tcx: TyCtxt<'tcx>, layout: Layout<'tcx>) {
237+
match layout.abi() {
238+
Abi::Scalar(_scalar) => {
239+
// No padding in scalars.
240+
/* FIXME(#96185):
241+
assert_eq!(
242+
layout.align().abi,
243+
scalar.align(&tcx).abi,
244+
"alignment mismatch between ABI and layout in {layout:#?}"
245+
);
246+
assert_eq!(
247+
layout.size(),
248+
scalar.size(&tcx),
249+
"size mismatch between ABI and layout in {layout:#?}"
250+
);*/
251+
}
252+
Abi::Vector { count, element } => {
253+
// No padding in vectors. Alignment can be strengthened, though.
254+
assert!(
255+
layout.align().abi >= element.align(&tcx).abi,
256+
"alignment mismatch between ABI and layout in {layout:#?}"
257+
);
258+
let size = element.size(&tcx) * count;
259+
assert_eq!(
260+
layout.size(),
261+
size.align_to(tcx.data_layout().vector_align(size).abi),
262+
"size mismatch between ABI and layout in {layout:#?}"
263+
);
264+
}
265+
Abi::ScalarPair(scalar1, scalar2) => {
266+
// Sanity-check scalar pairs. These are a bit more flexible and support
267+
// padding, but we can at least ensure both fields actually fit into the layout
268+
// and the alignment requirement has not been weakened.
269+
let align1 = scalar1.align(&tcx).abi;
270+
let align2 = scalar2.align(&tcx).abi;
271+
assert!(
272+
layout.align().abi >= cmp::max(align1, align2),
273+
"alignment mismatch between ABI and layout in {layout:#?}",
274+
);
275+
let field2_offset = scalar1.size(&tcx).align_to(align2);
276+
assert!(
277+
layout.size() >= field2_offset + scalar2.size(&tcx),
278+
"size mismatch between ABI and layout in {layout:#?}"
279+
);
280+
}
281+
Abi::Uninhabited | Abi::Aggregate { .. } => {} // Nothing to check.
282+
}
283+
}
284+
285+
check_layout_abi(tcx, layout.layout);
286+
287+
if let Variants::Multiple { variants, .. } = &layout.variants {
288+
for variant in variants {
289+
check_layout_abi(tcx, *variant);
290+
// No nested "multiple".
291+
assert!(matches!(variant.variants(), Variants::Single { .. }));
292+
// Skip empty variants.
293+
if variant.size() == Size::ZERO
294+
|| variant.fields().count() == 0
295+
|| variant.abi().is_uninhabited()
296+
{
297+
// These are never actually accessed anyway, so we can skip them. (Note that
298+
// sometimes, variants with fields have size 0, and sometimes, variants without
299+
// fields have non-0 size.)
300+
continue;
301+
}
302+
// Variants should have the same or a smaller size as the full thing.
303+
if variant.size() > layout.size {
304+
bug!(
305+
"Type with size {} bytes has variant with size {} bytes: {layout:#?}",
306+
layout.size.bytes(),
307+
variant.size().bytes(),
308+
)
309+
}
310+
// The top-level ABI and the ABI of the variants should be coherent.
311+
let abi_coherent = match (layout.abi, variant.abi()) {
312+
(Abi::Scalar(..), Abi::Scalar(..)) => true,
313+
(Abi::ScalarPair(..), Abi::ScalarPair(..)) => true,
314+
(Abi::Uninhabited, _) => true,
315+
(Abi::Aggregate { .. }, _) => true,
316+
_ => false,
317+
};
318+
if !abi_coherent {
319+
bug!(
320+
"Variant ABI is incompatible with top-level ABI:\nvariant={:#?}\nTop-level: {layout:#?}",
321+
variant
322+
);
323+
}
324+
}
325+
}
326+
}
327+
}
328+
224329
#[instrument(skip(tcx, query), level = "debug")]
225330
fn layout_of<'tcx>(
226331
tcx: TyCtxt<'tcx>,
@@ -264,10 +369,7 @@ fn layout_of<'tcx>(
264369

265370
cx.record_layout_for_printing(layout);
266371

267-
// Type-level uninhabitedness should always imply ABI uninhabitedness.
268-
if tcx.conservative_is_privately_uninhabited(param_env.and(ty)) {
269-
assert!(layout.abi.is_uninhabited());
270-
}
372+
sanity_check_layout(tcx, param_env, &layout);
271373

272374
Ok(layout)
273375
})
@@ -1314,9 +1416,11 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
13141416
};
13151417
let mut abi = Abi::Aggregate { sized: true };
13161418

1317-
// Without latter check aligned enums with custom discriminant values
1318-
// Would result in ICE see the issue #92464 for more info
1319-
if tag.size(dl) == size || variants.iter().all(|layout| layout.is_empty()) {
1419+
if layout_variants.iter().all(|v| v.abi.is_uninhabited()) {
1420+
abi = Abi::Uninhabited;
1421+
} else if tag.size(dl) == size || variants.iter().all(|layout| layout.is_empty()) {
1422+
// Without latter check aligned enums with custom discriminant values
1423+
// Would result in ICE see the issue #92464 for more info
13201424
abi = Abi::Scalar(tag);
13211425
} else {
13221426
// Try to use a ScalarPair for all tagged enums.
@@ -1390,8 +1494,22 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
13901494
}
13911495
}
13921496

1393-
if layout_variants.iter().all(|v| v.abi.is_uninhabited()) {
1394-
abi = Abi::Uninhabited;
1497+
// If we pick a "clever" (by-value) ABI, we might have to adjust the ABI of the
1498+
// variants to ensure they are consistent. This is because a downcast is
1499+
// semantically a NOP, and thus should not affect layout.
1500+
if matches!(abi, Abi::Scalar(..) | Abi::ScalarPair(..)) {
1501+
for variant in &mut layout_variants {
1502+
// We only do this for variants with fields; the others are not accessed anyway.
1503+
// Also do not overwrite any already existing "clever" ABIs.
1504+
if variant.fields.count() > 0
1505+
&& matches!(variant.abi, Abi::Aggregate { .. })
1506+
{
1507+
variant.abi = abi;
1508+
// Also need to bump up the size and alignment, so that the entire value fits in here.
1509+
variant.size = cmp::max(variant.size, size);
1510+
variant.align.abi = cmp::max(variant.align.abi, align.abi);
1511+
}
1512+
}
13951513
}
13961514

13971515
let largest_niche = Niche::from_scalar(dl, Size::ZERO, tag);

0 commit comments

Comments
 (0)