diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs index 2f5eca2d6b23e..5af47e698a6e1 100644 --- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs +++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs @@ -219,13 +219,18 @@ fn exported_non_generic_symbols_provider_local<'tcx>( // Mark allocator shim symbols as exported only if they were generated. if allocator_kind_for_codegen(tcx).is_some() { - for symbol_name in ALLOCATOR_METHODS + for (symbol_name, export_kind) in ALLOCATOR_METHODS .iter() - .map(|method| mangle_internal_symbol(tcx, global_fn_name(method.name).as_str())) + .map(|method| { + ( + mangle_internal_symbol(tcx, global_fn_name(method.name).as_str()), + SymbolExportKind::Text, + ) + }) .chain([ - mangle_internal_symbol(tcx, "__rust_alloc_error_handler"), - mangle_internal_symbol(tcx, OomStrategy::SYMBOL), - mangle_internal_symbol(tcx, NO_ALLOC_SHIM_IS_UNSTABLE), + (mangle_internal_symbol(tcx, "__rust_alloc_error_handler"), SymbolExportKind::Text), + (mangle_internal_symbol(tcx, OomStrategy::SYMBOL), SymbolExportKind::Data), + (mangle_internal_symbol(tcx, NO_ALLOC_SHIM_IS_UNSTABLE), SymbolExportKind::Text), ]) { let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(tcx, &symbol_name)); @@ -234,7 +239,7 @@ fn exported_non_generic_symbols_provider_local<'tcx>( exported_symbol, SymbolExportInfo { level: SymbolExportLevel::Rust, - kind: SymbolExportKind::Text, + kind: export_kind, used: false, rustc_std_internal_symbol: true, }, diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index 7ef04213d3207..60cf4e28b5a09 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -1117,7 +1117,7 @@ pub(super) fn transmute_immediate<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( // While optimizations will remove no-op transmutes, they might still be // there in debug or things that aren't no-op in MIR because they change // the Rust type but not the underlying layout/niche. - if from_scalar == to_scalar { + if from_scalar == to_scalar && from_backend_ty == to_backend_ty { return imm; } @@ -1136,13 +1136,7 @@ pub(super) fn transmute_immediate<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( assume_scalar_range(bx, imm, from_scalar, from_backend_ty); imm = match (from_scalar.primitive(), to_scalar.primitive()) { - (Int(..) | Float(_), Int(..) | Float(_)) => { - if from_backend_ty == to_backend_ty { - imm - } else { - bx.bitcast(imm, to_backend_ty) - } - } + (Int(..) | Float(_), Int(..) | Float(_)) => bx.bitcast(imm, to_backend_ty), (Pointer(..), Pointer(..)) => bx.pointercast(imm, to_backend_ty), (Int(..), Pointer(..)) => bx.ptradd(bx.const_null(bx.type_ptr()), imm), (Pointer(..), Int(..)) => { diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index 6b2854d96af61..8437ab6d3c081 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -1588,7 +1588,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { &infcx_ }; - tcx.all_traits() + tcx.all_traits_including_private() .filter(|trait_def_id| { // Consider only traits with the associated type tcx.associated_items(*trait_def_id) @@ -2459,13 +2459,15 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // type a projection. let in_trait = match opaque_ty.origin { hir::OpaqueTyOrigin::FnReturn { + parent, in_trait_or_impl: Some(hir::RpitContext::Trait), .. } | hir::OpaqueTyOrigin::AsyncFn { + parent, in_trait_or_impl: Some(hir::RpitContext::Trait), .. - } => true, + } => Some(parent), hir::OpaqueTyOrigin::FnReturn { in_trait_or_impl: None | Some(hir::RpitContext::TraitImpl), .. @@ -2474,7 +2476,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { in_trait_or_impl: None | Some(hir::RpitContext::TraitImpl), .. } - | hir::OpaqueTyOrigin::TyAlias { .. } => false, + | hir::OpaqueTyOrigin::TyAlias { .. } => None, }; self.lower_opaque_ty(opaque_ty.def_id, in_trait) @@ -2594,17 +2596,25 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { /// Lower an opaque type (i.e., an existential impl-Trait type) from the HIR. #[instrument(level = "debug", skip(self), ret)] - fn lower_opaque_ty(&self, def_id: LocalDefId, in_trait: bool) -> Ty<'tcx> { + fn lower_opaque_ty(&self, def_id: LocalDefId, in_trait: Option) -> Ty<'tcx> { let tcx = self.tcx(); let lifetimes = tcx.opaque_captured_lifetimes(def_id); debug!(?lifetimes); - // If this is an RPITIT and we are using the new RPITIT lowering scheme, we - // generate the def_id of an associated type for the trait and return as - // type a projection. - let def_id = if in_trait { - tcx.associated_type_for_impl_trait_in_trait(def_id).to_def_id() + // If this is an RPITIT and we are using the new RPITIT lowering scheme, + // do a linear search to map this to the synthetic associated type that + // it will be lowered to. + let def_id = if let Some(parent_def_id) = in_trait { + *tcx.associated_types_for_impl_traits_in_associated_fn(parent_def_id) + .iter() + .find(|rpitit| match tcx.opt_rpitit_info(**rpitit) { + Some(ty::ImplTraitInTraitData::Trait { opaque_def_id, .. }) => { + opaque_def_id.expect_local() == def_id + } + _ => unreachable!(), + }) + .unwrap() } else { def_id.to_def_id() }; @@ -2627,7 +2637,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { }); debug!(?args); - if in_trait { + if in_trait.is_some() { Ty::new_projection_from_args(tcx, def_id, args) } else { Ty::new_opaque(tcx, def_id, args) diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index df1ee0e79c243..2815621ffdecf 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -1725,7 +1725,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if unsatisfied_predicates.is_empty() // ...or if we already suggested that name because of `rustc_confusable` annotation && Some(similar_candidate.name()) != confusable_suggested - // and if the we aren't in an expansion. + // and if we aren't in an expansion. && !span.from_expansion() { self.find_likely_intended_associated_item( @@ -3481,9 +3481,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self, err: &mut Diag<'_>, item_name: Ident, - valid_out_of_scope_traits: Vec, + mut valid_out_of_scope_traits: Vec, explain: bool, ) -> bool { + valid_out_of_scope_traits.retain(|id| self.tcx.is_user_visible_dep(id.krate)); if !valid_out_of_scope_traits.is_empty() { let mut candidates = valid_out_of_scope_traits; candidates.sort_by_key(|id| self.tcx.def_path_str(id)); @@ -4388,7 +4389,7 @@ pub(crate) struct TraitInfo { /// Retrieves all traits in this crate and any dependent crates, /// and wraps them into `TraitInfo` for custom sorting. pub(crate) fn all_traits(tcx: TyCtxt<'_>) -> Vec { - tcx.all_traits().map(|def_id| TraitInfo { def_id }).collect() + tcx.all_traits_including_private().map(|def_id| TraitInfo { def_id }).collect() } fn print_disambiguation_help<'tcx>( diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 3e68f0f784e53..05154633a38a0 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1093,13 +1093,6 @@ rustc_queries! { separate_provide_extern } - /// Given an impl trait in trait `opaque_ty_def_id`, create and return the corresponding - /// associated item. - query associated_type_for_impl_trait_in_trait(opaque_ty_def_id: LocalDefId) -> LocalDefId { - desc { |tcx| "creating the associated item corresponding to the opaque type `{}`", tcx.def_path_str(opaque_ty_def_id.to_def_id()) } - cache_on_disk_if { true } - } - /// Given an `impl_id`, return the trait it implements along with some header information. /// Return `None` if this is an inherent impl. query impl_trait_header(impl_id: DefId) -> Option> { diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index f5c55f968757f..efa47b57cf38d 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -2287,7 +2287,7 @@ impl<'tcx> TyCtxt<'tcx> { } /// All traits in the crate graph, including those not visible to the user. - pub fn all_traits(self) -> impl Iterator { + pub fn all_traits_including_private(self) -> impl Iterator { iter::once(LOCAL_CRATE) .chain(self.crates(()).iter().copied()) .flat_map(move |cnum| self.traits(cnum).iter().copied()) diff --git a/compiler/rustc_resolve/messages.ftl b/compiler/rustc_resolve/messages.ftl index 58942474e3233..aa818cc9c4649 100644 --- a/compiler/rustc_resolve/messages.ftl +++ b/compiler/rustc_resolve/messages.ftl @@ -432,6 +432,7 @@ resolve_undeclared_label = resolve_underscore_lifetime_is_reserved = `'_` cannot be used here .label = `'_` is a reserved lifetime name + .help = use another lifetime specifier resolve_unexpected_res_change_ty_to_const_param_sugg = you might have meant to write a const parameter here diff --git a/compiler/rustc_resolve/src/errors.rs b/compiler/rustc_resolve/src/errors.rs index 6d3752c0c8345..671f4ed984279 100644 --- a/compiler/rustc_resolve/src/errors.rs +++ b/compiler/rustc_resolve/src/errors.rs @@ -934,6 +934,7 @@ pub(crate) struct ImplicitElidedLifetimeNotAllowedHere { #[derive(Diagnostic)] #[diag(resolve_underscore_lifetime_is_reserved, code = E0637)] +#[help] pub(crate) struct UnderscoreLifetimeIsReserved { #[primary_span] #[label] diff --git a/compiler/rustc_smir/src/rustc_smir/context.rs b/compiler/rustc_smir/src/rustc_smir/context.rs index baa4c0681e806..3fa83cfc6a08c 100644 --- a/compiler/rustc_smir/src/rustc_smir/context.rs +++ b/compiler/rustc_smir/src/rustc_smir/context.rs @@ -130,7 +130,11 @@ impl<'tcx> SmirCtxt<'tcx> { pub fn all_trait_decls(&self) -> stable_mir::TraitDecls { let mut tables = self.0.borrow_mut(); - tables.tcx.all_traits().map(|trait_def_id| tables.trait_def(trait_def_id)).collect() + tables + .tcx + .all_traits_including_private() + .map(|trait_def_id| tables.trait_def(trait_def_id)) + .collect() } pub fn trait_decls(&self, crate_num: CrateNum) -> stable_mir::TraitDecls { diff --git a/compiler/rustc_target/src/spec/targets/powerpc64_unknown_freebsd.rs b/compiler/rustc_target/src/spec/targets/powerpc64_unknown_freebsd.rs index 66733d5d4b89c..b01ca989282ef 100644 --- a/compiler/rustc_target/src/spec/targets/powerpc64_unknown_freebsd.rs +++ b/compiler/rustc_target/src/spec/targets/powerpc64_unknown_freebsd.rs @@ -10,6 +10,7 @@ pub(crate) fn target() -> Target { base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]); base.max_atomic_width = Some(64); base.stack_probes = StackProbeType::Inline; + base.abi = "elfv2".into(); base.llvm_abiname = "elfv2".into(); Target { diff --git a/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_gnu.rs index ecf68ddff8c2f..bc7e445f3f8ae 100644 --- a/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_gnu.rs @@ -10,6 +10,7 @@ pub(crate) fn target() -> Target { base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]); base.max_atomic_width = Some(64); base.stack_probes = StackProbeType::Inline; + base.abi = "elfv1".into(); base.llvm_abiname = "elfv1".into(); Target { diff --git a/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_musl.rs index e205aef82856e..4dc76f0936c92 100644 --- a/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_musl.rs @@ -12,6 +12,7 @@ pub(crate) fn target() -> Target { base.stack_probes = StackProbeType::Inline; // FIXME(compiler-team#422): musl targets should be dynamically linked by default. base.crt_static_default = true; + base.abi = "elfv2".into(); base.llvm_abiname = "elfv2".into(); Target { diff --git a/compiler/rustc_target/src/spec/targets/powerpc64_unknown_openbsd.rs b/compiler/rustc_target/src/spec/targets/powerpc64_unknown_openbsd.rs index bcb328020eea8..9dc44aa05cc0a 100644 --- a/compiler/rustc_target/src/spec/targets/powerpc64_unknown_openbsd.rs +++ b/compiler/rustc_target/src/spec/targets/powerpc64_unknown_openbsd.rs @@ -10,6 +10,7 @@ pub(crate) fn target() -> Target { base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]); base.max_atomic_width = Some(64); base.stack_probes = StackProbeType::Inline; + base.abi = "elfv2".into(); base.llvm_abiname = "elfv2".into(); Target { diff --git a/compiler/rustc_target/src/spec/targets/powerpc64_wrs_vxworks.rs b/compiler/rustc_target/src/spec/targets/powerpc64_wrs_vxworks.rs index 37c888ba51443..10072f8092deb 100644 --- a/compiler/rustc_target/src/spec/targets/powerpc64_wrs_vxworks.rs +++ b/compiler/rustc_target/src/spec/targets/powerpc64_wrs_vxworks.rs @@ -10,6 +10,7 @@ pub(crate) fn target() -> Target { base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]); base.max_atomic_width = Some(64); base.stack_probes = StackProbeType::Inline; + base.abi = "elfv1".into(); base.llvm_abiname = "elfv1".into(); Target { diff --git a/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_freebsd.rs b/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_freebsd.rs index 3096c4d14ad87..a7f4e0eabb0a2 100644 --- a/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_freebsd.rs +++ b/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_freebsd.rs @@ -8,6 +8,7 @@ pub(crate) fn target() -> Target { base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]); base.max_atomic_width = Some(64); base.stack_probes = StackProbeType::Inline; + base.abi = "elfv2".into(); base.llvm_abiname = "elfv2".into(); Target { diff --git a/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_linux_gnu.rs index 9e406af53b5b5..af5704b51ba33 100644 --- a/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_linux_gnu.rs @@ -8,6 +8,7 @@ pub(crate) fn target() -> Target { base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]); base.max_atomic_width = Some(64); base.stack_probes = StackProbeType::Inline; + base.abi = "elfv2".into(); base.llvm_abiname = "elfv2".into(); Target { diff --git a/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_linux_musl.rs index f145c5b8c1451..26ee6a68c6a8b 100644 --- a/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_linux_musl.rs @@ -10,6 +10,7 @@ pub(crate) fn target() -> Target { base.stack_probes = StackProbeType::Inline; // FIXME(compiler-team#422): musl targets should be dynamically linked by default. base.crt_static_default = true; + base.abi = "elfv2".into(); base.llvm_abiname = "elfv2".into(); Target { diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs index c72eff1d23161..28d572b303ac5 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs @@ -1855,7 +1855,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { let trait_def_id = trait_pred.def_id(); let trait_name = self.tcx.item_name(trait_def_id); let crate_name = self.tcx.crate_name(trait_def_id.krate); - if let Some(other_trait_def_id) = self.tcx.all_traits().find(|def_id| { + if let Some(other_trait_def_id) = self.tcx.all_traits_including_private().find(|def_id| { trait_name == self.tcx.item_name(trait_def_id) && trait_def_id.krate != def_id.krate && crate_name == self.tcx.crate_name(def_id.krate) diff --git a/compiler/rustc_ty_utils/src/assoc.rs b/compiler/rustc_ty_utils/src/assoc.rs index f14a45aa1e3b9..a65f9b347dc6d 100644 --- a/compiler/rustc_ty_utils/src/assoc.rs +++ b/compiler/rustc_ty_utils/src/assoc.rs @@ -1,9 +1,8 @@ -use rustc_data_structures::fx::FxIndexSet; +use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId}; use rustc_hir::definitions::{DefPathData, DisambiguatorState}; use rustc_hir::intravisit::{self, Visitor}; -use rustc_hir::{self as hir, AmbigArg}; use rustc_middle::query::Providers; use rustc_middle::ty::{self, ImplTraitInTraitData, TyCtxt}; use rustc_middle::{bug, span_bug}; @@ -14,7 +13,6 @@ pub(crate) fn provide(providers: &mut Providers) { associated_item_def_ids, associated_items, associated_types_for_impl_traits_in_associated_fn, - associated_type_for_impl_trait_in_trait, impl_item_implementor_ids, ..*providers }; @@ -160,20 +158,22 @@ fn associated_item_from_impl_item_ref(impl_item_ref: &hir::ImplItemRef) -> ty::A container: ty::AssocItemContainer::Impl, } } -struct RPITVisitor { - rpits: FxIndexSet, +struct RPITVisitor<'tcx> { + tcx: TyCtxt<'tcx>, + synthetics: Vec, + data: DefPathData, + disambiguator: DisambiguatorState, } -impl<'tcx> Visitor<'tcx> for RPITVisitor { - fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx, AmbigArg>) { - if let hir::TyKind::OpaqueDef(opaq) = ty.kind - && self.rpits.insert(opaq.def_id) - { - for bound in opaq.bounds { - intravisit::walk_param_bound(self, bound); - } - } - intravisit::walk_ty(self, ty) +impl<'tcx> Visitor<'tcx> for RPITVisitor<'tcx> { + fn visit_opaque_ty(&mut self, opaque: &'tcx hir::OpaqueTy<'tcx>) -> Self::Result { + self.synthetics.push(associated_type_for_impl_trait_in_trait( + self.tcx, + opaque.def_id, + self.data, + &mut self.disambiguator, + )); + intravisit::walk_opaque_ty(self, opaque) } } @@ -194,14 +194,18 @@ fn associated_types_for_impl_traits_in_associated_fn( match tcx.def_kind(parent_def_id) { DefKind::Trait => { - let mut visitor = RPITVisitor { rpits: FxIndexSet::default() }; - if let Some(output) = tcx.hir_get_fn_output(fn_def_id) { + let data = DefPathData::AnonAssocTy(tcx.item_name(fn_def_id.to_def_id())); + let mut visitor = RPITVisitor { + tcx, + synthetics: vec![], + data, + disambiguator: DisambiguatorState::with(parent_def_id, data, 0), + }; visitor.visit_fn_ret_ty(output); - - tcx.arena.alloc_from_iter(visitor.rpits.iter().map(|opaque_ty_def_id| { - tcx.associated_type_for_impl_trait_in_trait(opaque_ty_def_id).to_def_id() - })) + tcx.arena.alloc_from_iter( + visitor.synthetics.into_iter().map(|def_id| def_id.to_def_id()), + ) } else { &[] } @@ -211,7 +215,6 @@ fn associated_types_for_impl_traits_in_associated_fn( let Some(trait_fn_def_id) = tcx.associated_item(fn_def_id).trait_item_def_id else { return &[]; }; - tcx.arena.alloc_from_iter( tcx.associated_types_for_impl_traits_in_associated_fn(trait_fn_def_id).iter().map( move |&trait_assoc_def_id| { @@ -236,6 +239,8 @@ fn associated_types_for_impl_traits_in_associated_fn( fn associated_type_for_impl_trait_in_trait( tcx: TyCtxt<'_>, opaque_ty_def_id: LocalDefId, + data: DefPathData, + disambiguator: &mut DisambiguatorState, ) -> LocalDefId { let (hir::OpaqueTyOrigin::FnReturn { parent: fn_def_id, .. } | hir::OpaqueTyOrigin::AsyncFn { parent: fn_def_id, .. }) = @@ -246,22 +251,15 @@ fn associated_type_for_impl_trait_in_trait( let trait_def_id = tcx.local_parent(fn_def_id); assert_eq!(tcx.def_kind(trait_def_id), DefKind::Trait); - // Collect all opaque types in return position for the method and use - // the index as the disambiguator to make an unique def path. - let mut visitor = RPITVisitor { rpits: FxIndexSet::default() }; - visitor.visit_fn_ret_ty(tcx.hir_get_fn_output(fn_def_id).unwrap()); - let disambiguator = visitor.rpits.get_index_of(&opaque_ty_def_id).unwrap().try_into().unwrap(); - let span = tcx.def_span(opaque_ty_def_id); // Also use the method name to create an unique def path. - let data = DefPathData::AnonAssocTy(tcx.item_name(fn_def_id.to_def_id())); let trait_assoc_ty = tcx.at(span).create_def( trait_def_id, // No name because this is an anonymous associated type. None, DefKind::AssocTy, Some(data), - &mut DisambiguatorState::with(trait_def_id, data, disambiguator), + disambiguator, ); let local_def_id = trait_assoc_ty.def_id(); diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 5bd82560da7ed..ee7a882a13c9d 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -3031,6 +3031,61 @@ impl Vec { (initialized, spare, &mut self.len) } } + + /// Groups every `N` elements in the `Vec` into chunks to produce a `Vec<[T; N]>`, dropping + /// elements in the remainder. `N` must be greater than zero. + /// + /// If the capacity is not a multiple of the chunk size, the buffer will shrink down to the + /// nearest multiple with a reallocation or deallocation. + /// + /// This function can be used to reverse [`Vec::into_flattened`]. + /// + /// # Examples + /// + /// ``` + /// #![feature(vec_into_chunks)] + /// + /// let vec = vec![0, 1, 2, 3, 4, 5, 6, 7]; + /// assert_eq!(vec.into_chunks::<3>(), [[0, 1, 2], [3, 4, 5]]); + /// + /// let vec = vec![0, 1, 2, 3]; + /// let chunks: Vec<[u8; 10]> = vec.into_chunks(); + /// assert!(chunks.is_empty()); + /// + /// let flat = vec![0; 8 * 8 * 8]; + /// let reshaped: Vec<[[[u8; 8]; 8]; 8]> = flat.into_chunks().into_chunks().into_chunks(); + /// assert_eq!(reshaped.len(), 1); + /// ``` + #[cfg(not(no_global_oom_handling))] + #[unstable(feature = "vec_into_chunks", issue = "142137")] + pub fn into_chunks(mut self) -> Vec<[T; N], A> { + const { + assert!(N != 0, "chunk size must be greater than zero"); + } + + let (len, cap) = (self.len(), self.capacity()); + + let len_remainder = len % N; + if len_remainder != 0 { + self.truncate(len - len_remainder); + } + + let cap_remainder = cap % N; + if !T::IS_ZST && cap_remainder != 0 { + self.buf.shrink_to_fit(cap - cap_remainder); + } + + let (ptr, _, _, alloc) = self.into_raw_parts_with_alloc(); + + // SAFETY: + // - `ptr` and `alloc` were just returned from `self.into_raw_parts_with_alloc()` + // - `[T; N]` has the same alignment as `T` + // - `size_of::<[T; N]>() * cap / N == size_of::() * cap` + // - `len / N <= cap / N` because `len <= cap` + // - the allocated memory consists of `len / N` valid values of type `[T; N]` + // - `cap / N` fits the size of the allocated memory after shrinking + unsafe { Vec::from_raw_parts_in(ptr.cast(), len / N, cap / N, alloc) } + } } impl Vec { diff --git a/library/rustc-std-workspace-core/Cargo.toml b/library/rustc-std-workspace-core/Cargo.toml index bd318fc2f9e9c..1ddc112380f16 100644 --- a/library/rustc-std-workspace-core/Cargo.toml +++ b/library/rustc-std-workspace-core/Cargo.toml @@ -1,3 +1,5 @@ +cargo-features = ["public-dependency"] + [package] name = "rustc-std-workspace-core" version = "1.99.0" @@ -11,5 +13,7 @@ edition = "2024" path = "lib.rs" [dependencies] -core = { path = "../core" } -compiler_builtins = { path = "../compiler-builtins/compiler-builtins", features = ["compiler-builtins"] } +core = { path = "../core", public = true } +compiler_builtins = { path = "../compiler-builtins/compiler-builtins", features = [ + "compiler-builtins", +] } diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs index d9902d41928c5..8f6c8386c25dc 100644 --- a/library/std/src/fs.rs +++ b/library/std/src/fs.rs @@ -4,6 +4,27 @@ //! filesystem. All methods in this module represent cross-platform filesystem //! operations. Extra platform-specific functionality can be found in the //! extension traits of `std::os::$platform`. +//! +//! # Time of Check to Time of Use (TOCTOU) +//! +//! Many filesystem operations are subject to a race condition known as "Time of Check to Time of Use" +//! (TOCTOU). This occurs when a program checks a condition (like file existence or permissions) +//! and then uses the result of that check to make a decision, but the condition may have changed +//! between the check and the use. +//! +//! For example, checking if a file exists and then creating it if it doesn't is vulnerable to +//! TOCTOU - another process could create the file between your check and creation attempt. +//! +//! Another example is with symbolic links: when removing a directory, if another process replaces +//! the directory with a symbolic link between the check and the removal operation, the removal +//! might affect the wrong location. This is why operations like [`remove_dir_all`] need to use +//! atomic operations to prevent such race conditions. +//! +//! To avoid TOCTOU issues: +//! - Be aware that metadata operations (like [`metadata`] or [`symlink_metadata`]) may be affected by +//! changes made by other processes. +//! - Use atomic operations when possible (like [`File::create_new`] instead of checking existence then creating). +//! - Keep file open for the duration of operations. #![stable(feature = "rust1", since = "1.0.0")] #![deny(unsafe_op_in_unsafe_fn)] @@ -548,13 +569,14 @@ impl File { /// non-exhaustive list of likely errors. /// /// This option is useful because it is atomic. Otherwise between checking whether a file - /// exists and creating a new one, the file may have been created by another process (a TOCTOU + /// exists and creating a new one, the file may have been created by another process (a [TOCTOU] /// race condition / attack). /// /// This can also be written using /// `File::options().read(true).write(true).create_new(true).open(...)`. /// /// [`AlreadyExists`]: crate::io::ErrorKind::AlreadyExists + /// [TOCTOU]: self#time-of-check-to-time-of-use-toctou /// /// # Examples /// @@ -1610,7 +1632,7 @@ impl OpenOptions { /// /// This option is useful because it is atomic. Otherwise between checking /// whether a file exists and creating a new one, the file may have been - /// created by another process (a TOCTOU race condition / attack). + /// created by another process (a [TOCTOU] race condition / attack). /// /// If `.create_new(true)` is set, [`.create()`] and [`.truncate()`] are /// ignored. @@ -1621,6 +1643,7 @@ impl OpenOptions { /// [`.create()`]: OpenOptions::create /// [`.truncate()`]: OpenOptions::truncate /// [`AlreadyExists`]: io::ErrorKind::AlreadyExists + /// [TOCTOU]: self#time-of-check-to-time-of-use-toctou /// /// # Examples /// @@ -2954,17 +2977,17 @@ pub fn remove_dir>(path: P) -> io::Result<()> { /// `GetFileInformationByHandleEx`, `SetFileInformationByHandle`, and `NtCreateFile`. /// /// ## Time-of-check to time-of-use (TOCTOU) race conditions -/// On a few platforms there is no way to remove a directory's contents without following symlinks -/// unless you perform a check and then operate on paths based on that directory. -/// This allows concurrently-running code to replace the directory with a symlink after the check, -/// causing a removal to instead operate on a path based on the symlink. This is a TOCTOU race. -/// By default, `fs::remove_dir_all` protects against a symlink TOCTOU race on all platforms -/// except the following. It should not be used in security-sensitive contexts on these platforms: -/// - Miri: Even when emulating targets where the underlying implementation will protect against -/// TOCTOU races, Miri will not do so. -/// - Redox OS: This function does not protect against TOCTOU races, as Redox does not implement -/// the required platform support to do so. +/// See the [module-level TOCTOU explanation](self#time-of-check-to-time-of-use-toctou). +/// +/// On most platforms, `fs::remove_dir_all` protects against symlink TOCTOU races by default. +/// However, on the following platforms, this protection is not provided and the function should +/// not be used in security-sensitive contexts: +/// - **Miri**: Even when emulating targets where the underlying implementation will protect against +/// TOCTOU races, Miri will not do so. +/// - **Redox OS**: This function does not protect against TOCTOU races, as Redox does not implement +/// the required platform support to do so. /// +/// [TOCTOU]: self#time-of-check-to-time-of-use-toctou /// [changes]: io#platform-specific-behavior /// /// # Errors @@ -3238,7 +3261,7 @@ impl AsInnerMut for DirBuilder { /// permission is denied on one of the parent directories. /// /// Note that while this avoids some pitfalls of the `exists()` method, it still can not -/// prevent time-of-check to time-of-use (TOCTOU) bugs. You should only use it in scenarios +/// prevent time-of-check to time-of-use ([TOCTOU]) bugs. You should only use it in scenarios /// where those bugs are not an issue. /// /// # Examples @@ -3251,6 +3274,7 @@ impl AsInnerMut for DirBuilder { /// ``` /// /// [`Path::exists`]: crate::path::Path::exists +/// [TOCTOU]: self#time-of-check-to-time-of-use-toctou #[stable(feature = "fs_try_exists", since = "1.81.0")] #[inline] pub fn exists>(path: P) -> io::Result { diff --git a/library/std/src/path.rs b/library/std/src/path.rs index b734d2b324c08..0ce20a143df4c 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -3127,7 +3127,7 @@ impl Path { /// Returns `true` if the path points at an existing entity. /// /// Warning: this method may be error-prone, consider using [`try_exists()`] instead! - /// It also has a risk of introducing time-of-check to time-of-use (TOCTOU) bugs. + /// It also has a risk of introducing time-of-check to time-of-use ([TOCTOU]) bugs. /// /// This function will traverse symbolic links to query information about the /// destination file. @@ -3148,6 +3148,7 @@ impl Path { /// check errors, call [`Path::try_exists`]. /// /// [`try_exists()`]: Self::try_exists + /// [TOCTOU]: fs#time-of-check-to-time-of-use-toctou #[stable(feature = "path_ext", since = "1.5.0")] #[must_use] #[inline] @@ -3167,7 +3168,7 @@ impl Path { /// permission is denied on one of the parent directories. /// /// Note that while this avoids some pitfalls of the `exists()` method, it still can not - /// prevent time-of-check to time-of-use (TOCTOU) bugs. You should only use it in scenarios + /// prevent time-of-check to time-of-use ([TOCTOU]) bugs. You should only use it in scenarios /// where those bugs are not an issue. /// /// This is an alias for [`std::fs::exists`](crate::fs::exists). @@ -3180,6 +3181,7 @@ impl Path { /// assert!(Path::new("/root/secret_file.txt").try_exists().is_err()); /// ``` /// + /// [TOCTOU]: fs#time-of-check-to-time-of-use-toctou /// [`exists()`]: Self::exists #[stable(feature = "path_try_exists", since = "1.63.0")] #[inline] diff --git a/src/ci/citool/src/jobs.rs b/src/ci/citool/src/jobs.rs index 81e002edb1565..31c761d16703f 100644 --- a/src/ci/citool/src/jobs.rs +++ b/src/ci/citool/src/jobs.rs @@ -66,6 +66,8 @@ pub struct JobDatabase { pub try_jobs: Vec, #[serde(rename = "auto")] pub auto_jobs: Vec, + #[serde(rename = "optional")] + pub optional_jobs: Vec, /// Shared environments for the individual run types. envs: JobEnvironments, @@ -75,9 +77,10 @@ impl JobDatabase { /// Find `auto` jobs that correspond to the passed `pattern`. /// Patterns are matched using the glob syntax. /// For example `dist-*` matches all jobs starting with `dist-`. - fn find_auto_jobs_by_pattern(&self, pattern: &str) -> Vec { + fn find_auto_or_optional_jobs_by_pattern(&self, pattern: &str) -> Vec { self.auto_jobs .iter() + .chain(self.optional_jobs.iter()) .filter(|j| glob_match::glob_match(pattern, &j.name)) .cloned() .collect() @@ -181,7 +184,7 @@ fn calculate_jobs( let mut jobs: Vec = vec![]; let mut unknown_patterns = vec![]; for pattern in patterns { - let matched_jobs = db.find_auto_jobs_by_pattern(pattern); + let matched_jobs = db.find_auto_or_optional_jobs_by_pattern(pattern); if matched_jobs.is_empty() { unknown_patterns.push(pattern.clone()); } else { diff --git a/src/ci/citool/src/jobs/tests.rs b/src/ci/citool/src/jobs/tests.rs index ed5444d4333d3..63ac508b632eb 100644 --- a/src/ci/citool/src/jobs/tests.rs +++ b/src/ci/citool/src/jobs/tests.rs @@ -46,6 +46,13 @@ auto: - name: test-msvc-i686-2 os: ubuntu env: {} +optional: + - name: optional-job-1 + os: ubuntu + env: {} + - name: optional-dist-x86_64 + os: ubuntu + env: {} "#, ) .unwrap(); @@ -57,12 +64,18 @@ auto: "*i686*", &["test-i686", "dist-i686", "test-msvc-i686-1", "test-msvc-i686-2"], ); + // Test that optional jobs are found + check_pattern(&db, "optional-*", &["optional-job-1", "optional-dist-x86_64"]); + check_pattern(&db, "*optional*", &["optional-job-1", "optional-dist-x86_64"]); } #[track_caller] fn check_pattern(db: &JobDatabase, pattern: &str, expected: &[&str]) { - let jobs = - db.find_auto_jobs_by_pattern(pattern).into_iter().map(|j| j.name).collect::>(); + let jobs = db + .find_auto_or_optional_jobs_by_pattern(pattern) + .into_iter() + .map(|j| j.name) + .collect::>(); assert_eq!(jobs, expected); } @@ -116,8 +129,13 @@ fn validate_jobs() { load_job_db(&db_str).expect("Failed to load job database") }; - let all_jobs = - db.pr_jobs.iter().chain(db.try_jobs.iter()).chain(db.auto_jobs.iter()).collect::>(); + let all_jobs = db + .pr_jobs + .iter() + .chain(db.try_jobs.iter()) + .chain(db.auto_jobs.iter()) + .chain(db.optional_jobs.iter()) + .collect::>(); let errors: Vec = all_jobs.into_iter().filter_map(|job| validate_codebuild_image(job).err()).collect(); diff --git a/src/ci/citool/tests/test-jobs.yml b/src/ci/citool/tests/test-jobs.yml index d262da1110255..7b349ceba3f5b 100644 --- a/src/ci/citool/tests/test-jobs.yml +++ b/src/ci/citool/tests/test-jobs.yml @@ -139,3 +139,8 @@ auto: DIST_REQUIRE_ALL_TOOLS: 1 CODEGEN_BACKENDS: llvm,cranelift <<: *job-windows + +# Jobs that only run when explicitly invoked via `@bors try`. +optional: + - name: test-optional-job + <<: *job-linux-4c diff --git a/src/ci/docker/host-aarch64/aarch64-gnu/Dockerfile b/src/ci/docker/host-aarch64/aarch64-gnu/Dockerfile index d5027589e0bd6..e6133fce83e28 100644 --- a/src/ci/docker/host-aarch64/aarch64-gnu/Dockerfile +++ b/src/ci/docker/host-aarch64/aarch64-gnu/Dockerfile @@ -26,6 +26,5 @@ ENV RUST_CONFIGURE_ARGS \ --enable-sanitizers \ --enable-profiler \ --enable-compiler-docs -# FIXME: Skipping cargo panic_abort_doc_tests due to https://github.com/rust-lang/rust/issues/123733 ENV SCRIPT python3 ../x.py --stage 2 test && \ - python3 ../x.py --stage 2 test src/tools/cargo --test-args \"--skip panic_abort_doc_tests\" + python3 ../x.py --stage 2 test src/tools/cargo diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml index 3aa435003d3be..1e253131c1afe 100644 --- a/src/ci/github-actions/jobs.yml +++ b/src/ci/github-actions/jobs.yml @@ -160,6 +160,17 @@ pr: try: - <<: *job-dist-x86_64-linux +# Jobs that only run when explicitly invoked in one of the following ways: +# - comment `@bors2 try jobs=` +# - `try-job: ` in the PR description and comment `@bors try` or `@bors2 try`. +optional: + # This job is used just to test optional jobs. + # It will be replaced by tier 2 and tier 3 jobs in the future. + - name: optional-mingw-check-1 + env: + IMAGE: mingw-check-1 + <<: *job-linux-4c + # Main CI jobs that have to be green to merge a commit into master # These jobs automatically inherit envs.auto, to avoid repeating # it in each job definition. diff --git a/src/librustdoc/clean/blanket_impl.rs b/src/librustdoc/clean/blanket_impl.rs index c889f52b789a4..11d5b472d738b 100644 --- a/src/librustdoc/clean/blanket_impl.rs +++ b/src/librustdoc/clean/blanket_impl.rs @@ -23,7 +23,7 @@ pub(crate) fn synthesize_blanket_impls( let ty = tcx.type_of(item_def_id); let mut blanket_impls = Vec::new(); - for trait_def_id in tcx.all_traits() { + for trait_def_id in tcx.visible_traits() { if !cx.cache.effective_visibilities.is_reachable(tcx, trait_def_id) || cx.generated_synthetics.contains(&(ty.skip_binder(), trait_def_id)) { diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index cf3c4ac97af63..bd57bb21e639b 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -353,7 +353,7 @@ pub(crate) fn run_global_ctxt( rustc_passes::stability::check_unused_or_stable_features(tcx); let auto_traits = - tcx.all_traits().filter(|&trait_def_id| tcx.trait_is_auto(trait_def_id)).collect(); + tcx.visible_traits().filter(|&trait_def_id| tcx.trait_is_auto(trait_def_id)).collect(); let mut ctxt = DocContext { tcx, diff --git a/src/tools/compiletest/src/directive-list.rs b/src/tools/compiletest/src/directive-list.rs index 2ecb4fc865213..adf2a7bffeff9 100644 --- a/src/tools/compiletest/src/directive-list.rs +++ b/src/tools/compiletest/src/directive-list.rs @@ -1,6 +1,6 @@ /// This was originally generated by collecting directives from ui tests and then extracting their /// directive names. This is **not** an exhaustive list of all possible directives. Instead, this is -/// a best-effort approximation for diagnostics. Add new headers to this list when needed. +/// a best-effort approximation for diagnostics. Add new directives to this list when needed. const KNOWN_DIRECTIVE_NAMES: &[&str] = &[ // tidy-alphabetical-start "add-core-stubs", diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/directives.rs similarity index 98% rename from src/tools/compiletest/src/header.rs rename to src/tools/compiletest/src/directives.rs index 5636a146b0f4d..a6242cf0c225a 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/directives.rs @@ -11,10 +11,10 @@ use tracing::*; use crate::common::{Config, Debugger, FailMode, Mode, PassMode}; use crate::debuggers::{extract_cdb_version, extract_gdb_version}; +use crate::directives::auxiliary::{AuxProps, parse_and_update_aux}; +use crate::directives::needs::CachedNeedsConditions; use crate::errors::ErrorKind; use crate::executor::{CollectedTestDesc, ShouldPanic}; -use crate::header::auxiliary::{AuxProps, parse_and_update_aux}; -use crate::header::needs::CachedNeedsConditions; use crate::help; use crate::util::static_regex; @@ -24,11 +24,11 @@ mod needs; #[cfg(test)] mod tests; -pub struct HeadersCache { +pub struct DirectivesCache { needs: CachedNeedsConditions, } -impl HeadersCache { +impl DirectivesCache { pub fn load(config: &Config) -> Self { Self { needs: CachedNeedsConditions::load(config) } } @@ -54,7 +54,7 @@ impl EarlyProps { pub fn from_reader(config: &Config, testfile: &Utf8Path, rdr: R) -> Self { let mut props = EarlyProps::default(); let mut poisoned = false; - iter_header( + iter_directives( config.mode, &config.suite, &mut poisoned, @@ -138,12 +138,12 @@ pub struct TestProps { pub incremental_dir: Option, // If `true`, this test will use incremental compilation. // - // This can be set manually with the `incremental` header, or implicitly + // This can be set manually with the `incremental` directive, or implicitly // by being a part of an incremental mode test. Using the `incremental` - // header should be avoided if possible; using an incremental mode test is + // directive should be avoided if possible; using an incremental mode test is // preferred. Incremental mode tests support multiple passes, which can // verify that the incremental cache can be loaded properly after being - // created. Just setting the header will only verify the behavior with + // created. Just setting the directive will only verify the behavior with // creating an incremental cache, but doesn't check that it is created // correctly. // @@ -347,7 +347,7 @@ impl TestProps { let mut poisoned = false; - iter_header( + iter_directives( config.mode, &config.suite, &mut poisoned, @@ -642,11 +642,11 @@ impl TestProps { let check_ui = |mode: &str| { // Mode::Crashes may need build-fail in order to trigger llvm errors or stack overflows if config.mode != Mode::Ui && config.mode != Mode::Crashes { - panic!("`{}-fail` header is only supported in UI tests", mode); + panic!("`{}-fail` directive is only supported in UI tests", mode); } }; if config.mode == Mode::Ui && config.parse_name_directive(ln, "compile-fail") { - panic!("`compile-fail` header is useless in UI tests"); + panic!("`compile-fail` directive is useless in UI tests"); } let fail_mode = if config.parse_name_directive(ln, "check-fail") { check_ui("check"); @@ -662,7 +662,7 @@ impl TestProps { }; match (self.fail_mode, fail_mode) { (None, Some(_)) => self.fail_mode = fail_mode, - (Some(_), Some(_)) => panic!("multiple `*-fail` headers in a single test"), + (Some(_), Some(_)) => panic!("multiple `*-fail` directives in a single test"), (_, None) => {} } } @@ -674,10 +674,10 @@ impl TestProps { (Mode::Codegen, "build-pass") => (), (Mode::Incremental, _) => { if revision.is_some() && !self.revisions.iter().all(|r| r.starts_with("cfail")) { - panic!("`{s}` header is only supported in `cfail` incremental tests") + panic!("`{s}` directive is only supported in `cfail` incremental tests") } } - (mode, _) => panic!("`{s}` header is not supported in `{mode}` tests"), + (mode, _) => panic!("`{s}` directive is not supported in `{mode}` tests"), }; let pass_mode = if config.parse_name_directive(ln, "check-pass") { check_no_run("check-pass"); @@ -693,7 +693,7 @@ impl TestProps { }; match (self.pass_mode, pass_mode) { (None, Some(_)) => self.pass_mode = pass_mode, - (Some(_), Some(_)) => panic!("multiple `*-pass` headers in a single test"), + (Some(_), Some(_)) => panic!("multiple `*-pass` directives in a single test"), (_, None) => {} } } @@ -794,7 +794,7 @@ const KNOWN_JSONDOCCK_DIRECTIVE_NAMES: &[&str] = &["count", "!count", "has", "!has", "is", "!is", "ismany", "!ismany", "set", "!set"]; /// The (partly) broken-down contents of a line containing a test directive, -/// which [`iter_header`] passes to its callback function. +/// which [`iter_directives`] passes to its callback function. /// /// For example: /// @@ -867,7 +867,7 @@ pub(crate) fn check_directive<'a>( const COMPILETEST_DIRECTIVE_PREFIX: &str = "//@"; -fn iter_header( +fn iter_directives( mode: Mode, _suite: &str, poisoned: &mut bool, @@ -1163,8 +1163,7 @@ enum NormalizeKind { Stderr64bit, } -/// Parses the regex and replacement values of a `//@ normalize-*` header, -/// in the format: +/// Parses the regex and replacement values of a `//@ normalize-*` directive, in the format: /// ```text /// "REGEX" -> "REPLACEMENT" /// ``` @@ -1373,7 +1372,7 @@ where pub(crate) fn make_test_description( config: &Config, - cache: &HeadersCache, + cache: &DirectivesCache, name: String, path: &Utf8Path, src: R, @@ -1387,7 +1386,7 @@ pub(crate) fn make_test_description( let mut local_poisoned = false; // Scan through the test file to handle `ignore-*`, `only-*`, and `needs-*` directives. - iter_header( + iter_directives( config.mode, &config.suite, &mut local_poisoned, diff --git a/src/tools/compiletest/src/header/auxiliary.rs b/src/tools/compiletest/src/directives/auxiliary.rs similarity index 96% rename from src/tools/compiletest/src/header/auxiliary.rs rename to src/tools/compiletest/src/directives/auxiliary.rs index 0e1f3a785f87f..cdb75f6ffa907 100644 --- a/src/tools/compiletest/src/header/auxiliary.rs +++ b/src/tools/compiletest/src/directives/auxiliary.rs @@ -3,8 +3,8 @@ use std::iter; +use super::directives::{AUX_BIN, AUX_BUILD, AUX_CODEGEN_BACKEND, AUX_CRATE, PROC_MACRO}; use crate::common::Config; -use crate::header::directives::{AUX_BIN, AUX_BUILD, AUX_CODEGEN_BACKEND, AUX_CRATE, PROC_MACRO}; /// Properties parsed from `aux-*` test directives. #[derive(Clone, Debug, Default)] diff --git a/src/tools/compiletest/src/header/cfg.rs b/src/tools/compiletest/src/directives/cfg.rs similarity index 99% rename from src/tools/compiletest/src/header/cfg.rs rename to src/tools/compiletest/src/directives/cfg.rs index f1f1384afb971..35f6a9e164486 100644 --- a/src/tools/compiletest/src/header/cfg.rs +++ b/src/tools/compiletest/src/directives/cfg.rs @@ -1,7 +1,7 @@ use std::collections::HashSet; use crate::common::{CompareMode, Config, Debugger}; -use crate::header::IgnoreDecision; +use crate::directives::IgnoreDecision; const EXTRA_ARCHS: &[&str] = &["spirv"]; diff --git a/src/tools/compiletest/src/header/needs.rs b/src/tools/compiletest/src/directives/needs.rs similarity index 99% rename from src/tools/compiletest/src/header/needs.rs rename to src/tools/compiletest/src/directives/needs.rs index b1165f4bb184f..ee46f4c70cb8c 100644 --- a/src/tools/compiletest/src/header/needs.rs +++ b/src/tools/compiletest/src/directives/needs.rs @@ -1,5 +1,5 @@ use crate::common::{Config, KNOWN_CRATE_TYPES, KNOWN_TARGET_HAS_ATOMIC_WIDTHS, Sanitizer}; -use crate::header::{IgnoreDecision, llvm_has_libzstd}; +use crate::directives::{IgnoreDecision, llvm_has_libzstd}; pub(super) fn handle_needs( cache: &CachedNeedsConditions, diff --git a/src/tools/compiletest/src/header/test-auxillary/error_annotation.rs b/src/tools/compiletest/src/directives/test-auxillary/error_annotation.rs similarity index 100% rename from src/tools/compiletest/src/header/test-auxillary/error_annotation.rs rename to src/tools/compiletest/src/directives/test-auxillary/error_annotation.rs diff --git a/src/tools/compiletest/src/header/test-auxillary/known_directive.rs b/src/tools/compiletest/src/directives/test-auxillary/known_directive.rs similarity index 100% rename from src/tools/compiletest/src/header/test-auxillary/known_directive.rs rename to src/tools/compiletest/src/directives/test-auxillary/known_directive.rs diff --git a/src/tools/compiletest/src/header/test-auxillary/not_rs.Makefile b/src/tools/compiletest/src/directives/test-auxillary/not_rs.Makefile similarity index 100% rename from src/tools/compiletest/src/header/test-auxillary/not_rs.Makefile rename to src/tools/compiletest/src/directives/test-auxillary/not_rs.Makefile diff --git a/src/tools/compiletest/src/header/test-auxillary/unknown_directive.rs b/src/tools/compiletest/src/directives/test-auxillary/unknown_directive.rs similarity index 100% rename from src/tools/compiletest/src/header/test-auxillary/unknown_directive.rs rename to src/tools/compiletest/src/directives/test-auxillary/unknown_directive.rs diff --git a/src/tools/compiletest/src/header/tests.rs b/src/tools/compiletest/src/directives/tests.rs similarity index 99% rename from src/tools/compiletest/src/header/tests.rs rename to src/tools/compiletest/src/directives/tests.rs index 31b49b09bcdc2..d4570f8267781 100644 --- a/src/tools/compiletest/src/header/tests.rs +++ b/src/tools/compiletest/src/directives/tests.rs @@ -4,7 +4,7 @@ use camino::Utf8Path; use semver::Version; use super::{ - EarlyProps, HeadersCache, extract_llvm_version, extract_version_range, iter_header, + DirectivesCache, EarlyProps, extract_llvm_version, extract_version_range, iter_directives, parse_normalize_rule, }; use crate::common::{Config, Debugger, Mode}; @@ -17,9 +17,9 @@ fn make_test_description( src: R, revision: Option<&str>, ) -> CollectedTestDesc { - let cache = HeadersCache::load(config); + let cache = DirectivesCache::load(config); let mut poisoned = false; - let test = crate::header::make_test_description( + let test = crate::directives::make_test_description( config, &cache, name, @@ -785,7 +785,7 @@ fn threads_support() { fn run_path(poisoned: &mut bool, path: &Utf8Path, buf: &[u8]) { let rdr = std::io::Cursor::new(&buf); - iter_header(Mode::Ui, "ui", poisoned, path, rdr, &mut |_| {}); + iter_directives(Mode::Ui, "ui", poisoned, path, rdr, &mut |_| {}); } #[test] diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs index 09de3eb4c7025..dfce4b8b408be 100644 --- a/src/tools/compiletest/src/lib.rs +++ b/src/tools/compiletest/src/lib.rs @@ -12,9 +12,9 @@ pub mod common; pub mod compute_diff; mod debuggers; pub mod diagnostics; +pub mod directives; pub mod errors; mod executor; -pub mod header; mod json; mod raise_fd_limit; mod read2; @@ -37,13 +37,13 @@ use rayon::iter::{ParallelBridge, ParallelIterator}; use tracing::debug; use walkdir::WalkDir; -use self::header::{EarlyProps, make_test_description}; +use self::directives::{EarlyProps, make_test_description}; use crate::common::{ CompareMode, Config, Debugger, Mode, PassMode, TestPaths, UI_EXTENSIONS, expected_output_path, output_base_dir, output_relative_path, }; +use crate::directives::DirectivesCache; use crate::executor::{CollectedTest, ColorConfig, OutputFormat}; -use crate::header::HeadersCache; use crate::util::logv; /// Creates the `Config` instance for this invocation of compiletest. @@ -254,8 +254,8 @@ pub fn parse_config(args: Vec) -> Config { Some(x) => panic!("argument for --color must be auto, always, or never, but found `{}`", x), }; let llvm_version = - matches.opt_str("llvm-version").as_deref().map(header::extract_llvm_version).or_else( - || header::extract_llvm_version_from_binary(&matches.opt_str("llvm-filecheck")?), + matches.opt_str("llvm-version").as_deref().map(directives::extract_llvm_version).or_else( + || directives::extract_llvm_version_from_binary(&matches.opt_str("llvm-filecheck")?), ); let run_ignored = matches.opt_present("ignored"); @@ -618,7 +618,7 @@ pub fn run_tests(config: Arc) { /// Read-only context data used during test collection. struct TestCollectorCx { config: Arc, - cache: HeadersCache, + cache: DirectivesCache, common_inputs_stamp: Stamp, modified_tests: Vec, } @@ -654,7 +654,7 @@ pub(crate) fn collect_and_make_tests(config: Arc) -> Vec modified_tests(&config, &config.src_test_suite_root).unwrap_or_else(|err| { fatal!("modified_tests: {}: {err}", config.src_test_suite_root); }); - let cache = HeadersCache::load(&config); + let cache = DirectivesCache::load(&config); let cx = TestCollectorCx { config, cache, common_inputs_stamp, modified_tests }; let collector = collect_tests_from_dir(&cx, &cx.config.src_test_suite_root, Utf8Path::new("")) diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 53b5990d3cde1..f8bf4ee3022e1 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -23,8 +23,8 @@ use crate::common::{ output_base_dir, output_base_name, output_testname_unique, }; use crate::compute_diff::{DiffLine, make_diff, write_diff, write_filtered_diff}; +use crate::directives::TestProps; use crate::errors::{Error, ErrorKind, load_errors}; -use crate::header::TestProps; use crate::read2::{Truncated, read2_abbreviated}; use crate::util::{Utf8PathBufExt, add_dylib_path, logv, static_regex}; use crate::{ColorConfig, help, json, stamp_file_path, warning}; @@ -2039,7 +2039,7 @@ impl<'test> TestCx<'test> { // Provide more context on failures. filecheck.args(&["--dump-input-context", "100"]); - // Add custom flags supplied by the `filecheck-flags:` test header. + // Add custom flags supplied by the `filecheck-flags:` test directive. filecheck.args(&self.props.filecheck_flags); // FIXME(jieyouxu): don't pass an empty Path diff --git a/src/tools/compiletest/src/runtest/debuginfo.rs b/src/tools/compiletest/src/runtest/debuginfo.rs index 31240dff9a196..d9e1e4dfc8ddf 100644 --- a/src/tools/compiletest/src/runtest/debuginfo.rs +++ b/src/tools/compiletest/src/runtest/debuginfo.rs @@ -49,7 +49,7 @@ impl TestCx<'_> { std::fs::remove_file(pdb_file).unwrap(); } - // compile test file (it should have 'compile-flags:-g' in the header) + // compile test file (it should have 'compile-flags:-g' in the directive) let should_run = self.run_if_enabled(); let compile_result = self.compile_test(should_run, Emit::None); if !compile_result.status.success() { @@ -135,7 +135,7 @@ impl TestCx<'_> { .unwrap_or_else(|e| self.fatal(&e)); let mut cmds = dbg_cmds.commands.join("\n"); - // compile test file (it should have 'compile-flags:-g' in the header) + // compile test file (it should have 'compile-flags:-g' in the directive) let should_run = self.run_if_enabled(); let compiler_run_result = self.compile_test(should_run, Emit::None); if !compiler_run_result.status.success() { @@ -359,7 +359,7 @@ impl TestCx<'_> { } fn run_debuginfo_lldb_test_no_opt(&self) { - // compile test file (it should have 'compile-flags:-g' in the header) + // compile test file (it should have 'compile-flags:-g' in the directive) let should_run = self.run_if_enabled(); let compile_result = self.compile_test(should_run, Emit::None); if !compile_result.status.success() { diff --git a/src/tools/compiletest/src/runtest/ui.rs b/src/tools/compiletest/src/runtest/ui.rs index cc50a918f757a..f6bc85cd051ad 100644 --- a/src/tools/compiletest/src/runtest/ui.rs +++ b/src/tools/compiletest/src/runtest/ui.rs @@ -52,10 +52,10 @@ impl TestCx<'_> { // don't test rustfix with nll right now } else if self.config.rustfix_coverage { // Find out which tests have `MachineApplicable` suggestions but are missing - // `run-rustfix` or `run-rustfix-only-machine-applicable` headers. + // `run-rustfix` or `run-rustfix-only-machine-applicable` directives. // // This will return an empty `Vec` in case the executed test file has a - // `compile-flags: --error-format=xxxx` header with a value other than `json`. + // `compile-flags: --error-format=xxxx` directive with a value other than `json`. let suggestions = get_suggestions_from_json( &rustfix_input, &HashSet::new(), diff --git a/src/tools/rustdoc-gui-test/src/main.rs b/src/tools/rustdoc-gui-test/src/main.rs index addb0af4a541c..6461f38f527b4 100644 --- a/src/tools/rustdoc-gui-test/src/main.rs +++ b/src/tools/rustdoc-gui-test/src/main.rs @@ -4,7 +4,7 @@ use std::sync::Arc; use std::{env, fs}; use build_helper::util::try_run; -use compiletest::header::TestProps; +use compiletest::directives::TestProps; use config::Config; mod config; diff --git a/tests/codegen/transmute-scalar.rs b/tests/codegen/transmute-scalar.rs index c57ade58c30e4..3ac6ba3beb1ee 100644 --- a/tests/codegen/transmute-scalar.rs +++ b/tests/codegen/transmute-scalar.rs @@ -1,6 +1,12 @@ +//@ add-core-stubs //@ compile-flags: -C opt-level=0 -C no-prepopulate-passes #![crate_type = "lib"] +#![feature(no_core, repr_simd, arm_target_feature, mips_target_feature, s390x_target_feature)] +#![no_core] +extern crate minicore; + +use minicore::*; // With opaque ptrs in LLVM, `transmute` can load/store any `alloca` as any type, // without needing to pointercast, and SRoA will turn that into a `bitcast`. @@ -14,7 +20,7 @@ // CHECK-NEXT: ret i32 %_0 #[no_mangle] pub fn f32_to_bits(x: f32) -> u32 { - unsafe { std::mem::transmute(x) } + unsafe { mem::transmute(x) } } // CHECK-LABEL: define{{.*}}i8 @bool_to_byte(i1 zeroext %b) @@ -22,7 +28,7 @@ pub fn f32_to_bits(x: f32) -> u32 { // CHECK-NEXT: ret i8 %_0 #[no_mangle] pub fn bool_to_byte(b: bool) -> u8 { - unsafe { std::mem::transmute(b) } + unsafe { mem::transmute(b) } } // CHECK-LABEL: define{{.*}}zeroext i1 @byte_to_bool(i8{{.*}} %byte) @@ -30,14 +36,14 @@ pub fn bool_to_byte(b: bool) -> u8 { // CHECK-NEXT: ret i1 %_0 #[no_mangle] pub unsafe fn byte_to_bool(byte: u8) -> bool { - std::mem::transmute(byte) + mem::transmute(byte) } // CHECK-LABEL: define{{.*}}ptr @ptr_to_ptr(ptr %p) // CHECK: ret ptr %p #[no_mangle] pub fn ptr_to_ptr(p: *mut u16) -> *mut u8 { - unsafe { std::mem::transmute(p) } + unsafe { mem::transmute(p) } } // CHECK: define{{.*}}[[USIZE:i[0-9]+]] @ptr_to_int(ptr %p) @@ -45,7 +51,7 @@ pub fn ptr_to_ptr(p: *mut u16) -> *mut u8 { // CHECK-NEXT: ret [[USIZE]] %_0 #[no_mangle] pub fn ptr_to_int(p: *mut u16) -> usize { - unsafe { std::mem::transmute(p) } + unsafe { mem::transmute(p) } } // CHECK: define{{.*}}ptr @int_to_ptr([[USIZE]] %i) @@ -53,7 +59,7 @@ pub fn ptr_to_int(p: *mut u16) -> usize { // CHECK-NEXT: ret ptr %_0 #[no_mangle] pub fn int_to_ptr(i: usize) -> *mut u16 { - unsafe { std::mem::transmute(i) } + unsafe { mem::transmute(i) } } // This is the one case where signedness matters to transmuting: @@ -70,7 +76,7 @@ pub enum FakeBoolSigned { // CHECK-NEXT: ret i8 %_0 #[no_mangle] pub fn bool_to_fake_bool_signed(b: bool) -> FakeBoolSigned { - unsafe { std::mem::transmute(b) } + unsafe { mem::transmute(b) } } // CHECK-LABEL: define{{.*}}i1 @fake_bool_signed_to_bool(i8 %b) @@ -78,7 +84,7 @@ pub fn bool_to_fake_bool_signed(b: bool) -> FakeBoolSigned { // CHECK-NEXT: ret i1 %_0 #[no_mangle] pub fn fake_bool_signed_to_bool(b: FakeBoolSigned) -> bool { - unsafe { std::mem::transmute(b) } + unsafe { mem::transmute(b) } } #[repr(u8)] @@ -91,12 +97,41 @@ pub enum FakeBoolUnsigned { // CHECK: ret i1 %b #[no_mangle] pub fn bool_to_fake_bool_unsigned(b: bool) -> FakeBoolUnsigned { - unsafe { std::mem::transmute(b) } + unsafe { mem::transmute(b) } } // CHECK-LABEL: define{{.*}}i1 @fake_bool_unsigned_to_bool(i1 zeroext %b) // CHECK: ret i1 %b #[no_mangle] pub fn fake_bool_unsigned_to_bool(b: FakeBoolUnsigned) -> bool { - unsafe { std::mem::transmute(b) } + unsafe { mem::transmute(b) } +} + +#[repr(simd)] +struct S([i64; 1]); + +// CHECK-LABEL: define{{.*}}i64 @single_element_simd_to_scalar(<1 x i64> %b) +// CHECK: bitcast <1 x i64> %b to i64 +// CHECK: ret i64 +#[no_mangle] +#[cfg_attr(target_family = "wasm", target_feature(enable = "simd128"))] +#[cfg_attr(target_arch = "arm", target_feature(enable = "neon"))] +#[cfg_attr(target_arch = "x86", target_feature(enable = "sse"))] +#[cfg_attr(target_arch = "mips", target_feature(enable = "msa"))] +#[cfg_attr(target_arch = "s390x", target_feature(enable = "vector"))] +pub extern "C" fn single_element_simd_to_scalar(b: S) -> i64 { + unsafe { mem::transmute(b) } +} + +// CHECK-LABEL: define{{.*}}<1 x i64> @scalar_to_single_element_simd(i64 %b) +// CHECK: bitcast i64 %b to <1 x i64> +// CHECK: ret <1 x i64> +#[no_mangle] +#[cfg_attr(target_family = "wasm", target_feature(enable = "simd128"))] +#[cfg_attr(target_arch = "arm", target_feature(enable = "neon"))] +#[cfg_attr(target_arch = "x86", target_feature(enable = "sse"))] +#[cfg_attr(target_arch = "mips", target_feature(enable = "msa"))] +#[cfg_attr(target_arch = "s390x", target_feature(enable = "vector"))] +pub extern "C" fn scalar_to_single_element_simd(b: i64) -> S { + unsafe { mem::transmute(b) } } diff --git a/tests/ui/check-cfg/well-known-values.stderr b/tests/ui/check-cfg/well-known-values.stderr index 532c1ab13d118..2484974cdc27c 100644 --- a/tests/ui/check-cfg/well-known-values.stderr +++ b/tests/ui/check-cfg/well-known-values.stderr @@ -129,7 +129,7 @@ warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` LL | target_abi = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: expected values for `target_abi` are: ``, `abi64`, `abiv2`, `abiv2hf`, `eabi`, `eabihf`, `fortanix`, `ilp32`, `ilp32e`, `llvm`, `macabi`, `sim`, `softfloat`, `spe`, `uwp`, `vec-extabi`, and `x32` + = note: expected values for `target_abi` are: ``, `abi64`, `abiv2`, `abiv2hf`, `eabi`, `eabihf`, `elfv1`, `elfv2`, `fortanix`, `ilp32`, `ilp32e`, `llvm`, `macabi`, `sim`, `softfloat`, `spe`, `uwp`, `vec-extabi`, and `x32` = note: see for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` diff --git a/tests/ui/error-codes/E0637.stderr b/tests/ui/error-codes/E0637.stderr index 95a5a58ab8561..88c08cb94ba8d 100644 --- a/tests/ui/error-codes/E0637.stderr +++ b/tests/ui/error-codes/E0637.stderr @@ -3,6 +3,8 @@ error[E0637]: `'_` cannot be used here | LL | fn underscore_lifetime<'_>(str1: &'_ str, str2: &'_ str) -> &'_ str { | ^^ `'_` is a reserved lifetime name + | + = help: use another lifetime specifier error[E0106]: missing lifetime specifier --> $DIR/E0637.rs:1:62 diff --git a/tests/ui/typeck/auxiliary/private-dep.rs b/tests/ui/typeck/auxiliary/private-dep.rs new file mode 100644 index 0000000000000..472b40ef6229d --- /dev/null +++ b/tests/ui/typeck/auxiliary/private-dep.rs @@ -0,0 +1,3 @@ +pub trait A { + fn foo() {} +} diff --git a/tests/ui/typeck/auxiliary/public-dep.rs b/tests/ui/typeck/auxiliary/public-dep.rs new file mode 100644 index 0000000000000..438692a1caa39 --- /dev/null +++ b/tests/ui/typeck/auxiliary/public-dep.rs @@ -0,0 +1,11 @@ +//@ aux-crate:priv:private_dep=private-dep.rs +//@ compile-flags: -Zunstable-options + +extern crate private_dep; +use private_dep::A; + +pub struct B; + +impl A for B { + fn foo() {} +} diff --git a/tests/ui/typeck/dont-suggest-private-dependencies.rs b/tests/ui/typeck/dont-suggest-private-dependencies.rs new file mode 100644 index 0000000000000..afac00c521310 --- /dev/null +++ b/tests/ui/typeck/dont-suggest-private-dependencies.rs @@ -0,0 +1,30 @@ +// Don't suggest importing a function from a private dependency. +// Issues: #138191, #142676 + +// Avoid suggesting traits from std-private deps +//@ forbid-output: compiler_builtins +//@ forbid-output: object + +// Check a custom trait to withstand changes in above crates +//@ aux-crate:public_dep=public-dep.rs +//@ compile-flags: -Zunstable-options +//@ forbid-output: private_dep + +struct VecReader(Vec); + +impl std::io::Read for VecReader { + fn read(&mut self, buf: &mut [u8]) -> std::io::Result { + self.0.read(buf) + //~^ ERROR no method named `read` found for struct `Vec` + } +} + +extern crate public_dep; +use public_dep::B; + +fn main() { + let _ = u8::cast_from_lossy(9); + //~^ ERROR no function or associated item named `cast_from_lossy` found for type `u8` + let _ = B::foo(); + //~^ ERROR no function or associated item named `foo` found for struct `B` +} diff --git a/tests/ui/typeck/dont-suggest-private-dependencies.stderr b/tests/ui/typeck/dont-suggest-private-dependencies.stderr new file mode 100644 index 0000000000000..0fb1e69c28a21 --- /dev/null +++ b/tests/ui/typeck/dont-suggest-private-dependencies.stderr @@ -0,0 +1,26 @@ +error[E0599]: no method named `read` found for struct `Vec` in the current scope + --> $DIR/dont-suggest-private-dependencies.rs:17:16 + | +LL | self.0.read(buf) + | ^^^^ + | +help: there is a method `read_at` with a similar name + | +LL | self.0.read_at(buf) + | +++ + +error[E0599]: no function or associated item named `cast_from_lossy` found for type `u8` in the current scope + --> $DIR/dont-suggest-private-dependencies.rs:26:17 + | +LL | let _ = u8::cast_from_lossy(9); + | ^^^^^^^^^^^^^^^ function or associated item not found in `u8` + +error[E0599]: no function or associated item named `foo` found for struct `B` in the current scope + --> $DIR/dont-suggest-private-dependencies.rs:28:16 + | +LL | let _ = B::foo(); + | ^^^ function or associated item not found in `B` + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0599`. diff --git a/tests/ui/underscore-lifetime/in-binder.stderr b/tests/ui/underscore-lifetime/in-binder.stderr index fcd7eddb57605..f25db4d088982 100644 --- a/tests/ui/underscore-lifetime/in-binder.stderr +++ b/tests/ui/underscore-lifetime/in-binder.stderr @@ -3,36 +3,48 @@ error[E0637]: `'_` cannot be used here | LL | impl<'_> IceCube<'_> {} | ^^ `'_` is a reserved lifetime name + | + = help: use another lifetime specifier error[E0637]: `'_` cannot be used here --> $DIR/in-binder.rs:12:15 | LL | struct Struct<'_> { | ^^ `'_` is a reserved lifetime name + | + = help: use another lifetime specifier error[E0637]: `'_` cannot be used here --> $DIR/in-binder.rs:17:11 | LL | enum Enum<'_> { | ^^ `'_` is a reserved lifetime name + | + = help: use another lifetime specifier error[E0637]: `'_` cannot be used here --> $DIR/in-binder.rs:22:13 | LL | union Union<'_> { | ^^ `'_` is a reserved lifetime name + | + = help: use another lifetime specifier error[E0637]: `'_` cannot be used here --> $DIR/in-binder.rs:27:13 | LL | trait Trait<'_> { | ^^ `'_` is a reserved lifetime name + | + = help: use another lifetime specifier error[E0637]: `'_` cannot be used here --> $DIR/in-binder.rs:31:8 | LL | fn foo<'_>() { | ^^ `'_` is a reserved lifetime name + | + = help: use another lifetime specifier error: aborting due to 6 previous errors diff --git a/tests/ui/underscore-lifetime/underscore-lifetime-binders.stderr b/tests/ui/underscore-lifetime/underscore-lifetime-binders.stderr index d940166e9e28b..50359309c927b 100644 --- a/tests/ui/underscore-lifetime/underscore-lifetime-binders.stderr +++ b/tests/ui/underscore-lifetime/underscore-lifetime-binders.stderr @@ -15,12 +15,16 @@ error[E0637]: `'_` cannot be used here | LL | fn foo<'_> | ^^ `'_` is a reserved lifetime name + | + = help: use another lifetime specifier error[E0637]: `'_` cannot be used here --> $DIR/underscore-lifetime-binders.rs:10:25 | LL | fn meh() -> Box Meh<'_>> | ^^ `'_` is a reserved lifetime name + | + = help: use another lifetime specifier error[E0106]: missing lifetime specifier --> $DIR/underscore-lifetime-binders.rs:10:33