Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add rustc_abi debugging attribute #115226

Merged
merged 1 commit into from
Aug 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions compiler/rustc_feature/src/builtin_attrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -814,6 +814,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
rustc_attr!(TEST, rustc_strict_coherence, Normal, template!(Word), WarnFollowing),
rustc_attr!(TEST, rustc_variance, Normal, template!(Word), WarnFollowing),
rustc_attr!(TEST, rustc_layout, Normal, template!(List: "field1, field2, ..."), WarnFollowing),
rustc_attr!(TEST, rustc_abi, Normal, template!(List: "field1, field2, ..."), WarnFollowing),
rustc_attr!(TEST, rustc_regions, Normal, template!(Word), WarnFollowing),
rustc_attr!(
TEST, rustc_error, Normal,
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_interface/src/passes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ use rustc_middle::query::{ExternProviders, Providers};
use rustc_middle::ty::{self, GlobalCtxt, RegisteredTools, TyCtxt};
use rustc_mir_build as mir_build;
use rustc_parse::{parse_crate_from_file, parse_crate_from_source_str, validate_attr};
use rustc_passes::{self, hir_stats, layout_test};
use rustc_passes::{self, abi_test, hir_stats, layout_test};
use rustc_plugin_impl as plugin;
use rustc_resolve::Resolver;
use rustc_session::code_stats::VTableSizeInfo;
Expand Down Expand Up @@ -818,6 +818,7 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> {
}

sess.time("layout_testing", || layout_test::test_layout(tcx));
sess.time("abi_testing", || abi_test::test_abi(tcx));

// Avoid overwhelming user with errors if borrow checking failed.
// I'm not sure how helpful this is, to be honest, but it avoids a
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_passes/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
passes_abi =
abi: {$abi}

passes_abi_of =
fn_abi_of_instance({$fn_name}) = {$fn_abi}

passes_align =
align: {$align}

Expand Down
93 changes: 93 additions & 0 deletions compiler/rustc_passes/src/abi_test.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
use rustc_ast::Attribute;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::DefId;
use rustc_middle::ty::layout::{FnAbiError, LayoutError};
use rustc_middle::ty::{self, GenericArgs, Instance, TyCtxt};
use rustc_span::source_map::Spanned;
use rustc_span::symbol::sym;

use crate::errors::{AbiOf, UnrecognizedField};

pub fn test_abi(tcx: TyCtxt<'_>) {
if !tcx.features().rustc_attrs {
// if the `rustc_attrs` feature is not enabled, don't bother testing ABI
return;
}
for id in tcx.hir().items() {
match tcx.def_kind(id.owner_id) {
DefKind::Fn => {
for attr in tcx.get_attrs(id.owner_id, sym::rustc_abi) {
dump_abi_of(tcx, id.owner_id.def_id.into(), attr);
}
}
DefKind::Impl { .. } => {
// To find associated functions we need to go into the child items here.
for &id in tcx.associated_item_def_ids(id.owner_id) {
if matches!(tcx.def_kind(id), DefKind::AssocFn) {
for attr in tcx.get_attrs(id, sym::rustc_abi) {
dump_abi_of(tcx, id, attr);
}
}
}
}
_ => {}
}
}
}

fn dump_abi_of(tcx: TyCtxt<'_>, item_def_id: DefId, attr: &Attribute) {
let param_env = tcx.param_env(item_def_id);
let args = GenericArgs::identity_for_item(tcx, item_def_id);
let instance = match Instance::resolve(tcx, param_env, item_def_id, args) {
Ok(Some(instance)) => instance,
Ok(None) => {
// Not sure what to do here, but `LayoutError::Unknown` seems reasonable?
let ty = tcx.type_of(item_def_id).instantiate_identity();
tcx.sess.emit_fatal(Spanned {
node: LayoutError::Unknown(ty).into_diagnostic(),

span: tcx.def_span(item_def_id),
});
}
Err(_guaranteed) => return,
};
RalfJung marked this conversation as resolved.
Show resolved Hide resolved
match tcx.fn_abi_of_instance(param_env.and((instance, /* extra_args */ ty::List::empty()))) {
Ok(abi) => {
// Check out the `#[rustc_abi(..)]` 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_or_empty() {
sym::debug => {
let fn_name = tcx.item_name(item_def_id);
tcx.sess.emit_err(AbiOf {
span: tcx.def_span(item_def_id),
fn_name,
fn_abi: format!("{:#?}", abi),
});
}

name => {
tcx.sess.emit_err(UnrecognizedField { span: meta_item.span(), name });
}
}
}
}

Err(FnAbiError::Layout(layout_error)) => {
tcx.sess.emit_fatal(Spanned {
compiler-errors marked this conversation as resolved.
Show resolved Hide resolved
node: layout_error.into_diagnostic(),
span: tcx.def_span(item_def_id),
});
}
Err(FnAbiError::AdjustForForeignAbi(e)) => {
// Sadly there seems to be no `into_diagnostic` for this case... and I am not sure if
// this can even be reached. Anyway this is a perma-unstable debug attribute, an ICE
// isn't the worst thing. Also this matches what codegen does.
span_bug!(
tcx.def_span(item_def_id),
"error computing fn_abi_of_instance, cannot adjust for foreign ABI: {e:?}",
)
}
}
}
9 changes: 9 additions & 0 deletions compiler/rustc_passes/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -913,6 +913,15 @@ pub struct LayoutOf {
pub ty_layout: String,
}

