diff --git a/Cargo.lock b/Cargo.lock index 1a930b64f4581..5bf597f0aa68c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3431,6 +3431,7 @@ dependencies = [ "rustc_macros", "rustc_serialize", "rustc_span", + "serde", "tracing", ] @@ -4250,6 +4251,7 @@ dependencies = [ "rustc_target", "rustc_thread_pool", "rustc_type_ir", + "serde", "smallvec", "thin-vec", "tracing", diff --git a/compiler/rustc_abi/Cargo.toml b/compiler/rustc_abi/Cargo.toml index 83d96d8d04daf..4776454204f32 100644 --- a/compiler/rustc_abi/Cargo.toml +++ b/compiler/rustc_abi/Cargo.toml @@ -15,6 +15,7 @@ rustc_index = { path = "../rustc_index", default-features = false } rustc_macros = { path = "../rustc_macros", optional = true } rustc_serialize = { path = "../rustc_serialize", optional = true } rustc_span = { path = "../rustc_span", optional = true } +serde = { version = "1.0.125", features = ["derive"] } tracing = "0.1" # tidy-alphabetical-end diff --git a/compiler/rustc_abi/src/callconv/reg.rs b/compiler/rustc_abi/src/callconv/reg.rs index 66c8056d0c2af..66d4dca00726f 100644 --- a/compiler/rustc_abi/src/callconv/reg.rs +++ b/compiler/rustc_abi/src/callconv/reg.rs @@ -35,6 +35,7 @@ impl Reg { reg_ctor!(f32, Float, 32); reg_ctor!(f64, Float, 64); + reg_ctor!(f128, Float, 128); } impl Reg { diff --git a/compiler/rustc_abi/src/layout/ty.rs b/compiler/rustc_abi/src/layout/ty.rs index aafb124986e14..036d1c5f06cad 100644 --- a/compiler/rustc_abi/src/layout/ty.rs +++ b/compiler/rustc_abi/src/layout/ty.rs @@ -33,7 +33,7 @@ rustc_index::newtype_index! { /// `b` is `FieldIdx(1)` in `VariantIdx(0)`, /// `d` is `FieldIdx(1)` in `VariantIdx(1)`, and /// `f` is `FieldIdx(1)` in `VariantIdx(0)`. - #[derive(HashStable_Generic)] + #[derive(HashStable_Generic, serde::Serialize)] #[encodable] #[orderable] pub struct FieldIdx {} @@ -57,7 +57,7 @@ rustc_index::newtype_index! { /// /// `struct`s, `tuples`, and `unions`s are considered to have a single variant /// with variant index zero, aka [`FIRST_VARIANT`]. - #[derive(HashStable_Generic)] + #[derive(HashStable_Generic, serde::Serialize)] #[encodable] #[orderable] pub struct VariantIdx { diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index fa323b7cf581a..c0130a58cb6b7 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -2553,6 +2553,11 @@ pub enum TyKind { /// Pattern types like `pattern_type!(u32 is 1..=)`, which is the same as `NonZero`, /// just as part of the type system. Pat(Box, Box), + /// A `field_of` expression (e.g., `builtin # field_of(Struct, field)`). + /// + /// Usually not written directly in user code but indirectly via the macro + /// `core::field::field_of!(...)`. + FieldOf(Box, Option, Ident), /// Sometimes we need a dummy value when no error has occurred. Dummy, /// Placeholder for a kind that has failed to be defined. diff --git a/compiler/rustc_ast/src/util/classify.rs b/compiler/rustc_ast/src/util/classify.rs index 2e494b968b6bd..43ef6897b79cf 100644 --- a/compiler/rustc_ast/src/util/classify.rs +++ b/compiler/rustc_ast/src/util/classify.rs @@ -298,6 +298,7 @@ fn type_trailing_braced_mac_call(mut ty: &ast::Ty) -> Option<&ast::MacCall> { | ast::TyKind::ImplicitSelf | ast::TyKind::CVarArgs | ast::TyKind::Pat(..) + | ast::TyKind::FieldOf(..) | ast::TyKind::Dummy | ast::TyKind::Err(..) => break None, } diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index ff5edfc799439..c89fd8acb2a3e 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -1497,6 +1497,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { TyKind::Pat(ty, pat) => { hir::TyKind::Pat(self.lower_ty_alloc(ty, itctx), self.lower_ty_pat(pat, ty.span)) } + TyKind::FieldOf(ty, variant, field) => hir::TyKind::FieldOf( + self.lower_ty_alloc(ty, itctx), + self.arena.alloc(hir::TyFieldPath { + variant: variant.map(|variant| self.lower_ident(variant)), + field: self.lower_ident(*field), + }), + ), + TyKind::MacCall(_) => { span_bug!(t.span, "`TyKind::MacCall` should have been expanded by now") } diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index c8874ed99dca9..f4168301bc5df 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -1377,6 +1377,23 @@ impl<'a> State<'a> { self.word(" is "); self.print_ty_pat(pat); } + ast::TyKind::FieldOf(ty, variant, field) => { + self.word("builtin # field_of"); + self.popen(); + let ib = self.ibox(0); + self.print_type(ty); + self.word(","); + self.space(); + + if let Some(variant) = variant { + self.print_ident(*variant); + self.word("."); + } + self.print_ident(*field); + + self.end(ib); + self.pclose(); + } } self.end(ib); } diff --git a/compiler/rustc_attr_parsing/src/attributes/proc_macro_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/proc_macro_attrs.rs index 3674aa7124abb..f9ace7e25d1b3 100644 --- a/compiler/rustc_attr_parsing/src/attributes/proc_macro_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/proc_macro_attrs.rs @@ -1,3 +1,6 @@ +use rustc_hir::lints::AttributeLintKind; +use rustc_session::lint::builtin::AMBIGUOUS_DERIVE_HELPERS; + use super::prelude::*; const PROC_MACRO_ALLOWED_TARGETS: AllowedTargets = @@ -126,6 +129,13 @@ fn parse_derive_like( cx.expected_identifier(ident.span); return None; } + if rustc_feature::is_builtin_attr_name(ident.name) { + cx.emit_lint( + AMBIGUOUS_DERIVE_HELPERS, + AttributeLintKind::AmbiguousDeriveHelpers, + ident.span, + ); + } attributes.push(ident.name); } } diff --git a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs index 6ed07cf9b1c8c..a927c30fae325 100644 --- a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs @@ -24,7 +24,6 @@ use rustc_traits::{type_op_ascribe_user_type_with_span, type_op_prove_predicate_ use tracing::{debug, instrument}; use crate::MirBorrowckCtxt; -use crate::region_infer::values::RegionElement; use crate::session_diagnostics::{ HigherRankedErrorCause, HigherRankedLifetimeError, HigherRankedSubtypeError, }; @@ -49,11 +48,12 @@ impl<'tcx> UniverseInfo<'tcx> { UniverseInfo::RelateTys { expected, found } } + /// Report an error where an element erroneously made its way into `placeholder`. pub(crate) fn report_erroneous_element( &self, mbcx: &mut MirBorrowckCtxt<'_, '_, 'tcx>, placeholder: ty::PlaceholderRegion<'tcx>, - error_element: RegionElement<'tcx>, + error_element: Option>, cause: ObligationCause<'tcx>, ) { match *self { @@ -146,14 +146,14 @@ pub(crate) trait TypeOpInfo<'tcx> { ) -> Option>; /// Constraints require that `error_element` appear in the - /// values of `placeholder`, but this cannot be proven to + /// values of `placeholder`, but this cannot be proven to /// hold. Report an error. #[instrument(level = "debug", skip(self, mbcx))] fn report_erroneous_element( &self, mbcx: &mut MirBorrowckCtxt<'_, '_, 'tcx>, placeholder: ty::PlaceholderRegion<'tcx>, - error_element: RegionElement<'tcx>, + error_element: Option>, cause: ObligationCause<'tcx>, ) { let tcx = mbcx.infcx.tcx; @@ -172,19 +172,17 @@ pub(crate) trait TypeOpInfo<'tcx> { ty::PlaceholderRegion::new(adjusted_universe.into(), placeholder.bound), ); - let error_region = - if let RegionElement::PlaceholderRegion(error_placeholder) = error_element { - let adjusted_universe = - error_placeholder.universe.as_u32().checked_sub(base_universe.as_u32()); - adjusted_universe.map(|adjusted| { - ty::Region::new_placeholder( - tcx, - ty::PlaceholderRegion::new(adjusted.into(), error_placeholder.bound), - ) - }) - } else { - None - }; + // FIXME: one day this should just be error_element, + // and this method shouldn't do anything. + let error_region = error_element.and_then(|e| { + let adjusted_universe = e.universe.as_u32().checked_sub(base_universe.as_u32()); + adjusted_universe.map(|adjusted| { + ty::Region::new_placeholder( + tcx, + ty::PlaceholderRegion::new(adjusted.into(), e.bound), + ) + }) + }); debug!(?placeholder_region); diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs index ae389d1a6e10c..9dbb8f971c62f 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs @@ -29,7 +29,6 @@ use tracing::{debug, instrument, trace}; use super::{LIMITATION_NOTE, OutlivesSuggestionBuilder, RegionName, RegionNameSource}; use crate::nll::ConstraintDescription; -use crate::region_infer::values::RegionElement; use crate::region_infer::{BlameConstraint, TypeTest}; use crate::session_diagnostics::{ FnMutError, FnMutReturnTypeErr, GenericDoesNotLiveLongEnough, LifetimeOutliveErr, @@ -104,15 +103,9 @@ pub(crate) enum RegionErrorKind<'tcx> { /// A generic bound failure for a type test (`T: 'a`). TypeTestError { type_test: TypeTest<'tcx> }, - /// Higher-ranked subtyping error. - BoundUniversalRegionError { - /// The placeholder free region. - longer_fr: RegionVid, - /// The region element that erroneously must be outlived by `longer_fr`. - error_element: RegionElement<'tcx>, - /// The placeholder region. - placeholder: ty::PlaceholderRegion<'tcx>, - }, + /// 'p outlives 'r, which does not hold. 'p is always a placeholder + /// and 'r is some other region. + PlaceholderOutlivesIllegalRegion { longer_fr: RegionVid, illegally_outlived_r: RegionVid }, /// Any other lifetime error. RegionError { @@ -360,28 +353,11 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { } } - RegionErrorKind::BoundUniversalRegionError { + RegionErrorKind::PlaceholderOutlivesIllegalRegion { longer_fr, - placeholder, - error_element, + illegally_outlived_r, } => { - let error_vid = self.regioncx.region_from_element(longer_fr, &error_element); - - // Find the code to blame for the fact that `longer_fr` outlives `error_fr`. - let cause = self - .regioncx - .best_blame_constraint( - longer_fr, - NllRegionVariableOrigin::Placeholder(placeholder), - error_vid, - ) - .0 - .cause; - - let universe = placeholder.universe; - let universe_info = self.regioncx.universe_info(universe); - - universe_info.report_erroneous_element(self, placeholder, error_element, cause); + self.report_erroneous_rvid_reaches_placeholder(longer_fr, illegally_outlived_r) } RegionErrorKind::RegionError { fr_origin, longer_fr, shorter_fr, is_reported } => { @@ -412,6 +388,43 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { outlives_suggestion.add_suggestion(self); } + /// Report that `longer_fr: error_vid`, which doesn't hold, + /// where `longer_fr` is a placeholder. + fn report_erroneous_rvid_reaches_placeholder( + &mut self, + longer_fr: RegionVid, + error_vid: RegionVid, + ) { + use NllRegionVariableOrigin::*; + + let origin_longer = self.regioncx.definitions[longer_fr].origin; + + let Placeholder(placeholder) = origin_longer else { + bug!("Expected {longer_fr:?} to come from placeholder!"); + }; + + // FIXME: Is throwing away the existential region really the best here? + let error_region = match self.regioncx.definitions[error_vid].origin { + FreeRegion | Existential { .. } => None, + Placeholder(other_placeholder) => Some(other_placeholder), + }; + + // Find the code to blame for the fact that `longer_fr` outlives `error_fr`. + let cause = + self.regioncx.best_blame_constraint(longer_fr, origin_longer, error_vid).0.cause; + + // FIXME these methods should have better names, and also probably not be this generic. + // FIXME note that we *throw away* the error element here! We probably want to + // thread it through the computation further down and use it, but there currently isn't + // anything there to receive it. + self.regioncx.universe_info(placeholder.universe).report_erroneous_element( + self, + placeholder, + error_region, + cause, + ); + } + /// Report an error because the universal region `fr` was required to outlive /// `outlived_fr` but it is not known to do so. For example: /// diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 38b73a07a6891..9f07f6199695b 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -1890,6 +1890,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { | ty::Str | ty::Array(_, _) | ty::Pat(_, _) + | ty::FRT(..) | ty::Slice(_) | ty::FnDef(_, _) | ty::FnPtr(..) @@ -1934,6 +1935,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { | ty::Str | ty::Array(_, _) | ty::Pat(_, _) + | ty::FRT(..) | ty::Slice(_) | ty::RawPtr(_, _) | ty::Ref(_, _, _) diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index 6ed70b39c5b7f..5cdda777723b3 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -1379,11 +1379,11 @@ impl<'tcx> RegionInferenceContext<'tcx> { .elements_contained_in(longer_fr_scc) .find(|e| *e != RegionElement::PlaceholderRegion(placeholder)) { + let illegally_outlived_r = self.region_from_element(longer_fr, &error_element); // Stop after the first error, it gets too noisy otherwise, and does not provide more information. - errors_buffer.push(RegionErrorKind::BoundUniversalRegionError { + errors_buffer.push(RegionErrorKind::PlaceholderOutlivesIllegalRegion { longer_fr, - error_element, - placeholder, + illegally_outlived_r, }); } else { debug!("check_bound_universal_region: all bounds satisfied"); @@ -1572,7 +1572,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { } /// Get the region outlived by `longer_fr` and live at `element`. - pub(crate) fn region_from_element( + fn region_from_element( &self, longer_fr: RegionVid, element: &RegionElement<'tcx>, diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs index 553e4d3d2fe09..68939c9476d61 100644 --- a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs +++ b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs @@ -22,13 +22,18 @@ use rustc_codegen_ssa::traits::{ ArgAbiBuilderMethods, BaseTypeCodegenMethods, BuilderMethods, ConstCodegenMethods, IntrinsicCallBuilderMethods, LayoutTypeCodegenMethods, }; +use rustc_data_structures::fx::FxHashSet; use rustc_middle::bug; -use rustc_middle::ty::layout::{FnAbiOf, LayoutOf}; +#[cfg(feature = "master")] +use rustc_middle::ty::layout::FnAbiOf; +use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::{self, Instance, Ty}; use rustc_span::{Span, Symbol, sym}; use rustc_target::callconv::{ArgAbi, PassMode}; -use crate::abi::{FnAbiGccExt, GccType}; +#[cfg(feature = "master")] +use crate::abi::FnAbiGccExt; +use crate::abi::GccType; use crate::builder::Builder; use crate::common::{SignType, TypeReflection}; use crate::context::CodegenCx; @@ -617,8 +622,6 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc *func } else { self.linkage.set(FunctionType::Extern); - let fn_abi = self.fn_abi_of_instance(instance, ty::List::empty()); - let fn_ty = fn_abi.gcc_type(self); let func = match sym { "llvm.fma.f16" => { @@ -631,13 +634,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc self.intrinsics.borrow_mut().insert(sym.to_string(), func); - self.on_stack_function_params - .borrow_mut() - .insert(func, fn_ty.on_stack_param_indices); - #[cfg(feature = "master")] - for fn_attr in fn_ty.fn_attributes { - func.add_attribute(fn_attr); - } + self.on_stack_function_params.borrow_mut().insert(func, FxHashSet::default()); crate::attributes::from_fn_attrs(self, func, instance); diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index e035f0809d685..c0e7c18b4d470 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -646,10 +646,32 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { ) -> Self::Value { let tcx = self.tcx(); - // FIXME remove usage of fn_abi - let fn_abi = self.fn_abi_of_instance(instance, ty::List::empty()); - assert!(!fn_abi.ret.is_indirect()); - let fn_ty = fn_abi.llvm_type(self); + let fn_ty = instance.ty(tcx, self.typing_env()); + let fn_sig = match *fn_ty.kind() { + ty::FnDef(def_id, args) => { + tcx.instantiate_bound_regions_with_erased(tcx.fn_sig(def_id).instantiate(tcx, args)) + } + _ => unreachable!(), + }; + assert!(!fn_sig.c_variadic); + + let ret_layout = self.layout_of(fn_sig.output()); + let llreturn_ty = if ret_layout.is_zst() { + self.type_void() + } else { + ret_layout.immediate_llvm_type(self) + }; + + let mut llargument_tys = Vec::with_capacity(fn_sig.inputs().len()); + for &arg in fn_sig.inputs() { + let arg_layout = self.layout_of(arg); + if arg_layout.is_zst() { + continue; + } + llargument_tys.push(arg_layout.immediate_llvm_type(self)); + } + + let fn_ty = self.type_func(&llargument_tys, llreturn_ty); let fn_ptr = if let Some(&llfn) = self.intrinsic_instances.borrow().get(&instance) { llfn @@ -665,12 +687,11 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { let llfn = declare_raw_fn( self, sym, - fn_abi.llvm_cconv(self), + llvm::CCallConv, llvm::UnnamedAddr::Global, llvm::Visibility::Default, fn_ty, ); - fn_abi.apply_attrs_llfn(self, llfn, Some(instance)); llfn }; diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs index 1c88a8da5ea94..f3a1d42e96d7b 100644 --- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs +++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs @@ -216,6 +216,8 @@ fn push_debuginfo_type_name<'tcx>( write!(output, "{:?}", t).unwrap(); } } + // FIXME(FRTs): implement debuginfo for field representing types + ty::FRT(..) => todo!(), ty::Slice(inner_type) => { if cpp_like_debuginfo { output.push_str("slice2$<"); diff --git a/compiler/rustc_const_eval/src/const_eval/type_info.rs b/compiler/rustc_const_eval/src/const_eval/type_info.rs index f8881f0968bb4..2d2300497f6e9 100644 --- a/compiler/rustc_const_eval/src/const_eval/type_info.rs +++ b/compiler/rustc_const_eval/src/const_eval/type_info.rs @@ -136,6 +136,7 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> { variant } ty::Adt(_, _) + | ty::FRT(_, _) | ty::Foreign(_) | ty::Pat(_, _) | ty::FnDef(..) diff --git a/compiler/rustc_const_eval/src/const_eval/valtrees.rs b/compiler/rustc_const_eval/src/const_eval/valtrees.rs index b771addb8df55..efd07f7186f77 100644 --- a/compiler/rustc_const_eval/src/const_eval/valtrees.rs +++ b/compiler/rustc_const_eval/src/const_eval/valtrees.rs @@ -90,7 +90,7 @@ fn const_to_valtree_inner<'tcx>( } match ty.kind() { - ty::FnDef(..) => { + ty::FnDef(..) | ty::FRT(..) => { *num_nodes += 1; Ok(ty::ValTree::zst(tcx)) } @@ -273,7 +273,7 @@ pub fn valtree_to_const_value<'tcx>( // create inner `MPlace`s which are filled recursively. // FIXME: Does this need an example? match *cv.ty.kind() { - ty::FnDef(..) => { + ty::FnDef(..) | ty::FRT(..) => { assert!(cv.valtree.is_zst()); mir::ConstValue::ZeroSized } diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index 2ea5e4a25c116..c2c2c4e6c7ccb 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -222,6 +222,27 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { self.write_scalar(Scalar::from_target_usize(offset, self), dest)?; } + sym::field_offset => { + let frt_ty = instance.args.type_at(0); + + let (ty, field) = match frt_ty.kind() { + &ty::FRT(ty, field) => (ty, field), + ty::Alias(..) | ty::Param(..) | ty::Placeholder(..) | ty::Infer(..) => { + // This can happen in code which is generic over the field type. + throw_inval!(TooGeneric) + } + _ => { + span_bug!(self.cur_span(), "expected field representing type, got {frt_ty}") + } + }; + let layout = self.layout_of(ty)?; + let cx = ty::layout::LayoutCx::new(*self.tcx, self.typing_env); + + let layout = layout.for_variant(&cx, field.variant); + let offset = layout.fields.offset(field.field.index()).bytes(); + + self.write_scalar(Scalar::from_target_usize(offset, self), dest)?; + } sym::vtable_for => { let tp_ty = instance.args.type_at(0); let result_ty = instance.args.type_at(1); @@ -300,6 +321,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { | ty::UnsafeBinder(_) | ty::Never | ty::Tuple(_) + | ty::FRT(..) | ty::Error(_) => ConstValue::from_target_usize(0u64, &tcx), }; let val = self.const_val_to_op(val, dest.layout.ty, Some(dest.layout))?; diff --git a/compiler/rustc_const_eval/src/interpret/stack.rs b/compiler/rustc_const_eval/src/interpret/stack.rs index 1c1c59da9d886..ba9c2c7c212ac 100644 --- a/compiler/rustc_const_eval/src/interpret/stack.rs +++ b/compiler/rustc_const_eval/src/interpret/stack.rs @@ -507,6 +507,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { | ty::Closure(..) | ty::CoroutineClosure(..) | ty::Never + | ty::FRT(..) | ty::Error(_) => true, ty::Str | ty::Slice(_) | ty::Dynamic(_, _) | ty::Foreign(..) => false, diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index 5d8ae42f5eccd..72f926eb69e08 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -785,6 +785,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { | ty::Dynamic(..) | ty::Closure(..) | ty::Pat(..) + | ty::FRT(..) | ty::CoroutineClosure(..) | ty::Coroutine(..) => interp_ok(false), // Some types only occur during typechecking, they have no layout. diff --git a/compiler/rustc_const_eval/src/util/type_name.rs b/compiler/rustc_const_eval/src/util/type_name.rs index db651811551f3..5564277ac5053 100644 --- a/compiler/rustc_const_eval/src/util/type_name.rs +++ b/compiler/rustc_const_eval/src/util/type_name.rs @@ -34,6 +34,7 @@ impl<'tcx> Printer<'tcx> for TypeNamePrinter<'tcx> { | ty::Float(_) | ty::Str | ty::Pat(_, _) + | ty::FRT(..) | ty::Array(_, _) | ty::Slice(_) | ty::RawPtr(_, _) diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index add09c3ea58b0..76c0c76822bb1 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -494,6 +494,8 @@ declare_features! ( (unstable, ffi_const, "1.45.0", Some(58328)), /// Allows the use of `#[ffi_pure]` on foreign functions. (unstable, ffi_pure, "1.45.0", Some(58329)), + /// Experimental field projections. + (incomplete, field_projections, "CURRENT_RUSTC_VERSION", Some(145383)), /// Controlling the behavior of fmt::Debug (unstable, fmt_debug, "1.82.0", Some(129709)), /// Allows using `#[align(...)]` on function items diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 68fc7653b6368..183d2a596e96e 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1737,6 +1737,12 @@ impl<'hir> Block<'hir> { } } +#[derive(Debug, Clone, Copy, HashStable_Generic)] +pub struct TyFieldPath { + pub variant: Option, + pub field: Ident, +} + #[derive(Debug, Clone, Copy, HashStable_Generic)] pub struct TyPat<'hir> { #[stable_hasher(ignore)] @@ -3800,6 +3806,10 @@ pub enum TyKind<'hir, Unambig = ()> { Err(rustc_span::ErrorGuaranteed), /// Pattern types (`pattern_type!(u32 is 1..)`) Pat(&'hir Ty<'hir>, &'hir TyPat<'hir>), + /// Field representing type (`field_of!(Struct, field)`). + /// + /// The optional ident is the variant when an enum is passed `field_of!(Enum, Variant.field)`. + FieldOf(&'hir Ty<'hir>, &'hir TyFieldPath), /// `TyKind::Infer` means the type should be inferred instead of it having been /// specified. This can appear anywhere in a type. /// diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 21bcf53b5619f..e29fdd284b385 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -1047,6 +1047,13 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty<'v, AmbigArg>) - try_visit!(visitor.visit_ty_unambig(ty)); try_visit!(visitor.visit_pattern_type_pattern(pat)); } + TyKind::FieldOf(ty, TyFieldPath { variant, field }) => { + try_visit!(visitor.visit_ty_unambig(ty)); + if let Some(variant) = *variant { + try_visit!(visitor.visit_ident(variant)); + } + try_visit!(visitor.visit_ident(*field)); + } } V::Result::output() } diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index 557f76208bfe6..9ccdf77f50269 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -448,6 +448,12 @@ language_item_table! { // Reborrowing related lang-items Reborrow, sym::reborrow, reborrow, Target::Trait, GenericRequirement::Exact(0); CoerceShared, sym::coerce_shared, coerce_shared, Target::Trait, GenericRequirement::Exact(0); + + // Field projection related lang-items + Field, sym::field, field, Target::Trait, GenericRequirement::Exact(0); + FieldBase, sym::field_base, field_base, Target::AssocTy, GenericRequirement::Exact(0); + FieldType, sym::field_type, field_type, Target::AssocTy, GenericRequirement::Exact(0); + FieldOffset, sym::field_offset, field_offset, Target::AssocConst, GenericRequirement::Exact(0); } /// The requirement imposed on the generics of a lang item diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index 22ee490b81a7b..3045714105d22 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -117,6 +117,7 @@ fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -> hi | sym::fabsf128 | sym::fadd_algebraic | sym::fdiv_algebraic + | sym::field_offset | sym::floorf16 | sym::floorf32 | sym::floorf64 @@ -296,6 +297,7 @@ pub(crate) fn check_intrinsic_type( (1, 0, vec![Ty::new_imm_ptr(tcx, param(0))], tcx.types.usize) } sym::offset_of => (1, 0, vec![tcx.types.u32, tcx.types.u32], tcx.types.usize), + sym::field_offset => (1, 0, vec![], tcx.types.usize), sym::rustc_peek => (1, 0, vec![param(0)], param(0)), sym::caller_location => (0, 0, vec![], tcx.caller_location_ty()), sym::assert_inhabited | sym::assert_zero_valid | sym::assert_mem_uninitialized_valid => { diff --git a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs index edaf33e493c04..fb4b6daa9babc 100644 --- a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs +++ b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs @@ -15,7 +15,7 @@ use rustc_hir::find_attr; use rustc_middle::bug; use rustc_middle::ty::fast_reject::{SimplifiedType, TreatParams, simplify_type}; use rustc_middle::ty::{self, CrateInherentImpls, Ty, TyCtxt}; -use rustc_span::ErrorGuaranteed; +use rustc_span::{ErrorGuaranteed, Span}; use crate::errors; @@ -110,7 +110,22 @@ impl<'tcx> InherentCollect<'tcx> { Ok(()) } else { let impl_span = self.tcx.def_span(impl_def_id); - Err(self.tcx.dcx().emit_err(errors::InherentTyOutsideNew { span: impl_span })) + let mut err = errors::InherentTyOutsideNew { span: impl_span, note: None }; + + if let hir::TyKind::Path(rustc_hir::QPath::Resolved(_, path)) = + self.tcx.hir_node_by_def_id(impl_def_id).expect_item().expect_impl().self_ty.kind + && let rustc_hir::def::Res::Def(DefKind::TyAlias, def_id) = path.res + { + let ty_name = self.tcx.def_path_str(def_id); + let alias_ty_name = self.tcx.type_of(def_id).skip_binder().to_string(); + err.note = Some(errors::InherentTyOutsideNewAliasNote { + span: self.tcx.def_span(def_id), + ty_name, + alias_ty_name, + }); + } + + Err(self.tcx.dcx().emit_err(err)) } } @@ -160,12 +175,16 @@ impl<'tcx> InherentCollect<'tcx> { let id = id.owner_id.def_id; let item_span = self.tcx.def_span(id); let self_ty = self.tcx.type_of(id).instantiate_identity(); - let mut self_ty = self.tcx.peel_off_free_alias_tys(self_ty); - // We allow impls on pattern types exactly when we allow impls on the base type. - // FIXME(pattern_types): Figure out the exact coherence rules we want here. - while let ty::Pat(base, _) = *self_ty.kind() { - self_ty = base; - } + let self_ty = self.tcx.peel_off_free_alias_tys(self_ty); + self.check_impl_self_ty(self_ty, id, item_span) + } + + fn check_impl_self_ty( + &mut self, + self_ty: Ty<'tcx>, + id: LocalDefId, + item_span: Span, + ) -> Result<(), ErrorGuaranteed> { match *self_ty.kind() { ty::Adt(def, _) => self.check_def_id(id, self_ty, def.did()), ty::Foreign(did) => self.check_def_id(id, self_ty, did), @@ -175,7 +194,10 @@ impl<'tcx> InherentCollect<'tcx> { ty::Dynamic(..) => { Err(self.tcx.dcx().emit_err(errors::InherentDyn { span: item_span })) } - ty::Pat(_, _) => unreachable!(), + // We allow impls on pattern types exactly when we allow impls on the base type. + // FIXME(pattern_types): Figure out the exact coherence rules we want here. + ty::Pat(base, _) => self.check_impl_self_ty(base, id, item_span), + ty::FRT(ty, _) => self.check_impl_self_ty(ty, id, item_span), ty::Bool | ty::Char | ty::Int(_) diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs index f1e138dbcb97a..fb22cd4974502 100644 --- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs +++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs @@ -150,6 +150,10 @@ pub(crate) fn orphan_check_impl( NonlocalImpl::DisallowBecauseNonlocal }, ), + ty::FRT(..) => ( + LocalImpl::Disallow { problematic_kind: "field representing type" }, + NonlocalImpl::DisallowOther, + ), // extern { type OpaqueType; } // impl AutoTrait for OpaqueType {} diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index 6a23b42ae0981..839379cd538b7 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -1223,11 +1223,27 @@ pub(crate) struct InherentTyOutsideRelevant { #[derive(Diagnostic)] #[diag("cannot define inherent `impl` for a type outside of the crate where the type is defined", code = E0116)] -#[note("define and implement a trait or new type instead")] +#[help( + "consider defining a trait and implementing it for the type or using a newtype wrapper like `struct MyType(ExternalType);` and implement it" +)] +#[note( + "for more details about the orphan rules, see " +)] pub(crate) struct InherentTyOutsideNew { #[primary_span] #[label("impl for type defined outside of crate")] pub span: Span, + #[subdiagnostic] + pub note: Option, +} + +#[derive(Subdiagnostic)] +#[note("`{$ty_name}` does not define a new type, only an alias of `{$alias_ty_name}` defined here")] +pub(crate) struct InherentTyOutsideNewAliasNote { + #[primary_span] + pub span: Span, + pub ty_name: String, + pub alias_ty_name: String, } #[derive(Diagnostic)] @@ -1420,6 +1436,15 @@ pub struct NoVariantNamed<'tcx> { pub ty: Ty<'tcx>, } +#[derive(Diagnostic)] +#[diag("no field `{$field}` on type `{$ty}`", code = E0609)] +pub struct NoFieldOnType<'tcx> { + #[primary_span] + pub span: Span, + pub ty: Ty<'tcx>, + pub field: Ident, +} + // FIXME(fmease): Deduplicate: #[derive(Diagnostic)] diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index 1578f098dd953..24284be3d3e3c 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -21,6 +21,7 @@ pub mod generics; use std::slice; +use rustc_abi::FIRST_VARIANT; use rustc_ast::LitKind; use rustc_data_structures::assert_matches; use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; @@ -38,7 +39,7 @@ use rustc_middle::middle::stability::AllowUnstable; use rustc_middle::mir::interpret::LitToConstInput; use rustc_middle::ty::print::PrintPolyTraitRefExt as _; use rustc_middle::ty::{ - self, Const, GenericArgKind, GenericArgsRef, GenericParamDefKind, Ty, TyCtxt, + self, Const, FieldId, GenericArgKind, GenericArgsRef, GenericParamDefKind, Ty, TyCtxt, TypeSuperFoldable, TypeVisitableExt, TypingMode, Upcast, fold_regions, }; use rustc_middle::{bug, span_bug}; @@ -51,11 +52,11 @@ use rustc_trait_selection::traits::{self, FulfillmentError}; use tracing::{debug, instrument}; use crate::check::check_abi; -use crate::check_c_variadic_abi; -use crate::errors::{AmbiguousLifetimeBound, BadReturnTypeNotation}; +use crate::errors::{AmbiguousLifetimeBound, BadReturnTypeNotation, NoFieldOnType}; use crate::hir_ty_lowering::errors::{GenericsArgsErrExtend, prohibit_assoc_item_constraint}; use crate::hir_ty_lowering::generics::{check_generic_arg_count, lower_generic_args}; use crate::middle::resolve_bound_vars as rbv; +use crate::{NoVariantNamed, check_c_variadic_abi}; /// The context in which an implied bound is being added to a item being lowered (i.e. a sizedness /// trait or a default trait) @@ -3028,6 +3029,14 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { self.record_ty(pat.hir_id, ty, pat.span); pat_ty } + hir::TyKind::FieldOf(ty, hir::TyFieldPath { variant, field }) => self.lower_field_of( + self.lower_ty(ty), + self.item_def_id(), + ty.span, + hir_ty.hir_id, + *variant, + *field, + ), hir::TyKind::Err(guar) => Ty::new_error(tcx, *guar), }; @@ -3069,6 +3078,168 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } } + fn lower_field_of( + &self, + ty: Ty<'tcx>, + item_def_id: LocalDefId, + ty_span: Span, + hir_id: HirId, + variant: Option, + field: Ident, + ) -> Ty<'tcx> { + let dcx = self.dcx(); + let tcx = self.tcx(); + match ty.kind() { + ty::Adt(def, _) => { + let base_did = def.did(); + let kind_name = tcx.def_descr(base_did); + let (variant_idx, variant) = if def.is_enum() { + let Some(variant) = variant else { + let err = dcx + .create_err(NoVariantNamed { span: field.span, ident: field, ty }) + .with_span_help( + field.span.shrink_to_lo(), + "you might be missing a variant here: `Variant.`", + ) + .emit(); + return Ty::new_error(tcx, err); + }; + + if let Some(res) = def + .variants() + .iter_enumerated() + .find(|(_, f)| f.ident(tcx).normalize_to_macros_2_0() == variant) + { + res + } else { + let err = dcx + .create_err(NoVariantNamed { span: variant.span, ident: variant, ty }) + .emit(); + return Ty::new_error(tcx, err); + } + } else { + if let Some(variant) = variant { + let adt_path = tcx.def_path_str(base_did); + struct_span_code_err!( + dcx, + variant.span, + E0609, + "{kind_name} `{adt_path}` does not have any variants", + ) + .with_span_label(variant.span, "variant unknown") + .emit(); + } + (FIRST_VARIANT, def.non_enum_variant()) + }; + let block = tcx.local_def_id_to_hir_id(item_def_id); + let (ident, def_scope) = tcx.adjust_ident_and_get_scope(field, def.did(), block); + if let Some((field_idx, field)) = variant + .fields + .iter_enumerated() + .find(|(_, f)| f.ident(tcx).normalize_to_macros_2_0() == ident) + { + if field.vis.is_accessible_from(def_scope, tcx) { + tcx.check_stability(field.did, Some(hir_id), ident.span, None); + } else { + let adt_path = tcx.def_path_str(base_did); + struct_span_code_err!( + dcx, + ident.span, + E0616, + "field `{ident}` of {kind_name} `{adt_path}` is private", + ) + .with_span_label(ident.span, "private field") + .emit(); + } + Ty::new_field_representing_type( + tcx, + ty, + FieldId { variant: variant_idx, field: field_idx }, + ) + } else { + let err = + dcx.create_err(NoFieldOnType { span: ident.span, field: ident, ty }).emit(); + Ty::new_error(tcx, err) + } + } + ty::Tuple(tys) => { + let index = match field.as_str().parse::() { + Ok(idx) => idx, + Err(_) => { + let err = + dcx.create_err(NoFieldOnType { span: field.span, field, ty }).emit(); + return Ty::new_error(tcx, err); + } + }; + if field.name != sym::integer(index) { + bug!("we parsed above, but now not equal?"); + } + if tys.get(index).is_some() { + Ty::new_field_representing_type( + tcx, + ty, + FieldId { variant: FIRST_VARIANT, field: index.into() }, + ) + } else { + let err = dcx.create_err(NoFieldOnType { span: field.span, field, ty }).emit(); + Ty::new_error(tcx, err) + } + } + // FIXME(FRTs): support type aliases + /* + ty::Alias(AliasTyKind::Free, ty) => { + return self.lower_field_of( + ty, + item_def_id, + ty_span, + hir_id, + variant, + field, + ); + }*/ + ty::Alias(..) => Ty::new_error( + tcx, + dcx.span_err(ty_span, format!("could not resolve fields of `{ty}`")), + ), + ty::Error(err) => Ty::new_error(tcx, *err), + ty::Bool + | ty::Char + | ty::Int(_) + | ty::Uint(_) + | ty::Float(_) + | ty::Foreign(_) + | ty::Str + | ty::FRT(_, _) + | ty::RawPtr(_, _) + | ty::Ref(_, _, _) + | ty::FnDef(_, _) + | ty::FnPtr(_, _) + | ty::UnsafeBinder(_) + | ty::Dynamic(_, _) + | ty::Closure(_, _) + | ty::CoroutineClosure(_, _) + | ty::Coroutine(_, _) + | ty::CoroutineWitness(_, _) + | ty::Never + | ty::Param(_) + | ty::Bound(_, _) + | ty::Placeholder(_) + | ty::Slice(..) => Ty::new_error( + tcx, + dcx.span_err(ty_span, format!("type `{ty}` doesn't have fields")), + ), + ty::Infer(_) => Ty::new_error( + tcx, + dcx.span_err(ty_span, format!("cannot use `{ty}` in this position")), + ), + // FIXME(FRTs): support these types? + ty::Array(..) | ty::Pat(..) => Ty::new_error( + tcx, + dcx.span_err(ty_span, format!("type `{ty}` is not yet supported in `field_of!`")), + ), + } + } + /// Lower an opaque type (i.e., an existential impl-Trait type) from the HIR. #[instrument(level = "debug", skip(self), ret)] fn lower_opaque_ty(&self, def_id: LocalDefId, in_trait: Option) -> Ty<'tcx> { diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index 6214106d422b5..925a4982e8333 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -83,7 +83,7 @@ mod impl_wf_check; mod outlives; mod variance; -pub use errors::NoVariantNamed; +pub use errors::{NoFieldOnType, NoVariantNamed}; use rustc_abi::{CVariadicStatus, ExternAbi}; use rustc_hir as hir; use rustc_hir::def::DefKind; diff --git a/compiler/rustc_hir_analysis/src/variance/constraints.rs b/compiler/rustc_hir_analysis/src/variance/constraints.rs index ce4668736b570..011a3f1dc2166 100644 --- a/compiler/rustc_hir_analysis/src/variance/constraints.rs +++ b/compiler/rustc_hir_analysis/src/variance/constraints.rs @@ -255,6 +255,10 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { self.add_constraints_from_ty(current, typ, variance); } + ty::FRT(ty, _) => { + self.add_constraints_from_ty(current, ty, variance); + } + ty::Slice(typ) => { self.add_constraints_from_ty(current, typ, variance); } diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index fc6cc4e672517..ec0688b64f3dd 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -19,7 +19,7 @@ use rustc_hir::attrs::{AttributeKind, PrintAttribute}; use rustc_hir::{ BindingMode, ByRef, ConstArg, ConstArgExprField, ConstArgKind, GenericArg, GenericBound, GenericParam, GenericParamKind, HirId, ImplicitSelfKind, LifetimeParamKind, Node, PatKind, - PreciseCapturingArg, RangeEnd, Term, TyPatKind, + PreciseCapturingArg, RangeEnd, Term, TyFieldPath, TyPatKind, }; use rustc_span::source_map::{SourceMap, Spanned}; use rustc_span::{DUMMY_SP, FileName, Ident, Span, Symbol, kw, sym}; @@ -464,6 +464,17 @@ impl<'a> State<'a> { self.word(" is "); self.print_ty_pat(pat); } + hir::TyKind::FieldOf(ty, TyFieldPath { variant, field }) => { + self.word("field_of!("); + self.print_type(ty); + self.word(", "); + if let Some(variant) = *variant { + self.print_ident(variant); + self.word("."); + } + self.print_ident(*field); + self.word(")"); + } } self.end(ib) } diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs index 3f13a102684e0..d6964f4e8d2d7 100644 --- a/compiler/rustc_hir_typeck/src/cast.rs +++ b/compiler/rustc_hir_typeck/src/cast.rs @@ -137,6 +137,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { | ty::RawPtr(_, _) | ty::Ref(..) | ty::Pat(..) + | ty::FRT(..) | ty::FnDef(..) | ty::FnPtr(..) | ty::Closure(..) @@ -572,6 +573,17 @@ impl<'a, 'tcx> CastCheck<'tcx> { let metadata = known_metadata.unwrap_or("type-specific metadata"); let known_wide = known_metadata.is_some(); let span = self.cast_span; + let param_note = (!known_wide) + .then(|| match cast_ty.kind() { + ty::RawPtr(pointee, _) => match pointee.kind() { + ty::Param(param) => { + Some(errors::IntToWideParamNote { param: param.name }) + } + _ => None, + }, + _ => None, + }) + .flatten(); fcx.dcx().emit_err(errors::IntToWide { span, metadata, @@ -579,6 +591,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { cast_ty, expr_if_nightly, known_wide, + param_note, }); } CastError::UnknownCastPtrKind | CastError::UnknownExprPtrKind => { diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs index a5de1014dd7a3..54df596dd9bac 100644 --- a/compiler/rustc_hir_typeck/src/errors.rs +++ b/compiler/rustc_hir_typeck/src/errors.rs @@ -494,15 +494,6 @@ impl HelpUseLatestEdition { } } -#[derive(Diagnostic)] -#[diag("no field `{$field}` on type `{$ty}`", code = E0609)] -pub(crate) struct NoFieldOnType<'tcx> { - #[primary_span] - pub(crate) span: Span, - pub(crate) ty: Ty<'tcx>, - pub(crate) field: Ident, -} - #[derive(Diagnostic)] #[diag("no field named `{$field}` on enum variant `{$container}::{$ident}`", code = E0609)] pub(crate) struct NoFieldOnVariant<'tcx> { @@ -590,6 +581,14 @@ pub(crate) struct IntToWide<'tcx> { )] pub expr_if_nightly: Option, pub known_wide: bool, + #[subdiagnostic] + pub param_note: Option, +} + +#[derive(Subdiagnostic)] +#[note("the type parameter `{$param}` is not known to be `Sized`, so this pointer may be wide")] +pub(crate) struct IntToWideParamNote { + pub param: Symbol, } #[derive(Subdiagnostic)] diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 5b40531f94627..ac2af89c518b1 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -20,8 +20,8 @@ use rustc_hir::def::{CtorKind, DefKind, Res}; use rustc_hir::def_id::DefId; use rustc_hir::lang_items::LangItem; use rustc_hir::{ExprKind, HirId, QPath, find_attr, is_range_literal}; -use rustc_hir_analysis::NoVariantNamed; use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer as _; +use rustc_hir_analysis::{NoFieldOnType, NoVariantNamed}; use rustc_infer::infer::{self, DefineOpaqueTypes, InferOk, RegionVariableOrigin}; use rustc_infer::traits::query::NoSolution; use rustc_middle::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase}; @@ -44,7 +44,7 @@ use crate::coercion::CoerceMany; use crate::errors::{ AddressOfTemporaryTaken, BaseExpressionDoubleDot, BaseExpressionDoubleDotAddExpr, BaseExpressionDoubleDotRemove, CantDereference, FieldMultiplySpecifiedInInitializer, - FunctionalRecordUpdateOnNonStruct, HelpUseLatestEdition, NakedAsmOutsideNakedFn, NoFieldOnType, + FunctionalRecordUpdateOnNonStruct, HelpUseLatestEdition, NakedAsmOutsideNakedFn, NoFieldOnVariant, ReturnLikeStatementKind, ReturnStmtOutsideOfFnBody, StructExprNonExhaustive, TypeMismatchFruTypo, YieldExprOutsideOfCoroutine, }; diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs index 89ea6324d8543..53d81d1a259e2 100644 --- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs +++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs @@ -420,6 +420,7 @@ impl<'cx, 'tcx> TypeFolder> for Canonicalizer<'cx, 'tcx> { | ty::Alias(..) | ty::Foreign(..) | ty::Pat(..) + | ty::FRT(..) | ty::Param(..) => { if t.flags().intersects(self.needs_canonical_flags) { t.super_fold_with(self) diff --git a/compiler/rustc_lint/src/early/diagnostics.rs b/compiler/rustc_lint/src/early/diagnostics.rs index 7681eedc75ed0..3da2b1bf4069e 100644 --- a/compiler/rustc_lint/src/early/diagnostics.rs +++ b/compiler/rustc_lint/src/early/diagnostics.rs @@ -383,6 +383,10 @@ pub fn decorate_attribute_lint( lints::DocAutoCfgExpectsHideOrShow.decorate_lint(diag) } + &AttributeLintKind::AmbiguousDeriveHelpers => { + lints::AmbiguousDeriveHelpers.decorate_lint(diag) + } + &AttributeLintKind::DocAutoCfgHideShowUnexpectedItem { attr_name } => { lints::DocAutoCfgHideShowUnexpectedItem { attr_name }.decorate_lint(diag) } diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 0aa5199cffc6e..206a46d5416c7 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -3752,6 +3752,10 @@ pub(crate) struct DocAliasDuplicated { #[diag("only `hide` or `show` are allowed in `#[doc(auto_cfg(...))]`")] pub(crate) struct DocAutoCfgExpectsHideOrShow; +#[derive(LintDiagnostic)] +#[diag("there exists a built-in attribute with the same name")] +pub(crate) struct AmbiguousDeriveHelpers; + #[derive(LintDiagnostic)] #[diag("`#![doc(auto_cfg({$attr_name}(...)))]` only accepts identifiers or key/value items")] pub(crate) struct DocAutoCfgHideShowUnexpectedItem { diff --git a/compiler/rustc_lint/src/types/improper_ctypes.rs b/compiler/rustc_lint/src/types/improper_ctypes.rs index fb9b55efa2204..c8d84f0a411d0 100644 --- a/compiler/rustc_lint/src/types/improper_ctypes.rs +++ b/compiler/rustc_lint/src/types/improper_ctypes.rs @@ -594,6 +594,12 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { // but only the base type is relevant for being representable in FFI. ty::Pat(base, ..) => self.visit_type(state, base), + ty::FRT(..) => FfiUnsafe { + ty, + reason: inline_fluent!("field representing types have no C equivalent"), + help: None, + }, + // Primitive types with a stable representation. ty::Bool | ty::Int(..) | ty::Uint(..) | ty::Float(..) | ty::Never => FfiSafe, diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 488e3a70b6695..9e80ddbd551f9 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -17,6 +17,7 @@ declare_lint_pass! { AARCH64_SOFTFLOAT_NEON, ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE, AMBIGUOUS_ASSOCIATED_ITEMS, + AMBIGUOUS_DERIVE_HELPERS, AMBIGUOUS_GLOB_IMPORTED_TRAITS, AMBIGUOUS_GLOB_IMPORTS, AMBIGUOUS_GLOB_REEXPORTS, @@ -4267,6 +4268,75 @@ declare_lint! { }; } +declare_lint! { + /// The `ambiguous_derive_helpers` lint detects cases where a derive macro's helper attribute + /// is the same name as that of a built-in attribute. + /// + /// ### Example + /// + /// ```rust,ignore (proc-macro) + /// #![crate_type = "proc-macro"] + /// #![deny(ambiguous_derive_helpers)] + /// + /// use proc_macro::TokenStream; + /// + /// #[proc_macro_derive(Trait, attributes(ignore))] + /// pub fn example(input: TokenStream) -> TokenStream { + /// TokenStream::new() + /// } + /// ``` + /// + /// Produces: + /// + /// ```text + /// warning: there exists a built-in attribute with the same name + /// --> file.rs:5:39 + /// | + /// 5 | #[proc_macro_derive(Trait, attributes(ignore))] + /// | ^^^^^^ + /// | + /// = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + /// = note: for more information, see issue #151152 + /// = note: `#[deny(ambiguous_derive_helpers)]` (part of `#[deny(future_incompatible)]`) on by default + /// ``` + /// + /// ### Explanation + /// + /// Attempting to use this helper attribute will throw an error: + /// + /// ```rust,ignore (needs-dependency) + /// #[derive(Trait)] + /// struct Example { + /// #[ignore] + /// fields: () + /// } + /// ``` + /// + /// Produces: + /// + /// ```text + /// error[E0659]: `ignore` is ambiguous + /// --> src/lib.rs:5:7 + /// | + /// 5 | #[ignore] + /// | ^^^^^^ ambiguous name + /// | + /// = note: ambiguous because of a name conflict with a builtin attribute + /// = note: `ignore` could refer to a built-in attribute + /// note: `ignore` could also refer to the derive helper attribute defined here + /// --> src/lib.rs:3:10 + /// | + /// 3 | #[derive(Trait)] + /// | ^^^^^ + /// ``` + pub AMBIGUOUS_DERIVE_HELPERS, + Warn, + "detects derive helper attributes that are ambiguous with built-in attributes", + @future_incompatible = FutureIncompatibleInfo { + reason: fcw!(FutureReleaseError #151276), + }; +} + declare_lint! { /// The `private_interfaces` lint detects types in a primary interface of an item, /// that are more private than the item itself. Primary interface of an item is all diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index 0c454ec60f4a6..a1b8b135819a0 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -800,6 +800,7 @@ pub enum AttributeLintKind { attr_name: Symbol, }, DocInvalid, + AmbiguousDeriveHelpers, DocUnknownInclude { span: Span, inner: &'static str, diff --git a/compiler/rustc_middle/Cargo.toml b/compiler/rustc_middle/Cargo.toml index f9d5e7c027894..09c5417f39787 100644 --- a/compiler/rustc_middle/Cargo.toml +++ b/compiler/rustc_middle/Cargo.toml @@ -32,6 +32,7 @@ rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } rustc_thread_pool = { path = "../rustc_thread_pool" } rustc_type_ir = { path = "../rustc_type_ir" } +serde = { version = "1.0.125", features = ["derive"] } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } thin-vec = "0.2.12" tracing = "0.1" diff --git a/compiler/rustc_middle/src/query/plumbing.rs b/compiler/rustc_middle/src/query/plumbing.rs index b80f096ec9935..3c844eac1fca0 100644 --- a/compiler/rustc_middle/src/query/plumbing.rs +++ b/compiler/rustc_middle/src/query/plumbing.rs @@ -49,8 +49,21 @@ pub struct QueryVTable<'tcx, C: QueryCache> { // Offset of this query's cache field in the QueryCaches struct pub query_cache: usize, pub will_cache_on_disk_for_key_fn: Option>, - pub execute_query: fn(tcx: TyCtxt<'tcx>, k: C::Key) -> C::Value, - pub compute_fn: fn(tcx: TyCtxt<'tcx>, key: C::Key) -> C::Value, + + /// Function pointer that calls `tcx.$query(key)` for this query and + /// discards the returned value. + /// + /// This is a weird thing to be doing, and probably not what you want. + /// It is used for loading query results from disk-cache in some cases. + pub call_query_method_fn: fn(tcx: TyCtxt<'tcx>, key: C::Key), + + /// Function pointer that actually calls this query's provider. + /// Also performs some associated secondary tasks; see the macro-defined + /// implementation in `mod invoke_provider_fn` for more details. + /// + /// This should be the only code that calls the provider function. + pub invoke_provider_fn: fn(tcx: TyCtxt<'tcx>, key: C::Key) -> C::Value, + pub try_load_from_disk_fn: Option>, pub is_loadable_from_disk_fn: Option>, pub hash_result: HashResult, diff --git a/compiler/rustc_middle/src/ty/adt.rs b/compiler/rustc_middle/src/ty/adt.rs index 510c546f82a4e..7f2019e16a227 100644 --- a/compiler/rustc_middle/src/ty/adt.rs +++ b/compiler/rustc_middle/src/ty/adt.rs @@ -3,7 +3,7 @@ use std::hash::{Hash, Hasher}; use std::ops::Range; use std::str; -use rustc_abi::{FIRST_VARIANT, ReprOptions, VariantIdx}; +use rustc_abi::{FIRST_VARIANT, FieldIdx, ReprOptions, VariantIdx}; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::intern::Interned; @@ -14,7 +14,7 @@ use rustc_hir::def::{CtorKind, DefKind, Res}; use rustc_hir::def_id::DefId; use rustc_hir::{self as hir, LangItem, find_attr}; use rustc_index::{IndexSlice, IndexVec}; -use rustc_macros::{HashStable, TyDecodable, TyEncodable}; +use rustc_macros::{Decodable, Encodable, HashStable, TyDecodable, TyEncodable}; use rustc_query_system::ich::StableHashingContext; use rustc_session::DataTypeKind; use rustc_type_ir::solve::AdtDestructorKind; @@ -212,6 +212,10 @@ impl<'tcx> rustc_type_ir::inherent::AdtDef> for AdtDef<'tcx> { self.is_struct() } + fn is_packed(self) -> bool { + self.repr().packed() + } + fn struct_tail_ty(self, interner: TyCtxt<'tcx>) -> Option>> { Some(interner.type_of(self.non_enum_variant().tail_opt()?.did)) } @@ -681,3 +685,69 @@ pub enum Representability { Representable, Infinite(ErrorGuaranteed), } + +#[derive( + Copy, + Clone, + PartialEq, + Eq, + Hash, + Debug, + Encodable, + Decodable, + HashStable, + serde::Serialize +)] +#[rustc_pass_by_value] +pub struct FieldId { + pub variant: VariantIdx, + pub field: FieldIdx, +} + +impl FieldId { + pub fn ty<'tcx>(self, tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> { + match ty.kind() { + ty::Adt(def, args) => def.variants()[self.variant].fields[self.field].ty(tcx, args), + ty::Tuple(tys) => { + debug_assert_eq!(FIRST_VARIANT, self.variant); + tys[self.field.index()] + } + ty::Bool + | ty::Char + | ty::Int(_) + | ty::Uint(_) + | ty::Float(_) + | ty::Foreign(_) + | ty::Str + | ty::FRT(_, _) + | ty::RawPtr(_, _) + | ty::Ref(_, _, _) + | ty::FnDef(_, _) + | ty::FnPtr(_, _) + | ty::UnsafeBinder(_) + | ty::Dynamic(_, _) + | ty::Closure(_, _) + | ty::CoroutineClosure(_, _) + | ty::Coroutine(_, _) + | ty::CoroutineWitness(_, _) + | ty::Never + | ty::Param(_) + | ty::Bound(_, _) + | ty::Placeholder(_) + | ty::Infer(_) + | ty::Array(..) + | ty::Pat(..) + | ty::Slice(..) + | ty::Error(_) + | ty::Alias(..) => bug!( + "don't expect to see this TyKind here, should be handled by lowering hir to mir" + ), + } + } +} + +impl<'tcx> rustc_type_ir::inherent::FieldId> for FieldId { + fn ty(self, tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> { + FieldId::ty(self, tcx, ty) + } +} diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index f638dd80864cb..022a8d5f8a87a 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -1867,6 +1867,7 @@ impl<'tcx> TyCtxt<'tcx> { Infer, Alias, Pat, + FRT, Foreign )?; diff --git a/compiler/rustc_middle/src/ty/context/impl_interner.rs b/compiler/rustc_middle/src/ty/context/impl_interner.rs index 5a15d132048dd..4ad6fb9f0266c 100644 --- a/compiler/rustc_middle/src/ty/context/impl_interner.rs +++ b/compiler/rustc_middle/src/ty/context/impl_interner.rs @@ -21,8 +21,8 @@ use crate::traits::solve::{ self, CanonicalInput, ExternalConstraints, ExternalConstraintsData, QueryResult, inspect, }; use crate::ty::{ - self, Clause, Const, List, ParamTy, Pattern, PolyExistentialPredicate, Predicate, Region, Ty, - TyCtxt, + self, Clause, Const, FieldId, List, ParamTy, Pattern, PolyExistentialPredicate, Predicate, + Region, Ty, TyCtxt, }; #[allow(rustc::usage_of_ty_tykind)] @@ -188,6 +188,8 @@ impl<'tcx> Interner for TyCtxt<'tcx> { self.adt_def(adt_def_id) } + type FieldId = FieldId; + fn alias_ty_kind(self, alias: ty::AliasTy<'tcx>) -> ty::AliasTyKind { match self.def_kind(alias.def_id) { DefKind::AssocTy => { @@ -514,6 +516,7 @@ impl<'tcx> Interner for TyCtxt<'tcx> { | ty::Str | ty::Array(_, _) | ty::Pat(_, _) + | ty::FRT(..) | ty::Slice(_) | ty::RawPtr(_, _) | ty::Ref(_, _, _) @@ -755,6 +758,8 @@ bidirectional_lang_item_map! { CoroutineReturn, CoroutineYield, DynMetadata, + FieldBase, + FieldType, FutureOutput, Metadata, // tidy-alphabetical-end @@ -786,6 +791,7 @@ bidirectional_lang_item_map! { Destruct, DiscriminantKind, Drop, + Field, Fn, FnMut, FnOnce, diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs index 66542525d2841..03784b2420f67 100644 --- a/compiler/rustc_middle/src/ty/error.rs +++ b/compiler/rustc_middle/src/ty/error.rs @@ -186,6 +186,7 @@ impl<'tcx> Ty<'tcx> { ty::Foreign(_) => "extern type".into(), ty::Array(..) => "array".into(), ty::Pat(..) => "pattern type".into(), + ty::FRT(..) => "field representing type".into(), ty::Slice(_) => "slice".into(), ty::RawPtr(_, _) => "raw pointer".into(), ty::Ref(.., mutbl) => match mutbl { diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index d3b4654a8d799..17c500fabd585 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -847,6 +847,7 @@ where | ty::Uint(_) | ty::Float(_) | ty::FnPtr(..) + | ty::FRT(..) | ty::Never | ty::FnDef(..) | ty::CoroutineWitness(..) diff --git a/compiler/rustc_middle/src/ty/offload_meta.rs b/compiler/rustc_middle/src/ty/offload_meta.rs index 67c00765ed57b..83a82b6d3a7bb 100644 --- a/compiler/rustc_middle/src/ty/offload_meta.rs +++ b/compiler/rustc_middle/src/ty/offload_meta.rs @@ -82,9 +82,12 @@ impl MappingFlags { MappingFlags::LITERAL | MappingFlags::IMPLICIT } - ty::Adt(_, _) | ty::Tuple(_) | ty::Array(_, _) | ty::Alias(_, _) | ty::Param(_) => { - MappingFlags::TO - } + ty::Adt(_, _) + | ty::FRT(..) + | ty::Tuple(_) + | ty::Array(_, _) + | ty::Alias(_, _) + | ty::Param(_) => MappingFlags::TO, ty::RawPtr(_, Not) | ty::Ref(_, _, Not) => MappingFlags::TO, diff --git a/compiler/rustc_middle/src/ty/print/mod.rs b/compiler/rustc_middle/src/ty/print/mod.rs index 0fd68e74e0441..456447a342d11 100644 --- a/compiler/rustc_middle/src/ty/print/mod.rs +++ b/compiler/rustc_middle/src/ty/print/mod.rs @@ -296,6 +296,8 @@ fn characteristic_def_id_of_type_cached<'a>( characteristic_def_id_of_type_cached(subty, visited) } + ty::FRT(ty, _) => characteristic_def_id_of_type_cached(ty, visited), + ty::RawPtr(ty, _) => characteristic_def_id_of_type_cached(ty, visited), ty::Ref(_, ty, _) => characteristic_def_id_of_type_cached(ty, visited), diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 02b804c1ab29c..af289081e42cb 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -3,7 +3,7 @@ use std::fmt::{self, Write as _}; use std::iter; use std::ops::{Deref, DerefMut}; -use rustc_abi::{ExternAbi, Size}; +use rustc_abi::{ExternAbi, FIRST_VARIANT, Size}; use rustc_apfloat::Float; use rustc_apfloat::ieee::{Double, Half, Quad, Single}; use rustc_data_structures::fx::{FxIndexMap, IndexEntry}; @@ -721,6 +721,29 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { ty.print(self)?; write!(self, ") is {pat:?}")?; } + ty::FRT(ty, field) => { + write!(self, "field_of!(")?; + ty.print(self)?; + write!(self, ", ")?; + match ty.kind() { + ty::Adt(def, _) => { + let variant = if def.is_enum() { + let variant = &def.variants()[field.variant]; + write!(self, "{}.", variant.name)?; + variant + } else { + def.non_enum_variant() + }; + write!(self, "{}", variant.fields[field.field].name)?; + } + ty::Tuple(_) => { + debug_assert_eq!(field.variant, FIRST_VARIANT); + write!(self, "{}", field.field.index())?; + } + _ => bug!("unexpected ty in resolved FRT: {ty}"), + } + write!(self, ")")?; + } ty::RawPtr(ty, mutbl) => { write!(self, "*{} ", mutbl.ptr_str())?; ty.print(self)?; diff --git a/compiler/rustc_middle/src/ty/significant_drop_order.rs b/compiler/rustc_middle/src/ty/significant_drop_order.rs index f1aa7076d98ac..b7cdb26c7d117 100644 --- a/compiler/rustc_middle/src/ty/significant_drop_order.rs +++ b/compiler/rustc_middle/src/ty/significant_drop_order.rs @@ -136,6 +136,7 @@ pub fn ty_dtor_span<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Option { | ty::Alias(_, _) | ty::Bound(_, _) | ty::Pat(_, _) + | ty::FRT(_, _) | ty::Placeholder(_) | ty::Infer(_) | ty::Slice(_) diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 8707b03e4b8f2..693a646c90571 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -376,6 +376,7 @@ impl<'tcx> TypeSuperFoldable> for Ty<'tcx> { } ty::Alias(kind, data) => ty::Alias(kind, data.try_fold_with(folder)?), ty::Pat(ty, pat) => ty::Pat(ty.try_fold_with(folder)?, pat.try_fold_with(folder)?), + ty::FRT(ty, field) => ty::FRT(ty.try_fold_with(folder)?, field), ty::Bool | ty::Char @@ -415,6 +416,7 @@ impl<'tcx> TypeSuperFoldable> for Ty<'tcx> { ty::CoroutineClosure(did, args) => ty::CoroutineClosure(did, args.fold_with(folder)), ty::Alias(kind, data) => ty::Alias(kind, data.fold_with(folder)), ty::Pat(ty, pat) => ty::Pat(ty.fold_with(folder), pat.fold_with(folder)), + ty::FRT(ty, field) => ty::FRT(ty.fold_with(folder), field), ty::Bool | ty::Char @@ -467,6 +469,7 @@ impl<'tcx> TypeSuperVisitable> for Ty<'tcx> { try_visit!(ty.visit_with(visitor)); pat.visit_with(visitor) } + ty::FRT(ty, _field) => ty.visit_with(visitor), ty::Error(guar) => guar.visit_with(visitor), diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 4be30d8b6c918..ddf79fbeb4c25 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -26,8 +26,8 @@ use crate::infer::canonical::Canonical; use crate::traits::ObligationCause; use crate::ty::InferTy::*; use crate::ty::{ - self, AdtDef, Discr, GenericArg, GenericArgs, GenericArgsRef, List, ParamEnv, Region, Ty, - TyCtxt, TypeFlags, TypeSuperVisitable, TypeVisitable, TypeVisitor, UintTy, + self, AdtDef, Discr, FieldId, GenericArg, GenericArgs, GenericArgsRef, List, ParamEnv, Region, + Ty, TyCtxt, TypeFlags, TypeSuperVisitable, TypeVisitable, TypeVisitor, UintTy, }; // Re-export and re-parameterize some `I = TyCtxt<'tcx>` types here @@ -487,6 +487,15 @@ impl<'tcx> Ty<'tcx> { Ty::new(tcx, Pat(base, pat)) } + #[inline] + pub fn new_field_representing_type( + tcx: TyCtxt<'tcx>, + ty: Ty<'tcx>, + field_id: FieldId, + ) -> Ty<'tcx> { + Ty::new(tcx, FRT(ty, field_id)) + } + #[inline] #[instrument(level = "debug", skip(tcx))] pub fn new_opaque(tcx: TyCtxt<'tcx>, def_id: DefId, args: GenericArgsRef<'tcx>) -> Ty<'tcx> { @@ -1063,6 +1072,10 @@ impl<'tcx> rustc_type_ir::inherent::Ty> for Ty<'tcx> { Ty::new_pat(interner, ty, pat) } + fn new_field_representing_type(tcx: TyCtxt<'tcx>, ty: Self, field_id: FieldId) -> Self { + Self::new_field_representing_type(tcx, ty, field_id) + } + fn new_unsafe_binder(interner: TyCtxt<'tcx>, ty: ty::Binder<'tcx, Ty<'tcx>>) -> Self { Ty::new_unsafe_binder(interner, ty) } @@ -1082,6 +1095,10 @@ impl<'tcx> rustc_type_ir::inherent::Ty> for Ty<'tcx> { fn has_unsafe_fields(self) -> bool { Ty::has_unsafe_fields(self) } + + fn is_packed(self) -> bool { + Ty::is_packed(self) + } } /// Type utilities @@ -1136,6 +1153,11 @@ impl<'tcx> Ty<'tcx> { matches!(self.kind(), Adt(..)) } + #[inline] + pub fn is_packed(self) -> bool { + matches!(self.kind(), Adt(def, _) if def.repr().packed()) + } + #[inline] pub fn is_ref(self) -> bool { matches!(self.kind(), Ref(..)) @@ -1629,6 +1651,7 @@ impl<'tcx> Ty<'tcx> { | ty::Uint(_) | ty::Float(_) | ty::Adt(..) + | ty::FRT(..) | ty::Foreign(_) | ty::Str | ty::Array(..) @@ -1680,6 +1703,7 @@ impl<'tcx> Ty<'tcx> { | ty::Array(..) | ty::Closure(..) | ty::CoroutineClosure(..) + | ty::FRT(..) | ty::Never | ty::Error(_) // Extern types have metadata = (). @@ -1870,6 +1894,7 @@ impl<'tcx> Ty<'tcx> { | ty::CoroutineWitness(..) | ty::Array(..) | ty::Pat(..) + | ty::FRT(..) | ty::Closure(..) | ty::CoroutineClosure(..) | ty::Never @@ -1923,6 +1948,9 @@ impl<'tcx> Ty<'tcx> { // ZST which can't be named are fine. ty::FnDef(..) => true, + // ZST. + ty::FRT(..) => true, + ty::Array(element_ty, _len) => element_ty.is_trivially_pure_clone_copy(), // A 100-tuple isn't "trivial", so doing this only for reasonable sizes. @@ -1993,6 +2021,7 @@ impl<'tcx> Ty<'tcx> { | ty::Array(..) | ty::Foreign(_) | ty::Pat(_, _) + | ty::FRT(..) | ty::FnDef(..) | ty::UnsafeBinder(..) | ty::Dynamic(..) diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index e01a5721a5e03..ae3631ea1717d 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -1166,6 +1166,7 @@ impl<'tcx> Ty<'tcx> { | ty::Char | ty::Str | ty::Never + | ty::FRT(..) | ty::Ref(..) | ty::RawPtr(_, _) | ty::FnDef(..) @@ -1207,6 +1208,7 @@ impl<'tcx> Ty<'tcx> { | ty::Char | ty::Str | ty::Never + | ty::FRT(..) | ty::Ref(..) | ty::RawPtr(_, _) | ty::FnDef(..) @@ -1258,6 +1260,7 @@ impl<'tcx> Ty<'tcx> { | ty::Char | ty::Str | ty::Never + | ty::FRT(..) | ty::Ref(..) | ty::RawPtr(..) | ty::FnDef(..) @@ -1429,6 +1432,9 @@ impl<'tcx> Ty<'tcx> { // Raw pointers use bitwise comparison. ty::RawPtr(_, _) | ty::FnPtr(..) => true, + // FRTs are ZSTs. + ty::FRT(..) => true, + // Floating point numbers are not `Eq`. ty::Float(_) => false, @@ -1508,6 +1514,7 @@ pub fn needs_drop_components_with_async<'tcx>( | ty::Uint(_) | ty::Float(_) | ty::Never + | ty::FRT(..) | ty::FnDef(..) | ty::FnPtr(..) | ty::Char diff --git a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs index ced9bd735ba2b..0790d26e9ed91 100644 --- a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs +++ b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs @@ -154,6 +154,7 @@ impl<'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> MoveDataBuilder<'a, 'tcx, F> { | ty::Str | ty::Array(_, _) | ty::Pat(_, _) + | ty::FRT(..) | ty::Slice(_) | ty::FnDef(_, _) | ty::FnPtr(..) @@ -196,6 +197,7 @@ impl<'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> MoveDataBuilder<'a, 'tcx, F> { | ty::Str | ty::Array(_, _) | ty::Pat(_, _) + | ty::FRT(..) | ty::Slice(_) | ty::RawPtr(_, _) | ty::Ref(_, _, _) diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs index 604f1da1a3abb..5bbace972eefb 100644 --- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs +++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs @@ -867,7 +867,7 @@ fn try_write_constant<'tcx>( match ty.kind() { // ZSTs. Nothing to do. - ty::FnDef(..) => {} + ty::FnDef(..) | ty::FRT(..) => {} // Those are scalars, must be handled above. ty::Bool | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Char => diff --git a/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs b/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs index ce2be24adc586..312d41dc6deca 100644 --- a/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs +++ b/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs @@ -381,6 +381,7 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { | ty::RawPtr(_, _) | ty::Ref(_, _, _) | ty::Pat(_, _) + | ty::FRT(_, _) | ty::FnDef(_, _) | ty::FnPtr(..) | ty::UnsafeBinder(_) diff --git a/compiler/rustc_next_trait_solver/src/coherence.rs b/compiler/rustc_next_trait_solver/src/coherence.rs index c370fd24a1bb3..4e99d8de6ea65 100644 --- a/compiler/rustc_next_trait_solver/src/coherence.rs +++ b/compiler/rustc_next_trait_solver/src/coherence.rs @@ -408,6 +408,7 @@ where // For fundamental types, we just look inside of them. ty::Ref(_, ty, _) => ty.visit_with(self), + ty::FRT(ty, _) => ty.visit_with(self), ty::Adt(def, args) => { if self.def_id_is_local(def.def_id()) { ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty)) diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs index 63f246db8a5fb..885f60956402a 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs @@ -348,6 +348,11 @@ where ecx: &mut EvalCtxt<'_, D>, goal: Goal, ) -> Vec>; + + fn consider_builtin_field_candidate( + ecx: &mut EvalCtxt<'_, D>, + goal: Goal, + ) -> Result, NoSolution>; } /// Allows callers of `assemble_and_evaluate_candidates` to choose whether to limit @@ -617,6 +622,7 @@ where Some(SolverTraitLangItem::BikeshedGuaranteedNoDrop) => { G::consider_builtin_bikeshed_guaranteed_no_drop_candidate(self, goal) } + Some(SolverTraitLangItem::Field) => G::consider_builtin_field_candidate(self, goal), _ => Err(NoSolution), } }; @@ -690,6 +696,7 @@ where | ty::Str | ty::Array(_, _) | ty::Pat(_, _) + | ty::FRT(_, _) | ty::Slice(_) | ty::RawPtr(_, _) | ty::Ref(_, _, _) @@ -810,6 +817,7 @@ where | ty::Str | ty::Array(_, _) | ty::Pat(_, _) + | ty::FRT(_, _) | ty::Slice(_) | ty::RawPtr(_, _) | ty::Ref(_, _, _) diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs index 05ea217c1de08..e21da4a1d0902 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs @@ -35,6 +35,7 @@ where | ty::Float(_) | ty::FnDef(..) | ty::FnPtr(..) + | ty::FRT(..) | ty::Error(_) | ty::Never | ty::Char => Ok(ty::Binder::dummy(vec![])), @@ -117,7 +118,7 @@ where match ty.kind() { // impl {Meta,}Sized for u*, i*, bool, f*, FnDef, FnPtr, *(const/mut) T, char // impl {Meta,}Sized for &mut? T, [T; N], dyn* Trait, !, Coroutine, CoroutineWitness - // impl {Meta,}Sized for Closure, CoroutineClosure + // impl {Meta,}Sized for FRT, Closure, CoroutineClosure ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) | ty::Uint(_) | ty::Int(_) @@ -132,6 +133,7 @@ where | ty::CoroutineWitness(..) | ty::Array(..) | ty::Pat(..) + | ty::FRT(..) | ty::Closure(..) | ty::CoroutineClosure(..) | ty::Never @@ -194,7 +196,7 @@ where { match ty.kind() { // impl Copy/Clone for FnDef, FnPtr - ty::FnDef(..) | ty::FnPtr(..) | ty::Error(_) => Ok(ty::Binder::dummy(vec![])), + ty::FnDef(..) | ty::FnPtr(..) | ty::Error(_) | ty::FRT(..) => Ok(ty::Binder::dummy(vec![])), // Implementations are provided in core ty::Uint(_) @@ -389,6 +391,7 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_callable( | ty::Never | ty::Tuple(_) | ty::Pat(_, _) + | ty::FRT(_, _) | ty::Alias(_, _) | ty::Param(_) | ty::Placeholder(..) @@ -784,6 +789,7 @@ pub(in crate::solve) fn const_conditions_for_destruct( | ty::FnPtr(..) | ty::Never | ty::Infer(ty::InferTy::FloatVar(_) | ty::InferTy::IntVar(_)) + | ty::FRT(..) | ty::Error(_) => Ok(vec![]), // Coroutines and closures could implement `[const] Drop`, diff --git a/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs b/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs index 2837b8565f603..4da76b88b5de0 100644 --- a/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs @@ -430,6 +430,13 @@ where ) -> Vec> { unreachable!("Unsize is not const") } + + fn consider_builtin_field_candidate( + _ecx: &mut EvalCtxt<'_, D>, + _goal: Goal<::Interner, Self>, + ) -> Result::Interner>, NoSolution> { + unreachable!("Field is not const") + } } impl EvalCtxt<'_, D> diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs index 70c28421c57ea..1d0c33ca6b5ca 100644 --- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs @@ -631,6 +631,7 @@ where | ty::Float(..) | ty::Array(..) | ty::Pat(..) + | ty::FRT(..) | ty::RawPtr(..) | ty::Ref(..) | ty::FnDef(..) @@ -884,6 +885,7 @@ where | ty::Float(..) | ty::Array(..) | ty::Pat(..) + | ty::FRT(..) | ty::RawPtr(..) | ty::Ref(..) | ty::FnDef(..) @@ -950,6 +952,29 @@ where ) -> Result, NoSolution> { unreachable!("`BikeshedGuaranteedNoDrop` does not have an associated type: {:?}", goal) } + + fn consider_builtin_field_candidate( + ecx: &mut EvalCtxt<'_, D>, + goal: Goal, + ) -> Result, NoSolution> { + let self_ty = goal.predicate.self_ty(); + let ty::FRT(container, field) = self_ty.kind() else { + return Err(NoSolution); + }; + + let ty = if ecx.cx().is_lang_item(goal.predicate.def_id(), SolverLangItem::FieldBase) { + container + } else if ecx.cx().is_lang_item(goal.predicate.def_id(), SolverLangItem::FieldType) { + field.ty(ecx.cx(), container) + } else { + panic!("unexpected associated type {:?} in `Field`", goal.predicate) + }; + + ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| { + ecx.instantiate_normalizes_to_term(goal, ty.into()); + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + }) + } } impl EvalCtxt<'_, D> diff --git a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs index 003841f3af3fd..fb44f9a87581c 100644 --- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs @@ -735,6 +735,7 @@ where | ty::RawPtr(..) | ty::Never | ty::Pat(..) + | ty::FRT(..) | ty::Dynamic(..) | ty::Str | ty::Slice(_) @@ -841,6 +842,27 @@ where } }) } + + fn consider_builtin_field_candidate( + ecx: &mut EvalCtxt<'_, D>, + goal: Goal, + ) -> Result, NoSolution> { + if goal.predicate.polarity != ty::PredicatePolarity::Positive { + return Err(NoSolution); + } + if let ty::FRT(ty, _) = goal.predicate.self_ty().kind() + && match ty.kind() { + ty::Adt(def, _) => def.is_struct() && !def.is_packed(), + ty::Tuple(..) => true, + _ => false, + } + { + ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc) + .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)) + } else { + Err(NoSolution) + } + } } /// Small helper function to change the `def_id` of a trait predicate - this is not normally @@ -1241,6 +1263,7 @@ where | ty::Str | ty::Array(_, _) | ty::Pat(_, _) + | ty::FRT(_, _) | ty::Slice(_) | ty::RawPtr(_, _) | ty::Ref(_, _, _) diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 05216be06ff56..f6a3155d08514 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -1140,7 +1140,7 @@ impl<'a> Parser<'a> { /// Parse the field access used in offset_of, matched by `$(e:expr)+`. /// Currently returns a list of idents. However, it should be possible in /// future to also do array indices, which might be arbitrary expressions. - fn parse_floating_field_access(&mut self) -> PResult<'a, Vec> { + pub(crate) fn parse_floating_field_access(&mut self) -> PResult<'a, Vec> { let mut fields = Vec::new(); let mut trailing_dot = None; diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index 6ff165eb22b71..eae129b22cfb0 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -329,6 +329,8 @@ impl<'a> Parser<'a> { self.parse_borrowed_pointee()? } else if self.eat_keyword_noexpect(kw::Typeof) { self.parse_typeof_ty(lo)? + } else if self.is_builtin() { + self.parse_builtin_ty()? } else if self.eat_keyword(exp!(Underscore)) { // A type to be inferred `_` TyKind::Infer @@ -803,6 +805,53 @@ impl<'a> Parser<'a> { Ok(TyKind::Err(guar)) } + fn parse_builtin_ty(&mut self) -> PResult<'a, TyKind> { + self.parse_builtin(|this, lo, ident| { + Ok(match ident.name { + sym::field_of => Some(this.parse_ty_field_of(lo)?), + _ => None, + }) + }) + } + + /// Built-in macro for `field_of!` expressions. + pub(crate) fn parse_ty_field_of(&mut self, _lo: Span) -> PResult<'a, TyKind> { + let container = self.parse_ty()?; + self.expect(exp!(Comma))?; + + let fields = self.parse_floating_field_access()?; + let trailing_comma = self.eat_noexpect(&TokenKind::Comma); + + if let Err(mut e) = self.expect_one_of(&[], &[exp!(CloseParen)]) { + if trailing_comma { + e.note("unexpected third argument to field_of"); + } else { + e.note("field_of expects dot-separated field and variant names"); + } + e.emit(); + } + + // Eat tokens until the macro call ends. + if self.may_recover() { + while !self.token.kind.is_close_delim_or_eof() { + self.bump(); + } + } + + match fields.len() { + 0 => Err(self.dcx().struct_span_err( + self.token.span, + "`field_of!` expects dot-separated field and variant names", + )), + 1 => Ok(TyKind::FieldOf(container, None, fields[0])), + 2 => Ok(TyKind::FieldOf(container, Some(fields[0]), fields[1])), + _ => Err(self.dcx().struct_span_err( + fields.iter().map(|f| f.span).collect::>(), + "`field_of!` only supports a single field or a variant with a field", + )), + } + } + /// Parses a function pointer type (`TyKind::FnPtr`). /// ```ignore (illustrative) /// [unsafe] [extern "ABI"] fn (S) -> T diff --git a/compiler/rustc_passes/src/check_export.rs b/compiler/rustc_passes/src/check_export.rs index fee920221e1d1..1295a7a814461 100644 --- a/compiler/rustc_passes/src/check_export.rs +++ b/compiler/rustc_passes/src/check_export.rs @@ -301,6 +301,7 @@ impl<'tcx, 'a> TypeVisitor> for ExportableItemsChecker<'tcx, 'a> { | ty::Str | ty::Tuple(_) | ty::Pat(..) + | ty::FRT(..) | ty::Slice(_) | ty::RawPtr(_, _) | ty::FnDef(_, _) diff --git a/compiler/rustc_passes/src/input_stats.rs b/compiler/rustc_passes/src/input_stats.rs index 23fbb9ab3a2b7..d731c524ca637 100644 --- a/compiler/rustc_passes/src/input_stats.rs +++ b/compiler/rustc_passes/src/input_stats.rs @@ -410,6 +410,7 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> { TraitObject, Infer, Pat, + FieldOf, Err ] ); @@ -680,6 +681,7 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> { Tup, Path, Pat, + FieldOf, TraitObject, ImplTrait, Paren, diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs index dc38f2d8bc70f..965597cdc4071 100644 --- a/compiler/rustc_pattern_analysis/src/rustc.rs +++ b/compiler/rustc_pattern_analysis/src/rustc.rs @@ -407,6 +407,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { ty::Adt(..) | ty::Tuple(..) => { ConstructorSet::Struct { empty: cx.is_uninhabited(ty.inner()) } } + ty::FRT(..) => ConstructorSet::Struct { empty: false }, ty::Ref(..) => ConstructorSet::Ref, ty::Never => ConstructorSet::NoConstructors, // This type is one for which we cannot list constructors, like `str` or `f64`. diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 9a952bb721951..936d49c9aed88 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -290,6 +290,7 @@ where | ty::RawPtr(..) | ty::Ref(..) | ty::Pat(..) + | ty::FRT(..) | ty::FnPtr(..) | ty::UnsafeBinder(_) | ty::Param(..) diff --git a/compiler/rustc_public/src/ty.rs b/compiler/rustc_public/src/ty.rs index d4f128f87d6ff..e640485a74e73 100644 --- a/compiler/rustc_public/src/ty.rs +++ b/compiler/rustc_public/src/ty.rs @@ -1,6 +1,7 @@ use std::fmt::{self, Debug, Display, Formatter}; use std::ops::Range; +use rustc_middle::ty::FieldId; use serde::Serialize; use super::abi::ReprOptions; @@ -554,6 +555,7 @@ pub enum RigidTy { Str, Array(Ty, TyConst), Pat(Ty, Pattern), + FRT(Ty, FieldId), Slice(Ty), RawPtr(Ty, Mutability), Ref(Region, Ty, Mutability), diff --git a/compiler/rustc_public/src/unstable/convert/internal.rs b/compiler/rustc_public/src/unstable/convert/internal.rs index 8594f65100415..c8b22e3e8048e 100644 --- a/compiler/rustc_public/src/unstable/convert/internal.rs +++ b/compiler/rustc_public/src/unstable/convert/internal.rs @@ -153,6 +153,7 @@ impl RustcInternal for RigidTy { RigidTy::Pat(ty, pat) => { rustc_ty::TyKind::Pat(ty.internal(tables, tcx), pat.internal(tables, tcx)) } + RigidTy::FRT(ty, field) => rustc_ty::TyKind::FRT(ty.internal(tables, tcx), *field), RigidTy::Adt(def, args) => { rustc_ty::TyKind::Adt(def.internal(tables, tcx), args.internal(tables, tcx)) } diff --git a/compiler/rustc_public/src/unstable/convert/stable/ty.rs b/compiler/rustc_public/src/unstable/convert/stable/ty.rs index 70cdae43126c4..5fe30327cd34d 100644 --- a/compiler/rustc_public/src/unstable/convert/stable/ty.rs +++ b/compiler/rustc_public/src/unstable/convert/stable/ty.rs @@ -413,6 +413,7 @@ impl<'tcx> Stable<'tcx> for ty::TyKind<'tcx> { ty::Pat(ty, pat) => { TyKind::RigidTy(RigidTy::Pat(ty.stable(tables, cx), pat.stable(tables, cx))) } + ty::FRT(ty, field) => TyKind::RigidTy(RigidTy::FRT(ty.stable(tables, cx), *field)), ty::Slice(ty) => TyKind::RigidTy(RigidTy::Slice(ty.stable(tables, cx))), ty::RawPtr(ty, mutbl) => { TyKind::RigidTy(RigidTy::RawPtr(ty.stable(tables, cx), mutbl.stable(tables, cx))) diff --git a/compiler/rustc_public/src/visitor.rs b/compiler/rustc_public/src/visitor.rs index acc3334769613..d7591146f4955 100644 --- a/compiler/rustc_public/src/visitor.rs +++ b/compiler/rustc_public/src/visitor.rs @@ -158,6 +158,7 @@ impl Visitable for RigidTy { c.visit(visitor) } RigidTy::Pat(t, _p) => t.visit(visitor), + RigidTy::FRT(t, _f) => t.visit(visitor), RigidTy::Slice(inner) => inner.visit(visitor), RigidTy::RawPtr(ty, _) => ty.visit(visitor), RigidTy::Ref(reg, ty, _) => { diff --git a/compiler/rustc_query_impl/src/execution.rs b/compiler/rustc_query_impl/src/execution.rs index 88604c91d0259..c0d7a86acad21 100644 --- a/compiler/rustc_query_impl/src/execution.rs +++ b/compiler/rustc_query_impl/src/execution.rs @@ -416,7 +416,8 @@ fn execute_job_non_incr<'tcx, C: QueryCache, const FLAGS: QueryFlags>( } let prof_timer = qcx.tcx.prof.query_provider(); - let result = qcx.start_query(job_id, query.depth_limit(), || query.compute(qcx, key)); + // Call the query provider. + let result = qcx.start_query(job_id, query.depth_limit(), || query.invoke_provider(qcx, key)); let dep_node_index = qcx.tcx.dep_graph.next_virtual_depnode_index(); prof_timer.finish_with_query_invocation_id(dep_node_index.into()); @@ -459,18 +460,21 @@ fn execute_job_incr<'tcx, C: QueryCache, const FLAGS: QueryFlags>( let (result, dep_node_index) = qcx.start_query(job_id, query.depth_limit(), || { if query.anon() { - return dep_graph_data - .with_anon_task_inner(qcx.tcx, query.dep_kind(), || query.compute(qcx, key)); + // Call the query provider inside an anon task. + return dep_graph_data.with_anon_task_inner(qcx.tcx, query.dep_kind(), || { + query.invoke_provider(qcx, key) + }); } // `to_dep_node` is expensive for some `DepKind`s. let dep_node = dep_node_opt.unwrap_or_else(|| query.construct_dep_node(qcx.tcx, &key)); + // Call the query provider. dep_graph_data.with_task( dep_node, (qcx, query), key, - |(qcx, query), key| query.compute(qcx, key), + |(qcx, query), key| query.invoke_provider(qcx, key), query.hash_result(), ) }); @@ -547,7 +551,8 @@ fn try_load_from_disk_and_cache_in_memory<'tcx, C: QueryCache, const FLAGS: Quer let prof_timer = qcx.tcx.prof.query_provider(); // The dep-graph for this computation is already in-place. - let result = qcx.tcx.dep_graph.with_ignore(|| query.compute(qcx, *key)); + // Call the query provider. + let result = qcx.tcx.dep_graph.with_ignore(|| query.invoke_provider(qcx, *key)); prof_timer.finish_with_query_invocation_id(dep_node_index.into()); diff --git a/compiler/rustc_query_impl/src/lib.rs b/compiler/rustc_query_impl/src/lib.rs index a33bdd22a7970..c79990ac1da4c 100644 --- a/compiler/rustc_query_impl/src/lib.rs +++ b/compiler/rustc_query_impl/src/lib.rs @@ -107,15 +107,18 @@ impl<'tcx, C: QueryCache, const FLAGS: QueryFlags> SemiDynamicQueryDispatcher<'t } } - // Don't use this method to compute query results, instead use the methods on TyCtxt. + /// Calls `tcx.$query(key)` for this query, and discards the returned value. + /// See [`QueryVTable::call_query_method_fn`] for details of this strange operation. #[inline(always)] - fn execute_query(self, tcx: TyCtxt<'tcx>, key: C::Key) -> C::Value { - (self.vtable.execute_query)(tcx, key) + fn call_query_method(self, tcx: TyCtxt<'tcx>, key: C::Key) { + (self.vtable.call_query_method_fn)(tcx, key) } + /// Calls the actual provider function for this query. + /// See [`QueryVTable::invoke_provider_fn`] for more details. #[inline(always)] - fn compute(self, qcx: QueryCtxt<'tcx>, key: C::Key) -> C::Value { - (self.vtable.compute_fn)(qcx.tcx, key) + fn invoke_provider(self, qcx: QueryCtxt<'tcx>, key: C::Key) -> C::Value { + (self.vtable.invoke_provider_fn)(qcx.tcx, key) } #[inline(always)] diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs index eb195550b2e50..a61793facec6a 100644 --- a/compiler/rustc_query_impl/src/plumbing.rs +++ b/compiler/rustc_query_impl/src/plumbing.rs @@ -457,7 +457,9 @@ fn try_load_from_on_disk_cache<'tcx, C: QueryCache, const FLAGS: QueryFlags>( panic!("Failed to recover key for {:?} with hash {}", dep_node, dep_node.hash) }); if query.will_cache_on_disk_for_key(tcx, &key) { - let _ = query.execute_query(tcx, key); + // Call `tcx.$query(key)` for its side-effect of loading the disk-cached + // value into memory. + query.call_query_method(tcx, key); } } @@ -625,14 +627,15 @@ macro_rules! define_queries { } } - /// Defines a `compute` function for this query, to be used as a - /// function pointer in the query's vtable. - mod compute_fn { + /// Defines an `invoke_provider` function that calls the query's provider, + /// to be used as a function pointer in the query's vtable. + /// + /// To mark a short-backtrace boundary, the function's actual name + /// (after demangling) must be `__rust_begin_short_backtrace`. + mod invoke_provider_fn { use super::*; use ::rustc_middle::queries::$name::{Key, Value, provided_to_erased}; - /// This function would be named `compute`, but we also want it - /// to mark the boundaries of an omitted region in backtraces. #[inline(never)] pub(crate) fn __rust_begin_short_backtrace<'tcx>( tcx: TyCtxt<'tcx>, @@ -643,10 +646,13 @@ macro_rules! define_queries { // Call the actual provider function for this query. let provided_value = call_provider!([$($modifiers)*][tcx, $name, key]); + rustc_middle::ty::print::with_reduced_queries!({ tracing::trace!(?provided_value); }); + // Erase the returned value, because `QueryVTable` uses erased values. + // For queries with `arena_cache`, this also arena-allocates the value. provided_to_erased(tcx, provided_value) } } @@ -666,8 +672,12 @@ macro_rules! define_queries { } { None }), - execute_query: |tcx, key| erase::erase_val(tcx.$name(key)), - compute_fn: self::compute_fn::__rust_begin_short_backtrace, + call_query_method_fn: |tcx, key| { + // Call the query method for its side-effect of loading a value + // from disk-cache; the caller doesn't need the value. + let _ = tcx.$name(key); + }, + invoke_provider_fn: self::invoke_provider_fn::__rust_begin_short_backtrace, try_load_from_disk_fn: if_cache_on_disk!([$($modifiers)*] { Some(|tcx, key, prev_index, index| { // Check the `cache_on_disk_if` condition for this key. diff --git a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs index 5505fe82cea65..3f9e781801be4 100644 --- a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs +++ b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs @@ -434,6 +434,9 @@ pub(crate) fn encode_ty<'tcx>( typeid.push_str(&s); } + // FIXME(FRTs): add mangling support + ty::FRT(..) => todo!(), + ty::Slice(ty0) => { // u5sliceIE as vendor extended type let mut s = String::from("u5sliceI"); diff --git a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs index 971ac9348fc4c..f348b200d85d7 100644 --- a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs +++ b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs @@ -60,6 +60,7 @@ impl<'tcx> TypeFolder> for TransformTy<'tcx> { | ty::Foreign(..) | ty::Never | ty::Pat(..) + | ty::FRT(..) | ty::Slice(..) | ty::Str | ty::Tuple(..) diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 0f248925602ff..9e8179c701f5c 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1084,7 +1084,12 @@ symbols! { ffi_pure, ffi_returns_twice, field, + field_base, field_init_shorthand, + field_of, + field_offset, + field_projections, + field_type, file, file_options, flags, diff --git a/compiler/rustc_symbol_mangling/src/export.rs b/compiler/rustc_symbol_mangling/src/export.rs index c99ba1d58f31f..31a1381f218eb 100644 --- a/compiler/rustc_symbol_mangling/src/export.rs +++ b/compiler/rustc_symbol_mangling/src/export.rs @@ -105,6 +105,7 @@ impl<'tcx> AbiHashStable<'tcx> for Ty<'tcx> { | ty::Str | ty::Array(_, _) | ty::Pat(_, _) + | ty::FRT(_, _) | ty::Slice(_) | ty::RawPtr(_, _) | ty::FnDef(_, _) diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index 95cbb9e07ebb7..9a573a2bbf64e 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -510,6 +510,9 @@ impl<'tcx> Printer<'tcx> for V0SymbolMangler<'tcx> { self.print_pat(pat)?; } + // FIXME(FRTs): add mangling support + ty::FRT(..) => todo!("mangle {ty}"), + ty::Array(ty, len) => { self.push("A"); ty.print(self)?; diff --git a/compiler/rustc_target/src/callconv/sparc64.rs b/compiler/rustc_target/src/callconv/sparc64.rs index fc732170dcb73..f55d03d89e8ff 100644 --- a/compiler/rustc_target/src/callconv/sparc64.rs +++ b/compiler/rustc_target/src/callconv/sparc64.rs @@ -1,214 +1,203 @@ -// FIXME: This needs an audit for correctness and completeness. - use rustc_abi::{ - BackendRepr, FieldsShape, Float, HasDataLayout, Primitive, Reg, Scalar, Size, TyAbiInterface, - TyAndLayout, + Align, BackendRepr, FieldsShape, Float, HasDataLayout, Primitive, Reg, Size, TyAbiInterface, + TyAndLayout, Variants, }; use crate::callconv::{ArgAbi, ArgAttribute, CastTarget, FnAbi, Uniform}; -use crate::spec::{Env, HasTargetSpec, Os}; - -#[derive(Clone, Debug)] -struct Sdata { - pub prefix: [Option; 8], - pub prefix_index: usize, - pub last_offset: Size, - pub has_float: bool, - pub arg_attribute: ArgAttribute, -} - -fn arg_scalar(cx: &C, scalar: &Scalar, offset: Size, mut data: Sdata) -> Sdata -where - C: HasDataLayout, -{ - let dl = cx.data_layout(); - - if !matches!(scalar.primitive(), Primitive::Float(Float::F32 | Float::F64)) { - return data; - } - - data.has_float = true; - - if !data.last_offset.is_aligned(dl.f64_align) && data.last_offset < offset { - if data.prefix_index == data.prefix.len() { - return data; - } - data.prefix[data.prefix_index] = Some(Reg::i32()); - data.prefix_index += 1; - data.last_offset = data.last_offset + Reg::i32().size; - } - - for _ in 0..((offset - data.last_offset).bits() / 64) - .min((data.prefix.len() - data.prefix_index) as u64) - { - data.prefix[data.prefix_index] = Some(Reg::i64()); - data.prefix_index += 1; - data.last_offset = data.last_offset + Reg::i64().size; - } +use crate::spec::{HasTargetSpec, Os}; - if data.last_offset < offset { - if data.prefix_index == data.prefix.len() { - return data; - } - data.prefix[data.prefix_index] = Some(Reg::i32()); - data.prefix_index += 1; - data.last_offset = data.last_offset + Reg::i32().size; - } - - if data.prefix_index == data.prefix.len() { - return data; - } +// NOTE: GCC and Clang/LLVM have disagreements that the ABI doesn't resolve, we match the +// Clang/LLVM behavior in these cases. - if scalar.primitive() == Primitive::Float(Float::F32) { - data.arg_attribute = ArgAttribute::InReg; - data.prefix[data.prefix_index] = Some(Reg::f32()); - data.last_offset = offset + Reg::f32().size; - } else { - data.prefix[data.prefix_index] = Some(Reg::f64()); - data.last_offset = offset + Reg::f64().size; - } - data.prefix_index += 1; - data +#[derive(Copy, Clone)] +enum DoubleWord { + F64, + F128Start, + F128End, + Words([Word; 2]), } -fn arg_scalar_pair( - cx: &C, - scalar1: &Scalar, - scalar2: &Scalar, - mut offset: Size, - mut data: Sdata, -) -> Sdata -where - C: HasDataLayout, -{ - data = arg_scalar(cx, scalar1, offset, data); - match (scalar1.primitive(), scalar2.primitive()) { - (Primitive::Float(Float::F32), _) => offset += Reg::f32().size, - (_, Primitive::Float(Float::F64)) => offset += Reg::f64().size, - (Primitive::Int(i, _signed), _) => offset += i.size(), - (Primitive::Pointer(_), _) => offset += Reg::i64().size, - _ => {} - } - - if !offset.bytes().is_multiple_of(4) - && matches!(scalar2.primitive(), Primitive::Float(Float::F32 | Float::F64)) - { - offset += Size::from_bytes(4 - (offset.bytes() % 4)); - } - data = arg_scalar(cx, scalar2, offset, data); - data +#[derive(Copy, Clone)] +enum Word { + F32, + Integer, } -fn parse_structure<'a, Ty, C>( +fn classify<'a, Ty, C>( cx: &C, - layout: TyAndLayout<'a, Ty>, - mut data: Sdata, - mut offset: Size, -) -> Sdata -where + arg_layout: &TyAndLayout<'a, Ty>, + offset: Size, + double_words: &mut [DoubleWord; 4], +) where Ty: TyAbiInterface<'a, C> + Copy, C: HasDataLayout, { - if let FieldsShape::Union(_) = layout.fields { - return data; - } - - match layout.backend_repr { - BackendRepr::Scalar(scalar) => { - data = arg_scalar(cx, &scalar, offset, data); - } - BackendRepr::Memory { .. } => { - for i in 0..layout.fields.count() { - if offset < layout.fields.offset(i) { - offset = layout.fields.offset(i); + // If this function does not update the `double_words` array, the value will be passed via + // integer registers. The array is initialized with `DoubleWord::Words([Word::Integer; 2])`. + + match arg_layout.backend_repr { + BackendRepr::Scalar(scalar) => match scalar.primitive() { + Primitive::Float(float) => { + if offset.is_aligned(Ord::min(*float.align(cx), Align::EIGHT)) { + let index = offset.bytes_usize() / 8; + match float { + Float::F128 => { + double_words[index] = DoubleWord::F128Start; + double_words[index + 1] = DoubleWord::F128End; + } + Float::F64 => { + double_words[index] = DoubleWord::F64; + } + Float::F32 => match &mut double_words[index] { + DoubleWord::Words(words) => { + words[(offset.bytes_usize() % 8) / 4] = Word::F32; + } + _ => unreachable!(), + }, + Float::F16 => { + // Match LLVM by passing `f16` in integer registers. + } + } + } else { + /* pass unaligned floats in integer registers */ } - data = parse_structure(cx, layout.field(cx, i), data.clone(), offset); } - } - _ => { - if let BackendRepr::ScalarPair(scalar1, scalar2) = &layout.backend_repr { - data = arg_scalar_pair(cx, scalar1, scalar2, offset, data); + Primitive::Int(_, _) | Primitive::Pointer(_) => { /* pass in integer registers */ } + }, + BackendRepr::SimdVector { .. } => {} + BackendRepr::ScalableVector { .. } => {} + BackendRepr::ScalarPair(..) | BackendRepr::Memory { .. } => match arg_layout.fields { + FieldsShape::Primitive => { + unreachable!("aggregates can't have `FieldsShape::Primitive`") } - } + FieldsShape::Union(_) => { + if !arg_layout.is_zst() { + if arg_layout.is_transparent() { + let non_1zst_elem = arg_layout.non_1zst_field(cx).expect("not exactly one non-1-ZST field in non-ZST repr(transparent) union").1; + classify(cx, &non_1zst_elem, offset, double_words); + } + } + } + FieldsShape::Array { .. } => {} + FieldsShape::Arbitrary { .. } => match arg_layout.variants { + Variants::Multiple { .. } => {} + Variants::Single { .. } | Variants::Empty => { + // Match Clang by ignoring whether a struct is packed and just considering + // whether individual fields are aligned. GCC currently uses only integer + // registers when passing packed structs. + for i in arg_layout.fields.index_by_increasing_offset() { + classify( + cx, + &arg_layout.field(cx, i), + offset + arg_layout.fields.offset(i), + double_words, + ); + } + } + }, + }, } - - data } -fn classify_arg<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>, in_registers_max: Size) -where +fn classify_arg<'a, Ty, C>( + cx: &C, + arg: &mut ArgAbi<'a, Ty>, + in_registers_max: Size, + total_double_word_count: &mut usize, +) where Ty: TyAbiInterface<'a, C> + Copy, C: HasDataLayout, { + // 64-bit SPARC allocates argument stack space in 64-bit chunks (double words), some of which + // are promoted to registers based on their position on the stack. + + // Keep track of the total number of double words used by arguments so far. This allows padding + // arguments to be inserted where necessary to ensure that 16-aligned arguments are passed in an + // aligned set of registers. + + let pad = !total_double_word_count.is_multiple_of(2) && arg.layout.align.abi.bytes() == 16; + // The number of double words used by this argument. + let double_word_count = arg.layout.size.bytes_usize().div_ceil(8); + // The number of double words before this argument, including any padding. + let start_double_word_count = *total_double_word_count + usize::from(pad); + if arg.layout.pass_indirectly_in_non_rustic_abis(cx) { arg.make_indirect(); + *total_double_word_count += 1; return; } + if !arg.layout.is_aggregate() { arg.extend_integer_width_to(64); + *total_double_word_count = start_double_word_count + double_word_count; return; } let total = arg.layout.size; if total > in_registers_max { arg.make_indirect(); + *total_double_word_count += 1; return; } - match arg.layout.fields { - FieldsShape::Primitive => unreachable!(), - FieldsShape::Array { .. } => { - // Arrays are passed indirectly - arg.make_indirect(); - return; - } - FieldsShape::Union(_) => { - // Unions and are always treated as a series of 64-bit integer chunks - } - FieldsShape::Arbitrary { .. } => { - // Structures with floating point numbers need special care. - - let mut data = parse_structure( - cx, - arg.layout, - Sdata { - prefix: [None; 8], - prefix_index: 0, - last_offset: Size::ZERO, - has_float: false, - arg_attribute: ArgAttribute::default(), - }, - Size::ZERO, - ); - - if data.has_float { - // Structure { float, int, int } doesn't like to be handled like - // { float, long int }. Other way around it doesn't mind. - if data.last_offset < arg.layout.size - && !data.last_offset.bytes().is_multiple_of(8) - && data.prefix_index < data.prefix.len() - { - data.prefix[data.prefix_index] = Some(Reg::i32()); - data.prefix_index += 1; - data.last_offset += Reg::i32().size; - } + *total_double_word_count = start_double_word_count + double_word_count; - let mut rest_size = arg.layout.size - data.last_offset; - if !rest_size.bytes().is_multiple_of(8) && data.prefix_index < data.prefix.len() { - data.prefix[data.prefix_index] = Some(Reg::i32()); - rest_size = rest_size - Reg::i32().size; - } + const ARGUMENT_REGISTERS: usize = 8; - arg.cast_to( - CastTarget::prefixed(data.prefix, Uniform::new(Reg::i64(), rest_size)) - .with_attrs(data.arg_attribute.into()), - ); - return; + let mut double_words = [DoubleWord::Words([Word::Integer; 2]); ARGUMENT_REGISTERS / 2]; + classify(cx, &arg.layout, Size::ZERO, &mut double_words); + + let mut regs = [None; ARGUMENT_REGISTERS]; + let mut i = 0; + let mut push = |reg| { + regs[i] = Some(reg); + i += 1; + }; + let mut attrs = ArgAttribute::empty(); + + for (index, double_word) in double_words.into_iter().enumerate() { + if arg.layout.size.bytes_usize() <= index * 8 { + break; + } + match double_word { + // `f128` must be aligned to be assigned a float register. + DoubleWord::F128Start if (start_double_word_count + index).is_multiple_of(2) => { + push(Reg::f128()); + } + DoubleWord::F128Start => { + // Clang currently handles this case nonsensically, always returning a packed + // `struct { long double x; }` in an aligned quad floating-point register even when + // the `long double` isn't aligned on the stack, which also makes all future + // arguments get passed in the wrong registers. This passes the `f128` in integer + // registers when it is unaligned, same as with `f32` and `f64`. + push(Reg::i64()); + push(Reg::i64()); + } + DoubleWord::F128End => {} // Already handled by `F128Start` + DoubleWord::F64 => push(Reg::f64()), + DoubleWord::Words([Word::Integer, Word::Integer]) => push(Reg::i64()), + DoubleWord::Words(words) => { + attrs |= ArgAttribute::InReg; + for word in words { + match word { + Word::F32 => push(Reg::f32()), + Word::Integer => push(Reg::i32()), + } + } } } } - arg.cast_to(Uniform::new(Reg::i64(), total)); + let cast_target = match regs { + [Some(reg), None, rest @ ..] => { + // Just a single register is needed for this value. + debug_assert!(rest.iter().all(|x| x.is_none())); + CastTarget::from(reg) + } + _ => CastTarget::prefixed(regs, Uniform::new(Reg::i8(), Size::ZERO)), + }; + + arg.cast_to_and_pad_i32(cast_target.with_attrs(attrs.into()), pad); } pub(crate) fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>) @@ -217,23 +206,26 @@ where C: HasDataLayout + HasTargetSpec, { if !fn_abi.ret.is_ignore() && fn_abi.ret.layout.is_sized() { - classify_arg(cx, &mut fn_abi.ret, Size::from_bytes(32)); + // A return value of 32 bytes or smaller is passed via registers. + classify_arg(cx, &mut fn_abi.ret, Size::from_bytes(32), &mut 0); } + // sparc64-unknown-linux-{gnu,musl,uclibc} doesn't ignore ZSTs. + let passes_zsts = matches!(cx.target_spec().os, Os::Linux); + + let mut double_word_count = 0; for arg in fn_abi.args.iter_mut() { if !arg.layout.is_sized() { continue; } if arg.is_ignore() { - // sparc64-unknown-linux-{gnu,musl,uclibc} doesn't ignore ZSTs. - if cx.target_spec().os == Os::Linux - && matches!(cx.target_spec().env, Env::Gnu | Env::Musl | Env::Uclibc) - && arg.layout.is_zst() - { + if passes_zsts && arg.layout.is_zst() { arg.make_indirect_from_ignore(); + double_word_count += 1; } - return; + continue; } - classify_arg(cx, arg, Size::from_bytes(16)); + // An argument of 16 bytes or smaller is passed via registers. + classify_arg(cx, arg, Size::from_bytes(16), &mut double_word_count); } } diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs index 1de088f19cc7f..c47918ba1d6aa 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs @@ -1883,6 +1883,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ty::CoroutineClosure(..) => Some(21), ty::Pat(..) => Some(22), ty::UnsafeBinder(..) => Some(23), + ty::FRT(..) => Some(24), ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) | ty::Error(_) => None, } } diff --git a/compiler/rustc_trait_selection/src/traits/effects.rs b/compiler/rustc_trait_selection/src/traits/effects.rs index 66c949a38cea7..3a57600ba3644 100644 --- a/compiler/rustc_trait_selection/src/traits/effects.rs +++ b/compiler/rustc_trait_selection/src/traits/effects.rs @@ -328,7 +328,7 @@ fn evaluate_host_effect_for_copy_clone_goal<'tcx>( let self_ty = obligation.predicate.self_ty(); let constituent_tys = match *self_ty.kind() { // impl Copy/Clone for FnDef, FnPtr - ty::FnDef(..) | ty::FnPtr(..) | ty::Error(_) => Ok(ty::Binder::dummy(vec![])), + ty::FnDef(..) | ty::FnPtr(..) | ty::Error(_) | ty::FRT(..) => Ok(ty::Binder::dummy(vec![])), // Implementations are provided in core ty::Uint(_) @@ -470,6 +470,7 @@ fn evaluate_host_effect_for_destruct_goal<'tcx>( | ty::FnPtr(..) | ty::Never | ty::Infer(ty::InferTy::FloatVar(_) | ty::InferTy::IntVar(_)) + | ty::FRT(..) | ty::Error(_) => thin_vec![], // Coroutines and closures could implement `[const] Drop`, diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 5bbbad0b5bbfa..f901d6b941316 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -992,7 +992,8 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( | LangItem::FnOnce | LangItem::AsyncFn | LangItem::AsyncFnMut - | LangItem::AsyncFnOnce, + | LangItem::AsyncFnOnce + | LangItem::Field, ) => true, Some(LangItem::AsyncFnKindHelper) => { // FIXME(async_closures): Validity constraints here could be cleaned up. @@ -1023,6 +1024,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( | ty::Str | ty::Array(..) | ty::Pat(..) + | ty::FRT(..) | ty::Slice(_) | ty::RawPtr(..) | ty::Ref(..) @@ -1078,6 +1080,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( | ty::Str | ty::Array(..) | ty::Pat(..) + | ty::FRT(..) | ty::Slice(_) | ty::RawPtr(..) | ty::Ref(..) @@ -1547,6 +1550,17 @@ fn confirm_builtin_candidate<'cx, 'tcx>( } }); (metadata_ty.into(), obligations) + } else if tcx.is_lang_item(trait_def_id, LangItem::Field) { + let &ty::FRT(container, field) = self_ty.kind() else { + bug!("only `field_of!()` can implement `Field`") + }; + if tcx.is_lang_item(item_def_id, LangItem::FieldBase) { + (container.into(), PredicateObligations::new()) + } else if tcx.is_lang_item(item_def_id, LangItem::FieldType) { + (field.ty(tcx, container).into(), PredicateObligations::new()) + } else { + bug!("unexpected associated type {:?} in `Field`", obligation.predicate); + } } else { bug!("unexpected builtin trait with associated type: {:?}", obligation.predicate); }; diff --git a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs index 2e60805cd10a5..2aada90e0d985 100644 --- a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs +++ b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs @@ -43,6 +43,7 @@ pub fn trivial_dropck_outlives<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool { | ty::Ref(..) | ty::Str | ty::Foreign(..) + | ty::FRT(..) | ty::Error(_) => true, // `T is PAT` and `[T]` have same properties as T. @@ -275,6 +276,7 @@ pub fn dtorck_constraint_for_ty_inner<'tcx>( | ty::Float(_) | ty::Str | ty::Never + | ty::FRT(..) | ty::Foreign(..) | ty::RawPtr(..) | ty::Ref(..) diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index f5bf74a799192..da5a532c440ab 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -128,6 +128,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { &mut candidates, ); } + Some(LangItem::Field) => { + self.assemble_candidates_for_field_trait(obligation, &mut candidates); + } _ => { // We re-match here for traits that can have both builtin impls and user written impls. // After the builtin impls we need to also add user written impls, which we do not want to @@ -691,6 +694,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { | ty::Str | ty::Array(_, _) | ty::Pat(_, _) + | ty::FRT(..) | ty::Slice(_) | ty::RawPtr(_, _) | ty::Ref(_, _, _) @@ -865,6 +869,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { | ty::Str | ty::Array(_, _) | ty::Pat(_, _) + | ty::FRT(..) | ty::Slice(_) | ty::Adt(..) | ty::RawPtr(_, _) @@ -1134,7 +1139,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { match *self_ty.kind() { // These impls are built-in because we cannot express sufficiently // generic impls in libcore. - ty::FnDef(..) | ty::FnPtr(..) | ty::Error(_) | ty::Tuple(..) | ty::Pat(..) => { + ty::FnDef(..) + | ty::FnPtr(..) + | ty::Error(_) + | ty::Tuple(..) + | ty::Pat(..) + | ty::FRT(..) => { candidates.vec.push(BuiltinCandidate); } @@ -1249,6 +1259,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { | ty::Closure(..) | ty::CoroutineClosure(..) | ty::Never + | ty::FRT(..) | ty::Error(_) => { candidates.vec.push(SizedCandidate); } @@ -1331,6 +1342,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { | ty::Ref(_, _, _) | ty::FnDef(_, _) | ty::Pat(_, _) + | ty::FRT(_, _) | ty::FnPtr(..) | ty::UnsafeBinder(_) | ty::Dynamic(_, _) @@ -1367,6 +1379,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { | ty::Str | ty::Array(..) | ty::Pat(..) + | ty::FRT(..) | ty::Slice(_) | ty::RawPtr(_, _) | ty::Ref(..) @@ -1418,6 +1431,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { | ty::RawPtr(..) | ty::Never | ty::Pat(..) + | ty::FRT(..) | ty::Dynamic(..) | ty::Str | ty::Slice(_) @@ -1439,4 +1453,20 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } } + + fn assemble_candidates_for_field_trait( + &mut self, + obligation: &PolyTraitObligation<'tcx>, + candidates: &mut SelectionCandidateSet<'tcx>, + ) { + if let ty::FRT(ty, _) = obligation.predicate.self_ty().skip_binder().kind() + && match ty.kind() { + ty::Adt(def, _) => def.is_struct() && !def.repr().packed(), + ty::Tuple(..) => true, + _ => false, + } + { + candidates.vec.push(BuiltinCandidate); + } + } } diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 4f65b30775ed0..8d90aebe30bd3 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -265,6 +265,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { | LangItem::FnPtrTrait | LangItem::PointeeTrait | LangItem::Tuple + | LangItem::Field | LangItem::Unpin, ) => ty::Binder::dummy(vec![]), other => bug!("unexpected builtin trait {trait_def:?} ({other:?})"), @@ -1299,6 +1300,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { | ty::RawPtr(..) | ty::Never | ty::Pat(..) + | ty::FRT(..) | ty::Dynamic(..) | ty::Str | ty::Slice(_) diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 4469afc3a4ebf..4818f919b6d14 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -2159,6 +2159,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> { | ty::Closure(..) | ty::CoroutineClosure(..) | ty::Never + | ty::FRT(..) | ty::Error(_) => ty::Binder::dummy(vec![]), ty::Str | ty::Slice(_) | ty::Dynamic(..) => match sizedness { @@ -2196,7 +2197,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> { fn copy_clone_conditions(&mut self, self_ty: Ty<'tcx>) -> ty::Binder<'tcx, Vec>> { match *self_ty.kind() { - ty::FnDef(..) | ty::FnPtr(..) | ty::Error(_) => ty::Binder::dummy(vec![]), + ty::FnDef(..) | ty::FnPtr(..) | ty::Error(_) | ty::FRT(..) => ty::Binder::dummy(vec![]), ty::Uint(_) | ty::Int(_) @@ -2302,6 +2303,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> { | ty::FnPtr(..) | ty::Error(_) | ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) + | ty::FRT(..) | ty::Never | ty::Char => { ty::Binder::dummy(AutoImplConstituents { types: vec![], assumptions: vec![] }) diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index d383cb9d91dd4..a93050163c9ba 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -794,7 +794,7 @@ impl<'a, 'tcx> TypeVisitor> for WfPredicates<'a, 'tcx> { } } - ty::RawPtr(_, _) => { + ty::RawPtr(_, _) | ty::FRT(..) => { // Simple cases that are WF if their type args are WF. } diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs index cbe15eb54787f..cad69e6198990 100644 --- a/compiler/rustc_ty_utils/src/instance.rs +++ b/compiler/rustc_ty_utils/src/instance.rs @@ -380,6 +380,22 @@ fn resolve_associated_item<'tcx>( assert_eq!(name, sym::transmute); let args = tcx.erase_and_anonymize_regions(rcvr_args); Some(ty::Instance::new_raw(trait_item_id, args)) + } else if tcx.is_lang_item(trait_ref.def_id, LangItem::Field) { + if tcx.is_lang_item(trait_item_id, LangItem::FieldOffset) { + let self_ty = trait_ref.self_ty(); + match self_ty.kind() { + ty::FRT(..) => {} + _ => bug!("expected field representing type, found {self_ty}"), + } + Some(Instance { + def: ty::InstanceKind::Item( + tcx.lang_items().get(LangItem::FieldOffset).unwrap(), + ), + args: rcvr_args, + }) + } else { + bug!("unexpected associated associated item") + } } else { Instance::try_resolve_item_for_coroutine(tcx, trait_item_id, trait_id, rcvr_args) } diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs index 62f3667ad7f4f..484c34582b411 100644 --- a/compiler/rustc_ty_utils/src/layout.rs +++ b/compiler/rustc_ty_utils/src/layout.rs @@ -379,6 +379,8 @@ fn layout_of_uncached<'tcx>( tcx.mk_layout(layout) } + ty::FRT(..) => cx.layout_of(tcx.types.unit)?.layout, + // Basic scalars. ty::Bool => tcx.mk_layout(LayoutData::scalar( cx, @@ -764,14 +766,20 @@ fn layout_of_uncached<'tcx>( } ty::Alias(..) => { - // NOTE(eddyb) `layout_of` query should've normalized these away, - // if that was possible, so there's no reason to try again here. - let err = if ty.has_param() { + // In case we're still in a generic context, aliases might be rigid. E.g. + // if we've got a `T: Trait` where-bound, `T::Assoc` cannot be normalized + // in the current context. + // + // For some builtin traits, generic aliases can be rigid even in an empty environment, + // e.g. `::Metadata`. + // + // Due to trivial bounds, this can even be the case if the alias does not reference + // any generic parameters, e.g. a `for<'a> u32: Trait<'a>` where-bound means that + // `>::Assoc` is rigid. + let err = if ty.has_param() || !cx.typing_env.param_env.caller_bounds().is_empty() { LayoutError::TooGeneric(ty) } else { - // This is only reachable with unsatisfiable predicates. For example, if we have - // `u8: Iterator`, then we can't compute the layout of `::Item`. - LayoutError::Unknown(ty) + unreachable!("invalid rigid alias in layout_of after normalization: {ty:?}"); }; return Err(error(cx, err)); } diff --git a/compiler/rustc_ty_utils/src/needs_drop.rs b/compiler/rustc_ty_utils/src/needs_drop.rs index 06eef7e95145e..6f3a9b0359286 100644 --- a/compiler/rustc_ty_utils/src/needs_drop.rs +++ b/compiler/rustc_ty_utils/src/needs_drop.rs @@ -290,6 +290,7 @@ where | ty::RawPtr(..) | ty::FnDef(..) | ty::Pat(..) + | ty::FRT(..) | ty::FnPtr(..) | ty::Tuple(_) | ty::Bound(..) diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs index d6a29aba22b90..22ab03b033d58 100644 --- a/compiler/rustc_ty_utils/src/ty.rs +++ b/compiler/rustc_ty_utils/src/ty.rs @@ -34,6 +34,7 @@ fn sizedness_constraint_for_ty<'tcx>( | ty::FnDef(..) | ty::FnPtr(..) | ty::Array(..) + | ty::FRT(..) | ty::Closure(..) | ty::CoroutineClosure(..) | ty::Coroutine(..) @@ -377,6 +378,7 @@ fn impl_self_is_guaranteed_unsized<'tcx>(tcx: TyCtxt<'tcx>, impl_def_id: DefId) | ty::Foreign(_) | ty::Array(_, _) | ty::Pat(_, _) + | ty::FRT(_, _) | ty::RawPtr(_, _) | ty::Ref(_, _, _) | ty::FnDef(_, _) diff --git a/compiler/rustc_type_ir/src/fast_reject.rs b/compiler/rustc_type_ir/src/fast_reject.rs index ed6416a7f55f2..e66be092082c3 100644 --- a/compiler/rustc_type_ir/src/fast_reject.rs +++ b/compiler/rustc_type_ir/src/fast_reject.rs @@ -46,6 +46,8 @@ pub enum SimplifiedType { Function(usize), UnsafeBinder, Placeholder, + /// Field representing type. + FRT, Error, } @@ -127,6 +129,7 @@ pub fn simplify_type( ty::Array(..) => Some(SimplifiedType::Array), ty::Slice(..) => Some(SimplifiedType::Slice), ty::Pat(ty, ..) => simplify_type(cx, ty, treat_params), + ty::FRT(..) => Some(SimplifiedType::FRT), ty::RawPtr(_, mutbl) => Some(SimplifiedType::Ptr(mutbl)), ty::Dynamic(trait_info, ..) => match trait_info.principal_def_id() { Some(principal_def_id) if !cx.trait_is_auto(principal_def_id) => { @@ -298,6 +301,7 @@ impl matches!(rhs.kind(), ty::FRT(rhs_ty, rhs_field) if + lhs_field == rhs_field && self.types_may_unify_inner(lhs_ty, rhs_ty, depth) + ), + ty::UnsafeBinder(lhs_ty) => match rhs.kind() { ty::UnsafeBinder(rhs_ty) => { self.types_may_unify(lhs_ty.skip_binder(), rhs_ty.skip_binder()) diff --git a/compiler/rustc_type_ir/src/flags.rs b/compiler/rustc_type_ir/src/flags.rs index 8b057e5866cd9..a232411e87599 100644 --- a/compiler/rustc_type_ir/src/flags.rs +++ b/compiler/rustc_type_ir/src/flags.rs @@ -322,6 +322,10 @@ impl FlagComputation { self.add_ty_pat(pat); } + ty::FRT(ty, _field) => { + self.add_ty(ty); + } + ty::Slice(tt) => self.add_ty(tt), ty::RawPtr(ty, _) => { diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs index c9580d589d217..a72890b54383b 100644 --- a/compiler/rustc_type_ir/src/inherent.rs +++ b/compiler/rustc_type_ir/src/inherent.rs @@ -119,6 +119,8 @@ pub trait Ty>: fn new_pat(interner: I, ty: Self, pat: I::Pat) -> Self; + fn new_field_representing_type(interner: I, ty: Self, field: I::FieldId) -> Self; + fn new_unsafe_binder(interner: I, ty: ty::Binder) -> Self; fn tuple_fields(self) -> I::Tys; @@ -152,6 +154,9 @@ pub trait Ty>: /// Checks whether this type is an ADT that has unsafe fields. fn has_unsafe_fields(self) -> bool; + /// Checks whether this type is an ADT that is `repr(packed)`. + fn is_packed(self) -> bool; + fn fn_sig(self, interner: I) -> ty::Binder> { self.kind().fn_sig(interner) } @@ -174,6 +179,7 @@ pub trait Ty>: | ty::Foreign(_) | ty::Array(_, _) | ty::Pat(_, _) + | ty::FRT(_, _) | ty::RawPtr(_, _) | ty::Ref(_, _, _) | ty::FnDef(_, _) @@ -577,6 +583,8 @@ pub trait AdtDef: Copy + Debug + Hash + Eq { fn is_struct(self) -> bool; + fn is_packed(self) -> bool; + /// Returns the type of the struct tail. /// /// Expects the `AdtDef` to be a struct. If it is not, then this will panic. @@ -600,6 +608,10 @@ pub trait AdtDef: Copy + Debug + Hash + Eq { fn destructor(self, interner: I) -> Option; } +pub trait FieldId: Copy + Debug + Hash + Eq { + fn ty(self, interner: I, ty: I::Ty) -> I::Ty; +} + pub trait ParamEnv: Copy + Debug + Hash + Eq + TypeFoldable { fn caller_bounds(self) -> impl SliceLike; } diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index 8f446cdfba6d5..9d202c778aef9 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -210,6 +210,8 @@ pub trait Interner: type AdtDef: AdtDef; fn adt_def(self, adt_def_id: Self::AdtId) -> Self::AdtDef; + type FieldId: FieldId; + fn alias_ty_kind(self, alias: ty::AliasTy) -> ty::AliasTyKind; fn alias_term_kind(self, alias: ty::AliasTerm) -> ty::AliasTermKind; diff --git a/compiler/rustc_type_ir/src/lang_items.rs b/compiler/rustc_type_ir/src/lang_items.rs index 39b575ebab63b..f1c45a4d98b5e 100644 --- a/compiler/rustc_type_ir/src/lang_items.rs +++ b/compiler/rustc_type_ir/src/lang_items.rs @@ -9,6 +9,8 @@ pub enum SolverLangItem { CoroutineReturn, CoroutineYield, DynMetadata, + FieldBase, + FieldType, FutureOutput, Metadata, // tidy-alphabetical-end @@ -36,6 +38,7 @@ pub enum SolverTraitLangItem { Destruct, DiscriminantKind, Drop, + Field, Fn, FnMut, FnOnce, diff --git a/compiler/rustc_type_ir/src/outlives.rs b/compiler/rustc_type_ir/src/outlives.rs index 300e5c0b46956..671eb9f2ea2b5 100644 --- a/compiler/rustc_type_ir/src/outlives.rs +++ b/compiler/rustc_type_ir/src/outlives.rs @@ -198,6 +198,7 @@ impl TypeVisitor for OutlivesCollector<'_, I> { | ty::Foreign(_) | ty::Array(_, _) | ty::Pat(_, _) + | ty::FRT(_, _) | ty::Slice(_) | ty::RawPtr(_, _) | ty::Ref(_, _, _) diff --git a/compiler/rustc_type_ir/src/relate.rs b/compiler/rustc_type_ir/src/relate.rs index 3610605462ba9..c0f2621c07780 100644 --- a/compiler/rustc_type_ir/src/relate.rs +++ b/compiler/rustc_type_ir/src/relate.rs @@ -511,6 +511,15 @@ pub fn structurally_relate_tys>( Ok(Ty::new_pat(cx, ty, pat)) } + (ty::FRT(a_ty, a_field), ty::FRT(b_ty, b_field)) => { + let ty = relation.relate(a_ty, b_ty)?; + if a_field == b_field { + Ok(Ty::new_field_representing_type(cx, ty, a_field)) + } else { + Err(TypeError::Mismatch) + } + } + (ty::UnsafeBinder(a_binder), ty::UnsafeBinder(b_binder)) => { Ok(Ty::new_unsafe_binder(cx, relation.binders(*a_binder, *b_binder)?)) } diff --git a/compiler/rustc_type_ir/src/ty_kind.rs b/compiler/rustc_type_ir/src/ty_kind.rs index 7cb71387e8680..fef605b3cd175 100644 --- a/compiler/rustc_type_ir/src/ty_kind.rs +++ b/compiler/rustc_type_ir/src/ty_kind.rs @@ -106,6 +106,9 @@ pub enum TyKind { /// Only supports integer range patterns for now. Pat(I::Ty, I::Pat), + /// Field representing type (`field_of!(Struct, field)`). + FRT(I::Ty, I::FieldId), + /// The pointee of an array slice. Written as `[T]`. Slice(I::Ty), @@ -298,6 +301,7 @@ impl TyKind { | ty::Str | ty::Array(_, _) | ty::Pat(_, _) + | ty::FRT(_, _) | ty::Slice(_) | ty::RawPtr(_, _) | ty::Ref(_, _, _) @@ -350,6 +354,7 @@ impl fmt::Debug for TyKind { Str => write!(f, "str"), Array(t, c) => write!(f, "[{t:?}; {c:?}]"), Pat(t, p) => write!(f, "pattern_type!({t:?} is {p:?})"), + FRT(t, i) => write!(f, "field_of!({t:?}, {i:?})"), Slice(t) => write!(f, "[{:?}]", &t), RawPtr(ty, mutbl) => write!(f, "*{} {:?}", mutbl.ptr_str(), ty), Ref(r, t, m) => write!(f, "&{:?} {}{:?}", r, m.prefix_str(), t), diff --git a/compiler/rustc_type_ir/src/walk.rs b/compiler/rustc_type_ir/src/walk.rs index e48d598a5328d..a07fde2d00975 100644 --- a/compiler/rustc_type_ir/src/walk.rs +++ b/compiler/rustc_type_ir/src/walk.rs @@ -92,6 +92,9 @@ fn push_inner(stack: &mut TypeWalkerStack, parent: I::GenericArg push_ty_pat::(stack, pat); stack.push(ty.into()); } + ty::FRT(ty, _) => { + stack.push(ty.into()); + } ty::Array(ty, len) => { stack.push(len.into()); stack.push(ty.into()); diff --git a/library/core/src/field.rs b/library/core/src/field.rs new file mode 100644 index 0000000000000..62590a3ec78c8 --- /dev/null +++ b/library/core/src/field.rs @@ -0,0 +1,35 @@ +//! Field Reflection + +/// Type representing a field of a `struct`, `union`, `enum` variant or tuple. +/// +/// # Safety +/// +/// Given a valid value of type `Self::Base`, there exists a valid value of type `Self::Type` at +/// byte offset `OFFSET`. +#[lang = "field"] +#[unstable(feature = "field_projections", issue = "145383")] +#[rustc_deny_explicit_impl] +#[rustc_dyn_incompatible_trait] +pub unsafe trait Field: Sized { + /// The type of the base where this field exists in. + #[lang = "field_base"] + type Base; + + /// The type of the field. + #[lang = "field_type"] + type Type; + + /// The offset of the field in bytes. + #[lang = "field_offset"] + const OFFSET: usize = crate::intrinsics::field_offset::(); +} + +/// Expands to the field representing type of the given field. +/// +/// The container type may be a tuple, `struct`, `union` or `enum`. In the case of an enum, the +/// variant must also be specified. Only a single field is supported. +#[unstable(feature = "field_projections", issue = "145383")] +#[allow_internal_unstable(builtin_syntax)] +pub macro field_of($Container:ty, $($fields:expr)+ $(,)?) { + builtin # field_of($Container, $($fields)+) +} diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs index 3ddea90652d16..f0ffe12e13924 100644 --- a/library/core/src/intrinsics/mod.rs +++ b/library/core/src/intrinsics/mod.rs @@ -2811,6 +2811,20 @@ pub const fn align_of() -> usize; #[lang = "offset_of"] pub const fn offset_of(variant: u32, field: u32) -> usize; +/// The offset of a field queried by its field representing type. +/// +/// Returns the offset of the field represented by `F`. This function essentially does the same as +/// the [`offset_of`] intrinsic, but expects the field to be represented by a generic rather than +/// the variant and field indices. This also is a safe intrinsic and can only be evaluated at +/// compile-time, so it should only appear in constants or inline const blocks. +/// +/// There should be no need to call this intrinsic manually, as its value is used to define +/// [`Field::OFFSET`](crate::field::Field::OFFSET), which is publicly accessible. +#[rustc_intrinsic] +#[unstable(feature = "field_projections", issue = "145383")] +#[rustc_const_unstable(feature = "field_projections", issue = "145383")] +pub const fn field_offset() -> usize; + /// Returns the number of variants of the type `T` cast to a `usize`; /// if `T` has no variants, returns `0`. Uninhabited variants will be counted. /// diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 17cf6b3714f50..3b3568c3da65c 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -155,6 +155,7 @@ #![feature(extern_types)] #![feature(f16)] #![feature(f128)] +#![feature(field_projections)] #![feature(freeze_impls)] #![feature(fundamental)] #![feature(funnel_shifts)] @@ -311,6 +312,8 @@ pub mod bstr; pub mod cell; pub mod char; pub mod ffi; +#[unstable(feature = "field_projections", issue = "145383")] +pub mod field; #[unstable(feature = "core_io_borrowed_buf", issue = "117693")] pub mod io; pub mod iter; diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index dcde208fac77b..1f46866bf2301 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -497,6 +497,8 @@ pub use core::cmp; pub use core::convert; #[stable(feature = "rust1", since = "1.0.0")] pub use core::default; +#[unstable(feature = "field_projections", issue = "145383")] +pub use core::field; #[stable(feature = "futures_api", since = "1.36.0")] pub use core::future; #[stable(feature = "core_hint", since = "1.27.0")] diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index c09e17d3787e1..87bfab0ef25bb 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1808,6 +1808,14 @@ pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> T } TyKind::Slice(ty) => Slice(Box::new(clean_ty(ty, cx))), TyKind::Pat(ty, pat) => Type::Pat(Box::new(clean_ty(ty, cx)), format!("{pat:?}").into()), + TyKind::FieldOf(ty, hir::TyFieldPath { variant, field }) => { + let field_str = if let Some(variant) = variant { + format!("{variant}.{field}") + } else { + format!("{field}") + }; + Type::FRT(Box::new(clean_ty(ty, cx)), field_str.into()) + } TyKind::Array(ty, const_arg) => { // NOTE(min_const_generics): We can't use `const_eval_poly` for constants // as we currently do not supply the parent generics to anonymous constants @@ -2049,6 +2057,26 @@ pub(crate) fn clean_middle_ty<'tcx>( Box::new(clean_middle_ty(bound_ty.rebind(ty), cx, None, None)), format!("{pat:?}").into_boxed_str(), ), + ty::FRT(ty, field) => { + let field_str = match ty.kind() { + ty::Adt(def, _) => { + if def.is_enum() { + let variant = &def.variants()[field.variant]; + format!("{}.{}", variant.name, variant.fields[field.field].name) + } else { + format!("{}", def.non_enum_variant().fields[field.field].name) + } + } + ty::Tuple(_) => { + format!("{}", field.field.index()) + } + _ => bug!("unexpected ty in resolved FRT: {ty}"), + }; + Type::FRT( + Box::new(clean_middle_ty(bound_ty.rebind(ty), cx, None, None)), + field_str.into_boxed_str(), + ) + } ty::Array(ty, n) => { let n = cx.tcx.normalize_erasing_regions(cx.typing_env(), n); let n = print_const(cx, n); diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index c145929534d97..60987caab5019 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -1321,6 +1321,7 @@ pub(crate) enum Type { /// The `String` field is a stringified version of the array's length parameter. Array(Box, Box), Pat(Box, Box), + FRT(Box, Box), /// A raw pointer type: `*const i32`, `*mut i32` RawPointer(Mutability, Box), /// A reference type: `&i32`, `&'a mut Foo` @@ -1534,6 +1535,7 @@ impl Type { Slice(..) => PrimitiveType::Slice, Array(..) => PrimitiveType::Array, Type::Pat(..) => PrimitiveType::Pat, + Type::FRT(..) => PrimitiveType::FRT, RawPointer(..) => PrimitiveType::RawPointer, QPath(box QPathData { self_type, .. }) => return self_type.def_id(cache), Generic(_) | SelfTy | Infer | ImplTrait(_) | UnsafeBinder(_) => return None, @@ -1581,6 +1583,7 @@ pub(crate) enum PrimitiveType { Slice, Array, Pat, + FRT, Tuple, Unit, RawPointer, @@ -1736,6 +1739,7 @@ impl PrimitiveType { Char => sym::char, Array => sym::array, Pat => sym::pat, + FRT => sym::field_of, Slice => sym::slice, Tuple => sym::tuple, Unit => sym::unit, diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index f38a21bd1ff36..44f6374802974 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -958,6 +958,11 @@ fn fmt_type( fmt::Display::fmt(&print_type(t, cx), f)?; write!(f, " is {pat}") } + clean::Type::FRT(t, field) => { + write!(f, "field_of!(")?; + fmt::Display::fmt(&print_type(t, cx), f)?; + write!(f, ", {field})") + } clean::Array(box clean::Generic(name), n) if !f.alternate() => primitive_link( f, PrimitiveType::Array, diff --git a/src/librustdoc/html/render/search_index.rs b/src/librustdoc/html/render/search_index.rs index 30b534003da17..0dd311b073396 100644 --- a/src/librustdoc/html/render/search_index.rs +++ b/src/librustdoc/html/render/search_index.rs @@ -2041,6 +2041,7 @@ fn get_index_type_id( } // Not supported yet clean::Type::Pat(..) + | clean::Type::FRT(..) | clean::Generic(_) | clean::SelfTy | clean::ImplTrait(_) diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index 2edf7891be400..59ce937fa3002 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -579,6 +579,8 @@ impl FromClean for Type { type_: Box::new(t.into_json(renderer)), __pat_unstable_do_not_use: p.to_string(), }, + // FIXME(FRTs): implement + clean::Type::FRT(..) => todo!(), ImplTrait(g) => Type::ImplTrait(g.into_json(renderer)), Infer => Type::Infer, RawPointer(mutability, type_) => Type::RawPointer { diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index a68e9dc87ae52..db758fcc19dce 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -526,6 +526,7 @@ fn ty_to_res<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Option { ty::Tuple(tys) if tys.is_empty() => Res::Primitive(Unit), ty::Tuple(_) => Res::Primitive(Tuple), ty::Pat(..) => Res::Primitive(Pat), + ty::FRT(..) => Res::Primitive(FRT), ty::Array(..) => Res::Primitive(Array), ty::Slice(_) => Res::Primitive(Slice), ty::RawPtr(_, _) => Res::Primitive(RawPointer), diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs index 32fd4afb122e6..2bdbdfd905257 100644 --- a/src/tools/clippy/clippy_lints/src/dereference.rs +++ b/src/tools/clippy/clippy_lints/src/dereference.rs @@ -855,6 +855,7 @@ impl TyCoercionStability { | TyKind::Ptr(_) | TyKind::FnPtr(_) | TyKind::Pat(..) + | TyKind::FieldOf(..) | TyKind::Never | TyKind::Tup(_) | TyKind::Path(_) => Self::Deref, @@ -907,6 +908,7 @@ impl TyCoercionStability { | ty::Uint(_) | ty::Array(..) | ty::Pat(..) + | ty::FRT(..) | ty::Float(_) | ty::RawPtr(..) | ty::FnPtr(..) diff --git a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs index 7fb8616072a59..7d50466c86605 100644 --- a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs +++ b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs @@ -532,6 +532,7 @@ fn ast_ty_search_pat(ty: &ast::Ty) -> (Pat, Pat) { // experimental | TyKind::Pat(..) + | TyKind::FieldOf(..) // unused | TyKind::CVarArgs diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs index abc6885bef2d1..b4966071d20fd 100644 --- a/src/tools/clippy/clippy_utils/src/hir_utils.rs +++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs @@ -14,7 +14,7 @@ use rustc_hir::{ GenericParam, GenericParamKind, GenericParamSource, Generics, HirId, HirIdMap, InlineAsmOperand, ItemId, ItemKind, LetExpr, Lifetime, LifetimeKind, LifetimeParamKind, Node, ParamName, Pat, PatExpr, PatExprKind, PatField, PatKind, Path, PathSegment, PreciseCapturingArgKind, PrimTy, QPath, Stmt, StmtKind, StructTailExpr, TraitBoundModifiers, Ty, - TyKind, TyPat, TyPatKind, UseKind, WherePredicate, WherePredicateKind, + TyFieldPath, TyKind, TyPat, TyPatKind, UseKind, WherePredicate, WherePredicateKind, }; use rustc_lexer::{FrontmatterAllowed, TokenKind, tokenize}; use rustc_lint::LateContext; @@ -1529,6 +1529,13 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { self.hash_ty(ty); self.hash_ty_pat(pat); }, + TyKind::FieldOf(ty, TyFieldPath { variant, field }) => { + self.hash_ty(ty); + if let Some(variant) = variant { + self.hash_name(variant.name); + } + self.hash_name(field.name); + }, TyKind::Ptr(mut_ty) => { self.hash_ty(mut_ty.ty); mut_ty.mutbl.hash(&mut self.s); diff --git a/src/tools/rustfmt/src/types.rs b/src/tools/rustfmt/src/types.rs index 2d7bc59c62788..d040a5ca5a3d6 100644 --- a/src/tools/rustfmt/src/types.rs +++ b/src/tools/rustfmt/src/types.rs @@ -1035,6 +1035,14 @@ impl Rewrite for ast::Ty { let pat = pat.rewrite_result(context, shape)?; Ok(format!("{ty} is {pat}")) } + ast::TyKind::FieldOf(ref ty, ref variant, ref field) => { + let ty = ty.rewrite_result(context, shape)?; + if let Some(variant) = variant { + Ok(format!("field_of!({ty}, {variant}.{field})")) + } else { + Ok(format!("field_of!({ty}, {field})")) + } + } ast::TyKind::UnsafeBinder(ref binder) => { let mut result = String::new(); if binder.generic_params.is_empty() { diff --git a/tests/assembly-llvm/sparc-struct-abi.rs b/tests/assembly-llvm/sparc-struct-abi.rs index c6e83b6f8dabe..41ac2be09b653 100644 --- a/tests/assembly-llvm/sparc-struct-abi.rs +++ b/tests/assembly-llvm/sparc-struct-abi.rs @@ -9,6 +9,7 @@ #![crate_type = "lib"] #![feature(no_core, lang_items)] #![no_core] +#![feature(f128)] extern crate minicore; use minicore::*; @@ -21,8 +22,33 @@ pub struct Franta { d: f32, } +#[repr(C, packed)] +struct Misaligned(i32, f64); + +#[repr(C)] +struct AlignToMakeAssemblyShorter(T, f64); + +#[repr(C)] +pub struct Floats(i32, f32, f64, f128); + +#[repr(C)] +pub struct LessFloats(f32, i32, f64); + +#[repr(C)] +pub struct NotMisaligned(i32, Misaligned); + +#[repr(C, align(16))] +pub struct Align16(f64, i32, i32); + +impl Copy for Misaligned {} +impl Copy for AlignToMakeAssemblyShorter {} +impl Copy for Floats {} +impl Copy for LessFloats {} +impl Copy for NotMisaligned {} +impl Copy for Align16 {} + // NB: due to delay slots the `ld` following the call is actually executed before the call. -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn callee(arg: Franta) { // CHECK-LABEL: callee: // CHECK: st %f3, [[PLACE_D:.*]] @@ -54,7 +80,7 @@ extern "C" { fn tail_call_avoidance_fn(); } -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn caller() { // CHECK-LABEL: caller: // CHECK: ld [{{.*}}], %f0 @@ -62,7 +88,168 @@ pub unsafe extern "C" fn caller() { // CHECK: ld [{{.*}}], %f2 // CHECK: ld [{{.*}}], %f3 // CHECK: call opaque_callee - // CHECK: mov 3, %o2 + // CHECK: mov 3, %o2 opaque_callee(Franta { a: 1.0, b: 2.0, c: 3.0, d: 4.0 }, 3); tail_call_avoidance_fn(); } + +// Check that misaligned floats aren't promoted to floating point registers. +// CHECK-LABEL: misaligned_arg: +#[unsafe(no_mangle)] +extern "C" fn misaligned_arg(x: &mut AlignToMakeAssemblyShorter, value: Misaligned) { + // CHECK: srlx %o2, 32, %o2 + // CHECK-NEXT: stx %o1, [%o0] + // CHECK-NEXT: retl + // CHECK-NEXT: st %o2, [%o0+8] + x.0 = value; +} + +// CHECK-LABEL: misaligned_ret: +#[unsafe(no_mangle)] +extern "C" fn misaligned_ret(x: &AlignToMakeAssemblyShorter) -> Misaligned { + // CHECK: ld [%o0+8], %o1 + // CHECK-NEXT: ldx [%o0], %o0 + // CHECK-NEXT: retl + // CHECK-NEXT: sllx %o1, 32, %o1 + x.0 +} + +// Check structs where 32 >= size > 16 are promoted to register only as an argument. +// Also check that the various floating-point types are promoted to the correct registers. +// CHECK-LABEL: floats_arg: +#[unsafe(no_mangle)] +extern "C" fn floats_arg(x: &mut Floats, value: Floats) { + // CHECK: ldx [%o1+24], %o2 + // CHECK-NEXT: ldx [%o1+16], %o3 + // CHECK-NEXT: ldx [%o1+8], %o4 + // CHECK-NEXT: ldx [%o1], %o1 + // CHECK-NEXT: stx %o2, [%o0+24] + // CHECK-NEXT: stx %o3, [%o0+16] + // CHECK-NEXT: stx %o4, [%o0+8] + // CHECK-NEXT: retl + // CHECK-NEXT: stx %o1, [%o0] + *x = value; +} + +// CHECK-LABEL: floats_ret: +#[unsafe(no_mangle)] +extern "C" fn floats_ret(x: &Floats) -> Floats { + // CHECK: ld [%o0+4], %f1 + // CHECK-NEXT: ldd [%o0+8], %f2 + // CHECK-NEXT: ldd [%o0+16], %f4 + // CHECK-NEXT: ld [%o0], %o1 + // CHECK-NEXT: ldd [%o0+24], %f6 + // CHECK-NEXT: retl + // CHECK-NEXT: sllx %o1, 32, %o0 + *x +} + +// Check float promotion when passing as an argument with a struct where size <= 16. +// CHECK-LABEL: less_floats_arg: +#[unsafe(no_mangle)] +extern "C" fn less_floats_arg(x: &mut LessFloats, value: LessFloats) { + // CHECK: st %f2, [%o0] + // CHECK-NEXT: st %o1, [%o0+4] + // CHECK-NEXT: retl + // CHECK-NEXT: std %f4, [%o0+8] + *x = value; +} + +// CHECK-LABEL: less_floats_ret: +#[unsafe(no_mangle)] +extern "C" fn less_floats_ret(x: &LessFloats) -> LessFloats { + // CHECK: ld [%o0], %f0 + // CHECK-NEXT: ldd [%o0+8], %f2 + // CHECK-NEXT: retl + // CHECK-NEXT: ld [%o0+4], %o0 + *x +} + +// Check fields are promoted if they are aligned in the overall structure. +// This matches Clang's behaviour but not GCC's. +// CHECK-LABEL: not_misaligned_arg: +#[unsafe(no_mangle)] +extern "C" fn not_misaligned_arg( + x: &mut AlignToMakeAssemblyShorter, + value: NotMisaligned, +) { + // CHECK: stx %o1, [%o0] + // CHECK-NEXT: retl + // CHECK-NEXT: std %f4, [%o0+8] + x.0 = value; +} + +// CHECK-LABEL: not_misaligned_ret: +#[unsafe(no_mangle)] +extern "C" fn not_misaligned_ret(x: &AlignToMakeAssemblyShorter) -> NotMisaligned { + // CHECK: ldx [%o0], %o1 + // CHECK-NEXT: ldd [%o0+8], %f2 + // CHECK-NEXT: retl + // CHECK-NEXT: mov %o1, %o0 + x.0 +} + +// Check that 16-aligned structs are allocated the correct registers. +// CHECK-LABEL: align_16_arg: +#[unsafe(no_mangle)] +extern "C" fn align_16_arg(x: &mut Align16, value: Align16) { + // CHECK: std %f4, [%o0] + // CHECK-NEXT: retl + // CHECK-NEXT: stx %o3, [%o0+8] + *x = value; +} + +// CHECK-LABEL: align_16_ret: +#[unsafe(no_mangle)] +extern "C" fn align_16_ret(x: &Align16) -> Align16 { + // CHECK: ldd [%o0], %f0 + // CHECK-NEXT: retl + // CHECK-NEXT: ldx [%o0+8], %o1 + *x +} + +// Check ZST args don't prevent further arguments from being processed. +// CHECK-LABEL: zst_arg: +#[unsafe(no_mangle)] +extern "C" fn zst_arg(_: (), value: LessFloats, x: &mut LessFloats) { + // CHECK: st %f0, [%o2] + // CHECK-NEXT: st %o0, [%o2+4] + // CHECK-NEXT: retl + // CHECK-NEXT: std %f2, [%o2+8] + *x = value; +} + +#[repr(C)] +struct I32F32Input { + a: i32, + b: f32, +} + +#[repr(C)] +struct I32F32Output { + b: f32, + a: i32, +} + +// The clang/LLVM implementation mentions that this case requires special handling. +// CHECK-LABEL: i32_f32: +#[unsafe(no_mangle)] +extern "C" fn i32_f32(input: I32F32Input) -> I32F32Output { + // CHECK: srlx %o0, 32, %o0 + // CHECK-NEXT: fmovs %f1, %f0 + // CHECK-NEXT: retl + // CHECK-NEXT: nop + I32F32Output { a: input.a, b: input.b } +} + +#[repr(C)] +pub struct C { + a: f64, + b: f32, +} + +// regression test for https://github.com/rust-lang/rust/issues/147883. +#[unsafe(no_mangle)] +pub extern "C" fn foo(c: C) -> C { + c +} diff --git a/tests/codegen-llvm/cast-target-abi.rs b/tests/codegen-llvm/cast-target-abi.rs index 101e73e33c915..6f1ab4572ee0d 100644 --- a/tests/codegen-llvm/cast-target-abi.rs +++ b/tests/codegen-llvm/cast-target-abi.rs @@ -119,7 +119,7 @@ pub extern "C" fn returns_twou16s() -> TwoU16s { // aarch64-SAME: ([[ABI_TYPE:\[2 x i64\]]] {{.*}}[[ABI_VALUE:%.+]]) // loongarch64-SAME: ([[ABI_TYPE:\[2 x i64\]]] {{.*}}[[ABI_VALUE:%.+]]) // powerpc64-SAME: ([[ABI_TYPE:\[2 x i64\]]] {{.*}}[[ABI_VALUE:%.+]]) -// sparc64-SAME: ([[ABI_TYPE:\[2 x i64\]]] {{.*}}[[ABI_VALUE:%.+]]) +// sparc64-SAME: ([[ABI_TYPE:{ i64, i64 }]] {{.*}}[[ABI_VALUE:%.+]]) // x86_64-SAME: ([[ABI_TYPE:{ i64, i16 }]] {{.*}}[[ABI_VALUE:%.+]]) #[no_mangle] #[inline(never)] @@ -148,7 +148,7 @@ pub extern "C" fn returns_fiveu16s() -> FiveU16s { // aarch64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] // loongarch64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - // sparc64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + // sparc64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:{ i64, i64 }]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] // x86_64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:{ i64, i16 }]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] // aarch64: ret [[ABI_TYPE]] [[ABI_VALUE]] @@ -217,7 +217,7 @@ pub extern "C" fn returns_doubledouble() -> DoubleDouble { // aarch64-SAME: ([[ABI_TYPE:\[2 x i64\]]] {{.*}}[[ABI_VALUE:%.+]]) // loongarch64-SAME: ([[ABI_TYPE:\[2 x i64\]]] {{.*}}[[ABI_VALUE:%.+]]) // powerpc64-SAME: ([[ABI_TYPE:\[2 x i64\]]] {{.*}}[[ABI_VALUE:%.+]]) -// sparc64-SAME: ([[ABI_TYPE:\[2 x i64\]]] {{.*}}[[ABI_VALUE:%.+]]) +// sparc64-SAME: ([[ABI_TYPE:{ i64, i64 }]] {{.*}}[[ABI_VALUE:%.+]]) // x86_64-SAME: ([[ABI_TYPE:{ i64, i32 }]] {{.*}}[[ABI_VALUE:%.+]]) #[no_mangle] #[inline(never)] @@ -246,7 +246,7 @@ pub extern "C" fn returns_three32s() -> Three32s { // aarch64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] // loongarch64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - // sparc64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + // sparc64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:{ i64, i64 }]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] // x86_64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:{ i64, i32 }]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] // aarch64: ret [[ABI_TYPE]] [[ABI_VALUE]] @@ -399,7 +399,7 @@ pub fn call_fiveu16s() { // aarch64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] // loongarch64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] // powerpc64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - // sparc64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + // sparc64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:{ i64, i64 }]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] // x86_64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:{ i64, i16 }]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] // CHECK: call void @receives_fiveu16s([[ABI_TYPE]] [[ABI_VALUE]]) @@ -424,7 +424,7 @@ pub fn return_fiveu16s() -> FiveU16s { // aarch64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE:\[2 x i64\]]] @returns_fiveu16s() // loongarch64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE:\[2 x i64\]]] @returns_fiveu16s() - // sparc64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE:\[2 x i64\]]] @returns_fiveu16s() + // sparc64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE:{ i64, i64 }]] @returns_fiveu16s() // x86_64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE:{ i64, i16 }]] @returns_fiveu16s() // aarch64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] @@ -595,7 +595,7 @@ pub fn call_three32s() { // aarch64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] // loongarch64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] // powerpc64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - // sparc64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + // sparc64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:{ i64, i64 }]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] // x86_64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:{ i64, i32 }]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] // CHECK: call void @receives_three32s([[ABI_TYPE]] [[ABI_VALUE]]) @@ -619,7 +619,7 @@ pub fn return_three32s() -> Three32s { // aarch64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE:\[2 x i64\]]] @returns_three32s() // loongarch64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE:\[2 x i64\]]] @returns_three32s() - // sparc64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE:\[2 x i64\]]] @returns_three32s() + // sparc64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE:{ i64, i64 }]] @returns_three32s() // x86_64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE:{ i64, i32 }]] @returns_three32s() // aarch64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] diff --git a/tests/debuginfo/function-names.rs b/tests/debuginfo/function-names.rs index e2f106e565439..abba8814c6663 100644 --- a/tests/debuginfo/function-names.rs +++ b/tests/debuginfo/function-names.rs @@ -39,7 +39,7 @@ // Const generic parameter //@ gdb-command:info functions -q function_names::const_generic_fn.* //@ gdb-check:[...]static fn function_names::const_generic_fn_bool(); -//@ gdb-check:[...]static fn function_names::const_generic_fn_non_int<{CONST#ffa3db4ca1d52dce}>(); +//@ gdb-check:[...]static fn function_names::const_generic_fn_non_int<{CONST#5177fe61e1757625}>(); //@ gdb-check:[...]static fn function_names::const_generic_fn_signed_int<-7>(); //@ gdb-check:[...]static fn function_names::const_generic_fn_unsigned_int<14>(); @@ -85,6 +85,7 @@ use std::ops::Coroutine; use std::pin::Pin; + use Mod1::TestTrait2; fn main() { diff --git a/tests/rustdoc-html/type-layout.rs b/tests/rustdoc-html/type-layout.rs index 482b8b597dd30..84d2aa8060079 100644 --- a/tests/rustdoc-html/type-layout.rs +++ b/tests/rustdoc-html/type-layout.rs @@ -64,6 +64,12 @@ pub type GenericTypeAlias = (Generic<(u32, ())>, Generic); //@ hasraw type_layout/type.Edges.html 'Unable to compute type layout, possibly due to this type having generic parameters. Layout can only be computed for concrete, fully-instantiated types.' pub type Edges<'a, E> = std::borrow::Cow<'a, [E]>; +pub trait Project { type Assoc; } +// We can't compute layout as the alias stays rigid. A `LayoutError::TooGeneric` is returned. +//@ hasraw type_layout/struct.RigidAlias.html 'Unable to compute type layout, possibly due to this type having generic parameters. Layout can only be computed for concrete, fully-instantiated types.' +//@ !hasraw - 'Size: ' +pub struct RigidAlias(<() as Project>::Assoc) where for<'a> (): Project; + //@ !hasraw type_layout/trait.MyTrait.html 'Size: ' pub trait MyTrait {} @@ -92,9 +98,3 @@ pub enum Uninhabited {} //@ hasraw type_layout/struct.Uninhabited2.html 'Size: ' //@ hasraw - '8 bytes (uninhabited)' pub struct Uninhabited2(std::convert::Infallible, u64); - -pub trait Project { type Assoc; } -// We can't compute layout. A `LayoutError::Unknown` is returned. -//@ hasraw type_layout/struct.Unknown.html 'Unable to compute type layout.' -//@ !hasraw - 'Size: ' -pub struct Unknown(<() as Project>::Assoc) where for<'a> (): Project; diff --git a/tests/ui/README.md b/tests/ui/README.md index 237cfb9c4f071..164e60c0237b6 100644 --- a/tests/ui/README.md +++ b/tests/ui/README.md @@ -611,6 +611,12 @@ See: - [`ffi_const` | The Unstable book](https://doc.rust-lang.org/unstable-book/language-features/ffi-const.html) - [`ffi_pure` | The Unstable book](https://doc.rust-lang.org/beta/unstable-book/language-features/ffi-pure.html) +## `tests/ui/field_representing_types`: `#![feature(field_projections)]` + +Tests for field representing types `field_of!(Struct, field)`. + +See: [Tracking Issue for Field Projections #145383](https://github.com/rust-lang/rust/issues/145383) + ## `tests/ui/float` See: [Tracking Issue for `f16` and `f128` float types #116909](https://github.com/rust-lang/rust/issues/116909) diff --git a/tests/ui/attributes/ambiguous_derive_helpers.rs b/tests/ui/attributes/ambiguous_derive_helpers.rs new file mode 100644 index 0000000000000..aee498a7067a5 --- /dev/null +++ b/tests/ui/attributes/ambiguous_derive_helpers.rs @@ -0,0 +1,15 @@ +//@ force-host +//@ no-prefer-dynamic + +#![crate_type = "proc-macro"] +#![deny(ambiguous_derive_helpers)] + +extern crate proc_macro; + +use proc_macro::TokenStream; + +#[proc_macro_derive(Trait, attributes(ignore))] //~ ERROR there exists a built-in attribute with the same name +//~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! +pub fn deriving(input: TokenStream) -> TokenStream { + TokenStream::new() +} diff --git a/tests/ui/attributes/ambiguous_derive_helpers.stderr b/tests/ui/attributes/ambiguous_derive_helpers.stderr new file mode 100644 index 0000000000000..a1eb8d172c25f --- /dev/null +++ b/tests/ui/attributes/ambiguous_derive_helpers.stderr @@ -0,0 +1,16 @@ +error: there exists a built-in attribute with the same name + --> $DIR/ambiguous_derive_helpers.rs:11:39 + | +LL | #[proc_macro_derive(Trait, attributes(ignore))] + | ^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #151276 +note: the lint level is defined here + --> $DIR/ambiguous_derive_helpers.rs:5:9 + | +LL | #![deny(ambiguous_derive_helpers)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/cast/fat-ptr-cast.stderr b/tests/ui/cast/fat-ptr-cast.stderr index 2b0bceebf15ca..c6354122f5685 100644 --- a/tests/ui/cast/fat-ptr-cast.stderr +++ b/tests/ui/cast/fat-ptr-cast.stderr @@ -81,6 +81,8 @@ LL | let s = 0 as *const T; | - ^^^^^^^^ creating a `*const T` requires both an address and type-specific metadata | | | consider casting this expression to `*const ()`, then using `core::ptr::from_raw_parts` + | + = note: the type parameter `T` is not known to be `Sized`, so this pointer may be wide error: aborting due to 11 previous errors diff --git a/tests/ui/error-codes/E0116.stderr b/tests/ui/error-codes/E0116.stderr index 1ea5a57f46db1..20e3b196226af 100644 --- a/tests/ui/error-codes/E0116.stderr +++ b/tests/ui/error-codes/E0116.stderr @@ -4,7 +4,8 @@ error[E0116]: cannot define inherent `impl` for a type outside of the crate wher LL | impl Vec {} | ^^^^^^^^^^^^ impl for type defined outside of crate | - = note: define and implement a trait or new type instead + = help: consider defining a trait and implementing it for the type or using a newtype wrapper like `struct MyType(ExternalType);` and implement it + = note: for more details about the orphan rules, see error: aborting due to 1 previous error diff --git a/tests/ui/feature-gates/feature-gate-field-projections.rs b/tests/ui/feature-gates/feature-gate-field-projections.rs new file mode 100644 index 0000000000000..5fa6b1ea30810 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-field-projections.rs @@ -0,0 +1,21 @@ +#![allow(dead_code)] + +use std::field::{Field, field_of}; //~ ERROR: use of unstable library feature `field_projections` [E0658] +//~^ ERROR: use of unstable library feature `field_projections` [E0658] +use std::ptr; + +fn project_ref( + //~^ ERROR: use of unstable library feature `field_projections` [E0658] + r: &F::Base, //~ ERROR: use of unstable library feature `field_projections` [E0658] +) -> &F::Type +//~^ ERROR: use of unstable library feature `field_projections` [E0658] +where + F::Type: Sized, //~ ERROR: use of unstable library feature `field_projections` [E0658] +{ + unsafe { &*ptr::from_ref(r).byte_add(F::OFFSET).cast() } //~ ERROR: use of unstable library feature `field_projections` [E0658] +} + +fn main() { + struct Foo(()); + let _ = project_ref::(&Foo(())); //~ ERROR: use of unstable library feature `field_projections` [E0658] +} diff --git a/tests/ui/feature-gates/feature-gate-field-projections.stderr b/tests/ui/feature-gates/feature-gate-field-projections.stderr new file mode 100644 index 0000000000000..01074d49fa862 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-field-projections.stderr @@ -0,0 +1,83 @@ +error[E0658]: use of unstable library feature `field_projections` + --> $DIR/feature-gate-field-projections.rs:20:27 + | +LL | let _ = project_ref::(&Foo(())); + | ^^^^^^^^ + | + = note: see issue #145383 for more information + = help: add `#![feature(field_projections)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: use of unstable library feature `field_projections` + --> $DIR/feature-gate-field-projections.rs:3:18 + | +LL | use std::field::{Field, field_of}; + | ^^^^^ + | + = note: see issue #145383 for more information + = help: add `#![feature(field_projections)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: use of unstable library feature `field_projections` + --> $DIR/feature-gate-field-projections.rs:3:25 + | +LL | use std::field::{Field, field_of}; + | ^^^^^^^^ + | + = note: see issue #145383 for more information + = help: add `#![feature(field_projections)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: use of unstable library feature `field_projections` + --> $DIR/feature-gate-field-projections.rs:7:19 + | +LL | fn project_ref( + | ^^^^^ + | + = note: see issue #145383 for more information + = help: add `#![feature(field_projections)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: use of unstable library feature `field_projections` + --> $DIR/feature-gate-field-projections.rs:13:5 + | +LL | F::Type: Sized, + | ^^^^^^^ + | + = note: see issue #145383 for more information + = help: add `#![feature(field_projections)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: use of unstable library feature `field_projections` + --> $DIR/feature-gate-field-projections.rs:9:9 + | +LL | r: &F::Base, + | ^^^^^^^ + | + = note: see issue #145383 for more information + = help: add `#![feature(field_projections)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: use of unstable library feature `field_projections` + --> $DIR/feature-gate-field-projections.rs:10:7 + | +LL | ) -> &F::Type + | ^^^^^^^ + | + = note: see issue #145383 for more information + = help: add `#![feature(field_projections)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: use of unstable library feature `field_projections` + --> $DIR/feature-gate-field-projections.rs:15:42 + | +LL | unsafe { &*ptr::from_ref(r).byte_add(F::OFFSET).cast() } + | ^^^^^^^^^ + | + = note: see issue #145383 for more information + = help: add `#![feature(field_projections)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 8 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/field_representing_types/auxiliary/extern-crate.rs b/tests/ui/field_representing_types/auxiliary/extern-crate.rs new file mode 100644 index 0000000000000..8e7e6d2679b44 --- /dev/null +++ b/tests/ui/field_representing_types/auxiliary/extern-crate.rs @@ -0,0 +1,6 @@ +pub struct Point { + pub x: usize, + pub y: usize, +} + +pub trait ForeignTrait {} diff --git a/tests/ui/field_representing_types/incoherent-impl.next.stderr b/tests/ui/field_representing_types/incoherent-impl.next.stderr new file mode 100644 index 0000000000000..8e5450eb47bcb --- /dev/null +++ b/tests/ui/field_representing_types/incoherent-impl.next.stderr @@ -0,0 +1,27 @@ +error[E0117]: only traits defined in the current crate can be implemented for arbitrary types + --> $DIR/incoherent-impl.rs:22:1 + | +LL | impl ForeignTrait for field_of!(Point, x) {} + | ^^^^^^^^^^^^^^^^^^^^^^------------------- + | | + | `Point` is not defined in the current crate + | + = note: impl doesn't have any local type before any uncovered type parameters + = note: for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules + = note: define and implement a trait or new type instead + +error[E0117]: only traits defined in the current crate can be implemented for arbitrary types + --> $DIR/incoherent-impl.rs:25:1 + | +LL | impl ForeignTrait for field_of!((usize, usize), 0) {} + | ^^^^^^^^^^^^^^^^^^^^^^---------------------------- + | | + | this is not defined in the current crate because tuples are always foreign + | + = note: impl doesn't have any local type before any uncovered type parameters + = note: for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules + = note: define and implement a trait or new type instead + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0117`. diff --git a/tests/ui/field_representing_types/incoherent-impl.old.stderr b/tests/ui/field_representing_types/incoherent-impl.old.stderr new file mode 100644 index 0000000000000..8e5450eb47bcb --- /dev/null +++ b/tests/ui/field_representing_types/incoherent-impl.old.stderr @@ -0,0 +1,27 @@ +error[E0117]: only traits defined in the current crate can be implemented for arbitrary types + --> $DIR/incoherent-impl.rs:22:1 + | +LL | impl ForeignTrait for field_of!(Point, x) {} + | ^^^^^^^^^^^^^^^^^^^^^^------------------- + | | + | `Point` is not defined in the current crate + | + = note: impl doesn't have any local type before any uncovered type parameters + = note: for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules + = note: define and implement a trait or new type instead + +error[E0117]: only traits defined in the current crate can be implemented for arbitrary types + --> $DIR/incoherent-impl.rs:25:1 + | +LL | impl ForeignTrait for field_of!((usize, usize), 0) {} + | ^^^^^^^^^^^^^^^^^^^^^^---------------------------- + | | + | this is not defined in the current crate because tuples are always foreign + | + = note: impl doesn't have any local type before any uncovered type parameters + = note: for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules + = note: define and implement a trait or new type instead + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0117`. diff --git a/tests/ui/field_representing_types/incoherent-impl.rs b/tests/ui/field_representing_types/incoherent-impl.rs new file mode 100644 index 0000000000000..38969222f66d1 --- /dev/null +++ b/tests/ui/field_representing_types/incoherent-impl.rs @@ -0,0 +1,28 @@ +//@ revisions: old next +//@ [next] compile-flags: -Znext-solver +//@ aux-build:extern-crate.rs +#![expect(incomplete_features)] +#![feature(field_projections)] +extern crate extern_crate; + +use std::field::field_of; + +use extern_crate::{ForeignTrait, Point}; + +pub trait MyTrait {} + +impl MyTrait for field_of!(Point, x) {} +impl MyTrait for field_of!(Player, pos) {} +impl MyTrait for field_of!((usize, usize), 0) {} + +pub struct Player { + pos: Point, +} + +impl ForeignTrait for field_of!(Point, x) {} +//~^ ERROR: only traits defined in the current crate can be implemented for arbitrary types [E0117] +impl ForeignTrait for field_of!(Player, pos) {} +impl ForeignTrait for field_of!((usize, usize), 0) {} +//~^ ERROR: only traits defined in the current crate can be implemented for arbitrary types [E0117] + +fn main() {} diff --git a/tests/ui/field_representing_types/invalid.next.stderr b/tests/ui/field_representing_types/invalid.next.stderr new file mode 100644 index 0000000000000..2a5e884a5e3f9 --- /dev/null +++ b/tests/ui/field_representing_types/invalid.next.stderr @@ -0,0 +1,71 @@ +error: unexpected end of macro invocation + --> $DIR/invalid.rs:23:28 + | +LL | let _: field_of!(Struct); + | ^ missing tokens in macro arguments + | +note: while trying to match `,` + --> $SRC_DIR/core/src/field.rs:LL:COL + +error: unexpected end of macro invocation + --> $DIR/invalid.rs:24:29 + | +LL | let _: field_of!(Struct,); + | ^ missing tokens in macro arguments + | +note: while trying to match meta-variable `$fields:expr` + --> $SRC_DIR/core/src/field.rs:LL:COL + +error: no rules expected `extra` + --> $DIR/invalid.rs:25:37 + | +LL | let _: field_of!(Struct, field, extra); + | ^^^^^ no rules expected this token in macro call + | + = note: while trying to match sequence end + +error: offset_of expects dot-separated field and variant names + --> $DIR/invalid.rs:27:28 + | +LL | let _: field_of!(Enum, Variant..field); + | ^^^^^^^^^^^^^^ + +error: `field_of!` expects dot-separated field and variant names + --> $DIR/invalid.rs:27:12 + | +LL | let _: field_of!(Enum, Variant..field); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | in this macro invocation + | this macro call doesn't expand to a type + | + = note: this error originates in the macro `field_of` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: offset_of expects dot-separated field and variant names + --> $DIR/invalid.rs:29:30 + | +LL | let _: field_of!(Struct, [42]); + | ^^^^ + +error: `field_of!` expects dot-separated field and variant names + --> $DIR/invalid.rs:29:12 + | +LL | let _: field_of!(Struct, [42]); + | ^^^^^^^^^^^^^^^^^^^^^^^ + | | + | in this macro invocation + | this macro call doesn't expand to a type + | + = note: this error originates in the macro `field_of` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: `field_of!` only supports a single field or a variant with a field + --> $DIR/invalid.rs:31:30 + | +LL | let _: field_of!(Struct, field1.field2.field3); + | ------------------^^^^^^-^^^^^^-^^^^^^- + | | + | in this macro invocation + | this macro call doesn't expand to a type + +error: aborting due to 8 previous errors + diff --git a/tests/ui/field_representing_types/invalid.old.stderr b/tests/ui/field_representing_types/invalid.old.stderr new file mode 100644 index 0000000000000..2a5e884a5e3f9 --- /dev/null +++ b/tests/ui/field_representing_types/invalid.old.stderr @@ -0,0 +1,71 @@ +error: unexpected end of macro invocation + --> $DIR/invalid.rs:23:28 + | +LL | let _: field_of!(Struct); + | ^ missing tokens in macro arguments + | +note: while trying to match `,` + --> $SRC_DIR/core/src/field.rs:LL:COL + +error: unexpected end of macro invocation + --> $DIR/invalid.rs:24:29 + | +LL | let _: field_of!(Struct,); + | ^ missing tokens in macro arguments + | +note: while trying to match meta-variable `$fields:expr` + --> $SRC_DIR/core/src/field.rs:LL:COL + +error: no rules expected `extra` + --> $DIR/invalid.rs:25:37 + | +LL | let _: field_of!(Struct, field, extra); + | ^^^^^ no rules expected this token in macro call + | + = note: while trying to match sequence end + +error: offset_of expects dot-separated field and variant names + --> $DIR/invalid.rs:27:28 + | +LL | let _: field_of!(Enum, Variant..field); + | ^^^^^^^^^^^^^^ + +error: `field_of!` expects dot-separated field and variant names + --> $DIR/invalid.rs:27:12 + | +LL | let _: field_of!(Enum, Variant..field); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | in this macro invocation + | this macro call doesn't expand to a type + | + = note: this error originates in the macro `field_of` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: offset_of expects dot-separated field and variant names + --> $DIR/invalid.rs:29:30 + | +LL | let _: field_of!(Struct, [42]); + | ^^^^ + +error: `field_of!` expects dot-separated field and variant names + --> $DIR/invalid.rs:29:12 + | +LL | let _: field_of!(Struct, [42]); + | ^^^^^^^^^^^^^^^^^^^^^^^ + | | + | in this macro invocation + | this macro call doesn't expand to a type + | + = note: this error originates in the macro `field_of` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: `field_of!` only supports a single field or a variant with a field + --> $DIR/invalid.rs:31:30 + | +LL | let _: field_of!(Struct, field1.field2.field3); + | ------------------^^^^^^-^^^^^^-^^^^^^- + | | + | in this macro invocation + | this macro call doesn't expand to a type + +error: aborting due to 8 previous errors + diff --git a/tests/ui/field_representing_types/invalid.rs b/tests/ui/field_representing_types/invalid.rs new file mode 100644 index 0000000000000..d1fc217db7ddd --- /dev/null +++ b/tests/ui/field_representing_types/invalid.rs @@ -0,0 +1,32 @@ +//@ revisions: old next +//@ [next] compile-flags: -Znext-solver +#![expect(incomplete_features)] +#![feature(field_projections)] + +use std::field::field_of; + +pub struct Struct { + field: i32, +} + +pub union Union { + field: i32, +} + +pub enum Enum { + Variant { field: i32 }, +} + +pub trait Trait {} + +fn main() { + let _: field_of!(Struct); //~ ERROR: unexpected end of macro invocation + let _: field_of!(Struct,); //~ ERROR: unexpected end of macro invocation + let _: field_of!(Struct, field, extra); //~ ERROR: no rules expected `extra` + // FIXME(FRTs): adjust error message to mention `field_of!` & prevent double errors + let _: field_of!(Enum, Variant..field); //~ ERROR: offset_of expects dot-separated field and variant names + //~^ ERROR: `field_of!` expects dot-separated field and variant names + let _: field_of!(Struct, [42]); //~ ERROR: offset_of expects dot-separated field and variant names + //~^ ERROR: `field_of!` expects dot-separated field and variant names + let _: field_of!(Struct, field1.field2.field3); //~ ERROR: `field_of!` only supports a single field or a variant with a field +} diff --git a/tests/ui/field_representing_types/non-struct.next.stderr b/tests/ui/field_representing_types/non-struct.next.stderr new file mode 100644 index 0000000000000..7a6c33c3b6f54 --- /dev/null +++ b/tests/ui/field_representing_types/non-struct.next.stderr @@ -0,0 +1,27 @@ +error[E0277]: the trait bound `field_of!(MyUnion, field): std::field::Field` is not satisfied + --> $DIR/non-struct.rs:22:20 + | +LL | assert_field::(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ the nightly-only, unstable trait `std::field::Field` is not implemented for `field_of!(MyUnion, field)` + | +note: required by a bound in `assert_field` + --> $DIR/non-struct.rs:18:20 + | +LL | fn assert_field() {} + | ^^^^^ required by this bound in `assert_field` + +error[E0277]: the trait bound `field_of!(MyEnum, A.a): std::field::Field` is not satisfied + --> $DIR/non-struct.rs:25:20 + | +LL | assert_field::(); + | ^^^^^^^^^^^^^^^^^^^^^^ the nightly-only, unstable trait `std::field::Field` is not implemented for `field_of!(MyEnum, A.a)` + | +note: required by a bound in `assert_field` + --> $DIR/non-struct.rs:18:20 + | +LL | fn assert_field() {} + | ^^^^^ required by this bound in `assert_field` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/field_representing_types/non-struct.old.stderr b/tests/ui/field_representing_types/non-struct.old.stderr new file mode 100644 index 0000000000000..7a6c33c3b6f54 --- /dev/null +++ b/tests/ui/field_representing_types/non-struct.old.stderr @@ -0,0 +1,27 @@ +error[E0277]: the trait bound `field_of!(MyUnion, field): std::field::Field` is not satisfied + --> $DIR/non-struct.rs:22:20 + | +LL | assert_field::(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ the nightly-only, unstable trait `std::field::Field` is not implemented for `field_of!(MyUnion, field)` + | +note: required by a bound in `assert_field` + --> $DIR/non-struct.rs:18:20 + | +LL | fn assert_field() {} + | ^^^^^ required by this bound in `assert_field` + +error[E0277]: the trait bound `field_of!(MyEnum, A.a): std::field::Field` is not satisfied + --> $DIR/non-struct.rs:25:20 + | +LL | assert_field::(); + | ^^^^^^^^^^^^^^^^^^^^^^ the nightly-only, unstable trait `std::field::Field` is not implemented for `field_of!(MyEnum, A.a)` + | +note: required by a bound in `assert_field` + --> $DIR/non-struct.rs:18:20 + | +LL | fn assert_field() {} + | ^^^^^ required by this bound in `assert_field` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/field_representing_types/non-struct.rs b/tests/ui/field_representing_types/non-struct.rs new file mode 100644 index 0000000000000..50fd4b0e6b0e7 --- /dev/null +++ b/tests/ui/field_representing_types/non-struct.rs @@ -0,0 +1,27 @@ +//@ revisions: old next +//@ [next] compile-flags: -Znext-solver +#![expect(incomplete_features)] +#![feature(field_projections)] + +use std::field::{Field, field_of}; + +pub union MyUnion { + field: u32, + other: i32, +} + +pub enum MyEnum { + A { a: i32, b: i64 }, + B { x: i64, y: i32 }, +} + +fn assert_field() {} + +fn main() { + // FIXME(FRTs): improve this error message, point to the `union`. + assert_field::(); + //~^ ERROR: the trait bound `field_of!(MyUnion, field): std::field::Field` is not satisfied [E0277] + // FIXME(FRTs): improve this error message, point to the `enum`. + assert_field::(); + //~^ ERROR: the trait bound `field_of!(MyEnum, A.a): std::field::Field` is not satisfied [E0277] +} diff --git a/tests/ui/field_representing_types/nonexistent.next.stderr b/tests/ui/field_representing_types/nonexistent.next.stderr new file mode 100644 index 0000000000000..76026ab4a496f --- /dev/null +++ b/tests/ui/field_representing_types/nonexistent.next.stderr @@ -0,0 +1,124 @@ +error[E0573]: expected type, found function `main` + --> $DIR/nonexistent.rs:43:22 + | +LL | let _: field_of!(main, field); + | ^^^^ not a type + +error[E0609]: no field `other` on type `Struct` + --> $DIR/nonexistent.rs:23:30 + | +LL | let _: field_of!(Struct, other); + | ^^^^^ + +error[E0609]: no field `0` on type `Struct` + --> $DIR/nonexistent.rs:24:30 + | +LL | let _: field_of!(Struct, 0); + | ^ + +error[E0609]: no field `other` on type `Union` + --> $DIR/nonexistent.rs:25:29 + | +LL | let _: field_of!(Union, other); + | ^^^^^ + +error[E0609]: no field `0` on type `Union` + --> $DIR/nonexistent.rs:26:29 + | +LL | let _: field_of!(Union, 0); + | ^ + +error[E0609]: no field `other` on type `Enum` + --> $DIR/nonexistent.rs:28:36 + | +LL | let _: field_of!(Enum, Variant.other); + | ^^^^^ + +error[E0609]: no field `0` on type `Enum` + --> $DIR/nonexistent.rs:29:36 + | +LL | let _: field_of!(Enum, Variant.0); + | ^ + +error[E0599]: no variant named `OtherVariant` found for enum `Enum` + --> $DIR/nonexistent.rs:31:28 + | +LL | let _: field_of!(Enum, OtherVariant.field); + | ^^^^^^^^^^^^ + +error[E0599]: no variant named `OtherVariant` found for enum `Enum` + --> $DIR/nonexistent.rs:32:28 + | +LL | let _: field_of!(Enum, OtherVariant.0); + | ^^^^^^^^^^^^ + +error[E0609]: no field `2` on type `((), ())` + --> $DIR/nonexistent.rs:33:32 + | +LL | let _: field_of!(((), ()), 2); + | ^ + +error[E0609]: no field `field` on type `((), ())` + --> $DIR/nonexistent.rs:34:32 + | +LL | let _: field_of!(((), ()), field); + | ^^^^^ + +error: type `i32` doesn't have fields + --> $DIR/nonexistent.rs:36:22 + | +LL | let _: field_of!(i32, field); + | ^^^ + +error: type `[Struct]` doesn't have fields + --> $DIR/nonexistent.rs:37:22 + | +LL | let _: field_of!([Struct], field); + | ^^^^^^^^ + +error: type `[Struct; 42]` is not yet supported in `field_of!` + --> $DIR/nonexistent.rs:38:22 + | +LL | let _: field_of!([Struct; 42], field); + | ^^^^^^^^^^^^ + +error: type `&'static Struct` doesn't have fields + --> $DIR/nonexistent.rs:39:22 + | +LL | let _: field_of!(&'static Struct, field); + | ^^^^^^^^^^^^^^^ + +error: type `*const Struct` doesn't have fields + --> $DIR/nonexistent.rs:40:22 + | +LL | let _: field_of!(*const Struct, field); + | ^^^^^^^^^^^^^ + +error: type `fn() -> Struct` doesn't have fields + --> $DIR/nonexistent.rs:41:22 + | +LL | let _: field_of!(fn() -> Struct, field); + | ^^^^^^^^^^^^^^ + +error: type `dyn Trait` doesn't have fields + --> $DIR/nonexistent.rs:42:22 + | +LL | let _: field_of!(dyn Trait, field); + | ^^^^^^^^^ + +error: cannot use `_` in this position + --> $DIR/nonexistent.rs:44:22 + | +LL | let _: field_of!(_, field); + | ^ + +error: type `T` doesn't have fields + --> $DIR/nonexistent.rs:48:22 + | +LL | let _: field_of!(T, field); + | ^ + +error: aborting due to 20 previous errors + +Some errors have detailed explanations: E0573, E0599, E0609. +For more information about an error, try `rustc --explain E0573`. diff --git a/tests/ui/field_representing_types/nonexistent.old.stderr b/tests/ui/field_representing_types/nonexistent.old.stderr new file mode 100644 index 0000000000000..76026ab4a496f --- /dev/null +++ b/tests/ui/field_representing_types/nonexistent.old.stderr @@ -0,0 +1,124 @@ +error[E0573]: expected type, found function `main` + --> $DIR/nonexistent.rs:43:22 + | +LL | let _: field_of!(main, field); + | ^^^^ not a type + +error[E0609]: no field `other` on type `Struct` + --> $DIR/nonexistent.rs:23:30 + | +LL | let _: field_of!(Struct, other); + | ^^^^^ + +error[E0609]: no field `0` on type `Struct` + --> $DIR/nonexistent.rs:24:30 + | +LL | let _: field_of!(Struct, 0); + | ^ + +error[E0609]: no field `other` on type `Union` + --> $DIR/nonexistent.rs:25:29 + | +LL | let _: field_of!(Union, other); + | ^^^^^ + +error[E0609]: no field `0` on type `Union` + --> $DIR/nonexistent.rs:26:29 + | +LL | let _: field_of!(Union, 0); + | ^ + +error[E0609]: no field `other` on type `Enum` + --> $DIR/nonexistent.rs:28:36 + | +LL | let _: field_of!(Enum, Variant.other); + | ^^^^^ + +error[E0609]: no field `0` on type `Enum` + --> $DIR/nonexistent.rs:29:36 + | +LL | let _: field_of!(Enum, Variant.0); + | ^ + +error[E0599]: no variant named `OtherVariant` found for enum `Enum` + --> $DIR/nonexistent.rs:31:28 + | +LL | let _: field_of!(Enum, OtherVariant.field); + | ^^^^^^^^^^^^ + +error[E0599]: no variant named `OtherVariant` found for enum `Enum` + --> $DIR/nonexistent.rs:32:28 + | +LL | let _: field_of!(Enum, OtherVariant.0); + | ^^^^^^^^^^^^ + +error[E0609]: no field `2` on type `((), ())` + --> $DIR/nonexistent.rs:33:32 + | +LL | let _: field_of!(((), ()), 2); + | ^ + +error[E0609]: no field `field` on type `((), ())` + --> $DIR/nonexistent.rs:34:32 + | +LL | let _: field_of!(((), ()), field); + | ^^^^^ + +error: type `i32` doesn't have fields + --> $DIR/nonexistent.rs:36:22 + | +LL | let _: field_of!(i32, field); + | ^^^ + +error: type `[Struct]` doesn't have fields + --> $DIR/nonexistent.rs:37:22 + | +LL | let _: field_of!([Struct], field); + | ^^^^^^^^ + +error: type `[Struct; 42]` is not yet supported in `field_of!` + --> $DIR/nonexistent.rs:38:22 + | +LL | let _: field_of!([Struct; 42], field); + | ^^^^^^^^^^^^ + +error: type `&'static Struct` doesn't have fields + --> $DIR/nonexistent.rs:39:22 + | +LL | let _: field_of!(&'static Struct, field); + | ^^^^^^^^^^^^^^^ + +error: type `*const Struct` doesn't have fields + --> $DIR/nonexistent.rs:40:22 + | +LL | let _: field_of!(*const Struct, field); + | ^^^^^^^^^^^^^ + +error: type `fn() -> Struct` doesn't have fields + --> $DIR/nonexistent.rs:41:22 + | +LL | let _: field_of!(fn() -> Struct, field); + | ^^^^^^^^^^^^^^ + +error: type `dyn Trait` doesn't have fields + --> $DIR/nonexistent.rs:42:22 + | +LL | let _: field_of!(dyn Trait, field); + | ^^^^^^^^^ + +error: cannot use `_` in this position + --> $DIR/nonexistent.rs:44:22 + | +LL | let _: field_of!(_, field); + | ^ + +error: type `T` doesn't have fields + --> $DIR/nonexistent.rs:48:22 + | +LL | let _: field_of!(T, field); + | ^ + +error: aborting due to 20 previous errors + +Some errors have detailed explanations: E0573, E0599, E0609. +For more information about an error, try `rustc --explain E0573`. diff --git a/tests/ui/field_representing_types/nonexistent.rs b/tests/ui/field_representing_types/nonexistent.rs new file mode 100644 index 0000000000000..74083666af76d --- /dev/null +++ b/tests/ui/field_representing_types/nonexistent.rs @@ -0,0 +1,49 @@ +//@ revisions: old next +//@ [next] compile-flags: -Znext-solver +#![expect(incomplete_features)] +#![feature(field_projections)] + +use std::field::field_of; + +pub struct Struct { + field: i32, +} + +pub union Union { + field: i32, +} + +pub enum Enum { + Variant { field: i32 }, +} + +pub trait Trait {} + +fn main() { + let _: field_of!(Struct, other); //~ ERROR: no field `other` on type `Struct` [E0609] + let _: field_of!(Struct, 0); //~ ERROR: no field `0` on type `Struct` [E0609] + let _: field_of!(Union, other); //~ ERROR: no field `other` on type `Union` [E0609] + let _: field_of!(Union, 0); //~ ERROR: no field `0` on type `Union` [E0609] + // FIXME(FRTs): make the error mention the variant too. + let _: field_of!(Enum, Variant.other); //~ ERROR: no field `other` on type `Enum` [E0609] + let _: field_of!(Enum, Variant.0); //~ ERROR: no field `0` on type `Enum` [E0609] + // FIXME(FRTs): select correct error code + let _: field_of!(Enum, OtherVariant.field); //~ ERROR: no variant named `OtherVariant` found for enum `Enum` + let _: field_of!(Enum, OtherVariant.0); //~ ERROR: no variant named `OtherVariant` found for enum `Enum` + let _: field_of!(((), ()), 2); //~ ERROR: no field `2` on type `((), ())` [E0609] + let _: field_of!(((), ()), field); //~ ERROR: no field `field` on type `((), ())` [E0609] + + let _: field_of!(i32, field); //~ ERROR: type `i32` doesn't have fields + let _: field_of!([Struct], field); //~ ERROR: type `[Struct]` doesn't have fields + let _: field_of!([Struct; 42], field); //~ ERROR: type `[Struct; 42]` is not yet supported in `field_of!` + let _: field_of!(&'static Struct, field); //~ ERROR: type `&'static Struct` doesn't have fields + let _: field_of!(*const Struct, field); //~ ERROR: type `*const Struct` doesn't have fields + let _: field_of!(fn() -> Struct, field); //~ ERROR: type `fn() -> Struct` doesn't have fields + let _: field_of!(dyn Trait, field); //~ ERROR: type `dyn Trait` doesn't have fields + let _: field_of!(main, field); //~ ERROR: expected type, found function `main` + let _: field_of!(_, field); //~ ERROR: cannot use `_` in this position +} + +fn generic() { + let _: field_of!(T, field); //~ ERROR: type `T` doesn't have fields +} diff --git a/tests/ui/field_representing_types/not-field-if-packed.next.stderr b/tests/ui/field_representing_types/not-field-if-packed.next.stderr new file mode 100644 index 0000000000000..a4ff5875a87a1 --- /dev/null +++ b/tests/ui/field_representing_types/not-field-if-packed.next.stderr @@ -0,0 +1,15 @@ +error[E0277]: the trait bound `field_of!(MyStruct, 0): std::field::Field` is not satisfied + --> $DIR/not-field-if-packed.rs:15:20 + | +LL | assert_field::(); + | ^^^^^^^^^^^^^^^^^^^^^^ the nightly-only, unstable trait `std::field::Field` is not implemented for `field_of!(MyStruct, 0)` + | +note: required by a bound in `assert_field` + --> $DIR/not-field-if-packed.rs:11:20 + | +LL | fn assert_field() {} + | ^^^^^ required by this bound in `assert_field` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/field_representing_types/not-field-if-packed.old.stderr b/tests/ui/field_representing_types/not-field-if-packed.old.stderr new file mode 100644 index 0000000000000..a4ff5875a87a1 --- /dev/null +++ b/tests/ui/field_representing_types/not-field-if-packed.old.stderr @@ -0,0 +1,15 @@ +error[E0277]: the trait bound `field_of!(MyStruct, 0): std::field::Field` is not satisfied + --> $DIR/not-field-if-packed.rs:15:20 + | +LL | assert_field::(); + | ^^^^^^^^^^^^^^^^^^^^^^ the nightly-only, unstable trait `std::field::Field` is not implemented for `field_of!(MyStruct, 0)` + | +note: required by a bound in `assert_field` + --> $DIR/not-field-if-packed.rs:11:20 + | +LL | fn assert_field() {} + | ^^^^^ required by this bound in `assert_field` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/field_representing_types/not-field-if-packed.rs b/tests/ui/field_representing_types/not-field-if-packed.rs new file mode 100644 index 0000000000000..7391ef312ba2c --- /dev/null +++ b/tests/ui/field_representing_types/not-field-if-packed.rs @@ -0,0 +1,17 @@ +//@ revisions: old next +//@ [next] compile-flags: -Znext-solver +#![expect(incomplete_features)] +#![feature(field_projections)] + +use std::field::{Field, field_of}; + +#[repr(packed)] +pub struct MyStruct(usize); + +fn assert_field() {} + +fn main() { + // FIXME(FRTs): improve this error message, point to the `repr(packed)` span. + assert_field::(); + //~^ ERROR: the trait bound `field_of!(MyStruct, 0): std::field::Field` is not satisfied [E0277] +} diff --git a/tests/ui/field_representing_types/offset.rs b/tests/ui/field_representing_types/offset.rs new file mode 100644 index 0000000000000..20b7c8b6d036d --- /dev/null +++ b/tests/ui/field_representing_types/offset.rs @@ -0,0 +1,51 @@ +//@ revisions: old next +//@ [next] compile-flags: -Znext-solver +//@ run-pass +#![expect(incomplete_features)] +#![feature(field_projections)] + +use std::field::{Field, field_of}; +use std::ptr; + +#[repr(C)] +pub struct Struct { + a: i32, + b: i64, +} + +// FIXME(FRTs): need to mark these fields as used by the `field_of!` macro. +#[expect(dead_code)] +pub union Union { + a: i32, + b: i64, +} + +#[repr(C, i8)] +pub enum Enum { + A { a: i32, b: i64 }, + B { x: i64, y: i32 }, +} + +fn project_ref<'a, T, F: Field>(r: &'a T) -> &'a F::Type { + unsafe { &*ptr::from_ref(r).byte_add(F::OFFSET).cast() } +} + +fn main() { + assert_eq!(::OFFSET, 0); + assert_eq!(::OFFSET, 8); + + let _: field_of!(Union, a); + let _: field_of!(Union, b); + + let _: field_of!(Enum, A.a); + let _: field_of!(Enum, A.b); + let _: field_of!(Enum, B.x); + let _: field_of!(Enum, B.y); + + let s = Struct { a: 42, b: 24 }; + let r = &s; + let a = project_ref::(r); + let b = project_ref::(r); + assert_eq!(*a, 42); + assert_eq!(*b, 24); +} diff --git a/tests/ui/field_representing_types/privacy.next.stderr b/tests/ui/field_representing_types/privacy.next.stderr new file mode 100644 index 0000000000000..9df19529d3fab --- /dev/null +++ b/tests/ui/field_representing_types/privacy.next.stderr @@ -0,0 +1,15 @@ +error[E0616]: field `a` of struct `Struct` is private + --> $DIR/privacy.rs:28:30 + | +LL | let _: field_of!(Struct, a); + | ^ private field + +error[E0616]: field `a` of union `foo::Union` is private + --> $DIR/privacy.rs:30:29 + | +LL | let _: field_of!(Union, a); + | ^ private field + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0616`. diff --git a/tests/ui/field_representing_types/privacy.old.stderr b/tests/ui/field_representing_types/privacy.old.stderr new file mode 100644 index 0000000000000..9df19529d3fab --- /dev/null +++ b/tests/ui/field_representing_types/privacy.old.stderr @@ -0,0 +1,15 @@ +error[E0616]: field `a` of struct `Struct` is private + --> $DIR/privacy.rs:28:30 + | +LL | let _: field_of!(Struct, a); + | ^ private field + +error[E0616]: field `a` of union `foo::Union` is private + --> $DIR/privacy.rs:30:29 + | +LL | let _: field_of!(Union, a); + | ^ private field + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0616`. diff --git a/tests/ui/field_representing_types/privacy.rs b/tests/ui/field_representing_types/privacy.rs new file mode 100644 index 0000000000000..a25be8e780bad --- /dev/null +++ b/tests/ui/field_representing_types/privacy.rs @@ -0,0 +1,34 @@ +//@ revisions: old next +//@ [next] compile-flags: -Znext-solver +#![expect(incomplete_features)] +#![feature(field_projections)] + +use std::field::field_of; + +mod foo { + pub struct Struct { + a: i32, + pub b: i32, + } + + pub union Union { + a: i32, + pub b: u32, + } + + pub enum Enum { + A { field: i32 }, + B(i32), + } +} + +use foo::{Enum, Struct, Union}; + +fn main() { + let _: field_of!(Struct, a); //~ ERROR: field `a` of struct `Struct` is private [E0616] + let _: field_of!(Struct, b); + let _: field_of!(Union, a); //~ ERROR: field `a` of union `foo::Union` is private [E0616] + let _: field_of!(Union, b); + let _: field_of!(Enum, A.field); + let _: field_of!(Enum, B.0); +} diff --git a/tests/ui/field_representing_types/projections.next.stderr b/tests/ui/field_representing_types/projections.next.stderr new file mode 100644 index 0000000000000..bf3b41cc23a54 --- /dev/null +++ b/tests/ui/field_representing_types/projections.next.stderr @@ -0,0 +1,32 @@ +error: could not resolve fields of `<::Assoc as Special>::Assoc` + --> $DIR/projections.rs:39:18 + | +LL | _: field_of!(<::Assoc as Special>::Assoc, field), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: could not resolve fields of `<::Assoc as Special>::Assoc` + --> $DIR/projections.rs:45:19 + | +LL | _x: field_of!(<::Assoc as Special>::Assoc, field), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: could not resolve fields of `::Assoc` + --> $DIR/projections.rs:24:22 + | +LL | let _: field_of!(::Assoc, field); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error: could not resolve fields of `<::Assoc as Special>::Assoc` + --> $DIR/projections.rs:51:22 + | +LL | let _: field_of!(<::Assoc as Special>::Assoc, field); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: could not resolve fields of `<::Assoc as Special>::Assoc` + --> $DIR/projections.rs:56:22 + | +LL | let _: field_of!(<::Assoc as Special>::Assoc, other); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 5 previous errors + diff --git a/tests/ui/field_representing_types/projections.old.stderr b/tests/ui/field_representing_types/projections.old.stderr new file mode 100644 index 0000000000000..bf3b41cc23a54 --- /dev/null +++ b/tests/ui/field_representing_types/projections.old.stderr @@ -0,0 +1,32 @@ +error: could not resolve fields of `<::Assoc as Special>::Assoc` + --> $DIR/projections.rs:39:18 + | +LL | _: field_of!(<::Assoc as Special>::Assoc, field), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: could not resolve fields of `<::Assoc as Special>::Assoc` + --> $DIR/projections.rs:45:19 + | +LL | _x: field_of!(<::Assoc as Special>::Assoc, field), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: could not resolve fields of `::Assoc` + --> $DIR/projections.rs:24:22 + | +LL | let _: field_of!(::Assoc, field); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error: could not resolve fields of `<::Assoc as Special>::Assoc` + --> $DIR/projections.rs:51:22 + | +LL | let _: field_of!(<::Assoc as Special>::Assoc, field); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: could not resolve fields of `<::Assoc as Special>::Assoc` + --> $DIR/projections.rs:56:22 + | +LL | let _: field_of!(<::Assoc as Special>::Assoc, other); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 5 previous errors + diff --git a/tests/ui/field_representing_types/projections.rs b/tests/ui/field_representing_types/projections.rs new file mode 100644 index 0000000000000..625f22e25e991 --- /dev/null +++ b/tests/ui/field_representing_types/projections.rs @@ -0,0 +1,58 @@ +//@ revisions: old next +//@ [next] compile-flags: -Znext-solver +#![feature(field_projections, freeze)] +#![expect(incomplete_features, dead_code)] + +use std::field::field_of; + +struct Struct { + field: u32, +} + +type Alias = Struct; + +trait Trait { + type Assoc; +} + +impl Trait for Struct { + type Assoc = Struct; +} + +fn main() { + let _: field_of!(Alias, field); + let _: field_of!(::Assoc, field); + //~^ ERROR: could not resolve fields of `::Assoc` +} + +trait Special { + type Assoc; +} + +trait Constraint: Trait {} + +impl Special for Struct { + type Assoc = Self; +} + +fn with_constraint1( + _: field_of!(<::Assoc as Special>::Assoc, field), + //~^ ERROR: could not resolve fields of `<::Assoc as Special>::Assoc` +) { +} + +fn with_constraint2( + _x: field_of!(<::Assoc as Special>::Assoc, field), + //~^ ERROR: could not resolve fields of `<::Assoc as Special>::Assoc` +) { +} + +fn with_constraint3() { + let _: field_of!(<::Assoc as Special>::Assoc, field); + //~^ ERROR: could not resolve fields of `<::Assoc as Special>::Assoc` +} + +fn with_constraint_invalid_field() { + let _: field_of!(<::Assoc as Special>::Assoc, other); + //~^ ERROR: could not resolve fields of `<::Assoc as Special>::Assoc` +} diff --git a/tests/ui/field_representing_types/traits.rs b/tests/ui/field_representing_types/traits.rs new file mode 100644 index 0000000000000..6b5bb15f9ee9a --- /dev/null +++ b/tests/ui/field_representing_types/traits.rs @@ -0,0 +1,29 @@ +//@ revisions: old next +//@ [next] compile-flags: -Znext-solver +//@ run-pass +#![feature(field_projections, freeze)] +#![expect(incomplete_features, dead_code)] +use std::field::field_of; +use std::marker::{Freeze, Unpin}; + +struct Struct { + field: u32, +} + +union Union { + field: u32, +} + +enum Enum { + Variant1 { field: u32 }, + Variant2(u32), +} + +fn assert_traits() {} + +fn main() { + assert_traits::(); + assert_traits::(); + assert_traits::(); + assert_traits::(); +} diff --git a/tests/ui/field_representing_types/weird-impls.next.stderr b/tests/ui/field_representing_types/weird-impls.next.stderr new file mode 100644 index 0000000000000..427d5e756af48 --- /dev/null +++ b/tests/ui/field_representing_types/weird-impls.next.stderr @@ -0,0 +1,30 @@ +error[E0120]: the `Drop` trait may only be implemented for local structs, enums, and unions + --> $DIR/weird-impls.rs:10:15 + | +LL | impl Drop for field_of!(MyStruct, 0) { + | ^^^^^^^^^^^^^^^^^^^^^^ must be a struct, enum, or union in the current crate + | + = note: this error originates in the macro `field_of` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0321]: cross-crate traits with a default impl, like `Send`, can only be implemented for a struct/enum type, not `field_of!(MyStruct, 0)` + --> $DIR/weird-impls.rs:15:1 + | +LL | unsafe impl Send for field_of!(MyStruct, 0) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't implement cross-crate trait with a default impl for non-struct/enum type + +error[E0322]: explicit impls for the `Field` trait are not permitted + --> $DIR/weird-impls.rs:21:1 + | +LL | unsafe impl Field for field_of!(MyStruct2, 0) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl of `Field` not allowed + +error[E0322]: explicit impls for the `Field` trait are not permitted + --> $DIR/weird-impls.rs:30:1 + | +LL | unsafe impl Field for MyField { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl of `Field` not allowed + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0120, E0321, E0322. +For more information about an error, try `rustc --explain E0120`. diff --git a/tests/ui/field_representing_types/weird-impls.old.stderr b/tests/ui/field_representing_types/weird-impls.old.stderr new file mode 100644 index 0000000000000..427d5e756af48 --- /dev/null +++ b/tests/ui/field_representing_types/weird-impls.old.stderr @@ -0,0 +1,30 @@ +error[E0120]: the `Drop` trait may only be implemented for local structs, enums, and unions + --> $DIR/weird-impls.rs:10:15 + | +LL | impl Drop for field_of!(MyStruct, 0) { + | ^^^^^^^^^^^^^^^^^^^^^^ must be a struct, enum, or union in the current crate + | + = note: this error originates in the macro `field_of` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0321]: cross-crate traits with a default impl, like `Send`, can only be implemented for a struct/enum type, not `field_of!(MyStruct, 0)` + --> $DIR/weird-impls.rs:15:1 + | +LL | unsafe impl Send for field_of!(MyStruct, 0) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't implement cross-crate trait with a default impl for non-struct/enum type + +error[E0322]: explicit impls for the `Field` trait are not permitted + --> $DIR/weird-impls.rs:21:1 + | +LL | unsafe impl Field for field_of!(MyStruct2, 0) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl of `Field` not allowed + +error[E0322]: explicit impls for the `Field` trait are not permitted + --> $DIR/weird-impls.rs:30:1 + | +LL | unsafe impl Field for MyField { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl of `Field` not allowed + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0120, E0321, E0322. +For more information about an error, try `rustc --explain E0120`. diff --git a/tests/ui/field_representing_types/weird-impls.rs b/tests/ui/field_representing_types/weird-impls.rs new file mode 100644 index 0000000000000..1fd58ba0da060 --- /dev/null +++ b/tests/ui/field_representing_types/weird-impls.rs @@ -0,0 +1,37 @@ +//@ revisions: old next +//@ [next] compile-flags: -Znext-solver +#![expect(incomplete_features)] +#![feature(field_projections)] + +use std::field::{Field, field_of}; + +pub struct MyStruct(()); + +impl Drop for field_of!(MyStruct, 0) { + //~^ ERROR: the `Drop` trait may only be implemented for local structs, enums, and unions [E0120] + fn drop(&mut self) {} +} + +unsafe impl Send for field_of!(MyStruct, 0) {} +//~^ ERROR: cross-crate traits with a default impl, like `Send`, can only be implemented for a struct/enum type, not `field_of!(MyStruct, 0)` [E0321] + +#[repr(packed)] +pub struct MyStruct2(usize); + +unsafe impl Field for field_of!(MyStruct2, 0) { + //~^ ERROR: explicit impls for the `Field` trait are not permitted [E0322] + type Base = MyStruct2; + type Type = usize; + const OFFSET: usize = 0; +} + +pub struct MyField; + +unsafe impl Field for MyField { + //~^ ERROR: explicit impls for the `Field` trait are not permitted [E0322] + type Base = (); + type Type = (); + const OFFSET: usize = 0; +} + +fn main() {} diff --git a/tests/ui/incoherent-inherent-impls/insufficient-suggestion-issue-141679.rs b/tests/ui/incoherent-inherent-impls/insufficient-suggestion-issue-141679.rs new file mode 100644 index 0000000000000..b13b6f418d425 --- /dev/null +++ b/tests/ui/incoherent-inherent-impls/insufficient-suggestion-issue-141679.rs @@ -0,0 +1,8 @@ +use std::rc::Rc; +pub struct Foo; + +pub type Function = Rc; + +impl Function {} +//~^ ERROR cannot define inherent `impl` for a type outside of the crate where the type is defined [E0116] +fn main(){} diff --git a/tests/ui/incoherent-inherent-impls/insufficient-suggestion-issue-141679.stderr b/tests/ui/incoherent-inherent-impls/insufficient-suggestion-issue-141679.stderr new file mode 100644 index 0000000000000..a62f7f82ba9d9 --- /dev/null +++ b/tests/ui/incoherent-inherent-impls/insufficient-suggestion-issue-141679.stderr @@ -0,0 +1,17 @@ +error[E0116]: cannot define inherent `impl` for a type outside of the crate where the type is defined + --> $DIR/insufficient-suggestion-issue-141679.rs:6:1 + | +LL | impl Function {} + | ^^^^^^^^^^^^^ impl for type defined outside of crate + | + = help: consider defining a trait and implementing it for the type or using a newtype wrapper like `struct MyType(ExternalType);` and implement it + = note: for more details about the orphan rules, see +note: `Function` does not define a new type, only an alias of `Rc` defined here + --> $DIR/insufficient-suggestion-issue-141679.rs:4:1 + | +LL | pub type Function = Rc; + | ^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0116`. diff --git a/tests/ui/incoherent-inherent-impls/no-attr-empty-impl.stderr b/tests/ui/incoherent-inherent-impls/no-attr-empty-impl.stderr index f8491697910c0..de61c3900d461 100644 --- a/tests/ui/incoherent-inherent-impls/no-attr-empty-impl.stderr +++ b/tests/ui/incoherent-inherent-impls/no-attr-empty-impl.stderr @@ -4,7 +4,8 @@ error[E0116]: cannot define inherent `impl` for a type outside of the crate wher LL | impl extern_crate::StructWithAttr {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl for type defined outside of crate | - = note: define and implement a trait or new type instead + = help: consider defining a trait and implementing it for the type or using a newtype wrapper like `struct MyType(ExternalType);` and implement it + = note: for more details about the orphan rules, see error[E0116]: cannot define inherent `impl` for a type outside of the crate where the type is defined --> $DIR/no-attr-empty-impl.rs:7:1 @@ -12,7 +13,8 @@ error[E0116]: cannot define inherent `impl` for a type outside of the crate wher LL | impl extern_crate::StructNoAttr {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl for type defined outside of crate | - = note: define and implement a trait or new type instead + = help: consider defining a trait and implementing it for the type or using a newtype wrapper like `struct MyType(ExternalType);` and implement it + = note: for more details about the orphan rules, see error[E0116]: cannot define inherent `impl` for a type outside of the crate where the type is defined --> $DIR/no-attr-empty-impl.rs:10:1 @@ -20,7 +22,8 @@ error[E0116]: cannot define inherent `impl` for a type outside of the crate wher LL | impl extern_crate::EnumWithAttr {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl for type defined outside of crate | - = note: define and implement a trait or new type instead + = help: consider defining a trait and implementing it for the type or using a newtype wrapper like `struct MyType(ExternalType);` and implement it + = note: for more details about the orphan rules, see error[E0116]: cannot define inherent `impl` for a type outside of the crate where the type is defined --> $DIR/no-attr-empty-impl.rs:13:1 @@ -28,7 +31,8 @@ error[E0116]: cannot define inherent `impl` for a type outside of the crate wher LL | impl extern_crate::EnumNoAttr {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl for type defined outside of crate | - = note: define and implement a trait or new type instead + = help: consider defining a trait and implementing it for the type or using a newtype wrapper like `struct MyType(ExternalType);` and implement it + = note: for more details about the orphan rules, see error[E0390]: cannot define inherent `impl` for primitive types --> $DIR/no-attr-empty-impl.rs:16:1 diff --git a/tests/ui/incoherent-inherent-impls/no-other-unrelated-errors.stderr b/tests/ui/incoherent-inherent-impls/no-other-unrelated-errors.stderr index 2a33262f83898..f01817e294430 100644 --- a/tests/ui/incoherent-inherent-impls/no-other-unrelated-errors.stderr +++ b/tests/ui/incoherent-inherent-impls/no-other-unrelated-errors.stderr @@ -4,7 +4,8 @@ error[E0116]: cannot define inherent `impl` for a type outside of the crate wher LL | impl Vec {} | ^^^^^^^^^^^^^^^ impl for type defined outside of crate | - = note: define and implement a trait or new type instead + = help: consider defining a trait and implementing it for the type or using a newtype wrapper like `struct MyType(ExternalType);` and implement it + = note: for more details about the orphan rules, see error: aborting due to 1 previous error diff --git a/tests/ui/layout/rigid-alias-no-params.rs b/tests/ui/layout/rigid-alias-no-params.rs new file mode 100644 index 0000000000000..bc2622eb7ca64 --- /dev/null +++ b/tests/ui/layout/rigid-alias-no-params.rs @@ -0,0 +1,30 @@ +//@ compile-flags: -O -Cdebug-assertions=on +//@ build-pass + +// A regression test for #151791. Computing the layout of +// `>::Archived` fails as the alias +// is still rigid as the where-bound in scope shadows the impl. +// +// This previously caused an incorrect error during MIR optimizations. + +struct ArchivedString; + +pub trait ArchiveWith<'a> { + type Archived; +} + +struct AsOwned; +impl ArchiveWith<'_> for AsOwned { + type Archived = ArchivedString; +} + +fn foo<'a>() +where + AsOwned: ArchiveWith<'a>, +{ + let _ = unsafe { &*std::ptr::dangling::<>::Archived>() }; +} + +fn main() { + foo(); +} diff --git a/tests/ui/reflection/dump.bit64.run.stdout b/tests/ui/reflection/dump.bit64.run.stdout index efae226539515..41b7c35d132a8 100644 --- a/tests/ui/reflection/dump.bit64.run.stdout +++ b/tests/ui/reflection/dump.bit64.run.stdout @@ -11,7 +11,7 @@ Type { offset: 1, }, Field { - ty: TypeId(0x41223169ff28813ba79b7268a2a968d9), + ty: TypeId(0x76973a66f24df6db7173e51528fa5bec), offset: 2, }, ], @@ -179,7 +179,7 @@ Type { Type { kind: Reference( Reference { - pointee: TypeId(0x641e3def269c37acc6dcb92bf8c5f196), + pointee: TypeId(0x2a675f7e9d3320493042d9e4b41ba9eb), mutable: false, }, ), diff --git a/tests/ui/symbol-names/basic.legacy.stderr b/tests/ui/symbol-names/basic.legacy.stderr index a028f4331725e..6f1777c84c191 100644 --- a/tests/ui/symbol-names/basic.legacy.stderr +++ b/tests/ui/symbol-names/basic.legacy.stderr @@ -1,10 +1,10 @@ -error: symbol-name(_ZN5basic4main17h1dddcfd03744167fE) +error: symbol-name(_ZN5basic4main17h9dcd691dfd66f09dE) --> $DIR/basic.rs:8:1 | LL | #[rustc_symbol_name] | ^^^^^^^^^^^^^^^^^^^^ -error: demangling(basic::main::h1dddcfd03744167f) +error: demangling(basic::main::h9dcd691dfd66f09d) --> $DIR/basic.rs:8:1 | LL | #[rustc_symbol_name] diff --git a/tests/ui/symbol-names/issue-60925.legacy.stderr b/tests/ui/symbol-names/issue-60925.legacy.stderr index 14cbd877d9f8a..397ae379a3f48 100644 --- a/tests/ui/symbol-names/issue-60925.legacy.stderr +++ b/tests/ui/symbol-names/issue-60925.legacy.stderr @@ -1,10 +1,10 @@ -error: symbol-name(_ZN11issue_609253foo37Foo$LT$issue_60925..llv$u6d$..Foo$GT$3foo17h4b3099ec5dc5d306E) +error: symbol-name(_ZN11issue_609253foo37Foo$LT$issue_60925..llv$u6d$..Foo$GT$3foo17h0c5a913a7866cf0eE) --> $DIR/issue-60925.rs:21:9 | LL | #[rustc_symbol_name] | ^^^^^^^^^^^^^^^^^^^^ -error: demangling(issue_60925::foo::Foo::foo::h4b3099ec5dc5d306) +error: demangling(issue_60925::foo::Foo::foo::h0c5a913a7866cf0e) --> $DIR/issue-60925.rs:21:9 | LL | #[rustc_symbol_name] diff --git a/tests/ui/traits/trait-or-new-type-instead.stderr b/tests/ui/traits/trait-or-new-type-instead.stderr index 5f5aa3ac56982..ad12a84a4b808 100644 --- a/tests/ui/traits/trait-or-new-type-instead.stderr +++ b/tests/ui/traits/trait-or-new-type-instead.stderr @@ -4,7 +4,8 @@ error[E0116]: cannot define inherent `impl` for a type outside of the crate wher LL | impl Option { | ^^^^^^^^^^^^^^^^^ impl for type defined outside of crate | - = note: define and implement a trait or new type instead + = help: consider defining a trait and implementing it for the type or using a newtype wrapper like `struct MyType(ExternalType);` and implement it + = note: for more details about the orphan rules, see error: aborting due to 1 previous error diff --git a/tests/ui/where-clauses/projection-bound-unsatisfied-item-bounds-mit-opt-ice.rs b/tests/ui/where-clauses/projection-bound-unsatisfied-item-bounds-mit-opt-ice.rs index 80eec709eecbc..9448c8a2f9112 100644 --- a/tests/ui/where-clauses/projection-bound-unsatisfied-item-bounds-mit-opt-ice.rs +++ b/tests/ui/where-clauses/projection-bound-unsatisfied-item-bounds-mit-opt-ice.rs @@ -2,7 +2,7 @@ //@ build-pass // A regression test for #149081. The environment of `size` and `align` -// currently means that the item bound of`T::Assoc` doesn't hold. This can +// currently means that the item bound of `T::Assoc` doesn't hold. This can // result in normalization failures and ICE during MIR optimizations. // // This will no longer be an issue once #149283 is implemented.