diff --git a/compiler/rustc_passes/src/abi_test.rs b/compiler/rustc_passes/src/abi_test.rs index 7e781bdd6f4a8..6a946b552130b 100644 --- a/compiler/rustc_passes/src/abi_test.rs +++ b/compiler/rustc_passes/src/abi_test.rs @@ -1,12 +1,13 @@ use rustc_ast::Attribute; use rustc_hir::def::DefKind; -use rustc_hir::def_id::DefId; +use rustc_hir::def_id::LocalDefId; use rustc_middle::ty::layout::{FnAbiError, LayoutError}; use rustc_middle::ty::{self, GenericArgs, Instance, Ty, TyCtxt}; use rustc_span::source_map::Spanned; use rustc_span::symbol::sym; use rustc_target::abi::call::FnAbi; +use super::layout_test::ensure_wf; use crate::errors::{AbiInvalidAttribute, AbiNe, AbiOf, UnrecognizedField}; pub fn test_abi(tcx: TyCtxt<'_>) { @@ -14,32 +15,17 @@ pub fn test_abi(tcx: TyCtxt<'_>) { // if the `rustc_attrs` feature is not enabled, don't bother testing ABI return; } - for id in tcx.hir().items() { - for attr in tcx.get_attrs(id.owner_id, sym::rustc_abi) { - match tcx.def_kind(id.owner_id) { - DefKind::Fn => { - dump_abi_of_fn_item(tcx, id.owner_id.def_id.into(), attr); + for id in tcx.hir_crate_items(()).definitions() { + for attr in tcx.get_attrs(id, sym::rustc_abi) { + match tcx.def_kind(id) { + DefKind::Fn | DefKind::AssocFn => { + dump_abi_of_fn_item(tcx, id, attr); } DefKind::TyAlias { .. } => { - dump_abi_of_fn_type(tcx, id.owner_id.def_id.into(), attr); + dump_abi_of_fn_type(tcx, id, attr); } _ => { - tcx.sess.emit_err(AbiInvalidAttribute { span: tcx.def_span(id.owner_id) }); - } - } - } - if matches!(tcx.def_kind(id.owner_id), 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) { - for attr in tcx.get_attrs(id, sym::rustc_abi) { - match tcx.def_kind(id) { - DefKind::AssocFn => { - dump_abi_of_fn_item(tcx, id, attr); - } - _ => { - tcx.sess.emit_err(AbiInvalidAttribute { span: tcx.def_span(id) }); - } - } + tcx.sess.emit_err(AbiInvalidAttribute { span: tcx.def_span(id) }); } } } @@ -49,7 +35,7 @@ pub fn test_abi(tcx: TyCtxt<'_>) { fn unwrap_fn_abi<'tcx>( abi: Result<&'tcx FnAbi<'tcx, Ty<'tcx>>, &'tcx FnAbiError<'tcx>>, tcx: TyCtxt<'tcx>, - item_def_id: DefId, + item_def_id: LocalDefId, ) -> &'tcx FnAbi<'tcx, Ty<'tcx>> { match abi { Ok(abi) => abi, @@ -71,10 +57,10 @@ fn unwrap_fn_abi<'tcx>( } } -fn dump_abi_of_fn_item(tcx: TyCtxt<'_>, item_def_id: DefId, attr: &Attribute) { +fn dump_abi_of_fn_item(tcx: TyCtxt<'_>, item_def_id: LocalDefId, 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) { + let instance = match Instance::resolve(tcx, param_env, item_def_id.into(), args) { Ok(Some(instance)) => instance, Ok(None) => { // Not sure what to do here, but `LayoutError::Unknown` seems reasonable? @@ -99,7 +85,7 @@ fn dump_abi_of_fn_item(tcx: TyCtxt<'_>, item_def_id: DefId, attr: &Attribute) { for meta_item in meta_items { match meta_item.name_or_empty() { sym::debug => { - let fn_name = tcx.item_name(item_def_id); + let fn_name = tcx.item_name(item_def_id.into()); tcx.sess.emit_err(AbiOf { span: tcx.def_span(item_def_id), fn_name, @@ -128,9 +114,13 @@ fn test_abi_eq<'tcx>(abi1: &'tcx FnAbi<'tcx, Ty<'tcx>>, abi2: &'tcx FnAbi<'tcx, && abi1.args.iter().zip(abi2.args.iter()).all(|(arg1, arg2)| arg1.eq_abi(arg2)) } -fn dump_abi_of_fn_type(tcx: TyCtxt<'_>, item_def_id: DefId, attr: &Attribute) { +fn dump_abi_of_fn_type(tcx: TyCtxt<'_>, item_def_id: LocalDefId, attr: &Attribute) { let param_env = tcx.param_env(item_def_id); let ty = tcx.type_of(item_def_id).instantiate_identity(); + let span = tcx.def_span(item_def_id); + if !ensure_wf(tcx, param_env, ty, item_def_id, span) { + return; + } let meta_items = attr.meta_item_list().unwrap_or_default(); for meta_item in meta_items { match meta_item.name_or_empty() { @@ -147,12 +137,8 @@ fn dump_abi_of_fn_type(tcx: TyCtxt<'_>, item_def_id: DefId, attr: &Attribute) { item_def_id, ); - 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), - }); + let fn_name = tcx.item_name(item_def_id.into()); + tcx.sess.emit_err(AbiOf { span, fn_name, fn_abi: format!("{:#?}", abi) }); } sym::assert_eq => { let ty::Tuple(fields) = ty.kind() else { @@ -196,7 +182,7 @@ fn dump_abi_of_fn_type(tcx: TyCtxt<'_>, item_def_id: DefId, attr: &Attribute) { if !test_abi_eq(abi1, abi2) { tcx.sess.emit_err(AbiNe { - span: tcx.def_span(item_def_id), + span, left: format!("{:#?}", abi1), right: format!("{:#?}", abi2), }); diff --git a/compiler/rustc_passes/src/layout_test.rs b/compiler/rustc_passes/src/layout_test.rs index f3c12e0746d97..3e0dc1f6063ff 100644 --- a/compiler/rustc_passes/src/layout_test.rs +++ b/compiler/rustc_passes/src/layout_test.rs @@ -2,11 +2,13 @@ use rustc_ast::Attribute; use rustc_hir::def::DefKind; use rustc_hir::def_id::LocalDefId; use rustc_middle::ty::layout::{HasParamEnv, HasTyCtxt, LayoutError, LayoutOfHelpers, TyAndLayout}; -use rustc_middle::ty::{ParamEnv, Ty, TyCtxt}; +use rustc_middle::ty::{self, ParamEnv, Ty, TyCtxt}; use rustc_span::source_map::Spanned; use rustc_span::symbol::sym; use rustc_span::Span; use rustc_target::abi::{HasDataLayout, TargetDataLayout}; +use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt; +use rustc_trait_selection::{infer::TyCtxtInferExt, traits}; use crate::errors::{ LayoutAbi, LayoutAlign, LayoutHomogeneousAggregate, LayoutInvalidAttribute, LayoutOf, @@ -18,21 +20,13 @@ pub fn test_layout(tcx: TyCtxt<'_>) { // if the `rustc_attrs` feature is not enabled, don't bother testing layout return; } - for id in tcx.hir().items() { - for attr in tcx.get_attrs(id.owner_id, sym::rustc_layout) { - match tcx.def_kind(id.owner_id) { + 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.owner_id.def_id, attr); + dump_layout_of(tcx, id, attr); } _ => { - tcx.sess.emit_err(LayoutInvalidAttribute { span: tcx.def_span(id.owner_id) }); - } - } - } - if matches!(tcx.def_kind(id.owner_id), 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) { - for _attr in tcx.get_attrs(id, sym::rustc_layout) { tcx.sess.emit_err(LayoutInvalidAttribute { span: tcx.def_span(id) }); } } @@ -40,9 +34,44 @@ pub fn test_layout(tcx: TyCtxt<'_>) { } } +pub fn ensure_wf<'tcx>( + tcx: TyCtxt<'tcx>, + param_env: ParamEnv<'tcx>, + ty: Ty<'tcx>, + def_id: LocalDefId, + span: Span, +) -> bool { + let pred = ty::ClauseKind::WellFormed(ty.into()); + let obligation = traits::Obligation::new( + tcx, + traits::ObligationCause::new( + span, + def_id, + traits::ObligationCauseCode::WellFormed(Some(traits::WellFormedLoc::Ty(def_id))), + ), + param_env, + pred, + ); + let infcx = tcx.infer_ctxt().build(); + let ocx = traits::ObligationCtxt::new(&infcx); + ocx.register_obligation(obligation); + let errors = ocx.select_all_or_error(); + if !errors.is_empty() { + infcx.err_ctxt().report_fulfillment_errors(&errors); + false + } else { + // looks WF! + true + } +} + fn dump_layout_of(tcx: TyCtxt<'_>, item_def_id: LocalDefId, attr: &Attribute) { let param_env = tcx.param_env(item_def_id); let ty = tcx.type_of(item_def_id).instantiate_identity(); + let span = tcx.def_span(item_def_id.to_def_id()); + if !ensure_wf(tcx, param_env, ty, item_def_id, span) { + return; + } match tcx.layout_of(param_env.and(ty)) { Ok(ty_layout) => { // Check out the `#[rustc_layout(..)]` attribute to tell what to dump. @@ -51,29 +80,24 @@ fn dump_layout_of(tcx: TyCtxt<'_>, item_def_id: LocalDefId, attr: &Attribute) { for meta_item in meta_items { match meta_item.name_or_empty() { sym::abi => { - tcx.sess.emit_err(LayoutAbi { - span: tcx.def_span(item_def_id.to_def_id()), - abi: format!("{:?}", ty_layout.abi), - }); + tcx.sess.emit_err(LayoutAbi { span, abi: format!("{:?}", ty_layout.abi) }); } sym::align => { tcx.sess.emit_err(LayoutAlign { - span: tcx.def_span(item_def_id.to_def_id()), + span, align: format!("{:?}", ty_layout.align), }); } sym::size => { - tcx.sess.emit_err(LayoutSize { - span: tcx.def_span(item_def_id.to_def_id()), - size: format!("{:?}", ty_layout.size), - }); + tcx.sess + .emit_err(LayoutSize { span, size: format!("{:?}", ty_layout.size) }); } sym::homogeneous_aggregate => { tcx.sess.emit_err(LayoutHomogeneousAggregate { - span: tcx.def_span(item_def_id.to_def_id()), + span, homogeneous_aggregate: format!( "{:?}", ty_layout.homogeneous_aggregate(&UnwrapLayoutCx { tcx, param_env }) @@ -90,11 +114,7 @@ fn dump_layout_of(tcx: TyCtxt<'_>, item_def_id: LocalDefId, attr: &Attribute) { ) ); let ty_layout = format!("{:#?}", *ty_layout); - tcx.sess.emit_err(LayoutOf { - span: tcx.def_span(item_def_id.to_def_id()), - normalized_ty, - ty_layout, - }); + tcx.sess.emit_err(LayoutOf { span, normalized_ty, ty_layout }); } name => { @@ -105,11 +125,7 @@ fn dump_layout_of(tcx: TyCtxt<'_>, item_def_id: LocalDefId, attr: &Attribute) { } Err(layout_error) => { - tcx.sess.emit_fatal(Spanned { - node: layout_error.into_diagnostic(), - - span: tcx.def_span(item_def_id.to_def_id()), - }); + tcx.sess.emit_fatal(Spanned { node: layout_error.into_diagnostic(), span }); } } } diff --git a/tests/ui/abi/compatibility.rs b/tests/ui/abi/compatibility.rs index 0bbcba200c7e3..86fb365507a88 100644 --- a/tests/ui/abi/compatibility.rs +++ b/tests/ui/abi/compatibility.rs @@ -2,6 +2,7 @@ #![feature(rustc_attrs, transparent_unions)] #![allow(unused, improper_ctypes_definitions)] use std::marker::PhantomData; +use std::mem::ManuallyDrop; use std::num::NonZeroI32; use std::ptr::NonNull; @@ -37,9 +38,9 @@ enum ReprCEnum { Variant2(T), } #[repr(C)] -union ReprCUnion { +union ReprCUnion { nothing: (), - something: T, + something: ManuallyDrop, } macro_rules! test_abi_compatible { @@ -82,9 +83,9 @@ struct Wrapper2((), Zst, T); #[repr(transparent)] struct Wrapper3(T, [u8; 0], PhantomData); #[repr(transparent)] -union WrapperUnion { +union WrapperUnion { nothing: (), - something: T, + something: ManuallyDrop, } macro_rules! test_transparent { diff --git a/tests/ui/abi/debug.rs b/tests/ui/abi/debug.rs index 9decb41d56517..77715ee4023b8 100644 --- a/tests/ui/abi/debug.rs +++ b/tests/ui/abi/debug.rs @@ -48,3 +48,6 @@ type TestAbiNeFloat = (fn(f32), fn(u32)); //~ ERROR: ABIs are not compatible // Sign matters on some targets (such as s390x), so let's make sure we never accept this. #[rustc_abi(assert_eq)] type TestAbiNeSign = (fn(i32), fn(u32)); //~ ERROR: ABIs are not compatible + +#[rustc_abi(assert_eq)] +type TestAbiEqNonsense = (fn((str, str)), fn((str, str))); //~ ERROR: cannot be known at compilation time diff --git a/tests/ui/abi/debug.stderr b/tests/ui/abi/debug.stderr index 0feaf0971d8d2..ceaf5136a6f55 100644 --- a/tests/ui/abi/debug.stderr +++ b/tests/ui/abi/debug.stderr @@ -268,100 +268,6 @@ error: `#[rustc_abi]` can only be applied to function items, type aliases, and a LL | const C: () = (); | ^^^^^^^^^^^ -error: `#[rustc_abi]` can only be applied to function items, type aliases, and associated functions - --> $DIR/debug.rs:28:5 - | -LL | const C: () = (); - | ^^^^^^^^^^^ - -error: fn_abi_of(assoc_test) = FnAbi { - args: [ - ArgAbi { - layout: TyAndLayout { - ty: &S, - layout: Layout { - size: $SOME_SIZE, - align: AbiAndPrefAlign { - abi: $SOME_ALIGN, - pref: $SOME_ALIGN, - }, - abi: Scalar( - Initialized { - value: Pointer( - AddressSpace( - 0, - ), - ), - valid_range: $NON_NULL, - }, - ), - fields: Primitive, - largest_niche: Some( - Niche { - offset: Size(0 bytes), - value: Pointer( - AddressSpace( - 0, - ), - ), - valid_range: $NON_NULL, - }, - ), - variants: Single { - index: 0, - }, - max_repr_align: None, - unadjusted_abi_align: $SOME_ALIGN, - }, - }, - mode: Direct( - ArgAttributes { - regular: NoAlias | NonNull | ReadOnly | NoUndef, - arg_ext: None, - pointee_size: Size(2 bytes), - pointee_align: Some( - Align(2 bytes), - ), - }, - ), - }, - ], - ret: ArgAbi { - layout: TyAndLayout { - ty: (), - layout: Layout { - size: Size(0 bytes), - align: AbiAndPrefAlign { - abi: $SOME_ALIGN, - pref: $SOME_ALIGN, - }, - abi: Aggregate { - sized: true, - }, - fields: Arbitrary { - offsets: [], - memory_index: [], - }, - largest_niche: None, - variants: Single { - index: 0, - }, - max_repr_align: None, - unadjusted_abi_align: $SOME_ALIGN, - }, - }, - mode: Ignore, - }, - c_variadic: false, - fixed_count: 1, - conv: Rust, - can_unwind: $SOME_BOOL, - } - --> $DIR/debug.rs:33:5 - | -LL | fn assoc_test(&self) { } - | ^^^^^^^^^^^^^^^^^^^^ - error: ABIs are not compatible left ABI = FnAbi { args: [ @@ -945,5 +851,109 @@ error: ABIs are not compatible LL | type TestAbiNeSign = (fn(i32), fn(u32)); | ^^^^^^^^^^^^^^^^^^ -error: aborting due to 10 previous errors +error[E0277]: the size for values of type `str` cannot be known at compilation time + --> $DIR/debug.rs:53:46 + | +LL | type TestAbiEqNonsense = (fn((str, str)), fn((str, str))); + | ^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `str` + = note: only the last element of a tuple may have a dynamically sized type + +error: `#[rustc_abi]` can only be applied to function items, type aliases, and associated functions + --> $DIR/debug.rs:28:5 + | +LL | const C: () = (); + | ^^^^^^^^^^^ + +error: fn_abi_of(assoc_test) = FnAbi { + args: [ + ArgAbi { + layout: TyAndLayout { + ty: &S, + layout: Layout { + size: $SOME_SIZE, + align: AbiAndPrefAlign { + abi: $SOME_ALIGN, + pref: $SOME_ALIGN, + }, + abi: Scalar( + Initialized { + value: Pointer( + AddressSpace( + 0, + ), + ), + valid_range: $NON_NULL, + }, + ), + fields: Primitive, + largest_niche: Some( + Niche { + offset: Size(0 bytes), + value: Pointer( + AddressSpace( + 0, + ), + ), + valid_range: $NON_NULL, + }, + ), + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: $SOME_ALIGN, + }, + }, + mode: Direct( + ArgAttributes { + regular: NoAlias | NonNull | ReadOnly | NoUndef, + arg_ext: None, + pointee_size: Size(2 bytes), + pointee_align: Some( + Align(2 bytes), + ), + }, + ), + }, + ], + ret: ArgAbi { + layout: TyAndLayout { + ty: (), + layout: Layout { + size: Size(0 bytes), + align: AbiAndPrefAlign { + abi: $SOME_ALIGN, + pref: $SOME_ALIGN, + }, + abi: Aggregate { + sized: true, + }, + fields: Arbitrary { + offsets: [], + memory_index: [], + }, + largest_niche: None, + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: $SOME_ALIGN, + }, + }, + mode: Ignore, + }, + c_variadic: false, + fixed_count: 1, + conv: Rust, + can_unwind: $SOME_BOOL, + } + --> $DIR/debug.rs:33:5 + | +LL | fn assoc_test(&self) { } + | ^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 11 previous errors +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/associated-types/issue-85103-layout-debug.rs b/tests/ui/associated-types/issue-85103-layout-debug.rs new file mode 100644 index 0000000000000..77c9876ffa57f --- /dev/null +++ b/tests/ui/associated-types/issue-85103-layout-debug.rs @@ -0,0 +1,9 @@ +#![feature(rustc_attrs)] + +use std::borrow::Cow; + +#[rustc_layout(debug)] +type Edges<'a, E> = Cow<'a, [E]>; +//~^ the trait bound `[E]: ToOwned` is not satisfied + +fn main() {} diff --git a/tests/ui/associated-types/issue-85103-layout-debug.stderr b/tests/ui/associated-types/issue-85103-layout-debug.stderr new file mode 100644 index 0000000000000..0bdea10ba474a --- /dev/null +++ b/tests/ui/associated-types/issue-85103-layout-debug.stderr @@ -0,0 +1,16 @@ +error[E0277]: the trait bound `[E]: ToOwned` is not satisfied + --> $DIR/issue-85103-layout-debug.rs:6:21 + | +LL | type Edges<'a, E> = Cow<'a, [E]>; + | ^^^^^^^^^^^^ the trait `ToOwned` is not implemented for `[E]` + | +note: required by a bound in `Cow` + --> $SRC_DIR/alloc/src/borrow.rs:LL:COL +help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement + | +LL | type Edges<'a, E> where [E]: ToOwned = Cow<'a, [E]>; + | ++++++++++++++++++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/associated-types/issue-85103.rs b/tests/ui/associated-types/issue-85103.rs deleted file mode 100644 index 9c6a419e9f72d..0000000000000 --- a/tests/ui/associated-types/issue-85103.rs +++ /dev/null @@ -1,9 +0,0 @@ -#![feature(rustc_attrs)] - -use std::borrow::Cow; - -#[rustc_layout(debug)] -type Edges<'a, E> = Cow<'a, [E]>; -//~^ 6:1: 6:18: unable to determine layout for `<[E] as ToOwned>::Owned` because `<[E] as ToOwned>::Owned` cannot be normalized - -fn main() {} diff --git a/tests/ui/associated-types/issue-85103.stderr b/tests/ui/associated-types/issue-85103.stderr deleted file mode 100644 index 17f7148074cf3..0000000000000 --- a/tests/ui/associated-types/issue-85103.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error: unable to determine layout for `<[E] as ToOwned>::Owned` because `<[E] as ToOwned>::Owned` cannot be normalized - --> $DIR/issue-85103.rs:6:1 - | -LL | type Edges<'a, E> = Cow<'a, [E]>; - | ^^^^^^^^^^^^^^^^^ - -error: aborting due to previous error - diff --git a/tests/ui/layout/debug.rs b/tests/ui/layout/debug.rs index 97dc73d3aa70c..65f2f3b89af1f 100644 --- a/tests/ui/layout/debug.rs +++ b/tests/ui/layout/debug.rs @@ -73,3 +73,6 @@ impl S { #[rustc_layout(debug)] const C: () = (); //~ ERROR: can only be applied to } + +#[rustc_layout(debug)] +type Impossible = (str, str); //~ ERROR: cannot be known at compilation time diff --git a/tests/ui/layout/debug.stderr b/tests/ui/layout/debug.stderr index 0973043c67814..1ba70ae39e71b 100644 --- a/tests/ui/layout/debug.stderr +++ b/tests/ui/layout/debug.stderr @@ -557,11 +557,21 @@ error: `#[rustc_layout]` can only be applied to `struct`/`enum`/`union` declarat LL | const C: () = (); | ^^^^^^^^^^^ +error[E0277]: the size for values of type `str` cannot be known at compilation time + --> $DIR/debug.rs:78:19 + | +LL | type Impossible = (str, str); + | ^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `str` + = note: only the last element of a tuple may have a dynamically sized type + error: `#[rustc_layout]` can only be applied to `struct`/`enum`/`union` declarations and type aliases --> $DIR/debug.rs:74:5 | LL | const C: () = (); | ^^^^^^^^^^^ -error: aborting due to 16 previous errors +error: aborting due to 17 previous errors +For more information about this error, try `rustc --explain E0277`.