Rollup merge of #151831 - clubby789:port-rustc-layout, r=JonathanBrouwer

Port `rustc_layout` to attribute parser

Tracking issue: rust-lang/rust#131229

Uses rust-lang/rust#151827

r? jdonszelmann
This commit is contained in:
Jonathan Brouwer
2026-01-30 12:12:05 +01:00
committed by GitHub
10 changed files with 115 additions and 55 deletions
@@ -1,4 +1,5 @@
use rustc_ast::{LitIntType, LitKind, MetaItemLit};
use rustc_hir::attrs::RustcLayoutType;
use rustc_session::errors;
use super::prelude::*;
@@ -329,3 +330,61 @@ impl<S: Stage> NoArgsAttributeParser<S> for RustcOffloadKernelParser {
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]);
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcOffloadKernel;
}
pub(crate) struct RustcLayoutParser;
impl<S: Stage> CombineAttributeParser<S> for RustcLayoutParser {
const PATH: &[rustc_span::Symbol] = &[sym::rustc_layout];
type Item = RustcLayoutType;
const CONVERT: ConvertFn<Self::Item> = |items, _| AttributeKind::RustcLayout(items);
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
Allow(Target::Struct),
Allow(Target::Enum),
Allow(Target::Union),
Allow(Target::TyAlias),
]);
const TEMPLATE: AttributeTemplate =
template!(List: &["abi", "align", "size", "homogenous_aggregate", "debug"]);
fn extend(
cx: &mut AcceptContext<'_, '_, S>,
args: &ArgParser,
) -> impl IntoIterator<Item = Self::Item> {
let ArgParser::List(items) = args else {
cx.expected_list(cx.attr_span, args);
return vec![];
};
let mut result = Vec::new();
for item in items.mixed() {
let Some(arg) = item.meta_item() else {
cx.unexpected_literal(item.span());
continue;
};
let Some(ident) = arg.ident() else {
cx.expected_identifier(arg.span());
return vec![];
};
let ty = match ident.name {
sym::abi => RustcLayoutType::Abi,
sym::align => RustcLayoutType::Align,
sym::size => RustcLayoutType::Size,
sym::homogeneous_aggregate => RustcLayoutType::HomogenousAggregate,
sym::debug => RustcLayoutType::Debug,
_ => {
cx.expected_specific_argument(
ident.span,
&[sym::abi, sym::align, sym::size, sym::homogeneous_aggregate, sym::debug],
);
continue;
}
};
result.push(ty);
}
result
}
}
+2 -1
View File
@@ -75,7 +75,7 @@
RustcDumpVtable,
};
use crate::attributes::rustc_internal::{
RustcHasIncoherentInherentImplsParser, RustcLayoutScalarValidRangeEndParser,
RustcHasIncoherentInherentImplsParser, RustcLayoutParser, RustcLayoutScalarValidRangeEndParser,
RustcLayoutScalarValidRangeStartParser, RustcLegacyConstGenericsParser,
RustcLintOptDenyFieldAccessParser, RustcLintOptTyParser, RustcLintQueryInstabilityParser,
RustcLintUntrackedQueryInformationParser, RustcMainParser, RustcMustImplementOneOfParser,
@@ -198,6 +198,7 @@ mod late {
Combine<ForceTargetFeatureParser>,
Combine<LinkParser>,
Combine<ReprParser>,
Combine<RustcLayoutParser>,
Combine<TargetFeatureParser>,
Combine<UnstableFeatureBoundParser>,
// tidy-alphabetical-end
@@ -690,6 +690,15 @@ fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
}
}
#[derive(Clone, Debug, HashStable_Generic, Encodable, Decodable, PrintAttribute)]
pub enum RustcLayoutType {
Abi,
Align,
Size,
HomogenousAggregate,
Debug,
}
/// Represents parsed *built-in* inert attributes.
///
/// ## Overview
@@ -1048,6 +1057,9 @@ pub enum AttributeKind {
/// Represents `#[rustc_has_incoherent_inherent_impls]`
RustcHasIncoherentInherentImpls,
/// Represents `#[rustc_layout]`
RustcLayout(ThinVec<RustcLayoutType>),
/// Represents `#[rustc_layout_scalar_valid_range_end]`.
RustcLayoutScalarValidRangeEnd(Box<u128>, Span),
@@ -111,6 +111,7 @@ pub fn encode_cross_crate(&self) -> EncodeCrossCrate {
RustcDumpVtable(..) => No,
RustcDynIncompatibleTrait(..) => No,
RustcHasIncoherentInherentImpls => Yes,
RustcLayout(..) => No,
RustcLayoutScalarValidRangeEnd(..) => Yes,
RustcLayoutScalarValidRangeStart(..) => Yes,
RustcLegacyConstGenerics { .. } => Yes,
-2
View File
@@ -302,8 +302,6 @@ passes_layout_align =
align: {$align}
passes_layout_homogeneous_aggregate =
homogeneous_aggregate: {$homogeneous_aggregate}
passes_layout_invalid_attribute =
`#[rustc_layout]` can only be applied to `struct`/`enum`/`union` declarations and type aliases
passes_layout_of =
layout_of({$normalized_ty}) = {$ty_layout}
passes_layout_size =
+1
View File
@@ -299,6 +299,7 @@ fn check_attributes(
| AttributeKind::RustcDumpVtable(..)
| AttributeKind::RustcDynIncompatibleTrait(..)
| AttributeKind::RustcHasIncoherentInherentImpls
| AttributeKind::RustcLayout(..)
| AttributeKind::RustcLayoutScalarValidRangeEnd(..)
| AttributeKind::RustcLayoutScalarValidRangeStart(..)
| AttributeKind::RustcLintOptDenyFieldAccess { .. }
-7
View File
@@ -519,13 +519,6 @@ pub(crate) struct LayoutOf<'tcx> {
pub ty_layout: String,
}
#[derive(Diagnostic)]
#[diag(passes_layout_invalid_attribute)]
pub(crate) struct LayoutInvalidAttribute {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(passes_abi_of)]
pub(crate) struct AbiOf {
+20 -29
View File
@@ -1,20 +1,18 @@
use rustc_abi::{HasDataLayout, TargetDataLayout};
use rustc_hir::Attribute;
use rustc_hir::attrs::{AttributeKind, RustcLayoutType};
use rustc_hir::def::DefKind;
use rustc_hir::def_id::LocalDefId;
use rustc_hir::find_attr;
use rustc_middle::span_bug;
use rustc_middle::ty::layout::{HasTyCtxt, HasTypingEnv, LayoutError, LayoutOfHelpers};
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_span::Span;
use rustc_span::source_map::Spanned;
use rustc_span::{Span, sym};
use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
use rustc_trait_selection::infer::TyCtxtInferExt;
use rustc_trait_selection::traits;
use crate::errors::{
LayoutAbi, LayoutAlign, LayoutHomogeneousAggregate, LayoutInvalidAttribute, LayoutOf,
LayoutSize, UnrecognizedArgument,
};
use crate::errors::{LayoutAbi, LayoutAlign, LayoutHomogeneousAggregate, LayoutOf, LayoutSize};
pub fn test_layout(tcx: TyCtxt<'_>) {
if !tcx.features().rustc_attrs() {
@@ -22,14 +20,14 @@ pub fn test_layout(tcx: TyCtxt<'_>) {
return;
}
for id in tcx.hir_crate_items(()).definitions() {
for attr in tcx.get_attrs(id, sym::rustc_layout) {
match tcx.def_kind(id) {
DefKind::TyAlias | DefKind::Enum | DefKind::Struct | DefKind::Union => {
dump_layout_of(tcx, id, attr);
}
_ => {
tcx.dcx().emit_err(LayoutInvalidAttribute { span: tcx.def_span(id) });
}
let attrs = tcx.get_all_attrs(id);
if let Some(attrs) = find_attr!(attrs, AttributeKind::RustcLayout(attrs) => attrs) {
// Attribute parsing handles error reporting
if matches!(
tcx.def_kind(id),
DefKind::TyAlias | DefKind::Enum | DefKind::Struct | DefKind::Union
) {
dump_layout_of(tcx, id, attrs);
}
}
}
@@ -66,7 +64,7 @@ pub fn ensure_wf<'tcx>(
}
}
fn dump_layout_of(tcx: TyCtxt<'_>, item_def_id: LocalDefId, attr: &Attribute) {
fn dump_layout_of(tcx: TyCtxt<'_>, item_def_id: LocalDefId, attrs: &[RustcLayoutType]) {
let typing_env = ty::TypingEnv::post_analysis(tcx, item_def_id);
let ty = tcx.type_of(item_def_id).instantiate_identity();
let span = tcx.def_span(item_def_id.to_def_id());
@@ -75,32 +73,29 @@ fn dump_layout_of(tcx: TyCtxt<'_>, item_def_id: LocalDefId, attr: &Attribute) {
}
match tcx.layout_of(typing_env.as_query_input(ty)) {
Ok(ty_layout) => {
// Check out the `#[rustc_layout(..)]` attribute to tell what to dump.
// The `..` are the names of fields to dump.
let meta_items = attr.meta_item_list().unwrap_or_default();
for meta_item in meta_items {
match meta_item.name() {
for attr in attrs {
match attr {
// FIXME: this never was about ABI and now this dump arg is confusing
Some(sym::abi) => {
RustcLayoutType::Abi => {
tcx.dcx().emit_err(LayoutAbi {
span,
abi: format!("{:?}", ty_layout.backend_repr),
});
}
Some(sym::align) => {
RustcLayoutType::Align => {
tcx.dcx().emit_err(LayoutAlign {
span,
align: format!("{:?}", ty_layout.align),
});
}
Some(sym::size) => {
RustcLayoutType::Size => {
tcx.dcx()
.emit_err(LayoutSize { span, size: format!("{:?}", ty_layout.size) });
}
Some(sym::homogeneous_aggregate) => {
RustcLayoutType::HomogenousAggregate => {
tcx.dcx().emit_err(LayoutHomogeneousAggregate {
span,
homogeneous_aggregate: format!(
@@ -111,16 +106,12 @@ fn dump_layout_of(tcx: TyCtxt<'_>, item_def_id: LocalDefId, attr: &Attribute) {
});
}
Some(sym::debug) => {
RustcLayoutType::Debug => {
let normalized_ty = tcx.normalize_erasing_regions(typing_env, ty);
// FIXME: using the `Debug` impl here isn't ideal.
let ty_layout = format!("{:#?}", *ty_layout);
tcx.dcx().emit_err(LayoutOf { span, normalized_ty, ty_layout });
}
_ => {
tcx.dcx().emit_err(UnrecognizedArgument { span: meta_item.span() });
}
}
}
}
+4 -4
View File
@@ -68,12 +68,12 @@ union P4 { x: E } //~ ERROR: layout_of
#[rustc_layout(debug)]
type X = std::mem::MaybeUninit<u8>; //~ ERROR: layout_of
#[rustc_layout(debug)]
const C: () = (); //~ ERROR: can only be applied to
#[rustc_layout(debug)] //~ ERROR: cannot be used on constants
const C: () = ();
impl S {
#[rustc_layout(debug)]
const C: () = (); //~ ERROR: can only be applied to
#[rustc_layout(debug)] //~ ERROR: cannot be used on associated consts
const C: () = ();
}
#[rustc_layout(debug)]
+16 -12
View File
@@ -4,6 +4,22 @@ error: unions cannot have zero fields
LL | union EmptyUnion {}
| ^^^^^^^^^^^^^^^^^^^
error: `#[rustc_layout]` attribute cannot be used on constants
--> $DIR/debug.rs:71:1
|
LL | #[rustc_layout(debug)]
| ^^^^^^^^^^^^^^^^^^^^^^
|
= help: `#[rustc_layout]` can be applied to data types and type aliases
error: `#[rustc_layout]` attribute cannot be used on associated consts
--> $DIR/debug.rs:75:5
|
LL | #[rustc_layout(debug)]
| ^^^^^^^^^^^^^^^^^^^^^^
|
= help: `#[rustc_layout]` can be applied to data types and type aliases
error: layout_of(E) = Layout {
size: Size(12 bytes),
align: AbiAlign {
@@ -577,12 +593,6 @@ error: layout_of(MaybeUninit<u8>) = Layout {
LL | type X = std::mem::MaybeUninit<u8>;
| ^^^^^^
error: `#[rustc_layout]` can only be applied to `struct`/`enum`/`union` declarations and type aliases
--> $DIR/debug.rs:72:1
|
LL | const C: () = ();
| ^^^^^^^^^^^
error[E0277]: the size for values of type `str` cannot be known at compilation time
--> $DIR/debug.rs:80:19
|
@@ -604,12 +614,6 @@ error: the type `T` does not have a fixed layout
LL | type TooGeneric<T> = T;
| ^^^^^^^^^^^^^^^^^^
error: `#[rustc_layout]` can only be applied to `struct`/`enum`/`union` declarations and type aliases
--> $DIR/debug.rs:76:5
|
LL | const C: () = ();
| ^^^^^^^^^^^
error: aborting due to 20 previous errors
For more information about this error, try `rustc --explain E0277`.