#[derive(Diagnostic)]
#[diag(passes_abi_of)]
pub struct AbiOf {
#[primary_span]
pub span: Span,
pub fn_name: Symbol,
pub fn_abi: String,
}

#[derive(Diagnostic)]
#[diag(passes_unrecognized_field)]
pub struct UnrecognizedField {
Expand Down
19 changes: 10 additions & 9 deletions compiler/rustc_passes/src/layout_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,17 @@ use rustc_target::abi::{HasDataLayout, TargetDataLayout};
use crate::errors::{Abi, Align, HomogeneousAggregate, LayoutOf, Size, UnrecognizedField};

pub fn test_layout(tcx: TyCtxt<'_>) {
if tcx.features().rustc_attrs {
if !tcx.features().rustc_attrs {
// if the `rustc_attrs` feature is not enabled, don't bother testing layout
for id in tcx.hir().items() {
if matches!(
tcx.def_kind(id.owner_id),
DefKind::TyAlias { .. } | DefKind::Enum | DefKind::Struct | DefKind::Union
) {
for attr in tcx.get_attrs(id.owner_id, sym::rustc_layout) {
dump_layout_of(tcx, id.owner_id.def_id, attr);
}
return;
}
for id in tcx.hir().items() {
if matches!(
tcx.def_kind(id.owner_id),
DefKind::TyAlias { .. } | DefKind::Enum | DefKind::Struct | DefKind::Union
) {
for attr in tcx.get_attrs(id.owner_id, sym::rustc_layout) {
dump_layout_of(tcx, id.owner_id.def_id, attr);
}
}
}
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_passes/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage};
use rustc_fluent_macro::fluent_messages;
use rustc_middle::query::Providers;

pub mod abi_test;
mod check_attr;
mod check_const;
pub mod dead;
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_span/src/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1281,6 +1281,7 @@ symbols! {
rust_eh_catch_typeinfo,
rust_eh_personality,
rustc,
rustc_abi,
rustc_allocator,
rustc_allocator_zeroed,
rustc_allow_const_fn_unstable,
Expand Down
23 changes: 23 additions & 0 deletions tests/ui/abi/debug.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// normalize-stderr-test "(abi|pref|unadjusted_abi_align): Align\([1-8] bytes\)" -> "$1: $$SOME_ALIGN"
// normalize-stderr-test "(size): Size\([48] bytes\)" -> "$1: $$SOME_SIZE"
// normalize-stderr-test "(can_unwind): (true|false)" -> "$1: $$SOME_BOOL"
// normalize-stderr-test "(valid_range): 0\.\.=(4294967295|18446744073709551615)" -> "$1: $$FULL"
// This pattern is prepared for when we account for alignment in the niche.
// normalize-stderr-test "(valid_range): [1-9]\.\.=(429496729[0-9]|1844674407370955161[0-9])" -> "$1: $$NON_NULL"
// Some attributes are only computed for release builds:
// compile-flags: -O
#![feature(rustc_attrs)]
#![crate_type = "lib"]

#[rustc_abi(debug)]
fn test(_x: u8) -> bool { true } //~ ERROR: fn_abi


#[rustc_abi(debug)]
fn test_generic<T>(_x: *const T) { } //~ ERROR: fn_abi

struct S(u16);
impl S {
#[rustc_abi(debug)]
fn assoc_test(&self) { } //~ ERROR: fn_abi
}
Loading