diff options
125 files changed, 1070 insertions, 327 deletions
diff --git a/Cargo.lock b/Cargo.lock index cff5864dbbe..8be13e84596 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -674,7 +674,7 @@ checksum = "fe6d2e5af09e8c8ad56c969f2157a3d4238cebc7c55f0a517728c38f7b200f81" dependencies = [ "serde", "termcolor", - "unicode-width 0.2.1", + "unicode-width 0.1.14", ] [[package]] @@ -1458,9 +1458,9 @@ dependencies = [ [[package]] name = "getopts" -version = "0.2.23" +version = "0.2.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cba6ae63eb948698e300f645f87c70f76630d505f23b8907cf1e193ee85048c1" +checksum = "cfe4fbac503b8d1f88e6676011885f34b7174f46e59956bba534ba83abded4df" dependencies = [ "unicode-width 0.2.1", ] diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 3674814b796..bb6b25baf01 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -1536,7 +1536,13 @@ impl<'hir> LoweringContext<'_, 'hir> { hir::LangItem::Range } } - (None, Some(..), Closed) => hir::LangItem::RangeToInclusive, + (None, Some(..), Closed) => { + if self.tcx.features().new_range() { + hir::LangItem::RangeToInclusiveCopy + } else { + hir::LangItem::RangeToInclusive + } + } (Some(e1), Some(e2), Closed) => { if self.tcx.features().new_range() { hir::LangItem::RangeInclusiveCopy @@ -1560,13 +1566,26 @@ impl<'hir> LoweringContext<'_, 'hir> { }; let fields = self.arena.alloc_from_iter( - e1.iter().map(|e| (sym::start, e)).chain(e2.iter().map(|e| (sym::end, e))).map( - |(s, e)| { + e1.iter() + .map(|e| (sym::start, e)) + .chain(e2.iter().map(|e| { + ( + if matches!( + lang_item, + hir::LangItem::RangeInclusiveCopy | hir::LangItem::RangeToInclusiveCopy + ) { + sym::last + } else { + sym::end + }, + e, + ) + })) + .map(|(s, e)| { let expr = self.lower_expr(e); let ident = Ident::new(s, self.lower_span(e.span)); self.expr_field(ident, expr, e.span) - }, - ), + }), ); hir::ExprKind::Struct( diff --git a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs index ffdacff7152..d5d51f2e79a 100644 --- a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs @@ -218,6 +218,7 @@ impl<S: Stage> AttributeParser<S> for NakedParser { sym::rustc_std_internal_symbol, // FIXME(#82232, #143834): temporarily renamed to mitigate `#[align]` nameres ambiguity sym::rustc_align, + sym::rustc_align_static, // obviously compatible with self sym::naked, // documentation diff --git a/compiler/rustc_attr_parsing/src/attributes/repr.rs b/compiler/rustc_attr_parsing/src/attributes/repr.rs index 23aabd15597..0330e2515c7 100644 --- a/compiler/rustc_attr_parsing/src/attributes/repr.rs +++ b/compiler/rustc_attr_parsing/src/attributes/repr.rs @@ -331,3 +331,30 @@ impl<S: Stage> AttributeParser<S> for AlignParser { Some(AttributeKind::Align { align, span }) } } + +#[derive(Default)] +pub(crate) struct AlignStaticParser(AlignParser); + +impl AlignStaticParser { + const PATH: &'static [Symbol] = &[sym::rustc_align_static]; + const TEMPLATE: AttributeTemplate = AlignParser::TEMPLATE; + + fn parse<'c, S: Stage>( + &mut self, + cx: &'c mut AcceptContext<'_, '_, S>, + args: &'c ArgParser<'_>, + ) { + self.0.parse(cx, args) + } +} + +impl<S: Stage> AttributeParser<S> for AlignStaticParser { + const ATTRIBUTES: AcceptMapping<Self, S> = &[(Self::PATH, Self::TEMPLATE, Self::parse)]; + const ALLOWED_TARGETS: AllowedTargets = + AllowedTargets::AllowList(&[Allow(Target::Static), Allow(Target::ForeignStatic)]); + + fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> { + let (align, span) = self.0.0?; + Some(AttributeKind::Align { align, span }) + } +} diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 98e86838a3a..d2b35090135 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -50,7 +50,7 @@ use crate::attributes::proc_macro_attrs::{ ProcMacroAttributeParser, ProcMacroDeriveParser, ProcMacroParser, RustcBuiltinMacroParser, }; use crate::attributes::prototype::CustomMirParser; -use crate::attributes::repr::{AlignParser, ReprParser}; +use crate::attributes::repr::{AlignParser, AlignStaticParser, ReprParser}; use crate::attributes::rustc_internal::{ RustcLayoutScalarValidRangeEnd, RustcLayoutScalarValidRangeStart, RustcObjectLifetimeDefaultParser, @@ -152,6 +152,7 @@ attribute_parsers!( pub(crate) static ATTRIBUTE_PARSERS = [ // tidy-alphabetical-start AlignParser, + AlignStaticParser, BodyStabilityParser, ConfusablesParser, ConstStabilityParser, diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index 9990f4cb3f2..f57456949bb 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -615,7 +615,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { } // Type-test failed. Report the error. - let erased_generic_kind = infcx.tcx.erase_regions(type_test.generic_kind); + let erased_generic_kind = infcx.tcx.erase_and_anonymize_regions(type_test.generic_kind); // Skip duplicate-ish errors. if deduplicate_errors.insert(( diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types/mod.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types/mod.rs index 95c5366a6c8..0af636aa734 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types/mod.rs @@ -341,7 +341,7 @@ fn compute_concrete_types_from_defining_uses<'tcx>( // // FIXME(-Znext-solver): This isn't necessary after all. We can remove this check again. if let Some((prev_decl_key, prev_span)) = decls_modulo_regions.insert( - rcx.infcx.tcx.erase_regions(opaque_type_key), + rcx.infcx.tcx.erase_and_anonymize_regions(opaque_type_key), (opaque_type_key, hidden_type.span), ) && let Some((arg1, arg2)) = std::iter::zip( prev_decl_key.iter_captured_args(infcx.tcx).map(|(_, arg)| arg), diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 02be78f90b0..8c5447fe1e9 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -1892,7 +1892,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { if is_diverging { // The signature in this call can reference region variables, // so erase them before calling a query. - let output_ty = self.tcx().erase_regions(sig.output()); + let output_ty = self.tcx().erase_and_anonymize_regions(sig.output()); if !output_ty .is_privately_uninhabited(self.tcx(), self.infcx.typing_env(self.infcx.param_env)) { @@ -1986,7 +1986,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { let op_arg_ty = self.normalize(op_arg_ty, term_location); let category = if call_source.from_hir_call() { - ConstraintCategory::CallArgument(Some(self.infcx.tcx.erase_regions(func_ty))) + ConstraintCategory::CallArgument(Some( + self.infcx.tcx.erase_and_anonymize_regions(func_ty), + )) } else { ConstraintCategory::Boring }; @@ -2120,7 +2122,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { // Erase the regions from `ty` to get a global type. The // `Sized` bound in no way depends on precise regions, so this // shouldn't affect `is_sized`. - let erased_ty = tcx.erase_regions(ty); + let erased_ty = tcx.erase_and_anonymize_regions(ty); // FIXME(#132279): Using `Ty::is_sized` causes us to incorrectly handle opaques here. if !erased_ty.is_sized(tcx, self.infcx.typing_env(self.infcx.param_env)) { // in current MIR construction, all non-control-flow rvalue diff --git a/compiler/rustc_codegen_gcc/src/consts.rs b/compiler/rustc_codegen_gcc/src/consts.rs index 619277eba8b..7fe8fc122b3 100644 --- a/compiler/rustc_codegen_gcc/src/consts.rs +++ b/compiler/rustc_codegen_gcc/src/consts.rs @@ -81,6 +81,8 @@ impl<'gcc, 'tcx> StaticCodegenMethods for CodegenCx<'gcc, 'tcx> { if global.to_rvalue().get_type() != val_llty { global.to_rvalue().set_type(val_llty); } + + // NOTE: Alignment from attributes has already been applied to the allocation. set_global_alignment(self, global, alloc.align); global.global_set_initializer_rvalue(value); diff --git a/compiler/rustc_codegen_gcc/src/type_of.rs b/compiler/rustc_codegen_gcc/src/type_of.rs index 093f902bc3d..93202483eed 100644 --- a/compiler/rustc_codegen_gcc/src/type_of.rs +++ b/compiler/rustc_codegen_gcc/src/type_of.rs @@ -240,7 +240,7 @@ impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> { // Make sure lifetimes are erased, to avoid generating distinct LLVM // types for Rust types that only differ in the choice of lifetimes. - let normal_ty = cx.tcx.erase_regions(self.ty); + let normal_ty = cx.tcx.erase_and_anonymize_regions(self.ty); let mut defer = None; let ty = if self.ty != normal_ty { diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs index 9ec7b0f80ae..dc9bb743560 100644 --- a/compiler/rustc_codegen_llvm/src/consts.rs +++ b/compiler/rustc_codegen_llvm/src/consts.rs @@ -452,6 +452,8 @@ impl<'ll> CodegenCx<'ll, '_> { self.statics_to_rauw.borrow_mut().push((g, new_g)); new_g }; + + // NOTE: Alignment from attributes has already been applied to the allocation. set_global_alignment(self, g, alloc.align); llvm::set_initializer(g, v); diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index 1790e212252..dc3a84b6a15 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -1436,7 +1436,7 @@ fn build_vtable_type_di_node<'ll, 'tcx>( let vtable_entries = if let Some(poly_trait_ref) = poly_trait_ref { let trait_ref = poly_trait_ref.with_self_ty(tcx, ty); - let trait_ref = tcx.erase_regions(trait_ref); + let trait_ref = tcx.erase_and_anonymize_regions(trait_ref); tcx.vtable_entries(trait_ref) } else { @@ -1563,7 +1563,7 @@ pub(crate) fn apply_vcall_visibility_metadata<'ll, 'tcx>( // Unwrap potential addrspacecast let vtable = find_vtable_behind_cast(vtable); let trait_ref_self = trait_ref.with_self_ty(cx.tcx, ty); - let trait_ref_self = cx.tcx.erase_regions(trait_ref_self); + let trait_ref_self = cx.tcx.erase_and_anonymize_regions(trait_ref_self); let trait_def_id = trait_ref_self.def_id; let trait_vis = cx.tcx.visibility(trait_def_id); diff --git a/compiler/rustc_codegen_llvm/src/type_of.rs b/compiler/rustc_codegen_llvm/src/type_of.rs index 53218340414..84998b5499b 100644 --- a/compiler/rustc_codegen_llvm/src/type_of.rs +++ b/compiler/rustc_codegen_llvm/src/type_of.rs @@ -231,7 +231,7 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyAndLayout<'tcx> { // Make sure lifetimes are erased, to avoid generating distinct LLVM // types for Rust types that only differ in the choice of lifetimes. - let normal_ty = cx.tcx.erase_regions(self.ty); + let normal_ty = cx.tcx.erase_and_anonymize_regions(self.ty); let mut defer = None; let llty = if self.ty != normal_ty { diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs index 6ec85648d6d..ebcdb9461d0 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -953,6 +953,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // # Global allocations if let Some(global_alloc) = self.tcx.try_get_global_alloc(id) { + // NOTE: `static` alignment from attributes has already been applied to the allocation. let (size, align) = global_alloc.size_and_align(*self.tcx, self.typing_env); let mutbl = global_alloc.mutability(*self.tcx, self.typing_env); let kind = match global_alloc { diff --git a/compiler/rustc_const_eval/src/interpret/traits.rs b/compiler/rustc_const_eval/src/interpret/traits.rs index e4b5c82853a..870f9a396ae 100644 --- a/compiler/rustc_const_eval/src/interpret/traits.rs +++ b/compiler/rustc_const_eval/src/interpret/traits.rs @@ -23,7 +23,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { ) -> InterpResult<'tcx, Pointer<Option<M::Provenance>>> { trace!("get_vtable(ty={ty:?}, dyn_ty={dyn_ty:?})"); - let (ty, dyn_ty) = self.tcx.erase_regions((ty, dyn_ty)); + let (ty, dyn_ty) = self.tcx.erase_and_anonymize_regions((ty, dyn_ty)); // All vtables must be monomorphic, bail out otherwise. ensure_monomorphic_enough(*self.tcx, ty)?; @@ -53,8 +53,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { ) -> &'tcx [VtblEntry<'tcx>] { if let Some(trait_) = trait_ { let trait_ref = trait_.with_self_ty(*self.tcx, dyn_ty); - let trait_ref = - self.tcx.erase_regions(self.tcx.instantiate_bound_regions_with_erased(trait_ref)); + let trait_ref = self.tcx.erase_and_anonymize_regions( + self.tcx.instantiate_bound_regions_with_erased(trait_ref), + ); self.tcx.vtable_entries(trait_ref) } else { TyCtxt::COMMON_VTABLE_ENTRIES diff --git a/compiler/rustc_const_eval/src/interpret/util.rs b/compiler/rustc_const_eval/src/interpret/util.rs index 72bee345406..f667823723c 100644 --- a/compiler/rustc_const_eval/src/interpret/util.rs +++ b/compiler/rustc_const_eval/src/interpret/util.rs @@ -1,6 +1,6 @@ use rustc_hir::def_id::LocalDefId; use rustc_middle::mir; -use rustc_middle::mir::interpret::{AllocInit, Allocation, InterpResult, Pointer}; +use rustc_middle::mir::interpret::{AllocInit, Allocation, GlobalAlloc, InterpResult, Pointer}; use rustc_middle::ty::layout::TyAndLayout; use rustc_middle::ty::{TyCtxt, TypeVisitable, TypeVisitableExt}; use tracing::debug; @@ -38,7 +38,14 @@ pub(crate) fn create_static_alloc<'tcx>( static_def_id: LocalDefId, layout: TyAndLayout<'tcx>, ) -> InterpResult<'tcx, MPlaceTy<'tcx>> { - let alloc = Allocation::try_new(layout.size, layout.align.abi, AllocInit::Uninit, ())?; + // Inherit size and align from the `GlobalAlloc::Static` so we can avoid duplicating + // the alignment attribute logic. + let (size, align) = + GlobalAlloc::Static(static_def_id.into()).size_and_align(*ecx.tcx, ecx.typing_env); + assert_eq!(size, layout.size); + assert!(align >= layout.align.abi); + + let alloc = Allocation::try_new(size, align, AllocInit::Uninit, ())?; let alloc_id = ecx.tcx.reserve_and_set_static_alloc(static_def_id.into()); assert_eq!(ecx.machine.static_root_ids, None); ecx.machine.static_root_ids = Some((alloc_id, static_def_id)); diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index e81003b1897..129ab7eccb5 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -621,6 +621,7 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ ), // FIXME(#82232, #143834): temporarily renamed to mitigate `#[align]` nameres ambiguity gated!(rustc_align, Normal, template!(List: &["alignment"]), DuplicatesOk, EncodeCrossCrate::No, fn_align, experimental!(rustc_align)), + gated!(rustc_align_static, Normal, template!(List: &["alignment"]), DuplicatesOk, EncodeCrossCrate::No, static_align, experimental!(rustc_align_static)), ungated!( unsafe(Edition2024) export_name, Normal, template!(NameValueStr: "name", "https://doc.rust-lang.org/reference/abi.html#the-export_name-attribute"), diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 4f35bf63a1a..93e5588146e 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -632,6 +632,8 @@ declare_features! ( (unstable, simd_ffi, "1.0.0", Some(27731)), /// Allows specialization of implementations (RFC 1210). (incomplete, specialization, "1.7.0", Some(31844)), + /// Allows using `#[rustc_align_static(...)]` on static items. + (unstable, static_align, "CURRENT_RUSTC_VERSION", Some(146177)), /// Allows attributes on expressions and non-item statements. (unstable, stmt_expr_attributes, "1.6.0", Some(15701)), /// Allows lints part of the strict provenance effort. diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index ae03121e5f7..75551fe4c19 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -2616,6 +2616,18 @@ impl Expr<'_> { ) | ( ExprKind::Struct( + QPath::LangItem(LangItem::RangeToInclusiveCopy, _), + [val1], + StructTailExpr::None, + ), + ExprKind::Struct( + QPath::LangItem(LangItem::RangeToInclusiveCopy, _), + [val2], + StructTailExpr::None, + ), + ) + | ( + ExprKind::Struct( QPath::LangItem(LangItem::RangeFrom, _), [val1], StructTailExpr::None, @@ -2705,7 +2717,8 @@ pub fn is_range_literal(expr: &Expr<'_>) -> bool { | LangItem::RangeToInclusive | LangItem::RangeCopy | LangItem::RangeFromCopy - | LangItem::RangeInclusiveCopy, + | LangItem::RangeInclusiveCopy + | LangItem::RangeToInclusiveCopy, .. ) ), diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index 0464665b41f..67d2f15d414 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -422,6 +422,7 @@ language_item_table! { RangeFromCopy, sym::RangeFromCopy, range_from_copy_struct, Target::Struct, GenericRequirement::None; RangeCopy, sym::RangeCopy, range_copy_struct, Target::Struct, GenericRequirement::None; RangeInclusiveCopy, sym::RangeInclusiveCopy, range_inclusive_copy_struct, Target::Struct, GenericRequirement::None; + RangeToInclusiveCopy, sym::RangeToInclusiveCopy, range_to_inclusive_copy_struct, Target::Struct, GenericRequirement::None; String, sym::String, string, Target::Struct, GenericRequirement::None; CStr, sym::CStr, c_str, Target::Struct, GenericRequirement::None; diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index b5c0ca4727c..63d0f400aef 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -85,7 +85,9 @@ use rustc_infer::traits::ObligationCause; use rustc_middle::query::Providers; use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::print::with_types_for_signature; -use rustc_middle::ty::{self, GenericArgs, GenericArgsRef, Ty, TyCtxt, TypingMode}; +use rustc_middle::ty::{ + self, GenericArgs, GenericArgsRef, GenericParamDefKind, Ty, TyCtxt, TypingMode, +}; use rustc_middle::{bug, span_bug}; use rustc_session::parse::feature_err; use rustc_span::def_id::CRATE_DEF_ID; @@ -233,8 +235,7 @@ fn missing_items_err( }; // Obtain the level of indentation ending in `sugg_sp`. - let padding = - tcx.sess.source_map().indentation_before(sugg_sp).unwrap_or_else(|| String::new()); + let padding = tcx.sess.source_map().indentation_before(sugg_sp).unwrap_or_else(String::new); let (mut missing_trait_item, mut missing_trait_item_none, mut missing_trait_item_label) = (Vec::new(), Vec::new(), Vec::new()); @@ -331,6 +332,7 @@ fn default_body_is_unstable( fn bounds_from_generic_predicates<'tcx>( tcx: TyCtxt<'tcx>, predicates: impl IntoIterator<Item = (ty::Clause<'tcx>, Span)>, + assoc: ty::AssocItem, ) -> (String, String) { let mut types: FxIndexMap<Ty<'tcx>, Vec<DefId>> = FxIndexMap::default(); let mut projections = vec![]; @@ -354,34 +356,50 @@ fn bounds_from_generic_predicates<'tcx>( } let mut where_clauses = vec![]; - let mut types_str = vec![]; - for (ty, bounds) in types { - if let ty::Param(_) = ty.kind() { - let mut bounds_str = vec![]; - for bound in bounds { - let mut projections_str = vec![]; - for projection in &projections { - let p = projection.skip_binder(); - if bound == tcx.parent(p.projection_term.def_id) - && p.projection_term.self_ty() == ty - { - let name = tcx.item_name(p.projection_term.def_id); - projections_str.push(format!("{} = {}", name, p.term)); + let generics = tcx.generics_of(assoc.def_id); + let types_str = generics + .own_params + .iter() + .filter(|p| matches!(p.kind, GenericParamDefKind::Type { synthetic: false, .. })) + .map(|p| { + // we just checked that it's a type, so the unwrap can't fail + let ty = tcx.mk_param_from_def(p).as_type().unwrap(); + if let Some(bounds) = types.get(&ty) { + let mut bounds_str = vec![]; + for bound in bounds.iter().copied() { + let mut projections_str = vec![]; + for projection in &projections { + let p = projection.skip_binder(); + if bound == tcx.parent(p.projection_term.def_id) + && p.projection_term.self_ty() == ty + { + let name = tcx.item_name(p.projection_term.def_id); + projections_str.push(format!("{} = {}", name, p.term)); + } + } + let bound_def_path = tcx.def_path_str(bound); + if projections_str.is_empty() { + where_clauses.push(format!("{}: {}", ty, bound_def_path)); + } else { + bounds_str.push(format!( + "{}<{}>", + bound_def_path, + projections_str.join(", ") + )); } } - let bound_def_path = tcx.def_path_str(bound); - if projections_str.is_empty() { - where_clauses.push(format!("{}: {}", ty, bound_def_path)); + if bounds_str.is_empty() { + ty.to_string() } else { - bounds_str.push(format!("{}<{}>", bound_def_path, projections_str.join(", "))); + format!("{}: {}", ty, bounds_str.join(" + ")) } - } - if bounds_str.is_empty() { - types_str.push(ty.to_string()); } else { - types_str.push(format!("{}: {}", ty, bounds_str.join(" + "))); + ty.to_string() } - } else { + }) + .collect::<Vec<_>>(); + for (ty, bounds) in types.into_iter() { + if !matches!(ty.kind(), ty::Param(_)) { // Avoid suggesting the following: // fn foo<T, <T as Trait>::Bar>(_: T) where T: Trait, <T as Trait>::Bar: Other {} where_clauses.extend( @@ -473,10 +491,10 @@ fn fn_sig_suggestion<'tcx>( let output = if !output.is_unit() { format!(" -> {output}") } else { String::new() }; let safety = sig.safety.prefix_str(); - let (generics, where_clauses) = bounds_from_generic_predicates(tcx, predicates); + let (generics, where_clauses) = bounds_from_generic_predicates(tcx, predicates, assoc); // FIXME: this is not entirely correct, as the lifetimes from borrowed params will - // not be present in the `fn` definition, not will we account for renamed + // not be present in the `fn` definition, nor will we account for renamed // lifetimes between the `impl` and the `trait`, but this should be good enough to // fill in a significant portion of the missing code, and other subsequent // suggestions can help the user fix the code. @@ -512,6 +530,7 @@ fn suggestion_signature<'tcx>( let (generics, where_clauses) = bounds_from_generic_predicates( tcx, tcx.predicates_of(assoc.def_id).instantiate_own(tcx, args), + assoc, ); format!("type {}{generics} = /* Type */{where_clauses};", assoc.name()) } diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index e6a1f6d8d8b..22a9446fd4c 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -1047,7 +1047,7 @@ fn check_type_defn<'tcx>( let needs_drop_copy = || { packed && { let ty = tcx.type_of(variant.tail().did).instantiate_identity(); - let ty = tcx.erase_regions(ty); + let ty = tcx.erase_and_anonymize_regions(ty); assert!(!ty.has_infer()); ty.needs_drop(tcx, wfcx.infcx.typing_env(wfcx.param_env)) } diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs index f707196c816..621431ae234 100644 --- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs +++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs @@ -404,7 +404,7 @@ fn emit_orphan_check_error<'tcx>( of_trait.trait_ref.path.span }; - ty = tcx.erase_regions(ty); + ty = tcx.erase_and_anonymize_regions(ty); let is_foreign = !trait_ref.def_id.is_local() && matches!(is_target_ty, IsFirstInputType::No); diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs index 93b82acf621..0cf9cb7193f 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs @@ -482,7 +482,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { .map(|header| header.trait_ref.instantiate_identity().self_ty()) // We don't care about blanket impls. .filter(|self_ty| !self_ty.has_non_region_param()) - .map(|self_ty| tcx.erase_regions(self_ty).to_string()) + .map(|self_ty| tcx.erase_and_anonymize_regions(self_ty).to_string()) .collect() }; // FIXME: also look at `tcx.generics_of(self.item_def_id()).params` any that diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs index 3eeb0eac023..27540fd1a43 100644 --- a/compiler/rustc_hir_typeck/src/cast.rs +++ b/compiler/rustc_hir_typeck/src/cast.rs @@ -851,8 +851,8 @@ impl<'a, 'tcx> CastCheck<'tcx> { debug!("check_ptr_ptr_cast m_src={m_src:?} m_dst={m_dst:?}"); // ptr-ptr cast. metadata must match. - let src_kind = fcx.tcx.erase_regions(fcx.pointer_kind(m_src.ty, self.span)?); - let dst_kind = fcx.tcx.erase_regions(fcx.pointer_kind(m_dst.ty, self.span)?); + let src_kind = fcx.tcx.erase_and_anonymize_regions(fcx.pointer_kind(m_src.ty, self.span)?); + let dst_kind = fcx.tcx.erase_and_anonymize_regions(fcx.pointer_kind(m_dst.ty, self.span)?); // We can't cast if target pointer kind is unknown let Some(dst_kind) = dst_kind else { diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 84ea2ec0f8a..d7ddbcc8b53 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -1358,7 +1358,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .infcx .type_implements_trait( clone_trait_def, - [self.tcx.erase_regions(expected_ty)], + [self.tcx.erase_and_anonymize_regions(expected_ty)], self.param_env, ) .must_apply_modulo_regions() diff --git a/compiler/rustc_hir_typeck/src/inline_asm.rs b/compiler/rustc_hir_typeck/src/inline_asm.rs index b59c1752c25..c0cd23be690 100644 --- a/compiler/rustc_hir_typeck/src/inline_asm.rs +++ b/compiler/rustc_hir_typeck/src/inline_asm.rs @@ -44,7 +44,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { if ty.has_non_region_infer() { Ty::new_misc_error(self.tcx()) } else { - self.tcx().erase_regions(ty) + self.tcx().erase_and_anonymize_regions(ty) } } diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs index d75bc9edab2..90301d1b391 100644 --- a/compiler/rustc_hir_typeck/src/writeback.rs +++ b/compiler/rustc_hir_typeck/src/writeback.rs @@ -802,7 +802,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { format!("unexpected inference variable after writeback: {predicate:?}"), ); } else { - let predicate = self.tcx().erase_regions(predicate); + let predicate = self.tcx().erase_and_anonymize_regions(predicate); if cause.has_infer() || cause.has_placeholders() { // We can't use the the obligation cause as it references // information local to this query. @@ -984,8 +984,8 @@ impl<'cx, 'tcx> Resolver<'cx, 'tcx> { // borrowck, and specifically region constraints will be populated during // MIR typeck which is run on the new body. // - // We're not using `tcx.erase_regions` as that also anonymizes bound variables, - // regressing borrowck diagnostics. + // We're not using `tcx.erase_and_anonymize_regions` as that also + // anonymizes bound variables, regressing borrowck diagnostics. value = fold_regions(tcx, value, |_, _| tcx.lifetimes.re_erased); // Normalize consts in writeback, because GCE doesn't normalize eagerly. diff --git a/compiler/rustc_index/src/idx.rs b/compiler/rustc_index/src/idx.rs index 33f406e2113..9cd7134659c 100644 --- a/compiler/rustc_index/src/idx.rs +++ b/compiler/rustc_index/src/idx.rs @@ -130,7 +130,22 @@ impl<I: Idx, T> IntoSliceIdx<I, [T]> for core::range::RangeFrom<I> { impl<I: Idx, T> IntoSliceIdx<I, [T]> for core::range::RangeInclusive<I> { type Output = core::range::RangeInclusive<usize>; #[inline] + #[cfg(bootstrap)] fn into_slice_idx(self) -> Self::Output { core::range::RangeInclusive { start: self.start.index(), end: self.end.index() } } + #[inline] + #[cfg(not(bootstrap))] + fn into_slice_idx(self) -> Self::Output { + core::range::RangeInclusive { start: self.start.index(), last: self.last.index() } + } +} + +#[cfg(all(feature = "nightly", not(bootstrap)))] +impl<I: Idx, T> IntoSliceIdx<I, [T]> for core::range::RangeToInclusive<I> { + type Output = core::range::RangeToInclusive<usize>; + #[inline] + fn into_slice_idx(self) -> Self::Output { + core::range::RangeToInclusive { last: self.last.index() } + } } diff --git a/compiler/rustc_infer/src/infer/outlives/test_type_match.rs b/compiler/rustc_infer/src/infer/outlives/test_type_match.rs index bfdd282d7e1..f06eb58a371 100644 --- a/compiler/rustc_infer/src/infer/outlives/test_type_match.rs +++ b/compiler/rustc_infer/src/infer/outlives/test_type_match.rs @@ -76,7 +76,7 @@ pub(super) fn can_match_erased_ty<'tcx>( erased_ty: Ty<'tcx>, ) -> bool { assert!(!outlives_predicate.has_escaping_bound_vars()); - let erased_outlives_predicate = tcx.erase_regions(outlives_predicate); + let erased_outlives_predicate = tcx.erase_and_anonymize_regions(outlives_predicate); let outlives_ty = erased_outlives_predicate.skip_binder().0; if outlives_ty == erased_ty { // pointless micro-optimization diff --git a/compiler/rustc_infer/src/infer/outlives/verify.rs b/compiler/rustc_infer/src/infer/outlives/verify.rs index 69feecfe30a..f67b99cb3f8 100644 --- a/compiler/rustc_infer/src/infer/outlives/verify.rs +++ b/compiler/rustc_infer/src/infer/outlives/verify.rs @@ -96,7 +96,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { &self, alias_ty: ty::AliasTy<'tcx>, ) -> Vec<ty::PolyTypeOutlivesPredicate<'tcx>> { - let erased_alias_ty = self.tcx.erase_regions(alias_ty.to_ty(self.tcx)); + let erased_alias_ty = self.tcx.erase_and_anonymize_regions(alias_ty.to_ty(self.tcx)); self.declared_generic_bounds_from_env_for_erased_ty(erased_alias_ty) } @@ -241,7 +241,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { } let p_ty = p.to_ty(tcx); - let erased_p_ty = self.tcx.erase_regions(p_ty); + let erased_p_ty = self.tcx.erase_and_anonymize_regions(p_ty); (erased_p_ty == erased_ty).then_some(ty::Binder::dummy(ty::OutlivesPredicate(p_ty, r))) })); diff --git a/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs b/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs index 943fcc0801b..e1c51ff8299 100644 --- a/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs +++ b/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs @@ -78,7 +78,7 @@ impl<'tcx> LateLintPass<'tcx> for DerefIntoDynSupertrait { { // erase regions in self type for better diagnostic presentation let (self_ty, target_principal, supertrait_principal) = - tcx.erase_regions((self_ty, target_principal, supertrait_principal)); + tcx.erase_and_anonymize_regions((self_ty, target_principal, supertrait_principal)); let label2 = tcx .associated_items(item.owner_id) .find_by_ident_and_kind( diff --git a/compiler/rustc_lint/src/for_loops_over_fallibles.rs b/compiler/rustc_lint/src/for_loops_over_fallibles.rs index a56b753bda7..9e1fc598171 100644 --- a/compiler/rustc_lint/src/for_loops_over_fallibles.rs +++ b/compiler/rustc_lint/src/for_loops_over_fallibles.rs @@ -176,7 +176,7 @@ fn suggest_question_mark<'tcx>( cause, param_env, // Erase any region vids from the type, which may not be resolved - infcx.tcx.erase_regions(ty), + infcx.tcx.erase_and_anonymize_regions(ty), into_iterator_did, ); diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index a72b802eb5d..88527fa2e6e 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -935,7 +935,7 @@ impl<'tcx> LateLintPass<'tcx> for VariantSizeDifferences { fn check_item(&mut self, cx: &LateContext<'_>, it: &hir::Item<'_>) { if let hir::ItemKind::Enum(_, _, ref enum_definition) = it.kind { let t = cx.tcx.type_of(it.owner_id).instantiate_identity(); - let ty = cx.tcx.erase_regions(t); + let ty = cx.tcx.erase_and_anonymize_regions(t); let Ok(layout) = cx.layout_of(ty) else { return }; let Variants::Multiple { tag_encoding: TagEncoding::Direct, tag, variants, .. } = &layout.variants diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs index bed99a4ff2a..9762e0f21da 100644 --- a/compiler/rustc_middle/src/mir/interpret/mod.rs +++ b/compiler/rustc_middle/src/mir/interpret/mod.rs @@ -386,7 +386,16 @@ impl<'tcx> GlobalAlloc<'tcx> { .expect("statics should not have generic parameters"); let layout = tcx.layout_of(typing_env.as_query_input(ty)).unwrap(); assert!(layout.is_sized()); - (layout.size, layout.align.abi) + + // Take over-alignment from attributes into account. + let align = match tcx.codegen_fn_attrs(def_id).alignment { + Some(align_from_attribute) => { + Ord::max(align_from_attribute, layout.align.abi) + } + None => layout.align.abi, + }; + + (layout.size, align) } } GlobalAlloc::Memory(alloc) => { diff --git a/compiler/rustc_middle/src/mir/interpret/queries.rs b/compiler/rustc_middle/src/mir/interpret/queries.rs index e25f35c59c2..ecf35d9dd6d 100644 --- a/compiler/rustc_middle/src/mir/interpret/queries.rs +++ b/compiler/rustc_middle/src/mir/interpret/queries.rs @@ -41,7 +41,7 @@ impl<'tcx> TyCtxt<'tcx> { let instance = ty::Instance::new_raw(def_id, args); let cid = GlobalId { instance, promoted: None }; let typing_env = ty::TypingEnv::post_analysis(self, def_id); - let inputs = self.erase_regions(typing_env.as_query_input(cid)); + let inputs = self.erase_and_anonymize_regions(typing_env.as_query_input(cid)); self.eval_to_allocation_raw(inputs) } @@ -172,8 +172,9 @@ impl<'tcx> TyCtxt<'tcx> { ) -> EvalToConstValueResult<'tcx> { // Const-eval shouldn't depend on lifetimes at all, so we can erase them, which should // improve caching of queries. - let inputs = - self.erase_regions(typing_env.with_post_analysis_normalized(self).as_query_input(cid)); + let inputs = self.erase_and_anonymize_regions( + typing_env.with_post_analysis_normalized(self).as_query_input(cid), + ); if !span.is_dummy() { // The query doesn't know where it is being invoked, so we need to fix the span. self.at(span).eval_to_const_value_raw(inputs).map_err(|e| e.with_span(span)) @@ -192,8 +193,9 @@ impl<'tcx> TyCtxt<'tcx> { ) -> ConstToValTreeResult<'tcx> { // Const-eval shouldn't depend on lifetimes at all, so we can erase them, which should // improve caching of queries. - let inputs = - self.erase_regions(typing_env.with_post_analysis_normalized(self).as_query_input(cid)); + let inputs = self.erase_and_anonymize_regions( + typing_env.with_post_analysis_normalized(self).as_query_input(cid), + ); debug!(?inputs); let res = if !span.is_dummy() { // The query doesn't know where it is being invoked, so we need to fix the span. diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 8fba218cc71..2aa32dfa0d8 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -761,9 +761,9 @@ rustc_queries! { } /// Erases regions from `ty` to yield a new type. - /// Normally you would just use `tcx.erase_regions(value)`, + /// Normally you would just use `tcx.erase_and_anonymize_regions(value)`, /// however, which uses this query as a kind of cache. - query erase_regions_ty(ty: Ty<'tcx>) -> Ty<'tcx> { + query erase_and_anonymize_regions_ty(ty: Ty<'tcx>) -> Ty<'tcx> { // This query is not expected to have input -- as a result, it // is not a good candidates for "replay" because it is essentially a // pure function of its input (and hence the expectation is that diff --git a/compiler/rustc_middle/src/ty/abstract_const.rs b/compiler/rustc_middle/src/ty/abstract_const.rs index c9b9ec771b3..463e4c58805 100644 --- a/compiler/rustc_middle/src/ty/abstract_const.rs +++ b/compiler/rustc_middle/src/ty/abstract_const.rs @@ -55,7 +55,7 @@ impl<'tcx> TyCtxt<'tcx> { ty::ConstKind::Unevaluated(uv) => match self.tcx.thir_abstract_const(uv.def) { Err(e) => ty::Const::new_error(self.tcx, e), Ok(Some(bac)) => { - let args = self.tcx.erase_regions(uv.args); + let args = self.tcx.erase_and_anonymize_regions(uv.args); let bac = bac.instantiate(self.tcx, args); return bac.fold_with(self); } diff --git a/compiler/rustc_middle/src/ty/erase_regions.rs b/compiler/rustc_middle/src/ty/erase_regions.rs index f4fead7e952..74b4adda7fd 100644 --- a/compiler/rustc_middle/src/ty/erase_regions.rs +++ b/compiler/rustc_middle/src/ty/erase_regions.rs @@ -6,20 +6,20 @@ use crate::ty::{ }; pub(super) fn provide(providers: &mut Providers) { - *providers = Providers { erase_regions_ty, ..*providers }; + *providers = Providers { erase_and_anonymize_regions_ty, ..*providers }; } -fn erase_regions_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> { +fn erase_and_anonymize_regions_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> { // N.B., use `super_fold_with` here. If we used `fold_with`, it - // could invoke the `erase_regions_ty` query recursively. - ty.super_fold_with(&mut RegionEraserVisitor { tcx }) + // could invoke the `erase_and_anonymize_regions_ty` query recursively. + ty.super_fold_with(&mut RegionEraserAndAnonymizerVisitor { tcx }) } impl<'tcx> TyCtxt<'tcx> { - /// Returns an equivalent value with all free regions removed (note - /// that late-bound regions remain, because they are important for - /// subtyping, but they are anonymized and normalized as well).. - pub fn erase_regions<T>(self, value: T) -> T + /// Returns an equivalent value with all free regions removed and + /// bound regions anonymized. (note that bound regions are important + /// for subtyping and generally type equality so *cannot* be removed) + pub fn erase_and_anonymize_regions<T>(self, value: T) -> T where T: TypeFoldable<TyCtxt<'tcx>>, { @@ -27,18 +27,18 @@ impl<'tcx> TyCtxt<'tcx> { if !value.has_type_flags(TypeFlags::HAS_BINDER_VARS | TypeFlags::HAS_FREE_REGIONS) { return value; } - debug!("erase_regions({:?})", value); - let value1 = value.fold_with(&mut RegionEraserVisitor { tcx: self }); - debug!("erase_regions = {:?}", value1); + debug!("erase_and_anonymize_regions({:?})", value); + let value1 = value.fold_with(&mut RegionEraserAndAnonymizerVisitor { tcx: self }); + debug!("erase_and_anonymize_regions = {:?}", value1); value1 } } -struct RegionEraserVisitor<'tcx> { +struct RegionEraserAndAnonymizerVisitor<'tcx> { tcx: TyCtxt<'tcx>, } -impl<'tcx> TypeFolder<TyCtxt<'tcx>> for RegionEraserVisitor<'tcx> { +impl<'tcx> TypeFolder<TyCtxt<'tcx>> for RegionEraserAndAnonymizerVisitor<'tcx> { fn cx(&self) -> TyCtxt<'tcx> { self.tcx } @@ -49,7 +49,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for RegionEraserVisitor<'tcx> { } else if ty.has_infer() { ty.super_fold_with(self) } else { - self.tcx.erase_regions_ty(ty) + self.tcx.erase_and_anonymize_regions_ty(ty) } } diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index 3a51f79f121..e76993e0542 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -544,7 +544,9 @@ impl<'tcx> Instance<'tcx> { // All regions in the result of this query are erased, so it's // fine to erase all of the input regions. - tcx.resolve_instance_raw(tcx.erase_regions(typing_env.as_query_input((def_id, args)))) + tcx.resolve_instance_raw( + tcx.erase_and_anonymize_regions(typing_env.as_query_input((def_id, args))), + ) } pub fn expect_resolve( diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index aed94f9aa04..2114d080dfa 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -401,7 +401,10 @@ impl<'tcx> SizeSkeleton<'tcx> { match tail.kind() { ty::Param(_) | ty::Alias(ty::Projection | ty::Inherent, _) => { debug_assert!(tail.has_non_region_param()); - Ok(SizeSkeleton::Pointer { non_zero, tail: tcx.erase_regions(tail) }) + Ok(SizeSkeleton::Pointer { + non_zero, + tail: tcx.erase_and_anonymize_regions(tail), + }) } ty::Error(guar) => { // Fixes ICE #124031 diff --git a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs index f2a4a5a4ecf..69c1eb9b345 100644 --- a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs +++ b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs @@ -51,7 +51,7 @@ impl<'tcx> TyCtxt<'tcx> { // Erase first before we do the real query -- this keeps the // cache from being too polluted. - let value = self.erase_regions(value); + let value = self.erase_and_anonymize_regions(value); debug!(?value); if !value.has_aliases() { @@ -83,7 +83,7 @@ impl<'tcx> TyCtxt<'tcx> { // Erase first before we do the real query -- this keeps the // cache from being too polluted. - let value = self.erase_regions(value); + let value = self.erase_and_anonymize_regions(value); debug!(?value); if !value.has_aliases() { diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 8101cabccdd..fc821ffdaa6 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -1436,8 +1436,8 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { // anonymized regions, but the super projections can still // contain named regions. So we erase and anonymize everything // here to compare the types modulo regions below. - let proj = p.tcx().erase_regions(proj); - let super_proj = p.tcx().erase_regions(super_proj); + let proj = p.tcx().erase_and_anonymize_regions(proj); + let super_proj = p.tcx().erase_and_anonymize_regions(super_proj); proj == super_proj }); diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index b8c99e83a8f..96fbdf44791 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -131,10 +131,9 @@ impl<'tcx> TyCtxt<'tcx> { /// Creates a hash of the type `Ty` which will be the same no matter what crate /// context it's calculated within. This is used by the `type_id` intrinsic. pub fn type_id_hash(self, ty: Ty<'tcx>) -> Hash128 { - // We want the type_id be independent of the types free regions, so we - // erase them. The erase_regions() call will also anonymize bound - // regions, which is desirable too. - let ty = self.erase_regions(ty); + // We don't have region information, so we erase all free regions. Equal types + // must have the same `TypeId`, so we must anonymize all bound regions as well. + let ty = self.erase_and_anonymize_regions(ty); self.with_stable_hashing_context(|mut hcx| { let mut hasher = StableHasher::new(); @@ -1309,7 +1308,7 @@ impl<'tcx> Ty<'tcx> { debug_assert!(!typing_env.param_env.has_infer()); let query_ty = tcx .try_normalize_erasing_regions(typing_env, query_ty) - .unwrap_or_else(|_| tcx.erase_regions(query_ty)); + .unwrap_or_else(|_| tcx.erase_and_anonymize_regions(query_ty)); tcx.needs_drop_raw(typing_env.as_query_input(query_ty)) } @@ -1346,7 +1345,7 @@ impl<'tcx> Ty<'tcx> { debug_assert!(!typing_env.has_infer()); let query_ty = tcx .try_normalize_erasing_regions(typing_env, query_ty) - .unwrap_or_else(|_| tcx.erase_regions(query_ty)); + .unwrap_or_else(|_| tcx.erase_and_anonymize_regions(query_ty)); tcx.needs_async_drop_raw(typing_env.as_query_input(query_ty)) } diff --git a/compiler/rustc_middle/src/ty/vtable.rs b/compiler/rustc_middle/src/ty/vtable.rs index 6fc19c82342..e2f09fdcb4b 100644 --- a/compiler/rustc_middle/src/ty/vtable.rs +++ b/compiler/rustc_middle/src/ty/vtable.rs @@ -89,7 +89,7 @@ pub(super) fn vtable_allocation_provider<'tcx>( let vtable_entries = if let Some(poly_trait_ref) = poly_trait_ref { let trait_ref = poly_trait_ref.with_self_ty(tcx, ty); - let trait_ref = tcx.erase_regions(trait_ref); + let trait_ref = tcx.erase_and_anonymize_regions(trait_ref); tcx.vtable_entries(trait_ref) } else { diff --git a/compiler/rustc_mir_build/src/check_tail_calls.rs b/compiler/rustc_mir_build/src/check_tail_calls.rs index e0cbe8519ed..d40c77d145f 100644 --- a/compiler/rustc_mir_build/src/check_tail_calls.rs +++ b/compiler/rustc_mir_build/src/check_tail_calls.rs @@ -64,10 +64,10 @@ impl<'tcx> TailCallCkVisitor<'_, 'tcx> { "`become` outside of functions should have been disallowed by hir_typeck" ) }; - // While the `caller_sig` does have its regions erased, it does not have its - // binders anonymized. We call `erase_regions` once again to anonymize any binders + // While the `caller_sig` does have its free regions erased, it does not have its + // binders anonymized. We call `erase_and_anonymize_regions` once again to anonymize any binders // within the signature, such as in function pointer or `dyn Trait` args. - let caller_sig = self.tcx.erase_regions(caller_sig); + let caller_sig = self.tcx.erase_and_anonymize_regions(caller_sig); let ExprKind::Scope { value, .. } = call.kind else { span_bug!(call.span, "expected scope, found: {call:?}") diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index 81b0e21a5f5..0b9bc018a09 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -792,10 +792,9 @@ impl<'tcx> ThirBuildCx<'tcx> { let ty = self.typeck_results.node_type(anon_const.hir_id); let did = anon_const.def_id.to_def_id(); let typeck_root_def_id = tcx.typeck_root_def_id(did); - let parent_args = tcx.erase_regions(GenericArgs::identity_for_item( - tcx, - typeck_root_def_id, - )); + let parent_args = tcx.erase_and_anonymize_regions( + GenericArgs::identity_for_item(tcx, typeck_root_def_id), + ); let args = InlineConstArgs::new(tcx, InlineConstArgsParts { parent_args, ty }) .args; @@ -831,8 +830,10 @@ impl<'tcx> ThirBuildCx<'tcx> { let ty = self.typeck_results.node_type(anon_const.hir_id); let did = anon_const.def_id.to_def_id(); let typeck_root_def_id = tcx.typeck_root_def_id(did); - let parent_args = - tcx.erase_regions(GenericArgs::identity_for_item(tcx, typeck_root_def_id)); + let parent_args = tcx.erase_and_anonymize_regions(GenericArgs::identity_for_item( + tcx, + typeck_root_def_id, + )); let args = InlineConstArgs::new(tcx, InlineConstArgsParts { parent_args, ty }).args; ExprKind::ConstBlock { did, args } diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs index d46c4678bcf..6316ccf1b8c 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs @@ -105,9 +105,11 @@ impl<'tcx> ConstToPat<'tcx> { // // FIXME: `const_eval_resolve_for_typeck` should probably just modify the env itself // instead of having this logic here - let typing_env = - self.tcx.erase_regions(self.typing_env).with_post_analysis_normalized(self.tcx); - let uv = self.tcx.erase_regions(uv); + let typing_env = self + .tcx + .erase_and_anonymize_regions(self.typing_env) + .with_post_analysis_normalized(self.tcx); + let uv = self.tcx.erase_and_anonymize_regions(uv); // try to resolve e.g. associated constants to their definition on an impl, and then // evaluate the const. diff --git a/compiler/rustc_mir_dataflow/src/value_analysis.rs b/compiler/rustc_mir_dataflow/src/value_analysis.rs index 9a00831dc01..bf5ec8f459e 100644 --- a/compiler/rustc_mir_dataflow/src/value_analysis.rs +++ b/compiler/rustc_mir_dataflow/src/value_analysis.rs @@ -891,7 +891,7 @@ pub fn iter_fields<'tcx>( let field_ty = f_def.ty(tcx, args); let field_ty = tcx .try_normalize_erasing_regions(typing_env, field_ty) - .unwrap_or_else(|_| tcx.erase_regions(field_ty)); + .unwrap_or_else(|_| tcx.erase_and_anonymize_regions(field_ty)); f(variant, f_index.into(), field_ty); } } diff --git a/compiler/rustc_mir_transform/src/add_subtyping_projections.rs b/compiler/rustc_mir_transform/src/add_subtyping_projections.rs index 92ee80eaa35..be4f84d64d0 100644 --- a/compiler/rustc_mir_transform/src/add_subtyping_projections.rs +++ b/compiler/rustc_mir_transform/src/add_subtyping_projections.rs @@ -32,8 +32,8 @@ impl<'a, 'tcx> MutVisitor<'tcx> for SubTypeChecker<'a, 'tcx> { let mut rval_ty = rvalue.ty(self.local_decls, self.tcx); // Not erasing this causes `Free Regions` errors in validator, // when rval is `ReStatic`. - rval_ty = self.tcx.erase_regions(rval_ty); - place_ty = self.tcx.erase_regions(place_ty); + rval_ty = self.tcx.erase_and_anonymize_regions(rval_ty); + place_ty = self.tcx.erase_and_anonymize_regions(place_ty); if place_ty != rval_ty { let temp = self .patcher diff --git a/compiler/rustc_mir_transform/src/promote_consts.rs b/compiler/rustc_mir_transform/src/promote_consts.rs index 462ddfa3dd3..9ea2eb4f25d 100644 --- a/compiler/rustc_mir_transform/src/promote_consts.rs +++ b/compiler/rustc_mir_transform/src/promote_consts.rs @@ -875,7 +875,8 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { let mut promoted_operand = |ty, span| { promoted.span = span; promoted.local_decls[RETURN_PLACE] = LocalDecl::new(ty, span); - let args = tcx.erase_regions(GenericArgs::identity_for_item(tcx, def)); + let args = + tcx.erase_and_anonymize_regions(GenericArgs::identity_for_item(tcx, def)); let uneval = mir::UnevaluatedConst { def, args, promoted: Some(next_promoted_index) }; diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 3169f2d4e1a..378d71cb1fc 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -1558,7 +1558,7 @@ impl<'v> RootCollector<'_, 'v> { ty::Closure(def_id, args) | ty::Coroutine(def_id, args) | ty::CoroutineClosure(def_id, args) => { - Instance::new_raw(def_id, self.tcx.erase_regions(args)) + Instance::new_raw(def_id, self.tcx.erase_and_anonymize_regions(args)) } _ => unreachable!(), }; diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index 77dd313d9b8..72cd75f6d89 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -479,9 +479,6 @@ parse_invalid_identifier_with_leading_number = identifiers cannot start with a n parse_invalid_literal_suffix_on_tuple_index = suffixes on a tuple index are invalid .label = invalid suffix `{$suffix}` - .tuple_exception_line_1 = `{$suffix}` is *temporarily* accepted on tuple index fields as it was incorrectly accepted on stable for a few releases - .tuple_exception_line_2 = on proc macros, you'll want to use `syn::Index::from` or `proc_macro::Literal::*_unsuffixed` for code that will desugar to tuple field access - .tuple_exception_line_3 = see issue #60210 <https://github.com/rust-lang/rust/issues/60210> for more information parse_invalid_logical_operator = `{$incorrect}` is not a logical operator .note = unlike in e.g., Python and PHP, `&&` and `||` are used for logical operators diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 797d4830c2f..00ca5acd84d 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -1017,10 +1017,6 @@ pub(crate) struct InvalidLiteralSuffixOnTupleIndex { #[label] pub span: Span, pub suffix: Symbol, - #[help(parse_tuple_exception_line_1)] - #[help(parse_tuple_exception_line_2)] - #[help(parse_tuple_exception_line_3)] - pub exception: bool, } #[derive(Diagnostic)] diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 4c02547357e..81a5d48d94e 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -1163,7 +1163,10 @@ impl<'a> Parser<'a> { suffix, }) => { if let Some(suffix) = suffix { - self.expect_no_tuple_index_suffix(current.span, suffix); + self.dcx().emit_err(errors::InvalidLiteralSuffixOnTupleIndex { + span: current.span, + suffix, + }); } match self.break_up_float(symbol, current.span) { // 1e2 @@ -1239,7 +1242,8 @@ impl<'a> Parser<'a> { suffix: Option<Symbol>, ) -> Box<Expr> { if let Some(suffix) = suffix { - self.expect_no_tuple_index_suffix(ident_span, suffix); + self.dcx() + .emit_err(errors::InvalidLiteralSuffixOnTupleIndex { span: ident_span, suffix }); } self.mk_expr(lo.to(ident_span), ExprKind::Field(base, Ident::new(field, ident_span))) } @@ -2225,24 +2229,6 @@ impl<'a> Parser<'a> { }) } - pub(super) fn expect_no_tuple_index_suffix(&self, span: Span, suffix: Symbol) { - if [sym::i32, sym::u32, sym::isize, sym::usize].contains(&suffix) { - // #59553: warn instead of reject out of hand to allow the fix to percolate - // through the ecosystem when people fix their macros - self.dcx().emit_warn(errors::InvalidLiteralSuffixOnTupleIndex { - span, - suffix, - exception: true, - }); - } else { - self.dcx().emit_err(errors::InvalidLiteralSuffixOnTupleIndex { - span, - suffix, - exception: false, - }); - } - } - /// Matches `'-' lit | lit` (cf. `ast_validation::AstValidator::check_expr_within_pat`). /// Keep this in sync with `Token::can_begin_literal_maybe_minus`. pub fn parse_literal_maybe_minus(&mut self) -> PResult<'a, Box<Expr>> { diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 3bbca622975..ed4069dae93 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -1335,7 +1335,10 @@ impl<'a> Parser<'a> { if let token::Literal(token::Lit { kind: token::Integer, symbol, suffix }) = self.token.kind { if let Some(suffix) = suffix { - self.expect_no_tuple_index_suffix(self.token.span, suffix); + self.dcx().emit_err(errors::InvalidLiteralSuffixOnTupleIndex { + span: self.token.span, + suffix, + }); } self.bump(); Ok(Ident::new(symbol, self.prev_token.span)) diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index afd08319738..ab7885905a6 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -501,6 +501,10 @@ passes_repr_align_should_be_align = `#[repr(align(...))]` is not supported on {$item} .help = use `#[rustc_align(...)]` instead +passes_repr_align_should_be_align_static = + `#[repr(align(...))]` is not supported on {$item} + .help = use `#[rustc_align_static(...)]` instead + passes_repr_conflicting = conflicting representation hints diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 487bdd2a888..38a6b4b16c9 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -1606,12 +1606,18 @@ impl<'tcx> CheckAttrVisitor<'tcx> { ReprAttr::ReprAlign(align) => { match target { Target::Struct | Target::Union | Target::Enum => {} - Target::Fn | Target::Method(_) => { + Target::Fn | Target::Method(_) if self.tcx.features().fn_align() => { self.dcx().emit_err(errors::ReprAlignShouldBeAlign { span: *repr_span, item: target.plural_name(), }); } + Target::Static if self.tcx.features().static_align() => { + self.dcx().emit_err(errors::ReprAlignShouldBeAlignStatic { + span: *repr_span, + item: target.plural_name(), + }); + } _ => { self.dcx().emit_err(errors::AttrApplication::StructEnumUnion { hint_span: *repr_span, diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 23dcabef1a1..2da4b6f52cf 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -1610,6 +1610,15 @@ pub(crate) struct ReprAlignShouldBeAlign { } #[derive(Diagnostic)] +#[diag(passes_repr_align_should_be_align_static)] +pub(crate) struct ReprAlignShouldBeAlignStatic { + #[primary_span] + #[help] + pub span: Span, + pub item: &'static str, +} + +#[derive(Diagnostic)] #[diag(passes_custom_mir_phase_requires_dialect)] pub(crate) struct CustomMirPhaseRequiresDialect { #[primary_span] diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index e5108d8b7e9..e21ff83c400 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -326,6 +326,7 @@ symbols! { RangeSub, RangeTo, RangeToInclusive, + RangeToInclusiveCopy, Rc, RcWeak, Ready, @@ -1280,6 +1281,7 @@ symbols! { lang, lang_items, large_assignments, + last, lateout, lazy_normalization_consts, lazy_type_alias, @@ -1846,6 +1848,7 @@ symbols! { rustc_abi, // FIXME(#82232, #143834): temporary name to mitigate `#[align]` nameres ambiguity rustc_align, + rustc_align_static, rustc_allocator, rustc_allocator_zeroed, rustc_allocator_zeroed_variant, @@ -2097,6 +2100,7 @@ symbols! { staged_api, start, state, + static_align, static_in_const, static_nobundle, static_recursion, diff --git a/compiler/rustc_symbol_mangling/src/legacy.rs b/compiler/rustc_symbol_mangling/src/legacy.rs index 4d9741f1d11..95a7ec61868 100644 --- a/compiler/rustc_symbol_mangling/src/legacy.rs +++ b/compiler/rustc_symbol_mangling/src/legacy.rs @@ -54,7 +54,7 @@ pub(super) fn mangle<'tcx>( // Erase regions because they may not be deterministic when hashed // and should not matter anyhow. - let instance_ty = tcx.erase_regions(instance_ty); + let instance_ty = tcx.erase_and_anonymize_regions(instance_ty); let hash = get_symbol_hash(tcx, instance, instance_ty, instantiating_crate); @@ -422,7 +422,10 @@ impl<'tcx> Printer<'tcx> for LegacySymbolMangler<'tcx> { || &args[..generics.count()] == self .tcx - .erase_regions(ty::GenericArgs::identity_for_item(self.tcx, impl_def_id)) + .erase_and_anonymize_regions(ty::GenericArgs::identity_for_item( + self.tcx, + impl_def_id, + )) .as_slice() { ( diff --git a/compiler/rustc_symbol_mangling/src/test.rs b/compiler/rustc_symbol_mangling/src/test.rs index 0c6d1495e39..50935e7caf3 100644 --- a/compiler/rustc_symbol_mangling/src/test.rs +++ b/compiler/rustc_symbol_mangling/src/test.rs @@ -58,7 +58,7 @@ impl SymbolNamesTest<'_> { let def_id = def_id.to_def_id(); let instance = Instance::new_raw( def_id, - tcx.erase_regions(GenericArgs::identity_for_item(tcx, def_id)), + tcx.erase_and_anonymize_regions(GenericArgs::identity_for_item(tcx, def_id)), ); let mangled = tcx.symbol_name(instance); tcx.dcx().emit_err(TestOutput { diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index 0655c2d5e81..1605b4958ba 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -329,7 +329,10 @@ impl<'tcx> Printer<'tcx> for V0SymbolMangler<'tcx> { || &args[..generics.count()] == self .tcx - .erase_regions(ty::GenericArgs::identity_for_item(self.tcx, impl_def_id)) + .erase_and_anonymize_regions(ty::GenericArgs::identity_for_item( + self.tcx, + impl_def_id, + )) .as_slice() { ( @@ -339,7 +342,7 @@ impl<'tcx> Printer<'tcx> for V0SymbolMangler<'tcx> { ) } else { assert!( - !args.has_non_region_param(), + !args.has_non_region_param() && !args.has_free_regions(), "should not be mangling partially substituted \ polymorphic instance: {impl_def_id:?} {args:?}" ); diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs index d3a17232a40..d71110521ff 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs @@ -1616,8 +1616,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { && let Some((e, f)) = values.ty() && let TypeError::ArgumentSorts(..) | TypeError::Sorts(_) = terr { - let e = self.tcx.erase_regions(e); - let f = self.tcx.erase_regions(f); + let e = self.tcx.erase_and_anonymize_regions(e); + let f = self.tcx.erase_and_anonymize_regions(f); let mut expected = with_forced_trimmed_paths!(e.sort_string(self.tcx)); let mut found = with_forced_trimmed_paths!(f.sort_string(self.tcx)); if let ObligationCauseCode::Pattern { span, .. } = cause.code() diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs index 40285e5d0e9..e042ce84955 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs @@ -629,7 +629,11 @@ impl<T> Trait<T> for X { let tcx = self.tcx; // Don't suggest constraining a projection to something containing itself - if self.tcx.erase_regions(values.found).contains(self.tcx.erase_regions(values.expected)) { + if self + .tcx + .erase_and_anonymize_regions(values.found) + .contains(self.tcx.erase_and_anonymize_regions(values.expected)) + { return; } 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 bc984f30472..c82043f0222 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 @@ -75,7 +75,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { { if let Some(cause) = self .tcx - .diagnostic_hir_wf_check((tcx.erase_regions(obligation.predicate), *wf_loc)) + .diagnostic_hir_wf_check((tcx.erase_and_anonymize_regions(obligation.predicate), *wf_loc)) { obligation.cause = cause.clone(); span = obligation.cause.span; @@ -2612,8 +2612,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } // Erase regions because layout code doesn't particularly care about regions. - let trait_pred = - self.tcx.erase_regions(self.tcx.instantiate_bound_regions_with_erased(trait_pred)); + let trait_pred = self.tcx.erase_and_anonymize_regions( + self.tcx.instantiate_bound_regions_with_erased(trait_pred), + ); let src_and_dst = rustc_transmute::Types { dst: trait_pred.trait_ref.args.type_at(0), diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs index f6dbbeb51ca..cb84d583e6e 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -2442,7 +2442,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // Look for a type inside the coroutine interior that matches the target type to get // a span. - let target_ty_erased = self.tcx.erase_regions(target_ty); + let target_ty_erased = self.tcx.erase_and_anonymize_regions(target_ty); let ty_matches = |ty| -> bool { // Careful: the regions for types that appear in the // coroutine interior are not generally known, so we @@ -2454,10 +2454,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // interior generally contain "bound regions" to // represent regions that are part of the suspended // coroutine frame. Bound regions are preserved by - // `erase_regions` and so we must also call + // `erase_and_anonymize_regions` and so we must also call // `instantiate_bound_regions_with_erased`. let ty_erased = self.tcx.instantiate_bound_regions_with_erased(ty); - let ty_erased = self.tcx.erase_regions(ty_erased); + let ty_erased = self.tcx.erase_and_anonymize_regions(ty_erased); let eq = ty_erased == target_ty_erased; debug!(?ty_erased, ?target_ty_erased, ?eq); eq diff --git a/compiler/rustc_trait_selection/src/solve/delegate.rs b/compiler/rustc_trait_selection/src/solve/delegate.rs index 16f444486a6..b6bdf1067a3 100644 --- a/compiler/rustc_trait_selection/src/solve/delegate.rs +++ b/compiler/rustc_trait_selection/src/solve/delegate.rs @@ -300,7 +300,7 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate< ) -> Result<Certainty, NoSolution> { // Erase regions because we compute layouts in `rustc_transmute`, // which will ICE for region vars. - let (dst, src) = self.tcx.erase_regions((dst, src)); + let (dst, src) = self.tcx.erase_and_anonymize_regions((dst, src)); let Some(assume) = rustc_transmute::Assume::from_const(self.tcx, assume) else { return Err(NoSolution); diff --git a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs index 4b493c95d59..bcd11d6918d 100644 --- a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs +++ b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs @@ -759,7 +759,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for IllegalSelfTypeVisitor<'tcx> { )), ) .map(|trait_ref| { - self.tcx.erase_regions( + self.tcx.erase_and_anonymize_regions( self.tcx.instantiate_bound_regions_with_erased(trait_ref), ) }) diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index a9fb16b8000..6fefac43699 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -576,7 +576,7 @@ pub fn try_evaluate_const<'tcx>( let args = replace_param_and_infer_args_with_placeholder(tcx, uv.args); let typing_env = infcx - .typing_env(tcx.erase_regions(param_env)) + .typing_env(tcx.erase_and_anonymize_regions(param_env)) .with_post_analysis_normalized(tcx); (args, typing_env) } @@ -589,7 +589,7 @@ pub fn try_evaluate_const<'tcx>( } } else { let typing_env = infcx - .typing_env(tcx.erase_regions(param_env)) + .typing_env(tcx.erase_and_anonymize_regions(param_env)) .with_post_analysis_normalized(tcx); (uv.args, typing_env) } @@ -634,14 +634,14 @@ pub fn try_evaluate_const<'tcx>( } let typing_env = infcx - .typing_env(tcx.erase_regions(param_env)) + .typing_env(tcx.erase_and_anonymize_regions(param_env)) .with_post_analysis_normalized(tcx); (uv.args, typing_env) } }; let uv = ty::UnevaluatedConst::new(uv.def, args); - let erased_uv = tcx.erase_regions(uv); + let erased_uv = tcx.erase_and_anonymize_regions(uv); use rustc_middle::mir::interpret::ErrorHandled; // FIXME: `def_span` will point at the definition of this const; ideally, we'd point at diff --git a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs index de404532899..945ca7c3775 100644 --- a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs +++ b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs @@ -350,7 +350,9 @@ pub fn dtorck_constraint_for_ty_inner<'tcx>( // Note that we don't care about whether the resume type has any drops since this is // redundant; there is no storage for the resume type, so if it is actually stored // in the interior, we'll already detect the need for a drop by checking the interior. - let typing_env = tcx.erase_regions(typing_env); + // + // FIXME(@lcnr): Why do we erase regions in the env here? Seems odd + let typing_env = tcx.erase_and_anonymize_regions(typing_env); let needs_drop = tcx.mir_coroutine_witnesses(def_id).is_some_and(|witness| { witness.field_tys.iter().any(|field| field.ty.needs_drop(tcx, typing_env)) }); diff --git a/compiler/rustc_traits/src/codegen.rs b/compiler/rustc_traits/src/codegen.rs index 7dd3c59edd0..4b05e2cc381 100644 --- a/compiler/rustc_traits/src/codegen.rs +++ b/compiler/rustc_traits/src/codegen.rs @@ -73,7 +73,7 @@ pub(crate) fn codegen_select_candidate<'tcx>( } let impl_source = infcx.resolve_vars_if_possible(impl_source); - let impl_source = tcx.erase_regions(impl_source); + let impl_source = tcx.erase_and_anonymize_regions(impl_source); if impl_source.has_non_region_infer() { // Unused generic types or consts on an impl get replaced with inference vars, // but never resolved, causing the return value of a query to contain inference diff --git a/compiler/rustc_traits/src/normalize_erasing_regions.rs b/compiler/rustc_traits/src/normalize_erasing_regions.rs index c1b848a2e79..c98b56abe9c 100644 --- a/compiler/rustc_traits/src/normalize_erasing_regions.rs +++ b/compiler/rustc_traits/src/normalize_erasing_regions.rs @@ -41,7 +41,7 @@ fn try_normalize_after_erasing_regions<'tcx, T: TypeFoldable<TyCtxt<'tcx>> + Par // fresh `InferCtxt`. If this assert does trigger, it will give // us a test case. debug_assert_eq!(normalized_value, resolved_value); - let erased = infcx.tcx.erase_regions(resolved_value); + let erased = infcx.tcx.erase_and_anonymize_regions(resolved_value); debug_assert!(!erased.has_infer(), "{erased:?}"); Ok(erased) } diff --git a/compiler/rustc_transmute/src/layout/mod.rs b/compiler/rustc_transmute/src/layout/mod.rs index acbce258f39..4e548ff8fe2 100644 --- a/compiler/rustc_transmute/src/layout/mod.rs +++ b/compiler/rustc_transmute/src/layout/mod.rs @@ -163,7 +163,7 @@ pub mod rustc { ty: Ty<'tcx>, ) -> Result<Layout<'tcx>, &'tcx LayoutError<'tcx>> { use rustc_middle::ty::layout::LayoutOf; - let ty = cx.tcx().erase_regions(ty); + let ty = cx.tcx().erase_and_anonymize_regions(ty); cx.layout_of(ty).map(|tl| tl.layout) } } diff --git a/compiler/rustc_transmute/src/layout/tree.rs b/compiler/rustc_transmute/src/layout/tree.rs index 3f83b4d50aa..d7ea26a2ab1 100644 --- a/compiler/rustc_transmute/src/layout/tree.rs +++ b/compiler/rustc_transmute/src/layout/tree.rs @@ -426,24 +426,23 @@ pub(crate) mod rustc { assert!(def.is_enum()); // Computes the layout of a variant. - let layout_of_variant = - |index, encoding: Option<TagEncoding<VariantIdx>>| -> Result<Self, Err> { - let variant_layout = ty_variant(cx, (ty, layout), index); - if variant_layout.is_uninhabited() { - return Ok(Self::uninhabited()); - } - let tag = cx.tcx().tag_for_variant( - cx.typing_env.as_query_input((cx.tcx().erase_regions(ty), index)), - ); - let variant_def = Def::Variant(def.variant(index)); - Self::from_variant( - variant_def, - tag.map(|tag| (tag, index, encoding.unwrap())), - (ty, variant_layout), - layout.size, - cx, - ) - }; + let layout_of_variant = |index, encoding: Option<_>| -> Result<Self, Err> { + let variant_layout = ty_variant(cx, (ty, layout), index); + if variant_layout.is_uninhabited() { + return Ok(Self::uninhabited()); + } + let tag = cx.tcx().tag_for_variant( + cx.typing_env.as_query_input((cx.tcx().erase_and_anonymize_regions(ty), index)), + ); + let variant_def = Def::Variant(def.variant(index)); + Self::from_variant( + variant_def, + tag.map(|tag| (tag, index, encoding.unwrap())), + (ty, variant_layout), + layout.size, + cx, + ) + }; match layout.variants() { Variants::Empty => Ok(Self::uninhabited()), @@ -634,7 +633,7 @@ pub(crate) mod rustc { (ty, layout): (Ty<'tcx>, Layout<'tcx>), i: VariantIdx, ) -> Layout<'tcx> { - let ty = cx.tcx().erase_regions(ty); + let ty = cx.tcx().erase_and_anonymize_regions(ty); TyAndLayout { ty, layout }.for_variant(&cx, i).layout } } diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs index 5c3f7d491a5..e28ebaabc0a 100644 --- a/compiler/rustc_ty_utils/src/instance.rs +++ b/compiler/rustc_ty_utils/src/instance.rs @@ -176,7 +176,7 @@ fn resolve_associated_item<'tcx>( args, leaf_def.defining_node, ); - let args = infcx.tcx.erase_regions(args); + let args = infcx.tcx.erase_and_anonymize_regions(args); // HACK: We may have overlapping `dyn Trait` built-in impls and // user-provided blanket impls. Detect that case here, and return @@ -222,7 +222,7 @@ fn resolve_associated_item<'tcx>( return Err(guar); } - let args = tcx.erase_regions(args); + let args = tcx.erase_and_anonymize_regions(args); // We check that the impl item is compatible with the trait item // because otherwise we may ICE in const eval due to type mismatches, @@ -279,7 +279,7 @@ fn resolve_associated_item<'tcx>( assert_eq!(name, sym::clone_from); // Use the default `fn clone_from` from `trait Clone`. - let args = tcx.erase_regions(rcvr_args); + let args = tcx.erase_and_anonymize_regions(rcvr_args); Some(ty::Instance::new_raw(trait_item_id, args)) } } else if tcx.is_lang_item(trait_ref.def_id, LangItem::FnPtrTrait) { @@ -380,7 +380,7 @@ fn resolve_associated_item<'tcx>( } else if tcx.is_lang_item(trait_ref.def_id, LangItem::TransmuteTrait) { let name = tcx.item_name(trait_item_id); assert_eq!(name, sym::transmute); - let args = tcx.erase_regions(rcvr_args); + let args = tcx.erase_and_anonymize_regions(rcvr_args); Some(ty::Instance::new_raw(trait_item_id, args)) } else { Instance::try_resolve_item_for_coroutine(tcx, trait_item_id, trait_id, rcvr_args) diff --git a/compiler/rustc_type_ir/src/search_graph/mod.rs b/compiler/rustc_type_ir/src/search_graph/mod.rs index dbbc0c217d7..8f8f019510f 100644 --- a/compiler/rustc_type_ir/src/search_graph/mod.rs +++ b/compiler/rustc_type_ir/src/search_graph/mod.rs @@ -1262,7 +1262,7 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> { encountered_overflow |= stack_entry.encountered_overflow; debug_assert_eq!(stack_entry.input, input); - // If the current goal is not the root of a cycle, we are done. + // If the current goal is not a cycle head, we are done. // // There are no provisional cache entries which depend on this goal. let Some(usages) = stack_entry.usages else { @@ -1278,7 +1278,7 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> { // // Check whether we reached a fixpoint, either because the final result // is equal to the provisional result of the previous iteration, or because - // this was only the root of either coinductive or inductive cycles, and the + // this was only the head of either coinductive or inductive cycles, and the // final result is equal to the initial response for that case. if self.reached_fixpoint(cx, &stack_entry, usages, result) { self.rebase_provisional_cache_entries(&stack_entry, |_, result| result); diff --git a/compiler/rustc_type_ir/src/search_graph/stack.rs b/compiler/rustc_type_ir/src/search_graph/stack.rs index 3fd8e2bd16e..8348666be41 100644 --- a/compiler/rustc_type_ir/src/search_graph/stack.rs +++ b/compiler/rustc_type_ir/src/search_graph/stack.rs @@ -13,7 +13,7 @@ rustc_index::newtype_index! { pub(super) struct StackDepth {} } -/// Stack entries of the evaluation stack. Its fields tend to be lazily +/// Stack entries of the evaluation stack. Its fields tend to be lazily updated /// when popping a child goal or completely immutable. #[derive_where(Debug; X: Cx)] pub(super) struct StackEntry<X: Cx> { @@ -42,7 +42,7 @@ pub(super) struct StackEntry<X: Cx> { /// Whether evaluating this goal encountered overflow. Lazily updated. pub encountered_overflow: bool, - /// Whether and how this goal has been used as the root of a cycle. Lazily updated. + /// Whether and how this goal has been used as a cycle head. Lazily updated. pub usages: Option<HeadUsages>, /// We want to be able to ignore head usages if they happen inside of candidates diff --git a/compiler/rustc_type_ir/src/visit.rs b/compiler/rustc_type_ir/src/visit.rs index 5104484e9c4..6e62e1031a9 100644 --- a/compiler/rustc_type_ir/src/visit.rs +++ b/compiler/rustc_type_ir/src/visit.rs @@ -398,9 +398,9 @@ impl std::fmt::Debug for HasTypeFlagsVisitor { // looks, particular for `Ty`/`Predicate` where it's just a field access. // // N.B. The only case where this isn't totally true is binders, which also -// add `HAS_{RE,TY,CT}_LATE_BOUND` flag depending on the *bound variables* that +// add `HAS_BINDER_VARS` flag depending on the *bound variables* that // are present, regardless of whether those bound variables are used. This -// is important for anonymization of binders in `TyCtxt::erase_regions`. We +// is important for anonymization of binders in `TyCtxt::erase_and_anonymize_regions`. We // specifically detect this case in `visit_binder`. impl<I: Interner> TypeVisitor<I> for HasTypeFlagsVisitor { type Result = ControlFlow<FoundFlags>; diff --git a/library/Cargo.lock b/library/Cargo.lock index e601137e005..e4b3839847b 100644 --- a/library/Cargo.lock +++ b/library/Cargo.lock @@ -99,13 +99,12 @@ dependencies = [ [[package]] name = "getopts" -version = "0.2.23" +version = "0.2.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cba6ae63eb948698e300f645f87c70f76630d505f23b8907cf1e193ee85048c1" +checksum = "cfe4fbac503b8d1f88e6676011885f34b7174f46e59956bba534ba83abded4df" dependencies = [ "rustc-std-workspace-core", "rustc-std-workspace-std", - "unicode-width", ] [[package]] @@ -362,16 +361,6 @@ dependencies = [ ] [[package]] -name = "unicode-width" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a1a07cc7db3810833284e8d372ccdc6da29741639ecc70c9ec107df0fa6154c" -dependencies = [ - "rustc-std-workspace-core", - "rustc-std-workspace-std", -] - -[[package]] name = "unwind" version = "0.0.0" dependencies = [ diff --git a/library/core/src/range.rs b/library/core/src/range.rs index 332ae51d848..8c49123fdaf 100644 --- a/library/core/src/range.rs +++ b/library/core/src/range.rs @@ -31,9 +31,7 @@ pub use iter::{IterRange, IterRangeFrom, IterRangeInclusive}; #[doc(inline)] pub use crate::iter::Step; #[doc(inline)] -pub use crate::ops::{ - Bound, IntoBounds, OneSidedRange, RangeBounds, RangeFull, RangeTo, RangeToInclusive, -}; +pub use crate::ops::{Bound, IntoBounds, OneSidedRange, RangeBounds, RangeFull, RangeTo}; /// A (half-open) range bounded inclusively below and exclusively above /// (`start..end` in a future edition). @@ -209,20 +207,20 @@ impl<T> const From<legacy::Range<T>> for Range<T> { } } -/// A range bounded inclusively below and above (`start..=end`). +/// A range bounded inclusively below and above (`start..=last`). /// -/// The `RangeInclusive` `start..=end` contains all values with `x >= start` -/// and `x <= end`. It is empty unless `start <= end`. +/// The `RangeInclusive` `start..=last` contains all values with `x >= start` +/// and `x <= last`. It is empty unless `start <= last`. /// /// # Examples /// -/// The `start..=end` syntax is a `RangeInclusive`: +/// The `start..=last` syntax is a `RangeInclusive`: /// /// ``` /// #![feature(new_range_api)] /// use core::range::RangeInclusive; /// -/// assert_eq!(RangeInclusive::from(3..=5), RangeInclusive { start: 3, end: 5 }); +/// assert_eq!(RangeInclusive::from(3..=5), RangeInclusive { start: 3, last: 5 }); /// assert_eq!(3 + 4 + 5, RangeInclusive::from(3..=5).into_iter().sum()); /// ``` #[lang = "RangeInclusiveCopy"] @@ -234,7 +232,7 @@ pub struct RangeInclusive<Idx> { pub start: Idx, /// The upper bound of the range (inclusive). #[unstable(feature = "new_range_api", issue = "125687")] - pub end: Idx, + pub last: Idx, } #[unstable(feature = "new_range_api", issue = "125687")] @@ -242,7 +240,7 @@ impl<Idx: fmt::Debug> fmt::Debug for RangeInclusive<Idx> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { self.start.fmt(fmt)?; write!(fmt, "..=")?; - self.end.fmt(fmt)?; + self.last.fmt(fmt)?; Ok(()) } } @@ -306,7 +304,7 @@ impl<Idx: PartialOrd<Idx>> RangeInclusive<Idx> { #[unstable(feature = "new_range_api", issue = "125687")] #[inline] pub fn is_empty(&self) -> bool { - !(self.start <= self.end) + !(self.start <= self.last) } } @@ -335,10 +333,10 @@ impl<Idx: Step> RangeInclusive<Idx> { impl RangeInclusive<usize> { /// Converts to an exclusive `Range` for `SliceIndex` implementations. - /// The caller is responsible for dealing with `end == usize::MAX`. + /// The caller is responsible for dealing with `last == usize::MAX`. #[inline] pub(crate) const fn into_slice_range(self) -> Range<usize> { - Range { start: self.start, end: self.end + 1 } + Range { start: self.start, end: self.last + 1 } } } @@ -348,7 +346,7 @@ impl<T> RangeBounds<T> for RangeInclusive<T> { Included(&self.start) } fn end_bound(&self) -> Bound<&T> { - Included(&self.end) + Included(&self.last) } } @@ -364,7 +362,7 @@ impl<T> RangeBounds<T> for RangeInclusive<&T> { Included(self.start) } fn end_bound(&self) -> Bound<&T> { - Included(self.end) + Included(self.last) } } @@ -372,7 +370,7 @@ impl<T> RangeBounds<T> for RangeInclusive<&T> { #[unstable(feature = "new_range_api", issue = "125687")] impl<T> IntoBounds<T> for RangeInclusive<T> { fn into_bounds(self) -> (Bound<T>, Bound<T>) { - (Included(self.start), Included(self.end)) + (Included(self.start), Included(self.last)) } } @@ -381,7 +379,7 @@ impl<T> IntoBounds<T> for RangeInclusive<T> { impl<T> const From<RangeInclusive<T>> for legacy::RangeInclusive<T> { #[inline] fn from(value: RangeInclusive<T>) -> Self { - Self::new(value.start, value.end) + Self::new(value.start, value.last) } } #[unstable(feature = "new_range_api", issue = "125687")] @@ -394,8 +392,8 @@ impl<T> const From<legacy::RangeInclusive<T>> for RangeInclusive<T> { "attempted to convert from an exhausted `legacy::RangeInclusive` (unspecified behavior)" ); - let (start, end) = value.into_inner(); - RangeInclusive { start, end } + let (start, last) = value.into_inner(); + RangeInclusive { start, last } } } @@ -544,3 +542,107 @@ impl<T> const From<legacy::RangeFrom<T>> for RangeFrom<T> { Self { start: value.start } } } + +/// A range only bounded inclusively above (`..=last`). +/// +/// The `RangeToInclusive` `..=last` contains all values with `x <= last`. +/// It cannot serve as an [`Iterator`] because it doesn't have a starting point. +/// +/// # Examples +/// +/// The `..=last` syntax is a `RangeToInclusive`: +/// +/// ``` +/// #![feature(new_range_api)] +/// #![feature(new_range)] +/// assert_eq!((..=5), std::range::RangeToInclusive{ last: 5 }); +/// ``` +/// +/// It does not have an [`IntoIterator`] implementation, so you can't use it in a +/// `for` loop directly. This won't compile: +/// +/// ```compile_fail,E0277 +/// // error[E0277]: the trait bound `std::range::RangeToInclusive<{integer}>: +/// // std::iter::Iterator` is not satisfied +/// for i in ..=5 { +/// // ... +/// } +/// ``` +/// +/// When used as a [slicing index], `RangeToInclusive` produces a slice of all +/// array elements up to and including the index indicated by `last`. +/// +/// ``` +/// let arr = [0, 1, 2, 3, 4]; +/// assert_eq!(arr[ .. ], [0, 1, 2, 3, 4]); +/// assert_eq!(arr[ .. 3], [0, 1, 2 ]); +/// assert_eq!(arr[ ..=3], [0, 1, 2, 3 ]); // This is a `RangeToInclusive` +/// assert_eq!(arr[1.. ], [ 1, 2, 3, 4]); +/// assert_eq!(arr[1.. 3], [ 1, 2 ]); +/// assert_eq!(arr[1..=3], [ 1, 2, 3 ]); +/// ``` +/// +/// [slicing index]: crate::slice::SliceIndex +#[lang = "RangeToInclusiveCopy"] +#[doc(alias = "..=")] +#[derive(Copy, Clone, PartialEq, Eq, Hash)] +#[unstable(feature = "new_range_api", issue = "125687")] +pub struct RangeToInclusive<Idx> { + /// The upper bound of the range (inclusive) + #[unstable(feature = "new_range_api", issue = "125687")] + pub last: Idx, +} + +#[unstable(feature = "new_range_api", issue = "125687")] +impl<Idx: fmt::Debug> fmt::Debug for RangeToInclusive<Idx> { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(fmt, "..=")?; + self.last.fmt(fmt)?; + Ok(()) + } +} + +impl<Idx: PartialOrd<Idx>> RangeToInclusive<Idx> { + /// Returns `true` if `item` is contained in the range. + /// + /// # Examples + /// + /// ``` + /// assert!( (..=5).contains(&-1_000_000_000)); + /// assert!( (..=5).contains(&5)); + /// assert!(!(..=5).contains(&6)); + /// + /// assert!( (..=1.0).contains(&1.0)); + /// assert!(!(..=1.0).contains(&f32::NAN)); + /// assert!(!(..=f32::NAN).contains(&0.5)); + /// ``` + #[inline] + #[unstable(feature = "new_range_api", issue = "125687")] + pub fn contains<U>(&self, item: &U) -> bool + where + Idx: PartialOrd<U>, + U: ?Sized + PartialOrd<Idx>, + { + <Self as RangeBounds<Idx>>::contains(self, item) + } +} + +// RangeToInclusive<Idx> cannot impl From<RangeTo<Idx>> +// because underflow would be possible with (..0).into() + +#[unstable(feature = "new_range_api", issue = "125687")] +impl<T> RangeBounds<T> for RangeToInclusive<T> { + fn start_bound(&self) -> Bound<&T> { + Unbounded + } + fn end_bound(&self) -> Bound<&T> { + Included(&self.last) + } +} + +#[unstable(feature = "range_into_bounds", issue = "136903")] +impl<T> IntoBounds<T> for RangeToInclusive<T> { + fn into_bounds(self) -> (Bound<T>, Bound<T>) { + (Unbounded, Included(self.last)) + } +} diff --git a/library/core/src/range/iter.rs b/library/core/src/range/iter.rs index 1e261d8c1d9..24efd4a204a 100644 --- a/library/core/src/range/iter.rs +++ b/library/core/src/range/iter.rs @@ -164,7 +164,7 @@ impl<A: Step> IterRangeInclusive<A> { return None; } - Some(RangeInclusive { start: self.0.start, end: self.0.end }) + Some(RangeInclusive { start: self.0.start, last: self.0.end }) } } diff --git a/library/core/src/range/legacy.rs b/library/core/src/range/legacy.rs index 6723c4903f7..aa11331382d 100644 --- a/library/core/src/range/legacy.rs +++ b/library/core/src/range/legacy.rs @@ -1,10 +1,10 @@ //! # Legacy range types //! //! The types within this module will be replaced by the types -//! [`Range`], [`RangeInclusive`], and [`RangeFrom`] in the parent +//! [`Range`], [`RangeInclusive`], [`RangeToInclusive`], and [`RangeFrom`] in the parent //! module, [`core::range`]. //! //! The types here are equivalent to those in [`core::ops`]. #[doc(inline)] -pub use crate::ops::{Range, RangeFrom, RangeInclusive}; +pub use crate::ops::{Range, RangeFrom, RangeInclusive, RangeToInclusive}; diff --git a/library/core/src/slice/index.rs b/library/core/src/slice/index.rs index 8e1bc0bae70..a8147d745f3 100644 --- a/library/core/src/slice/index.rs +++ b/library/core/src/slice/index.rs @@ -129,6 +129,8 @@ mod private_slice_index { #[unstable(feature = "new_range_api", issue = "125687")] impl Sealed for range::RangeInclusive<usize> {} #[unstable(feature = "new_range_api", issue = "125687")] + impl Sealed for range::RangeToInclusive<usize> {} + #[unstable(feature = "new_range_api", issue = "125687")] impl Sealed for range::RangeFrom<usize> {} impl Sealed for ops::IndexRange {} @@ -788,6 +790,45 @@ unsafe impl<T> const SliceIndex<[T]> for ops::RangeToInclusive<usize> { } } +/// The methods `index` and `index_mut` panic if the end of the range is out of bounds. +#[stable(feature = "inclusive_range", since = "1.26.0")] +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +unsafe impl<T> const SliceIndex<[T]> for range::RangeToInclusive<usize> { + type Output = [T]; + + #[inline] + fn get(self, slice: &[T]) -> Option<&[T]> { + (0..=self.last).get(slice) + } + + #[inline] + fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> { + (0..=self.last).get_mut(slice) + } + + #[inline] + unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] { + // SAFETY: the caller has to uphold the safety contract for `get_unchecked`. + unsafe { (0..=self.last).get_unchecked(slice) } + } + + #[inline] + unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] { + // SAFETY: the caller has to uphold the safety contract for `get_unchecked_mut`. + unsafe { (0..=self.last).get_unchecked_mut(slice) } + } + + #[inline] + fn index(self, slice: &[T]) -> &[T] { + (0..=self.last).index(slice) + } + + #[inline] + fn index_mut(self, slice: &mut [T]) -> &mut [T] { + (0..=self.last).index_mut(slice) + } +} + /// Performs bounds checking of a range. /// /// This method is similar to [`Index::index`] for slices, but it returns a diff --git a/library/core/src/str/traits.rs b/library/core/src/str/traits.rs index 4f228edf78e..5adae62b7e6 100644 --- a/library/core/src/str/traits.rs +++ b/library/core/src/str/traits.rs @@ -677,11 +677,11 @@ unsafe impl const SliceIndex<str> for range::RangeInclusive<usize> { type Output = str; #[inline] fn get(self, slice: &str) -> Option<&Self::Output> { - if self.end == usize::MAX { None } else { self.into_slice_range().get(slice) } + if self.last == usize::MAX { None } else { self.into_slice_range().get(slice) } } #[inline] fn get_mut(self, slice: &mut str) -> Option<&mut Self::Output> { - if self.end == usize::MAX { None } else { self.into_slice_range().get_mut(slice) } + if self.last == usize::MAX { None } else { self.into_slice_range().get_mut(slice) } } #[inline] unsafe fn get_unchecked(self, slice: *const str) -> *const Self::Output { @@ -695,14 +695,14 @@ unsafe impl const SliceIndex<str> for range::RangeInclusive<usize> { } #[inline] fn index(self, slice: &str) -> &Self::Output { - if self.end == usize::MAX { + if self.last == usize::MAX { str_index_overflow_fail(); } self.into_slice_range().index(slice) } #[inline] fn index_mut(self, slice: &mut str) -> &mut Self::Output { - if self.end == usize::MAX { + if self.last == usize::MAX { str_index_overflow_fail(); } self.into_slice_range().index_mut(slice) diff --git a/library/std/tests/floats/f32.rs b/library/std/tests/floats/f32.rs index c29d803b25e..3acd0670914 100644 --- a/library/std/tests/floats/f32.rs +++ b/library/std/tests/floats/f32.rs @@ -193,13 +193,13 @@ fn test_atanh() { #[test] fn test_gamma() { // precision can differ between platforms - assert_approx_eq!(1.0f32.gamma(), 1.0f32); - assert_approx_eq!(2.0f32.gamma(), 1.0f32); - assert_approx_eq!(3.0f32.gamma(), 2.0f32); + assert_approx_eq!(1.0f32.gamma(), 1.0f32, APPROX_DELTA); + assert_approx_eq!(2.0f32.gamma(), 1.0f32, APPROX_DELTA); + assert_approx_eq!(3.0f32.gamma(), 2.0f32, APPROX_DELTA); assert_approx_eq!(4.0f32.gamma(), 6.0f32, APPROX_DELTA); assert_approx_eq!(5.0f32.gamma(), 24.0f32, APPROX_DELTA); - assert_approx_eq!(0.5f32.gamma(), consts::PI.sqrt()); - assert_approx_eq!((-0.5f32).gamma(), -2.0 * consts::PI.sqrt()); + assert_approx_eq!(0.5f32.gamma(), consts::PI.sqrt(), APPROX_DELTA); + assert_approx_eq!((-0.5f32).gamma(), -2.0 * consts::PI.sqrt(), APPROX_DELTA); assert_eq!(0.0f32.gamma(), f32::INFINITY); assert_eq!((-0.0f32).gamma(), f32::NEG_INFINITY); assert!((-1.0f32).gamma().is_nan()); diff --git a/library/test/Cargo.toml b/library/test/Cargo.toml index 2a32a7dd76e..fe749847b7c 100644 --- a/library/test/Cargo.toml +++ b/library/test/Cargo.toml @@ -6,7 +6,7 @@ version = "0.0.0" edition = "2024" [dependencies] -getopts = { version = "0.2.21", features = ['rustc-dep-of-std'] } +getopts = { version = "0.2.24", default-features = false, features = ['rustc-dep-of-std'] } std = { path = "../std", public = true } core = { path = "../core", public = true } diff --git a/src/ci/docker/scripts/rfl-build.sh b/src/ci/docker/scripts/rfl-build.sh index 7e0fb5794f4..b7d7151b171 100755 --- a/src/ci/docker/scripts/rfl-build.sh +++ b/src/ci/docker/scripts/rfl-build.sh @@ -2,9 +2,7 @@ set -euo pipefail -# https://github.com/rust-lang/rust/pull/144443 -# https://github.com/rust-lang/rust/pull/145928 -LINUX_VERSION=8851e27d2cb947ea8bbbe8e812068f7bf5cbd00b +LINUX_VERSION=v6.17-rc5 # Build rustc, rustdoc, cargo, clippy-driver and rustfmt ../x.py build --stage 2 library rustdoc clippy rustfmt diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs index 9aa2f3cf0a5..9645a26a68a 100644 --- a/src/tools/clippy/clippy_lints/src/dereference.rs +++ b/src/tools/clippy/clippy_lints/src/dereference.rs @@ -364,7 +364,7 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> { // priority. if let Some(fn_id) = typeck.type_dependent_def_id(hir_id) && let Some(trait_id) = cx.tcx.trait_of_assoc(fn_id) - && let arg_ty = cx.tcx.erase_regions(adjusted_ty) + && let arg_ty = cx.tcx.erase_and_anonymize_regions(adjusted_ty) && let ty::Ref(_, sub_ty, _) = *arg_ty.kind() && let args = typeck.node_args_opt(hir_id).map(|args| &args[1..]).unwrap_or_default() diff --git a/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs b/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs index 010652e1cb9..6ce7f0b1f0b 100644 --- a/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs +++ b/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs @@ -140,7 +140,7 @@ fn is_ref_iterable<'tcx>( let res_ty = cx .tcx - .erase_regions(EarlyBinder::bind(req_res_ty).instantiate(cx.tcx, typeck.node_args(call_expr.hir_id))); + .erase_and_anonymize_regions(EarlyBinder::bind(req_res_ty).instantiate(cx.tcx, typeck.node_args(call_expr.hir_id))); let mutbl = if let ty::Ref(_, _, mutbl) = *req_self_ty.kind() { Some(mutbl) } else { diff --git a/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs b/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs index a42763172f5..809a6728e12 100644 --- a/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs +++ b/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs @@ -252,7 +252,7 @@ impl<'tcx> LateLintPass<'tcx> for OnlyUsedInRecursion { { ( trait_item_id, - FnKind::ImplTraitFn(std::ptr::from_ref(cx.tcx.erase_regions(trait_ref.args)) as usize), + FnKind::ImplTraitFn(std::ptr::from_ref(cx.tcx.erase_and_anonymize_regions(trait_ref.args)) as usize), usize::from(sig.decl.implicit_self.has_implicit_self()), ) } else { diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_ref_to_ref.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_ref_to_ref.rs index 3842c4eb60e..6aeb22d41a7 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/transmute_ref_to_ref.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/transmute_ref_to_ref.rs @@ -45,7 +45,7 @@ pub(super) fn check<'tcx>( Applicability::MaybeIncorrect, ); triggered = true; - } else if (cx.tcx.erase_regions(from_ty) != cx.tcx.erase_regions(to_ty)) && !const_context { + } else if (cx.tcx.erase_and_anonymize_regions(from_ty) != cx.tcx.erase_and_anonymize_regions(to_ty)) && !const_context { span_lint_and_then( cx, TRANSMUTE_PTR_TO_PTR, diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_undefined_repr.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_undefined_repr.rs index 26323af3122..3e6aae475ec 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/transmute_undefined_repr.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/transmute_undefined_repr.rs @@ -12,8 +12,8 @@ pub(super) fn check<'tcx>( from_ty_orig: Ty<'tcx>, to_ty_orig: Ty<'tcx>, ) -> bool { - let mut from_ty = cx.tcx.erase_regions(from_ty_orig); - let mut to_ty = cx.tcx.erase_regions(to_ty_orig); + let mut from_ty = cx.tcx.erase_and_anonymize_regions(from_ty_orig); + let mut to_ty = cx.tcx.erase_and_anonymize_regions(to_ty_orig); while from_ty != to_ty { let reduced_tys = reduce_refs(cx, from_ty, to_ty); diff --git a/src/tools/clippy/clippy_lints/src/useless_conversion.rs b/src/tools/clippy/clippy_lints/src/useless_conversion.rs index 70ae982a445..e45f884cfcb 100644 --- a/src/tools/clippy/clippy_lints/src/useless_conversion.rs +++ b/src/tools/clippy/clippy_lints/src/useless_conversion.rs @@ -98,7 +98,7 @@ fn into_iter_bound<'tcx>( if tr.def_id() == into_iter_did { into_iter_span = Some(*span); } else { - let tr = cx.tcx.erase_regions(tr); + let tr = cx.tcx.erase_and_anonymize_regions(tr); if tr.has_escaping_bound_vars() { return None; } diff --git a/src/tools/clippy/clippy_utils/src/sym.rs b/src/tools/clippy/clippy_utils/src/sym.rs index 278101ac27f..8033b74a8d2 100644 --- a/src/tools/clippy/clippy_utils/src/sym.rs +++ b/src/tools/clippy/clippy_utils/src/sym.rs @@ -194,7 +194,6 @@ generate! { itertools, join, kw, - last, lazy_static, lint_vec, ln, diff --git a/src/tools/clippy/clippy_utils/src/ty/mod.rs b/src/tools/clippy/clippy_utils/src/ty/mod.rs index 8e302f9d2ad..9f77a1c4d9b 100644 --- a/src/tools/clippy/clippy_utils/src/ty/mod.rs +++ b/src/tools/clippy/clippy_utils/src/ty/mod.rs @@ -285,7 +285,7 @@ pub fn implements_trait_with_env_from_iter<'tcx>( let _ = tcx.hir_body_owner_kind(callee_id); } - let ty = tcx.erase_regions(ty); + let ty = tcx.erase_and_anonymize_regions(ty); if ty.has_escaping_bound_vars() { return false; } diff --git a/src/tools/miri/tests/pass/static_align.rs b/src/tools/miri/tests/pass/static_align.rs new file mode 100644 index 00000000000..f292f028568 --- /dev/null +++ b/src/tools/miri/tests/pass/static_align.rs @@ -0,0 +1,14 @@ +#![feature(static_align)] + +// When a static uses `align(N)`, its address should be a multiple of `N`. + +#[rustc_align_static(256)] +static FOO: u64 = 0; + +#[rustc_align_static(512)] +static BAR: u64 = 0; + +fn main() { + assert!(core::ptr::from_ref(&FOO).addr().is_multiple_of(256)); + assert!(core::ptr::from_ref(&BAR).addr().is_multiple_of(512)); +} diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index fee48bea144..60347b2ea64 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -477,7 +477,6 @@ const PERMITTED_STDLIB_DEPENDENCIES: &[&str] = &[ "rustc-demangle", "rustc-literal-escaper", "shlex", - "unicode-width", "unwinding", "wasi", "windows-sys", diff --git a/src/tools/tidy/src/issues.txt b/src/tools/tidy/src/issues.txt index ee06707415f..849dcb9e88f 100644 --- a/src/tools/tidy/src/issues.txt +++ b/src/tools/tidy/src/issues.txt @@ -2021,7 +2021,6 @@ ui/parser/issues/issue-5806.rs ui/parser/issues/issue-58094-missing-right-square-bracket.rs ui/parser/issues/issue-58856-1.rs ui/parser/issues/issue-58856-2.rs -ui/parser/issues/issue-59418.rs ui/parser/issues/issue-60075.rs ui/parser/issues/issue-61858.rs ui/parser/issues/issue-62524.rs diff --git a/tests/codegen-llvm/align-static.rs b/tests/codegen-llvm/align-static.rs new file mode 100644 index 00000000000..53db998919a --- /dev/null +++ b/tests/codegen-llvm/align-static.rs @@ -0,0 +1,31 @@ +//@ compile-flags: -C no-prepopulate-passes -Z mir-opt-level=0 + +#![crate_type = "lib"] +#![feature(static_align)] + +// CHECK: @STATIC_ALIGN = +// CHECK-SAME: align 16 +#[no_mangle] +#[rustc_align_static(16)] +pub static STATIC_ALIGN: u64 = 0; + +// CHECK: @ALIGN_SPECIFIED_TWICE_1 = +// CHECK-SAME: align 64 +#[no_mangle] +#[rustc_align_static(32)] +#[rustc_align_static(64)] +pub static ALIGN_SPECIFIED_TWICE_1: u64 = 0; + +// CHECK: @ALIGN_SPECIFIED_TWICE_2 = +// CHECK-SAME: align 128 +#[no_mangle] +#[rustc_align_static(128)] +#[rustc_align_static(32)] +pub static ALIGN_SPECIFIED_TWICE_2: u64 = 0; + +// CHECK: @ALIGN_SPECIFIED_TWICE_3 = +// CHECK-SAME: align 256 +#[no_mangle] +#[rustc_align_static(32)] +#[rustc_align_static(256)] +pub static ALIGN_SPECIFIED_TWICE_3: u64 = 0; diff --git a/tests/ui/attributes/malformed-static-align.rs b/tests/ui/attributes/malformed-static-align.rs new file mode 100644 index 00000000000..305d8acf8af --- /dev/null +++ b/tests/ui/attributes/malformed-static-align.rs @@ -0,0 +1,17 @@ +#![feature(static_align)] +#![crate_type = "lib"] + +#[rustc_align_static = 16] //~ ERROR malformed `rustc_align_static` attribute input +static S1: () = (); + +#[rustc_align_static("hello")] //~ ERROR invalid alignment value: not an unsuffixed integer +static S2: () = (); + +#[rustc_align_static(0)] //~ ERROR invalid alignment value: not a power of two +static S3: () = (); + +#[repr(align(16))] //~ ERROR `#[repr(align(...))]` is not supported on static +static S4: () = (); + +#[rustc_align_static(16)] //~ ERROR `#[rustc_align_static]` attribute cannot be used on structs +struct Struct1; diff --git a/tests/ui/attributes/malformed-static-align.stderr b/tests/ui/attributes/malformed-static-align.stderr new file mode 100644 index 00000000000..35f654d3990 --- /dev/null +++ b/tests/ui/attributes/malformed-static-align.stderr @@ -0,0 +1,45 @@ +error[E0539]: malformed `rustc_align_static` attribute input + --> $DIR/malformed-static-align.rs:4:1 + | +LL | #[rustc_align_static = 16] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | expected this to be a list + | help: must be of the form: `#[rustc_align_static(<alignment in bytes>)]` + +error[E0589]: invalid alignment value: not an unsuffixed integer + --> $DIR/malformed-static-align.rs:7:22 + | +LL | #[rustc_align_static("hello")] + | ^^^^^^^ + +error[E0589]: invalid alignment value: not a power of two + --> $DIR/malformed-static-align.rs:10:22 + | +LL | #[rustc_align_static(0)] + | ^ + +error: `#[rustc_align_static]` attribute cannot be used on structs + --> $DIR/malformed-static-align.rs:16:1 + | +LL | #[rustc_align_static(16)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: `#[rustc_align_static]` can be applied to statics and foreign statics + +error: `#[repr(align(...))]` is not supported on statics + --> $DIR/malformed-static-align.rs:13:8 + | +LL | #[repr(align(16))] + | ^^^^^^^^^ + | +help: use `#[rustc_align_static(...)]` instead + --> $DIR/malformed-static-align.rs:13:8 + | +LL | #[repr(align(16))] + | ^^^^^^^^^ + +error: aborting due to 5 previous errors + +Some errors have detailed explanations: E0539, E0589. +For more information about an error, try `rustc --explain E0539`. diff --git a/tests/ui/const-generics/std/const-generics-range.full.stderr b/tests/ui/const-generics/std/const-generics-range.full.stderr index 2b5c63e6643..ccede2af9e5 100644 --- a/tests/ui/const-generics/std/const-generics-range.full.stderr +++ b/tests/ui/const-generics/std/const-generics-range.full.stderr @@ -28,7 +28,7 @@ error[E0741]: `RangeTo<usize>` must implement `ConstParamTy` to be used as the t LL | struct _RangeTo<const R: std::ops::RangeTo<usize>>; | ^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0741]: `RangeToInclusive<usize>` must implement `ConstParamTy` to be used as the type of a const generic parameter +error[E0741]: `std::ops::RangeToInclusive<usize>` must implement `ConstParamTy` to be used as the type of a const generic parameter --> $DIR/const-generics-range.rs:34:35 | LL | struct _RangeToInclusive<const R: std::ops::RangeToInclusive<usize>>; diff --git a/tests/ui/const-generics/std/const-generics-range.min.stderr b/tests/ui/const-generics/std/const-generics-range.min.stderr index 04e3fe74453..43a57c880d5 100644 --- a/tests/ui/const-generics/std/const-generics-range.min.stderr +++ b/tests/ui/const-generics/std/const-generics-range.min.stderr @@ -58,7 +58,7 @@ help: add `#![feature(adt_const_params)]` to the crate attributes to enable more LL + #![feature(adt_const_params)] | -error: `RangeToInclusive<usize>` is forbidden as the type of a const generic parameter +error: `std::ops::RangeToInclusive<usize>` is forbidden as the type of a const generic parameter --> $DIR/const-generics-range.rs:34:35 | LL | struct _RangeToInclusive<const R: std::ops::RangeToInclusive<usize>>; diff --git a/tests/ui/const-generics/std/const-generics-range.rs b/tests/ui/const-generics/std/const-generics-range.rs index 3a238ed177e..391366dadba 100644 --- a/tests/ui/const-generics/std/const-generics-range.rs +++ b/tests/ui/const-generics/std/const-generics-range.rs @@ -7,32 +7,32 @@ // `Range` should be usable within const generics: struct _Range<const R: std::ops::Range<usize>>; //[min]~^ ERROR `std::ops::Range<usize>` is forbidden -const RANGE : _Range<{ 0 .. 1000 }> = _Range; +const RANGE: _Range<{ 0..1000 }> = _Range; // `RangeFrom` should be usable within const generics: struct _RangeFrom<const R: std::ops::RangeFrom<usize>>; //[min]~^ ERROR `std::ops::RangeFrom<usize>` is forbidden -const RANGE_FROM : _RangeFrom<{ 0 .. }> = _RangeFrom; +const RANGE_FROM: _RangeFrom<{ 0.. }> = _RangeFrom; // `RangeFull` should be usable within const generics: struct _RangeFull<const R: std::ops::RangeFull>; //[min]~^ ERROR `RangeFull` is forbidden -const RANGE_FULL : _RangeFull<{ .. }> = _RangeFull; +const RANGE_FULL: _RangeFull<{ .. }> = _RangeFull; // Regression test for #70155 // `RangeInclusive` should be usable within const generics: struct _RangeInclusive<const R: std::ops::RangeInclusive<usize>>; //[min]~^ ERROR `std::ops::RangeInclusive<usize>` is forbidden -const RANGE_INCLUSIVE : _RangeInclusive<{ 0 ..= 999 }> = _RangeInclusive; +const RANGE_INCLUSIVE: _RangeInclusive<{ 0..=999 }> = _RangeInclusive; // `RangeTo` should be usable within const generics: struct _RangeTo<const R: std::ops::RangeTo<usize>>; //[min]~^ ERROR `RangeTo<usize>` is forbidden -const RANGE_TO : _RangeTo<{ .. 1000 }> = _RangeTo; +const RANGE_TO: _RangeTo<{ ..1000 }> = _RangeTo; // `RangeToInclusive` should be usable within const generics: struct _RangeToInclusive<const R: std::ops::RangeToInclusive<usize>>; -//[min]~^ ERROR `RangeToInclusive<usize>` is forbidden -const RANGE_TO_INCLUSIVE : _RangeToInclusive<{ ..= 999 }> = _RangeToInclusive; +//[min]~^ ERROR `std::ops::RangeToInclusive<usize>` is forbidden +const RANGE_TO_INCLUSIVE: _RangeToInclusive<{ ..=999 }> = _RangeToInclusive; pub fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-static_align.rs b/tests/ui/feature-gates/feature-gate-static_align.rs new file mode 100644 index 00000000000..4d8f0e18d94 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-static_align.rs @@ -0,0 +1,11 @@ +#![crate_type = "lib"] + +#[rustc_align_static(16)] +//~^ ERROR the `#[rustc_align_static]` attribute is an experimental feature +static REQUIRES_ALIGNMENT: u64 = 0; + +extern "C" { + #[rustc_align_static(16)] + //~^ ERROR the `#[rustc_align_static]` attribute is an experimental feature + static FOREIGN_STATIC: u32; +} diff --git a/tests/ui/feature-gates/feature-gate-static_align.stderr b/tests/ui/feature-gates/feature-gate-static_align.stderr new file mode 100644 index 00000000000..b45fcdefc9c --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-static_align.stderr @@ -0,0 +1,23 @@ +error[E0658]: the `#[rustc_align_static]` attribute is an experimental feature + --> $DIR/feature-gate-static_align.rs:3:1 + | +LL | #[rustc_align_static(16)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #146177 <https://github.com/rust-lang/rust/issues/146177> for more information + = help: add `#![feature(static_align)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the `#[rustc_align_static]` attribute is an experimental feature + --> $DIR/feature-gate-static_align.rs:8:5 + | +LL | #[rustc_align_static(16)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #146177 <https://github.com/rust-lang/rust/issues/146177> for more information + = help: add `#![feature(static_align)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/iterators/ranges.stderr b/tests/ui/iterators/ranges.stderr index b9fbcd5304b..f85ce644073 100644 --- a/tests/ui/iterators/ranges.stderr +++ b/tests/ui/iterators/ranges.stderr @@ -8,15 +8,15 @@ LL | for _ in ..10 {} = note: `..end` is a `RangeTo`, which cannot be iterated on; you might have meant to have a bounded `Range`: `0..end` = note: required for `RangeTo<{integer}>` to implement `IntoIterator` -error[E0277]: `RangeToInclusive<{integer}>` is not an iterator +error[E0277]: `std::ops::RangeToInclusive<{integer}>` is not an iterator --> $DIR/ranges.rs:4:14 | LL | for _ in ..=10 {} | ^^^^^ if you meant to iterate until a value (including it), add a starting value | - = help: the trait `Iterator` is not implemented for `RangeToInclusive<{integer}>` + = help: the trait `Iterator` is not implemented for `std::ops::RangeToInclusive<{integer}>` = note: `..=end` is a `RangeToInclusive`, which cannot be iterated on; you might have meant to have a bounded `RangeInclusive`: `0..=end` - = note: required for `RangeToInclusive<{integer}>` to implement `IntoIterator` + = note: required for `std::ops::RangeToInclusive<{integer}>` to implement `IntoIterator` error: aborting due to 2 previous errors diff --git a/tests/ui/new-range/disabled.rs b/tests/ui/new-range/disabled.rs index 1a5fe3f9743..6ba29f5ca9a 100644 --- a/tests/ui/new-range/disabled.rs +++ b/tests/ui/new-range/disabled.rs @@ -6,20 +6,20 @@ fn main() { // Unchanged let a: core::range::RangeFull = ..; let b: core::range::RangeTo<u8> = ..2; - let c: core::range::RangeToInclusive<u8> = ..=3; let _: core::ops::RangeFull = a; let _: core::ops::RangeTo<u8> = b; - let _: core::ops::RangeToInclusive<u8> = c; // Changed let a: core::range::legacy::RangeFrom<u8> = 1..; let b: core::range::legacy::Range<u8> = 2..3; let c: core::range::legacy::RangeInclusive<u8> = 4..=5; + let d: core::range::legacy::RangeToInclusive<u8> = ..=3; let a: core::ops::RangeFrom<u8> = a; let b: core::ops::Range<u8> = b; let c: core::ops::RangeInclusive<u8> = c; + let d: core::ops::RangeToInclusive<u8> = d; let _: core::ops::RangeFrom<u8> = a.into_iter(); let _: core::ops::Range<u8> = b.into_iter(); diff --git a/tests/ui/new-range/enabled.rs b/tests/ui/new-range/enabled.rs index a5fb76ad52b..5ddbba492e7 100644 --- a/tests/ui/new-range/enabled.rs +++ b/tests/ui/new-range/enabled.rs @@ -7,18 +7,18 @@ fn main() { // Unchanged let a: core::range::RangeFull = ..; let b: core::range::RangeTo<u8> = ..2; - let c: core::range::RangeToInclusive<u8> = ..=3; let _: core::ops::RangeFull = a; let _: core::ops::RangeTo<u8> = b; - let _: core::ops::RangeToInclusive<u8> = c; // Changed let a: core::range::RangeFrom<u8> = 1..; let b: core::range::Range<u8> = 2..3; let c: core::range::RangeInclusive<u8> = 4..=5; + let d: core::range::RangeToInclusive<u8> = ..=3; let _: core::range::IterRangeFrom<u8> = a.into_iter(); let _: core::range::IterRange<u8> = b.into_iter(); let _: core::range::IterRangeInclusive<u8> = c.into_iter(); + // RangeToInclusive has no Iterator implementation } diff --git a/tests/ui/parser/auxiliary/tuple-index-suffix-proc-macro-aux.rs b/tests/ui/parser/auxiliary/tuple-index-suffix-proc-macro-aux.rs new file mode 100644 index 00000000000..a5084b55aac --- /dev/null +++ b/tests/ui/parser/auxiliary/tuple-index-suffix-proc-macro-aux.rs @@ -0,0 +1,33 @@ +#![feature(proc_macro_quote, proc_macro_span)] + +extern crate proc_macro; + +use proc_macro::{Ident, Literal, Span, TokenStream, TokenTree, quote}; + +#[proc_macro] +pub fn bad_tup_indexing(input: TokenStream) -> TokenStream { + let tt = input.into_iter().next().unwrap(); + let TokenTree::Literal(indexing_expr) = tt else { + unreachable!(); + }; + quote! { (42,).$indexing_expr } +} + +// Expects {IDENT, COMMA, LITERAL} +#[proc_macro] +pub fn bad_tup_struct_indexing(input: TokenStream) -> TokenStream { + let mut input = input.into_iter(); + + let ident = input.next().unwrap(); + let _comma = input.next().unwrap(); + let lit = input.next().unwrap(); + + let TokenTree::Ident(ident) = ident else { + unreachable!("id"); + }; + let TokenTree::Literal(indexing_expr) = lit else { + unreachable!("lit"); + }; + + quote! { $ident.$indexing_expr } +} diff --git a/tests/ui/parser/issues/issue-59418.rs b/tests/ui/parser/issues/issue-59418.rs deleted file mode 100644 index 0fa191d4a7e..00000000000 --- a/tests/ui/parser/issues/issue-59418.rs +++ /dev/null @@ -1,18 +0,0 @@ -struct X(i32,i32,i32); - -fn main() { - let a = X(1, 2, 3); - let b = a.1suffix; - //~^ ERROR suffixes on a tuple index are invalid - println!("{}", b); - let c = (1, 2, 3); - let d = c.1suffix; - //~^ ERROR suffixes on a tuple index are invalid - println!("{}", d); - let s = X { 0suffix: 0, 1: 1, 2: 2 }; - //~^ ERROR suffixes on a tuple index are invalid - match s { - X { 0suffix: _, .. } => {} - //~^ ERROR suffixes on a tuple index are invalid - } -} diff --git a/tests/ui/parser/issues/issue-59418.stderr b/tests/ui/parser/issues/issue-59418.stderr deleted file mode 100644 index 347051e9f92..00000000000 --- a/tests/ui/parser/issues/issue-59418.stderr +++ /dev/null @@ -1,26 +0,0 @@ -error: suffixes on a tuple index are invalid - --> $DIR/issue-59418.rs:5:15 - | -LL | let b = a.1suffix; - | ^^^^^^^ invalid suffix `suffix` - -error: suffixes on a tuple index are invalid - --> $DIR/issue-59418.rs:9:15 - | -LL | let d = c.1suffix; - | ^^^^^^^ invalid suffix `suffix` - -error: suffixes on a tuple index are invalid - --> $DIR/issue-59418.rs:12:17 - | -LL | let s = X { 0suffix: 0, 1: 1, 2: 2 }; - | ^^^^^^^ invalid suffix `suffix` - -error: suffixes on a tuple index are invalid - --> $DIR/issue-59418.rs:15:13 - | -LL | X { 0suffix: _, .. } => {} - | ^^^^^^^ invalid suffix `suffix` - -error: aborting due to 4 previous errors - diff --git a/tests/ui/parser/tuple-index-suffix-proc-macro.rs b/tests/ui/parser/tuple-index-suffix-proc-macro.rs new file mode 100644 index 00000000000..557c67738d3 --- /dev/null +++ b/tests/ui/parser/tuple-index-suffix-proc-macro.rs @@ -0,0 +1,32 @@ +//! See #59418. +//! +//! Like `tuple-index-suffix.rs`, but exercises the proc-macro interaction. + +//@ proc-macro: tuple-index-suffix-proc-macro-aux.rs + +extern crate tuple_index_suffix_proc_macro_aux; +use tuple_index_suffix_proc_macro_aux as aux; + +fn main() { + struct TupStruct(i32); + let tup_struct = TupStruct(42); + + // Previously, #60186 had carve outs for `{i,u}{32,usize}` as non-lint pseudo-FCW warnings. Now, + // they all hard error. + + aux::bad_tup_indexing!(0usize); + //~^ ERROR suffixes on a tuple index are invalid + aux::bad_tup_struct_indexing!(tup_struct, 0isize); + //~^ ERROR suffixes on a tuple index are invalid + + // Not part of the #60186 carve outs. + + aux::bad_tup_indexing!(0u8); + //~^ ERROR suffixes on a tuple index are invalid + aux::bad_tup_struct_indexing!(tup_struct, 0u64); + //~^ ERROR suffixes on a tuple index are invalid + + // NOTE: didn't bother with trying to figure out how to generate `struct P { 0u32: u32 }` using + // *only* `proc_macro` without help with `syn`/`quote`, looks like you can't with just + // `proc_macro::quote`? +} diff --git a/tests/ui/parser/tuple-index-suffix-proc-macro.stderr b/tests/ui/parser/tuple-index-suffix-proc-macro.stderr new file mode 100644 index 00000000000..47d179d3555 --- /dev/null +++ b/tests/ui/parser/tuple-index-suffix-proc-macro.stderr @@ -0,0 +1,26 @@ +error: suffixes on a tuple index are invalid + --> $DIR/tuple-index-suffix-proc-macro.rs:17:28 + | +LL | aux::bad_tup_indexing!(0usize); + | ^^^^^^ invalid suffix `usize` + +error: suffixes on a tuple index are invalid + --> $DIR/tuple-index-suffix-proc-macro.rs:19:47 + | +LL | aux::bad_tup_struct_indexing!(tup_struct, 0isize); + | ^^^^^^ invalid suffix `isize` + +error: suffixes on a tuple index are invalid + --> $DIR/tuple-index-suffix-proc-macro.rs:24:28 + | +LL | aux::bad_tup_indexing!(0u8); + | ^^^ invalid suffix `u8` + +error: suffixes on a tuple index are invalid + --> $DIR/tuple-index-suffix-proc-macro.rs:26:47 + | +LL | aux::bad_tup_struct_indexing!(tup_struct, 0u64); + | ^^^^ invalid suffix `u64` + +error: aborting due to 4 previous errors + diff --git a/tests/ui/parser/tuple-index-suffix.rs b/tests/ui/parser/tuple-index-suffix.rs new file mode 100644 index 00000000000..c4769500005 --- /dev/null +++ b/tests/ui/parser/tuple-index-suffix.rs @@ -0,0 +1,79 @@ +//! Regression test for both the original regression in #59418 where invalid suffixes in indexing +//! positions were accidentally accepted, and also for the removal of the temporary carve out that +//! mitigated ecosystem impact following trying to reject #59418 (this was implemented as a FCW +//! tracked in #60210). +//! +//! Check that we hard error on invalid suffixes in tuple indexing subexpressions and struct numeral +//! field names. + +struct X(i32,i32,i32); + +fn main() { + let tup_struct = X(1, 2, 3); + let invalid_tup_struct_suffix = tup_struct.0suffix; + //~^ ERROR suffixes on a tuple index are invalid + let previous_carve_out_tup_struct_suffix = tup_struct.0i32; + //~^ ERROR suffixes on a tuple index are invalid + + let tup = (1, 2, 3); + let invalid_tup_suffix = tup.0suffix; + //~^ ERROR suffixes on a tuple index are invalid + let previous_carve_out_tup_suffix = tup.0u32; + //~^ ERROR suffixes on a tuple index are invalid + + numeral_struct_field_name_suffix_invalid(); + numeral_struct_field_name_suffix_previous_carve_out(); +} + +// Previously, there were very limited carve outs as a ecosystem impact mitigation implemented in +// #60186. *Only* `{i,u}{32,usize}` suffixes were temporarily accepted. Now, they all hard error. +fn previous_carve_outs() { + // Previously temporarily accepted by a pseudo-FCW (#60210), now hard error. + + let previous_carve_out_i32 = (42,).0i32; //~ ERROR suffixes on a tuple index are invalid + let previous_carve_out_i32 = (42,).0u32; //~ ERROR suffixes on a tuple index are invalid + let previous_carve_out_isize = (42,).0isize; //~ ERROR suffixes on a tuple index are invalid + let previous_carve_out_usize = (42,).0usize; //~ ERROR suffixes on a tuple index are invalid + + // Not part of the carve outs! + let error_i8 = (42,).0i8; //~ ERROR suffixes on a tuple index are invalid + let error_u8 = (42,).0u8; //~ ERROR suffixes on a tuple index are invalid + let error_i16 = (42,).0i16; //~ ERROR suffixes on a tuple index are invalid + let error_u16 = (42,).0u16; //~ ERROR suffixes on a tuple index are invalid + let error_i64 = (42,).0i64; //~ ERROR suffixes on a tuple index are invalid + let error_u64 = (42,).0u64; //~ ERROR suffixes on a tuple index are invalid + let error_i128 = (42,).0i128; //~ ERROR suffixes on a tuple index are invalid + let error_u128 = (42,).0u128; //~ ERROR suffixes on a tuple index are invalid +} + +fn numeral_struct_field_name_suffix_invalid() { + let invalid_struct_name = X { 0suffix: 0, 1: 1, 2: 2 }; + //~^ ERROR suffixes on a tuple index are invalid + match invalid_struct_name { + X { 0suffix: _, .. } => {} + //~^ ERROR suffixes on a tuple index are invalid + } +} + +fn numeral_struct_field_name_suffix_previous_carve_out() { + let carve_out_struct_name = X { 0u32: 0, 1: 1, 2: 2 }; + //~^ ERROR suffixes on a tuple index are invalid + match carve_out_struct_name { + X { 0u32: _, .. } => {} + //~^ ERROR suffixes on a tuple index are invalid + } +} + +// Unfortunately, it turns out `std::mem::offset_of!` uses the same expect suffix code path. +fn offset_of_suffix() { + #[repr(C)] + pub struct Struct<T>(u8, T); + + // Previous pseudo-FCW carve outs + assert_eq!(std::mem::offset_of!(Struct<u32>, 0usize), 0); + //~^ ERROR suffixes on a tuple index are invalid + + // Not part of carve outs + assert_eq!(std::mem::offset_of!(Struct<u32>, 0u8), 0); + //~^ ERROR suffixes on a tuple index are invalid +} diff --git a/tests/ui/parser/tuple-index-suffix.stderr b/tests/ui/parser/tuple-index-suffix.stderr new file mode 100644 index 00000000000..6d96c6d3cbf --- /dev/null +++ b/tests/ui/parser/tuple-index-suffix.stderr @@ -0,0 +1,134 @@ +error: suffixes on a tuple index are invalid + --> $DIR/tuple-index-suffix.rs:13:48 + | +LL | let invalid_tup_struct_suffix = tup_struct.0suffix; + | ^^^^^^^ invalid suffix `suffix` + +error: suffixes on a tuple index are invalid + --> $DIR/tuple-index-suffix.rs:15:59 + | +LL | let previous_carve_out_tup_struct_suffix = tup_struct.0i32; + | ^^^^ invalid suffix `i32` + +error: suffixes on a tuple index are invalid + --> $DIR/tuple-index-suffix.rs:19:34 + | +LL | let invalid_tup_suffix = tup.0suffix; + | ^^^^^^^ invalid suffix `suffix` + +error: suffixes on a tuple index are invalid + --> $DIR/tuple-index-suffix.rs:21:45 + | +LL | let previous_carve_out_tup_suffix = tup.0u32; + | ^^^^ invalid suffix `u32` + +error: suffixes on a tuple index are invalid + --> $DIR/tuple-index-suffix.rs:33:40 + | +LL | let previous_carve_out_i32 = (42,).0i32; + | ^^^^ invalid suffix `i32` + +error: suffixes on a tuple index are invalid + --> $DIR/tuple-index-suffix.rs:34:40 + | +LL | let previous_carve_out_i32 = (42,).0u32; + | ^^^^ invalid suffix `u32` + +error: suffixes on a tuple index are invalid + --> $DIR/tuple-index-suffix.rs:35:42 + | +LL | let previous_carve_out_isize = (42,).0isize; + | ^^^^^^ invalid suffix `isize` + +error: suffixes on a tuple index are invalid + --> $DIR/tuple-index-suffix.rs:36:42 + | +LL | let previous_carve_out_usize = (42,).0usize; + | ^^^^^^ invalid suffix `usize` + +error: suffixes on a tuple index are invalid + --> $DIR/tuple-index-suffix.rs:39:26 + | +LL | let error_i8 = (42,).0i8; + | ^^^ invalid suffix `i8` + +error: suffixes on a tuple index are invalid + --> $DIR/tuple-index-suffix.rs:40:26 + | +LL | let error_u8 = (42,).0u8; + | ^^^ invalid suffix `u8` + +error: suffixes on a tuple index are invalid + --> $DIR/tuple-index-suffix.rs:41:27 + | +LL | let error_i16 = (42,).0i16; + | ^^^^ invalid suffix `i16` + +error: suffixes on a tuple index are invalid + --> $DIR/tuple-index-suffix.rs:42:27 + | +LL | let error_u16 = (42,).0u16; + | ^^^^ invalid suffix `u16` + +error: suffixes on a tuple index are invalid + --> $DIR/tuple-index-suffix.rs:43:27 + | +LL | let error_i64 = (42,).0i64; + | ^^^^ invalid suffix `i64` + +error: suffixes on a tuple index are invalid + --> $DIR/tuple-index-suffix.rs:44:27 + | +LL | let error_u64 = (42,).0u64; + | ^^^^ invalid suffix `u64` + +error: suffixes on a tuple index are invalid + --> $DIR/tuple-index-suffix.rs:45:28 + | +LL | let error_i128 = (42,).0i128; + | ^^^^^ invalid suffix `i128` + +error: suffixes on a tuple index are invalid + --> $DIR/tuple-index-suffix.rs:46:28 + | +LL | let error_u128 = (42,).0u128; + | ^^^^^ invalid suffix `u128` + +error: suffixes on a tuple index are invalid + --> $DIR/tuple-index-suffix.rs:50:35 + | +LL | let invalid_struct_name = X { 0suffix: 0, 1: 1, 2: 2 }; + | ^^^^^^^ invalid suffix `suffix` + +error: suffixes on a tuple index are invalid + --> $DIR/tuple-index-suffix.rs:53:13 + | +LL | X { 0suffix: _, .. } => {} + | ^^^^^^^ invalid suffix `suffix` + +error: suffixes on a tuple index are invalid + --> $DIR/tuple-index-suffix.rs:59:37 + | +LL | let carve_out_struct_name = X { 0u32: 0, 1: 1, 2: 2 }; + | ^^^^ invalid suffix `u32` + +error: suffixes on a tuple index are invalid + --> $DIR/tuple-index-suffix.rs:62:13 + | +LL | X { 0u32: _, .. } => {} + | ^^^^ invalid suffix `u32` + +error: suffixes on a tuple index are invalid + --> $DIR/tuple-index-suffix.rs:73:50 + | +LL | assert_eq!(std::mem::offset_of!(Struct<u32>, 0usize), 0); + | ^^^^^^ invalid suffix `usize` + +error: suffixes on a tuple index are invalid + --> $DIR/tuple-index-suffix.rs:77:50 + | +LL | assert_eq!(std::mem::offset_of!(Struct<u32>, 0u8), 0); + | ^^^ invalid suffix `u8` + +error: aborting due to 22 previous errors + diff --git a/tests/ui/range/issue-54505-no-literals.stderr b/tests/ui/range/issue-54505-no-literals.stderr index c6d4384bcd3..62e2fe4a838 100644 --- a/tests/ui/range/issue-54505-no-literals.stderr +++ b/tests/ui/range/issue-54505-no-literals.stderr @@ -207,7 +207,7 @@ LL | take_range(std::ops::RangeToInclusive { end: 5 }); | arguments to this function are incorrect | = note: expected reference `&_` - found struct `RangeToInclusive<{integer}>` + found struct `std::ops::RangeToInclusive<{integer}>` note: function defined here --> $DIR/issue-54505-no-literals.rs:12:4 | @@ -227,7 +227,7 @@ LL | take_range(::std::ops::RangeToInclusive { end: 5 }); | arguments to this function are incorrect | = note: expected reference `&_` - found struct `RangeToInclusive<{integer}>` + found struct `std::ops::RangeToInclusive<{integer}>` note: function defined here --> $DIR/issue-54505-no-literals.rs:12:4 | diff --git a/tests/ui/range/issue-54505-no-std.stderr b/tests/ui/range/issue-54505-no-std.stderr index 2aa1d584046..866a82afb7e 100644 --- a/tests/ui/range/issue-54505-no-std.stderr +++ b/tests/ui/range/issue-54505-no-std.stderr @@ -112,7 +112,7 @@ LL | take_range(..=42); | arguments to this function are incorrect | = note: expected reference `&_` - found struct `RangeToInclusive<{integer}>` + found struct `core::ops::RangeToInclusive<{integer}>` note: function defined here --> $DIR/issue-54505-no-std.rs:25:4 | diff --git a/tests/ui/range/issue-54505.stderr b/tests/ui/range/issue-54505.stderr index 8b669b2910f..4d94c6c2d09 100644 --- a/tests/ui/range/issue-54505.stderr +++ b/tests/ui/range/issue-54505.stderr @@ -112,7 +112,7 @@ LL | take_range(..=42); | arguments to this function are incorrect | = note: expected reference `&_` - found struct `RangeToInclusive<{integer}>` + found struct `std::ops::RangeToInclusive<{integer}>` note: function defined here --> $DIR/issue-54505.rs:10:4 | diff --git a/tests/ui/static/static-align.rs b/tests/ui/static/static-align.rs new file mode 100644 index 00000000000..93241db09f9 --- /dev/null +++ b/tests/ui/static/static-align.rs @@ -0,0 +1,26 @@ +//@ run-pass +#![feature(static_align)] + +#[rustc_align_static(64)] +static A: u8 = 0; + +#[rustc_align_static(64)] +static B: u8 = 0; + +#[rustc_align_static(128)] +#[no_mangle] +static EXPORTED: u64 = 0; + +unsafe extern "C" { + #[rustc_align_static(128)] + #[link_name = "EXPORTED"] + static C: u64; +} + +fn main() { + assert!(core::ptr::from_ref(&A).addr().is_multiple_of(64)); + assert!(core::ptr::from_ref(&B).addr().is_multiple_of(64)); + + assert!(core::ptr::from_ref(&EXPORTED).addr().is_multiple_of(128)); + unsafe { assert!(core::ptr::from_ref(&C).addr().is_multiple_of(128)) }; +} diff --git a/tests/ui/suggestions/apitit-unimplemented-method.rs b/tests/ui/suggestions/apitit-unimplemented-method.rs new file mode 100644 index 00000000000..b182e1939b3 --- /dev/null +++ b/tests/ui/suggestions/apitit-unimplemented-method.rs @@ -0,0 +1,12 @@ +//@ aux-build:dep.rs + +extern crate dep; +use dep::*; + +struct Local; +impl Trait for Local {} +//~^ ERROR not all trait items implemented +//~| HELP implement the missing item: `fn foo(_: impl Sized) { todo!() }` +//~| HELP implement the missing item: `fn bar<T>(_: impl Sized) { todo!() }` + +fn main() {} diff --git a/tests/ui/suggestions/apitit-unimplemented-method.stderr b/tests/ui/suggestions/apitit-unimplemented-method.stderr new file mode 100644 index 00000000000..b309a64e958 --- /dev/null +++ b/tests/ui/suggestions/apitit-unimplemented-method.stderr @@ -0,0 +1,12 @@ +error[E0046]: not all trait items implemented, missing: `foo`, `bar` + --> $DIR/apitit-unimplemented-method.rs:7:1 + | +LL | impl Trait for Local {} + | ^^^^^^^^^^^^^^^^^^^^ missing `foo`, `bar` in implementation + | + = help: implement the missing item: `fn foo(_: impl Sized) { todo!() }` + = help: implement the missing item: `fn bar<T>(_: impl Sized) { todo!() }` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0046`. diff --git a/tests/ui/suggestions/auxiliary/dep.rs b/tests/ui/suggestions/auxiliary/dep.rs new file mode 100644 index 00000000000..ac0de418313 --- /dev/null +++ b/tests/ui/suggestions/auxiliary/dep.rs @@ -0,0 +1,4 @@ +pub trait Trait { + fn foo(_: impl Sized); + fn bar<T>(_: impl Sized); +} diff --git a/triagebot.toml b/triagebot.toml index bf9bfee4306..2d58c616bc2 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -1308,21 +1308,32 @@ cc = ["@m-ou-se"] [mentions."compiler/rustc_ast_lowering/src/format.rs"] cc = ["@m-ou-se"] +# Content-based mentions + [mentions."#[miri::intrinsic_fallback_is_spec]"] type = "content" message = """ -`#[miri::intrinsic_fallback_is_spec]` must only be used if the function actively checks for all UB cases, +⚠️ `#[miri::intrinsic_fallback_is_spec]` must only be used if the function actively checks for all UB cases, and explores the possible non-determinism of the intrinsic. """ cc = ["@rust-lang/miri"] + [mentions."#[rustc_allow_const_fn_unstable"] type = "content" message = """ -`#[rustc_allow_const_fn_unstable]` needs careful audit to avoid accidentally exposing unstable +⚠️ `#[rustc_allow_const_fn_unstable]` needs careful audit to avoid accidentally exposing unstable implementation details on stable. """ cc = ["@rust-lang/wg-const-eval"] +[mentions."#[rustc_intrinsic_const_stable_indirect]"] +type = "content" +message = """ +⚠️ `#[rustc_intrinsic_const_stable_indirect]` controls whether intrinsics can be exposed to stable const +code; adding it needs t-lang approval. +""" +cc = ["@rust-lang/wg-const-eval"] + # ------------------------------------------------------------------------------ # PR assignments |
