diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 6514de2b81315..474ec2b589b71 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -665,6 +665,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session) { // involved, so we only emit errors where there are no other parsing errors. gate_all!(destructuring_assignment, "destructuring assignments are unstable"); } + gate_all!(pub_macro_rules, "`pub` on `macro_rules` items is unstable"); // All uses of `gate_all!` below this point were added in #65742, // and subsequently disabled (with the non-early gating readded). diff --git a/compiler/rustc_codegen_ssa/src/mir/analyze.rs b/compiler/rustc_codegen_ssa/src/mir/analyze.rs index fd0ff5b66e607..289629d921545 100644 --- a/compiler/rustc_codegen_ssa/src/mir/analyze.rs +++ b/compiler/rustc_codegen_ssa/src/mir/analyze.rs @@ -199,7 +199,7 @@ impl> LocalAnalyzer<'mir, 'a, 'tcx, Bx> { } self.visit_local(&place_ref.local, context, location); - self.visit_projection(place_ref.local, place_ref.projection, context, location); + self.visit_projection(*place_ref, context, location); } } } diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index 2d0009c225c59..3f484ab568652 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -638,6 +638,9 @@ declare_features! ( /// Allows macro attributes to observe output of `#[derive]`. (active, macro_attributes_in_derive_output, "1.51.0", Some(81119), None), + /// Allows `pub` on `macro_rules` items. + (active, pub_macro_rules, "1.52.0", Some(78855), None), + // ------------------------------------------------------------------------- // feature-group-end: actual feature gates // ------------------------------------------------------------------------- diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index 023555d91cc92..9530efaedbce4 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -998,12 +998,11 @@ macro_rules! visit_place_fns { () => { fn visit_projection( &mut self, - local: Local, - projection: &[PlaceElem<'tcx>], + place_ref: PlaceRef<'tcx>, context: PlaceContext, location: Location, ) { - self.super_projection(local, projection, context, location); + self.super_projection(place_ref, context, location); } fn visit_projection_elem( @@ -1033,20 +1032,20 @@ macro_rules! visit_place_fns { self.visit_local(&place.local, context, location); - self.visit_projection(place.local, &place.projection, context, location); + self.visit_projection(place.as_ref(), context, location); } fn super_projection( &mut self, - local: Local, - projection: &[PlaceElem<'tcx>], + place_ref: PlaceRef<'tcx>, context: PlaceContext, location: Location, ) { - let mut cursor = projection; + // FIXME: Use PlaceRef::iter_projections, once that exists. + let mut cursor = place_ref.projection; while let &[ref proj_base @ .., elem] = cursor { cursor = proj_base; - self.visit_projection_elem(local, cursor, elem, context, location); + self.visit_projection_elem(place_ref.local, cursor, elem, context, location); } } diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 64604b6459f27..53c164d44b3e1 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -1018,7 +1018,7 @@ pub trait PrettyPrinter<'tcx>: p!(write("{:?}", char::try_from(int).unwrap())) } // Raw pointers - (Scalar::Int(int), ty::RawPtr(_)) => { + (Scalar::Int(int), ty::RawPtr(_) | ty::FnPtr(_)) => { let data = int.assert_bits(self.tcx().data_layout.pointer_size); self = self.typed_value( |mut this| { @@ -1030,15 +1030,18 @@ pub trait PrettyPrinter<'tcx>: )?; } (Scalar::Ptr(ptr), ty::FnPtr(_)) => { - // FIXME: this can ICE when the ptr is dangling or points to a non-function. - // We should probably have a helper method to share code with the "Byte strings" + // FIXME: We should probably have a helper method to share code with the "Byte strings" // printing above (which also has to handle pointers to all sorts of things). - let instance = self.tcx().global_alloc(ptr.alloc_id).unwrap_fn(); - self = self.typed_value( - |this| this.print_value_path(instance.def_id(), instance.substs), - |this| this.print_type(ty), - " as ", - )?; + match self.tcx().get_global_alloc(ptr.alloc_id) { + Some(GlobalAlloc::Function(instance)) => { + self = self.typed_value( + |this| this.print_value_path(instance.def_id(), instance.substs), + |this| this.print_type(ty), + " as ", + )?; + } + _ => self = self.pretty_print_const_pointer(ptr, ty, print_ty)?, + } } // For function type zsts just printing the path is enough (Scalar::Int(int), ty::FnDef(d, s)) if int == ScalarInt::ZST => { diff --git a/compiler/rustc_mir/src/dataflow/impls/liveness.rs b/compiler/rustc_mir/src/dataflow/impls/liveness.rs index 85aaff5ab7293..2d20f0d9547c1 100644 --- a/compiler/rustc_mir/src/dataflow/impls/liveness.rs +++ b/compiler/rustc_mir/src/dataflow/impls/liveness.rs @@ -95,7 +95,7 @@ where // We purposefully do not call `super_place` here to avoid calling `visit_local` for this // place with one of the `Projection` variants of `PlaceContext`. - self.visit_projection(local, projection, context, location); + self.visit_projection(place.as_ref(), context, location); match DefUse::for_place(context) { // Treat derefs as a use of the base local. `*p = 4` is not a def of `p` but a use. diff --git a/compiler/rustc_mir/src/interpret/operand.rs b/compiler/rustc_mir/src/interpret/operand.rs index 88236458a213a..4b131ecb863ad 100644 --- a/compiler/rustc_mir/src/interpret/operand.rs +++ b/compiler/rustc_mir/src/interpret/operand.rs @@ -106,7 +106,7 @@ impl std::fmt::Display for ImmTy<'tcx, Tag> { } ScalarMaybeUninit::Uninit => cx.typed_value( |mut this| { - this.write_str("{uninit ")?; + this.write_str("uninit ")?; Ok(this) }, |this| this.print_type(ty), diff --git a/compiler/rustc_mir/src/transform/check_consts/validation.rs b/compiler/rustc_mir/src/transform/check_consts/validation.rs index 4973450ca8374..a82636837122f 100644 --- a/compiler/rustc_mir/src/transform/check_consts/validation.rs +++ b/compiler/rustc_mir/src/transform/check_consts/validation.rs @@ -515,7 +515,7 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> { // Special-case reborrows to be more like a copy of a reference. match *rvalue { Rvalue::Ref(_, kind, place) => { - if let Some(reborrowed_proj) = place_as_reborrow(self.tcx, self.body, place) { + if let Some(reborrowed_place_ref) = place_as_reborrow(self.tcx, self.body, place) { let ctx = match kind { BorrowKind::Shared => { PlaceContext::NonMutatingUse(NonMutatingUseContext::SharedBorrow) @@ -530,21 +530,21 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> { PlaceContext::MutatingUse(MutatingUseContext::Borrow) } }; - self.visit_local(&place.local, ctx, location); - self.visit_projection(place.local, reborrowed_proj, ctx, location); + self.visit_local(&reborrowed_place_ref.local, ctx, location); + self.visit_projection(reborrowed_place_ref, ctx, location); return; } } Rvalue::AddressOf(mutbl, place) => { - if let Some(reborrowed_proj) = place_as_reborrow(self.tcx, self.body, place) { + if let Some(reborrowed_place_ref) = place_as_reborrow(self.tcx, self.body, place) { let ctx = match mutbl { Mutability::Not => { PlaceContext::NonMutatingUse(NonMutatingUseContext::AddressOf) } Mutability::Mut => PlaceContext::MutatingUse(MutatingUseContext::AddressOf), }; - self.visit_local(&place.local, ctx, location); - self.visit_projection(place.local, reborrowed_proj, ctx, location); + self.visit_local(&reborrowed_place_ref.local, ctx, location); + self.visit_projection(reborrowed_place_ref, ctx, location); return; } } @@ -1039,7 +1039,7 @@ fn place_as_reborrow( tcx: TyCtxt<'tcx>, body: &Body<'tcx>, place: Place<'tcx>, -) -> Option<&'a [PlaceElem<'tcx>]> { +) -> Option> { match place.as_ref().last_projection() { Some((place_base, ProjectionElem::Deref)) => { // A borrow of a `static` also looks like `&(*_1)` in the MIR, but `_1` is a `const` @@ -1048,13 +1048,14 @@ fn place_as_reborrow( None } else { // Ensure the type being derefed is a reference and not a raw pointer. - // // This is sufficient to prevent an access to a `static mut` from being marked as a // reborrow, even if the check above were to disappear. let inner_ty = place_base.ty(body, tcx).ty; - match inner_ty.kind() { - ty::Ref(..) => Some(place_base.projection), - _ => None, + + if let ty::Ref(..) = inner_ty.kind() { + return Some(place_base); + } else { + return None; } } } diff --git a/compiler/rustc_mir/src/transform/simplify.rs b/compiler/rustc_mir/src/transform/simplify.rs index 11539d3ef30f4..ae4f15b3bbc4d 100644 --- a/compiler/rustc_mir/src/transform/simplify.rs +++ b/compiler/rustc_mir/src/transform/simplify.rs @@ -413,8 +413,7 @@ impl UsedLocals { } else { // A definition. Although, it still might use other locals for indexing. self.super_projection( - place.local, - &place.projection, + place.as_ref(), PlaceContext::MutatingUse(MutatingUseContext::Projection), location, ); diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 0f907859a19a6..07c7b60a90fcd 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -1475,15 +1475,7 @@ impl<'a> Parser<'a> { let vstr = pprust::vis_to_string(vis); let vstr = vstr.trim_end(); if macro_rules { - let msg = format!("can't qualify macro_rules invocation with `{}`", vstr); - self.struct_span_err(vis.span, &msg) - .span_suggestion( - vis.span, - "try exporting the macro", - "#[macro_export]".to_owned(), - Applicability::MaybeIncorrect, // speculative - ) - .emit(); + self.sess.gated_spans.gate(sym::pub_macro_rules, vis.span); } else { self.struct_span_err(vis.span, "can't qualify macro invocation with `pub`") .span_suggestion( diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index d51b501f7ae3d..62a95aa57c29f 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -37,15 +37,6 @@ fn should_explore(tcx: TyCtxt<'_>, hir_id: hir::HirId) -> bool { ) } -fn base_expr<'a>(mut expr: &'a hir::Expr<'a>) -> &'a hir::Expr<'a> { - loop { - match expr.kind { - hir::ExprKind::Field(base, ..) => expr = base, - _ => return expr, - } - } -} - struct MarkSymbolVisitor<'tcx> { worklist: Vec, tcx: TyCtxt<'tcx>, @@ -143,6 +134,22 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { } } + fn handle_assign(&mut self, expr: &'tcx hir::Expr<'tcx>) { + if self + .typeck_results() + .expr_adjustments(expr) + .iter() + .any(|adj| matches!(adj.kind, ty::adjustment::Adjust::Deref(_))) + { + self.visit_expr(expr); + } else if let hir::ExprKind::Field(base, ..) = expr.kind { + // Ignore write to field + self.handle_assign(base); + } else { + self.visit_expr(expr); + } + } + fn handle_field_pattern_match( &mut self, lhs: &hir::Pat<'_>, @@ -272,8 +279,7 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> { self.lookup_and_handle_method(expr.hir_id); } hir::ExprKind::Assign(ref left, ref right, ..) => { - // Ignore write to field - self.visit_expr(base_expr(left)); + self.handle_assign(left); self.visit_expr(right); return; } diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 79ed0b5308dab..65e5b0dddea30 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -1230,13 +1230,13 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { }; let res = Res::Def(DefKind::Macro(ext.macro_kind()), def_id.to_def_id()); + let is_macro_export = self.r.session.contains_name(&item.attrs, sym::macro_export); self.r.macro_map.insert(def_id.to_def_id(), ext); self.r.local_macro_def_scopes.insert(def_id, parent_scope.module); - if macro_rules { + if macro_rules && matches!(item.vis.kind, ast::VisibilityKind::Inherited) { let ident = ident.normalize_to_macros_2_0(); self.r.macro_names.insert(ident); - let is_macro_export = self.r.session.contains_name(&item.attrs, sym::macro_export); let vis = if is_macro_export { ty::Visibility::Public } else { @@ -1261,6 +1261,11 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { }), )) } else { + if is_macro_export { + let what = if macro_rules { "`macro_rules` with `pub`" } else { "`macro` items" }; + let msg = format!("`#[macro_export]` cannot be used on {what}"); + self.r.session.span_err(item.span, &msg); + } let module = parent_scope.module; let vis = match item.kind { // Visibilities must not be resolved non-speculatively twice diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 653d70b6cf244..d4a0f968eee1e 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -874,6 +874,7 @@ symbols! { ptr_guaranteed_eq, ptr_guaranteed_ne, ptr_offset_from, + pub_macro_rules, pub_restricted, pure, pushpop_unsafe, diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 5b14795f5457c..f7b49ac52b0af 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -641,6 +641,7 @@ supported_targets! { ("powerpc64le-unknown-linux-gnu", powerpc64le_unknown_linux_gnu), ("powerpc64le-unknown-linux-musl", powerpc64le_unknown_linux_musl), ("s390x-unknown-linux-gnu", s390x_unknown_linux_gnu), + ("s390x-unknown-linux-musl", s390x_unknown_linux_musl), ("sparc-unknown-linux-gnu", sparc_unknown_linux_gnu), ("sparc64-unknown-linux-gnu", sparc64_unknown_linux_gnu), ("arm-unknown-linux-gnueabi", arm_unknown_linux_gnueabi), diff --git a/compiler/rustc_target/src/spec/s390x_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/s390x_unknown_linux_musl.rs new file mode 100644 index 0000000000000..4f811ce98c181 --- /dev/null +++ b/compiler/rustc_target/src/spec/s390x_unknown_linux_musl.rs @@ -0,0 +1,24 @@ +use crate::abi::Endian; +use crate::spec::Target; + +pub fn target() -> Target { + let mut base = super::linux_musl_base::opts(); + base.endian = Endian::Big; + // z10 is the oldest CPU supported by LLVM + base.cpu = "z10".to_string(); + // FIXME: The data_layout string below and the ABI implementation in + // cabi_s390x.rs are for now hard-coded to assume the no-vector ABI. + // Pass the -vector feature string to LLVM to respect this assumption. + base.features = "-vector".to_string(); + base.max_atomic_width = Some(64); + base.min_global_align = Some(16); + base.static_position_independent_executables = true; + + Target { + llvm_target: "s390x-unknown-linux-musl".to_string(), + pointer_width: 64, + data_layout: "E-m:e-i1:8:16-i8:8:16-i64:64-f128:64-a:8:16-n32:64".to_string(), + arch: "s390x".to_string(), + options: base, + } +} diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs index 7f27325f7f96f..f5e9cc1efcc45 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs @@ -1074,13 +1074,26 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; let last_expr_ty = self.node_ty(last_expr.hir_id); let needs_box = match (last_expr_ty.kind(), expected_ty.kind()) { + (ty::Opaque(last_def_id, _), ty::Opaque(exp_def_id, _)) + if last_def_id == exp_def_id => + { + StatementAsExpression::CorrectType + } (ty::Opaque(last_def_id, last_bounds), ty::Opaque(exp_def_id, exp_bounds)) => { debug!( "both opaque, likely future {:?} {:?} {:?} {:?}", last_def_id, last_bounds, exp_def_id, exp_bounds ); - let last_hir_id = self.tcx.hir().local_def_id_to_hir_id(last_def_id.expect_local()); - let exp_hir_id = self.tcx.hir().local_def_id_to_hir_id(exp_def_id.expect_local()); + + let (last_local_id, exp_local_id) = + match (last_def_id.as_local(), exp_def_id.as_local()) { + (Some(last_hir_id), Some(exp_hir_id)) => (last_hir_id, exp_hir_id), + (_, _) => return None, + }; + + let last_hir_id = self.tcx.hir().local_def_id_to_hir_id(last_local_id); + let exp_hir_id = self.tcx.hir().local_def_id_to_hir_id(exp_local_id); + match ( &self.tcx.hir().expect_item(last_hir_id).kind, &self.tcx.hir().expect_item(exp_hir_id).kind, diff --git a/library/core/benches/ascii.rs b/library/core/benches/ascii.rs index bc59c378609f0..64938745a4a16 100644 --- a/library/core/benches/ascii.rs +++ b/library/core/benches/ascii.rs @@ -66,6 +66,8 @@ macro_rules! benches { use test::black_box; use test::Bencher; +const ASCII_CASE_MASK: u8 = 0b0010_0000; + benches! { fn case00_alloc_only(_bytes: &mut [u8]) {} @@ -204,7 +206,7 @@ benches! { } } for byte in bytes { - *byte &= !((is_ascii_lowercase(*byte) as u8) << 5) + *byte &= !((is_ascii_lowercase(*byte) as u8) * ASCII_CASE_MASK) } } @@ -216,7 +218,7 @@ benches! { } } for byte in bytes { - *byte -= (is_ascii_lowercase(*byte) as u8) << 5 + *byte -= (is_ascii_lowercase(*byte) as u8) * ASCII_CASE_MASK } } diff --git a/library/core/benches/char/methods.rs b/library/core/benches/char/methods.rs index a9a08a4d76200..de4b63030fa7c 100644 --- a/library/core/benches/char/methods.rs +++ b/library/core/benches/char/methods.rs @@ -35,3 +35,13 @@ fn bench_to_digit_radix_var(b: &mut Bencher) { .min() }) } + +#[bench] +fn bench_to_ascii_uppercase(b: &mut Bencher) { + b.iter(|| CHARS.iter().cycle().take(10_000).map(|c| c.to_ascii_uppercase()).min()) +} + +#[bench] +fn bench_to_ascii_lowercase(b: &mut Bencher) { + b.iter(|| CHARS.iter().cycle().take(10_000).map(|c| c.to_ascii_lowercase()).min()) +} diff --git a/library/core/src/array/mod.rs b/library/core/src/array/mod.rs index d13061d220389..d4fd7545d9bda 100644 --- a/library/core/src/array/mod.rs +++ b/library/core/src/array/mod.rs @@ -11,8 +11,9 @@ use crate::cmp::Ordering; use crate::convert::{Infallible, TryFrom}; use crate::fmt; use crate::hash::{self, Hash}; +use crate::iter::TrustedLen; use crate::marker::Unsize; -use crate::mem::MaybeUninit; +use crate::mem::{self, MaybeUninit}; use crate::ops::{Index, IndexMut}; use crate::slice::{Iter, IterMut}; @@ -426,41 +427,13 @@ impl [T; N] { /// assert_eq!(y, [6, 9, 3, 3]); /// ``` #[unstable(feature = "array_map", issue = "75243")] - pub fn map(self, mut f: F) -> [U; N] + pub fn map(self, f: F) -> [U; N] where F: FnMut(T) -> U, { - struct Guard { - dst: *mut T, - initialized: usize, - } - - impl Drop for Guard { - fn drop(&mut self) { - debug_assert!(self.initialized <= N); - - let initialized_part = - crate::ptr::slice_from_raw_parts_mut(self.dst, self.initialized); - // SAFETY: this raw slice will contain only initialized objects - // that's why, it is allowed to drop it. - unsafe { - crate::ptr::drop_in_place(initialized_part); - } - } - } - let mut dst = MaybeUninit::uninit_array::(); - let mut guard: Guard = - Guard { dst: MaybeUninit::slice_as_mut_ptr(&mut dst), initialized: 0 }; - for (src, dst) in IntoIter::new(self).zip(&mut dst) { - dst.write(f(src)); - guard.initialized += 1; - } - // FIXME: Convert to crate::mem::transmute once it works with generics. - // unsafe { crate::mem::transmute::<[MaybeUninit; N], [U; N]>(dst) } - crate::mem::forget(guard); - // SAFETY: At this point we've properly initialized the whole array - // and we just need to cast it to the correct type. - unsafe { crate::mem::transmute_copy::<_, [U; N]>(&dst) } + // SAFETY: we know for certain that this iterator will yield exactly `N` + // items. + unsafe { collect_into_array_unchecked(&mut IntoIter::new(self).map(f)) } } /// 'Zips up' two arrays into a single array of pairs. @@ -481,15 +454,11 @@ impl [T; N] { /// ``` #[unstable(feature = "array_zip", issue = "80094")] pub fn zip(self, rhs: [U; N]) -> [(T, U); N] { - let mut dst = MaybeUninit::uninit_array::(); - for (i, (lhs, rhs)) in IntoIter::new(self).zip(IntoIter::new(rhs)).enumerate() { - dst[i].write((lhs, rhs)); - } - // FIXME: Convert to crate::mem::transmute once it works with generics. - // unsafe { crate::mem::transmute::<[MaybeUninit; N], [U; N]>(dst) } - // SAFETY: At this point we've properly initialized the whole array - // and we just need to cast it to the correct type. - unsafe { crate::mem::transmute_copy::<_, [(T, U); N]>(&dst) } + let mut iter = IntoIter::new(self).zip(IntoIter::new(rhs)); + + // SAFETY: we know for certain that this iterator will yield exactly `N` + // items. + unsafe { collect_into_array_unchecked(&mut iter) } } /// Returns a slice containing the entire array. Equivalent to `&s[..]`. @@ -535,16 +504,9 @@ impl [T; N] { /// ``` #[unstable(feature = "array_methods", issue = "76118")] pub fn each_ref(&self) -> [&T; N] { - // Unlike in `map`, we don't need a guard here, as dropping a reference - // is a noop. - let mut out = MaybeUninit::uninit_array::(); - for (src, dst) in self.iter().zip(&mut out) { - dst.write(src); - } - - // SAFETY: All elements of `dst` are properly initialized and - // `MaybeUninit` has the same layout as `T`, so this cast is valid. - unsafe { (&mut out as *mut _ as *mut [&T; N]).read() } + // SAFETY: we know for certain that this iterator will yield exactly `N` + // items. + unsafe { collect_into_array_unchecked(&mut self.iter()) } } /// Borrows each element mutably and returns an array of mutable references @@ -564,15 +526,103 @@ impl [T; N] { /// ``` #[unstable(feature = "array_methods", issue = "76118")] pub fn each_mut(&mut self) -> [&mut T; N] { - // Unlike in `map`, we don't need a guard here, as dropping a reference - // is a noop. - let mut out = MaybeUninit::uninit_array::(); - for (src, dst) in self.iter_mut().zip(&mut out) { - dst.write(src); + // SAFETY: we know for certain that this iterator will yield exactly `N` + // items. + unsafe { collect_into_array_unchecked(&mut self.iter_mut()) } + } +} + +/// Pulls `N` items from `iter` and returns them as an array. If the iterator +/// yields fewer than `N` items, this function exhibits undefined behavior. +/// +/// See [`collect_into_array`] for more information. +/// +/// +/// # Safety +/// +/// It is up to the caller to guarantee that `iter` yields at least `N` items. +/// Violating this condition causes undefined behavior. +unsafe fn collect_into_array_unchecked(iter: &mut I) -> [I::Item; N] +where + // Note: `TrustedLen` here is somewhat of an experiment. This is just an + // internal function, so feel free to remove if this bound turns out to be a + // bad idea. In that case, remember to also remove the lower bound + // `debug_assert!` below! + I: Iterator + TrustedLen, +{ + debug_assert!(N <= iter.size_hint().1.unwrap_or(usize::MAX)); + debug_assert!(N <= iter.size_hint().0); + + match collect_into_array(iter) { + Some(array) => array, + // SAFETY: covered by the function contract. + None => unsafe { crate::hint::unreachable_unchecked() }, + } +} + +/// Pulls `N` items from `iter` and returns them as an array. If the iterator +/// yields fewer than `N` items, `None` is returned and all already yielded +/// items are dropped. +/// +/// Since the iterator is passed as mutable reference and this function calls +/// `next` at most `N` times, the iterator can still be used afterwards to +/// retrieve the remaining items. +/// +/// If `iter.next()` panicks, all items already yielded by the iterator are +/// dropped. +fn collect_into_array(iter: &mut I) -> Option<[I::Item; N]> +where + I: Iterator, +{ + if N == 0 { + // SAFETY: An empty array is always inhabited and has no validity invariants. + return unsafe { Some(mem::zeroed()) }; + } + + struct Guard { + ptr: *mut T, + initialized: usize, + } + + impl Drop for Guard { + fn drop(&mut self) { + debug_assert!(self.initialized <= N); + + let initialized_part = crate::ptr::slice_from_raw_parts_mut(self.ptr, self.initialized); + + // SAFETY: this raw slice will contain only initialized objects. + unsafe { + crate::ptr::drop_in_place(initialized_part); + } + } + } + + let mut array = MaybeUninit::uninit_array::(); + let mut guard: Guard<_, N> = + Guard { ptr: MaybeUninit::slice_as_mut_ptr(&mut array), initialized: 0 }; + + while let Some(item) = iter.next() { + // SAFETY: `guard.initialized` starts at 0, is increased by one in the + // loop and the loop is aborted once it reaches N (which is + // `array.len()`). + unsafe { + array.get_unchecked_mut(guard.initialized).write(item); } + guard.initialized += 1; + + // Check if the whole array was initialized. + if guard.initialized == N { + mem::forget(guard); - // SAFETY: All elements of `dst` are properly initialized and - // `MaybeUninit` has the same layout as `T`, so this cast is valid. - unsafe { (&mut out as *mut _ as *mut [&mut T; N]).read() } + // SAFETY: the condition above asserts that all elements are + // initialized. + let out = unsafe { MaybeUninit::array_assume_init(array) }; + return Some(out); + } } + + // This is only reached if the iterator is exhausted before + // `guard.initialized` reaches `N`. Also note that `guard` is dropped here, + // dropping all already initialized elements. + None } diff --git a/library/core/src/char/methods.rs b/library/core/src/char/methods.rs index 64ae7db0d9b53..4390342134d1d 100644 --- a/library/core/src/char/methods.rs +++ b/library/core/src/char/methods.rs @@ -1088,7 +1088,11 @@ impl char { #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] #[inline] pub fn to_ascii_uppercase(&self) -> char { - if self.is_ascii() { (*self as u8).to_ascii_uppercase() as char } else { *self } + if self.is_ascii_lowercase() { + (*self as u8).ascii_change_case_unchecked() as char + } else { + *self + } } /// Makes a copy of the value in its ASCII lower case equivalent. @@ -1116,7 +1120,11 @@ impl char { #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] #[inline] pub fn to_ascii_lowercase(&self) -> char { - if self.is_ascii() { (*self as u8).to_ascii_lowercase() as char } else { *self } + if self.is_ascii_uppercase() { + (*self as u8).ascii_change_case_unchecked() as char + } else { + *self + } } /// Checks that two values are an ASCII case-insensitive match. diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs index 6bdfa18fa434c..c13f000a73615 100644 --- a/library/core/src/num/mod.rs +++ b/library/core/src/num/mod.rs @@ -152,6 +152,9 @@ impl isize { usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() } } +/// If 6th bit set ascii is upper case. +const ASCII_CASE_MASK: u8 = 0b0010_0000; + #[lang = "u8"] impl u8 { uint_impl! { u8, u8, 8, 255, 2, "0x82", "0xa", "0x12", "0x12", "0x48", "[0x12]", @@ -195,7 +198,7 @@ impl u8 { #[inline] pub fn to_ascii_uppercase(&self) -> u8 { // Unset the fifth bit if this is a lowercase letter - *self & !((self.is_ascii_lowercase() as u8) << 5) + *self & !((self.is_ascii_lowercase() as u8) * ASCII_CASE_MASK) } /// Makes a copy of the value in its ASCII lower case equivalent. @@ -218,7 +221,13 @@ impl u8 { #[inline] pub fn to_ascii_lowercase(&self) -> u8 { // Set the fifth bit if this is an uppercase letter - *self | ((self.is_ascii_uppercase() as u8) << 5) + *self | (self.is_ascii_uppercase() as u8 * ASCII_CASE_MASK) + } + + /// Assumes self is ascii + #[inline] + pub(crate) fn ascii_change_case_unchecked(&self) -> u8 { + *self ^ ASCII_CASE_MASK } /// Checks that two values are an ASCII case-insensitive match. diff --git a/library/proc_macro/src/lib.rs b/library/proc_macro/src/lib.rs index a89e7b53e43c4..5f1f7d8cac418 100644 --- a/library/proc_macro/src/lib.rs +++ b/library/proc_macro/src/lib.rs @@ -842,13 +842,20 @@ impl fmt::Debug for Punct { } } -#[stable(feature = "proc_macro_punct_eq", since = "1.49.0")] +#[stable(feature = "proc_macro_punct_eq", since = "1.50.0")] impl PartialEq for Punct { fn eq(&self, rhs: &char) -> bool { self.as_char() == *rhs } } +#[stable(feature = "proc_macro_punct_eq_flipped", since = "1.52.0")] +impl PartialEq for char { + fn eq(&self, rhs: &Punct) -> bool { + *self == rhs.as_char() + } +} + /// An identifier (`ident`). #[derive(Clone)] #[stable(feature = "proc_macro_lib2", since = "1.29.0")] diff --git a/library/std/src/sys/wasi/fs.rs b/library/std/src/sys/wasi/fs.rs index 4134ef676719c..83debdfc86043 100644 --- a/library/std/src/sys/wasi/fs.rs +++ b/library/std/src/sys/wasi/fs.rs @@ -557,12 +557,8 @@ pub fn symlink(original: &Path, link: &Path) -> io::Result<()> { pub fn link(original: &Path, link: &Path) -> io::Result<()> { let (original, original_file) = open_parent(original)?; let (link, link_file) = open_parent(link)?; - original.link( - wasi::LOOKUPFLAGS_SYMLINK_FOLLOW, - osstr2str(original_file.as_ref())?, - &link, - osstr2str(link_file.as_ref())?, - ) + // Pass 0 as the flags argument, meaning don't follow symlinks. + original.link(0, osstr2str(original_file.as_ref())?, &link, osstr2str(link_file.as_ref())?) } pub fn stat(p: &Path) -> io::Result { diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index 8198dbaa5278c..6335709dc48b9 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -207,6 +207,7 @@ target | std | host | notes `riscv64gc-unknown-linux-musl` | | | RISC-V Linux (kernel 4.20, musl 1.2.0) `riscv32gc-unknown-linux-gnu` | | | RISC-V Linux (kernel 5.4, glibc 2.33) `riscv32gc-unknown-linux-musl` | | | RISC-V Linux (kernel 5.4, musl + RISCV32 support patches) +`s390x-unknown-linux-musl` | | | S390x Linux (kernel 2.6.32, MUSL) `sparc-unknown-linux-gnu` | ✓ | | 32-bit SPARC Linux `sparc64-unknown-netbsd` | ✓ | ✓ | NetBSD/sparc64 `sparc64-unknown-openbsd` | ? | | diff --git a/src/test/ui/did_you_mean/pub-macro-rules.rs b/src/test/ui/did_you_mean/pub-macro-rules.rs deleted file mode 100644 index c5393703f7091..0000000000000 --- a/src/test/ui/did_you_mean/pub-macro-rules.rs +++ /dev/null @@ -1,16 +0,0 @@ -#[macro_use] mod bleh { - pub macro_rules! foo { //~ ERROR can't qualify macro_rules invocation - ($n:ident) => ( - fn $n () -> i32 { - 1 - } - ) - } - -} - -foo!(meh); - -fn main() { - println!("{}", meh()); -} diff --git a/src/test/ui/did_you_mean/pub-macro-rules.stderr b/src/test/ui/did_you_mean/pub-macro-rules.stderr deleted file mode 100644 index 0bde5783b8cc6..0000000000000 --- a/src/test/ui/did_you_mean/pub-macro-rules.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error: can't qualify macro_rules invocation with `pub` - --> $DIR/pub-macro-rules.rs:2:5 - | -LL | pub macro_rules! foo { - | ^^^ help: try exporting the macro: `#[macro_export]` - -error: aborting due to previous error - diff --git a/src/test/ui/feature-gates/feature-gate-pub_macro_rules.rs b/src/test/ui/feature-gates/feature-gate-pub_macro_rules.rs new file mode 100644 index 0000000000000..5504ec317ae59 --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-pub_macro_rules.rs @@ -0,0 +1,10 @@ +pub macro_rules! m1 { () => {} } //~ ERROR `pub` on `macro_rules` items is unstable + +#[cfg(FALSE)] +pub macro_rules! m2 { () => {} } //~ ERROR `pub` on `macro_rules` items is unstable + +pub(crate) macro_rules! m3 { () => {} } //~ ERROR `pub` on `macro_rules` items is unstable + +pub(in self) macro_rules! m4 { () => {} } //~ ERROR `pub` on `macro_rules` items is unstable + +fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-pub_macro_rules.stderr b/src/test/ui/feature-gates/feature-gate-pub_macro_rules.stderr new file mode 100644 index 0000000000000..bfaec398d9a97 --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-pub_macro_rules.stderr @@ -0,0 +1,39 @@ +error[E0658]: `pub` on `macro_rules` items is unstable + --> $DIR/feature-gate-pub_macro_rules.rs:1:1 + | +LL | pub macro_rules! m1 { () => {} } + | ^^^ + | + = note: see issue #78855 for more information + = help: add `#![feature(pub_macro_rules)]` to the crate attributes to enable + +error[E0658]: `pub` on `macro_rules` items is unstable + --> $DIR/feature-gate-pub_macro_rules.rs:4:1 + | +LL | pub macro_rules! m2 { () => {} } + | ^^^ + | + = note: see issue #78855 for more information + = help: add `#![feature(pub_macro_rules)]` to the crate attributes to enable + +error[E0658]: `pub` on `macro_rules` items is unstable + --> $DIR/feature-gate-pub_macro_rules.rs:6:1 + | +LL | pub(crate) macro_rules! m3 { () => {} } + | ^^^^^^^^^^ + | + = note: see issue #78855 for more information + = help: add `#![feature(pub_macro_rules)]` to the crate attributes to enable + +error[E0658]: `pub` on `macro_rules` items is unstable + --> $DIR/feature-gate-pub_macro_rules.rs:8:1 + | +LL | pub(in self) macro_rules! m4 { () => {} } + | ^^^^^^^^^^^^ + | + = note: see issue #78855 for more information + = help: add `#![feature(pub_macro_rules)]` to the crate attributes to enable + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/lint/dead-code/write-only-field.rs b/src/test/ui/lint/dead-code/write-only-field.rs index 78cfcfda8f971..7b3f1e9f5b6cb 100644 --- a/src/test/ui/lint/dead-code/write-only-field.rs +++ b/src/test/ui/lint/dead-code/write-only-field.rs @@ -17,4 +17,53 @@ fn field_write(s: &mut S) { fn main() { let mut s = S { f: 0, sub: Sub { f: 0 } }; field_write(&mut s); + + auto_deref(); + nested_boxes(); +} + +fn auto_deref() { + struct E { + x: bool, + y: bool, //~ ERROR: field is never read + } + + struct P<'a> { + e: &'a mut E + } + + impl P<'_> { + fn f(&mut self) { + self.e.x = true; + self.e.y = true; + } + } + + let mut e = E { x: false, y: false }; + let mut p = P { e: &mut e }; + p.f(); + assert!(e.x); +} + +fn nested_boxes() { + struct A { + b: Box, + } + + struct B { + c: Box, + } + + struct C { + u: u32, //~ ERROR: field is never read + v: u32, //~ ERROR: field is never read + } + + let mut a = A { + b: Box::new(B { + c: Box::new(C { u: 0, v: 0 }), + }), + }; + a.b.c.v = 10; + a.b.c = Box::new(C { u: 1, v: 2 }); } diff --git a/src/test/ui/lint/dead-code/write-only-field.stderr b/src/test/ui/lint/dead-code/write-only-field.stderr index 70d2149665b20..a191d22c8b94c 100644 --- a/src/test/ui/lint/dead-code/write-only-field.stderr +++ b/src/test/ui/lint/dead-code/write-only-field.stderr @@ -22,5 +22,23 @@ error: field is never read: `f` LL | f: i32, | ^^^^^^ -error: aborting due to 3 previous errors +error: field is never read: `y` + --> $DIR/write-only-field.rs:28:9 + | +LL | y: bool, + | ^^^^^^^ + +error: field is never read: `u` + --> $DIR/write-only-field.rs:58:9 + | +LL | u: u32, + | ^^^^^^ + +error: field is never read: `v` + --> $DIR/write-only-field.rs:59:9 + | +LL | v: u32, + | ^^^^^^ + +error: aborting due to 6 previous errors diff --git a/src/test/ui/macros/macro-export-on-modularized-macros.rs b/src/test/ui/macros/macro-export-on-modularized-macros.rs new file mode 100644 index 0000000000000..467c6ba7b78e4 --- /dev/null +++ b/src/test/ui/macros/macro-export-on-modularized-macros.rs @@ -0,0 +1,11 @@ +#![feature(decl_macro)] +#![feature(pub_macro_rules)] + +#[macro_export] +macro m1() {} //~ ERROR `#[macro_export]` cannot be used on `macro` items + +#[macro_export] +pub macro_rules! m2 { () => {} } +//~^ ERROR `#[macro_export]` cannot be used on `macro_rules` with `pub` + +fn main() {} diff --git a/src/test/ui/macros/macro-export-on-modularized-macros.stderr b/src/test/ui/macros/macro-export-on-modularized-macros.stderr new file mode 100644 index 0000000000000..8bb031e12cba2 --- /dev/null +++ b/src/test/ui/macros/macro-export-on-modularized-macros.stderr @@ -0,0 +1,14 @@ +error: `#[macro_export]` cannot be used on `macro` items + --> $DIR/macro-export-on-modularized-macros.rs:5:1 + | +LL | macro m1() {} + | ^^^^^^^^^^^^^ + +error: `#[macro_export]` cannot be used on `macro_rules` with `pub` + --> $DIR/macro-export-on-modularized-macros.rs:8:1 + | +LL | pub macro_rules! m2 { () => {} } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/macros/pub-macro-rules-fail.rs b/src/test/ui/macros/pub-macro-rules-fail.rs new file mode 100644 index 0000000000000..bdb4c73f18b18 --- /dev/null +++ b/src/test/ui/macros/pub-macro-rules-fail.rs @@ -0,0 +1,28 @@ +#![feature(pub_macro_rules)] + +#[macro_use] +mod m { + pub macro_rules! mac { () => {} } + + // `pub` `macro_rules` cannot be redefined in the same module. + pub macro_rules! mac { () => {} } //~ ERROR the name `mac` is defined multiple times + + pub(self) macro_rules! private_mac { () => {} } +} + +const _: () = { + pub macro_rules! block_mac { () => {} } +}; + +mod n { + // Scope of `pub` `macro_rules` is not extended by `#[macro_use]`. + mac!(); //~ ERROR cannot find macro `mac` in this scope + + // `pub` `macro_rules` doesn't put the macro into the root module, unlike `#[macro_export]`. + crate::mac!(); //~ ERROR failed to resolve: maybe a missing crate `mac` + crate::block_mac!(); //~ ERROR failed to resolve: maybe a missing crate `block_mac` + + crate::m::private_mac!(); //~ ERROR macro `private_mac` is private +} + +fn main() {} diff --git a/src/test/ui/macros/pub-macro-rules-fail.stderr b/src/test/ui/macros/pub-macro-rules-fail.stderr new file mode 100644 index 0000000000000..588d79dd76a4b --- /dev/null +++ b/src/test/ui/macros/pub-macro-rules-fail.stderr @@ -0,0 +1,48 @@ +error[E0428]: the name `mac` is defined multiple times + --> $DIR/pub-macro-rules-fail.rs:8:5 + | +LL | pub macro_rules! mac { () => {} } + | -------------------- previous definition of the macro `mac` here +... +LL | pub macro_rules! mac { () => {} } + | ^^^^^^^^^^^^^^^^^^^^ `mac` redefined here + | + = note: `mac` must be defined only once in the macro namespace of this module + +error[E0433]: failed to resolve: maybe a missing crate `mac`? + --> $DIR/pub-macro-rules-fail.rs:22:12 + | +LL | crate::mac!(); + | ^^^ maybe a missing crate `mac`? + +error[E0433]: failed to resolve: maybe a missing crate `block_mac`? + --> $DIR/pub-macro-rules-fail.rs:23:12 + | +LL | crate::block_mac!(); + | ^^^^^^^^^ maybe a missing crate `block_mac`? + +error: cannot find macro `mac` in this scope + --> $DIR/pub-macro-rules-fail.rs:19:5 + | +LL | mac!(); + | ^^^ + | + = note: consider importing this macro: + m::mac + +error[E0603]: macro `private_mac` is private + --> $DIR/pub-macro-rules-fail.rs:25:15 + | +LL | crate::m::private_mac!(); + | ^^^^^^^^^^^ private macro + | +note: the macro `private_mac` is defined here + --> $DIR/pub-macro-rules-fail.rs:10:5 + | +LL | pub(self) macro_rules! private_mac { () => {} } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 5 previous errors + +Some errors have detailed explanations: E0428, E0433, E0603. +For more information about an error, try `rustc --explain E0428`. diff --git a/src/test/ui/macros/pub-macro-rules.rs b/src/test/ui/macros/pub-macro-rules.rs new file mode 100644 index 0000000000000..cd4a845f7c07d --- /dev/null +++ b/src/test/ui/macros/pub-macro-rules.rs @@ -0,0 +1,20 @@ +// check-pass + +#![feature(pub_macro_rules)] + +mod m { + // `pub` `macro_rules` can be used earlier in item order than they are defined. + foo!(); + + pub macro_rules! foo { () => {} } + + // `pub(...)` works too. + pub(super) macro_rules! bar { () => {} } +} + +// `pub` `macro_rules` are available by module path. +m::foo!(); + +m::bar!(); + +fn main() {} diff --git a/src/test/ui/suggestions/auxiliary/issue-81839.rs b/src/test/ui/suggestions/auxiliary/issue-81839.rs new file mode 100644 index 0000000000000..5683c45adf26d --- /dev/null +++ b/src/test/ui/suggestions/auxiliary/issue-81839.rs @@ -0,0 +1,9 @@ +// edition:2018 + +pub struct Test {} + +impl Test { + pub async fn answer_str(&self, _s: &str) -> Test { + Test {} + } +} diff --git a/src/test/ui/suggestions/issue-81839.rs b/src/test/ui/suggestions/issue-81839.rs new file mode 100644 index 0000000000000..0b9b7aefe735d --- /dev/null +++ b/src/test/ui/suggestions/issue-81839.rs @@ -0,0 +1,17 @@ +// aux-build:issue-81839.rs +// edition:2018 + +extern crate issue_81839; + +async fn test(ans: &str, num: i32, cx: &issue_81839::Test) -> u32 { + match num { + 1 => { + cx.answer_str("hi"); + } + _ => cx.answer_str("hi"), //~ `match` arms have incompatible types + } + + 1 +} + +fn main() {} diff --git a/src/test/ui/suggestions/issue-81839.stderr b/src/test/ui/suggestions/issue-81839.stderr new file mode 100644 index 0000000000000..1a289d39e4467 --- /dev/null +++ b/src/test/ui/suggestions/issue-81839.stderr @@ -0,0 +1,27 @@ +error[E0308]: `match` arms have incompatible types + --> $DIR/issue-81839.rs:11:14 + | +LL | / match num { +LL | | 1 => { +LL | | cx.answer_str("hi"); + | | -------------------- + | | | | + | | | help: consider removing this semicolon + | | this is found to be of type `()` +LL | | } +LL | | _ => cx.answer_str("hi"), + | | ^^^^^^^^^^^^^^^^^^^ expected `()`, found opaque type +LL | | } + | |_____- `match` arms have incompatible types + | + ::: $DIR/auxiliary/issue-81839.rs:6:49 + | +LL | pub async fn answer_str(&self, _s: &str) -> Test { + | ---- the `Output` of this `async fn`'s found opaque type + | + = note: expected type `()` + found opaque type `impl Future` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/suggestions/match-prev-arm-needing-semi.stderr b/src/test/ui/suggestions/match-prev-arm-needing-semi.stderr index e9803a78f94b3..fae0c498b440a 100644 --- a/src/test/ui/suggestions/match-prev-arm-needing-semi.stderr +++ b/src/test/ui/suggestions/match-prev-arm-needing-semi.stderr @@ -24,13 +24,10 @@ help: consider `await`ing on the `Future` | LL | false => async_dummy().await, | ^^^^^^ -help: consider removing this semicolon and boxing the expressions - | -LL | Box::new(async_dummy()) -LL | -LL | } -LL | false => Box::new(async_dummy()), +help: consider removing this semicolon | +LL | async_dummy() + | -- error[E0308]: `match` arms have incompatible types --> $DIR/match-prev-arm-needing-semi.rs:39:18