Skip to content
59 changes: 59 additions & 0 deletions compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use rustc_ast::{LitIntType, LitKind, MetaItemLit};
use rustc_hir::attrs::RustcLayoutType;
use rustc_session::errors;

use super::prelude::*;
Expand Down Expand Up @@ -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
}
}
3 changes: 2 additions & 1 deletion compiler/rustc_attr_parsing/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ use crate::attributes::rustc_dump::{
RustcDumpVtable,
};
use crate::attributes::rustc_internal::{
RustcHasIncoherentInherentImplsParser, RustcLayoutScalarValidRangeEndParser,
RustcHasIncoherentInherentImplsParser, RustcLayoutParser, RustcLayoutScalarValidRangeEndParser,
RustcLayoutScalarValidRangeStartParser, RustcLegacyConstGenericsParser,
RustcLintOptDenyFieldAccessParser, RustcLintOptTyParser, RustcLintQueryInstabilityParser,
RustcLintUntrackedQueryInformationParser, RustcMainParser, RustcMustImplementOneOfParser,
Expand Down Expand Up @@ -198,6 +198,7 @@ attribute_parsers!(
Combine<ForceTargetFeatureParser>,
Combine<LinkParser>,
Combine<ReprParser>,
Combine<RustcLayoutParser>,
Combine<TargetFeatureParser>,
Combine<UnstableFeatureBoundParser>,
// tidy-alphabetical-end
Expand Down
12 changes: 12 additions & 0 deletions compiler/rustc_hir/src/attrs/data_structures.rs
Original file line number Diff line number Diff line change
Expand Up @@ -690,6 +690,15 @@ impl IntoDiagArg for CrateType {
}
}

#[derive(Clone, Debug, HashStable_Generic, Encodable, Decodable, PrintAttribute)]
pub enum RustcLayoutType {
Abi,
Align,
Size,
HomogenousAggregate,
Debug,
}

/// Represents parsed *built-in* inert attributes.
///
/// ## Overview
Expand Down Expand Up @@ -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),

Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_hir/src/attrs/encode_cross_crate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ impl AttributeKind {
RustcDumpVtable(..) => No,
RustcDynIncompatibleTrait(..) => No,
RustcHasIncoherentInherentImpls => Yes,
RustcLayout(..) => No,
RustcLayoutScalarValidRangeEnd(..) => Yes,
RustcLayoutScalarValidRangeStart(..) => Yes,
RustcLegacyConstGenerics { .. } => Yes,
Expand Down
24 changes: 5 additions & 19 deletions compiler/rustc_macros/src/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -280,31 +280,21 @@ fn add_query_desc_cached_impl(
let crate::query::Providers { #name: _, .. };
};

// Find out if we should cache the query on disk
let cache = if let Some((args, expr)) = modifiers.cache.as_ref() {
// Generate a function to check whether we should cache the query to disk, for some key.
if let Some((args, expr)) = modifiers.cache.as_ref() {
let tcx = args.as_ref().map(|t| quote! { #t }).unwrap_or_else(|| quote! { _ });
// expr is a `Block`, meaning that `{ #expr }` gets expanded
// to `{ { stmts... } }`, which triggers the `unused_braces` lint.
// we're taking `key` by reference, but some rustc types usually prefer being passed by value
quote! {
cached.extend(quote! {
#[allow(unused_variables, unused_braces, rustc::pass_by_value)]
#[inline]
pub fn #name<'tcx>(#tcx: TyCtxt<'tcx>, #key: &crate::query::queries::#name::Key<'tcx>) -> bool {
#ra_hint
#expr
}
}
} else {
quote! {
// we're taking `key` by reference, but some rustc types usually prefer being passed by value
#[allow(rustc::pass_by_value)]
#[inline]
pub fn #name<'tcx>(_: TyCtxt<'tcx>, _: &crate::query::queries::#name::Key<'tcx>) -> bool {
#ra_hint
false
}
}
};
});
}

let (tcx, desc) = &modifiers.desc;
let tcx = tcx.as_ref().map_or_else(|| quote! { _ }, |t| quote! { #t });
Expand All @@ -322,10 +312,6 @@ fn add_query_desc_cached_impl(
descs.extend(quote! {
#desc
});

cached.extend(quote! {
#cache
});
}

pub(super) fn rustc_queries(input: TokenStream) -> TokenStream {
Expand Down
25 changes: 15 additions & 10 deletions compiler/rustc_middle/src/query/plumbing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,18 @@ use crate::query::{
};
use crate::ty::TyCtxt;

pub type WillCacheOnDiskForKeyFn<'tcx, Key> = fn(tcx: TyCtxt<'tcx>, key: &Key) -> bool;

pub type TryLoadFromDiskFn<'tcx, Key, Value> = fn(
tcx: TyCtxt<'tcx>,
key: &Key,
prev_index: SerializedDepNodeIndex,
index: DepNodeIndex,
) -> Option<Value>;

pub type IsLoadableFromDiskFn<'tcx, Key> =
fn(tcx: TyCtxt<'tcx>, key: &Key, index: SerializedDepNodeIndex) -> bool;

/// Stores function pointers and other metadata for a particular query.
///
/// Used indirectly by query plumbing in `rustc_query_system`, via a trait.
Expand All @@ -31,18 +43,11 @@ pub struct QueryVTable<'tcx, C: QueryCache> {
pub query_state: usize,
// Offset of this query's cache field in the QueryCaches struct
pub query_cache: usize,
pub cache_on_disk: fn(tcx: TyCtxt<'tcx>, key: &C::Key) -> bool,
pub will_cache_on_disk_for_key_fn: Option<WillCacheOnDiskForKeyFn<'tcx, C::Key>>,
pub execute_query: fn(tcx: TyCtxt<'tcx>, k: C::Key) -> C::Value,
pub compute: fn(tcx: TyCtxt<'tcx>, key: C::Key) -> C::Value,
pub can_load_from_disk: bool,
pub try_load_from_disk: fn(
tcx: TyCtxt<'tcx>,
key: &C::Key,
prev_index: SerializedDepNodeIndex,
index: DepNodeIndex,
) -> Option<C::Value>,
pub loadable_from_disk:
fn(tcx: TyCtxt<'tcx>, key: &C::Key, index: SerializedDepNodeIndex) -> bool,
pub try_load_from_disk_fn: Option<TryLoadFromDiskFn<'tcx, C::Key, C::Value>>,
pub is_loadable_from_disk_fn: Option<IsLoadableFromDiskFn<'tcx, C::Key>>,
pub hash_result: HashResult<C::Value>,
pub value_from_cycle_error:
fn(tcx: TyCtxt<'tcx>, cycle_error: &CycleError, guar: ErrorGuaranteed) -> C::Value,
Expand Down
2 changes: 0 additions & 2 deletions compiler/rustc_passes/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -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 =
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_passes/src/check_attr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
| AttributeKind::RustcDumpVtable(..)
| AttributeKind::RustcDynIncompatibleTrait(..)
| AttributeKind::RustcHasIncoherentInherentImpls
| AttributeKind::RustcLayout(..)
| AttributeKind::RustcLayoutScalarValidRangeEnd(..)
| AttributeKind::RustcLayoutScalarValidRangeStart(..)
| AttributeKind::RustcLintOptDenyFieldAccess { .. }
Expand Down
7 changes: 0 additions & 7 deletions compiler/rustc_passes/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
49 changes: 20 additions & 29 deletions compiler/rustc_passes/src/layout_test.rs
Original file line number Diff line number Diff line change
@@ -1,35 +1,33 @@
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() {
// if the `rustc_attrs` feature is not enabled, don't bother testing layout
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);
}
}
}
Expand Down Expand Up @@ -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());
Expand All @@ -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!(
Expand All @@ -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() });
}
}
}
}
Expand Down
15 changes: 6 additions & 9 deletions compiler/rustc_query_impl/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,8 @@ where
}

