diff --git a/compiler/rustc_ast_lowering/messages.ftl b/compiler/rustc_ast_lowering/messages.ftl index f4e3086f2b589..e7177402db1d7 100644 --- a/compiler/rustc_ast_lowering/messages.ftl +++ b/compiler/rustc_ast_lowering/messages.ftl @@ -35,7 +35,7 @@ ast_lowering_bad_return_type_notation_output = ast_lowering_base_expression_double_dot = base expression required after `..` - .label = add a base expression here + .suggestion = add a base expression here ast_lowering_clobber_abi_not_supported = `clobber_abi` is not supported on this target diff --git a/compiler/rustc_ast_lowering/src/errors.rs b/compiler/rustc_ast_lowering/src/errors.rs index faa22eece380b..2811fe104cd09 100644 --- a/compiler/rustc_ast_lowering/src/errors.rs +++ b/compiler/rustc_ast_lowering/src/errors.rs @@ -114,10 +114,10 @@ pub struct UnderscoreExprLhsAssign { } #[derive(Diagnostic, Clone, Copy)] -#[diag(ast_lowering_base_expression_double_dot)] +#[diag(ast_lowering_base_expression_double_dot, code = "E0797")] pub struct BaseExpressionDoubleDot { #[primary_span] - #[label] + #[suggestion(code = "/* expr */", applicability = "has-placeholders", style = "verbose")] pub span: Span, } diff --git a/compiler/rustc_error_codes/src/error_codes.rs b/compiler/rustc_error_codes/src/error_codes.rs index a1391cceb7128..9cd9ed54d4146 100644 --- a/compiler/rustc_error_codes/src/error_codes.rs +++ b/compiler/rustc_error_codes/src/error_codes.rs @@ -516,6 +516,7 @@ E0793: include_str!("./error_codes/E0793.md"), E0794: include_str!("./error_codes/E0794.md"), E0795: include_str!("./error_codes/E0795.md"), E0796: include_str!("./error_codes/E0796.md"), +E0797: include_str!("./error_codes/E0797.md"), } // Undocumented removed error codes. Note that many removed error codes are kept in the list above diff --git a/compiler/rustc_error_codes/src/error_codes/E0797.md b/compiler/rustc_error_codes/src/error_codes/E0797.md new file mode 100644 index 0000000000000..8a912307264e3 --- /dev/null +++ b/compiler/rustc_error_codes/src/error_codes/E0797.md @@ -0,0 +1,26 @@ +Struct update syntax was used without a base expression. + +Erroneous code example: + +```compile_fail,E0797 +struct Foo { + fizz: u8, + buzz: u8 +} + +let f1 = Foo { fizz: 10, buzz: 1}; +let f2 = Foo { fizz: 10, .. }; // error +``` + +Using struct update syntax requires a 'base expression'. +This will be used to fill remaining fields. + +``` +struct Foo { + fizz: u8, + buzz: u8 +} + +let f1 = Foo { fizz: 10, buzz: 1}; +let f2 = Foo { fizz: 10, ..f1 }; +``` diff --git a/compiler/rustc_transmute/src/layout/tree.rs b/compiler/rustc_transmute/src/layout/tree.rs index 49f24f66b24ad..86a077ee808b6 100644 --- a/compiler/rustc_transmute/src/layout/tree.rs +++ b/compiler/rustc_transmute/src/layout/tree.rs @@ -199,6 +199,7 @@ pub(crate) mod rustc { match err { LayoutError::Unknown(..) | LayoutError::ReferencesError(..) => Self::UnknownLayout, LayoutError::SizeOverflow(..) => Self::SizeOverflow, + LayoutError::Cycle(err) => Self::TypeError(*err), err => unimplemented!("{:?}", err), } } diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index 3d5b544bc1bc1..3df3e8ea05cdb 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -1787,6 +1787,8 @@ extern "rust-intrinsic" { /// so this rounds half-way cases to the number with an even least significant digit. /// /// May raise an inexact floating-point exception if the argument is not an integer. + /// However, Rust assumes floating-point exceptions cannot be observed, so this is not something that + /// can actually be used from Rust code. /// /// The stabilized version of this intrinsic is /// [`f32::round_ties_even`](../../std/primitive.f32.html#method.round_ties_even) @@ -1796,6 +1798,8 @@ extern "rust-intrinsic" { /// so this rounds half-way cases to the number with an even least significant digit. /// /// May raise an inexact floating-point exception if the argument is not an integer. + /// However, Rust assumes floating-point exceptions cannot be observed, so this is not something that + /// can actually be used from Rust code. /// /// The stabilized version of this intrinsic is /// [`f64::round_ties_even`](../../std/primitive.f64.html#method.round_ties_even) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 0e81b31dd6c41..4441060de98a8 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -207,8 +207,13 @@ pub(crate) fn clean_trait_ref_with_bindings<'tcx>( span_bug!(cx.tcx.def_span(trait_ref.def_id()), "`TraitRef` had unexpected kind {kind:?}"); } inline::record_extern_fqn(cx, trait_ref.def_id(), kind); - let path = - external_path(cx, trait_ref.def_id(), true, bindings, trait_ref.map_bound(|tr| tr.args)); + let path = clean_middle_path( + cx, + trait_ref.def_id(), + true, + bindings, + trait_ref.map_bound(|tr| tr.args), + ); debug!(?trait_ref); @@ -467,7 +472,7 @@ fn projection_to_path_segment<'tcx>( PathSegment { name: item.name, args: GenericArgs::AngleBracketed { - args: ty_args_to_args( + args: clean_middle_generic_args( cx, ty.map_bound(|ty| &ty.args[generics.parent_count..]), false, @@ -1903,7 +1908,7 @@ fn normalize<'tcx>( fn clean_trait_object_lifetime_bound<'tcx>( region: ty::Region<'tcx>, - container: Option>, + container: Option>, preds: &'tcx ty::List>, tcx: TyCtxt<'tcx>, ) -> Option { @@ -1932,7 +1937,7 @@ fn clean_trait_object_lifetime_bound<'tcx>( fn can_elide_trait_object_lifetime_bound<'tcx>( region: ty::Region<'tcx>, - container: Option>, + container: Option>, preds: &'tcx ty::List>, tcx: TyCtxt<'tcx>, ) -> bool { @@ -1979,21 +1984,22 @@ fn can_elide_trait_object_lifetime_bound<'tcx>( } #[derive(Debug)] -pub(crate) enum ContainerTy<'tcx> { +pub(crate) enum ContainerTy<'a, 'tcx> { Ref(ty::Region<'tcx>), Regular { ty: DefId, - args: ty::Binder<'tcx, &'tcx [ty::GenericArg<'tcx>]>, - has_self: bool, + /// The arguments *have* to contain an arg for the self type if the corresponding generics + /// contain a self type. + args: ty::Binder<'tcx, &'a [ty::GenericArg<'tcx>]>, arg: usize, }, } -impl<'tcx> ContainerTy<'tcx> { +impl<'tcx> ContainerTy<'_, 'tcx> { fn object_lifetime_default(self, tcx: TyCtxt<'tcx>) -> ObjectLifetimeDefault<'tcx> { match self { Self::Ref(region) => ObjectLifetimeDefault::Arg(region), - Self::Regular { ty: container, args, has_self, arg: index } => { + Self::Regular { ty: container, args, arg: index } => { let (DefKind::Struct | DefKind::Union | DefKind::Enum @@ -2006,14 +2012,7 @@ impl<'tcx> ContainerTy<'tcx> { let generics = tcx.generics_of(container); debug_assert_eq!(generics.parent_count, 0); - // If the container is a trait object type, the arguments won't contain the self type but the - // generics of the corresponding trait will. In such a case, offset the index by one. - // For comparison, if the container is a trait inside a bound, the arguments do contain the - // self type. - let offset = - if !has_self && generics.parent.is_none() && generics.has_self { 1 } else { 0 }; - let param = generics.params[index + offset].def_id; - + let param = generics.params[index].def_id; let default = tcx.object_lifetime_default(param); match default { rbv::ObjectLifetimeDefault::Param(lifetime) => { @@ -2045,7 +2044,7 @@ pub(crate) fn clean_middle_ty<'tcx>( bound_ty: ty::Binder<'tcx, Ty<'tcx>>, cx: &mut DocContext<'tcx>, parent_def_id: Option, - container: Option>, + container: Option>, ) -> Type { let bound_ty = normalize(cx, bound_ty).unwrap_or(bound_ty); match *bound_ty.skip_binder().kind() { @@ -2096,12 +2095,12 @@ pub(crate) fn clean_middle_ty<'tcx>( AdtKind::Enum => ItemType::Enum, }; inline::record_extern_fqn(cx, did, kind); - let path = external_path(cx, did, false, ThinVec::new(), bound_ty.rebind(args)); + let path = clean_middle_path(cx, did, false, ThinVec::new(), bound_ty.rebind(args)); Type::Path { path } } ty::Foreign(did) => { inline::record_extern_fqn(cx, did, ItemType::ForeignType); - let path = external_path( + let path = clean_middle_path( cx, did, false, @@ -2132,7 +2131,7 @@ pub(crate) fn clean_middle_ty<'tcx>( let mut bounds = dids .map(|did| { let empty = ty::Binder::dummy(ty::GenericArgs::empty()); - let path = external_path(cx, did, false, ThinVec::new(), empty); + let path = clean_middle_path(cx, did, false, ThinVec::new(), empty); inline::record_extern_fqn(cx, did, ItemType::Trait); PolyTrait { trait_: path, generic_params: Vec::new() } }) @@ -2171,7 +2170,7 @@ pub(crate) fn clean_middle_ty<'tcx>( .collect(); let late_bound_regions = late_bound_regions.into_iter().collect(); - let path = external_path(cx, did, false, bindings, args); + let path = clean_middle_path(cx, did, false, bindings, args); bounds.insert(0, PolyTrait { trait_: path, generic_params: late_bound_regions }); DynTrait(bounds, lifetime) @@ -2193,7 +2192,7 @@ pub(crate) fn clean_middle_ty<'tcx>( assoc: PathSegment { name: cx.tcx.associated_item(def_id).name, args: GenericArgs::AngleBracketed { - args: ty_args_to_args( + args: clean_middle_generic_args( cx, alias_ty.map_bound(|ty| ty.args.as_slice()), true, @@ -2213,7 +2212,7 @@ pub(crate) fn clean_middle_ty<'tcx>( if cx.tcx.features().lazy_type_alias { // Weak type alias `data` represents the `type X` in `type X = Y`. If we need `Y`, // we need to use `type_of`. - let path = external_path( + let path = clean_middle_path( cx, data.def_id, false, @@ -2243,7 +2242,8 @@ pub(crate) fn clean_middle_ty<'tcx>( ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) => { // If it's already in the same alias, don't get an infinite loop. if cx.current_type_aliases.contains_key(&def_id) { - let path = external_path(cx, def_id, false, ThinVec::new(), bound_ty.rebind(args)); + let path = + clean_middle_path(cx, def_id, false, ThinVec::new(), bound_ty.rebind(args)); Type::Path { path } } else { *cx.current_type_aliases.entry(def_id).or_insert(0) += 1; diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 179f37e6d96a4..90eb783c7caee 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -36,7 +36,7 @@ use rustc_target::abi::VariantIdx; use rustc_target::spec::abi::Abi; use crate::clean::cfg::Cfg; -use crate::clean::external_path; +use crate::clean::clean_middle_path; use crate::clean::inline::{self, print_inlined_const}; use crate::clean::utils::{is_literal_expr, print_evaluated_const}; use crate::core::DocContext; @@ -1258,7 +1258,7 @@ impl GenericBound { fn sized_with(cx: &mut DocContext<'_>, modifier: hir::TraitBoundModifier) -> GenericBound { let did = cx.tcx.require_lang_item(LangItem::Sized, None); let empty = ty::Binder::dummy(ty::GenericArgs::empty()); - let path = external_path(cx, did, false, ThinVec::new(), empty); + let path = clean_middle_path(cx, did, false, ThinVec::new(), empty); inline::record_extern_fqn(cx, did, ItemType::Trait); GenericBound::TraitBound(PolyTrait { trait_: path, generic_params: Vec::new() }, modifier) } diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index bdfda07be096c..437517598ac49 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -16,9 +16,10 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, LocalDefId, LOCAL_CRATE}; use rustc_metadata::rendered_const; use rustc_middle::mir; +use rustc_middle::ty::TypeVisitableExt; use rustc_middle::ty::{self, GenericArgKind, GenericArgsRef, TyCtxt}; -use rustc_middle::ty::{TypeVisitable, TypeVisitableExt}; use rustc_span::symbol::{kw, sym, Symbol}; +use std::assert_matches::debug_assert_matches; use std::fmt::Write as _; use std::mem; use std::sync::LazyLock as Lazy; @@ -75,80 +76,83 @@ pub(crate) fn krate(cx: &mut DocContext<'_>) -> Crate { Crate { module, external_traits: cx.external_traits.clone() } } -pub(crate) fn ty_args_to_args<'tcx>( +pub(crate) fn clean_middle_generic_args<'tcx>( cx: &mut DocContext<'tcx>, - ty_args: ty::Binder<'tcx, &'tcx [ty::GenericArg<'tcx>]>, - has_self: bool, + args: ty::Binder<'tcx, &'tcx [ty::GenericArg<'tcx>]>, + mut has_self: bool, owner: DefId, ) -> Vec { - if ty_args.skip_binder().is_empty() { + let (args, bound_vars) = (args.skip_binder(), args.bound_vars()); + if args.is_empty() { // Fast path which avoids executing the query `generics_of`. return Vec::new(); } - let params = &cx.tcx.generics_of(owner).params; - let mut elision_has_failed_once_before = false; + // If the container is a trait object type, the arguments won't contain the self type but the + // generics of the corresponding trait will. In such a case, prepend a dummy self type in order + // to align the arguments and parameters for the iteration below and to enable us to correctly + // instantiate the generic parameter default later. + let generics = cx.tcx.generics_of(owner); + let args = if !has_self && generics.parent.is_none() && generics.has_self { + has_self = true; + [cx.tcx.types.trait_object_dummy_self.into()] + .into_iter() + .chain(args.iter().copied()) + .collect::>() + .into() + } else { + std::borrow::Cow::from(args) + }; - let offset = if has_self { 1 } else { 0 }; - let mut args = Vec::with_capacity(ty_args.skip_binder().len().saturating_sub(offset)); + let mut elision_has_failed_once_before = false; + let clean_arg = |(index, &arg): (usize, &ty::GenericArg<'tcx>)| { + // Elide the self type. + if has_self && index == 0 { + return None; + } - let ty_arg_to_arg = |(index, arg): (usize, &ty::GenericArg<'tcx>)| match arg.unpack() { - GenericArgKind::Lifetime(lt) => { - Some(GenericArg::Lifetime(clean_middle_region(lt).unwrap_or(Lifetime::elided()))) + // Elide internal host effect args. + let param = generics.param_at(index, cx.tcx); + if param.is_host_effect() { + return None; } - GenericArgKind::Type(_) if has_self && index == 0 => None, - GenericArgKind::Type(ty) => { - if !elision_has_failed_once_before - && let Some(default) = params[index].default_value(cx.tcx) - { - let default = - ty_args.map_bound(|args| default.instantiate(cx.tcx, args).expect_ty()); - - if can_elide_generic_arg(ty_args.rebind(ty), default) { - return None; - } - elision_has_failed_once_before = true; + let arg = ty::Binder::bind_with_vars(arg, bound_vars); + + // Elide arguments that coincide with their default. + if !elision_has_failed_once_before && let Some(default) = param.default_value(cx.tcx) { + let default = default.instantiate(cx.tcx, args.as_ref()); + if can_elide_generic_arg(arg, arg.rebind(default)) { + return None; } + elision_has_failed_once_before = true; + } - Some(GenericArg::Type(clean_middle_ty( - ty_args.rebind(ty), + match arg.skip_binder().unpack() { + GenericArgKind::Lifetime(lt) => { + Some(GenericArg::Lifetime(clean_middle_region(lt).unwrap_or(Lifetime::elided()))) + } + GenericArgKind::Type(ty) => Some(GenericArg::Type(clean_middle_ty( + arg.rebind(ty), cx, None, Some(crate::clean::ContainerTy::Regular { ty: owner, - args: ty_args, - has_self, + args: arg.rebind(args.as_ref()), arg: index, }), - ))) - } - GenericArgKind::Const(ct) => { - if let ty::GenericParamDefKind::Const { is_host_effect: true, .. } = params[index].kind - { - return None; - } - - if !elision_has_failed_once_before - && let Some(default) = params[index].default_value(cx.tcx) - { - let default = - ty_args.map_bound(|args| default.instantiate(cx.tcx, args).expect_const()); - - if can_elide_generic_arg(ty_args.rebind(ct), default) { - return None; - } - - elision_has_failed_once_before = true; + ))), + GenericArgKind::Const(ct) => { + Some(GenericArg::Const(Box::new(clean_middle_const(arg.rebind(ct), cx)))) } - - Some(GenericArg::Const(Box::new(clean_middle_const(ty_args.rebind(ct), cx)))) } }; - args.extend(ty_args.skip_binder().iter().enumerate().rev().filter_map(ty_arg_to_arg)); - args.reverse(); - args + let offset = if has_self { 1 } else { 0 }; + let mut clean_args = Vec::with_capacity(args.len().saturating_sub(offset)); + clean_args.extend(args.iter().enumerate().rev().filter_map(clean_arg)); + clean_args.reverse(); + clean_args } /// Check if the generic argument `actual` coincides with the `default` and can therefore be elided. @@ -156,13 +160,17 @@ pub(crate) fn ty_args_to_args<'tcx>( /// This uses a very conservative approach for performance and correctness reasons, meaning for /// several classes of terms it claims that they cannot be elided even if they theoretically could. /// This is absolutely fine since it mostly concerns edge cases. -fn can_elide_generic_arg<'tcx, Term>( - actual: ty::Binder<'tcx, Term>, - default: ty::Binder<'tcx, Term>, -) -> bool -where - Term: Eq + TypeVisitable>, -{ +fn can_elide_generic_arg<'tcx>( + actual: ty::Binder<'tcx, ty::GenericArg<'tcx>>, + default: ty::Binder<'tcx, ty::GenericArg<'tcx>>, +) -> bool { + debug_assert_matches!( + (actual.skip_binder().unpack(), default.skip_binder().unpack()), + (ty::GenericArgKind::Lifetime(_), ty::GenericArgKind::Lifetime(_)) + | (ty::GenericArgKind::Type(_), ty::GenericArgKind::Type(_)) + | (ty::GenericArgKind::Const(_), ty::GenericArgKind::Const(_)) + ); + // In practice, we shouldn't have any inference variables at this point. // However to be safe, we bail out if we do happen to stumble upon them. if actual.has_infer() || default.has_infer() { @@ -192,14 +200,14 @@ where actual.skip_binder() == default.skip_binder() } -fn external_generic_args<'tcx>( +fn clean_middle_generic_args_with_bindings<'tcx>( cx: &mut DocContext<'tcx>, did: DefId, has_self: bool, bindings: ThinVec, ty_args: ty::Binder<'tcx, GenericArgsRef<'tcx>>, ) -> GenericArgs { - let args = ty_args_to_args(cx, ty_args.map_bound(|args| &args[..]), has_self, did); + let args = clean_middle_generic_args(cx, ty_args.map_bound(|args| &args[..]), has_self, did); if cx.tcx.fn_trait_kind_from_def_id(did).is_some() { let ty = ty_args @@ -225,7 +233,7 @@ fn external_generic_args<'tcx>( } } -pub(super) fn external_path<'tcx>( +pub(super) fn clean_middle_path<'tcx>( cx: &mut DocContext<'tcx>, did: DefId, has_self: bool, @@ -238,7 +246,7 @@ pub(super) fn external_path<'tcx>( res: Res::Def(def_kind, did), segments: thin_vec![PathSegment { name, - args: external_generic_args(cx, did, has_self, bindings, args), + args: clean_middle_generic_args_with_bindings(cx, did, has_self, bindings, args), }], } } diff --git a/tests/rustdoc/inline_cross/auxiliary/default-generic-args.rs b/tests/rustdoc/inline_cross/auxiliary/default-generic-args.rs index 1e31f18927e9d..c2c94817fad37 100644 --- a/tests/rustdoc/inline_cross/auxiliary/default-generic-args.rs +++ b/tests/rustdoc/inline_cross/auxiliary/default-generic-args.rs @@ -40,6 +40,11 @@ pub struct Multi(A, B); pub type M0 = Multi; -pub trait Trait<'a, T = &'a ()> {} - -pub type F = dyn for<'a> Trait<'a>; +pub trait Trait0<'a, T = &'a ()> {} +pub type D0 = dyn for<'a> Trait0<'a>; + +// Regression test for issue #119529. +pub trait Trait1 {} +pub type D1 = dyn Trait1; +pub type D2 = dyn Trait1<(), K>; +pub type D3 = dyn Trait1; diff --git a/tests/rustdoc/inline_cross/auxiliary/u_default_generic_args.rs b/tests/rustdoc/inline_cross/auxiliary/u_default_generic_args.rs new file mode 100644 index 0000000000000..a742dd7d865f1 --- /dev/null +++ b/tests/rustdoc/inline_cross/auxiliary/u_default_generic_args.rs @@ -0,0 +1 @@ +pub use default_generic_args::*; diff --git a/tests/rustdoc/inline_cross/default-generic-args.rs b/tests/rustdoc/inline_cross/default-generic-args.rs index c9a87a1990184..775bf04153280 100644 --- a/tests/rustdoc/inline_cross/default-generic-args.rs +++ b/tests/rustdoc/inline_cross/default-generic-args.rs @@ -79,15 +79,14 @@ pub use default_generic_args::P1; pub use default_generic_args::P2; // @has user/type.A0.html -// Ensure that we elide generic arguments that are alpha-equivalent to their respective -// generic parameter (modulo substs) (#1): -// @has - '//*[@class="rust item-decl"]//code' "Alpha" +// @has - '//*[@class="rust item-decl"]//code' "Alpha;" pub use default_generic_args::A0; // @has user/type.A1.html -// Ensure that we elide generic arguments that are alpha-equivalent to their respective -// generic parameter (modulo substs) (#1): -// @has - '//*[@class="rust item-decl"]//code' "Alpha" +// Demonstrates that we currently don't elide generic arguments that are alpha-equivalent to their +// respective generic parameter (after instantiation) for perf reasons (it would require us to +// create an inference context). +// @has - '//*[@class="rust item-decl"]//code' "Alpha fn(_: &'arbitrary ())>" pub use default_generic_args::A1; // @has user/type.M0.html @@ -97,8 +96,19 @@ pub use default_generic_args::A1; // @has - '//*[@class="rust item-decl"]//code' "Multi" pub use default_generic_args::M0; -// @has user/type.F.html -// FIXME: Ideally, we would elide `&'a ()` but `'a` is an escaping bound var which we can't reason -// about at the moment since we don't keep track of bound vars. -// @has - '//*[@class="rust item-decl"]//code' "dyn for<'a> Trait<'a, &'a ()>" -pub use default_generic_args::F; +// @has user/type.D0.html +// @has - '//*[@class="rust item-decl"]//code' "dyn for<'a> Trait0<'a>" +pub use default_generic_args::D0; + +// Regression test for issue #119529. +// Check that we correctly elide def ty&const args inside trait object types. + +// @has user/type.D1.html +// @has - '//*[@class="rust item-decl"]//code' "dyn Trait1" +pub use default_generic_args::D1; +// @has user/type.D2.html +// @has - '//*[@class="rust item-decl"]//code' "dyn Trait1<(), K>" +pub use default_generic_args::D2; +// @has user/type.D3.html +// @has - '//*[@class="rust item-decl"]//code' "dyn Trait1;" +pub use default_generic_args::D3; diff --git a/tests/ui/destructuring-assignment/struct_destructure_fail.stderr b/tests/ui/destructuring-assignment/struct_destructure_fail.stderr index ae7b3d1e5a928..57851ed417ea8 100644 --- a/tests/ui/destructuring-assignment/struct_destructure_fail.stderr +++ b/tests/ui/destructuring-assignment/struct_destructure_fail.stderr @@ -12,11 +12,16 @@ error: functional record updates are not allowed in destructuring assignments LL | Struct { a, ..d } = Struct { a: 1, b: 2 }; | ^ help: consider removing the trailing pattern -error: base expression required after `..` +error[E0797]: base expression required after `..` --> $DIR/struct_destructure_fail.rs:15:19 | LL | Struct { a, .. }; - | ^ add a base expression here + | ^ + | +help: add a base expression here + | +LL | Struct { a, ../* expr */ }; + | ++++++++++ error[E0026]: struct `Struct` does not have a field named `c` --> $DIR/struct_destructure_fail.rs:10:20 @@ -41,5 +46,5 @@ LL | Struct { a, .. } = Struct { a: 1, b: 2 }; error: aborting due to 5 previous errors -Some errors have detailed explanations: E0026, E0027. +Some errors have detailed explanations: E0026, E0027, E0797. For more information about an error, try `rustc --explain E0026`. diff --git a/tests/ui/transmutability/structs/repr/transmute_infinitely_recursive_type.rs b/tests/ui/transmutability/structs/repr/transmute_infinitely_recursive_type.rs new file mode 100644 index 0000000000000..0be5b41c80bcd --- /dev/null +++ b/tests/ui/transmutability/structs/repr/transmute_infinitely_recursive_type.rs @@ -0,0 +1,26 @@ +//~ ERROR: cycle detected +//! Safe transmute did not handle cycle errors that could occur during +//! layout computation. This test checks that we do not ICE in such +//! situations (see #117491). +#![crate_type = "lib"] +#![feature(transmutability)] +#![allow(dead_code, incomplete_features, non_camel_case_types)] + +mod assert { + use std::mem::{Assume, BikeshedIntrinsicFrom}; + pub struct Context; + + pub fn is_maybe_transmutable() + where + Dst: BikeshedIntrinsicFrom, + { + } +} + +fn should_pad_explicitly_packed_field() { + #[repr(C)] + struct ExplicitlyPadded(ExplicitlyPadded); + //~^ ERROR: recursive type + + assert::is_maybe_transmutable::(); +} diff --git a/tests/ui/transmutability/structs/repr/transmute_infinitely_recursive_type.stderr b/tests/ui/transmutability/structs/repr/transmute_infinitely_recursive_type.stderr new file mode 100644 index 0000000000000..0dedd5aaf735c --- /dev/null +++ b/tests/ui/transmutability/structs/repr/transmute_infinitely_recursive_type.stderr @@ -0,0 +1,21 @@ +error[E0072]: recursive type `ExplicitlyPadded` has infinite size + --> $DIR/transmute_infinitely_recursive_type.rs:22:5 + | +LL | struct ExplicitlyPadded(ExplicitlyPadded); + | ^^^^^^^^^^^^^^^^^^^^^^^ ---------------- recursive without indirection + | +help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle + | +LL | struct ExplicitlyPadded(Box); + | ++++ + + +error[E0391]: cycle detected when computing layout of `should_pad_explicitly_packed_field::ExplicitlyPadded` + | + = note: ...which immediately requires computing layout of `should_pad_explicitly_packed_field::ExplicitlyPadded` again + = note: cycle used when evaluating trait selection obligation `(): core::mem::transmutability::BikeshedIntrinsicFrom` + = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0072, E0391. +For more information about an error, try `rustc --explain E0072`.