diff options
128 files changed, 3544 insertions, 639 deletions
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 75302d917bb..552680f06f6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -447,7 +447,7 @@ jobs: - name: dist-x86_64-msvc env: RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-msvc --host=x86_64-pc-windows-msvc --target=x86_64-pc-windows-msvc --enable-full-tools --enable-profiler --set rust.lto=thin" - SCRIPT: PGO_HOST=x86_64-pc-windows-msvc src/ci/pgo.sh python x.py dist bootstrap --include-default-paths + SCRIPT: PGO_HOST=x86_64-pc-windows-msvc python src/ci/stage-build.py python x.py dist bootstrap --include-default-paths DIST_REQUIRE_ALL_TOOLS: 1 os: windows-latest-xl - name: dist-i686-msvc diff --git a/compiler/rustc_builtin_macros/src/deriving/bounds.rs b/compiler/rustc_builtin_macros/src/deriving/bounds.rs index 240167146e1..0481a118906 100644 --- a/compiler/rustc_builtin_macros/src/deriving/bounds.rs +++ b/compiler/rustc_builtin_macros/src/deriving/bounds.rs @@ -17,6 +17,7 @@ pub fn expand_deriving_copy( span, path: path_std!(marker::Copy), skip_path_as_bound: false, + needs_copy_as_bound_if_packed: false, additional_bounds: Vec::new(), supports_unions: true, methods: Vec::new(), diff --git a/compiler/rustc_builtin_macros/src/deriving/clone.rs b/compiler/rustc_builtin_macros/src/deriving/clone.rs index ef5a75f428d..42f50d8ade2 100644 --- a/compiler/rustc_builtin_macros/src/deriving/clone.rs +++ b/compiler/rustc_builtin_macros/src/deriving/clone.rs @@ -73,6 +73,7 @@ pub fn expand_deriving_clone( span, path: path_std!(clone::Clone), skip_path_as_bound: false, + needs_copy_as_bound_if_packed: true, additional_bounds: bounds, supports_unions: true, methods: vec![MethodDef { diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs index 3e994f037ad..424719f9795 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs @@ -27,6 +27,7 @@ pub fn expand_deriving_eq( span, path: path_std!(cmp::Eq), skip_path_as_bound: false, + needs_copy_as_bound_if_packed: true, additional_bounds: Vec::new(), supports_unions: true, methods: vec![MethodDef { diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs index a926fca4e65..671f32550d2 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs @@ -20,6 +20,7 @@ pub fn expand_deriving_ord( span, path: path_std!(cmp::Ord), skip_path_as_bound: false, + needs_copy_as_bound_if_packed: true, additional_bounds: Vec::new(), supports_unions: false, methods: vec![MethodDef { diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs index 9051fe0b28a..88d454fbc11 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs @@ -84,6 +84,7 @@ pub fn expand_deriving_partial_eq( span, path: path_std!(cmp::PartialEq), skip_path_as_bound: false, + needs_copy_as_bound_if_packed: true, additional_bounds: Vec::new(), supports_unions: false, methods, diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs index 2fc30d8e05f..bcc90442eb7 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs @@ -59,6 +59,7 @@ pub fn expand_deriving_partial_ord( span, path: path_std!(cmp::PartialOrd), skip_path_as_bound: false, + needs_copy_as_bound_if_packed: true, additional_bounds: vec![], supports_unions: false, methods: vec![partial_cmp_def], diff --git a/compiler/rustc_builtin_macros/src/deriving/debug.rs b/compiler/rustc_builtin_macros/src/deriving/debug.rs index e0f487e8648..897048f6421 100644 --- a/compiler/rustc_builtin_macros/src/deriving/debug.rs +++ b/compiler/rustc_builtin_macros/src/deriving/debug.rs @@ -23,6 +23,7 @@ pub fn expand_deriving_debug( span, path: path_std!(fmt::Debug), skip_path_as_bound: false, + needs_copy_as_bound_if_packed: true, additional_bounds: Vec::new(), supports_unions: false, methods: vec![MethodDef { diff --git a/compiler/rustc_builtin_macros/src/deriving/decodable.rs b/compiler/rustc_builtin_macros/src/deriving/decodable.rs index 5f9519dad1b..c783e46eda9 100644 --- a/compiler/rustc_builtin_macros/src/deriving/decodable.rs +++ b/compiler/rustc_builtin_macros/src/deriving/decodable.rs @@ -25,6 +25,7 @@ pub fn expand_deriving_rustc_decodable( span, path: Path::new_(vec![krate, sym::Decodable], vec![], PathKind::Global), skip_path_as_bound: false, + needs_copy_as_bound_if_packed: true, additional_bounds: Vec::new(), supports_unions: false, methods: vec![MethodDef { diff --git a/compiler/rustc_builtin_macros/src/deriving/default.rs b/compiler/rustc_builtin_macros/src/deriving/default.rs index 18270747296..a6c8b111527 100644 --- a/compiler/rustc_builtin_macros/src/deriving/default.rs +++ b/compiler/rustc_builtin_macros/src/deriving/default.rs @@ -25,6 +25,7 @@ pub fn expand_deriving_default( span, path: Path::new(vec![kw::Default, sym::Default]), skip_path_as_bound: has_a_default_variant(item), + needs_copy_as_bound_if_packed: false, additional_bounds: Vec::new(), supports_unions: false, methods: vec![MethodDef { diff --git a/compiler/rustc_builtin_macros/src/deriving/encodable.rs b/compiler/rustc_builtin_macros/src/deriving/encodable.rs index 2afeed927ac..a5e2b599df4 100644 --- a/compiler/rustc_builtin_macros/src/deriving/encodable.rs +++ b/compiler/rustc_builtin_macros/src/deriving/encodable.rs @@ -109,6 +109,7 @@ pub fn expand_deriving_rustc_encodable( span, path: Path::new_(vec![krate, sym::Encodable], vec![], PathKind::Global), skip_path_as_bound: false, + needs_copy_as_bound_if_packed: true, additional_bounds: Vec::new(), supports_unions: false, methods: vec![MethodDef { diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index 17b7ac0eba1..97de40bac34 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -165,11 +165,12 @@ pub use SubstructureFields::*; use crate::deriving; use rustc_ast::ptr::P; use rustc_ast::{ - self as ast, BindingAnnotation, ByRef, EnumDef, Expr, Generics, Mutability, PatKind, + self as ast, BindingAnnotation, ByRef, EnumDef, Expr, GenericArg, GenericParamKind, Generics, + Mutability, PatKind, TyKind, VariantData, }; -use rustc_ast::{GenericArg, GenericParamKind, VariantData}; use rustc_attr as attr; use rustc_expand::base::{Annotatable, ExtCtxt}; +use rustc_session::lint::builtin::BYTE_SLICE_IN_PACKED_STRUCT_WITH_DERIVE; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{Span, DUMMY_SP}; use std::cell::RefCell; @@ -191,6 +192,9 @@ pub struct TraitDef<'a> { /// Whether to skip adding the current trait as a bound to the type parameters of the type. pub skip_path_as_bound: bool, + /// Whether `Copy` is needed as an additional bound on type parameters in a packed struct. + pub needs_copy_as_bound_if_packed: bool, + /// Additional bounds required of any type parameters of the type, /// other than the current trait pub additional_bounds: Vec<Ty>, @@ -455,18 +459,6 @@ impl<'a> TraitDef<'a> { } false }); - let has_no_type_params = match &item.kind { - ast::ItemKind::Struct(_, generics) - | ast::ItemKind::Enum(_, generics) - | ast::ItemKind::Union(_, generics) => !generics - .params - .iter() - .any(|param| matches!(param.kind, ast::GenericParamKind::Type { .. })), - _ => unreachable!(), - }; - let container_id = cx.current_expansion.id.expn_data().parent.expect_local(); - let copy_fields = - is_packed && has_no_type_params && cx.resolver.has_derive_copy(container_id); let newitem = match &item.kind { ast::ItemKind::Struct(struct_def, generics) => self.expand_struct_def( @@ -475,7 +467,7 @@ impl<'a> TraitDef<'a> { item.ident, generics, from_scratch, - copy_fields, + is_packed, ), ast::ItemKind::Enum(enum_def, generics) => { // We ignore `is_packed` here, because `repr(packed)` @@ -493,7 +485,7 @@ impl<'a> TraitDef<'a> { item.ident, generics, from_scratch, - copy_fields, + is_packed, ) } else { cx.span_err(mitem.span, "this trait cannot be derived for unions"); @@ -565,6 +557,7 @@ impl<'a> TraitDef<'a> { generics: &Generics, field_tys: Vec<P<ast::Ty>>, methods: Vec<P<ast::AssocItem>>, + is_packed: bool, ) -> P<ast::Item> { let trait_path = self.path.to_path(cx, self.span, type_ident, generics); @@ -607,20 +600,32 @@ impl<'a> TraitDef<'a> { .map(|param| match ¶m.kind { GenericParamKind::Lifetime { .. } => param.clone(), GenericParamKind::Type { .. } => { - // I don't think this can be moved out of the loop, since - // a GenericBound requires an ast id - let bounds: Vec<_> = - // extra restrictions on the generics parameters to the - // type being derived upon - self.additional_bounds.iter().map(|p| { - cx.trait_bound(p.to_path(cx, self.span, type_ident, generics)) - }).chain( - // require the current trait - self.skip_path_as_bound.not().then(|| cx.trait_bound(trait_path.clone())) - ).chain( - // also add in any bounds from the declaration - param.bounds.iter().cloned() - ).collect(); + // Extra restrictions on the generics parameters to the + // type being derived upon. + let bounds: Vec<_> = self + .additional_bounds + .iter() + .map(|p| cx.trait_bound(p.to_path(cx, self.span, type_ident, generics))) + .chain( + // Add a bound for the current trait. + self.skip_path_as_bound + .not() + .then(|| cx.trait_bound(trait_path.clone())), + ) + .chain({ + // Add a `Copy` bound if required. + if is_packed && self.needs_copy_as_bound_if_packed { + let p = deriving::path_std!(marker::Copy); + Some(cx.trait_bound(p.to_path(cx, self.span, type_ident, generics))) + } else { + None + } + }) + .chain( + // Also add in any bounds from the declaration. + param.bounds.iter().cloned(), + ) + .collect(); cx.typaram(param.ident.span.with_ctxt(ctxt), param.ident, bounds, None) } @@ -692,9 +697,17 @@ impl<'a> TraitDef<'a> { .map(|p| cx.trait_bound(p.to_path(cx, self.span, type_ident, generics))) .collect(); - // require the current trait + // Require the current trait. bounds.push(cx.trait_bound(trait_path.clone())); + // Add a `Copy` bound if required. + if is_packed && self.needs_copy_as_bound_if_packed { + let p = deriving::path_std!(marker::Copy); + bounds.push( + cx.trait_bound(p.to_path(cx, self.span, type_ident, generics)), + ); + } + let predicate = ast::WhereBoundPredicate { span: self.span, bound_generic_params: field_ty_param.bound_generic_params, @@ -762,7 +775,7 @@ impl<'a> TraitDef<'a> { type_ident: Ident, generics: &Generics, from_scratch: bool, - copy_fields: bool, + is_packed: bool, ) -> P<ast::Item> { let field_tys: Vec<P<ast::Ty>> = struct_def.fields().iter().map(|field| field.ty.clone()).collect(); @@ -790,7 +803,7 @@ impl<'a> TraitDef<'a> { type_ident, &selflike_args, &nonselflike_args, - copy_fields, + is_packed, ) }; @@ -806,7 +819,7 @@ impl<'a> TraitDef<'a> { }) .collect(); - self.create_derived_impl(cx, type_ident, generics, field_tys, methods) + self.create_derived_impl(cx, type_ident, generics, field_tys, methods, is_packed) } fn expand_enum_def( @@ -861,7 +874,8 @@ impl<'a> TraitDef<'a> { }) .collect(); - self.create_derived_impl(cx, type_ident, generics, field_tys, methods) + let is_packed = false; // enums are never packed + self.create_derived_impl(cx, type_ident, generics, field_tys, methods, is_packed) } } @@ -1011,8 +1025,8 @@ impl<'a> MethodDef<'a> { /// ``` /// But if the struct is `repr(packed)`, we can't use something like /// `&self.x` because that might cause an unaligned ref. So for any trait - /// method that takes a reference, if the struct impls `Copy` then we use a - /// local block to force a copy: + /// method that takes a reference, we use a local block to force a copy. + /// This requires that the field impl `Copy`. /// ``` /// # struct A { x: u8, y: u8 } /// impl PartialEq for A { @@ -1027,10 +1041,6 @@ impl<'a> MethodDef<'a> { /// ::core::hash::Hash::hash(&{ self.y }, state) /// } /// } - /// ``` - /// If the struct doesn't impl `Copy`, we use the normal `&self.x`. This - /// only works if the fields match the alignment required by the - /// `packed(N)` attribute. (We'll get errors later on if not.) fn expand_struct_method_body<'b>( &self, cx: &mut ExtCtxt<'_>, @@ -1039,12 +1049,12 @@ impl<'a> MethodDef<'a> { type_ident: Ident, selflike_args: &[P<Expr>], nonselflike_args: &[P<Expr>], - copy_fields: bool, + is_packed: bool, ) -> BlockOrExpr { assert!(selflike_args.len() == 1 || selflike_args.len() == 2); let selflike_fields = - trait_.create_struct_field_access_fields(cx, selflike_args, struct_def, copy_fields); + trait_.create_struct_field_access_fields(cx, selflike_args, struct_def, is_packed); self.call_substructure_method( cx, trait_, @@ -1514,7 +1524,7 @@ impl<'a> TraitDef<'a> { cx: &mut ExtCtxt<'_>, selflike_args: &[P<Expr>], struct_def: &'a VariantData, - copy_fields: bool, + is_packed: bool, ) -> Vec<FieldInfo> { self.create_fields(struct_def, |i, struct_field, sp| { selflike_args @@ -1533,10 +1543,39 @@ impl<'a> TraitDef<'a> { }), ), ); - if copy_fields { - field_expr = cx.expr_block( - cx.block(struct_field.span, vec![cx.stmt_expr(field_expr)]), - ); + // In general, fields in packed structs are copied via a + // block, e.g. `&{self.0}`. The one exception is `[u8]` + // fields, which cannot be copied and also never cause + // unaligned references. This exception is allowed to + // handle the `FlexZeroSlice` type in the `zerovec` crate + // within `icu4x-0.9.0`. + // + // Once use of `icu4x-0.9.0` has dropped sufficiently, this + // exception should be removed. + let is_u8_slice = if let TyKind::Slice(ty) = &struct_field.ty.kind && + let TyKind::Path(None, rustc_ast::Path { segments, .. }) = &ty.kind && + let [seg] = segments.as_slice() && + seg.ident.name == sym::u8 && seg.args.is_none() + { + true + } else { + false + }; + if is_packed { + if is_u8_slice { + cx.sess.parse_sess.buffer_lint_with_diagnostic( + BYTE_SLICE_IN_PACKED_STRUCT_WITH_DERIVE, + sp, + ast::CRATE_NODE_ID, + "byte slice in a packed struct that derives a built-in trait", + rustc_lint_defs::BuiltinLintDiagnostics::ByteSliceInPackedStructWithDerive + ); + } else { + // Wrap the expression in `{...}`, causing a copy. + field_expr = cx.expr_block( + cx.block(struct_field.span, vec![cx.stmt_expr(field_expr)]), + ); + } } cx.expr_addr_of(sp, field_expr) }) diff --git a/compiler/rustc_builtin_macros/src/deriving/hash.rs b/compiler/rustc_builtin_macros/src/deriving/hash.rs index f8570d8f86a..5c2e89c5697 100644 --- a/compiler/rustc_builtin_macros/src/deriving/hash.rs +++ b/compiler/rustc_builtin_macros/src/deriving/hash.rs @@ -24,6 +24,7 @@ pub fn expand_deriving_hash( span, path, skip_path_as_bound: false, + needs_copy_as_bound_if_packed: true, additional_bounds: Vec::new(), supports_unions: false, methods: vec![MethodDef { diff --git a/compiler/rustc_driver/src/pretty.rs b/compiler/rustc_driver/src/pretty.rs index 022051e008e..446c6832cb7 100644 --- a/compiler/rustc_driver/src/pretty.rs +++ b/compiler/rustc_driver/src/pretty.rs @@ -498,6 +498,21 @@ fn print_with_analysis(tcx: TyCtxt<'_>, ppm: PpMode) -> Result<(), ErrorGuarante out } + ThirFlat => { + let mut out = String::new(); + abort_on_err(rustc_hir_analysis::check_crate(tcx), tcx.sess); + debug!("pretty printing THIR flat"); + for did in tcx.hir().body_owners() { + let _ = writeln!( + out, + "{:?}:\n{}\n", + did, + tcx.thir_flat(ty::WithOptConstParam::unknown(did)) + ); + } + out + } + _ => unreachable!(), }; diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 4696a4bd9ab..a063307af0c 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -2263,7 +2263,7 @@ pub struct TraitItem<'hir> { pub defaultness: Defaultness, } -impl TraitItem<'_> { +impl<'hir> TraitItem<'hir> { #[inline] pub fn hir_id(&self) -> HirId { // Items are always HIR owners. @@ -2273,6 +2273,32 @@ impl TraitItem<'_> { pub fn trait_item_id(&self) -> TraitItemId { TraitItemId { owner_id: self.owner_id } } + + /// Expect an [`TraitItemKind::Const`] or panic. + #[track_caller] + pub fn expect_const(&self) -> (&'hir Ty<'hir>, Option<BodyId>) { + let TraitItemKind::Const(ty, body) = self.kind else { self.expect_failed("a constant") }; + (ty, body) + } + + /// Expect an [`TraitItemKind::Fn`] or panic. + #[track_caller] + pub fn expect_fn(&self) -> (&FnSig<'hir>, &TraitFn<'hir>) { + let TraitItemKind::Fn(ty, trfn) = &self.kind else { self.expect_failed("a function") }; + (ty, trfn) + } + + /// Expect an [`TraitItemKind::Type`] or panic. + #[track_caller] + pub fn expect_type(&self) -> (GenericBounds<'hir>, Option<&'hir Ty<'hir>>) { + let TraitItemKind::Type(bounds, ty) = self.kind else { self.expect_failed("a type") }; + (bounds, ty) + } + + #[track_caller] + fn expect_failed(&self, expected: &'static str) -> ! { + panic!("expected {expected} item, found {self:?}") + } } /// Represents a trait method's body (or just argument names). @@ -2325,7 +2351,7 @@ pub struct ImplItem<'hir> { pub vis_span: Span, } -impl ImplItem<'_> { +impl<'hir> ImplItem<'hir> { #[inline] pub fn hir_id(&self) -> HirId { // Items are always HIR owners. @@ -2335,6 +2361,32 @@ impl ImplItem<'_> { pub fn impl_item_id(&self) -> ImplItemId { ImplItemId { owner_id: self.owner_id } } + + /// Expect an [`ImplItemKind::Const`] or panic. + #[track_caller] + pub fn expect_const(&self) -> (&'hir Ty<'hir>, BodyId) { + let ImplItemKind::Const(ty, body) = self.kind else { self.expect_failed("a constant") }; + (ty, body) + } + + /// Expect an [`ImplItemKind::Fn`] or panic. + #[track_caller] + pub fn expect_fn(&self) -> (&FnSig<'hir>, BodyId) { + let ImplItemKind::Fn(ty, body) = &self.kind else { self.expect_failed("a function") }; + (ty, *body) + } + + /// Expect an [`ImplItemKind::Type`] or panic. + #[track_caller] + pub fn expect_type(&self) -> &'hir Ty<'hir> { + let ImplItemKind::Type(ty) = self.kind else { self.expect_failed("a type") }; + ty + } + + #[track_caller] + fn expect_failed(&self, expected: &'static str) -> ! { + panic!("expected {expected} item, found {self:?}") + } } /// Represents various kinds of content within an `impl`. @@ -2995,7 +3047,7 @@ pub struct Item<'hir> { pub vis_span: Span, } -impl Item<'_> { +impl<'hir> Item<'hir> { #[inline] pub fn hir_id(&self) -> HirId { // Items are always HIR owners. @@ -3005,6 +3057,132 @@ impl Item<'_> { pub fn item_id(&self) -> ItemId { ItemId { owner_id: self.owner_id } } + + /// Expect an [`ItemKind::ExternCrate`] or panic. + #[track_caller] + pub fn expect_extern_crate(&self) -> Option<Symbol> { + let ItemKind::ExternCrate(s) = self.kind else { self.expect_failed("an extern crate") }; + s + } + + /// Expect an [`ItemKind::Use`] or panic. + #[track_caller] + pub fn expect_use(&self) -> (&'hir UsePath<'hir>, UseKind) { + let ItemKind::Use(p, uk) = self.kind else { self.expect_failed("a use") }; + (p, uk) + } + + /// Expect an [`ItemKind::Static`] or panic. + #[track_caller] + pub fn expect_static(&self) -> (&'hir Ty<'hir>, Mutability, BodyId) { + let ItemKind::Static(ty, mutbl, body) = self.kind else { self.expect_failed("a static") }; + (ty, mutbl, body) + } + /// Expect an [`ItemKind::Const`] or panic. + #[track_caller] + pub fn expect_const(&self) -> (&'hir Ty<'hir>, BodyId) { + let ItemKind::Const(ty, body) = self.kind else { self.expect_failed("a constant") }; + (ty, body) + } + /// Expect an [`ItemKind::Fn`] or panic. + #[track_caller] + pub fn expect_fn(&self) -> (&FnSig<'hir>, &'hir Generics<'hir>, BodyId) { + let ItemKind::Fn(sig, gen, body) = &self.kind else { self.expect_failed("a function") }; + (sig, gen, *body) + } + + /// Expect an [`ItemKind::Macro`] or panic. + #[track_caller] + pub fn expect_macro(&self) -> (&ast::MacroDef, MacroKind) { + let ItemKind::Macro(def, mk) = &self.kind else { self.expect_failed("a macro") }; + (def, *mk) + } + + /// Expect an [`ItemKind::Mod`] or panic. + #[track_caller] + pub fn expect_mod(&self) -> &'hir Mod<'hir> { + let ItemKind::Mod(m) = self.kind else { self.expect_failed("a module") }; + m + } + + /// Expect an [`ItemKind::ForeignMod`] or panic. + #[track_caller] + pub fn expect_foreign_mod(&self) -> (Abi, &'hir [ForeignItemRef]) { + let ItemKind::ForeignMod { abi, items } = self.kind else { self.expect_failed("a foreign module") }; + (abi, items) + } + + /// Expect an [`ItemKind::GlobalAsm`] or panic. + #[track_caller] + pub fn expect_global_asm(&self) -> &'hir InlineAsm<'hir> { + let ItemKind::GlobalAsm(asm) = self.kind else { self.expect_failed("a global asm") }; + asm + } + + /// Expect an [`ItemKind::TyAlias`] or panic. + #[track_caller] + pub fn expect_ty_alias(&self) -> (&'hir Ty<'hir>, &'hir Generics<'hir>) { + let ItemKind::TyAlias(ty, gen) = self.kind else { self.expect_failed("a type alias") }; + (ty, gen) + } + + /// An opaque `impl Trait` type alias, e.g., `type Foo = impl Bar;`. + /// Expect an [`ItemKind::OpaqueTy`] or panic. + #[track_caller] + pub fn expect_opaque_ty(&self) -> &OpaqueTy<'hir> { + let ItemKind::OpaqueTy(ty) = &self.kind else { self.expect_failed("an opaque type") }; + ty + } + + /// Expect an [`ItemKind::Enum`] or panic. + #[track_caller] + pub fn expect_enum(&self) -> (&EnumDef<'hir>, &'hir Generics<'hir>) { + let ItemKind::Enum(def, gen) = &self.kind else { self.expect_failed("an enum") }; + (def, gen) + } + + /// Expect an [`ItemKind::Struct`] or panic. + #[track_caller] + pub fn expect_struct(&self) -> (&VariantData<'hir>, &'hir Generics<'hir>) { + let ItemKind::Struct(data, gen) = &self.kind else { self.expect_failed("a struct") }; + (data, gen) + } + + /// A union definition, e.g., `union Foo<A, B> {x: A, y: B}`. + /// Expect an [`ItemKind::Union`] or panic. + #[track_caller] + pub fn expect_union(&self) -> (&VariantData<'hir>, &'hir Generics<'hir>) { + let ItemKind::Union(data, gen) = &self.kind else { self.expect_failed("a union") }; + (data, gen) + } + + /// Expect an [`ItemKind::Trait`] or panic. + #[track_caller] + pub fn expect_trait( + self, + ) -> (IsAuto, Unsafety, &'hir Generics<'hir>, GenericBounds<'hir>, &'hir [TraitItemRef]) { + let ItemKind::Trait(is_auto, unsafety, gen, bounds, items) = self.kind else { self.expect_failed("a trait") }; + (is_auto, unsafety, gen, bounds, items) + } + + /// Expect an [`ItemKind::TraitAlias`] or panic. + #[track_caller] + pub fn expect_trait_alias(&self) -> (&'hir Generics<'hir>, GenericBounds<'hir>) { + let ItemKind::TraitAlias(gen, bounds) = self.kind else { self.expect_failed("a trait alias") }; + (gen, bounds) + } + + /// Expect an [`ItemKind::Impl`] or panic. + #[track_caller] + pub fn expect_impl(&self) -> &'hir Impl<'hir> { + let ItemKind::Impl(imp) = self.kind else { self.expect_failed("an impl") }; + imp + } + + #[track_caller] + fn expect_failed(&self, expected: &'static str) -> ! { + panic!("expected {expected} item, found {self:?}") + } } #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] @@ -3597,6 +3775,185 @@ impl<'hir> Node<'hir> { pub fn tuple_fields(&self) -> Option<&'hir [FieldDef<'hir>]> { if let Node::Ctor(&VariantData::Tuple(fields, _, _)) = self { Some(fields) } else { None } } + + /// Expect a [`Node::Param`] or panic. + #[track_caller] + pub fn expect_param(self) -> &'hir Param<'hir> { + let Node::Param(this) = self else { self.expect_failed("a parameter") }; + this + } + + /// Expect a [`Node::Item`] or panic. + #[track_caller] + pub fn expect_item(self) -> &'hir Item<'hir> { + let Node::Item(this) = self else { self.expect_failed("a item") }; + this + } + + /// Expect a [`Node::ForeignItem`] or panic. + #[track_caller] + pub fn expect_foreign_item(self) -> &'hir ForeignItem<'hir> { + let Node::ForeignItem(this) = self else { self.expect_failed("a foreign item") }; + this + } + + /// Expect a [`Node::TraitItem`] or panic. + #[track_caller] + pub fn expect_trait_item(self) -> &'hir TraitItem<'hir> { + let Node::TraitItem(this) = self else { self.expect_failed("a trait item") }; + this + } + + /// Expect a [`Node::ImplItem`] or panic. + #[track_caller] + pub fn expect_impl_item(self) -> &'hir ImplItem<'hir> { + let Node::ImplItem(this) = self else { self.expect_failed("an implementation item") }; + this + } + + /// Expect a [`Node::Variant`] or panic. + #[track_caller] + pub fn expect_variant(self) -> &'hir Variant<'hir> { + let Node::Variant(this) = self else { self.expect_failed("a variant") }; + this + } + + /// Expect a [`Node::Field`] or panic. + #[track_caller] + pub fn expect_field(self) -> &'hir FieldDef<'hir> { + let Node::Field(this) = self else { self.expect_failed("a field definition") }; + this + } + + /// Expect a [`Node::AnonConst`] or panic. + #[track_caller] + pub fn expect_anon_const(self) -> &'hir AnonConst { + let Node::AnonConst(this) = self else { self.expect_failed("an anonymous constant") }; + this + } + + /// Expect a [`Node::Expr`] or panic. + #[track_caller] + pub fn expect_expr(self) -> &'hir Expr<'hir> { + let Node::Expr(this) = self else { self.expect_failed("an expression") }; + this + } + /// Expect a [`Node::ExprField`] or panic. + #[track_caller] + pub fn expect_expr_field(self) -> &'hir ExprField<'hir> { + let Node::ExprField(this) = self else { self.expect_failed("an expression field") }; + this + } + + /// Expect a [`Node::Stmt`] or panic. + #[track_caller] + pub fn expect_stmt(self) -> &'hir Stmt<'hir> { + let Node::Stmt(this) = self else { self.expect_failed("a statement") }; + this + } + + /// Expect a [`Node::PathSegment`] or panic. + #[track_caller] + pub fn expect_path_segment(self) -> &'hir PathSegment<'hir> { + let Node::PathSegment(this) = self else { self.expect_failed("a path segment") }; + this + } + + /// Expect a [`Node::Ty`] or panic. + #[track_caller] + pub fn expect_ty(self) -> &'hir Ty<'hir> { + let Node::Ty(this) = self else { self.expect_failed("a type") }; + this + } + + /// Expect a [`Node::TypeBinding`] or panic. + #[track_caller] + pub fn expect_type_binding(self) -> &'hir TypeBinding<'hir> { + let Node::TypeBinding(this) = self else { self.expect_failed("a type binding") }; + this + } + + /// Expect a [`Node::TraitRef`] or panic. + #[track_caller] + pub fn expect_trait_ref(self) -> &'hir TraitRef<'hir> { + let Node::TraitRef(this) = self else { self.expect_failed("a trait reference") }; + this + } + + /// Expect a [`Node::Pat`] or panic. + #[track_caller] + pub fn expect_pat(self) -> &'hir Pat<'hir> { + let Node::Pat(this) = self else { self.expect_failed("a pattern") }; + this + } + + /// Expect a [`Node::PatField`] or panic. + #[track_caller] + pub fn expect_pat_field(self) -> &'hir PatField<'hir> { + let Node::PatField(this) = self else { self.expect_failed("a pattern field") }; + this + } + + /// Expect a [`Node::Arm`] or panic. + #[track_caller] + pub fn expect_arm(self) -> &'hir Arm<'hir> { + let Node::Arm(this) = self else { self.expect_failed("an arm") }; + this + } + + /// Expect a [`Node::Block`] or panic. + #[track_caller] + pub fn expect_block(self) -> &'hir Block<'hir> { + let Node::Block(this) = self else { self.expect_failed("a block") }; + this + } + + /// Expect a [`Node::Local`] or panic. + #[track_caller] + pub fn expect_local(self) -> &'hir Local<'hir> { + let Node::Local(this) = self else { self.expect_failed("a local") }; + this + } + + /// Expect a [`Node::Ctor`] or panic. + #[track_caller] + pub fn expect_ctor(self) -> &'hir VariantData<'hir> { + let Node::Ctor(this) = self else { self.expect_failed("a constructor") }; + this + } + + /// Expect a [`Node::Lifetime`] or panic. + #[track_caller] + pub fn expect_lifetime(self) -> &'hir Lifetime { + let Node::Lifetime(this) = self else { self.expect_failed("a lifetime") }; + this + } + + /// Expect a [`Node::GenericParam`] or panic. + #[track_caller] + pub fn expect_generic_param(self) -> &'hir GenericParam<'hir> { + let Node::GenericParam(this) = self else { self.expect_failed("a generic parameter") }; + this + } + + /// Expect a [`Node::Crate`] or panic. + #[track_caller] + pub fn expect_crate(self) -> &'hir Mod<'hir> { + let Node::Crate(this) = self else { self.expect_failed("a crate") }; + this + } + + /// Expect a [`Node::Infer`] or panic. + #[track_caller] + pub fn expect_infer(self) -> &'hir InferArg { + let Node::Infer(this) = self else { self.expect_failed("an infer") }; + this + } + + #[track_caller] + fn expect_failed(&self, expected: &'static str) -> ! { + panic!("expected {expected} node, found {self:?}") + } } // Some nodes are used a lot. Make sure they don't unintentionally get bigger. diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs index caf26a75d3c..bec9f0ff077 100644 --- a/compiler/rustc_hir_analysis/src/astconv/mod.rs +++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs @@ -3140,8 +3140,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Fn(..), ident, .. }) = hir.get(fn_hir_id) else { return None }; - let hir::Node::Item(hir::Item { kind: hir::ItemKind::Impl(i), .. }) = - hir.get_parent(fn_hir_id) else { bug!("ImplItem should have Impl parent") }; + let i = hir.get_parent(fn_hir_id).expect_item().expect_impl(); let trait_ref = self.instantiate_mono_trait_ref( i.of_trait.as_ref()?, diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index 780d5271619..3115f5f464a 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -8,7 +8,7 @@ use rustc_errors::{ use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::intravisit; -use rustc_hir::{GenericParamKind, ImplItemKind, TraitItemKind}; +use rustc_hir::{GenericParamKind, ImplItemKind}; use rustc_infer::infer::outlives::env::OutlivesEnvironment; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_infer::infer::{self, InferCtxt, TyCtxtInferExt}; @@ -918,7 +918,7 @@ fn report_trait_method_mismatch<'tcx>( // When the `impl` receiver is an arbitrary self type, like `self: Box<Self>`, the // span points only at the type `Box<Self`>, but we want to cover the whole // argument pattern and type. - let ImplItemKind::Fn(ref sig, body) = tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind else { bug!("{impl_m:?} is not a method") }; + let (sig, body) = tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).expect_fn(); let span = tcx .hir() .body_param_names(body) @@ -1080,12 +1080,12 @@ fn extract_spans_for_error_reporting<'tcx>( ) -> (Span, Option<Span>) { let tcx = infcx.tcx; let mut impl_args = { - let ImplItemKind::Fn(sig, _) = &tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind else { bug!("{:?} is not a method", impl_m) }; + let (sig, _) = tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).expect_fn(); sig.decl.inputs.iter().map(|t| t.span).chain(iter::once(sig.decl.output.span())) }; let trait_args = trait_m.def_id.as_local().map(|def_id| { - let TraitItemKind::Fn(sig, _) = &tcx.hir().expect_trait_item(def_id).kind else { bug!("{:?} is not a TraitItemKind::Fn", trait_m) }; + let (sig, _) = tcx.hir().expect_trait_item(def_id).expect_fn(); sig.decl.inputs.iter().map(|t| t.span).chain(iter::once(sig.decl.output.span())) }); @@ -1358,7 +1358,7 @@ fn compare_number_of_method_arguments<'tcx>( .def_id .as_local() .and_then(|def_id| { - let TraitItemKind::Fn(trait_m_sig, _) = &tcx.hir().expect_trait_item(def_id).kind else { bug!("{:?} is not a method", impl_m) }; + let (trait_m_sig, _) = &tcx.hir().expect_trait_item(def_id).expect_fn(); let pos = trait_number_args.saturating_sub(1); trait_m_sig.decl.inputs.get(pos).map(|arg| { if pos == 0 { @@ -1370,7 +1370,7 @@ fn compare_number_of_method_arguments<'tcx>( }) .or(trait_item_span); - let ImplItemKind::Fn(impl_m_sig, _) = &tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind else { bug!("{:?} is not a method", impl_m) }; + let (impl_m_sig, _) = &tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).expect_fn(); let pos = impl_number_args.saturating_sub(1); let impl_span = impl_m_sig .decl @@ -1506,7 +1506,7 @@ fn compare_synthetic_generics<'tcx>( let _: Option<_> = try { let impl_m = impl_m.def_id.as_local()?; let impl_m = tcx.hir().expect_impl_item(impl_m); - let hir::ImplItemKind::Fn(sig, _) = &impl_m.kind else { unreachable!() }; + let (sig, _) = impl_m.expect_fn(); let input_tys = sig.decl.inputs; struct Visitor(Option<Span>, hir::def_id::LocalDefId); @@ -1704,7 +1704,7 @@ pub(super) fn compare_impl_const_raw( ); // Locate the Span containing just the type of the offending impl - let ImplItemKind::Const(ty, _) = tcx.hir().expect_impl_item(impl_const_item_def).kind else { bug!("{impl_const_item:?} is not a impl const") }; + let (ty, _) = tcx.hir().expect_impl_item(impl_const_item_def).expect_const(); cause.span = ty.span; let mut diag = struct_span_err!( @@ -1717,7 +1717,7 @@ pub(super) fn compare_impl_const_raw( let trait_c_span = trait_const_item_def.as_local().map(|trait_c_def_id| { // Add a label to the Span containing just the type of the const - let TraitItemKind::Const(ty, _) = tcx.hir().expect_trait_item(trait_c_def_id).kind else { bug!("{trait_const_item:?} is not a trait const") }; + let (ty, _) = tcx.hir().expect_trait_item(trait_c_def_id).expect_const(); ty.span }); diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 67bcfb1cb70..5b9b57da382 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -1072,8 +1072,8 @@ fn check_type_defn<'tcx>(tcx: TyCtxt<'tcx>, item: &hir::Item<'tcx>, all_sized: b // All field types must be well-formed. for field in &variant.fields { let field_id = field.did.expect_local(); - let hir::Node::Field(hir::FieldDef { ty: hir_ty, .. }) = tcx.hir().get_by_def_id(field_id) - else { bug!() }; + let hir::FieldDef { ty: hir_ty, .. } = + tcx.hir().get_by_def_id(field_id).expect_field(); let ty = wfcx.normalize(hir_ty.span, None, tcx.type_of(field.did)); wfcx.register_wf_obligation( hir_ty.span, @@ -1106,8 +1106,8 @@ fn check_type_defn<'tcx>(tcx: TyCtxt<'tcx>, item: &hir::Item<'tcx>, all_sized: b { let last = idx == variant.fields.len() - 1; let field_id = field.did.expect_local(); - let hir::Node::Field(hir::FieldDef { ty: hir_ty, .. }) = tcx.hir().get_by_def_id(field_id) - else { bug!() }; + let hir::FieldDef { ty: hir_ty, .. } = + tcx.hir().get_by_def_id(field_id).expect_field(); let ty = wfcx.normalize(hir_ty.span, None, tcx.type_of(field.did)); wfcx.register_bound( traits::ObligationCause::new( diff --git a/compiler/rustc_hir_analysis/src/check_unused.rs b/compiler/rustc_hir_analysis/src/check_unused.rs index ebb78213a63..5716be4f1a9 100644 --- a/compiler/rustc_hir_analysis/src/check_unused.rs +++ b/compiler/rustc_hir_analysis/src/check_unused.rs @@ -29,7 +29,7 @@ pub fn check_crate(tcx: TyCtxt<'_>) { if item.span.is_dummy() { continue; } - let hir::ItemKind::Use(path, _) = item.kind else { unreachable!() }; + let (path, _) = item.expect_use(); let msg = if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(path.span) { format!("unused import: `{}`", snippet) } else { diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs index 76668f7e9ac..6600e4216bd 100644 --- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs +++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs @@ -56,7 +56,7 @@ fn visit_implementation_of_drop(tcx: TyCtxt<'_>, impl_did: LocalDefId) { _ => {} } - let ItemKind::Impl(impl_) = tcx.hir().expect_item(impl_did).kind else { bug!("expected Drop impl item") }; + let impl_ = tcx.hir().expect_item(impl_did).expect_impl(); tcx.sess.emit_err(DropImplOnWrongItem { span: impl_.self_ty.span }); } diff --git a/compiler/rustc_hir_analysis/src/coherence/unsafety.rs b/compiler/rustc_hir_analysis/src/coherence/unsafety.rs index fe6119dce87..c6b16171311 100644 --- a/compiler/rustc_hir_analysis/src/coherence/unsafety.rs +++ b/compiler/rustc_hir_analysis/src/coherence/unsafety.rs @@ -3,15 +3,13 @@ use rustc_errors::struct_span_err; use rustc_hir as hir; -use rustc_hir::def::DefKind; use rustc_hir::Unsafety; use rustc_middle::ty::TyCtxt; use rustc_span::def_id::LocalDefId; pub(super) fn check_item(tcx: TyCtxt<'_>, def_id: LocalDefId) { - debug_assert!(matches!(tcx.def_kind(def_id), DefKind::Impl)); let item = tcx.hir().expect_item(def_id); - let hir::ItemKind::Impl(impl_) = item.kind else { bug!() }; + let impl_ = item.expect_impl(); if let Some(trait_ref) = tcx.impl_trait_ref(item.owner_id) { let trait_ref = trait_ref.subst_identity(); diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index f5a1e51c07b..cc7235a61c0 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -1348,8 +1348,7 @@ fn suggest_impl_trait<'tcx>( fn impl_trait_ref(tcx: TyCtxt<'_>, def_id: DefId) -> Option<ty::EarlyBinder<ty::TraitRef<'_>>> { let icx = ItemCtxt::new(tcx, def_id); - let item = tcx.hir().expect_item(def_id.expect_local()); - let hir::ItemKind::Impl(impl_) = item.kind else { bug!() }; + let impl_ = tcx.hir().expect_item(def_id.expect_local()).expect_impl(); impl_ .of_trait .as_ref() diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index 8046cc21cea..d1d4bb37528 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -882,6 +882,9 @@ pub trait LintContext: Sized { ); } } + BuiltinLintDiagnostics::ByteSliceInPackedStructWithDerive => { + db.help("consider implementing the trait by hand, or remove the `packed` attribute"); + } } // Rewrap `db`, and pass control to the user. decorate(db) diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index b6481d70bc8..d731c10f46e 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -3381,6 +3381,7 @@ declare_lint_pass! { REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS, NAMED_ARGUMENTS_USED_POSITIONALLY, IMPLIED_BOUNDS_ENTAILMENT, + BYTE_SLICE_IN_PACKED_STRUCT_WITH_DERIVE, ] } @@ -3531,9 +3532,15 @@ declare_lint! { /// /// ### Explanation /// - /// Previously, there were very like checks being performed on `#[doc(..)]` - /// unlike the other attributes. It'll now catch all the issues that it - /// silently ignored previously. + /// Previously, incorrect usage of the `#[doc(..)]` attribute was not + /// being validated. Usually these should be rejected as a hard error, + /// but this lint was introduced to avoid breaking any existing + /// crates which included them. + /// + /// This is a [future-incompatible] lint to transition this to a hard + /// error in the future. See [issue #82730] for more details. + /// + /// [issue #82730]: https://github.com/rust-lang/rust/issues/82730 pub INVALID_DOC_ATTRIBUTES, Warn, "detects invalid `#[doc(...)]` attributes", @@ -4109,3 +4116,35 @@ declare_lint! { reason: FutureIncompatibilityReason::FutureReleaseErrorReportNow, }; } + +declare_lint! { + /// The `byte_slice_in_packed_struct_with_derive` lint detects cases where a byte slice field + /// (`[u8]`) is used in a `packed` struct that derives one or more built-in traits. + /// + /// ### Example + /// + /// ```rust + /// #[repr(packed)] + /// #[derive(Hash)] + /// struct FlexZeroSlice { + /// width: u8, + /// data: [u8], + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// This was previously accepted but is being phased out, because fields in packed structs are + /// now required to implement `Copy` for `derive` to work. Byte slices are a temporary + /// exception because certain crates depended on them. + pub BYTE_SLICE_IN_PACKED_STRUCT_WITH_DERIVE, + Warn, + "`[u8]` slice used in a packed struct with `derive`", + @future_incompatible = FutureIncompatibleInfo { + reference: "issue #107457 <https://github.com/rust-lang/rust/issues/107457>", + reason: FutureIncompatibilityReason::FutureReleaseErrorReportNow, + }; + report_in_external_macro +} diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index 7054d1e9f10..6efbf5ce9ee 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -521,6 +521,7 @@ pub enum BuiltinLintDiagnostics { /// Indicates if the named argument is used as a width/precision for formatting is_formatting_arg: bool, }, + ByteSliceInPackedStructWithDerive, } /// Lints that are buffered up early on in the `Session` before the diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 3917a97db4f..4cebe416354 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -183,6 +183,15 @@ rustc_queries! { separate_provide_extern } + query unsizing_params_for_adt(key: DefId) -> rustc_index::bit_set::BitSet<u32> + { + arena_cache + desc { |tcx| + "determining what parameters of `{}` can participate in unsizing", + tcx.def_path_str(key), + } + } + query analysis(key: ()) -> Result<(), ErrorGuaranteed> { eval_always desc { "running analysis passes on this crate" } @@ -361,6 +370,13 @@ rustc_queries! { desc { |tcx| "constructing THIR tree for `{}`", tcx.def_path_str(key.did.to_def_id()) } } + /// Create a list-like THIR representation for debugging. + query thir_flat(key: ty::WithOptConstParam<LocalDefId>) -> String { + no_hash + arena_cache + desc { |tcx| "constructing flat THIR representation for `{}`", tcx.def_path_str(key.did.to_def_id()) } + } + /// Set of all the `DefId`s in this crate that have MIR associated with /// them. This includes all the body owners, but also things like struct /// constructors. @@ -807,15 +823,6 @@ rustc_queries! { } } - /// HACK: when evaluated, this reports an "unsafe derive on repr(packed)" error. - /// - /// Unsafety checking is executed for each method separately, but we only want - /// to emit this error once per derive. As there are some impls with multiple - /// methods, we use a query for deduplication. - query unsafe_derive_on_repr_packed(key: LocalDefId) -> () { - desc { |tcx| "processing `{}`", tcx.def_path_str(key.to_def_id()) } - } - /// Returns the types assumed to be well formed while "inside" of the given item. /// /// Note that we've liberated the late bound regions of function signatures, so diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index 5f320708c84..6f2dac46753 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -29,6 +29,7 @@ use rustc_target::asm::InlineAsmRegOrRegClass; use std::fmt; use std::ops::Index; +pub mod print; pub mod visit; macro_rules! thir_with_elements { diff --git a/compiler/rustc_middle/src/thir/print.rs b/compiler/rustc_middle/src/thir/print.rs new file mode 100644 index 00000000000..60b903e9906 --- /dev/null +++ b/compiler/rustc_middle/src/thir/print.rs @@ -0,0 +1,881 @@ +use crate::thir::*; +use crate::ty::{self, TyCtxt}; + +use std::fmt::{self, Write}; + +impl<'tcx> TyCtxt<'tcx> { + pub fn thir_tree_representation<'a>(self, thir: &'a Thir<'tcx>) -> String { + let mut printer = ThirPrinter::new(thir); + printer.print(); + printer.into_buffer() + } +} + +struct ThirPrinter<'a, 'tcx> { + thir: &'a Thir<'tcx>, + fmt: String, +} + +const INDENT: &str = " "; + +macro_rules! print_indented { + ($writer:ident, $s:expr, $indent_lvl:expr) => { + let indent = (0..$indent_lvl).map(|_| INDENT).collect::<Vec<_>>().concat(); + writeln!($writer, "{}{}", indent, $s).expect("unable to write to ThirPrinter"); + }; +} + +impl<'a, 'tcx> Write for ThirPrinter<'a, 'tcx> { + fn write_str(&mut self, s: &str) -> fmt::Result { + self.fmt.push_str(s); + Ok(()) + } +} + +impl<'a, 'tcx> ThirPrinter<'a, 'tcx> { + fn new(thir: &'a Thir<'tcx>) -> Self { + Self { thir, fmt: String::new() } + } + + fn print(&mut self) { + print_indented!(self, "params: [", 0); + for param in self.thir.params.iter() { + self.print_param(param, 1); + } + print_indented!(self, "]", 0); + + print_indented!(self, "body:", 0); + let expr = ExprId::from_usize(self.thir.exprs.len() - 1); + self.print_expr(expr, 1); + } + + fn into_buffer(self) -> String { + self.fmt + } + + fn print_param(&mut self, param: &Param<'tcx>, depth_lvl: usize) { + let Param { pat, ty, ty_span, self_kind, hir_id } = param; + + print_indented!(self, "Param {", depth_lvl); + print_indented!(self, format!("ty: {:?}", ty), depth_lvl + 1); + print_indented!(self, format!("ty_span: {:?}", ty_span), depth_lvl + 1); + print_indented!(self, format!("self_kind: {:?}", self_kind), depth_lvl + 1); + print_indented!(self, format!("hir_id: {:?}", hir_id), depth_lvl + 1); + + if let Some(pat) = pat { + print_indented!(self, "param: Some( ", depth_lvl + 1); + self.print_pat(pat, depth_lvl + 2); + print_indented!(self, ")", depth_lvl + 1); + } else { + print_indented!(self, "param: None", depth_lvl + 1); + } + + print_indented!(self, "}", depth_lvl); + } + + fn print_block(&mut self, block_id: BlockId, depth_lvl: usize) { + let Block { + targeted_by_break, + opt_destruction_scope, + span, + region_scope, + stmts, + expr, + safety_mode, + } = &self.thir.blocks[block_id]; + + print_indented!(self, "Block {", depth_lvl); + print_indented!(self, format!("targeted_by_break: {}", targeted_by_break), depth_lvl + 1); + print_indented!( + self, + format!("opt_destruction_scope: {:?}", opt_destruction_scope), + depth_lvl + 1 + ); + print_indented!(self, format!("span: {:?}", span), depth_lvl + 1); + print_indented!(self, format!("region_scope: {:?}", region_scope), depth_lvl + 1); + print_indented!(self, format!("safety_mode: {:?}", safety_mode), depth_lvl + 1); + + if stmts.len() > 0 { + print_indented!(self, "stmts: [", depth_lvl + 1); + for stmt in stmts.iter() { + self.print_stmt(*stmt, depth_lvl + 2); + } + print_indented!(self, "]", depth_lvl + 1); + } else { + print_indented!(self, "stmts: []", depth_lvl + 1); + } + + if let Some(expr_id) = expr { + print_indented!(self, "expr:", depth_lvl + 1); + self.print_expr(*expr_id, depth_lvl + 2); + } else { + print_indented!(self, "expr: []", depth_lvl + 1); + } + + print_indented!(self, "}", depth_lvl); + } + + fn print_stmt(&mut self, stmt_id: StmtId, depth_lvl: usize) { + let Stmt { kind, opt_destruction_scope } = &self.thir.stmts[stmt_id]; + + print_indented!(self, "Stmt {", depth_lvl); + print_indented!( + self, + format!("opt_destruction_scope: {:?}", opt_destruction_scope), + depth_lvl + 1 + ); + + match kind { + StmtKind::Expr { scope, expr } => { + print_indented!(self, "kind: Expr {", depth_lvl + 1); + print_indented!(self, format!("scope: {:?}", scope), depth_lvl + 2); + print_indented!(self, "expr:", depth_lvl + 2); + self.print_expr(*expr, depth_lvl + 3); + print_indented!(self, "}", depth_lvl + 1); + } + StmtKind::Let { + remainder_scope, + init_scope, + pattern, + initializer, + else_block, + lint_level, + } => { + print_indented!(self, "kind: Let {", depth_lvl + 1); + print_indented!( + self, + format!("remainder_scope: {:?}", remainder_scope), + depth_lvl + 2 + ); + print_indented!(self, format!("init_scope: {:?}", init_scope), depth_lvl + 2); + + print_indented!(self, "pattern: ", depth_lvl + 2); + self.print_pat(pattern, depth_lvl + 3); + print_indented!(self, ",", depth_lvl + 2); + + if let Some(init) = initializer { + print_indented!(self, "initializer: Some(", depth_lvl + 2); + self.print_expr(*init, depth_lvl + 3); + print_indented!(self, ")", depth_lvl + 2); + } else { + print_indented!(self, "initializer: None", depth_lvl + 2); + } + + if let Some(else_block) = else_block { + print_indented!(self, "else_block: Some(", depth_lvl + 2); + self.print_block(*else_block, depth_lvl + 3); + print_indented!(self, ")", depth_lvl + 2); + } else { + print_indented!(self, "else_block: None", depth_lvl + 2); + } + + print_indented!(self, format!("lint_level: {:?}", lint_level), depth_lvl + 2); + print_indented!(self, "}", depth_lvl + 1); + } + } + + print_indented!(self, "}", depth_lvl); + } + + fn print_expr(&mut self, expr: ExprId, depth_lvl: usize) { + let Expr { ty, temp_lifetime, span, kind } = &self.thir[expr]; + print_indented!(self, "Expr {", depth_lvl); + print_indented!(self, format!("ty: {:?}", ty), depth_lvl + 1); + print_indented!(self, format!("temp_lifetime: {:?}", temp_lifetime), depth_lvl + 1); + print_indented!(self, format!("span: {:?}", span), depth_lvl + 1); + print_indented!(self, "kind: ", depth_lvl + 1); + self.print_expr_kind(kind, depth_lvl + 2); + print_indented!(self, "}", depth_lvl); + } + + fn print_expr_kind(&mut self, expr_kind: &ExprKind<'tcx>, depth_lvl: usize) { + use rustc_middle::thir::ExprKind::*; + + match expr_kind { + Scope { region_scope, value, lint_level } => { + print_indented!(self, "Scope {", depth_lvl); + print_indented!(self, format!("region_scope: {:?}", region_scope), depth_lvl + 1); + print_indented!(self, format!("lint_level: {:?}", lint_level), depth_lvl + 1); + print_indented!(self, "value:", depth_lvl + 1); + self.print_expr(*value, depth_lvl + 2); + print_indented!(self, "}", depth_lvl); + } + Box { value } => { + print_indented!(self, "Box {", depth_lvl); + self.print_expr(*value, depth_lvl + 1); + print_indented!(self, "}", depth_lvl); + } + If { if_then_scope, cond, then, else_opt } => { + print_indented!(self, "If {", depth_lvl); + print_indented!(self, format!("if_then_scope: {:?}", if_then_scope), depth_lvl + 1); + print_indented!(self, "cond:", depth_lvl + 1); + self.print_expr(*cond, depth_lvl + 2); + print_indented!(self, "then:", depth_lvl + 1); + self.print_expr(*then, depth_lvl + 2); + + if let Some(else_expr) = else_opt { + print_indented!(self, "else:", depth_lvl + 1); + self.print_expr(*else_expr, depth_lvl + 2); + } + + print_indented!(self, "}", depth_lvl); + } + Call { fun, args, ty, from_hir_call, fn_span } => { + print_indented!(self, "Call {", depth_lvl); + print_indented!(self, format!("ty: {:?}", ty), depth_lvl + 1); + print_indented!(self, format!("from_hir_call: {}", from_hir_call), depth_lvl + 1); + print_indented!(self, format!("fn_span: {:?}", fn_span), depth_lvl + 1); + print_indented!(self, "fun:", depth_lvl + 1); + self.print_expr(*fun, depth_lvl + 2); + + if args.len() > 0 { + print_indented!(self, "args: [", depth_lvl + 1); + for arg in args.iter() { + self.print_expr(*arg, depth_lvl + 2); + } + print_indented!(self, "]", depth_lvl + 1); + } else { + print_indented!(self, "args: []", depth_lvl + 1); + } + + print_indented!(self, "}", depth_lvl); + } + Deref { arg } => { + print_indented!(self, "Deref {", depth_lvl); + self.print_expr(*arg, depth_lvl + 1); + print_indented!(self, "}", depth_lvl); + } + Binary { op, lhs, rhs } => { + print_indented!(self, "Binary {", depth_lvl); + print_indented!(self, format!("op: {:?}", op), depth_lvl + 1); + print_indented!(self, "lhs:", depth_lvl + 1); + self.print_expr(*lhs, depth_lvl + 2); + print_indented!(self, "rhs:", depth_lvl + 1); + self.print_expr(*rhs, depth_lvl + 2); + print_indented!(self, "}", depth_lvl); + } + LogicalOp { op, lhs, rhs } => { + print_indented!(self, "LogicalOp {", depth_lvl); + print_indented!(self, format!("op: {:?}", op), depth_lvl + 1); + print_indented!(self, "lhs:", depth_lvl + 1); + self.print_expr(*lhs, depth_lvl + 2); + print_indented!(self, "rhs:", depth_lvl + 1); + self.print_expr(*rhs, depth_lvl + 2); + print_indented!(self, "}", depth_lvl); + } + Unary { op, arg } => { + print_indented!(self, "Unary {", depth_lvl); + print_indented!(self, format!("op: {:?}", op), depth_lvl + 1); + print_indented!(self, "arg:", depth_lvl + 1); + self.print_expr(*arg, depth_lvl + 2); + print_indented!(self, "}", depth_lvl); + } + Cast { source } => { + print_indented!(self, "Cast {", depth_lvl); + print_indented!(self, "source:", depth_lvl + 1); + self.print_expr(*source, depth_lvl + 2); + print_indented!(self, "}", depth_lvl); + } + Use { source } => { + print_indented!(self, "Use {", depth_lvl); + print_indented!(self, "source:", depth_lvl + 1); + self.print_expr(*source, depth_lvl + 2); + print_indented!(self, "}", depth_lvl); + } + NeverToAny { source } => { + print_indented!(self, "NeverToAny {", depth_lvl); + print_indented!(self, "source:", depth_lvl + 1); + self.print_expr(*source, depth_lvl + 2); + print_indented!(self, "}", depth_lvl); + } + Pointer { cast, source } => { + print_indented!(self, "Pointer {", depth_lvl); + print_indented!(self, format!("cast: {:?}", cast), depth_lvl + 1); + print_indented!(self, "source:", depth_lvl + 1); + self.print_expr(*source, depth_lvl + 2); + print_indented!(self, "}", depth_lvl); + } + Loop { body } => { + print_indented!(self, "Loop (", depth_lvl); + print_indented!(self, "body:", depth_lvl + 1); + self.print_expr(*body, depth_lvl + 2); + print_indented!(self, ")", depth_lvl); + } + Let { expr, pat } => { + print_indented!(self, "Let {", depth_lvl); + print_indented!(self, "expr:", depth_lvl + 1); + self.print_expr(*expr, depth_lvl + 2); + print_indented!(self, format!("pat: {:?}", pat), depth_lvl + 1); + print_indented!(self, "}", depth_lvl); + } + Match { scrutinee, arms } => { + print_indented!(self, "Match {", depth_lvl); + print_indented!(self, "scrutinee:", depth_lvl + 1); + self.print_expr(*scrutinee, depth_lvl + 2); + + print_indented!(self, "arms: [", depth_lvl + 1); + for arm_id in arms.iter() { + self.print_arm(*arm_id, depth_lvl + 2); + } + print_indented!(self, "]", depth_lvl + 1); + print_indented!(self, "}", depth_lvl); + } + Block { block } => self.print_block(*block, depth_lvl), + Assign { lhs, rhs } => { + print_indented!(self, "Assign {", depth_lvl); + print_indented!(self, "lhs:", depth_lvl + 1); + self.print_expr(*lhs, depth_lvl + 2); + print_indented!(self, "rhs:", depth_lvl + 1); + self.print_expr(*rhs, depth_lvl + 2); + print_indented!(self, "}", depth_lvl); + } + AssignOp { op, lhs, rhs } => { + print_indented!(self, "AssignOp {", depth_lvl); + print_indented!(self, format!("op: {:?}", op), depth_lvl + 1); + print_indented!(self, "lhs:", depth_lvl + 1); + self.print_expr(*lhs, depth_lvl + 2); + print_indented!(self, "rhs:", depth_lvl + 1); + self.print_expr(*rhs, depth_lvl + 2); + print_indented!(self, "}", depth_lvl); + } + Field { lhs, variant_index, name } => { + print_indented!(self, "Field {", depth_lvl); + print_indented!(self, format!("variant_index: {:?}", variant_index), depth_lvl + 1); + print_indented!(self, format!("name: {:?}", name), depth_lvl + 1); + print_indented!(self, "lhs:", depth_lvl + 1); + self.print_expr(*lhs, depth_lvl + 2); + print_indented!(self, "}", depth_lvl); + } + Index { lhs, index } => { + print_indented!(self, "Index {", depth_lvl); + print_indented!(self, format!("index: {:?}", index), depth_lvl + 1); + print_indented!(self, "lhs:", depth_lvl + 1); + self.print_expr(*lhs, depth_lvl + 2); + print_indented!(self, "}", depth_lvl); + } + VarRef { id } => { + print_indented!(self, "VarRef {", depth_lvl); + print_indented!(self, format!("id: {:?}", id), depth_lvl + 1); + print_indented!(self, "}", depth_lvl); + } + UpvarRef { closure_def_id, var_hir_id } => { + print_indented!(self, "UpvarRef {", depth_lvl); + print_indented!( + self, + format!("closure_def_id: {:?}", closure_def_id), + depth_lvl + 1 + ); + print_indented!(self, format!("var_hir_id: {:?}", var_hir_id), depth_lvl + 1); + print_indented!(self, "}", depth_lvl); + } + Borrow { borrow_kind, arg } => { + print_indented!(self, "Borrow (", depth_lvl); + print_indented!(self, format!("borrow_kind: {:?}", borrow_kind), depth_lvl + 1); + print_indented!(self, "arg:", depth_lvl + 1); + self.print_expr(*arg, depth_lvl + 2); + print_indented!(self, ")", depth_lvl); + } + AddressOf { mutability, arg } => { + print_indented!(self, "AddressOf {", depth_lvl); + print_indented!(self, format!("mutability: {:?}", mutability), depth_lvl + 1); + print_indented!(self, "arg:", depth_lvl + 1); + self.print_expr(*arg, depth_lvl + 2); + print_indented!(self, "}", depth_lvl); + } + Break { label, value } => { + print_indented!(self, "Break (", depth_lvl); + print_indented!(self, format!("label: {:?}", label), depth_lvl + 1); + + if let Some(value) = value { + print_indented!(self, "value:", depth_lvl + 1); + self.print_expr(*value, depth_lvl + 2); + } + + print_indented!(self, ")", depth_lvl); + } + Continue { label } => { + print_indented!(self, "Continue {", depth_lvl); + print_indented!(self, format!("label: {:?}", label), depth_lvl + 1); + print_indented!(self, "}", depth_lvl); + } + Return { value } => { + print_indented!(self, "Return {", depth_lvl); + print_indented!(self, "value:", depth_lvl + 1); + + if let Some(value) = value { + self.print_expr(*value, depth_lvl + 2); + } + + print_indented!(self, "}", depth_lvl); + } + ConstBlock { did, substs } => { + print_indented!(self, "ConstBlock {", depth_lvl); + print_indented!(self, format!("did: {:?}", did), depth_lvl + 1); + print_indented!(self, format!("substs: {:?}", substs), depth_lvl + 1); + print_indented!(self, "}", depth_lvl); + } + Repeat { value, count } => { + print_indented!(self, "Repeat {", depth_lvl); + print_indented!(self, format!("count: {:?}", count), depth_lvl + 1); + print_indented!(self, "value:", depth_lvl + 1); + self.print_expr(*value, depth_lvl + 2); + print_indented!(self, "}", depth_lvl); + } + Array { fields } => { + print_indented!(self, "Array {", depth_lvl); + print_indented!(self, "fields: [", depth_lvl + 1); + for field_id in fields.iter() { + self.print_expr(*field_id, depth_lvl + 2); + } + print_indented!(self, "]", depth_lvl + 1); + print_indented!(self, "}", depth_lvl); + } + Tuple { fields } => { + print_indented!(self, "Tuple {", depth_lvl); + print_indented!(self, "fields: [", depth_lvl + 1); + for field_id in fields.iter() { + self.print_expr(*field_id, depth_lvl + 2); + } + print_indented!(self, "]", depth_lvl + 1); + print_indented!(self, "}", depth_lvl); + } + Adt(adt_expr) => { + print_indented!(self, "Adt {", depth_lvl); + self.print_adt_expr(&**adt_expr, depth_lvl + 1); + print_indented!(self, "}", depth_lvl); + } + PlaceTypeAscription { source, user_ty } => { + print_indented!(self, "PlaceTypeAscription {", depth_lvl); + print_indented!(self, format!("user_ty: {:?}", user_ty), depth_lvl + 1); + print_indented!(self, "source:", depth_lvl + 1); + self.print_expr(*source, depth_lvl + 2); + print_indented!(self, "}", depth_lvl); + } + ValueTypeAscription { source, user_ty } => { + print_indented!(self, "ValueTypeAscription {", depth_lvl); + print_indented!(self, format!("user_ty: {:?}", user_ty), depth_lvl + 1); + print_indented!(self, "source:", depth_lvl + 1); + self.print_expr(*source, depth_lvl + 2); + print_indented!(self, "}", depth_lvl); + } + Closure(closure_expr) => { + print_indented!(self, "Closure {", depth_lvl); + print_indented!(self, "closure_expr:", depth_lvl + 1); + self.print_closure_expr(&**closure_expr, depth_lvl + 2); + print_indented!(self, "}", depth_lvl); + } + Literal { lit, neg } => { + print_indented!( + self, + format!("Literal( lit: {:?}, neg: {:?})\n", lit, neg), + depth_lvl + ); + } + NonHirLiteral { lit, user_ty } => { + print_indented!(self, "NonHirLiteral {", depth_lvl); + print_indented!(self, format!("lit: {:?}", lit), depth_lvl + 1); + print_indented!(self, format!("user_ty: {:?}", user_ty), depth_lvl + 1); + print_indented!(self, "}", depth_lvl); + } + ZstLiteral { user_ty } => { + print_indented!(self, format!("ZstLiteral(user_ty: {:?})", user_ty), depth_lvl); + } + NamedConst { def_id, substs, user_ty } => { + print_indented!(self, "NamedConst {", depth_lvl); + print_indented!(self, format!("def_id: {:?}", def_id), depth_lvl + 1); + print_indented!(self, format!("user_ty: {:?}", user_ty), depth_lvl + 1); + print_indented!(self, format!("substs: {:?}", substs), depth_lvl + 1); + print_indented!(self, "}", depth_lvl); + } + ConstParam { param, def_id } => { + print_indented!(self, "ConstParam {", depth_lvl); + print_indented!(self, format!("def_id: {:?}", def_id), depth_lvl + 1); + print_indented!(self, format!("param: {:?}", param), depth_lvl + 1); + print_indented!(self, "}", depth_lvl); + } + StaticRef { alloc_id, ty, def_id } => { + print_indented!(self, "StaticRef {", depth_lvl); + print_indented!(self, format!("def_id: {:?}", def_id), depth_lvl + 1); + print_indented!(self, format!("ty: {:?}", ty), depth_lvl + 1); + print_indented!(self, format!("alloc_id: {:?}", alloc_id), depth_lvl + 1); + print_indented!(self, "}", depth_lvl); + } + InlineAsm(expr) => { + print_indented!(self, "InlineAsm {", depth_lvl); + print_indented!(self, "expr:", depth_lvl + 1); + self.print_inline_asm_expr(&**expr, depth_lvl + 2); + print_indented!(self, "}", depth_lvl); + } + ThreadLocalRef(def_id) => { + print_indented!(self, "ThreadLocalRef {", depth_lvl); + print_indented!(self, format!("def_id: {:?}", def_id), depth_lvl + 1); + print_indented!(self, "}", depth_lvl); + } + Yield { value } => { + print_indented!(self, "Yield {", depth_lvl); + print_indented!(self, "value:", depth_lvl + 1); + self.print_expr(*value, depth_lvl + 2); + print_indented!(self, "}", depth_lvl); + } + } + } + + fn print_adt_expr(&mut self, adt_expr: &AdtExpr<'tcx>, depth_lvl: usize) { + print_indented!(self, "adt_def:", depth_lvl); + self.print_adt_def(adt_expr.adt_def, depth_lvl + 1); + print_indented!( + self, + format!("variant_index: {:?}", adt_expr.variant_index), + depth_lvl + 1 + ); + print_indented!(self, format!("substs: {:?}", adt_expr.substs), depth_lvl + 1); + print_indented!(self, format!("user_ty: {:?}", adt_expr.user_ty), depth_lvl + 1); + + for (i, field_expr) in adt_expr.fields.iter().enumerate() { + print_indented!(self, format!("field {}:", i), depth_lvl + 1); + self.print_expr(field_expr.expr, depth_lvl + 2); + } + + if let Some(ref base) = adt_expr.base { + print_indented!(self, "base:", depth_lvl + 1); + self.print_fru_info(base, depth_lvl + 2); + } else { + print_indented!(self, "base: None", depth_lvl + 1); + } + } + + fn print_adt_def(&mut self, adt_def: ty::AdtDef<'tcx>, depth_lvl: usize) { + print_indented!(self, "AdtDef {", depth_lvl); + print_indented!(self, format!("did: {:?}", adt_def.did()), depth_lvl + 1); + print_indented!(self, format!("variants: {:?}", adt_def.variants()), depth_lvl + 1); + print_indented!(self, format!("flags: {:?}", adt_def.flags()), depth_lvl + 1); + print_indented!(self, format!("repr: {:?}", adt_def.repr()), depth_lvl + 1); + } + + fn print_fru_info(&mut self, fru_info: &FruInfo<'tcx>, depth_lvl: usize) { + print_indented!(self, "FruInfo {", depth_lvl); + print_indented!(self, "base: ", depth_lvl + 1); + self.print_expr(fru_info.base, depth_lvl + 2); + print_indented!(self, "field_types: [", depth_lvl + 1); + for ty in fru_info.field_types.iter() { + print_indented!(self, format!("ty: {:?}", ty), depth_lvl + 2); + } + print_indented!(self, "}", depth_lvl); + } + + fn print_arm(&mut self, arm_id: ArmId, depth_lvl: usize) { + print_indented!(self, "Arm {", depth_lvl); + + let arm = &self.thir.arms[arm_id]; + let Arm { pattern, guard, body, lint_level, scope, span } = arm; + + print_indented!(self, "pattern: ", depth_lvl + 1); + self.print_pat(pattern, depth_lvl + 2); + + if let Some(guard) = guard { + print_indented!(self, "guard: ", depth_lvl + 1); + self.print_guard(guard, depth_lvl + 2); + } else { + print_indented!(self, "guard: None", depth_lvl + 1); + } + + print_indented!(self, "body: ", depth_lvl + 1); + self.print_expr(*body, depth_lvl + 2); + print_indented!(self, format!("lint_level: {:?}", lint_level), depth_lvl + 1); + print_indented!(self, format!("scope: {:?}", scope), depth_lvl + 1); + print_indented!(self, format!("span: {:?}", span), depth_lvl + 1); + print_indented!(self, "}", depth_lvl); + } + + fn print_pat(&mut self, pat: &Box<Pat<'tcx>>, depth_lvl: usize) { + let Pat { ty, span, kind } = &**pat; + + print_indented!(self, "Pat: {", depth_lvl); + print_indented!(self, format!("ty: {:?}", ty), depth_lvl + 1); + print_indented!(self, format!("span: {:?}", span), depth_lvl + 1); + self.print_pat_kind(kind, depth_lvl + 1); + print_indented!(self, "}", depth_lvl); + } + + fn print_pat_kind(&mut self, pat_kind: &PatKind<'tcx>, depth_lvl: usize) { + print_indented!(self, "kind: PatKind {", depth_lvl); + + match pat_kind { + PatKind::Wild => { + print_indented!(self, "Wild", depth_lvl + 1); + } + PatKind::AscribeUserType { ascription, subpattern } => { + print_indented!(self, "AscribeUserType: {", depth_lvl + 1); + print_indented!(self, format!("ascription: {:?}", ascription), depth_lvl + 2); + print_indented!(self, "subpattern: ", depth_lvl + 2); + self.print_pat(subpattern, depth_lvl + 3); + print_indented!(self, "}", depth_lvl + 1); + } + PatKind::Binding { mutability, name, mode, var, ty, subpattern, is_primary } => { + print_indented!(self, "Binding {", depth_lvl + 1); + print_indented!(self, format!("mutability: {:?}", mutability), depth_lvl + 2); + print_indented!(self, format!("name: {:?}", name), depth_lvl + 2); + print_indented!(self, format!("mode: {:?}", mode), depth_lvl + 2); + print_indented!(self, format!("var: {:?}", var), depth_lvl + 2); + print_indented!(self, format!("ty: {:?}", ty), depth_lvl + 2); + print_indented!(self, format!("is_primary: {:?}", is_primary), depth_lvl + 2); + + if let Some(subpattern) = subpattern { + print_indented!(self, "subpattern: Some( ", depth_lvl + 2); + self.print_pat(subpattern, depth_lvl + 3); + print_indented!(self, ")", depth_lvl + 2); + } else { + print_indented!(self, "subpattern: None", depth_lvl + 2); + } + + print_indented!(self, "}", depth_lvl + 1); + } + PatKind::Variant { adt_def, substs, variant_index, subpatterns } => { + print_indented!(self, "Variant {", depth_lvl + 1); + print_indented!(self, "adt_def: ", depth_lvl + 2); + self.print_adt_def(*adt_def, depth_lvl + 3); + print_indented!(self, format!("substs: {:?}", substs), depth_lvl + 2); + print_indented!(self, format!("variant_index: {:?}", variant_index), depth_lvl + 2); + + if subpatterns.len() > 0 { + print_indented!(self, "subpatterns: [", depth_lvl + 2); + for field_pat in subpatterns.iter() { + self.print_pat(&field_pat.pattern, depth_lvl + 3); + } + print_indented!(self, "]", depth_lvl + 2); + } else { + print_indented!(self, "subpatterns: []", depth_lvl + 2); + } + + print_indented!(self, "}", depth_lvl + 1); + } + PatKind::Leaf { subpatterns } => { + print_indented!(self, "Leaf { ", depth_lvl + 1); + print_indented!(self, "subpatterns: [", depth_lvl + 2); + for field_pat in subpatterns.iter() { + self.print_pat(&field_pat.pattern, depth_lvl + 3); + } + print_indented!(self, "]", depth_lvl + 2); + print_indented!(self, "}", depth_lvl + 1); + } + PatKind::Deref { subpattern } => { + print_indented!(self, "Deref { ", depth_lvl + 1); + print_indented!(self, "subpattern: ", depth_lvl + 2); + self.print_pat(subpattern, depth_lvl + 2); + print_indented!(self, "}", depth_lvl + 1); + } + PatKind::Constant { value } => { + print_indented!(self, "Constant {", depth_lvl + 1); + print_indented!(self, format!("value: {:?}", value), depth_lvl + 2); + print_indented!(self, "}", depth_lvl + 1); + } + PatKind::Range(pat_range) => { + print_indented!(self, format!("Range ( {:?} )", pat_range), depth_lvl + 1); + } + PatKind::Slice { prefix, slice, suffix } => { + print_indented!(self, "Slice {", depth_lvl + 1); + + print_indented!(self, "prefix: [", depth_lvl + 2); + for prefix_pat in prefix.iter() { + self.print_pat(prefix_pat, depth_lvl + 3); + } + print_indented!(self, "]", depth_lvl + 2); + + if let Some(slice) = slice { + print_indented!(self, "slice: ", depth_lvl + 2); + self.print_pat(slice, depth_lvl + 3); + } + + print_indented!(self, "suffix: [", depth_lvl + 2); + for suffix_pat in suffix.iter() { + self.print_pat(suffix_pat, depth_lvl + 3); + } + print_indented!(self, "]", depth_lvl + 2); + + print_indented!(self, "}", depth_lvl + 1); + } + PatKind::Array { prefix, slice, suffix } => { + print_indented!(self, "Array {", depth_lvl + 1); + + print_indented!(self, "prefix: [", depth_lvl + 2); + for prefix_pat in prefix.iter() { + self.print_pat(prefix_pat, depth_lvl + 3); + } + print_indented!(self, "]", depth_lvl + 2); + + if let Some(slice) = slice { + print_indented!(self, "slice: ", depth_lvl + 2); + self.print_pat(slice, depth_lvl + 3); + } + + print_indented!(self, "suffix: [", depth_lvl + 2); + for suffix_pat in suffix.iter() { + self.print_pat(suffix_pat, depth_lvl + 3); + } + print_indented!(self, "]", depth_lvl + 2); + + print_indented!(self, "}", depth_lvl + 1); + } + PatKind::Or { pats } => { + print_indented!(self, "Or {", depth_lvl + 1); + print_indented!(self, "pats: [", depth_lvl + 2); + for pat in pats.iter() { + self.print_pat(pat, depth_lvl + 3); + } + print_indented!(self, "]", depth_lvl + 2); + print_indented!(self, "}", depth_lvl + 1); + } + } + + print_indented!(self, "}", depth_lvl); + } + + fn print_guard(&mut self, guard: &Guard<'tcx>, depth_lvl: usize) { + print_indented!(self, "Guard {", depth_lvl); + + match guard { + Guard::If(expr_id) => { + print_indented!(self, "If (", depth_lvl + 1); + self.print_expr(*expr_id, depth_lvl + 2); + print_indented!(self, ")", depth_lvl + 1); + } + Guard::IfLet(pat, expr_id) => { + print_indented!(self, "IfLet (", depth_lvl + 1); + self.print_pat(pat, depth_lvl + 2); + print_indented!(self, ",", depth_lvl + 1); + self.print_expr(*expr_id, depth_lvl + 2); + print_indented!(self, ")", depth_lvl + 1); + } + } + + print_indented!(self, "}", depth_lvl); + } + + fn print_closure_expr(&mut self, expr: &ClosureExpr<'tcx>, depth_lvl: usize) { + let ClosureExpr { closure_id, substs, upvars, movability, fake_reads } = expr; + + print_indented!(self, "ClosureExpr {", depth_lvl); + print_indented!(self, format!("closure_id: {:?}", closure_id), depth_lvl + 1); + print_indented!(self, format!("substs: {:?}", substs), depth_lvl + 1); + + if upvars.len() > 0 { + print_indented!(self, "upvars: [", depth_lvl + 1); + for upvar in upvars.iter() { + self.print_expr(*upvar, depth_lvl + 2); + print_indented!(self, ",", depth_lvl + 1); + } + print_indented!(self, "]", depth_lvl + 1); + } else { + print_indented!(self, "upvars: []", depth_lvl + 1); + } + + print_indented!(self, format!("movability: {:?}", movability), depth_lvl + 1); + + if fake_reads.len() > 0 { + print_indented!(self, "fake_reads: [", depth_lvl + 1); + for (fake_read_expr, cause, hir_id) in fake_reads.iter() { + print_indented!(self, "(", depth_lvl + 2); + self.print_expr(*fake_read_expr, depth_lvl + 3); + print_indented!(self, ",", depth_lvl + 2); + print_indented!(self, format!("cause: {:?}", cause), depth_lvl + 3); + print_indented!(self, ",", depth_lvl + 2); + print_indented!(self, format!("hir_id: {:?}", hir_id), depth_lvl + 3); + print_indented!(self, "),", depth_lvl + 2); + } + print_indented!(self, "]", depth_lvl + 1); + } else { + print_indented!(self, "fake_reads: []", depth_lvl + 1); + } + + print_indented!(self, "}", depth_lvl); + } + + fn print_inline_asm_expr(&mut self, expr: &InlineAsmExpr<'tcx>, depth_lvl: usize) { + let InlineAsmExpr { template, operands, options, line_spans } = expr; + + print_indented!(self, "InlineAsmExpr {", depth_lvl); + + print_indented!(self, "template: [", depth_lvl + 1); + for template_piece in template.iter() { + print_indented!(self, format!("{:?}", template_piece), depth_lvl + 2); + } + print_indented!(self, "]", depth_lvl + 1); + + print_indented!(self, "operands: [", depth_lvl + 1); + for operand in operands.iter() { + self.print_inline_operand(operand, depth_lvl + 2); + } + print_indented!(self, "]", depth_lvl + 1); + + print_indented!(self, format!("options: {:?}", options), depth_lvl + 1); + print_indented!(self, format!("line_spans: {:?}", line_spans), depth_lvl + 1); + } + + fn print_inline_operand(&mut self, operand: &InlineAsmOperand<'tcx>, depth_lvl: usize) { + match operand { + InlineAsmOperand::In { reg, expr } => { + print_indented!(self, "InlineAsmOperand::In {", depth_lvl); + print_indented!(self, format!("reg: {:?}", reg), depth_lvl + 1); + print_indented!(self, "expr: ", depth_lvl + 1); + self.print_expr(*expr, depth_lvl + 2); + print_indented!(self, "}", depth_lvl + 1); + } + InlineAsmOperand::Out { reg, late, expr } => { + print_indented!(self, "InlineAsmOperand::Out {", depth_lvl); + print_indented!(self, format!("reg: {:?}", reg), depth_lvl + 1); + print_indented!(self, format!("late: {:?}", late), depth_lvl + 1); + + if let Some(out) = expr { + print_indented!(self, "place: Some( ", depth_lvl + 1); + self.print_expr(*out, depth_lvl + 2); + print_indented!(self, ")", depth_lvl + 1); + } else { + print_indented!(self, "place: None", depth_lvl + 1); + } + print_indented!(self, "}", depth_lvl + 1); + } + InlineAsmOperand::InOut { reg, late, expr } => { + print_indented!(self, "InlineAsmOperand::InOut {", depth_lvl); + print_indented!(self, format!("reg: {:?}", reg), depth_lvl + 1); + print_indented!(self, format!("late: {:?}", late), depth_lvl + 1); + print_indented!(self, "expr: ", depth_lvl + 1); + self.print_expr(*expr, depth_lvl + 2); + print_indented!(self, "}", depth_lvl + 1); + } + InlineAsmOperand::SplitInOut { reg, late, in_expr, out_expr } => { + print_indented!(self, "InlineAsmOperand::SplitInOut {", depth_lvl); + print_indented!(self, format!("reg: {:?}", reg), depth_lvl + 1); + print_indented!(self, format!("late: {:?}", late), depth_lvl + 1); + print_indented!(self, "in_expr: ", depth_lvl + 1); + self.print_expr(*in_expr, depth_lvl + 2); + + if let Some(out_expr) = out_expr { + print_indented!(self, "out_expr: Some( ", depth_lvl + 1); + self.print_expr(*out_expr, depth_lvl + 2); + print_indented!(self, ")", depth_lvl + 1); + } else { + print_indented!(self, "out_expr: None", depth_lvl + 1); + } + + print_indented!(self, "}", depth_lvl + 1); + } + InlineAsmOperand::Const { value, span } => { + print_indented!(self, "InlineAsmOperand::Const {", depth_lvl); + print_indented!(self, format!("value: {:?}", value), depth_lvl + 1); + print_indented!(self, format!("span: {:?}", span), depth_lvl + 1); + print_indented!(self, "}", depth_lvl + 1); + } + InlineAsmOperand::SymFn { value, span } => { + print_indented!(self, "InlineAsmOperand::SymFn {", depth_lvl); + print_indented!(self, format!("value: {:?}", *value), depth_lvl + 1); + print_indented!(self, format!("span: {:?}", span), depth_lvl + 1); + print_indented!(self, "}", depth_lvl + 1); + } + InlineAsmOperand::SymStatic { def_id } => { + print_indented!(self, "InlineAsmOperand::SymStatic {", depth_lvl); + print_indented!(self, format!("def_id: {:?}", def_id), depth_lvl + 1); + print_indented!(self, "}", depth_lvl + 1); + } + } + } +} diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs index f85831b4fc6..1655e224ddb 100644 --- a/compiler/rustc_mir_build/src/build/mod.rs +++ b/compiler/rustc_mir_build/src/build/mod.rs @@ -439,6 +439,10 @@ fn construct_fn<'tcx>( let fn_id = tcx.hir().local_def_id_to_hir_id(fn_def.did); let generator_kind = tcx.generator_kind(fn_def.did); + // The representation of thir for `-Zunpretty=thir-tree` relies on + // the entry expression being the last element of `thir.exprs`. + assert_eq!(expr.as_usize(), thir.exprs.len() - 1); + // Figure out what primary body this item has. let body_id = tcx.hir().body_owned_by(fn_def.did); let span_with_body = tcx.hir().span_with_body(fn_id); diff --git a/compiler/rustc_mir_build/src/lib.rs b/compiler/rustc_mir_build/src/lib.rs index a428180a4fa..94dae36154c 100644 --- a/compiler/rustc_mir_build/src/lib.rs +++ b/compiler/rustc_mir_build/src/lib.rs @@ -34,4 +34,5 @@ pub fn provide(providers: &mut Providers) { providers.thir_check_unsafety_for_const_arg = check_unsafety::thir_check_unsafety_for_const_arg; providers.thir_body = thir::cx::thir_body; providers.thir_tree = thir::cx::thir_tree; + providers.thir_flat = thir::cx::thir_flat; } diff --git a/compiler/rustc_mir_build/src/thir/cx/mod.rs b/compiler/rustc_mir_build/src/thir/cx/mod.rs index a355e1bdab5..10df4b22952 100644 --- a/compiler/rustc_mir_build/src/thir/cx/mod.rs +++ b/compiler/rustc_mir_build/src/thir/cx/mod.rs @@ -54,6 +54,16 @@ pub(crate) fn thir_body( pub(crate) fn thir_tree(tcx: TyCtxt<'_>, owner_def: ty::WithOptConstParam<LocalDefId>) -> String { match thir_body(tcx, owner_def) { + Ok((thir, _)) => { + let thir = thir.steal(); + tcx.thir_tree_representation(&thir) + } + Err(_) => "error".into(), + } +} + +pub(crate) fn thir_flat(tcx: TyCtxt<'_>, owner_def: ty::WithOptConstParam<LocalDefId>) -> String { + match thir_body(tcx, owner_def) { Ok((thir, _)) => format!("{:#?}", thir.steal()), Err(_) => "error".into(), } diff --git a/compiler/rustc_mir_transform/src/check_packed_ref.rs b/compiler/rustc_mir_transform/src/check_packed_ref.rs index 51abcf51189..3e7571aa7a2 100644 --- a/compiler/rustc_mir_transform/src/check_packed_ref.rs +++ b/compiler/rustc_mir_transform/src/check_packed_ref.rs @@ -1,17 +1,11 @@ -use rustc_hir::def_id::LocalDefId; use rustc_middle::mir::visit::{PlaceContext, Visitor}; use rustc_middle::mir::*; -use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, TyCtxt}; use rustc_session::lint::builtin::UNALIGNED_REFERENCES; use crate::util; use crate::MirLint; -pub(crate) fn provide(providers: &mut Providers) { - *providers = Providers { unsafe_derive_on_repr_packed, ..*providers }; -} - pub struct CheckPackedRef; impl<'tcx> MirLint<'tcx> for CheckPackedRef { @@ -30,32 +24,6 @@ struct PackedRefChecker<'a, 'tcx> { source_info: SourceInfo, } -fn unsafe_derive_on_repr_packed(tcx: TyCtxt<'_>, def_id: LocalDefId) { - let lint_hir_id = tcx.hir().local_def_id_to_hir_id(def_id); - - // FIXME: when we make this a hard error, this should have its - // own error code. - - let extra = if tcx.generics_of(def_id).own_requires_monomorphization() { - "with type or const parameters" - } else { - "that does not derive `Copy`" - }; - let message = format!( - "`{}` can't be derived on this `#[repr(packed)]` struct {}", - tcx.item_name(tcx.trait_id_of_impl(def_id.to_def_id()).expect("derived trait name")), - extra - ); - - tcx.struct_span_lint_hir( - UNALIGNED_REFERENCES, - lint_hir_id, - tcx.def_span(def_id), - message, - |lint| lint, - ); -} - impl<'tcx> Visitor<'tcx> for PackedRefChecker<'_, 'tcx> { fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) { // Make sure we know where in the MIR we are. @@ -73,14 +41,13 @@ impl<'tcx> Visitor<'tcx> for PackedRefChecker<'_, 'tcx> { if context.is_borrow() { if util::is_disaligned(self.tcx, self.body, self.param_env, *place) { let def_id = self.body.source.instance.def_id(); - if let Some(impl_def_id) = self - .tcx - .impl_of_method(def_id) - .filter(|&def_id| self.tcx.is_builtin_derive(def_id)) + if let Some(impl_def_id) = self.tcx.impl_of_method(def_id) + && self.tcx.is_builtin_derive(impl_def_id) { - // If a method is defined in the local crate, - // the impl containing that method should also be. - self.tcx.ensure().unsafe_derive_on_repr_packed(impl_def_id.expect_local()); + // If we ever reach here it means that the generated derive + // code is somehow doing an unaligned reference, which it + // shouldn't do. + unreachable!(); } else { let source_info = self.source_info; let lint_root = self.body.source_scopes[source_info.scope] diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index 43d5b445258..cbebca15483 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -104,7 +104,6 @@ use rustc_mir_dataflow::rustc_peek; pub fn provide(providers: &mut Providers) { check_unsafety::provide(providers); - check_packed_ref::provide(providers); coverage::query::provide(providers); ffi_unwind_calls::provide(providers); shim::provide(providers); diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index 25de0a9e750..82d9138c7a3 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -1048,7 +1048,7 @@ impl<'a> Parser<'a> { self.parse_remaining_bounds(bounds, true)?; self.expect(&token::CloseDelim(Delimiter::Parenthesis))?; let sp = vec![lo, self.prev_token.span]; - let sugg: Vec<_> = sp.iter().map(|sp| (*sp, String::new())).collect(); + let sugg = vec![(lo, String::from(" ")), (self.prev_token.span, String::new())]; self.struct_span_err(sp, "incorrect braces around trait bounds") .multipart_suggestion( "remove the parentheses", diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index db95b8bca2f..c49c5fa9904 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -2573,6 +2573,7 @@ fn parse_pretty(unstable_opts: &UnstableOptions, efmt: ErrorOutputType) -> Optio "hir,typed" => Hir(PpHirMode::Typed), "hir-tree" => HirTree, "thir-tree" => ThirTree, + "thir-flat" => ThirFlat, "mir" => Mir, "mir-cfg" => MirCFG, name => early_error( @@ -2581,7 +2582,8 @@ fn parse_pretty(unstable_opts: &UnstableOptions, efmt: ErrorOutputType) -> Optio "argument to `unpretty` must be one of `normal`, `identified`, \ `expanded`, `expanded,identified`, `expanded,hygiene`, \ `ast-tree`, `ast-tree,expanded`, `hir`, `hir,identified`, \ - `hir,typed`, `hir-tree`, `thir-tree`, `mir` or `mir-cfg`; got {name}" + `hir,typed`, `hir-tree`, `thir-tree`, `thir-flat`, `mir` or \ + `mir-cfg`; got {name}" ), ), }; @@ -2736,6 +2738,8 @@ pub enum PpMode { HirTree, /// `-Zunpretty=thir-tree` ThirTree, + /// `-Zunpretty=`thir-flat` + ThirFlat, /// `-Zunpretty=mir` Mir, /// `-Zunpretty=mir-cfg` @@ -2754,6 +2758,7 @@ impl PpMode { | Hir(_) | HirTree | ThirTree + | ThirFlat | Mir | MirCFG => true, } @@ -2763,13 +2768,13 @@ impl PpMode { match *self { Source(_) | AstTree(_) => false, - Hir(_) | HirTree | ThirTree | Mir | MirCFG => true, + Hir(_) | HirTree | ThirTree | ThirFlat | Mir | MirCFG => true, } } pub fn needs_analysis(&self) -> bool { use PpMode::*; - matches!(*self, Mir | MirCFG | ThirTree) + matches!(*self, Mir | MirCFG | ThirTree | ThirFlat) } } diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 9c84bfaad49..89a8fdbac1c 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -8,12 +8,11 @@ //! https://rustc-dev-guide.rust-lang.org/traits/resolution.html#confirmation use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_hir::lang_items::LangItem; -use rustc_index::bit_set::GrowableBitSet; use rustc_infer::infer::InferOk; use rustc_infer::infer::LateBoundRegionConversionTime::HigherRankedType; use rustc_middle::ty::{ - self, Binder, GenericArg, GenericArgKind, GenericParamDefKind, InternalSubsts, SubstsRef, - ToPolyTraitRef, ToPredicate, TraitRef, Ty, TyCtxt, TypeVisitable, + self, Binder, GenericParamDefKind, InternalSubsts, SubstsRef, ToPolyTraitRef, ToPredicate, + TraitRef, Ty, TyCtxt, TypeVisitable, }; use rustc_session::config::TraitSolver; use rustc_span::def_id::DefId; @@ -1064,51 +1063,18 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // `Struct<T>` -> `Struct<U>` (&ty::Adt(def, substs_a), &ty::Adt(_, substs_b)) => { - let maybe_unsizing_param_idx = |arg: GenericArg<'tcx>| match arg.unpack() { - GenericArgKind::Type(ty) => match ty.kind() { - ty::Param(p) => Some(p.index), - _ => None, - }, - - // Lifetimes aren't allowed to change during unsizing. - GenericArgKind::Lifetime(_) => None, - - GenericArgKind::Const(ct) => match ct.kind() { - ty::ConstKind::Param(p) => Some(p.index), - _ => None, - }, - }; - - // FIXME(eddyb) cache this (including computing `unsizing_params`) - // by putting it in a query; it would only need the `DefId` as it - // looks at declared field types, not anything substituted. - - // The last field of the structure has to exist and contain type/const parameters. - let (tail_field, prefix_fields) = - def.non_enum_variant().fields.split_last().ok_or(Unimplemented)?; - let tail_field_ty = tcx.bound_type_of(tail_field.did); - - let mut unsizing_params = GrowableBitSet::new_empty(); - for arg in tail_field_ty.0.walk() { - if let Some(i) = maybe_unsizing_param_idx(arg) { - unsizing_params.insert(i); - } - } - - // Ensure none of the other fields mention the parameters used - // in unsizing. - for field in prefix_fields { - for arg in tcx.type_of(field.did).walk() { - if let Some(i) = maybe_unsizing_param_idx(arg) { - unsizing_params.remove(i); - } - } - } - + let unsizing_params = tcx.unsizing_params_for_adt(def.did()); if unsizing_params.is_empty() { return Err(Unimplemented); } + let tail_field = def + .non_enum_variant() + .fields + .last() + .expect("expected unsized ADT to have a tail field"); + let tail_field_ty = tcx.bound_type_of(tail_field.did); + // Extract `TailField<T>` and `TailField<U>` from `Struct<T>` and `Struct<U>`, // normalizing in the process, since `type_of` returns something directly from // astconv (which means it's un-normalized). diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs index 89abffebdc6..b5005c1d8d8 100644 --- a/compiler/rustc_ty_utils/src/ty.rs +++ b/compiler/rustc_ty_utils/src/ty.rs @@ -1,5 +1,6 @@ use rustc_data_structures::fx::FxIndexSet; use rustc_hir as hir; +use rustc_index::bit_set::BitSet; use rustc_middle::ty::{self, Binder, Predicate, PredicateKind, ToPredicate, Ty, TyCtxt}; use rustc_session::config::TraitSolver; use rustc_span::def_id::{DefId, CRATE_DEF_ID}; @@ -406,6 +407,56 @@ fn asyncness(tcx: TyCtxt<'_>, def_id: DefId) -> hir::IsAsync { node.fn_sig().map_or(hir::IsAsync::NotAsync, |sig| sig.header.asyncness) } +fn unsizing_params_for_adt<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> BitSet<u32> { + let def = tcx.adt_def(def_id); + let num_params = tcx.generics_of(def_id).count(); + + let maybe_unsizing_param_idx = |arg: ty::GenericArg<'tcx>| match arg.unpack() { + ty::GenericArgKind::Type(ty) => match ty.kind() { + ty::Param(p) => Some(p.index), + _ => None, + }, + + // We can't unsize a lifetime + ty::GenericArgKind::Lifetime(_) => None, + + ty::GenericArgKind::Const(ct) => match ct.kind() { + ty::ConstKind::Param(p) => Some(p.index), + _ => None, + }, + }; + + // FIXME(eddyb) cache this (including computing `unsizing_params`) + // by putting it in a query; it would only need the `DefId` as it + // looks at declared field types, not anything substituted. + + // The last field of the structure has to exist and contain type/const parameters. + let Some((tail_field, prefix_fields)) = + def.non_enum_variant().fields.split_last() else + { + return BitSet::new_empty(num_params); + }; + + let mut unsizing_params = BitSet::new_empty(num_params); + for arg in tcx.bound_type_of(tail_field.did).subst_identity().walk() { + if let Some(i) = maybe_unsizing_param_idx(arg) { + unsizing_params.insert(i); + } + } + + // Ensure none of the other fields mention the parameters used + // in unsizing. + for field in prefix_fields { + for arg in tcx.bound_type_of(field.did).subst_identity().walk() { + if let Some(i) = maybe_unsizing_param_idx(arg) { + unsizing_params.remove(i); + } + } + } + + unsizing_params +} + pub fn provide(providers: &mut ty::query::Providers) { *providers = ty::query::Providers { asyncness, @@ -415,6 +466,7 @@ pub fn provide(providers: &mut ty::query::Providers) { instance_def_size_estimate, issue33140_self_ty, impl_defaultness, + unsizing_params_for_adt, ..*providers }; } diff --git a/config.toml.example b/config.toml.example index 299bfd779e5..85f058f3664 100644 --- a/config.toml.example +++ b/config.toml.example @@ -233,6 +233,9 @@ changelog-seen = 2 # and generated in already-minified form from the beginning. #docs-minification = true +# Flag to specify whether private items should be included in the library docs. +#library-docs-private-items = false + # Indicate whether the compiler should be documented in addition to the standard # library and facade crates. #compiler-docs = false diff --git a/library/alloc/src/fmt.rs b/library/alloc/src/fmt.rs index eadb35cb96d..1da86e1a46a 100644 --- a/library/alloc/src/fmt.rs +++ b/library/alloc/src/fmt.rs @@ -558,7 +558,7 @@ pub use core::fmt::Alignment; #[stable(feature = "rust1", since = "1.0.0")] pub use core::fmt::Error; #[stable(feature = "rust1", since = "1.0.0")] -pub use core::fmt::{write, ArgumentV1, Arguments}; +pub use core::fmt::{write, Arguments}; #[stable(feature = "rust1", since = "1.0.0")] pub use core::fmt::{Binary, Octal}; #[stable(feature = "rust1", since = "1.0.0")] diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index c9aa23fc4af..fd1e3e0f75b 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -1092,7 +1092,7 @@ impl<T: ?Sized> Rc<T> { /// # Safety /// /// If any other `Rc` or [`Weak`] pointers to the same allocation exist, then - /// they must be must not be dereferenced or have active borrows for the duration + /// they must not be dereferenced or have active borrows for the duration /// of the returned borrow, and their inner type must be exactly the same as the /// inner type of this Rc (including lifetimes). This is trivially the case if no /// such pointers exist, for example immediately after `Rc::new`. diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index 9bc9182f7b5..f20486ca9e4 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -1733,7 +1733,7 @@ impl<T: ?Sized> Arc<T> { /// # Safety /// /// If any other `Arc` or [`Weak`] pointers to the same allocation exist, then - /// they must be must not be dereferenced or have active borrows for the duration + /// they must not be dereferenced or have active borrows for the duration /// of the returned borrow, and their inner type must be exactly the same as the /// inner type of this Rc (including lifetimes). This is trivially the case if no /// such pointers exist, for example immediately after `Arc::new`. diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs index 2cae98b8e49..b59f28193e2 100644 --- a/library/core/src/num/int_macros.rs +++ b/library/core/src/num/int_macros.rs @@ -5,7 +5,7 @@ macro_rules! int_impl { $to_xe_bytes_doc:expr, $from_xe_bytes_doc:expr, $bound_condition:expr) => { /// The smallest value that can be represented by this integer type - #[doc = concat!("(−2<sup>", $BITS_MINUS_ONE, "</sup>", $bound_condition, ")")] + #[doc = concat!("(−2<sup>", $BITS_MINUS_ONE, "</sup>", $bound_condition, ").")] /// /// # Examples /// @@ -18,7 +18,7 @@ macro_rules! int_impl { pub const MIN: Self = !0 ^ ((!0 as $UnsignedT) >> 1) as Self; /// The largest value that can be represented by this integer type - #[doc = concat!("(2<sup>", $BITS_MINUS_ONE, "</sup> − 1", $bound_condition, ")")] + #[doc = concat!("(2<sup>", $BITS_MINUS_ONE, "</sup> − 1", $bound_condition, ").")] /// /// # Examples /// @@ -2574,12 +2574,13 @@ macro_rules! int_impl { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline(always)] + #[rustc_allow_const_fn_unstable(const_cmp)] pub const fn signum(self) -> Self { - match self { - n if n > 0 => 1, - 0 => 0, - _ => -1, - } + // Picking the right way to phrase this is complicated + // (<https://graphics.stanford.edu/~seander/bithacks.html#CopyIntegerSign>) + // so delegate it to `Ord` which is already producing -1/0/+1 + // exactly like we need and can be the place to deal with the complexity. + self.cmp(&0) as _ } /// Returns `true` if `self` is positive and `false` if the number is zero or diff --git a/library/std/src/os/fuchsia/raw.rs b/library/std/src/os/fuchsia/raw.rs index 060d6e86b6c..ea6b94f2f13 100644 --- a/library/std/src/os/fuchsia/raw.rs +++ b/library/std/src/os/fuchsia/raw.rs @@ -24,12 +24,7 @@ pub type pthread_t = c_ulong; #[stable(feature = "raw_ext", since = "1.1.0")] pub use self::arch::{blkcnt_t, blksize_t, ino_t, nlink_t, off_t, stat, time_t}; -#[cfg(any( - target_arch = "x86", - target_arch = "le32", - target_arch = "powerpc", - target_arch = "arm" -))] +#[cfg(any(target_arch = "x86", target_arch = "powerpc", target_arch = "arm"))] mod arch { use crate::os::raw::{c_long, c_short, c_uint}; diff --git a/library/std/src/os/l4re/raw.rs b/library/std/src/os/l4re/raw.rs index 699e8be33c8..b3f7439f8cd 100644 --- a/library/std/src/os/l4re/raw.rs +++ b/library/std/src/os/l4re/raw.rs @@ -26,7 +26,6 @@ pub use self::arch::{blkcnt_t, blksize_t, ino_t, nlink_t, off_t, stat, time_t}; #[cfg(any( target_arch = "x86", - target_arch = "le32", target_arch = "m68k", target_arch = "powerpc", target_arch = "sparc", diff --git a/library/std/src/os/linux/raw.rs b/library/std/src/os/linux/raw.rs index c73791d1452..f46028c3a96 100644 --- a/library/std/src/os/linux/raw.rs +++ b/library/std/src/os/linux/raw.rs @@ -26,7 +26,6 @@ pub use self::arch::{blkcnt_t, blksize_t, ino_t, nlink_t, off_t, stat, time_t}; #[cfg(any( target_arch = "x86", - target_arch = "le32", target_arch = "m68k", target_arch = "powerpc", target_arch = "sparc", diff --git a/library/std/src/time.rs b/library/std/src/time.rs index ecd06ebf743..acf9c29083f 100644 --- a/library/std/src/time.rs +++ b/library/std/src/time.rs @@ -1,6 +1,6 @@ //! Temporal quantification. //! -//! # Examples: +//! # Examples //! //! There are multiple ways to create a new [`Duration`]: //! diff --git a/library/test/src/console.rs b/library/test/src/console.rs index 24cbe035f2f..1ee68c8540b 100644 --- a/library/test/src/console.rs +++ b/library/test/src/console.rs @@ -53,6 +53,7 @@ pub struct ConsoleTestState { pub metrics: MetricMap, pub failures: Vec<(TestDesc, Vec<u8>)>, pub not_failures: Vec<(TestDesc, Vec<u8>)>, + pub ignores: Vec<(TestDesc, Vec<u8>)>, pub time_failures: Vec<(TestDesc, Vec<u8>)>, pub options: Options, } @@ -76,6 +77,7 @@ impl ConsoleTestState { metrics: MetricMap::new(), failures: Vec::new(), not_failures: Vec::new(), + ignores: Vec::new(), time_failures: Vec::new(), options: opts.options, }) @@ -194,7 +196,10 @@ fn handle_test_result(st: &mut ConsoleTestState, completed_test: CompletedTest) st.passed += 1; st.not_failures.push((test, stdout)); } - TestResult::TrIgnored => st.ignored += 1, + TestResult::TrIgnored => { + st.ignored += 1; + st.ignores.push((test, stdout)); + } TestResult::TrBench(bs) => { st.metrics.insert_metric( test.name.as_slice(), diff --git a/library/test/src/formatters/terse.rs b/library/test/src/formatters/terse.rs index 0837ab16905..a431acfbc27 100644 --- a/library/test/src/formatters/terse.rs +++ b/library/test/src/formatters/terse.rs @@ -254,6 +254,15 @@ impl<T: Write> OutputFormatter for TerseFormatter<T> { self.write_plain("\n\n")?; + // Custom handling of cases where there is only 1 test to execute and that test was ignored. + // We want to show more detailed information(why was the test ignored) for investigation purposes. + if self.total_test_count == 1 && state.ignores.len() == 1 { + let test_desc = &state.ignores[0].0; + if let Some(im) = test_desc.ignore_message { + self.write_plain(format!("test: {}, ignore_message: {}\n\n", test_desc.name, im))?; + } + } + Ok(success) } } diff --git a/library/test/src/tests.rs b/library/test/src/tests.rs index 3a0260f86cf..44776fb0a31 100644 --- a/library/test/src/tests.rs +++ b/library/test/src/tests.rs @@ -790,6 +790,7 @@ fn should_sort_failures_before_printing_them() { failures: vec![(test_b, Vec::new()), (test_a, Vec::new())], options: Options::new(), not_failures: Vec::new(), + ignores: Vec::new(), time_failures: Vec::new(), }; diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index fdd659c60ca..165502b0a41 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -65,6 +65,7 @@ pub struct Config { pub verbose: usize, pub submodules: Option<bool>, pub compiler_docs: bool, + pub library_docs_private_items: bool, pub docs_minification: bool, pub docs: bool, pub locked_deps: bool, @@ -606,6 +607,7 @@ define_config! { rustfmt: Option<PathBuf> = "rustfmt", docs: Option<bool> = "docs", compiler_docs: Option<bool> = "compiler-docs", + library_docs_private_items: Option<bool> = "library-docs-private-items", docs_minification: Option<bool> = "docs-minification", submodules: Option<bool> = "submodules", gdb: Option<String> = "gdb", @@ -1018,6 +1020,7 @@ impl Config { config.submodules = build.submodules; set(&mut config.low_priority, build.low_priority); set(&mut config.compiler_docs, build.compiler_docs); + set(&mut config.library_docs_private_items, build.library_docs_private_items); set(&mut config.docs_minification, build.docs_minification); set(&mut config.docs, build.docs); set(&mut config.locked_deps, build.locked_deps); diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs index 9bad9046ecc..7f8aa2573dd 100644 --- a/src/bootstrap/doc.rs +++ b/src/bootstrap/doc.rs @@ -597,6 +597,9 @@ fn doc_std( .arg("--resource-suffix") .arg(&builder.version) .args(extra_args); + if builder.config.library_docs_private_items { + cargo.arg("--document-private-items").arg("--document-hidden-items"); + } builder.run(&mut cargo.into()); }; diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 522b3b7e851..267aa3278d8 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -110,7 +110,7 @@ use std::fs::{self, File}; use std::io; use std::io::ErrorKind; use std::path::{Path, PathBuf}; -use std::process::Command; +use std::process::{Command, Stdio}; use std::str; use build_helper::ci::CiEnv; @@ -203,7 +203,6 @@ const EXTRA_CHECK_CFGS: &[(Option<Mode>, &'static str, Option<&[&'static str]>)] (None, "bootstrap", None), (Some(Mode::Rustc), "parallel_compiler", None), (Some(Mode::ToolRustc), "parallel_compiler", None), - (Some(Mode::ToolRustc), "emulate_second_only_system", None), (Some(Mode::Codegen), "parallel_compiler", None), (Some(Mode::Std), "stdarch_intel_sde", None), (Some(Mode::Std), "no_fp_fmt_parse", None), @@ -214,18 +213,9 @@ const EXTRA_CHECK_CFGS: &[(Option<Mode>, &'static str, Option<&[&'static str]>)] (Some(Mode::Std), "backtrace_in_libstd", None), /* Extra values not defined in the built-in targets yet, but used in std */ (Some(Mode::Std), "target_env", Some(&["libnx"])), - (Some(Mode::Std), "target_os", Some(&["watchos"])), - ( - Some(Mode::Std), - "target_arch", - Some(&["asmjs", "spirv", "nvptx", "nvptx64", "le32", "xtensa"]), - ), + // (Some(Mode::Std), "target_os", Some(&[])), + (Some(Mode::Std), "target_arch", Some(&["asmjs", "spirv", "nvptx", "xtensa"])), /* Extra names used by dependencies */ - // FIXME: Used by rustfmt is their test but is invalid (neither cargo nor bootstrap ever set - // this config) should probably by removed or use a allow attribute. - (Some(Mode::ToolRustc), "release", None), - // FIXME: Used by stdarch in their test, should use a allow attribute instead. - (Some(Mode::Std), "dont_compile_me", None), // FIXME: Used by serde_json, but we should not be triggering on external dependencies. (Some(Mode::Rustc), "no_btreemap_remove_entry", None), (Some(Mode::ToolRustc), "no_btreemap_remove_entry", None), @@ -235,8 +225,12 @@ const EXTRA_CHECK_CFGS: &[(Option<Mode>, &'static str, Option<&[&'static str]>)] // FIXME: Used by proc-macro2, but we should not be triggering on external dependencies. (Some(Mode::Rustc), "span_locations", None), (Some(Mode::ToolRustc), "span_locations", None), - // Can be passed in RUSTFLAGS to prevent direct syscalls in rustix. - (None, "rustix_use_libc", None), + // FIXME: Used by rustix, but we should not be triggering on external dependencies. + (Some(Mode::Rustc), "rustix_use_libc", None), + (Some(Mode::ToolRustc), "rustix_use_libc", None), + // FIXME: Used by filetime, but we should not be triggering on external dependencies. + (Some(Mode::Rustc), "emulate_second_only_system", None), + (Some(Mode::ToolRustc), "emulate_second_only_system", None), ]; /// A structure representing a Rust compiler. @@ -662,12 +656,32 @@ impl Build { // Try passing `--progress` to start, then run git again without if that fails. let update = |progress: bool| { - let mut git = Command::new("git"); + // Git is buggy and will try to fetch submodules from the tracking branch for *this* repository, + // even though that has no relation to the upstream for the submodule. + let current_branch = { + let output = self + .config + .git() + .args(["symbolic-ref", "--short", "HEAD"]) + .stderr(Stdio::inherit()) + .output(); + let output = t!(output); + if output.status.success() { + Some(String::from_utf8(output.stdout).unwrap().trim().to_owned()) + } else { + None + } + }; + + let mut git = self.config.git(); + if let Some(branch) = current_branch { + git.arg("-c").arg(format!("branch.{branch}.remote=origin")); + } git.args(&["submodule", "update", "--init", "--recursive", "--depth=1"]); if progress { git.arg("--progress"); } - git.arg(relative_path).current_dir(&self.config.src); + git.arg(relative_path); git }; // NOTE: doesn't use `try_run` because this shouldn't print an error if it fails. @@ -1433,7 +1447,8 @@ impl Build { if !stamp.exists() { eprintln!( - "Warning: Unable to find the stamp file, did you try to keep a nonexistent build stage?" + "Error: Unable to find the stamp file {}, did you try to keep a nonexistent build stage?", + stamp.display() ); crate::detail_exit(1); } diff --git a/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile index 6bdc88e18f5..5feba4e0605 100644 --- a/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile @@ -81,7 +81,7 @@ ENV RUST_CONFIGURE_ARGS \ --set rust.jemalloc \ --set rust.use-lld=true \ --set rust.lto=thin -ENV SCRIPT ../src/ci/pgo.sh python3 ../x.py dist \ +ENV SCRIPT python3 ../src/ci/stage-build.py python3 ../x.py dist \ --host $HOSTS --target $HOSTS \ --include-default-paths \ build-manifest bootstrap diff --git a/src/ci/docker/host-x86_64/mingw-check/validate-toolstate.sh b/src/ci/docker/host-x86_64/mingw-check/validate-toolstate.sh index c6d728eb80d..0b06f5e3623 100755 --- a/src/ci/docker/host-x86_64/mingw-check/validate-toolstate.sh +++ b/src/ci/docker/host-x86_64/mingw-check/validate-toolstate.sh @@ -9,11 +9,5 @@ git clone --depth=1 https://github.com/rust-lang-nursery/rust-toolstate.git cd rust-toolstate python3 "../../src/tools/publish_toolstate.py" "$(git rev-parse HEAD)" \ "$(git log --format=%s -n1 HEAD)" "" "" -# Only check maintainers if this build is supposed to publish toolstate. -# Builds that are not supposed to publish don't have the access token. -if [ -n "${TOOLSTATE_PUBLISH+is_set}" ]; then - TOOLSTATE_VALIDATE_MAINTAINERS_REPO=rust-lang/rust python3 \ - "../../src/tools/publish_toolstate.py" -fi cd .. rm -rf rust-toolstate diff --git a/src/ci/github-actions/ci.yml b/src/ci/github-actions/ci.yml index 70b5a9d301b..5e676a470a0 100644 --- a/src/ci/github-actions/ci.yml +++ b/src/ci/github-actions/ci.yml @@ -680,7 +680,7 @@ jobs: --enable-full-tools --enable-profiler --set rust.lto=thin - SCRIPT: PGO_HOST=x86_64-pc-windows-msvc src/ci/pgo.sh python x.py dist bootstrap --include-default-paths + SCRIPT: PGO_HOST=x86_64-pc-windows-msvc python src/ci/stage-build.py python x.py dist bootstrap --include-default-paths DIST_REQUIRE_ALL_TOOLS: 1 <<: *job-windows-xl diff --git a/src/ci/stage-build.py b/src/ci/stage-build.py new file mode 100644 index 00000000000..c373edfcf46 --- /dev/null +++ b/src/ci/stage-build.py @@ -0,0 +1,663 @@ +#!/usr/bin/env python3 +# ignore-tidy-linelength + +# Compatible with Python 3.6+ + +import contextlib +import getpass +import glob +import logging +import os +import pprint +import shutil +import subprocess +import sys +import time +import traceback +import urllib.request +from collections import OrderedDict +from io import StringIO +from pathlib import Path +from typing import Callable, Dict, Iterable, List, Optional, Union + +PGO_HOST = os.environ["PGO_HOST"] + +LOGGER = logging.getLogger("stage-build") + +LLVM_PGO_CRATES = [ + "syn-1.0.89", + "cargo-0.60.0", + "serde-1.0.136", + "ripgrep-13.0.0", + "regex-1.5.5", + "clap-3.1.6", + "hyper-0.14.18" +] + +RUSTC_PGO_CRATES = [ + "externs", + "ctfe-stress-5", + "cargo-0.60.0", + "token-stream-stress", + "match-stress", + "tuple-stress", + "diesel-1.4.8", + "bitmaps-3.1.0" +] + +LLVM_BOLT_CRATES = LLVM_PGO_CRATES + + +class Pipeline: + # Paths + def checkout_path(self) -> Path: + """ + The root checkout, where the source is located. + """ + raise NotImplementedError + + def downloaded_llvm_dir(self) -> Path: + """ + Directory where the host LLVM is located. + """ + raise NotImplementedError + + def build_root(self) -> Path: + """ + The main directory where the build occurs. + """ + raise NotImplementedError + + def build_artifacts(self) -> Path: + return self.build_root() / "build" / PGO_HOST + + def rustc_stage_0(self) -> Path: + return self.build_artifacts() / "stage0" / "bin" / "rustc" + + def cargo_stage_0(self) -> Path: + return self.build_artifacts() / "stage0" / "bin" / "cargo" + + def rustc_stage_2(self) -> Path: + return self.build_artifacts() / "stage2" / "bin" / "rustc" + + def opt_artifacts(self) -> Path: + raise NotImplementedError + + def llvm_profile_dir_root(self) -> Path: + return self.opt_artifacts() / "llvm-pgo" + + def llvm_profile_merged_file(self) -> Path: + return self.opt_artifacts() / "llvm-pgo.profdata" + + def rustc_perf_dir(self) -> Path: + return self.opt_artifacts() / "rustc-perf" + + def build_rustc_perf(self): + raise NotImplementedError() + + def rustc_profile_dir_root(self) -> Path: + return self.opt_artifacts() / "rustc-pgo" + + def rustc_profile_merged_file(self) -> Path: + return self.opt_artifacts() / "rustc-pgo.profdata" + + def rustc_profile_template_path(self) -> Path: + """ + The profile data is written into a single filepath that is being repeatedly merged when each + rustc invocation ends. Empirically, this can result in some profiling data being lost. That's + why we override the profile path to include the PID. This will produce many more profiling + files, but the resulting profile will produce a slightly faster rustc binary. + """ + return self.rustc_profile_dir_root() / "default_%m_%p.profraw" + + def supports_bolt(self) -> bool: + raise NotImplementedError + + def llvm_bolt_profile_merged_file(self) -> Path: + return self.opt_artifacts() / "bolt.profdata" + + +class LinuxPipeline(Pipeline): + def checkout_path(self) -> Path: + return Path("/checkout") + + def downloaded_llvm_dir(self) -> Path: + return Path("/rustroot") + + def build_root(self) -> Path: + return self.checkout_path() / "obj" + + def opt_artifacts(self) -> Path: + return Path("/tmp/tmp-multistage/opt-artifacts") + + def build_rustc_perf(self): + # /tmp/rustc-perf comes from the Dockerfile + shutil.copytree("/tmp/rustc-perf", self.rustc_perf_dir()) + cmd(["chown", "-R", f"{getpass.getuser()}:", self.rustc_perf_dir()]) + + with change_cwd(self.rustc_perf_dir()): + cmd([self.cargo_stage_0(), "build", "-p", "collector"], env=dict( + RUSTC=str(self.rustc_stage_0()), + RUSTC_BOOTSTRAP="1" + )) + + def supports_bolt(self) -> bool: + return True + + +class WindowsPipeline(Pipeline): + def __init__(self): + self.checkout_dir = Path(os.getcwd()) + + def checkout_path(self) -> Path: + return self.checkout_dir + + def downloaded_llvm_dir(self) -> Path: + return self.checkout_path() / "citools" / "clang-rust" + + def build_root(self) -> Path: + return self.checkout_path() + + def opt_artifacts(self) -> Path: + return self.checkout_path() / "opt-artifacts" + + def rustc_stage_0(self) -> Path: + return super().rustc_stage_0().with_suffix(".exe") + + def cargo_stage_0(self) -> Path: + return super().cargo_stage_0().with_suffix(".exe") + + def rustc_stage_2(self) -> Path: + return super().rustc_stage_2().with_suffix(".exe") + + def build_rustc_perf(self): + # rustc-perf version from 2022-07-22 + perf_commit = "3c253134664fdcba862c539d37f0de18557a9a4c" + rustc_perf_zip_path = self.opt_artifacts() / "perf.zip" + + def download_rustc_perf(): + download_file( + f"https://github.com/rust-lang/rustc-perf/archive/{perf_commit}.zip", + rustc_perf_zip_path + ) + with change_cwd(self.opt_artifacts()): + unpack_archive(rustc_perf_zip_path) + move_path(Path(f"rustc-perf-{perf_commit}"), self.rustc_perf_dir()) + delete_file(rustc_perf_zip_path) + + retry_action(download_rustc_perf, "Download rustc-perf") + + with change_cwd(self.rustc_perf_dir()): + cmd([self.cargo_stage_0(), "build", "-p", "collector"], env=dict( + RUSTC=str(self.rustc_stage_0()), + RUSTC_BOOTSTRAP="1" + )) + + def rustc_profile_template_path(self) -> Path: + """ + On Windows, we don't have enough space to use separate files for each rustc invocation. + Therefore, we use a single file for the generated profiles. + """ + return self.rustc_profile_dir_root() / "default_%m.profraw" + + def supports_bolt(self) -> bool: + return False + + +class Timer: + def __init__(self): + # We want this dictionary to be ordered by insertion. + # We use `OrderedDict` for compatibility with older Python versions. + self.stages = OrderedDict() + + @contextlib.contextmanager + def stage(self, name: str): + assert name not in self.stages + + start = time.time() + exc = None + try: + LOGGER.info(f"Stage `{name}` starts") + yield + except BaseException as exception: + exc = exception + raise + finally: + end = time.time() + duration = end - start + self.stages[name] = duration + if exc is None: + LOGGER.info(f"Stage `{name}` ended: OK ({duration:.2f}s)") + else: + LOGGER.info(f"Stage `{name}` ended: FAIL ({duration:.2f}s)") + + def print_stats(self): + total_duration = sum(self.stages.values()) + + # 57 is the width of the whole table + divider = "-" * 57 + + with StringIO() as output: + print(divider, file=output) + for (name, duration) in self.stages.items(): + pct = (duration / total_duration) * 100 + name_str = f"{name}:" + print(f"{name_str:<34} {duration:>12.2f}s ({pct:>5.2f}%)", file=output) + + total_duration_label = "Total duration:" + print(f"{total_duration_label:<34} {total_duration:>12.2f}s", file=output) + print(divider, file=output, end="") + LOGGER.info(f"Timer results\n{output.getvalue()}") + + +@contextlib.contextmanager +def change_cwd(dir: Path): + """ + Temporarily change working directory to `dir`. + """ + cwd = os.getcwd() + LOGGER.debug(f"Changing working dir from `{cwd}` to `{dir}`") + os.chdir(dir) + try: + yield + finally: + LOGGER.debug(f"Reverting working dir to `{cwd}`") + os.chdir(cwd) + + +def move_path(src: Path, dst: Path): + LOGGER.info(f"Moving `{src}` to `{dst}`") + shutil.move(src, dst) + + +def delete_file(path: Path): + LOGGER.info(f"Deleting file `{path}`") + os.unlink(path) + + +def delete_directory(path: Path): + LOGGER.info(f"Deleting directory `{path}`") + shutil.rmtree(path) + + +def unpack_archive(archive: Path): + LOGGER.info(f"Unpacking archive `{archive}`") + shutil.unpack_archive(archive) + + +def download_file(src: str, target: Path): + LOGGER.info(f"Downloading `{src}` into `{target}`") + urllib.request.urlretrieve(src, str(target)) + + +def retry_action(action, name: str, max_fails: int = 5): + LOGGER.info(f"Attempting to perform action `{name}` with retry") + for iteration in range(max_fails): + LOGGER.info(f"Attempt {iteration + 1}/{max_fails}") + try: + action() + return + except: + LOGGER.error(f"Action `{name}` has failed\n{traceback.format_exc()}") + + raise Exception(f"Action `{name}` has failed after {max_fails} attempts") + + +def cmd( + args: List[Union[str, Path]], + env: Optional[Dict[str, str]] = None, + output_path: Optional[Path] = None +): + args = [str(arg) for arg in args] + + environment = os.environ.copy() + + cmd_str = "" + if env is not None: + environment.update(env) + cmd_str += " ".join(f"{k}={v}" for (k, v) in (env or {}).items()) + cmd_str += " " + cmd_str += " ".join(args) + if output_path is not None: + cmd_str += f" > {output_path}" + LOGGER.info(f"Executing `{cmd_str}`") + + if output_path is not None: + with open(output_path, "w") as f: + return subprocess.run( + args, + env=environment, + check=True, + stdout=f + ) + return subprocess.run(args, env=environment, check=True) + + +def run_compiler_benchmarks( + pipeline: Pipeline, + profiles: List[str], + scenarios: List[str], + crates: List[str], + env: Optional[Dict[str, str]] = None +): + env = env if env is not None else {} + + # Compile libcore, both in opt-level=0 and opt-level=3 + with change_cwd(pipeline.build_root()): + cmd([ + pipeline.rustc_stage_2(), + "--edition", "2021", + "--crate-type", "lib", + str(pipeline.checkout_path() / "library/core/src/lib.rs"), + "--out-dir", pipeline.opt_artifacts() + ], env=dict(RUSTC_BOOTSTRAP="1", **env)) + + cmd([ + pipeline.rustc_stage_2(), + "--edition", "2021", + "--crate-type", "lib", + "-Copt-level=3", + str(pipeline.checkout_path() / "library/core/src/lib.rs"), + "--out-dir", pipeline.opt_artifacts() + ], env=dict(RUSTC_BOOTSTRAP="1", **env)) + + # Run rustc-perf benchmarks + # Benchmark using profile_local with eprintln, which essentially just means + # don't actually benchmark -- just make sure we run rustc a bunch of times. + with change_cwd(pipeline.rustc_perf_dir()): + cmd([ + pipeline.cargo_stage_0(), + "run", + "-p", "collector", "--bin", "collector", "--", + "profile_local", "eprintln", + pipeline.rustc_stage_2(), + "--id", "Test", + "--cargo", pipeline.cargo_stage_0(), + "--profiles", ",".join(profiles), + "--scenarios", ",".join(scenarios), + "--include", ",".join(crates) + ], env=dict( + RUST_LOG="collector=debug", + RUSTC=str(pipeline.rustc_stage_0()), + RUSTC_BOOTSTRAP="1", + **env + )) + + +# https://stackoverflow.com/a/31631711/1107768 +def format_bytes(size: int) -> str: + """Return the given bytes as a human friendly KiB, MiB or GiB string.""" + KB = 1024 + MB = KB ** 2 # 1,048,576 + GB = KB ** 3 # 1,073,741,824 + TB = KB ** 4 # 1,099,511,627,776 + + if size < KB: + return f"{size} B" + elif KB <= size < MB: + return f"{size / KB:.2f} KiB" + elif MB <= size < GB: + return f"{size / MB:.2f} MiB" + elif GB <= size < TB: + return f"{size / GB:.2f} GiB" + else: + return str(size) + + +# https://stackoverflow.com/a/63307131/1107768 +def count_files(path: Path) -> int: + return sum(1 for p in path.rglob("*") if p.is_file()) + + +def count_files_with_prefix(path: Path) -> int: + return sum(1 for p in glob.glob(f"{path}*") if Path(p).is_file()) + + +# https://stackoverflow.com/a/55659577/1107768 +def get_path_size(path: Path) -> int: + if path.is_dir(): + return sum(p.stat().st_size for p in path.rglob("*")) + return path.stat().st_size + + +def get_path_prefix_size(path: Path) -> int: + """ + Get size of all files beginning with the prefix `path`. + Alternative to shell `du -sh <path>*`. + """ + return sum(Path(p).stat().st_size for p in glob.glob(f"{path}*")) + + +def get_files(directory: Path, filter: Optional[Callable[[Path], bool]] = None) -> Iterable[Path]: + for file in os.listdir(directory): + path = directory / file + if filter is None or filter(path): + yield path + + +def build_rustc( + pipeline: Pipeline, + args: List[str], + env: Optional[Dict[str, str]] = None +): + arguments = [ + sys.executable, + pipeline.checkout_path() / "x.py", + "build", + "--target", PGO_HOST, + "--host", PGO_HOST, + "--stage", "2", + "library/std" + ] + args + cmd(arguments, env=env) + + +def create_pipeline() -> Pipeline: + if sys.platform == "linux": + return LinuxPipeline() + elif sys.platform in ("cygwin", "win32"): + return WindowsPipeline() + else: + raise Exception(f"Optimized build is not supported for platform {sys.platform}") + + +def gather_llvm_profiles(pipeline: Pipeline): + LOGGER.info("Running benchmarks with PGO instrumented LLVM") + run_compiler_benchmarks( + pipeline, + profiles=["Debug", "Opt"], + scenarios=["Full"], + crates=LLVM_PGO_CRATES + ) + + profile_path = pipeline.llvm_profile_merged_file() + LOGGER.info(f"Merging LLVM PGO profiles to {profile_path}") + cmd([ + pipeline.downloaded_llvm_dir() / "bin" / "llvm-profdata", + "merge", + "-o", profile_path, + pipeline.llvm_profile_dir_root() + ]) + + LOGGER.info("LLVM PGO statistics") + LOGGER.info(f"{profile_path}: {format_bytes(get_path_size(profile_path))}") + LOGGER.info( + f"{pipeline.llvm_profile_dir_root()}: {format_bytes(get_path_size(pipeline.llvm_profile_dir_root()))}") + LOGGER.info(f"Profile file count: {count_files(pipeline.llvm_profile_dir_root())}") + + # We don't need the individual .profraw files now that they have been merged + # into a final .profdata + delete_directory(pipeline.llvm_profile_dir_root()) + + +def gather_rustc_profiles(pipeline: Pipeline): + LOGGER.info("Running benchmarks with PGO instrumented rustc") + + # Here we're profiling the `rustc` frontend, so we also include `Check`. + # The benchmark set includes various stress tests that put the frontend under pressure. + run_compiler_benchmarks( + pipeline, + profiles=["Check", "Debug", "Opt"], + scenarios=["All"], + crates=RUSTC_PGO_CRATES, + env=dict( + LLVM_PROFILE_FILE=str(pipeline.rustc_profile_template_path()) + ) + ) + + profile_path = pipeline.rustc_profile_merged_file() + LOGGER.info(f"Merging Rustc PGO profiles to {profile_path}") + cmd([ + pipeline.build_artifacts() / "llvm" / "bin" / "llvm-profdata", + "merge", + "-o", profile_path, + pipeline.rustc_profile_dir_root() + ]) + + LOGGER.info("Rustc PGO statistics") + LOGGER.info(f"{profile_path}: {format_bytes(get_path_size(profile_path))}") + LOGGER.info( + f"{pipeline.rustc_profile_dir_root()}: {format_bytes(get_path_size(pipeline.rustc_profile_dir_root()))}") + LOGGER.info(f"Profile file count: {count_files(pipeline.rustc_profile_dir_root())}") + + # We don't need the individual .profraw files now that they have been merged + # into a final .profdata + delete_directory(pipeline.rustc_profile_dir_root()) + + +def gather_llvm_bolt_profiles(pipeline: Pipeline): + LOGGER.info("Running benchmarks with BOLT instrumented LLVM") + run_compiler_benchmarks( + pipeline, + profiles=["Check", "Debug", "Opt"], + scenarios=["Full"], + crates=LLVM_BOLT_CRATES + ) + + merged_profile_path = pipeline.llvm_bolt_profile_merged_file() + profile_files_path = Path("/tmp/prof.fdata") + LOGGER.info(f"Merging LLVM BOLT profiles to {merged_profile_path}") + + profile_files = sorted(glob.glob(f"{profile_files_path}*")) + cmd([ + "merge-fdata", + *profile_files, + ], output_path=merged_profile_path) + + LOGGER.info("LLVM BOLT statistics") + LOGGER.info(f"{merged_profile_path}: {format_bytes(get_path_size(merged_profile_path))}") + LOGGER.info( + f"{profile_files_path}: {format_bytes(get_path_prefix_size(profile_files_path))}") + LOGGER.info(f"Profile file count: {count_files_with_prefix(profile_files_path)}") + + +def clear_llvm_files(pipeline: Pipeline): + """ + Rustbuild currently doesn't support rebuilding LLVM when PGO options + change (or any other llvm-related options); so just clear out the relevant + directories ourselves. + """ + LOGGER.info("Clearing LLVM build files") + delete_directory(pipeline.build_artifacts() / "llvm") + delete_directory(pipeline.build_artifacts() / "lld") + + +def print_binary_sizes(pipeline: Pipeline): + bin_dir = pipeline.build_artifacts() / "stage2" / "bin" + binaries = get_files(bin_dir) + + lib_dir = pipeline.build_artifacts() / "stage2" / "lib" + libraries = get_files(lib_dir, lambda p: p.suffix == ".so") + + paths = sorted(binaries) + sorted(libraries) + with StringIO() as output: + for path in paths: + path_str = f"{path.name}:" + print(f"{path_str:<30}{format_bytes(path.stat().st_size):>14}", file=output) + LOGGER.info(f"Rustc binary size\n{output.getvalue()}") + + +def execute_build_pipeline(timer: Timer, pipeline: Pipeline, final_build_args: List[str]): + # Clear and prepare tmp directory + shutil.rmtree(pipeline.opt_artifacts(), ignore_errors=True) + os.makedirs(pipeline.opt_artifacts(), exist_ok=True) + + pipeline.build_rustc_perf() + + # Stage 1: Build rustc + PGO instrumented LLVM + with timer.stage("Build rustc (LLVM PGO)"): + build_rustc(pipeline, args=[ + "--llvm-profile-generate" + ], env=dict( + LLVM_PROFILE_DIR=str(pipeline.llvm_profile_dir_root() / "prof-%p") + )) + + with timer.stage("Gather profiles (LLVM PGO)"): + gather_llvm_profiles(pipeline) + + clear_llvm_files(pipeline) + final_build_args += [ + "--llvm-profile-use", + pipeline.llvm_profile_merged_file() + ] + + # Stage 2: Build PGO instrumented rustc + LLVM + with timer.stage("Build rustc (rustc PGO)"): + build_rustc(pipeline, args=[ + "--rust-profile-generate", + pipeline.rustc_profile_dir_root() + ]) + + with timer.stage("Gather profiles (rustc PGO)"): + gather_rustc_profiles(pipeline) + + clear_llvm_files(pipeline) + final_build_args += [ + "--rust-profile-use", + pipeline.rustc_profile_merged_file() + ] + + # Stage 3: Build rustc + BOLT instrumented LLVM + if pipeline.supports_bolt(): + with timer.stage("Build rustc (LLVM BOLT)"): + build_rustc(pipeline, args=[ + "--llvm-profile-use", + pipeline.llvm_profile_merged_file(), + "--llvm-bolt-profile-generate", + ]) + with timer.stage("Gather profiles (LLVM BOLT)"): + gather_llvm_bolt_profiles(pipeline) + + clear_llvm_files(pipeline) + final_build_args += [ + "--llvm-bolt-profile-use", + pipeline.llvm_bolt_profile_merged_file() + ] + + # Stage 4: Build PGO optimized rustc + PGO/BOLT optimized LLVM + with timer.stage("Final build"): + cmd(final_build_args) + + +if __name__ == "__main__": + logging.basicConfig( + level=logging.DEBUG, + format="%(name)s %(levelname)-4s: %(message)s", + ) + + LOGGER.info(f"Running multi-stage build using Python {sys.version}") + LOGGER.info(f"Environment values\n{pprint.pformat(dict(os.environ), indent=2)}") + + build_args = sys.argv[1:] + + timer = Timer() + pipeline = create_pipeline() + try: + execute_build_pipeline(timer, pipeline, build_args) + except BaseException as e: + LOGGER.error("The multi-stage build has failed") + raise e + finally: + timer.print_stats() + + print_binary_sizes(pipeline) diff --git a/src/etc/pre-push.sh b/src/etc/pre-push.sh index 7a846d44ad6..ff17931115c 100755 --- a/src/etc/pre-push.sh +++ b/src/etc/pre-push.sh @@ -14,4 +14,4 @@ ROOT_DIR="$(git rev-parse --show-toplevel)" echo "Running pre-push script $ROOT_DIR/x test tidy" cd "$ROOT_DIR" -./x test tidy +CARGOFLAGS="--locked" ./x test tidy diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index d644293d3ef..be6de231854 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -1528,11 +1528,7 @@ fn render_impl( }) }) .map(|item| format!("{}.{}", item.type_(), name)); - write!( - w, - "<section id=\"{}\" class=\"{}{} has-srclink\">", - id, item_type, in_trait_class, - ); + write!(w, "<section id=\"{}\" class=\"{}{}\">", id, item_type, in_trait_class,); render_rightside(w, cx, item, containing_item, render_mode); if trait_.is_some() { // Anchors are only used on trait impls. @@ -1554,11 +1550,7 @@ fn render_impl( kind @ (clean::TyAssocConstItem(ty) | clean::AssocConstItem(ty, _)) => { let source_id = format!("{}.{}", item_type, name); let id = cx.derive_id(source_id.clone()); - write!( - w, - "<section id=\"{}\" class=\"{}{} has-srclink\">", - id, item_type, in_trait_class - ); + write!(w, "<section id=\"{}\" class=\"{}{}\">", id, item_type, in_trait_class); render_rightside(w, cx, item, containing_item, render_mode); if trait_.is_some() { // Anchors are only used on trait impls. @@ -1606,11 +1598,7 @@ fn render_impl( clean::AssocTypeItem(tydef, _bounds) => { let source_id = format!("{}.{}", item_type, name); let id = cx.derive_id(source_id.clone()); - write!( - w, - "<section id=\"{}\" class=\"{}{} has-srclink\">", - id, item_type, in_trait_class - ); + write!(w, "<section id=\"{}\" class=\"{}{}\">", id, item_type, in_trait_class); if trait_.is_some() { // Anchors are only used on trait impls. write!(w, "<a href=\"#{}\" class=\"anchor\">§</a>", id); @@ -1844,7 +1832,7 @@ pub(crate) fn render_impl_summary( } else { format!(" data-aliases=\"{}\"", aliases.join(",")) }; - write!(w, "<section id=\"{}\" class=\"impl has-srclink\"{}>", id, aliases); + write!(w, "<section id=\"{}\" class=\"impl\"{}>", id, aliases); render_rightside(w, cx, &i.impl_item, containing_item, RenderMode::Normal); write!(w, "<a href=\"#{}\" class=\"anchor\">§</a>", id); write!(w, "<h3 class=\"code-header\">"); diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index 508b2bab0eb..b0288d55c25 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -735,7 +735,7 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean: let method_toggle_class = if item_type.is_method() { " method-toggle" } else { "" }; write!(w, "<details class=\"toggle{method_toggle_class}\" open><summary>"); } - write!(w, "<section id=\"{}\" class=\"method has-srclink\">", id); + write!(w, "<section id=\"{}\" class=\"method\">", id); render_rightside(w, cx, m, t, RenderMode::Normal); write!(w, "<h4 class=\"code-header\">"); render_assoc_item( diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index dc30e4bb1be..45fd87bea9b 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -926,7 +926,7 @@ pub fn make_test_description<R: Read>( cfg: Option<&str>, ) -> test::TestDesc { let mut ignore = false; - let ignore_message = None; + let mut ignore_message = None; let mut should_fail = false; let rustc_has_profiler_support = env::var_os("RUSTC_PROFILER_SUPPORT").is_some(); @@ -966,41 +966,67 @@ pub fn make_test_description<R: Read>( if revision.is_some() && revision != cfg { return; } + macro_rules! reason { + ($e:expr) => { + ignore |= match $e { + true => { + ignore_message = Some(stringify!($e)); + true + } + false => ignore, + } + }; + } ignore = match config.parse_cfg_name_directive(ln, "ignore") { - ParsedNameDirective::Match => true, + ParsedNameDirective::Match => { + ignore_message = Some("cfg -> ignore => Match"); + true + } ParsedNameDirective::NoMatch => ignore, }; + if config.has_cfg_prefix(ln, "only") { ignore = match config.parse_cfg_name_directive(ln, "only") { ParsedNameDirective::Match => ignore, - ParsedNameDirective::NoMatch => true, + ParsedNameDirective::NoMatch => { + ignore_message = Some("cfg -> only => NoMatch"); + true + } }; } - ignore |= ignore_llvm(config, ln); - ignore |= - config.run_clang_based_tests_with.is_none() && config.parse_needs_matching_clang(ln); - ignore |= !has_asm_support && config.parse_name_directive(ln, "needs-asm-support"); - ignore |= !rustc_has_profiler_support && config.parse_needs_profiler_support(ln); - ignore |= !config.run_enabled() && config.parse_name_directive(ln, "needs-run-enabled"); - ignore |= !rustc_has_sanitizer_support - && config.parse_name_directive(ln, "needs-sanitizer-support"); - ignore |= !has_asan && config.parse_name_directive(ln, "needs-sanitizer-address"); - ignore |= !has_cfi && config.parse_name_directive(ln, "needs-sanitizer-cfi"); - ignore |= !has_kcfi && config.parse_name_directive(ln, "needs-sanitizer-kcfi"); - ignore |= !has_lsan && config.parse_name_directive(ln, "needs-sanitizer-leak"); - ignore |= !has_msan && config.parse_name_directive(ln, "needs-sanitizer-memory"); - ignore |= !has_tsan && config.parse_name_directive(ln, "needs-sanitizer-thread"); - ignore |= !has_hwasan && config.parse_name_directive(ln, "needs-sanitizer-hwaddress"); - ignore |= !has_memtag && config.parse_name_directive(ln, "needs-sanitizer-memtag"); - ignore |= !has_shadow_call_stack - && config.parse_name_directive(ln, "needs-sanitizer-shadow-call-stack"); - ignore |= !config.can_unwind() && config.parse_name_directive(ln, "needs-unwind"); - ignore |= config.target == "wasm32-unknown-unknown" - && config.parse_name_directive(ln, directives::CHECK_RUN_RESULTS); - ignore |= config.debugger == Some(Debugger::Cdb) && ignore_cdb(config, ln); - ignore |= config.debugger == Some(Debugger::Gdb) && ignore_gdb(config, ln); - ignore |= config.debugger == Some(Debugger::Lldb) && ignore_lldb(config, ln); - ignore |= !has_rust_lld && config.parse_name_directive(ln, "needs-rust-lld"); + + reason!(ignore_llvm(config, ln)); + reason!( + config.run_clang_based_tests_with.is_none() && config.parse_needs_matching_clang(ln) + ); + reason!(!has_asm_support && config.parse_name_directive(ln, "needs-asm-support")); + reason!(!rustc_has_profiler_support && config.parse_needs_profiler_support(ln)); + reason!(!config.run_enabled() && config.parse_name_directive(ln, "needs-run-enabled")); + reason!( + !rustc_has_sanitizer_support + && config.parse_name_directive(ln, "needs-sanitizer-support") + ); + reason!(!has_asan && config.parse_name_directive(ln, "needs-sanitizer-address")); + reason!(!has_cfi && config.parse_name_directive(ln, "needs-sanitizer-cfi")); + reason!(!has_kcfi && config.parse_name_directive(ln, "needs-sanitizer-kcfi")); + reason!(!has_lsan && config.parse_name_directive(ln, "needs-sanitizer-leak")); + reason!(!has_msan && config.parse_name_directive(ln, "needs-sanitizer-memory")); + reason!(!has_tsan && config.parse_name_directive(ln, "needs-sanitizer-thread")); + reason!(!has_hwasan && config.parse_name_directive(ln, "needs-sanitizer-hwaddress")); + reason!(!has_memtag && config.parse_name_directive(ln, "needs-sanitizer-memtag")); + reason!( + !has_shadow_call_stack + && config.parse_name_directive(ln, "needs-sanitizer-shadow-call-stack") + ); + reason!(!config.can_unwind() && config.parse_name_directive(ln, "needs-unwind")); + reason!( + config.target == "wasm32-unknown-unknown" + && config.parse_name_directive(ln, directives::CHECK_RUN_RESULTS) + ); + reason!(config.debugger == Some(Debugger::Cdb) && ignore_cdb(config, ln)); + reason!(config.debugger == Some(Debugger::Gdb) && ignore_gdb(config, ln)); + reason!(config.debugger == Some(Debugger::Lldb) && ignore_lldb(config, ln)); + reason!(!has_rust_lld && config.parse_name_directive(ln, "needs-rust-lld")); should_fail |= config.parse_name_directive(ln, "should-fail"); }); diff --git a/src/tools/publish_toolstate.py b/src/tools/publish_toolstate.py index 9c16ef2cbec..395bcc745f8 100755 --- a/src/tools/publish_toolstate.py +++ b/src/tools/publish_toolstate.py @@ -68,52 +68,6 @@ def load_json_from_response(resp): print("Refusing to decode " + str(type(content)) + " to str") return json.loads(content_str) -def validate_maintainers(repo, github_token): - # type: (str, str) -> None - '''Ensure all maintainers are assignable on a GitHub repo''' - next_link_re = re.compile(r'<([^>]+)>; rel="next"') - - # Load the list of assignable people in the GitHub repo - assignable = [] # type: typing.List[str] - url = 'https://api.github.com/repos/' \ - + '%s/collaborators?per_page=100' % repo # type: typing.Optional[str] - while url is not None: - response = urllib2.urlopen(urllib2.Request(url, headers={ - 'Authorization': 'token ' + github_token, - # Properly load nested teams. - 'Accept': 'application/vnd.github.hellcat-preview+json', - })) - assignable.extend(user['login'] for user in load_json_from_response(response)) - # Load the next page if available - url = None - link_header = response.headers.get('Link') - if link_header: - matches = next_link_re.match(link_header) - if matches is not None: - url = matches.group(1) - - errors = False - for tool, maintainers in MAINTAINERS.items(): - for maintainer in maintainers: - if maintainer not in assignable: - errors = True - print( - "error: %s maintainer @%s is not assignable in the %s repo" - % (tool, maintainer, repo), - ) - - if errors: - print() - print(" To be assignable, a person needs to be explicitly listed as a") - print(" collaborator in the repository settings. The simple way to") - print(" fix this is to ask someone with 'admin' privileges on the repo") - print(" to add the person or whole team as a collaborator with 'read'") - print(" privileges. Those privileges don't grant any extra permissions") - print(" so it's safe to apply them.") - print() - print("The build will fail due to this.") - exit(1) - def read_current_status(current_commit, path): # type: (str, str) -> typing.Mapping[str, typing.Any] @@ -280,21 +234,6 @@ def update_latest( try: if __name__ != '__main__': exit(0) - repo = os.environ.get('TOOLSTATE_VALIDATE_MAINTAINERS_REPO') - if repo: - github_token = os.environ.get('TOOLSTATE_REPO_ACCESS_TOKEN') - if github_token: - # FIXME: This is currently broken. Starting on 2021-09-15, GitHub - # seems to have changed it so that to list the collaborators - # requires admin permissions. I think this will probably just need - # to be removed since we are probably not going to use an admin - # token, and I don't see another way to do this. - print('maintainer validation disabled') - # validate_maintainers(repo, github_token) - else: - print('skipping toolstate maintainers validation since no GitHub token is present') - # When validating maintainers don't run the full script. - exit(0) cur_commit = sys.argv[1] cur_datetime = datetime.datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%SZ') diff --git a/tests/pretty/issue-4264.pp b/tests/pretty/issue-4264.pp index 44d21625a2d..e0fa1fe2824 100644 --- a/tests/pretty/issue-4264.pp +++ b/tests/pretty/issue-4264.pp @@ -34,10 +34,11 @@ fn bar() ({ ((::alloc::fmt::format as for<'a> fn(Arguments<'a>) -> String {format})(((<#[lang = "format_arguments"]>::new_v1 as - fn(&[&'static str], &[ArgumentV1<'_>]) -> Arguments<'_> {Arguments::<'_>::new_v1})((&([("test" + fn(&[&'static str], &[core::fmt::ArgumentV1<'_>]) -> Arguments<'_> {Arguments::<'_>::new_v1})((&([("test" as &str)] as [&str; 1]) as &[&str; 1]), - (&([] as [ArgumentV1<'_>; 0]) as &[ArgumentV1<'_>; 0])) as - Arguments<'_>)) as String); + (&([] as [core::fmt::ArgumentV1<'_>; 0]) as + &[core::fmt::ArgumentV1<'_>; 0])) as Arguments<'_>)) as + String); (res as String) } as String); } as ()) diff --git a/tests/rustdoc-gui/src-font-size.goml b/tests/rustdoc-gui/src-font-size.goml index 9233f37444b..bab66dae70c 100644 --- a/tests/rustdoc-gui/src-font-size.goml +++ b/tests/rustdoc-gui/src-font-size.goml @@ -4,13 +4,13 @@ goto: "file://" + |DOC_PATH| + "/test_docs/struct.Foo.html" show-text: true // Check the impl headers. -assert-css: (".impl.has-srclink .srclink", {"font-size": "16px", "font-weight": 400}, ALL) -assert-css: (".impl.has-srclink .code-header", {"font-size": "18px", "font-weight": 600}, ALL) +assert-css: (".impl .srclink", {"font-size": "16px", "font-weight": 400}, ALL) +assert-css: (".impl .code-header", {"font-size": "18px", "font-weight": 600}, ALL) // Check the impl items. -assert-css: (".impl-items .has-srclink .srclink", {"font-size": "16px", "font-weight": 400}, ALL) -assert-css: (".impl-items .has-srclink .code-header", {"font-size": "16px", "font-weight": 600}, ALL) +assert-css: (".impl-items .srclink", {"font-size": "16px", "font-weight": 400}, ALL) +assert-css: (".impl-items .code-header", {"font-size": "16px", "font-weight": 600}, ALL) // Check that we can click on source link store-document-property: (url, "URL") -click: ".impl-items .has-srclink .srclink" +click: ".impl-items .srclink" assert-document-property-false: {"URL": |url|} diff --git a/tests/rustdoc/anchors.no_const_anchor.html b/tests/rustdoc/anchors.no_const_anchor.html index 75e67330a3e..a8587829d3e 100644 --- a/tests/rustdoc/anchors.no_const_anchor.html +++ b/tests/rustdoc/anchors.no_const_anchor.html @@ -1 +1 @@ -<section id="associatedconstant.YOLO" class="method has-srclink"><a class="srclink rightside" href="../src/foo/anchors.rs.html#16">source</a><h4 class="code-header">const <a href="#associatedconstant.YOLO" class="constant">YOLO</a>: <a class="primitive" href="{{channel}}/std/primitive.u32.html">u32</a></h4></section> \ No newline at end of file +<section id="associatedconstant.YOLO" class="method"><a class="srclink rightside" href="../src/foo/anchors.rs.html#16">source</a><h4 class="code-header">const <a href="#associatedconstant.YOLO" class="constant">YOLO</a>: <a class="primitive" href="{{channel}}/std/primitive.u32.html">u32</a></h4></section> \ No newline at end of file diff --git a/tests/rustdoc/anchors.no_const_anchor2.html b/tests/rustdoc/anchors.no_const_anchor2.html index c0025197602..4c5e45fea2d 100644 --- a/tests/rustdoc/anchors.no_const_anchor2.html +++ b/tests/rustdoc/anchors.no_const_anchor2.html @@ -1 +1 @@ -<section id="associatedconstant.X" class="associatedconstant has-srclink"><a class="srclink rightside" href="../src/foo/anchors.rs.html#42">source</a><h4 class="code-header">pub const <a href="#associatedconstant.X" class="constant">X</a>: <a class="primitive" href="{{channel}}/std/primitive.i32.html">i32</a> = 0i32</h4></section> \ No newline at end of file +<section id="associatedconstant.X" class="associatedconstant"><a class="srclink rightside" href="../src/foo/anchors.rs.html#42">source</a><h4 class="code-header">pub const <a href="#associatedconstant.X" class="constant">X</a>: <a class="primitive" href="{{channel}}/std/primitive.i32.html">i32</a> = 0i32</h4></section> \ No newline at end of file diff --git a/tests/rustdoc/anchors.no_method_anchor.html b/tests/rustdoc/anchors.no_method_anchor.html index b9ec8bf4c09..44957a5b71a 100644 --- a/tests/rustdoc/anchors.no_method_anchor.html +++ b/tests/rustdoc/anchors.no_method_anchor.html @@ -1 +1 @@ -<section id="method.new" class="method has-srclink"><a class="srclink rightside" href="../src/foo/anchors.rs.html#48">source</a><h4 class="code-header">pub fn <a href="#method.new" class="fn">new</a>() -> Self</h4></section> \ No newline at end of file +<section id="method.new" class="method"><a class="srclink rightside" href="../src/foo/anchors.rs.html#48">source</a><h4 class="code-header">pub fn <a href="#method.new" class="fn">new</a>() -> Self</h4></section> \ No newline at end of file diff --git a/tests/rustdoc/anchors.no_trait_method_anchor.html b/tests/rustdoc/anchors.no_trait_method_anchor.html index 4308ddad412..75c2caf87a8 100644 --- a/tests/rustdoc/anchors.no_trait_method_anchor.html +++ b/tests/rustdoc/anchors.no_trait_method_anchor.html @@ -1 +1 @@ -<section id="method.bar" class="method has-srclink"><a class="srclink rightside" href="../src/foo/anchors.rs.html#23">source</a><h4 class="code-header">fn <a href="#method.bar" class="fn">bar</a>()</h4></section> \ No newline at end of file +<section id="method.bar" class="method"><a class="srclink rightside" href="../src/foo/anchors.rs.html#23">source</a><h4 class="code-header">fn <a href="#method.bar" class="fn">bar</a>()</h4></section> \ No newline at end of file diff --git a/tests/rustdoc/anchors.no_tymethod_anchor.html b/tests/rustdoc/anchors.no_tymethod_anchor.html index 91eed8a3742..38575eadfa9 100644 --- a/tests/rustdoc/anchors.no_tymethod_anchor.html +++ b/tests/rustdoc/anchors.no_tymethod_anchor.html @@ -1 +1 @@ -<section id="tymethod.foo" class="method has-srclink"><a class="srclink rightside" href="../src/foo/anchors.rs.html#20">source</a><h4 class="code-header">fn <a href="#tymethod.foo" class="fn">foo</a>()</h4></section> \ No newline at end of file +<section id="tymethod.foo" class="method"><a class="srclink rightside" href="../src/foo/anchors.rs.html#20">source</a><h4 class="code-header">fn <a href="#tymethod.foo" class="fn">foo</a>()</h4></section> \ No newline at end of file diff --git a/tests/rustdoc/anchors.no_type_anchor.html b/tests/rustdoc/anchors.no_type_anchor.html index 2c66d5aa315..dd65d98fee6 100644 --- a/tests/rustdoc/anchors.no_type_anchor.html +++ b/tests/rustdoc/anchors.no_type_anchor.html @@ -1 +1 @@ -<section id="associatedtype.T" class="method has-srclink"><a class="srclink rightside" href="../src/foo/anchors.rs.html#13">source</a><h4 class="code-header">type <a href="#associatedtype.T" class="associatedtype">T</a></h4></section> \ No newline at end of file +<section id="associatedtype.T" class="method"><a class="srclink rightside" href="../src/foo/anchors.rs.html#13">source</a><h4 class="code-header">type <a href="#associatedtype.T" class="associatedtype">T</a></h4></section> \ No newline at end of file diff --git a/tests/rustdoc/anchors.no_type_anchor2.html b/tests/rustdoc/anchors.no_type_anchor2.html index 72a1186bf7e..f8b59160f15 100644 --- a/tests/rustdoc/anchors.no_type_anchor2.html +++ b/tests/rustdoc/anchors.no_type_anchor2.html @@ -1 +1 @@ -<section id="associatedtype.Y" class="associatedtype has-srclink"><h4 class="code-header">type <a href="#associatedtype.Y" class="associatedtype">Y</a> = <a class="primitive" href="{{channel}}/std/primitive.u32.html">u32</a></h4></section> +<section id="associatedtype.Y" class="associatedtype"><h4 class="code-header">type <a href="#associatedtype.Y" class="associatedtype">Y</a> = <a class="primitive" href="{{channel}}/std/primitive.u32.html">u32</a></h4></section> \ No newline at end of file diff --git a/tests/rustdoc/async-fn.rs b/tests/rustdoc/async-fn.rs index fb7ebb5f822..8cafb5a2497 100644 --- a/tests/rustdoc/async-fn.rs +++ b/tests/rustdoc/async-fn.rs @@ -77,12 +77,12 @@ struct AsyncFdReadyGuard<'a, T> { x: &'a T } impl Foo { // @has async_fn/struct.Foo.html - // @has - '//*[@class="method has-srclink"]' 'pub async fn complicated_lifetimes( &self, context: &impl Bar) -> impl Iterator<Item = &usize>' + // @has - '//*[@class="method"]' 'pub async fn complicated_lifetimes( &self, context: &impl Bar) -> impl Iterator<Item = &usize>' pub async fn complicated_lifetimes(&self, context: &impl Bar) -> impl Iterator<Item = &usize> {} // taken from `tokio` as an example of a method that was particularly bad before - // @has - '//*[@class="method has-srclink"]' "pub async fn readable<T>(&self) -> Result<AsyncFdReadyGuard<'_, T>, ()>" + // @has - '//*[@class="method"]' "pub async fn readable<T>(&self) -> Result<AsyncFdReadyGuard<'_, T>, ()>" pub async fn readable<T>(&self) -> Result<AsyncFdReadyGuard<'_, T>, ()> {} - // @has - '//*[@class="method has-srclink"]' "pub async fn mut_self(&mut self)" + // @has - '//*[@class="method"]' "pub async fn mut_self(&mut self)" pub async fn mut_self(&mut self) {} } diff --git a/tests/rustdoc/const-fn.rs b/tests/rustdoc/const-fn.rs index 4366ad4d0ad..18863abaeac 100644 --- a/tests/rustdoc/const-fn.rs +++ b/tests/rustdoc/const-fn.rs @@ -8,7 +8,7 @@ pub const fn bar() -> usize { } // @has foo/struct.Foo.html -// @has - '//*[@class="method has-srclink"]' 'const fn new()' +// @has - '//*[@class="method"]' 'const fn new()' pub struct Foo(usize); impl Foo { diff --git a/tests/rustdoc/const-generics/const-generic-slice.rs b/tests/rustdoc/const-generics/const-generic-slice.rs index 4279de91f56..80a9ab3f12e 100644 --- a/tests/rustdoc/const-generics/const-generic-slice.rs +++ b/tests/rustdoc/const-generics/const-generic-slice.rs @@ -5,7 +5,7 @@ pub trait Array { } // @has foo/trait.Array.html -// @has - '//*[@class="impl has-srclink"]' 'impl<T, const N: usize> Array for [T; N]' +// @has - '//*[@class="impl"]' 'impl<T, const N: usize> Array for [T; N]' impl<T, const N: usize> Array for [T; N] { type Item = T; } diff --git a/tests/rustdoc/doc-assoc-item.rs b/tests/rustdoc/doc-assoc-item.rs index 4f15418650c..4d5c9f83e1e 100644 --- a/tests/rustdoc/doc-assoc-item.rs +++ b/tests/rustdoc/doc-assoc-item.rs @@ -8,7 +8,7 @@ pub trait Bar { fn foo(foo: Self::Fuu); } -// @has doc_assoc_item/struct.Foo.html '//*[@class="impl has-srclink"]' 'impl<T: Bar<Fuu = u32>> Foo<T>' +// @has doc_assoc_item/struct.Foo.html '//*[@class="impl"]' 'impl<T: Bar<Fuu = u32>> Foo<T>' impl<T: Bar<Fuu = u32>> Foo<T> { pub fn new(t: T) -> Foo<T> { Foo { diff --git a/tests/rustdoc/duplicate_impls/issue-33054.rs b/tests/rustdoc/duplicate_impls/issue-33054.rs index c1f95ac91c3..4c2071b8322 100644 --- a/tests/rustdoc/duplicate_impls/issue-33054.rs +++ b/tests/rustdoc/duplicate_impls/issue-33054.rs @@ -3,8 +3,8 @@ // @has issue_33054/impls/struct.Foo.html // @has - '//h3[@class="code-header"]' 'impl Foo' // @has - '//h3[@class="code-header"]' 'impl Bar for Foo' -// @count - '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]' 1 -// @count - '//*[@id="main-content"]/div[@id="implementations-list"]/details/summary/*[@class="impl has-srclink"]' 1 +// @count - '//*[@id="trait-implementations-list"]//*[@class="impl"]' 1 +// @count - '//*[@id="main-content"]/div[@id="implementations-list"]/details/summary/*[@class="impl"]' 1 // @has issue_33054/impls/bar/trait.Bar.html // @has - '//h3[@class="code-header"]' 'impl Bar for Foo' // @count - '//*[@class="struct"]' 1 diff --git a/tests/rustdoc/duplicated_impl.rs b/tests/rustdoc/duplicated_impl.rs index 4e901b31c90..f32cf310055 100644 --- a/tests/rustdoc/duplicated_impl.rs +++ b/tests/rustdoc/duplicated_impl.rs @@ -7,7 +7,7 @@ // blanket implementations. // @has 'foo/struct.Whatever.html' -// @count - '//*[@id="blanket-implementations-list"]/section[@class="impl has-srclink"]' 1 +// @count - '//*[@id="blanket-implementations-list"]/section[@class="impl"]' 1 pub trait Something<T> { } pub struct Whatever; diff --git a/tests/rustdoc/empty-impl-block-private-with-doc.rs b/tests/rustdoc/empty-impl-block-private-with-doc.rs index 43971996163..e6cff97b184 100644 --- a/tests/rustdoc/empty-impl-block-private-with-doc.rs +++ b/tests/rustdoc/empty-impl-block-private-with-doc.rs @@ -10,7 +10,7 @@ pub struct Foo; // There are 3 impl blocks with public item and one that should not be displayed // by default because it only contains private items (but not in this case because // we used `--document-private-items`). -// @count - '//*[@class="impl has-srclink"]' 'impl Foo' 4 +// @count - '//*[@class="impl"]' 'impl Foo' 4 // Impl block only containing private items should not be displayed unless the // `--document-private-items` flag is used. diff --git a/tests/rustdoc/empty-impl-block-private.rs b/tests/rustdoc/empty-impl-block-private.rs index 5caf020658c..d44b4a47cee 100644 --- a/tests/rustdoc/empty-impl-block-private.rs +++ b/tests/rustdoc/empty-impl-block-private.rs @@ -7,7 +7,7 @@ pub struct Foo; // There are 3 impl blocks with public item and one that should not be displayed // because it only contains private items. -// @count - '//*[@class="impl has-srclink"]' 'impl Foo' 3 +// @count - '//*[@class="impl"]' 'impl Foo' 3 // Impl block only containing private items should not be displayed. /// Private diff --git a/tests/rustdoc/empty-impl-block.rs b/tests/rustdoc/empty-impl-block.rs index 95d4db06b31..da780580bd0 100644 --- a/tests/rustdoc/empty-impl-block.rs +++ b/tests/rustdoc/empty-impl-block.rs @@ -8,7 +8,7 @@ pub struct Foo; /// Hello empty impl block! impl Foo {} // We ensure that this empty impl block without doc isn't rendered. -// @count - '//*[@class="impl has-srclink"]' 'impl Foo' 1 +// @count - '//*[@class="impl"]' 'impl Foo' 1 impl Foo {} // Just to ensure that empty trait impl blocks are rendered. diff --git a/tests/rustdoc/impl-parts.rs b/tests/rustdoc/impl-parts.rs index 90cbb77cb6b..f7738060e99 100644 --- a/tests/rustdoc/impl-parts.rs +++ b/tests/rustdoc/impl-parts.rs @@ -5,7 +5,7 @@ pub auto trait AnAutoTrait {} pub struct Foo<T> { field: T } -// @has impl_parts/struct.Foo.html '//*[@class="impl has-srclink"]//h3[@class="code-header"]' \ +// @has impl_parts/struct.Foo.html '//*[@class="impl"]//h3[@class="code-header"]' \ // "impl<T> !AnAutoTrait for Foo<T>where T: Sync + Clone," // @has impl_parts/trait.AnAutoTrait.html '//*[@id="implementors-list"]//h3[@class="code-header"]' \ // "impl<T> !AnAutoTrait for Foo<T>where T: Sync + Clone," diff --git a/tests/rustdoc/inline_cross/issue-31948-1.rs b/tests/rustdoc/inline_cross/issue-31948-1.rs index 6e89167b3a4..571eaf6be96 100644 --- a/tests/rustdoc/inline_cross/issue-31948-1.rs +++ b/tests/rustdoc/inline_cross/issue-31948-1.rs @@ -5,8 +5,8 @@ extern crate rustdoc_nonreachable_impls; // @has issue_31948_1/struct.Wobble.html -// @has - '//*[@class="impl has-srclink"]//h3[@class="code-header"]' 'Bark for' -// @has - '//*[@class="impl has-srclink"]//h3[@class="code-header"]' 'Woof for' +// @has - '//*[@class="impl"]//h3[@class="code-header"]' 'Bark for' +// @has - '//*[@class="impl"]//h3[@class="code-header"]' 'Woof for' // @!has - '//*[@class="impl"]//h3[@class="code-header"]' 'Bar for' // @!has - '//*[@class="impl"]//h3[@class="code-header"]' 'Qux for' pub use rustdoc_nonreachable_impls::hidden::Wobble; diff --git a/tests/rustdoc/inline_cross/issue-31948-2.rs b/tests/rustdoc/inline_cross/issue-31948-2.rs index 141e07656a0..7eae21046cc 100644 --- a/tests/rustdoc/inline_cross/issue-31948-2.rs +++ b/tests/rustdoc/inline_cross/issue-31948-2.rs @@ -5,9 +5,9 @@ extern crate rustdoc_nonreachable_impls; // @has issue_31948_2/struct.Wobble.html -// @has - '//*[@class="impl has-srclink"]//h3[@class="code-header"]' 'Qux for' -// @has - '//*[@class="impl has-srclink"]//h3[@class="code-header"]' 'Bark for' -// @has - '//*[@class="impl has-srclink"]//h3[@class="code-header"]' 'Woof for' +// @has - '//*[@class="impl"]//h3[@class="code-header"]' 'Qux for' +// @has - '//*[@class="impl"]//h3[@class="code-header"]' 'Bark for' +// @has - '//*[@class="impl"]//h3[@class="code-header"]' 'Woof for' // @!has - '//*[@class="impl"]//h3[@class="code-header"]' 'Bar for' pub use rustdoc_nonreachable_impls::hidden::Wobble; diff --git a/tests/rustdoc/inline_cross/issue-31948.rs b/tests/rustdoc/inline_cross/issue-31948.rs index 96fc6ca47e7..9c271bf4ad4 100644 --- a/tests/rustdoc/inline_cross/issue-31948.rs +++ b/tests/rustdoc/inline_cross/issue-31948.rs @@ -5,9 +5,9 @@ extern crate rustdoc_nonreachable_impls; // @has issue_31948/struct.Foo.html -// @has - '//*[@class="impl has-srclink"]//h3[@class="code-header"]' 'Bark for' -// @has - '//*[@class="impl has-srclink"]//h3[@class="code-header"]' 'Woof for' -// @!has - '//*[@class="impl has-srclink"]//h3[@class="code-header"]' 'Bar for' +// @has - '//*[@class="impl"]//h3[@class="code-header"]' 'Bark for' +// @has - '//*[@class="impl"]//h3[@class="code-header"]' 'Woof for' +// @!has - '//*[@class="impl"]//h3[@class="code-header"]' 'Bar for' // @!has - '//*[@class="impl"]//h3[@class="code-header"]' 'Qux for' pub use rustdoc_nonreachable_impls::Foo; diff --git a/tests/rustdoc/issue-21474.rs b/tests/rustdoc/issue-21474.rs index 43ce13fd9b1..5de26abace6 100644 --- a/tests/rustdoc/issue-21474.rs +++ b/tests/rustdoc/issue-21474.rs @@ -7,5 +7,5 @@ mod inner { pub trait Blah { } // @count issue_21474/struct.What.html \ -// '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]' 1 +// '//*[@id="trait-implementations-list"]//*[@class="impl"]' 1 pub struct What; diff --git a/tests/rustdoc/issue-33302.rs b/tests/rustdoc/issue-33302.rs index b4c52e2f17a..7af00c77836 100644 --- a/tests/rustdoc/issue-33302.rs +++ b/tests/rustdoc/issue-33302.rs @@ -22,7 +22,7 @@ macro_rules! make { } // @has issue_33302/struct.S.html \ - // '//*[@class="impl has-srclink"]' 'impl T<[i32; 16]> for S' + // '//*[@class="impl"]' 'impl T<[i32; 16]> for S' // @has - '//*[@id="associatedconstant.C"]' 'const C: [i32; 16]' // @has - '//*[@id="associatedconstant.D"]' 'const D: i32' impl T<[i32; ($n * $n)]> for S { @@ -30,7 +30,7 @@ macro_rules! make { } // @has issue_33302/struct.S.html \ - // '//*[@class="impl has-srclink"]' 'impl T<[i32; 16]> for S' + // '//*[@class="impl"]' 'impl T<[i32; 16]> for S' // @has - '//*[@id="associatedconstant.C-1"]' 'const C: (i32,)' // @has - '//*[@id="associatedconstant.D-1"]' 'const D: i32' impl T<(i32,)> for S { @@ -38,7 +38,7 @@ macro_rules! make { } // @has issue_33302/struct.S.html \ - // '//*[@class="impl has-srclink"]' 'impl T<(i32, i32)> for S' + // '//*[@class="impl"]' 'impl T<(i32, i32)> for S' // @has - '//*[@id="associatedconstant.C-2"]' 'const C: (i32, i32)' // @has - '//*[@id="associatedconstant.D-2"]' 'const D: i32' impl T<(i32, i32)> for S { diff --git a/tests/rustdoc/issue-45584.rs b/tests/rustdoc/issue-45584.rs index 86479e6fb2e..8a5f0413826 100644 --- a/tests/rustdoc/issue-45584.rs +++ b/tests/rustdoc/issue-45584.rs @@ -4,12 +4,12 @@ pub trait Bar<T, U> {} // @has 'foo/struct.Foo1.html' pub struct Foo1; -// @count - '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]' 1 -// @has - '//*[@class="impl has-srclink"]' "impl Bar<Foo1, &'static Foo1> for Foo1" +// @count - '//*[@id="trait-implementations-list"]//*[@class="impl"]' 1 +// @has - '//*[@class="impl"]' "impl Bar<Foo1, &'static Foo1> for Foo1" impl Bar<Foo1, &'static Foo1> for Foo1 {} // @has 'foo/struct.Foo2.html' pub struct Foo2; -// @count - '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]' 1 -// @has - '//*[@class="impl has-srclink"]' "impl Bar<&'static Foo2, Foo2> for u8" +// @count - '//*[@id="trait-implementations-list"]//*[@class="impl"]' 1 +// @has - '//*[@class="impl"]' "impl Bar<&'static Foo2, Foo2> for u8" impl Bar<&'static Foo2, Foo2> for u8 {} diff --git a/tests/rustdoc/issue-50159.rs b/tests/rustdoc/issue-50159.rs index 04bc4f304d6..13bedd5dbb0 100644 --- a/tests/rustdoc/issue-50159.rs +++ b/tests/rustdoc/issue-50159.rs @@ -14,7 +14,7 @@ impl<B, C> Signal2 for B where B: Signal<Item = C> { // @has - '//h3[@class="code-header"]' 'impl<B> Send for Switch<B>where <B as Signal>::Item: Send' // @has - '//h3[@class="code-header"]' 'impl<B> Sync for Switch<B>where <B as Signal>::Item: Sync' // @count - '//*[@id="implementations-list"]//*[@class="impl"]' 0 -// @count - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]' 5 +// @count - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]' 5 pub struct Switch<B: Signal> { pub inner: <B as Signal2>::Item2, } diff --git a/tests/rustdoc/issue-51236.rs b/tests/rustdoc/issue-51236.rs index 1c7aa9c7eef..04664805a88 100644 --- a/tests/rustdoc/issue-51236.rs +++ b/tests/rustdoc/issue-51236.rs @@ -7,7 +7,7 @@ pub mod traits { } // @has issue_51236/struct.Owned.html -// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \ +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \ // "impl<T> Send for Owned<T>where <T as Owned<'static>>::Reader: Send" pub struct Owned<T> where T: for<'a> ::traits::Owned<'a> { marker: PhantomData<<T as ::traits::Owned<'static>>::Reader>, diff --git a/tests/rustdoc/issue-53812.rs b/tests/rustdoc/issue-53812.rs index c68ffd52186..dc1eb304c3d 100644 --- a/tests/rustdoc/issue-53812.rs +++ b/tests/rustdoc/issue-53812.rs @@ -12,9 +12,9 @@ macro_rules! array_impls { } // @has issue_53812/trait.MyIterator.html -// @has - '//*[@id="implementors-list"]/*[@class="impl has-srclink"][1]' 'MyStruct<[T; 0]>' -// @has - '//*[@id="implementors-list"]/*[@class="impl has-srclink"][2]' 'MyStruct<[T; 1]>' -// @has - '//*[@id="implementors-list"]/*[@class="impl has-srclink"][3]' 'MyStruct<[T; 2]>' -// @has - '//*[@id="implementors-list"]/*[@class="impl has-srclink"][4]' 'MyStruct<[T; 3]>' -// @has - '//*[@id="implementors-list"]/*[@class="impl has-srclink"][5]' 'MyStruct<[T; 10]>' +// @has - '//*[@id="implementors-list"]/*[@class="impl"][1]' 'MyStruct<[T; 0]>' +// @has - '//*[@id="implementors-list"]/*[@class="impl"][2]' 'MyStruct<[T; 1]>' +// @has - '//*[@id="implementors-list"]/*[@class="impl"][3]' 'MyStruct<[T; 2]>' +// @has - '//*[@id="implementors-list"]/*[@class="impl"][4]' 'MyStruct<[T; 3]>' +// @has - '//*[@id="implementors-list"]/*[@class="impl"][5]' 'MyStruct<[T; 10]>' array_impls! { 10 3 2 1 0 } diff --git a/tests/rustdoc/issue-54705.rs b/tests/rustdoc/issue-54705.rs index 7b7290ab4b7..a886eb0de24 100644 --- a/tests/rustdoc/issue-54705.rs +++ b/tests/rustdoc/issue-54705.rs @@ -1,10 +1,10 @@ pub trait ScopeHandle<'scope> {} // @has issue_54705/struct.ScopeFutureContents.html -// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \ +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \ // "impl<'scope, S> Send for ScopeFutureContents<'scope, S>where S: Sync" // -// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \ +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \ // "impl<'scope, S> Sync for ScopeFutureContents<'scope, S>where S: Sync" pub struct ScopeFutureContents<'scope, S> where S: ScopeHandle<'scope>, diff --git a/tests/rustdoc/issue-55321.rs b/tests/rustdoc/issue-55321.rs index 22a18ef90e1..d3c2070d915 100644 --- a/tests/rustdoc/issue-55321.rs +++ b/tests/rustdoc/issue-55321.rs @@ -1,9 +1,9 @@ #![feature(negative_impls)] // @has issue_55321/struct.A.html -// @has - '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \ +// @has - '//*[@id="trait-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \ // "impl !Send for A" -// @has - '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \ +// @has - '//*[@id="trait-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \ // "impl !Sync for A" pub struct A(); @@ -11,8 +11,8 @@ impl !Send for A {} impl !Sync for A {} // @has issue_55321/struct.B.html -// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \ +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \ // "impl<T> !Send for B<T>" -// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \ +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \ // "impl<T> !Sync for B<T>" pub struct B<T: ?Sized>(A, Box<T>); diff --git a/tests/rustdoc/issue-56822.rs b/tests/rustdoc/issue-56822.rs index b4eef344b5f..c9a74335702 100644 --- a/tests/rustdoc/issue-56822.rs +++ b/tests/rustdoc/issue-56822.rs @@ -17,7 +17,7 @@ impl<'a, T> MyTrait for Inner<'a, T> { } // @has issue_56822/struct.Parser.html -// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \ +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \ // "impl<'a> Send for Parser<'a>" pub struct Parser<'a> { field: <Wrapper<Inner<'a, u8>> as MyTrait>::Output diff --git a/tests/rustdoc/issue-60726.rs b/tests/rustdoc/issue-60726.rs index fbb0f82ae39..e337e4a4f7a 100644 --- a/tests/rustdoc/issue-60726.rs +++ b/tests/rustdoc/issue-60726.rs @@ -26,9 +26,9 @@ where {} // @has issue_60726/struct.IntoIter.html -// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \ +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \ // "impl<T> !Send for IntoIter<T>" -// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \ +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \ // "impl<T> !Sync for IntoIter<T>" pub struct IntoIter<T>{ hello:DynTrait<FooInterface<T>>, diff --git a/tests/rustdoc/issue-76501.rs b/tests/rustdoc/issue-76501.rs index a90e0fea092..5caea0ec992 100644 --- a/tests/rustdoc/issue-76501.rs +++ b/tests/rustdoc/issue-76501.rs @@ -8,7 +8,7 @@ pub const fn bloop() -> i32 { pub struct Struct {} impl Struct { - // @has 'issue_76501/struct.Struct.html' '//*[@class="method has-srclink"]' \ + // @has 'issue_76501/struct.Struct.html' '//*[@class="method"]' \ // 'pub const fn blurp() -> i32' /// A useless function that always returns 1. pub const fn blurp() -> i32 { diff --git a/tests/rustdoc/issue-78673.rs b/tests/rustdoc/issue-78673.rs index 2e4bec2544c..d09141c3204 100644 --- a/tests/rustdoc/issue-78673.rs +++ b/tests/rustdoc/issue-78673.rs @@ -7,8 +7,8 @@ pub trait AnAmazingTrait {} impl<T: Something> AnAmazingTrait for T {} // @has 'issue_78673/struct.MyStruct.html' -// @has - '//*[@class="impl has-srclink"]' 'AnAmazingTrait for MyStruct' -// @!has - '//*[@class="impl has-srclink"]' 'AnAmazingTrait for T' +// @has - '//*[@class="impl"]' 'AnAmazingTrait for MyStruct' +// @!has - '//*[@class="impl"]' 'AnAmazingTrait for T' pub struct MyStruct; impl AnAmazingTrait for MyStruct {} @@ -16,8 +16,8 @@ impl AnAmazingTrait for MyStruct {} // generic structs may have _both_ specific and blanket impls that apply // @has 'issue_78673/struct.AnotherStruct.html' -// @has - '//*[@class="impl has-srclink"]' 'AnAmazingTrait for AnotherStruct<()>' -// @has - '//*[@class="impl has-srclink"]' 'AnAmazingTrait for T' +// @has - '//*[@class="impl"]' 'AnAmazingTrait for AnotherStruct<()>' +// @has - '//*[@class="impl"]' 'AnAmazingTrait for T' pub struct AnotherStruct<T>(T); impl<T: Something> Something for AnotherStruct<T> {} diff --git a/tests/rustdoc/mut-params.rs b/tests/rustdoc/mut-params.rs index 3b862e651c9..431db51d95f 100644 --- a/tests/rustdoc/mut-params.rs +++ b/tests/rustdoc/mut-params.rs @@ -5,7 +5,7 @@ pub struct Foo; -// @count foo/struct.Foo.html '//*[@class="impl-items"]//*[@class="method has-srclink"]' 2 +// @count foo/struct.Foo.html '//*[@class="impl-items"]//*[@class="method"]' 2 // @!has - '//*[@class="impl-items"]//*[@class="method"]' 'mut' impl Foo { pub fn foo(mut self) {} diff --git a/tests/rustdoc/negative-impl.rs b/tests/rustdoc/negative-impl.rs index af19c784d6d..51223af6737 100644 --- a/tests/rustdoc/negative-impl.rs +++ b/tests/rustdoc/negative-impl.rs @@ -5,10 +5,10 @@ pub struct Alpha; // @matches negative_impl/struct.Bravo.html '//pre' "pub struct Bravo<B>" pub struct Bravo<B>(B); -// @matches negative_impl/struct.Alpha.html '//*[@class="impl has-srclink"]//h3[@class="code-header"]' \ +// @matches negative_impl/struct.Alpha.html '//*[@class="impl"]//h3[@class="code-header"]' \ // "impl !Send for Alpha" impl !Send for Alpha {} -// @matches negative_impl/struct.Bravo.html '//*[@class="impl has-srclink"]//h3[@class="code-header"]' "\ +// @matches negative_impl/struct.Bravo.html '//*[@class="impl"]//h3[@class="code-header"]' "\ // impl<B> !Send for Bravo<B>" impl<B> !Send for Bravo<B> {} diff --git a/tests/rustdoc/primitive-reference.rs b/tests/rustdoc/primitive-reference.rs index c3a5eb6d324..10efbefd2b1 100644 --- a/tests/rustdoc/primitive-reference.rs +++ b/tests/rustdoc/primitive-reference.rs @@ -13,7 +13,7 @@ // @has - '//section[@id="main-content"]//div[@class="docblock"]//p' 'this is a test!' // There should be only one implementation listed. -// @count - '//*[@class="impl has-srclink"]' 1 +// @count - '//*[@class="impl"]' 1 // @has - '//*[@id="impl-Foo%3C%26A%3E-for-%26B"]/*[@class="code-header"]' \ // 'impl<A, B> Foo<&A> for &B' #[doc(primitive = "reference")] diff --git a/tests/rustdoc/pub-method.rs b/tests/rustdoc/pub-method.rs index 0dca3f672cd..7115a01d079 100644 --- a/tests/rustdoc/pub-method.rs +++ b/tests/rustdoc/pub-method.rs @@ -10,8 +10,8 @@ pub fn bar() -> usize { } // @has foo/struct.Foo.html -// @has - '//*[@class="method has-srclink"]' 'pub fn new()' -// @has - '//*[@class="method has-srclink"]' 'fn not_pub()' +// @has - '//*[@class="method"]' 'pub fn new()' +// @has - '//*[@class="method"]' 'fn not_pub()' pub struct Foo(usize); impl Foo { diff --git a/tests/rustdoc/synthetic_auto/basic.rs b/tests/rustdoc/synthetic_auto/basic.rs index 7c6a388653c..043ac241488 100644 --- a/tests/rustdoc/synthetic_auto/basic.rs +++ b/tests/rustdoc/synthetic_auto/basic.rs @@ -1,8 +1,8 @@ // @has basic/struct.Foo.html // @has - '//h3[@class="code-header"]' 'impl<T> Send for Foo<T>where T: Send' // @has - '//h3[@class="code-header"]' 'impl<T> Sync for Foo<T>where T: Sync' -// @count - '//*[@id="implementations-list"]//*[@class="impl has-srclink"]' 0 -// @count - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]' 5 +// @count - '//*[@id="implementations-list"]//*[@class="impl"]' 0 +// @count - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]' 5 pub struct Foo<T> { field: T, } diff --git a/tests/rustdoc/synthetic_auto/complex.rs b/tests/rustdoc/synthetic_auto/complex.rs index 43393c21fdd..4c39f0bf1e0 100644 --- a/tests/rustdoc/synthetic_auto/complex.rs +++ b/tests/rustdoc/synthetic_auto/complex.rs @@ -20,7 +20,7 @@ mod foo { } // @has complex/struct.NotOuter.html -// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \ +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \ // "impl<'a, T, K: ?Sized> Send for Outer<'a, T, K>where K: for<'b> Fn((&'b bool, &'a u8)) \ // -> &'b i8, T: MyTrait<'a>, <T as MyTrait<'a>>::MyItem: Copy, 'a: 'static" diff --git a/tests/rustdoc/synthetic_auto/lifetimes.rs b/tests/rustdoc/synthetic_auto/lifetimes.rs index 33170a84435..71265b3078a 100644 --- a/tests/rustdoc/synthetic_auto/lifetimes.rs +++ b/tests/rustdoc/synthetic_auto/lifetimes.rs @@ -9,10 +9,10 @@ where {} // @has lifetimes/struct.Foo.html -// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \ +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \ // "impl<'c, K> Send for Foo<'c, K>where K: for<'b> Fn(&'b bool) -> &'c u8, 'c: 'static" // -// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \ +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \ // "impl<'c, K> Sync for Foo<'c, K>where K: Sync" pub struct Foo<'c, K: 'c> { inner_field: Inner<'c, K>, diff --git a/tests/rustdoc/synthetic_auto/manual.rs b/tests/rustdoc/synthetic_auto/manual.rs index 77c04ad2ad9..7fc8447df3e 100644 --- a/tests/rustdoc/synthetic_auto/manual.rs +++ b/tests/rustdoc/synthetic_auto/manual.rs @@ -1,12 +1,12 @@ // @has manual/struct.Foo.html -// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \ +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \ // 'impl<T> Sync for Foo<T>where T: Sync' // -// @has - '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \ +// @has - '//*[@id="trait-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \ // 'impl<T> Send for Foo<T>' // -// @count - '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]' 1 -// @count - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]' 4 +// @count - '//*[@id="trait-implementations-list"]//*[@class="impl"]' 1 +// @count - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]' 4 pub struct Foo<T> { field: T, } diff --git a/tests/rustdoc/synthetic_auto/negative.rs b/tests/rustdoc/synthetic_auto/negative.rs index 2c2c848a5e0..97da2d57424 100644 --- a/tests/rustdoc/synthetic_auto/negative.rs +++ b/tests/rustdoc/synthetic_auto/negative.rs @@ -3,10 +3,10 @@ pub struct Inner<T: Copy> { } // @has negative/struct.Outer.html -// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \ +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \ // "impl<T> !Send for Outer<T>" // -// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \ +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \ // "impl<T> !Sync for Outer<T>" pub struct Outer<T: Copy> { inner_field: Inner<T>, diff --git a/tests/rustdoc/synthetic_auto/nested.rs b/tests/rustdoc/synthetic_auto/nested.rs index 423bf115ab1..e4aead71bf2 100644 --- a/tests/rustdoc/synthetic_auto/nested.rs +++ b/tests/rustdoc/synthetic_auto/nested.rs @@ -9,10 +9,10 @@ where } // @has nested/struct.Foo.html -// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \ +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \ // 'impl<T> Send for Foo<T>where T: Copy' // -// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \ +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \ // 'impl<T> Sync for Foo<T>where T: Sync' pub struct Foo<T> { inner_field: Inner<T>, diff --git a/tests/rustdoc/synthetic_auto/no-redundancy.rs b/tests/rustdoc/synthetic_auto/no-redundancy.rs index 59f33623322..ea57d7388b8 100644 --- a/tests/rustdoc/synthetic_auto/no-redundancy.rs +++ b/tests/rustdoc/synthetic_auto/no-redundancy.rs @@ -9,7 +9,7 @@ where } // @has no_redundancy/struct.Outer.html -// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \ +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \ // "impl<T> Send for Outer<T>where T: Send + Copy" pub struct Outer<T> { inner_field: Inner<T>, diff --git a/tests/rustdoc/synthetic_auto/project.rs b/tests/rustdoc/synthetic_auto/project.rs index 558ff2add40..7c9412ae962 100644 --- a/tests/rustdoc/synthetic_auto/project.rs +++ b/tests/rustdoc/synthetic_auto/project.rs @@ -23,10 +23,10 @@ where } // @has project/struct.Foo.html -// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \ +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \ // "impl<'c, K> Send for Foo<'c, K>where K: MyTrait<MyItem = bool>, 'c: 'static" // -// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \ +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \ // "impl<'c, K> Sync for Foo<'c, K>where K: MyTrait, <K as MyTrait>::MyItem: OtherTrait, \ // 'c: 'static," pub struct Foo<'c, K: 'c> { diff --git a/tests/rustdoc/synthetic_auto/self-referential.rs b/tests/rustdoc/synthetic_auto/self-referential.rs index c6ae96de776..145a2b7e00c 100644 --- a/tests/rustdoc/synthetic_auto/self-referential.rs +++ b/tests/rustdoc/synthetic_auto/self-referential.rs @@ -23,7 +23,7 @@ impl<T> Pattern for Wrapper<T> { // @has self_referential/struct.WriteAndThen.html -// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \ +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \ // "impl<P1> Send for WriteAndThen<P1>where <P1 as Pattern>::Value: Send" pub struct WriteAndThen<P1>(pub P1::Value,pub <Constrain<P1, Wrapper<P1::Value>> as Pattern>::Value) where P1: Pattern; diff --git a/tests/rustdoc/synthetic_auto/static-region.rs b/tests/rustdoc/synthetic_auto/static-region.rs index 1a76cb919c2..9dc6211ec20 100644 --- a/tests/rustdoc/synthetic_auto/static-region.rs +++ b/tests/rustdoc/synthetic_auto/static-region.rs @@ -3,7 +3,7 @@ pub trait OwnedTrait<'a> { } // @has static_region/struct.Owned.html -// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \ +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \ // "impl<T> Send for Owned<T>where <T as OwnedTrait<'static>>::Reader: Send" pub struct Owned<T> where T: OwnedTrait<'static> { marker: <T as OwnedTrait<'static>>::Reader, diff --git a/tests/rustdoc/typedef.rs b/tests/rustdoc/typedef.rs index d5dfa948489..63e2973c759 100644 --- a/tests/rustdoc/typedef.rs +++ b/tests/rustdoc/typedef.rs @@ -9,8 +9,8 @@ impl MyStruct { } // @has typedef/type.MyAlias.html -// @has - '//*[@class="impl has-srclink"]//h3[@class="code-header"]' 'impl MyAlias' -// @has - '//*[@class="impl has-srclink"]//h3[@class="code-header"]' 'impl MyTrait for MyAlias' +// @has - '//*[@class="impl"]//h3[@class="code-header"]' 'impl MyAlias' +// @has - '//*[@class="impl"]//h3[@class="code-header"]' 'impl MyTrait for MyAlias' // @hasraw - 'Alias docstring' // @has - '//*[@class="sidebar"]//*[@class="location"]' 'MyAlias' // @has - '//*[@class="sidebar"]//a[@href="#implementations"]' 'Methods' diff --git a/tests/rustdoc/where.rs b/tests/rustdoc/where.rs index 3ac0c6872a8..644a0058244 100644 --- a/tests/rustdoc/where.rs +++ b/tests/rustdoc/where.rs @@ -13,7 +13,7 @@ pub fn charlie<C>() where C: MyTrait {} pub struct Delta<D>(D); -// @has foo/struct.Delta.html '//*[@class="impl has-srclink"]//h3[@class="code-header"]' \ +// @has foo/struct.Delta.html '//*[@class="impl"]//h3[@class="code-header"]' \ // "impl<D> Delta<D>where D: MyTrait" impl<D> Delta<D> where D: MyTrait { pub fn delta() {} @@ -43,7 +43,7 @@ pub trait TraitWhere { { todo!() } } -// @has foo/struct.Echo.html '//*[@class="impl has-srclink"]//h3[@class="code-header"]' \ +// @has foo/struct.Echo.html '//*[@class="impl"]//h3[@class="code-header"]' \ // "impl<E> MyTrait for Echo<E>where E: MyTrait" // @has foo/trait.MyTrait.html '//*[@id="implementors-list"]//h3[@class="code-header"]' \ // "impl<E> MyTrait for Echo<E>where E: MyTrait" @@ -51,7 +51,7 @@ impl<E> MyTrait for Echo<E>where E: MyTrait {} pub enum Foxtrot<F> { Foxtrot1(F) } -// @has foo/enum.Foxtrot.html '//*[@class="impl has-srclink"]//h3[@class="code-header"]' \ +// @has foo/enum.Foxtrot.html '//*[@class="impl"]//h3[@class="code-header"]' \ // "impl<F> MyTrait for Foxtrot<F>where F: MyTrait" // @has foo/trait.MyTrait.html '//*[@id="implementors-list"]//h3[@class="code-header"]' \ // "impl<F> MyTrait for Foxtrot<F>where F: MyTrait" diff --git a/tests/ui/derives/deriving-with-repr-packed-2.rs b/tests/ui/derives/deriving-with-repr-packed-2.rs new file mode 100644 index 00000000000..cbd7432fce4 --- /dev/null +++ b/tests/ui/derives/deriving-with-repr-packed-2.rs @@ -0,0 +1,22 @@ +#![deny(unaligned_references)] + +// Check that deriving certain builtin traits on certain packed structs cause +// errors. To avoid potentially misaligned references, field copies must be +// used, which involves adding `T: Copy` bounds. + +#[derive(Copy, Clone, Default, PartialEq, Eq)] +#[repr(packed)] +pub struct Foo<T>(T, T, T); + +struct NonCopy; + +fn main() { + // This one is fine because `u32` impls `Copy`. + let x: Foo<u32> = Foo(1, 2, 3); + _ = x.clone(); + + // This one is an error because `NonCopy` doesn't impl `Copy`. + let x: Foo<NonCopy> = Foo(NonCopy, NonCopy, NonCopy); + _ = x.clone(); + //~^ ERROR the method `clone` exists for struct `Foo<NonCopy>`, but its trait bounds were not satisfied +} diff --git a/tests/ui/derives/deriving-with-repr-packed-2.stderr b/tests/ui/derives/deriving-with-repr-packed-2.stderr new file mode 100644 index 00000000000..83540739ee3 --- /dev/null +++ b/tests/ui/derives/deriving-with-repr-packed-2.stderr @@ -0,0 +1,33 @@ +error[E0599]: the method `clone` exists for struct `Foo<NonCopy>`, but its trait bounds were not satisfied + --> $DIR/deriving-with-repr-packed-2.rs:20:11 + | +LL | pub struct Foo<T>(T, T, T); + | ----------------- + | | + | method `clone` not found for this struct + | doesn't satisfy `Foo<NonCopy>: Clone` +LL | +LL | struct NonCopy; + | -------------- + | | + | doesn't satisfy `NonCopy: Clone` + | doesn't satisfy `NonCopy: Copy` +... +LL | _ = x.clone(); + | ^^^^^ method cannot be called on `Foo<NonCopy>` due to unsatisfied trait bounds + | +note: the following trait bounds were not satisfied: + `NonCopy: Clone` + `NonCopy: Copy` + --> $DIR/deriving-with-repr-packed-2.rs:7:16 + | +LL | #[derive(Copy, Clone, Default, PartialEq, Eq)] + | ^^^^^ unsatisfied trait bound introduced in this `derive` macro +help: consider annotating `NonCopy` with `#[derive(Clone, Copy)]` + | +LL | #[derive(Clone, Copy)] + | + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0599`. diff --git a/tests/ui/derives/deriving-with-repr-packed.rs b/tests/ui/derives/deriving-with-repr-packed.rs index 3884e397764..eddf41f5553 100644 --- a/tests/ui/derives/deriving-with-repr-packed.rs +++ b/tests/ui/derives/deriving-with-repr-packed.rs @@ -1,45 +1,38 @@ #![deny(unaligned_references)] // Check that deriving certain builtin traits on certain packed structs cause -// errors. This happens when the derived trait would need to use a potentially -// misaligned reference. But there are two cases that are allowed: -// - If all the fields within the struct meet the required alignment: 1 for -// `repr(packed)`, or `N` for `repr(packed(N))`. -// - If `Default` is the only trait derived, because it doesn't involve any -// references. +// errors. To avoid potentially misaligned references, field copies must be +// used, which involves adding `T: Copy` bounds. #[derive(Copy, Clone, Default, PartialEq, Eq)] -//~^ ERROR `Clone` can't be derived on this `#[repr(packed)]` struct with type or const parameters -//~| hard error -//~^^^ ERROR `PartialEq` can't be derived on this `#[repr(packed)]` struct with type or const parameters -//~| hard error #[repr(packed)] pub struct Foo<T>(T, T, T); +// This one is fine because the fields all impl `Copy`. #[derive(Default, Hash)] -//~^ ERROR `Hash` can't be derived on this `#[repr(packed)]` struct that does not derive `Copy` -//~| hard error #[repr(packed)] pub struct Bar(u32, u32, u32); -// This one is fine because the field alignment is 1. -#[derive(Default, Hash)] -#[repr(packed)] -pub struct Bar2(u8, i8, bool); - -// This one is fine because the field alignment is 2, matching `packed(2)`. -#[derive(Default, Hash)] -#[repr(packed(2))] -pub struct Bar3(u16, i16, bool); - // This one is fine because it's not packed. #[derive(Debug, Default)] struct Y(usize); +// This one has an error because `Y` doesn't impl `Copy`. +// Note: there is room for improvement in the error message. #[derive(Debug, Default)] -//~^ ERROR `Debug` can't be derived on this `#[repr(packed)]` struct that does not derive `Copy` -//~| hard error #[repr(packed)] struct X(Y); +//~^ ERROR cannot move out of `self` which is behind a shared reference + +// This is currently allowed, but will be phased out at some point. From +// `zerovec` within icu4x-0.9.0. +#[derive(Debug)] +#[repr(packed)] +struct FlexZeroSlice { + width: u8, + data: [u8], + //~^ WARNING byte slice in a packed struct that derives a built-in trait + //~^^ this was previously accepted +} fn main() {} diff --git a/tests/ui/derives/deriving-with-repr-packed.stderr b/tests/ui/derives/deriving-with-repr-packed.stderr index 0ad800c3981..2cb2a696d97 100644 --- a/tests/ui/derives/deriving-with-repr-packed.stderr +++ b/tests/ui/derives/deriving-with-repr-packed.stderr @@ -1,111 +1,45 @@ -error: `Clone` can't be derived on this `#[repr(packed)]` struct with type or const parameters - --> $DIR/deriving-with-repr-packed.rs:11:16 +warning: byte slice in a packed struct that derives a built-in trait + --> $DIR/deriving-with-repr-packed.rs:33:5 | -LL | #[derive(Copy, Clone, Default, PartialEq, Eq)] - | ^^^^^ +LL | #[derive(Debug)] + | ----- in this derive macro expansion +... +LL | data: [u8], + | ^^^^^^^^^^ | = 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 #82523 <https://github.com/rust-lang/rust/issues/82523> -note: the lint level is defined here - --> $DIR/deriving-with-repr-packed.rs:1:9 - | -LL | #![deny(unaligned_references)] - | ^^^^^^^^^^^^^^^^^^^^ - = note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info) - -error: `PartialEq` can't be derived on this `#[repr(packed)]` struct with type or const parameters - --> $DIR/deriving-with-repr-packed.rs:11:32 - | -LL | #[derive(Copy, Clone, Default, PartialEq, Eq)] - | ^^^^^^^^^ - | - = 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 #82523 <https://github.com/rust-lang/rust/issues/82523> - = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info) - -error: `Hash` can't be derived on this `#[repr(packed)]` struct that does not derive `Copy` - --> $DIR/deriving-with-repr-packed.rs:19:19 - | -LL | #[derive(Default, Hash)] - | ^^^^ - | - = 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 #82523 <https://github.com/rust-lang/rust/issues/82523> - = note: this error originates in the derive macro `Hash` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: for more information, see issue #107457 <https://github.com/rust-lang/rust/issues/107457> + = help: consider implementing the trait by hand, or remove the `packed` attribute + = note: `#[warn(byte_slice_in_packed_struct_with_derive)]` on by default + = note: this warning originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info) -error: `Debug` can't be derived on this `#[repr(packed)]` struct that does not derive `Copy` - --> $DIR/deriving-with-repr-packed.rs:39:10 +error[E0507]: cannot move out of `self` which is behind a shared reference + --> $DIR/deriving-with-repr-packed.rs:24:10 | LL | #[derive(Debug, Default)] - | ^^^^^ + | ----- in this derive macro expansion +LL | #[repr(packed)] +LL | struct X(Y); + | ^ move occurs because `self.0` has type `Y`, which does not implement the `Copy` trait | - = 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 #82523 <https://github.com/rust-lang/rust/issues/82523> = note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 4 previous errors +error: aborting due to previous error; 1 warning emitted +For more information about this error, try `rustc --explain E0507`. Future incompatibility report: Future breakage diagnostic: -error: `Clone` can't be derived on this `#[repr(packed)]` struct with type or const parameters - --> $DIR/deriving-with-repr-packed.rs:11:16 - | -LL | #[derive(Copy, Clone, Default, PartialEq, Eq)] - | ^^^^^ - | - = 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 #82523 <https://github.com/rust-lang/rust/issues/82523> -note: the lint level is defined here - --> $DIR/deriving-with-repr-packed.rs:1:9 - | -LL | #![deny(unaligned_references)] - | ^^^^^^^^^^^^^^^^^^^^ - = note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info) - -Future breakage diagnostic: -error: `PartialEq` can't be derived on this `#[repr(packed)]` struct with type or const parameters - --> $DIR/deriving-with-repr-packed.rs:11:32 - | -LL | #[derive(Copy, Clone, Default, PartialEq, Eq)] - | ^^^^^^^^^ - | - = 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 #82523 <https://github.com/rust-lang/rust/issues/82523> -note: the lint level is defined here - --> $DIR/deriving-with-repr-packed.rs:1:9 - | -LL | #![deny(unaligned_references)] - | ^^^^^^^^^^^^^^^^^^^^ - = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info) - -Future breakage diagnostic: -error: `Hash` can't be derived on this `#[repr(packed)]` struct that does not derive `Copy` - --> $DIR/deriving-with-repr-packed.rs:19:19 - | -LL | #[derive(Default, Hash)] - | ^^^^ +warning: byte slice in a packed struct that derives a built-in trait + --> $DIR/deriving-with-repr-packed.rs:33:5 | - = 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 #82523 <https://github.com/rust-lang/rust/issues/82523> -note: the lint level is defined here - --> $DIR/deriving-with-repr-packed.rs:1:9 - | -LL | #![deny(unaligned_references)] - | ^^^^^^^^^^^^^^^^^^^^ - = note: this error originates in the derive macro `Hash` (in Nightly builds, run with -Z macro-backtrace for more info) - -Future breakage diagnostic: -error: `Debug` can't be derived on this `#[repr(packed)]` struct that does not derive `Copy` - --> $DIR/deriving-with-repr-packed.rs:39:10 - | -LL | #[derive(Debug, Default)] - | ^^^^^ +LL | #[derive(Debug)] + | ----- in this derive macro expansion +... +LL | data: [u8], + | ^^^^^^^^^^ | = 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 #82523 <https://github.com/rust-lang/rust/issues/82523> -note: the lint level is defined here - --> $DIR/deriving-with-repr-packed.rs:1:9 - | -LL | #![deny(unaligned_references)] - | ^^^^^^^^^^^^^^^^^^^^ - = note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: for more information, see issue #107457 <https://github.com/rust-lang/rust/issues/107457> + = help: consider implementing the trait by hand, or remove the `packed` attribute + = note: `#[warn(byte_slice_in_packed_struct_with_derive)]` on by default + = note: this warning originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/deriving/deriving-all-codegen.rs b/tests/ui/deriving/deriving-all-codegen.rs index ba7809413bd..51f9708d3cd 100644 --- a/tests/ui/deriving/deriving-all-codegen.rs +++ b/tests/ui/deriving/deriving-all-codegen.rs @@ -21,36 +21,88 @@ #[derive(Clone, Copy, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)] struct Empty; -// A basic struct. +// A basic struct. Note: because this derives `Copy`, it gets the simple +// `clone` implemention that just does `*self`. #[derive(Clone, Copy, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)] struct Point { x: u32, y: u32, } -// A large struct. -#[derive(Clone, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)] +// A basic packed struct. Note: because this derives `Copy`, it gets the simple +// `clone` implemention that just does `*self`. +#[derive(Clone, Copy, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[repr(packed)] +struct PackedPoint { + x: u32, + y: u32, +} + +// A large struct. Note: because this derives `Copy`, it gets the simple +// `clone` implemention that just does `*self`. +#[derive(Clone, Copy, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)] struct Big { b1: u32, b2: u32, b3: u32, b4: u32, b5: u32, b6: u32, b7: u32, b8: u32, } +// A struct that doesn't impl `Copy`, which means it gets the non-simple +// `clone` implemention that clones the fields individually. +#[derive(Clone)] +struct NonCopy(u32); + +// A packed struct that doesn't impl `Copy`, which means it gets the non-simple +// `clone` implemention that clones the fields individually. +#[derive(Clone)] +#[repr(packed)] +struct PackedNonCopy(u32); + +// A struct that impls `Copy` manually, which means it gets the non-simple +// `clone` implemention that clones the fields individually. +#[derive(Clone)] +struct ManualCopy(u32); +impl Copy for ManualCopy {} + +// A packed struct that impls `Copy` manually, which means it gets the +// non-simple `clone` implemention that clones the fields individually. +#[derive(Clone)] +#[repr(packed)] +struct PackedManualCopy(u32); +impl Copy for PackedManualCopy {} + // A struct with an unsized field. Some derives are not usable in this case. #[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] struct Unsized([u32]); -// A packed tuple struct that impls `Copy`. -#[derive(Clone, Copy, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)] +// A packed struct with an unsized `[u8]` field. This is currently allowed, but +// causes a warning and will be phased out at some point. +#[derive(Debug, Hash)] #[repr(packed)] -struct PackedCopy(u32); +struct PackedUnsizedU8([u8]); +//~^ WARNING byte slice in a packed struct that derives a built-in trait +//~^^ WARNING byte slice in a packed struct that derives a built-in trait +//~^^^ this was previously accepted +//~^^^^ this was previously accepted -// A packed tuple struct that does not impl `Copy`. Note that the alignment of -// the field must be 1 for this code to be valid. Otherwise it triggers an -// error "`#[derive]` can't be used on a `#[repr(packed)]` struct that does not -// derive Copy (error E0133)" at MIR building time. This is a weird case and -// it's possible that this struct is not supposed to work, but for now it does. -#[derive(Clone, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)] +trait Trait { + type A; +} + +// A generic struct involving an associated type. +#[derive(Clone, Copy, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)] +struct Generic<T: Trait, U> { + t: T, + ta: T::A, + u: U, +} + +// A packed, generic tuple struct involving an associated type. Because it is +// packed, a `T: Copy` bound is added to all impls (and where clauses within +// them) except for `Default`. This is because we must access fields using +// copies (e.g. `&{self.0}`), instead of using direct references (e.g. +// `&self.0`) which may be misaligned in a packed struct. +#[derive(Clone, Copy, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)] #[repr(packed)] -struct PackedNonCopy(u8); +struct PackedGeneric<T: Trait, U>(T, T::A, U); // An empty enum. #[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] @@ -97,6 +149,13 @@ enum Fielded { Z(Option<i32>), } +// A generic enum. Note that `Default` cannot be derived for this enum. +#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] +enum EnumGeneric<T, U> { + One(T), + Two(U), +} + // A union. Most builtin traits are not derivable for unions. #[derive(Clone, Copy)] pub union Union { diff --git a/tests/ui/deriving/deriving-all-codegen.stderr b/tests/ui/deriving/deriving-all-codegen.stderr new file mode 100644 index 00000000000..503f0cae73b --- /dev/null +++ b/tests/ui/deriving/deriving-all-codegen.stderr @@ -0,0 +1,63 @@ +warning: byte slice in a packed struct that derives a built-in trait + --> $DIR/deriving-all-codegen.rs:80:24 + | +LL | #[derive(Debug, Hash)] + | ----- in this derive macro expansion +LL | #[repr(packed)] +LL | struct PackedUnsizedU8([u8]); + | ^^^^ + | + = 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 #107457 <https://github.com/rust-lang/rust/issues/107457> + = help: consider implementing the trait by hand, or remove the `packed` attribute + = note: `#[warn(byte_slice_in_packed_struct_with_derive)]` on by default + = note: this warning originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info) + +warning: byte slice in a packed struct that derives a built-in trait + --> $DIR/deriving-all-codegen.rs:80:24 + | +LL | #[derive(Debug, Hash)] + | ---- in this derive macro expansion +LL | #[repr(packed)] +LL | struct PackedUnsizedU8([u8]); + | ^^^^ + | + = 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 #107457 <https://github.com/rust-lang/rust/issues/107457> + = help: consider implementing the trait by hand, or remove the `packed` attribute + = note: this warning originates in the derive macro `Hash` (in Nightly builds, run with -Z macro-backtrace for more info) + +warning: 2 warnings emitted + +Future incompatibility report: Future breakage diagnostic: +warning: byte slice in a packed struct that derives a built-in trait + --> $DIR/deriving-all-codegen.rs:80:24 + | +LL | #[derive(Debug, Hash)] + | ----- in this derive macro expansion +LL | #[repr(packed)] +LL | struct PackedUnsizedU8([u8]); + | ^^^^ + | + = 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 #107457 <https://github.com/rust-lang/rust/issues/107457> + = help: consider implementing the trait by hand, or remove the `packed` attribute + = note: `#[warn(byte_slice_in_packed_struct_with_derive)]` on by default + = note: this warning originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info) + +Future breakage diagnostic: +warning: byte slice in a packed struct that derives a built-in trait + --> $DIR/deriving-all-codegen.rs:80:24 + | +LL | #[derive(Debug, Hash)] + | ---- in this derive macro expansion +LL | #[repr(packed)] +LL | struct PackedUnsizedU8([u8]); + | ^^^^ + | + = 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 #107457 <https://github.com/rust-lang/rust/issues/107457> + = help: consider implementing the trait by hand, or remove the `packed` attribute + = note: `#[warn(byte_slice_in_packed_struct_with_derive)]` on by default + = note: this warning originates in the derive macro `Hash` (in Nightly builds, run with -Z macro-backtrace for more info) + diff --git a/tests/ui/deriving/deriving-all-codegen.stdout b/tests/ui/deriving/deriving-all-codegen.stdout index 2a93a05c627..b4874cef134 100644 --- a/tests/ui/deriving/deriving-all-codegen.stdout +++ b/tests/ui/deriving/deriving-all-codegen.stdout @@ -78,7 +78,8 @@ impl ::core::cmp::Ord for Empty { } } -// A basic struct. +// A basic struct. Note: because this derives `Copy`, it gets the simple +// `clone` implemention that just does `*self`. struct Point { x: u32, y: u32, @@ -161,7 +162,95 @@ impl ::core::cmp::Ord for Point { } } -// A large struct. +// A basic packed struct. Note: because this derives `Copy`, it gets the simple +// `clone` implemention that just does `*self`. +#[repr(packed)] +struct PackedPoint { + x: u32, + y: u32, +} +#[automatically_derived] +impl ::core::clone::Clone for PackedPoint { + #[inline] + fn clone(&self) -> PackedPoint { + let _: ::core::clone::AssertParamIsClone<u32>; + *self + } +} +#[automatically_derived] +impl ::core::marker::Copy for PackedPoint { } +#[automatically_derived] +impl ::core::fmt::Debug for PackedPoint { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + ::core::fmt::Formatter::debug_struct_field2_finish(f, "PackedPoint", + "x", &&{ self.x }, "y", &&{ self.y }) + } +} +#[automatically_derived] +impl ::core::default::Default for PackedPoint { + #[inline] + fn default() -> PackedPoint { + PackedPoint { + x: ::core::default::Default::default(), + y: ::core::default::Default::default(), + } + } +} +#[automatically_derived] +impl ::core::hash::Hash for PackedPoint { + fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () { + ::core::hash::Hash::hash(&{ self.x }, state); + ::core::hash::Hash::hash(&{ self.y }, state) + } +} +#[automatically_derived] +impl ::core::marker::StructuralPartialEq for PackedPoint { } +#[automatically_derived] +impl ::core::cmp::PartialEq for PackedPoint { + #[inline] + fn eq(&self, other: &PackedPoint) -> bool { + { self.x } == { other.x } && { self.y } == { other.y } + } +} +#[automatically_derived] +impl ::core::marker::StructuralEq for PackedPoint { } +#[automatically_derived] +impl ::core::cmp::Eq for PackedPoint { + #[inline] + #[doc(hidden)] + #[no_coverage] + fn assert_receiver_is_total_eq(&self) -> () { + let _: ::core::cmp::AssertParamIsEq<u32>; + } +} +#[automatically_derived] +impl ::core::cmp::PartialOrd for PackedPoint { + #[inline] + fn partial_cmp(&self, other: &PackedPoint) + -> ::core::option::Option<::core::cmp::Ordering> { + match ::core::cmp::PartialOrd::partial_cmp(&{ self.x }, &{ other.x }) + { + ::core::option::Option::Some(::core::cmp::Ordering::Equal) => + ::core::cmp::PartialOrd::partial_cmp(&{ self.y }, + &{ other.y }), + cmp => cmp, + } + } +} +#[automatically_derived] +impl ::core::cmp::Ord for PackedPoint { + #[inline] + fn cmp(&self, other: &PackedPoint) -> ::core::cmp::Ordering { + match ::core::cmp::Ord::cmp(&{ self.x }, &{ other.x }) { + ::core::cmp::Ordering::Equal => + ::core::cmp::Ord::cmp(&{ self.y }, &{ other.y }), + cmp => cmp, + } + } +} + +// A large struct. Note: because this derives `Copy`, it gets the simple +// `clone` implemention that just does `*self`. struct Big { b1: u32, b2: u32, @@ -176,19 +265,13 @@ struct Big { impl ::core::clone::Clone for Big { #[inline] fn clone(&self) -> Big { - Big { - b1: ::core::clone::Clone::clone(&self.b1), - b2: ::core::clone::Clone::clone(&self.b2), - b3: ::core::clone::Clone::clone(&self.b3), - b4: ::core::clone::Clone::clone(&self.b4), - b5: ::core::clone::Clone::clone(&self.b5), - b6: ::core::clone::Clone::clone(&self.b6), - b7: ::core::clone::Clone::clone(&self.b7), - b8: ::core::clone::Clone::clone(&self.b8), - } + let _: ::core::clone::AssertParamIsClone<u32>; + *self } } #[automatically_derived] +impl ::core::marker::Copy for Big { } +#[automatically_derived] impl ::core::fmt::Debug for Big { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { let names: &'static _ = @@ -336,6 +419,54 @@ impl ::core::cmp::Ord for Big { } } +// A struct that doesn't impl `Copy`, which means it gets the non-simple +// `clone` implemention that clones the fields individually. +struct NonCopy(u32); +#[automatically_derived] +impl ::core::clone::Clone for NonCopy { + #[inline] + fn clone(&self) -> NonCopy { + NonCopy(::core::clone::Clone::clone(&self.0)) + } +} + +// A packed struct that doesn't impl `Copy`, which means it gets the non-simple +// `clone` implemention that clones the fields individually. +#[repr(packed)] +struct PackedNonCopy(u32); +#[automatically_derived] +impl ::core::clone::Clone for PackedNonCopy { + #[inline] + fn clone(&self) -> PackedNonCopy { + PackedNonCopy(::core::clone::Clone::clone(&{ self.0 })) + } +} + +// A struct that impls `Copy` manually, which means it gets the non-simple +// `clone` implemention that clones the fields individually. +struct ManualCopy(u32); +#[automatically_derived] +impl ::core::clone::Clone for ManualCopy { + #[inline] + fn clone(&self) -> ManualCopy { + ManualCopy(::core::clone::Clone::clone(&self.0)) + } +} +impl Copy for ManualCopy {} + +// A packed struct that impls `Copy` manually, which means it gets the +// non-simple `clone` implemention that clones the fields individually. +#[repr(packed)] +struct PackedManualCopy(u32); +#[automatically_derived] +impl ::core::clone::Clone for PackedManualCopy { + #[inline] + fn clone(&self) -> PackedManualCopy { + PackedManualCopy(::core::clone::Clone::clone(&{ self.0 })) + } +} +impl Copy for PackedManualCopy {} + // A struct with an unsized field. Some derives are not usable in this case. struct Unsized([u32]); #[automatically_derived] @@ -385,138 +516,265 @@ impl ::core::cmp::Ord for Unsized { } } -// A packed tuple struct that impls `Copy`. +// A packed struct with an unsized `[u8]` field. This is currently allowed, but +// causes a warning and will be phased out at some point. #[repr(packed)] -struct PackedCopy(u32); +struct PackedUnsizedU8([u8]); +#[automatically_derived] +impl ::core::fmt::Debug for PackedUnsizedU8 { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + ::core::fmt::Formatter::debug_tuple_field1_finish(f, + "PackedUnsizedU8", &&self.0) + } +} #[automatically_derived] -impl ::core::clone::Clone for PackedCopy { +impl ::core::hash::Hash for PackedUnsizedU8 { + fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () { + ::core::hash::Hash::hash(&self.0, state) + } +} + +trait Trait { + type A; +} + +// A generic struct involving an associated type. +struct Generic<T: Trait, U> { + t: T, + ta: T::A, + u: U, +} +#[automatically_derived] +impl<T: ::core::clone::Clone + Trait, U: ::core::clone::Clone> + ::core::clone::Clone for Generic<T, U> where T::A: ::core::clone::Clone { #[inline] - fn clone(&self) -> PackedCopy { - let _: ::core::clone::AssertParamIsClone<u32>; - *self + fn clone(&self) -> Generic<T, U> { + Generic { + t: ::core::clone::Clone::clone(&self.t), + ta: ::core::clone::Clone::clone(&self.ta), + u: ::core::clone::Clone::clone(&self.u), + } } } #[automatically_derived] -impl ::core::marker::Copy for PackedCopy { } +impl<T: ::core::marker::Copy + Trait, U: ::core::marker::Copy> + ::core::marker::Copy for Generic<T, U> where T::A: ::core::marker::Copy { +} #[automatically_derived] -impl ::core::fmt::Debug for PackedCopy { +impl<T: ::core::fmt::Debug + Trait, U: ::core::fmt::Debug> ::core::fmt::Debug + for Generic<T, U> where T::A: ::core::fmt::Debug { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { - ::core::fmt::Formatter::debug_tuple_field1_finish(f, "PackedCopy", - &&{ self.0 }) + ::core::fmt::Formatter::debug_struct_field3_finish(f, "Generic", "t", + &&self.t, "ta", &&self.ta, "u", &&self.u) } } #[automatically_derived] -impl ::core::default::Default for PackedCopy { +impl<T: ::core::default::Default + Trait, U: ::core::default::Default> + ::core::default::Default for Generic<T, U> where + T::A: ::core::default::Default { #[inline] - fn default() -> PackedCopy { - PackedCopy(::core::default::Default::default()) + fn default() -> Generic<T, U> { + Generic { + t: ::core::default::Default::default(), + ta: ::core::default::Default::default(), + u: ::core::default::Default::default(), + } } } #[automatically_derived] -impl ::core::hash::Hash for PackedCopy { +impl<T: ::core::hash::Hash + Trait, U: ::core::hash::Hash> ::core::hash::Hash + for Generic<T, U> where T::A: ::core::hash::Hash { fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () { - ::core::hash::Hash::hash(&{ self.0 }, state) + ::core::hash::Hash::hash(&self.t, state); + ::core::hash::Hash::hash(&self.ta, state); + ::core::hash::Hash::hash(&self.u, state) } } #[automatically_derived] -impl ::core::marker::StructuralPartialEq for PackedCopy { } +impl<T: Trait, U> ::core::marker::StructuralPartialEq for Generic<T, U> { } #[automatically_derived] -impl ::core::cmp::PartialEq for PackedCopy { +impl<T: ::core::cmp::PartialEq + Trait, U: ::core::cmp::PartialEq> + ::core::cmp::PartialEq for Generic<T, U> where + T::A: ::core::cmp::PartialEq { #[inline] - fn eq(&self, other: &PackedCopy) -> bool { { self.0 } == { other.0 } } + fn eq(&self, other: &Generic<T, U>) -> bool { + self.t == other.t && self.ta == other.ta && self.u == other.u + } } #[automatically_derived] -impl ::core::marker::StructuralEq for PackedCopy { } +impl<T: Trait, U> ::core::marker::StructuralEq for Generic<T, U> { } #[automatically_derived] -impl ::core::cmp::Eq for PackedCopy { +impl<T: ::core::cmp::Eq + Trait, U: ::core::cmp::Eq> ::core::cmp::Eq for + Generic<T, U> where T::A: ::core::cmp::Eq { #[inline] #[doc(hidden)] #[no_coverage] fn assert_receiver_is_total_eq(&self) -> () { - let _: ::core::cmp::AssertParamIsEq<u32>; + let _: ::core::cmp::AssertParamIsEq<T>; + let _: ::core::cmp::AssertParamIsEq<T::A>; + let _: ::core::cmp::AssertParamIsEq<U>; } } #[automatically_derived] -impl ::core::cmp::PartialOrd for PackedCopy { +impl<T: ::core::cmp::PartialOrd + Trait, U: ::core::cmp::PartialOrd> + ::core::cmp::PartialOrd for Generic<T, U> where + T::A: ::core::cmp::PartialOrd { #[inline] - fn partial_cmp(&self, other: &PackedCopy) + fn partial_cmp(&self, other: &Generic<T, U>) -> ::core::option::Option<::core::cmp::Ordering> { - ::core::cmp::PartialOrd::partial_cmp(&{ self.0 }, &{ other.0 }) + match ::core::cmp::PartialOrd::partial_cmp(&self.t, &other.t) { + ::core::option::Option::Some(::core::cmp::Ordering::Equal) => + match ::core::cmp::PartialOrd::partial_cmp(&self.ta, + &other.ta) { + ::core::option::Option::Some(::core::cmp::Ordering::Equal) + => ::core::cmp::PartialOrd::partial_cmp(&self.u, &other.u), + cmp => cmp, + }, + cmp => cmp, + } } } #[automatically_derived] -impl ::core::cmp::Ord for PackedCopy { +impl<T: ::core::cmp::Ord + Trait, U: ::core::cmp::Ord> ::core::cmp::Ord for + Generic<T, U> where T::A: ::core::cmp::Ord { #[inline] - fn cmp(&self, other: &PackedCopy) -> ::core::cmp::Ordering { - ::core::cmp::Ord::cmp(&{ self.0 }, &{ other.0 }) + fn cmp(&self, other: &Generic<T, U>) -> ::core::cmp::Ordering { + match ::core::cmp::Ord::cmp(&self.t, &other.t) { + ::core::cmp::Ordering::Equal => + match ::core::cmp::Ord::cmp(&self.ta, &other.ta) { + ::core::cmp::Ordering::Equal => + ::core::cmp::Ord::cmp(&self.u, &other.u), + cmp => cmp, + }, + cmp => cmp, + } } } -// A packed tuple struct that does not impl `Copy`. Note that the alignment of -// the field must be 1 for this code to be valid. Otherwise it triggers an -// error "`#[derive]` can't be used on a `#[repr(packed)]` struct that does not -// derive Copy (error E0133)" at MIR building time. This is a weird case and -// it's possible that this struct is not supposed to work, but for now it does. +// A packed, generic tuple struct involving an associated type. Because it is +// packed, a `T: Copy` bound is added to all impls (and where clauses within +// them) except for `Default`. This is because we must access fields using +// copies (e.g. `&{self.0}`), instead of using direct references (e.g. +// `&self.0`) which may be misaligned in a packed struct. #[repr(packed)] -struct PackedNonCopy(u8); +struct PackedGeneric<T: Trait, U>(T, T::A, U); #[automatically_derived] -impl ::core::clone::Clone for PackedNonCopy { +impl<T: ::core::clone::Clone + ::core::marker::Copy + Trait, + U: ::core::clone::Clone + ::core::marker::Copy> ::core::clone::Clone for + PackedGeneric<T, U> where T::A: ::core::clone::Clone + + ::core::marker::Copy { #[inline] - fn clone(&self) -> PackedNonCopy { - PackedNonCopy(::core::clone::Clone::clone(&self.0)) + fn clone(&self) -> PackedGeneric<T, U> { + PackedGeneric(::core::clone::Clone::clone(&{ self.0 }), + ::core::clone::Clone::clone(&{ self.1 }), + ::core::clone::Clone::clone(&{ self.2 })) } } #[automatically_derived] -impl ::core::fmt::Debug for PackedNonCopy { +impl<T: ::core::marker::Copy + Trait, U: ::core::marker::Copy> + ::core::marker::Copy for PackedGeneric<T, U> where + T::A: ::core::marker::Copy { +} +#[automatically_derived] +impl<T: ::core::fmt::Debug + ::core::marker::Copy + Trait, + U: ::core::fmt::Debug + ::core::marker::Copy> ::core::fmt::Debug for + PackedGeneric<T, U> where T::A: ::core::fmt::Debug + ::core::marker::Copy + { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { - ::core::fmt::Formatter::debug_tuple_field1_finish(f, "PackedNonCopy", - &&self.0) + ::core::fmt::Formatter::debug_tuple_field3_finish(f, "PackedGeneric", + &&{ self.0 }, &&{ self.1 }, &&{ self.2 }) } } #[automatically_derived] -impl ::core::default::Default for PackedNonCopy { +impl<T: ::core::default::Default + Trait, U: ::core::default::Default> + ::core::default::Default for PackedGeneric<T, U> where + T::A: ::core::default::Default { #[inline] - fn default() -> PackedNonCopy { - PackedNonCopy(::core::default::Default::default()) + fn default() -> PackedGeneric<T, U> { + PackedGeneric(::core::default::Default::default(), + ::core::default::Default::default(), + ::core::default::Default::default()) } } #[automatically_derived] -impl ::core::hash::Hash for PackedNonCopy { +impl<T: ::core::hash::Hash + ::core::marker::Copy + Trait, + U: ::core::hash::Hash + ::core::marker::Copy> ::core::hash::Hash for + PackedGeneric<T, U> where T::A: ::core::hash::Hash + ::core::marker::Copy + { fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () { - ::core::hash::Hash::hash(&self.0, state) + ::core::hash::Hash::hash(&{ self.0 }, state); + ::core::hash::Hash::hash(&{ self.1 }, state); + ::core::hash::Hash::hash(&{ self.2 }, state) } } #[automatically_derived] -impl ::core::marker::StructuralPartialEq for PackedNonCopy { } +impl<T: Trait, U> ::core::marker::StructuralPartialEq for PackedGeneric<T, U> + { +} #[automatically_derived] -impl ::core::cmp::PartialEq for PackedNonCopy { +impl<T: ::core::cmp::PartialEq + ::core::marker::Copy + Trait, + U: ::core::cmp::PartialEq + ::core::marker::Copy> ::core::cmp::PartialEq + for PackedGeneric<T, U> where T::A: ::core::cmp::PartialEq + + ::core::marker::Copy { #[inline] - fn eq(&self, other: &PackedNonCopy) -> bool { self.0 == other.0 } + fn eq(&self, other: &PackedGeneric<T, U>) -> bool { + { self.0 } == { other.0 } && { self.1 } == { other.1 } && + { self.2 } == { other.2 } + } } #[automatically_derived] -impl ::core::marker::StructuralEq for PackedNonCopy { } +impl<T: Trait, U> ::core::marker::StructuralEq for PackedGeneric<T, U> { } #[automatically_derived] -impl ::core::cmp::Eq for PackedNonCopy { +impl<T: ::core::cmp::Eq + ::core::marker::Copy + Trait, U: ::core::cmp::Eq + + ::core::marker::Copy> ::core::cmp::Eq for PackedGeneric<T, U> where + T::A: ::core::cmp::Eq + ::core::marker::Copy { #[inline] #[doc(hidden)] #[no_coverage] fn assert_receiver_is_total_eq(&self) -> () { - let _: ::core::cmp::AssertParamIsEq<u8>; + let _: ::core::cmp::AssertParamIsEq<T>; + let _: ::core::cmp::AssertParamIsEq<T::A>; + let _: ::core::cmp::AssertParamIsEq<U>; } } #[automatically_derived] -impl ::core::cmp::PartialOrd for PackedNonCopy { +impl<T: ::core::cmp::PartialOrd + ::core::marker::Copy + Trait, + U: ::core::cmp::PartialOrd + ::core::marker::Copy> ::core::cmp::PartialOrd + for PackedGeneric<T, U> where T::A: ::core::cmp::PartialOrd + + ::core::marker::Copy { #[inline] - fn partial_cmp(&self, other: &PackedNonCopy) + fn partial_cmp(&self, other: &PackedGeneric<T, U>) -> ::core::option::Option<::core::cmp::Ordering> { - ::core::cmp::PartialOrd::partial_cmp(&self.0, &other.0) + match ::core::cmp::PartialOrd::partial_cmp(&{ self.0 }, &{ other.0 }) + { + ::core::option::Option::Some(::core::cmp::Ordering::Equal) => + match ::core::cmp::PartialOrd::partial_cmp(&{ self.1 }, + &{ other.1 }) { + ::core::option::Option::Some(::core::cmp::Ordering::Equal) + => + ::core::cmp::PartialOrd::partial_cmp(&{ self.2 }, + &{ other.2 }), + cmp => cmp, + }, + cmp => cmp, + } } } #[automatically_derived] -impl ::core::cmp::Ord for PackedNonCopy { +impl<T: ::core::cmp::Ord + ::core::marker::Copy + Trait, U: ::core::cmp::Ord + + ::core::marker::Copy> ::core::cmp::Ord for PackedGeneric<T, U> where + T::A: ::core::cmp::Ord + ::core::marker::Copy { #[inline] - fn cmp(&self, other: &PackedNonCopy) -> ::core::cmp::Ordering { - ::core::cmp::Ord::cmp(&self.0, &other.0) + fn cmp(&self, other: &PackedGeneric<T, U>) -> ::core::cmp::Ordering { + match ::core::cmp::Ord::cmp(&{ self.0 }, &{ other.0 }) { + ::core::cmp::Ordering::Equal => + match ::core::cmp::Ord::cmp(&{ self.1 }, &{ other.1 }) { + ::core::cmp::Ordering::Equal => + ::core::cmp::Ord::cmp(&{ self.2 }, &{ other.2 }), + cmp => cmp, + }, + cmp => cmp, + } } } @@ -1051,6 +1309,125 @@ impl ::core::cmp::Ord for Fielded { } } +// A generic enum. Note that `Default` cannot be derived for this enum. +enum EnumGeneric<T, U> { One(T), Two(U), } +#[automatically_derived] +impl<T: ::core::clone::Clone, U: ::core::clone::Clone> ::core::clone::Clone + for EnumGeneric<T, U> { + #[inline] + fn clone(&self) -> EnumGeneric<T, U> { + match self { + EnumGeneric::One(__self_0) => + EnumGeneric::One(::core::clone::Clone::clone(__self_0)), + EnumGeneric::Two(__self_0) => + EnumGeneric::Two(::core::clone::Clone::clone(__self_0)), + } + } +} +#[automatically_derived] +impl<T: ::core::marker::Copy, U: ::core::marker::Copy> ::core::marker::Copy + for EnumGeneric<T, U> { +} +#[automatically_derived] +impl<T: ::core::fmt::Debug, U: ::core::fmt::Debug> ::core::fmt::Debug for + EnumGeneric<T, U> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + match self { + EnumGeneric::One(__self_0) => + ::core::fmt::Formatter::debug_tuple_field1_finish(f, "One", + &__self_0), + EnumGeneric::Two(__self_0) => + ::core::fmt::Formatter::debug_tuple_field1_finish(f, "Two", + &__self_0), + } + } +} +#[automatically_derived] +impl<T: ::core::hash::Hash, U: ::core::hash::Hash> ::core::hash::Hash for + EnumGeneric<T, U> { + fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () { + let __self_tag = ::core::intrinsics::discriminant_value(self); + ::core::hash::Hash::hash(&__self_tag, state); + match self { + EnumGeneric::One(__self_0) => + ::core::hash::Hash::hash(__self_0, state), + EnumGeneric::Two(__self_0) => + ::core::hash::Hash::hash(__self_0, state), + } + } +} +#[automatically_derived] +impl<T, U> ::core::marker::StructuralPartialEq for EnumGeneric<T, U> { } +#[automatically_derived] +impl<T: ::core::cmp::PartialEq, U: ::core::cmp::PartialEq> + ::core::cmp::PartialEq for EnumGeneric<T, U> { + #[inline] + fn eq(&self, other: &EnumGeneric<T, U>) -> bool { + let __self_tag = ::core::intrinsics::discriminant_value(self); + let __arg1_tag = ::core::intrinsics::discriminant_value(other); + __self_tag == __arg1_tag && + match (self, other) { + (EnumGeneric::One(__self_0), EnumGeneric::One(__arg1_0)) => + *__self_0 == *__arg1_0, + (EnumGeneric::Two(__self_0), EnumGeneric::Two(__arg1_0)) => + *__self_0 == *__arg1_0, + _ => unsafe { ::core::intrinsics::unreachable() } + } + } +} +#[automatically_derived] +impl<T, U> ::core::marker::StructuralEq for EnumGeneric<T, U> { } +#[automatically_derived] +impl<T: ::core::cmp::Eq, U: ::core::cmp::Eq> ::core::cmp::Eq for + EnumGeneric<T, U> { + #[inline] + #[doc(hidden)] + #[no_coverage] + fn assert_receiver_is_total_eq(&self) -> () { + let _: ::core::cmp::AssertParamIsEq<T>; + let _: ::core::cmp::AssertParamIsEq<U>; + } +} +#[automatically_derived] +impl<T: ::core::cmp::PartialOrd, U: ::core::cmp::PartialOrd> + ::core::cmp::PartialOrd for EnumGeneric<T, U> { + #[inline] + fn partial_cmp(&self, other: &EnumGeneric<T, U>) + -> ::core::option::Option<::core::cmp::Ordering> { + let __self_tag = ::core::intrinsics::discriminant_value(self); + let __arg1_tag = ::core::intrinsics::discriminant_value(other); + match (self, other) { + (EnumGeneric::One(__self_0), EnumGeneric::One(__arg1_0)) => + ::core::cmp::PartialOrd::partial_cmp(__self_0, __arg1_0), + (EnumGeneric::Two(__self_0), EnumGeneric::Two(__arg1_0)) => + ::core::cmp::PartialOrd::partial_cmp(__self_0, __arg1_0), + _ => + ::core::cmp::PartialOrd::partial_cmp(&__self_tag, + &__arg1_tag), + } + } +} +#[automatically_derived] +impl<T: ::core::cmp::Ord, U: ::core::cmp::Ord> ::core::cmp::Ord for + EnumGeneric<T, U> { + #[inline] + fn cmp(&self, other: &EnumGeneric<T, U>) -> ::core::cmp::Ordering { + let __self_tag = ::core::intrinsics::discriminant_value(self); + let __arg1_tag = ::core::intrinsics::discriminant_value(other); + match ::core::cmp::Ord::cmp(&__self_tag, &__arg1_tag) { + ::core::cmp::Ordering::Equal => + match (self, other) { + (EnumGeneric::One(__self_0), EnumGeneric::One(__arg1_0)) => + ::core::cmp::Ord::cmp(__self_0, __arg1_0), + (EnumGeneric::Two(__self_0), EnumGeneric::Two(__arg1_0)) => + ::core::cmp::Ord::cmp(__self_0, __arg1_0), + _ => unsafe { ::core::intrinsics::unreachable() } + }, + cmp => cmp, + } + } +} + // A union. Most builtin traits are not derivable for unions. pub union Union { pub b: bool, diff --git a/tests/ui/fmt/ifmt-unimpl.stderr b/tests/ui/fmt/ifmt-unimpl.stderr index be321c3c5c0..3480a2ec815 100644 --- a/tests/ui/fmt/ifmt-unimpl.stderr +++ b/tests/ui/fmt/ifmt-unimpl.stderr @@ -15,7 +15,7 @@ LL | format!("{:X}", "3"); NonZeroIsize and 21 others = note: required for `&str` to implement `UpperHex` -note: required by a bound in `ArgumentV1::<'a>::new_upper_hex` +note: required by a bound in `core::fmt::ArgumentV1::<'a>::new_upper_hex` --> $SRC_DIR/core/src/fmt/mod.rs:LL:COL = note: this error originates in the macro `$crate::__export::format_args` which comes from the expansion of the macro `arg_new` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/fmt/send-sync.stderr b/tests/ui/fmt/send-sync.stderr index 3ed040c3ab3..d43f4f0d957 100644 --- a/tests/ui/fmt/send-sync.stderr +++ b/tests/ui/fmt/send-sync.stderr @@ -6,11 +6,11 @@ LL | send(format_args!("{:?}", c)); | | | required by a bound introduced by this call | - = help: within `[ArgumentV1<'_>]`, the trait `Sync` is not implemented for `core::fmt::Opaque` + = help: within `[core::fmt::ArgumentV1<'_>]`, the trait `Sync` is not implemented for `core::fmt::Opaque` = note: required because it appears within the type `&core::fmt::Opaque` = note: required because it appears within the type `ArgumentV1<'_>` = note: required because it appears within the type `[ArgumentV1<'_>]` - = note: required for `&[ArgumentV1<'_>]` to implement `Send` + = note: required for `&[core::fmt::ArgumentV1<'_>]` to implement `Send` = note: required because it appears within the type `Arguments<'_>` note: required by a bound in `send` --> $DIR/send-sync.rs:1:12 diff --git a/tests/ui/parser/trait-object-delimiters.rs b/tests/ui/parser/trait-object-delimiters.rs index cc04ac05204..c41cda18743 100644 --- a/tests/ui/parser/trait-object-delimiters.rs +++ b/tests/ui/parser/trait-object-delimiters.rs @@ -5,6 +5,8 @@ fn foo1(_: &dyn Drop + AsRef<str>) {} //~ ERROR ambiguous `+` in a type fn foo2(_: &dyn (Drop + AsRef<str>)) {} //~ ERROR incorrect braces around trait bounds +fn foo2_no_space(_: &dyn(Drop + AsRef<str>)) {} //~ ERROR incorrect braces around trait bounds + fn foo3(_: &dyn {Drop + AsRef<str>}) {} //~ ERROR expected parameter name, found `{` //~^ ERROR expected one of `!`, `(`, `)`, `*`, `,`, `?`, `for`, `~`, lifetime, or path, found `{` //~| ERROR at least one trait is required for an object type diff --git a/tests/ui/parser/trait-object-delimiters.stderr b/tests/ui/parser/trait-object-delimiters.stderr index 99c4515459d..ccce3a8053e 100644 --- a/tests/ui/parser/trait-object-delimiters.stderr +++ b/tests/ui/parser/trait-object-delimiters.stderr @@ -13,17 +13,29 @@ LL | fn foo2(_: &dyn (Drop + AsRef<str>)) {} help: remove the parentheses | LL - fn foo2(_: &dyn (Drop + AsRef<str>)) {} -LL + fn foo2(_: &dyn Drop + AsRef<str>) {} +LL + fn foo2(_: &dyn Drop + AsRef<str>) {} + | + +error: incorrect braces around trait bounds + --> $DIR/trait-object-delimiters.rs:8:25 + | +LL | fn foo2_no_space(_: &dyn(Drop + AsRef<str>)) {} + | ^ ^ + | +help: remove the parentheses + | +LL - fn foo2_no_space(_: &dyn(Drop + AsRef<str>)) {} +LL + fn foo2_no_space(_: &dyn Drop + AsRef<str>) {} | error: expected parameter name, found `{` - --> $DIR/trait-object-delimiters.rs:8:17 + --> $DIR/trait-object-delimiters.rs:10:17 | LL | fn foo3(_: &dyn {Drop + AsRef<str>}) {} | ^ expected parameter name error: expected one of `!`, `(`, `)`, `*`, `,`, `?`, `for`, `~`, lifetime, or path, found `{` - --> $DIR/trait-object-delimiters.rs:8:17 + --> $DIR/trait-object-delimiters.rs:10:17 | LL | fn foo3(_: &dyn {Drop + AsRef<str>}) {} | -^ expected one of 10 possible tokens @@ -31,13 +43,13 @@ LL | fn foo3(_: &dyn {Drop + AsRef<str>}) {} | help: missing `,` error: expected identifier, found `<` - --> $DIR/trait-object-delimiters.rs:12:17 + --> $DIR/trait-object-delimiters.rs:14:17 | LL | fn foo4(_: &dyn <Drop + AsRef<str>>) {} | ^ expected identifier error: invalid `dyn` keyword - --> $DIR/trait-object-delimiters.rs:14:25 + --> $DIR/trait-object-delimiters.rs:16:25 | LL | fn foo5(_: &(dyn Drop + dyn AsRef<str>)) {} | ^^^ help: remove this keyword @@ -56,13 +68,13 @@ LL | fn foo1(_: &dyn Drop + AsRef<str>) {} = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits> error[E0224]: at least one trait is required for an object type - --> $DIR/trait-object-delimiters.rs:8:13 + --> $DIR/trait-object-delimiters.rs:10:13 | LL | fn foo3(_: &dyn {Drop + AsRef<str>}) {} | ^^^ error[E0225]: only auto traits can be used as additional traits in a trait object - --> $DIR/trait-object-delimiters.rs:14:29 + --> $DIR/trait-object-delimiters.rs:16:29 | LL | fn foo5(_: &(dyn Drop + dyn AsRef<str>)) {} | ---- ^^^^^^^^^^ additional non-auto trait @@ -72,7 +84,7 @@ LL | fn foo5(_: &(dyn Drop + dyn AsRef<str>)) {} = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Drop + AsRef<str> {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits> -error: aborting due to 9 previous errors +error: aborting due to 10 previous errors Some errors have detailed explanations: E0224, E0225. For more information about an error, try `rustc --explain E0224`. diff --git a/tests/ui/thir-print/thir-flat.rs b/tests/ui/thir-print/thir-flat.rs new file mode 100644 index 00000000000..8fa95ce62b5 --- /dev/null +++ b/tests/ui/thir-print/thir-flat.rs @@ -0,0 +1,4 @@ +// compile-flags: -Z unpretty=thir-flat +// check-pass + +pub fn main() {} diff --git a/tests/ui/thir-tree.stdout b/tests/ui/thir-print/thir-flat.stdout index 4b6915f7715..c399fa66b6a 100644 --- a/tests/ui/thir-tree.stdout +++ b/tests/ui/thir-print/thir-flat.stdout @@ -1,4 +1,4 @@ -DefId(0:3 ~ thir_tree[8f1d]::main): +DefId(0:3 ~ thir_flat[45a6]::main): Thir { arms: [], blocks: [ @@ -6,7 +6,7 @@ Thir { targeted_by_break: false, region_scope: Node(1), opt_destruction_scope: None, - span: $DIR/thir-tree.rs:4:15: 4:17 (#0), + span: $DIR/thir-flat.rs:4:15: 4:17 (#0), stmts: [], expr: None, safety_mode: Safe, @@ -18,7 +18,7 @@ Thir { temp_lifetime: Some( Node(2), ), - span: $DIR/thir-tree.rs:4:15: 4:17 (#0), + span: $DIR/thir-flat.rs:4:15: 4:17 (#0), kind: Block { block: b0, }, @@ -28,11 +28,11 @@ Thir { temp_lifetime: Some( Node(2), ), - span: $DIR/thir-tree.rs:4:15: 4:17 (#0), + span: $DIR/thir-flat.rs:4:15: 4:17 (#0), kind: Scope { region_scope: Node(2), lint_level: Explicit( - HirId(DefId(0:3 ~ thir_tree[8f1d]::main).2), + HirId(DefId(0:3 ~ thir_flat[45a6]::main).2), ), value: e0, }, @@ -42,7 +42,7 @@ Thir { temp_lifetime: Some( Node(2), ), - span: $DIR/thir-tree.rs:4:15: 4:17 (#0), + span: $DIR/thir-flat.rs:4:15: 4:17 (#0), kind: Scope { region_scope: Destruction(2), lint_level: Inherited, diff --git a/tests/ui/thir-print/thir-tree-match.rs b/tests/ui/thir-print/thir-tree-match.rs new file mode 100644 index 00000000000..a5511ec9543 --- /dev/null +++ b/tests/ui/thir-print/thir-tree-match.rs @@ -0,0 +1,23 @@ +// check-pass +// compile-flags: -Zunpretty=thir-tree + +enum Bar { + First, + Second, + Third, +} + +enum Foo { + FooOne(Bar), + FooTwo, +} + +fn has_match(foo: Foo) -> bool { + match foo { + Foo::FooOne(Bar::First) => true, + Foo::FooOne(_) => false, + Foo::FooTwo => true, + } +} + +fn main() {} diff --git a/tests/ui/thir-print/thir-tree-match.stdout b/tests/ui/thir-print/thir-tree-match.stdout new file mode 100644 index 00000000000..d6174ec262a --- /dev/null +++ b/tests/ui/thir-print/thir-tree-match.stdout @@ -0,0 +1,342 @@ +DefId(0:16 ~ thir_tree_match[3c9a]::has_match): +params: [ + Param { + ty: Foo + ty_span: Some($DIR/thir-tree-match.rs:15:19: 15:22 (#0)) + self_kind: None + hir_id: Some(HirId(DefId(0:16 ~ thir_tree_match[3c9a]::has_match).1)) + param: Some( + Pat: { + ty: Foo + span: $DIR/thir-tree-match.rs:15:14: 15:17 (#0) + kind: PatKind { + Binding { + mutability: Not + name: "foo" + mode: ByValue + var: LocalVarId(HirId(DefId(0:16 ~ thir_tree_match[3c9a]::has_match).2)) + ty: Foo + is_primary: true + subpattern: None + } + } + } + ) + } +] +body: + Expr { + ty: bool + temp_lifetime: Some(Node(26)) + span: $DIR/thir-tree-match.rs:15:32: 21:2 (#0) + kind: + Scope { + region_scope: Destruction(26) + lint_level: Inherited + value: + Expr { + ty: bool + temp_lifetime: Some(Node(26)) + span: $DIR/thir-tree-match.rs:15:32: 21:2 (#0) + kind: + Scope { + region_scope: Node(26) + lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[3c9a]::has_match).26)) + value: + Expr { + ty: bool + temp_lifetime: Some(Node(26)) + span: $DIR/thir-tree-match.rs:15:32: 21:2 (#0) + kind: + Block { + targeted_by_break: false + opt_destruction_scope: None + span: $DIR/thir-tree-match.rs:15:32: 21:2 (#0) + region_scope: Node(25) + safety_mode: Safe + stmts: [] + expr: + Expr { + ty: bool + temp_lifetime: Some(Node(26)) + span: $DIR/thir-tree-match.rs:16:5: 20:6 (#0) + kind: + Scope { + region_scope: Node(3) + lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[3c9a]::has_match).3)) + value: + Expr { + ty: bool + temp_lifetime: Some(Node(26)) + span: $DIR/thir-tree-match.rs:16:5: 20:6 (#0) + kind: + Match { + scrutinee: + Expr { + ty: Foo + temp_lifetime: Some(Node(26)) + span: $DIR/thir-tree-match.rs:16:11: 16:14 (#0) + kind: + Scope { + region_scope: Node(4) + lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[3c9a]::has_match).4)) + value: + Expr { + ty: Foo + temp_lifetime: Some(Node(26)) + span: $DIR/thir-tree-match.rs:16:11: 16:14 (#0) + kind: + VarRef { + id: LocalVarId(HirId(DefId(0:16 ~ thir_tree_match[3c9a]::has_match).2)) + } + } + } + } + arms: [ + Arm { + pattern: + Pat: { + ty: Foo + span: $DIR/thir-tree-match.rs:17:9: 17:32 (#0) + kind: PatKind { + Variant { + adt_def: + AdtDef { + did: DefId(0:10 ~ thir_tree_match[3c9a]::Foo) + variants: [VariantDef { def_id: DefId(0:11 ~ thir_tree_match[3c9a]::Foo::FooOne), ctor: Some((Fn, DefId(0:12 ~ thir_tree_match[3c9a]::Foo::FooOne::{constructor#0}))), name: "FooOne", discr: Relative(0), fields: [FieldDef { did: DefId(0:13 ~ thir_tree_match[3c9a]::Foo::FooOne::0), name: "0", vis: Restricted(DefId(0:0 ~ thir_tree_match[3c9a])) }], flags: NO_VARIANT_FLAGS }, VariantDef { def_id: DefId(0:14 ~ thir_tree_match[3c9a]::Foo::FooTwo), ctor: Some((Const, DefId(0:15 ~ thir_tree_match[3c9a]::Foo::FooTwo::{constructor#0}))), name: "FooTwo", discr: Relative(1), fields: [], flags: NO_VARIANT_FLAGS }] + flags: IS_ENUM + repr: ReprOptions { int: None, align: None, pack: None, flags: (empty), field_shuffle_seed: 11573694388057581 } + substs: [] + variant_index: 0 + subpatterns: [ + Pat: { + ty: Bar + span: $DIR/thir-tree-match.rs:17:21: 17:31 (#0) + kind: PatKind { + Variant { + adt_def: + AdtDef { + did: DefId(0:3 ~ thir_tree_match[3c9a]::Bar) + variants: [VariantDef { def_id: DefId(0:4 ~ thir_tree_match[3c9a]::Bar::First), ctor: Some((Const, DefId(0:5 ~ thir_tree_match[3c9a]::Bar::First::{constructor#0}))), name: "First", discr: Relative(0), fields: [], flags: NO_VARIANT_FLAGS }, VariantDef { def_id: DefId(0:6 ~ thir_tree_match[3c9a]::Bar::Second), ctor: Some((Const, DefId(0:7 ~ thir_tree_match[3c9a]::Bar::Second::{constructor#0}))), name: "Second", discr: Relative(1), fields: [], flags: NO_VARIANT_FLAGS }, VariantDef { def_id: DefId(0:8 ~ thir_tree_match[3c9a]::Bar::Third), ctor: Some((Const, DefId(0:9 ~ thir_tree_match[3c9a]::Bar::Third::{constructor#0}))), name: "Third", discr: Relative(2), fields: [], flags: NO_VARIANT_FLAGS }] + flags: IS_ENUM + repr: ReprOptions { int: None, align: None, pack: None, flags: (empty), field_shuffle_seed: 3125160937860410723 } + substs: [] + variant_index: 0 + subpatterns: [] + } + } + } + ] + } + } + } + guard: None + body: + Expr { + ty: bool + temp_lifetime: Some(Node(13)) + span: $DIR/thir-tree-match.rs:17:36: 17:40 (#0) + kind: + Scope { + region_scope: Destruction(13) + lint_level: Inherited + value: + Expr { + ty: bool + temp_lifetime: Some(Node(13)) + span: $DIR/thir-tree-match.rs:17:36: 17:40 (#0) + kind: + Scope { + region_scope: Node(13) + lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[3c9a]::has_match).13)) + value: + Expr { + ty: bool + temp_lifetime: Some(Node(13)) + span: $DIR/thir-tree-match.rs:17:36: 17:40 (#0) + kind: + Literal( lit: Spanned { node: Bool(true), span: $DIR/thir-tree-match.rs:17:36: 17:40 (#0) }, neg: false) + + } + } + } + } + } + lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[3c9a]::has_match).12)) + scope: Node(12) + span: $DIR/thir-tree-match.rs:17:9: 17:40 (#0) + } + Arm { + pattern: + Pat: { + ty: Foo + span: $DIR/thir-tree-match.rs:18:9: 18:23 (#0) + kind: PatKind { + Variant { + adt_def: + AdtDef { + did: DefId(0:10 ~ thir_tree_match[3c9a]::Foo) + variants: [VariantDef { def_id: DefId(0:11 ~ thir_tree_match[3c9a]::Foo::FooOne), ctor: Some((Fn, DefId(0:12 ~ thir_tree_match[3c9a]::Foo::FooOne::{constructor#0}))), name: "FooOne", discr: Relative(0), fields: [FieldDef { did: DefId(0:13 ~ thir_tree_match[3c9a]::Foo::FooOne::0), name: "0", vis: Restricted(DefId(0:0 ~ thir_tree_match[3c9a])) }], flags: NO_VARIANT_FLAGS }, VariantDef { def_id: DefId(0:14 ~ thir_tree_match[3c9a]::Foo::FooTwo), ctor: Some((Const, DefId(0:15 ~ thir_tree_match[3c9a]::Foo::FooTwo::{constructor#0}))), name: "FooTwo", discr: Relative(1), fields: [], flags: NO_VARIANT_FLAGS }] + flags: IS_ENUM + repr: ReprOptions { int: None, align: None, pack: None, flags: (empty), field_shuffle_seed: 11573694388057581 } + substs: [] + variant_index: 0 + subpatterns: [ + Pat: { + ty: Bar + span: $DIR/thir-tree-match.rs:18:21: 18:22 (#0) + kind: PatKind { + Wild + } + } + ] + } + } + } + guard: None + body: + Expr { + ty: bool + temp_lifetime: Some(Node(19)) + span: $DIR/thir-tree-match.rs:18:27: 18:32 (#0) + kind: + Scope { + region_scope: Destruction(19) + lint_level: Inherited + value: + Expr { + ty: bool + temp_lifetime: Some(Node(19)) + span: $DIR/thir-tree-match.rs:18:27: 18:32 (#0) + kind: + Scope { + region_scope: Node(19) + lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[3c9a]::has_match).19)) + value: + Expr { + ty: bool + temp_lifetime: Some(Node(19)) + span: $DIR/thir-tree-match.rs:18:27: 18:32 (#0) + kind: + Literal( lit: Spanned { node: Bool(false), span: $DIR/thir-tree-match.rs:18:27: 18:32 (#0) }, neg: false) + + } + } + } + } + } + lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[3c9a]::has_match).18)) + scope: Node(18) + span: $DIR/thir-tree-match.rs:18:9: 18:32 (#0) + } + Arm { + pattern: + Pat: { + ty: Foo + span: $DIR/thir-tree-match.rs:19:9: 19:20 (#0) + kind: PatKind { + Variant { + adt_def: + AdtDef { + did: DefId(0:10 ~ thir_tree_match[3c9a]::Foo) + variants: [VariantDef { def_id: DefId(0:11 ~ thir_tree_match[3c9a]::Foo::FooOne), ctor: Some((Fn, DefId(0:12 ~ thir_tree_match[3c9a]::Foo::FooOne::{constructor#0}))), name: "FooOne", discr: Relative(0), fields: [FieldDef { did: DefId(0:13 ~ thir_tree_match[3c9a]::Foo::FooOne::0), name: "0", vis: Restricted(DefId(0:0 ~ thir_tree_match[3c9a])) }], flags: NO_VARIANT_FLAGS }, VariantDef { def_id: DefId(0:14 ~ thir_tree_match[3c9a]::Foo::FooTwo), ctor: Some((Const, DefId(0:15 ~ thir_tree_match[3c9a]::Foo::FooTwo::{constructor#0}))), name: "FooTwo", discr: Relative(1), fields: [], flags: NO_VARIANT_FLAGS }] + flags: IS_ENUM + repr: ReprOptions { int: None, align: None, pack: None, flags: (empty), field_shuffle_seed: 11573694388057581 } + substs: [] + variant_index: 1 + subpatterns: [] + } + } + } + guard: None + body: + Expr { + ty: bool + temp_lifetime: Some(Node(24)) + span: $DIR/thir-tree-match.rs:19:24: 19:28 (#0) + kind: + Scope { + region_scope: Destruction(24) + lint_level: Inherited + value: + Expr { + ty: bool + temp_lifetime: Some(Node(24)) + span: $DIR/thir-tree-match.rs:19:24: 19:28 (#0) + kind: + Scope { + region_scope: Node(24) + lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[3c9a]::has_match).24)) + value: + Expr { + ty: bool + temp_lifetime: Some(Node(24)) + span: $DIR/thir-tree-match.rs:19:24: 19:28 (#0) + kind: + Literal( lit: Spanned { node: Bool(true), span: $DIR/thir-tree-match.rs:19:24: 19:28 (#0) }, neg: false) + + } + } + } + } + } + lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[3c9a]::has_match).23)) + scope: Node(23) + span: $DIR/thir-tree-match.rs:19:9: 19:28 (#0) + } + ] + } + } + } + } + } + } + } + } + } + } + + +DefId(0:17 ~ thir_tree_match[3c9a]::main): +params: [ +] +body: + Expr { + ty: () + temp_lifetime: Some(Node(2)) + span: $DIR/thir-tree-match.rs:23:11: 23:13 (#0) + kind: + Scope { + region_scope: Destruction(2) + lint_level: Inherited + value: + Expr { + ty: () + temp_lifetime: Some(Node(2)) + span: $DIR/thir-tree-match.rs:23:11: 23:13 (#0) + kind: + Scope { + region_scope: Node(2) + lint_level: Explicit(HirId(DefId(0:17 ~ thir_tree_match[3c9a]::main).2)) + value: + Expr { + ty: () + temp_lifetime: Some(Node(2)) + span: $DIR/thir-tree-match.rs:23:11: 23:13 (#0) + kind: + Block { + targeted_by_break: false + opt_destruction_scope: None + span: $DIR/thir-tree-match.rs:23:11: 23:13 (#0) + region_scope: Node(1) + safety_mode: Safe + stmts: [] + expr: [] + } + } + } + } + } + } + + diff --git a/tests/ui/thir-tree.rs b/tests/ui/thir-print/thir-tree.rs index 32df7905adb..32df7905adb 100644 --- a/tests/ui/thir-tree.rs +++ b/tests/ui/thir-print/thir-tree.rs diff --git a/tests/ui/thir-print/thir-tree.stdout b/tests/ui/thir-print/thir-tree.stdout new file mode 100644 index 00000000000..0a35d9fb78c --- /dev/null +++ b/tests/ui/thir-print/thir-tree.stdout @@ -0,0 +1,43 @@ +DefId(0:3 ~ thir_tree[8f1d]::main): +params: [ +] +body: + Expr { + ty: () + temp_lifetime: Some(Node(2)) + span: $DIR/thir-tree.rs:4:15: 4:17 (#0) + kind: + Scope { + region_scope: Destruction(2) + lint_level: Inherited + value: + Expr { + ty: () + temp_lifetime: Some(Node(2)) + span: $DIR/thir-tree.rs:4:15: 4:17 (#0) + kind: + Scope { + region_scope: Node(2) + lint_level: Explicit(HirId(DefId(0:3 ~ thir_tree[8f1d]::main).2)) + value: + Expr { + ty: () + temp_lifetime: Some(Node(2)) + span: $DIR/thir-tree.rs:4:15: 4:17 (#0) + kind: + Block { + targeted_by_break: false + opt_destruction_scope: None + span: $DIR/thir-tree.rs:4:15: 4:17 (#0) + region_scope: Node(1) + safety_mode: Safe + stmts: [] + expr: [] + } + } + } + } + } + } + + |