#[inline(always)]
fn cache_on_disk(self, tcx: TyCtxt<'tcx>, key: &Self::Key) -> bool {
(self.vtable.cache_on_disk)(tcx, key)
fn will_cache_on_disk_for_key(self, tcx: TyCtxt<'tcx>, key: &Self::Key) -> bool {
self.vtable.will_cache_on_disk_for_key_fn.map_or(false, |f| f(tcx, key))
}

#[inline(always)]
Expand Down Expand Up @@ -128,21 +128,18 @@ where
prev_index: SerializedDepNodeIndex,
index: DepNodeIndex,
) -> Option<Self::Value> {
if self.vtable.can_load_from_disk {
(self.vtable.try_load_from_disk)(qcx.tcx, key, prev_index, index)
} else {
None
}
// `?` will return None immediately for queries that never cache to disk.
self.vtable.try_load_from_disk_fn?(qcx.tcx, key, prev_index, index)
}

#[inline]
fn loadable_from_disk(
fn is_loadable_from_disk(
self,
qcx: QueryCtxt<'tcx>,
key: &Self::Key,
index: SerializedDepNodeIndex,
) -> bool {
(self.vtable.loadable_from_disk)(qcx.tcx, key, index)
self.vtable.is_loadable_from_disk_fn.map_or(false, |f| f(qcx.tcx, key, index))
}

fn value_from_cycle_error(
Expand Down
Loading
Loading