diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs index cb7b7c0eb6116..a1cbcde1f4291 100644 --- a/compiler/rustc_ast_lowering/src/pat.rs +++ b/compiler/rustc_ast_lowering/src/pat.rs @@ -10,82 +10,90 @@ use rustc_span::symbol::Ident; use rustc_span::{source_map::Spanned, Span}; impl<'a, 'hir> LoweringContext<'a, 'hir> { - crate fn lower_pat(&mut self, p: &Pat) -> &'hir hir::Pat<'hir> { + crate fn lower_pat(&mut self, mut pattern: &Pat) -> &'hir hir::Pat<'hir> { ensure_sufficient_stack(|| { - let node = match p.kind { - PatKind::Wild => hir::PatKind::Wild, - PatKind::Ident(ref binding_mode, ident, ref sub) => { - let lower_sub = |this: &mut Self| sub.as_ref().map(|s| this.lower_pat(&*s)); - let node = self.lower_pat_ident(p, binding_mode, ident, lower_sub); - node - } - PatKind::Lit(ref e) => hir::PatKind::Lit(self.lower_expr(e)), - PatKind::TupleStruct(ref path, ref pats) => { - let qpath = self.lower_qpath( - p.id, - &None, - path, - ParamMode::Optional, - ImplTraitContext::disallowed(), - ); - let (pats, ddpos) = self.lower_pat_tuple(pats, "tuple struct"); - hir::PatKind::TupleStruct(qpath, pats, ddpos) - } - PatKind::Or(ref pats) => hir::PatKind::Or( - self.arena.alloc_from_iter(pats.iter().map(|x| self.lower_pat(x))), - ), - PatKind::Path(ref qself, ref path) => { - let qpath = self.lower_qpath( - p.id, - qself, - path, - ParamMode::Optional, - ImplTraitContext::disallowed(), - ); - hir::PatKind::Path(qpath) - } - PatKind::Struct(ref path, ref fields, etc) => { - let qpath = self.lower_qpath( - p.id, - &None, - path, - ParamMode::Optional, - ImplTraitContext::disallowed(), - ); + // loop here to avoid recursion + let node = loop { + match pattern.kind { + PatKind::Wild => break hir::PatKind::Wild, + PatKind::Ident(ref binding_mode, ident, ref sub) => { + let lower_sub = |this: &mut Self| sub.as_ref().map(|s| this.lower_pat(&*s)); + break self.lower_pat_ident(pattern, binding_mode, ident, lower_sub); + } + PatKind::Lit(ref e) => break hir::PatKind::Lit(self.lower_expr(e)), + PatKind::TupleStruct(ref path, ref pats) => { + let qpath = self.lower_qpath( + pattern.id, + &None, + path, + ParamMode::Optional, + ImplTraitContext::disallowed(), + ); + let (pats, ddpos) = self.lower_pat_tuple(pats, "tuple struct"); + break hir::PatKind::TupleStruct(qpath, pats, ddpos); + } + PatKind::Or(ref pats) => { + break hir::PatKind::Or( + self.arena.alloc_from_iter(pats.iter().map(|x| self.lower_pat(x))), + ); + } + PatKind::Path(ref qself, ref path) => { + let qpath = self.lower_qpath( + pattern.id, + qself, + path, + ParamMode::Optional, + ImplTraitContext::disallowed(), + ); + break hir::PatKind::Path(qpath); + } + PatKind::Struct(ref path, ref fields, etc) => { + let qpath = self.lower_qpath( + pattern.id, + &None, + path, + ParamMode::Optional, + ImplTraitContext::disallowed(), + ); - let fs = self.arena.alloc_from_iter(fields.iter().map(|f| hir::FieldPat { - hir_id: self.next_id(), - ident: f.ident, - pat: self.lower_pat(&f.pat), - is_shorthand: f.is_shorthand, - span: f.span, - })); - hir::PatKind::Struct(qpath, fs, etc) - } - PatKind::Tuple(ref pats) => { - let (pats, ddpos) = self.lower_pat_tuple(pats, "tuple"); - hir::PatKind::Tuple(pats, ddpos) - } - PatKind::Box(ref inner) => hir::PatKind::Box(self.lower_pat(inner)), - PatKind::Ref(ref inner, mutbl) => hir::PatKind::Ref(self.lower_pat(inner), mutbl), - PatKind::Range(ref e1, ref e2, Spanned { node: ref end, .. }) => { - hir::PatKind::Range( - e1.as_deref().map(|e| self.lower_expr(e)), - e2.as_deref().map(|e| self.lower_expr(e)), - self.lower_range_end(end, e2.is_some()), - ) - } - PatKind::Slice(ref pats) => self.lower_pat_slice(pats), - PatKind::Rest => { - // If we reach here the `..` pattern is not semantically allowed. - self.ban_illegal_rest_pat(p.span) + let fs = self.arena.alloc_from_iter(fields.iter().map(|f| hir::FieldPat { + hir_id: self.next_id(), + ident: f.ident, + pat: self.lower_pat(&f.pat), + is_shorthand: f.is_shorthand, + span: f.span, + })); + break hir::PatKind::Struct(qpath, fs, etc); + } + PatKind::Tuple(ref pats) => { + let (pats, ddpos) = self.lower_pat_tuple(pats, "tuple"); + break hir::PatKind::Tuple(pats, ddpos); + } + PatKind::Box(ref inner) => { + break hir::PatKind::Box(self.lower_pat(inner)); + } + PatKind::Ref(ref inner, mutbl) => { + break hir::PatKind::Ref(self.lower_pat(inner), mutbl); + } + PatKind::Range(ref e1, ref e2, Spanned { node: ref end, .. }) => { + break hir::PatKind::Range( + e1.as_deref().map(|e| self.lower_expr(e)), + e2.as_deref().map(|e| self.lower_expr(e)), + self.lower_range_end(end, e2.is_some()), + ); + } + PatKind::Slice(ref pats) => break self.lower_pat_slice(pats), + PatKind::Rest => { + // If we reach here the `..` pattern is not semantically allowed. + break self.ban_illegal_rest_pat(pattern.span); + } + // return inner to be processed in next loop + PatKind::Paren(ref inner) => pattern = inner, + PatKind::MacCall(_) => panic!("{:?} shouldn't exist here", pattern.span), } - // FIXME: consider not using recursion to lower this. - PatKind::Paren(ref inner) => return self.lower_pat(inner), - PatKind::MacCall(_) => panic!("{:?} shouldn't exist here", p.span), }; - self.pat_with_node_id_of(p, node) + self.pat_with_node_id_of(pattern, node) }) } diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index 092d1cea29515..ea1a7cfa5d3b5 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -936,8 +936,8 @@ unsafe fn embed_bitcode( llvm::LLVMRustAppendModuleInlineAsm(llmod, asm.as_ptr().cast(), asm.len()); } else { let asm = " - .section .llvmbc,\"a\" - .section .llvmcmd,\"a\" + .section .llvmbc,\"e\" + .section .llvmcmd,\"e\" "; llvm::LLVMRustAppendModuleInlineAsm(llmod, asm.as_ptr().cast(), asm.len()); } diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index 150cedde7e833..56ff580b43b59 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -324,8 +324,8 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { } #[inline] - pub fn coverage_context(&'a self) -> &'a coverageinfo::CrateCoverageContext<'tcx> { - self.coverage_cx.as_ref().unwrap() + pub fn coverage_context(&'a self) -> Option<&'a coverageinfo::CrateCoverageContext<'tcx>> { + self.coverage_cx.as_ref() } } diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs index 0098555a3736b..c1163a871cf1f 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs @@ -26,7 +26,10 @@ use tracing::debug; /// undocumented details in Clang's implementation (that may or may not be important) were also /// replicated for Rust's Coverage Map. pub fn finalize<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>) { - let function_coverage_map = cx.coverage_context().take_function_coverage_map(); + let function_coverage_map = match cx.coverage_context() { + Some(ctx) => ctx.take_function_coverage_map(), + None => return, + }; if function_coverage_map.is_empty() { // This module has no functions with coverage instrumentation return; diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs index 2bd37bf9c4f9c..7fdbe1a55128a 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs @@ -64,17 +64,22 @@ impl CoverageInfoBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> { function_source_hash: u64, id: CounterValueReference, region: CodeRegion, - ) { - debug!( - "adding counter to coverage_regions: instance={:?}, function_source_hash={}, id={:?}, \ - at {:?}", - instance, function_source_hash, id, region, - ); - let mut coverage_regions = self.coverage_context().function_coverage_map.borrow_mut(); - coverage_regions - .entry(instance) - .or_insert_with(|| FunctionCoverage::new(self.tcx, instance)) - .add_counter(function_source_hash, id, region); + ) -> bool { + if let Some(coverage_context) = self.coverage_context() { + debug!( + "adding counter to coverage_regions: instance={:?}, function_source_hash={}, id={:?}, \ + at {:?}", + instance, function_source_hash, id, region, + ); + let mut coverage_regions = coverage_context.function_coverage_map.borrow_mut(); + coverage_regions + .entry(instance) + .or_insert_with(|| FunctionCoverage::new(self.tcx, instance)) + .add_counter(function_source_hash, id, region); + true + } else { + false + } } fn add_counter_expression_region( @@ -85,29 +90,39 @@ impl CoverageInfoBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> { op: Op, rhs: ExpressionOperandId, region: CodeRegion, - ) { - debug!( - "adding counter expression to coverage_regions: instance={:?}, id={:?}, {:?} {:?} {:?}, \ - at {:?}", - instance, id, lhs, op, rhs, region, - ); - let mut coverage_regions = self.coverage_context().function_coverage_map.borrow_mut(); - coverage_regions - .entry(instance) - .or_insert_with(|| FunctionCoverage::new(self.tcx, instance)) - .add_counter_expression(id, lhs, op, rhs, region); + ) -> bool { + if let Some(coverage_context) = self.coverage_context() { + debug!( + "adding counter expression to coverage_regions: instance={:?}, id={:?}, {:?} {:?} {:?}, \ + at {:?}", + instance, id, lhs, op, rhs, region, + ); + let mut coverage_regions = coverage_context.function_coverage_map.borrow_mut(); + coverage_regions + .entry(instance) + .or_insert_with(|| FunctionCoverage::new(self.tcx, instance)) + .add_counter_expression(id, lhs, op, rhs, region); + true + } else { + false + } } - fn add_unreachable_region(&mut self, instance: Instance<'tcx>, region: CodeRegion) { - debug!( - "adding unreachable code to coverage_regions: instance={:?}, at {:?}", - instance, region, - ); - let mut coverage_regions = self.coverage_context().function_coverage_map.borrow_mut(); - coverage_regions - .entry(instance) - .or_insert_with(|| FunctionCoverage::new(self.tcx, instance)) - .add_unreachable_region(region); + fn add_unreachable_region(&mut self, instance: Instance<'tcx>, region: CodeRegion) -> bool { + if let Some(coverage_context) = self.coverage_context() { + debug!( + "adding unreachable code to coverage_regions: instance={:?}, at {:?}", + instance, region, + ); + let mut coverage_regions = coverage_context.function_coverage_map.borrow_mut(); + coverage_regions + .entry(instance) + .or_insert_with(|| FunctionCoverage::new(self.tcx, instance)) + .add_unreachable_region(region); + true + } else { + false + } } } diff --git a/compiler/rustc_codegen_ssa/src/mir/coverageinfo.rs b/compiler/rustc_codegen_ssa/src/mir/coverageinfo.rs index a2ad27b925c34..4811adea9ec06 100644 --- a/compiler/rustc_codegen_ssa/src/mir/coverageinfo.rs +++ b/compiler/rustc_codegen_ssa/src/mir/coverageinfo.rs @@ -10,19 +10,19 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let Coverage { kind, code_region } = coverage; match kind { CoverageKind::Counter { function_source_hash, id } => { - bx.add_counter_region(self.instance, function_source_hash, id, code_region); + if bx.add_counter_region(self.instance, function_source_hash, id, code_region) { + let coverageinfo = bx.tcx().coverageinfo(self.instance.def_id()); - let coverageinfo = bx.tcx().coverageinfo(self.instance.def_id()); - - let fn_name = bx.create_pgo_func_name_var(self.instance); - let hash = bx.const_u64(function_source_hash); - let num_counters = bx.const_u32(coverageinfo.num_counters); - let id = bx.const_u32(u32::from(id)); - debug!( - "codegen intrinsic instrprof.increment(fn_name={:?}, hash={:?}, num_counters={:?}, index={:?})", - fn_name, hash, num_counters, id, - ); - bx.instrprof_increment(fn_name, hash, num_counters, id); + let fn_name = bx.create_pgo_func_name_var(self.instance); + let hash = bx.const_u64(function_source_hash); + let num_counters = bx.const_u32(coverageinfo.num_counters); + let id = bx.const_u32(u32::from(id)); + debug!( + "codegen intrinsic instrprof.increment(fn_name={:?}, hash={:?}, num_counters={:?}, index={:?})", + fn_name, hash, num_counters, id, + ); + bx.instrprof_increment(fn_name, hash, num_counters, id); + } } CoverageKind::Expression { id, lhs, op, rhs } => { bx.add_counter_expression_region(self.instance, id, lhs, op, rhs, code_region); diff --git a/compiler/rustc_codegen_ssa/src/traits/coverageinfo.rs b/compiler/rustc_codegen_ssa/src/traits/coverageinfo.rs index b74e4e459016f..3b1654f3ad4fc 100644 --- a/compiler/rustc_codegen_ssa/src/traits/coverageinfo.rs +++ b/compiler/rustc_codegen_ssa/src/traits/coverageinfo.rs @@ -9,14 +9,18 @@ pub trait CoverageInfoMethods: BackendTypes { pub trait CoverageInfoBuilderMethods<'tcx>: BackendTypes { fn create_pgo_func_name_var(&self, instance: Instance<'tcx>) -> Self::Value; + /// Returns true if the counter was added to the coverage map; false if `-Z instrument-coverage` + /// is not enabled (a coverage map is not being generated). fn add_counter_region( &mut self, instance: Instance<'tcx>, function_source_hash: u64, id: CounterValueReference, region: CodeRegion, - ); + ) -> bool; + /// Returns true if the expression was added to the coverage map; false if + /// `-Z instrument-coverage` is not enabled (a coverage map is not being generated). fn add_counter_expression_region( &mut self, instance: Instance<'tcx>, @@ -25,7 +29,9 @@ pub trait CoverageInfoBuilderMethods<'tcx>: BackendTypes { op: Op, rhs: ExpressionOperandId, region: CodeRegion, - ); + ) -> bool; - fn add_unreachable_region(&mut self, instance: Instance<'tcx>, region: CodeRegion); + /// Returns true if the region was added to the coverage map; false if `-Z instrument-coverage` + /// is not enabled (a coverage map is not being generated). + fn add_unreachable_region(&mut self, instance: Instance<'tcx>, region: CodeRegion) -> bool; } diff --git a/compiler/rustc_middle/src/infer/unify_key.rs b/compiler/rustc_middle/src/infer/unify_key.rs index 4d884dde39387..16e9aafb25a54 100644 --- a/compiler/rustc_middle/src/infer/unify_key.rs +++ b/compiler/rustc_middle/src/infer/unify_key.rs @@ -175,19 +175,15 @@ impl<'tcx> UnifyKey for ty::ConstVid<'tcx> { impl<'tcx> UnifyValue for ConstVarValue<'tcx> { type Error = (&'tcx ty::Const<'tcx>, &'tcx ty::Const<'tcx>); - fn unify_values(value1: &Self, value2: &Self) -> Result { - let (val, span) = match (value1.val, value2.val) { + fn unify_values(&value1: &Self, &value2: &Self) -> Result { + Ok(match (value1.val, value2.val) { (ConstVariableValue::Known { .. }, ConstVariableValue::Known { .. }) => { bug!("equating two const variables, both of which have known values") } // If one side is known, prefer that one. - (ConstVariableValue::Known { .. }, ConstVariableValue::Unknown { .. }) => { - (value1.val, value1.origin.span) - } - (ConstVariableValue::Unknown { .. }, ConstVariableValue::Known { .. }) => { - (value2.val, value2.origin.span) - } + (ConstVariableValue::Known { .. }, ConstVariableValue::Unknown { .. }) => value1, + (ConstVariableValue::Unknown { .. }, ConstVariableValue::Known { .. }) => value2, // If both sides are *unknown*, it hardly matters, does it? ( @@ -200,16 +196,11 @@ impl<'tcx> UnifyValue for ConstVarValue<'tcx> { // universe is the minimum of the two universes, because that is // the one which contains the fewest names in scope. let universe = cmp::min(universe1, universe2); - (ConstVariableValue::Unknown { universe }, value1.origin.span) + ConstVarValue { + val: ConstVariableValue::Unknown { universe }, + origin: value1.origin, + } } - }; - - Ok(ConstVarValue { - origin: ConstVariableOrigin { - kind: ConstVariableOriginKind::ConstInference, - span: span, - }, - val, }) } } diff --git a/compiler/rustc_middle/src/ty/fold.rs b/compiler/rustc_middle/src/ty/fold.rs index 5524d91a6d533..0e5e22dcaae9f 100644 --- a/compiler/rustc_middle/src/ty/fold.rs +++ b/compiler/rustc_middle/src/ty/fold.rs @@ -30,8 +30,6 @@ //! //! These methods return true to indicate that the visitor has found what it is //! looking for, and does not need to visit anything else. - -use crate::ty::structural_impls::PredicateVisitor; use crate::ty::{self, flags::FlagComputation, Binder, Ty, TyCtxt, TypeFlags}; use rustc_hir as hir; use rustc_hir::def_id::DefId; @@ -211,6 +209,10 @@ pub trait TypeVisitor<'tcx>: Sized { fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> bool { c.super_visit_with(self) } + + fn visit_predicate(&mut self, p: ty::Predicate<'tcx>) -> bool { + p.super_visit_with(self) + } } /////////////////////////////////////////////////////////////////////////// @@ -868,9 +870,7 @@ impl<'tcx> TypeVisitor<'tcx> for HasEscapingVarsVisitor { _ => ct.super_visit_with(self), } } -} -impl<'tcx> PredicateVisitor<'tcx> for HasEscapingVarsVisitor { fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> bool { predicate.inner.outer_exclusive_binder > self.outer_index } @@ -903,9 +903,7 @@ impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor { debug!("HasTypeFlagsVisitor: c={:?} c.flags={:?} self.flags={:?}", c, flags, self.flags); flags.intersects(self.flags) } -} -impl<'tcx> PredicateVisitor<'tcx> for HasTypeFlagsVisitor { fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> bool { debug!( "HasTypeFlagsVisitor: predicate={:?} predicate.flags={:?} self.flags={:?}", @@ -914,6 +912,7 @@ impl<'tcx> PredicateVisitor<'tcx> for HasTypeFlagsVisitor { predicate.inner.flags.intersects(self.flags) } } + /// Collects all the late-bound regions at the innermost binding level /// into a hash set. struct LateBoundRegionsCollector { diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index d9ec6bb20fda8..53521d0e9f332 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -1040,16 +1040,6 @@ impl<'tcx> TypeFoldable<'tcx> for ty::Predicate<'tcx> { } } -pub(super) trait PredicateVisitor<'tcx>: TypeVisitor<'tcx> { - fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> bool; -} - -impl> PredicateVisitor<'tcx> for T { - default fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> bool { - predicate.super_visit_with(self) - } -} - impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List> { fn super_fold_with>(&self, folder: &mut F) -> Self { fold_list(*self, folder, |tcx, v| tcx.intern_predicates(v)) diff --git a/compiler/rustc_mir/src/transform/simplify_branches.rs b/compiler/rustc_mir/src/transform/simplify_branches.rs index 5f63c03993d3a..a9a45e61a38cb 100644 --- a/compiler/rustc_mir/src/transform/simplify_branches.rs +++ b/compiler/rustc_mir/src/transform/simplify_branches.rs @@ -49,9 +49,10 @@ impl<'tcx> MirPass<'tcx> for SimplifyBranches { } TerminatorKind::Assert { target, cond: Operand::Constant(ref c), expected, .. - } if (c.literal.try_eval_bool(tcx, param_env) == Some(true)) == expected => { - TerminatorKind::Goto { target } - } + } => match c.literal.try_eval_bool(tcx, param_env) { + Some(v) if v == expected => TerminatorKind::Goto { target }, + _ => continue, + }, TerminatorKind::FalseEdge { real_target, .. } => { TerminatorKind::Goto { target: real_target } } diff --git a/compiler/rustc_target/src/spec/apple_sdk_base.rs b/compiler/rustc_target/src/spec/apple_sdk_base.rs index e34277d5af04c..1b17c2c278f9a 100644 --- a/compiler/rustc_target/src/spec/apple_sdk_base.rs +++ b/compiler/rustc_target/src/spec/apple_sdk_base.rs @@ -34,6 +34,7 @@ fn link_env_remove(arch: Arch) -> Vec { pub fn opts(arch: Arch) -> TargetOptions { TargetOptions { cpu: target_cpu(arch), + dynamic_linking: false, executables: true, link_env_remove: link_env_remove(arch), has_elf_tls: false, diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index b69e19072af44..c039be8f67cda 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -118,6 +118,7 @@ #![feature(raw_ref_op)] #![feature(rustc_attrs)] #![feature(receiver_trait)] +#![feature(renamed_spin_loop)] #![feature(min_specialization)] #![feature(slice_ptr_get)] #![feature(slice_ptr_len)] diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index 3a83aa7cbe5bd..cd18535b0697d 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -10,6 +10,7 @@ use core::cmp::Ordering; use core::convert::{From, TryFrom}; use core::fmt; use core::hash::{Hash, Hasher}; +use core::hint; use core::intrinsics::abort; use core::iter; use core::marker::{PhantomData, Unpin, Unsize}; @@ -764,6 +765,7 @@ impl Arc { loop { // check if the weak counter is currently "locked"; if so, spin. if cur == usize::MAX { + hint::spin_loop(); cur = this.inner().weak.load(Relaxed); continue; } diff --git a/library/alloc/tests/str.rs b/library/alloc/tests/str.rs index ed8ee2d8823c0..834dd4656ff76 100644 --- a/library/alloc/tests/str.rs +++ b/library/alloc/tests/str.rs @@ -529,6 +529,13 @@ mod slice_index { message: "out of bounds"; } + in mod rangeinclusive_len { + data: "abcdef"; + good: data[0..=5] == "abcdef"; + bad: data[0..=6]; + message: "out of bounds"; + } + in mod range_len_len { data: "abcdef"; good: data[6..6] == ""; @@ -544,6 +551,28 @@ mod slice_index { } } + panic_cases! { + in mod rangeinclusive_exhausted { + data: "abcdef"; + + good: data[0..=5] == "abcdef"; + good: data[{ + let mut iter = 0..=5; + iter.by_ref().count(); // exhaust it + iter + }] == ""; + + // 0..=6 is out of bounds before exhaustion, so it + // stands to reason that it still would be after. + bad: data[{ + let mut iter = 0..=6; + iter.by_ref().count(); // exhaust it + iter + }]; + message: "out of bounds"; + } + } + panic_cases! { in mod range_neg_width { data: "abcdef"; diff --git a/library/core/src/ops/range.rs b/library/core/src/ops/range.rs index 4423cfc27dd17..1d67e65e51f5f 100644 --- a/library/core/src/ops/range.rs +++ b/library/core/src/ops/range.rs @@ -446,6 +446,20 @@ impl RangeInclusive { } } +impl RangeInclusive { + /// Converts to an exclusive `Range` for `SliceIndex` implementations. + /// The caller is responsible for dealing with `end == usize::MAX`. + #[inline] + pub(crate) fn into_slice_range(self) -> Range { + // If we're not exhausted, we want to simply slice `start..end + 1`. + // If we are exhausted, then slicing with `end + 1..end + 1` gives us an + // empty range that is still subject to bounds-checks for that endpoint. + let exclusive_end = self.end + 1; + let start = if self.exhausted { exclusive_end } else { self.start }; + start..exclusive_end + } +} + #[stable(feature = "inclusive_range", since = "1.26.0")] impl fmt::Debug for RangeInclusive { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -479,6 +493,16 @@ impl> RangeInclusive { /// assert!(!(0.0..=f32::NAN).contains(&0.0)); /// assert!(!(f32::NAN..=1.0).contains(&1.0)); /// ``` + /// + /// This method always returns `false` after iteration has finished: + /// + /// ``` + /// let mut r = 3..=5; + /// assert!(r.contains(&3) && r.contains(&5)); + /// for _ in r.by_ref() {} + /// // Precise field values are unspecified here + /// assert!(!r.contains(&3) && !r.contains(&5)); + /// ``` #[stable(feature = "range_contains", since = "1.35.0")] pub fn contains(&self, item: &U) -> bool where @@ -881,7 +905,13 @@ impl RangeBounds for RangeInclusive { Included(&self.start) } fn end_bound(&self) -> Bound<&T> { - Included(&self.end) + if self.exhausted { + // When the iterator is exhausted, we usually have start == end, + // but we want the range to appear empty, containing nothing. + Excluded(&self.end) + } else { + Included(&self.end) + } } } diff --git a/library/core/src/option.rs b/library/core/src/option.rs index 825144e5a6fbe..3daf26208b937 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -562,6 +562,36 @@ impl Option { } } + /// Inserts `value` into the option then returns a mutable reference to it. + /// + /// If the option already contains a value, the old value is dropped. + /// + /// # Example + /// + /// ``` + /// #![feature(option_insert)] + /// + /// let mut opt = None; + /// let val = opt.insert(1); + /// assert_eq!(*val, 1); + /// assert_eq!(opt.unwrap(), 1); + /// let val = opt.insert(2); + /// assert_eq!(*val, 2); + /// *val = 3; + /// assert_eq!(opt.unwrap(), 3); + /// ``` + #[inline] + #[unstable(feature = "option_insert", reason = "newly added", issue = "78271")] + pub fn insert(&mut self, value: T) -> &mut T { + *self = Some(value); + + match self { + Some(v) => v, + // SAFETY: the code above just filled the option + None => unsafe { hint::unreachable_unchecked() }, + } + } + ///////////////////////////////////////////////////////////////////////// // Iterator constructors ///////////////////////////////////////////////////////////////////////// @@ -792,7 +822,7 @@ impl Option { // Entry-like operations to insert if None and return a reference ///////////////////////////////////////////////////////////////////////// - /// Inserts `v` into the option if it is [`None`], then + /// Inserts `value` into the option if it is [`None`], then /// returns a mutable reference to the contained value. /// /// # Examples @@ -811,12 +841,12 @@ impl Option { /// ``` #[inline] #[stable(feature = "option_entry", since = "1.20.0")] - pub fn get_or_insert(&mut self, v: T) -> &mut T { - self.get_or_insert_with(|| v) + pub fn get_or_insert(&mut self, value: T) -> &mut T { + self.get_or_insert_with(|| value) } - /// Inserts a value computed from `f` into the option if it is [`None`], then - /// returns a mutable reference to the contained value. + /// Inserts a value computed from `f` into the option if it is [`None`], + /// then returns a mutable reference to the contained value. /// /// # Examples /// @@ -839,8 +869,8 @@ impl Option { *self = Some(f()); } - match *self { - Some(ref mut v) => v, + match self { + Some(v) => v, // SAFETY: a `None` variant for `self` would have been replaced by a `Some` // variant in the code above. None => unsafe { hint::unreachable_unchecked() }, diff --git a/library/core/src/slice/index.rs b/library/core/src/slice/index.rs index f1f21c1d24b0b..660c8a2da5da0 100644 --- a/library/core/src/slice/index.rs +++ b/library/core/src/slice/index.rs @@ -376,28 +376,24 @@ unsafe impl SliceIndex<[T]> for ops::RangeInclusive { #[inline] fn get(self, slice: &[T]) -> Option<&[T]> { - if *self.end() == usize::MAX { None } else { (*self.start()..self.end() + 1).get(slice) } + if *self.end() == usize::MAX { None } else { self.into_slice_range().get(slice) } } #[inline] fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> { - if *self.end() == usize::MAX { - None - } else { - (*self.start()..self.end() + 1).get_mut(slice) - } + if *self.end() == usize::MAX { None } else { self.into_slice_range().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 { (*self.start()..self.end() + 1).get_unchecked(slice) } + unsafe { self.into_slice_range().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 { (*self.start()..self.end() + 1).get_unchecked_mut(slice) } + unsafe { self.into_slice_range().get_unchecked_mut(slice) } } #[inline] @@ -405,7 +401,7 @@ unsafe impl SliceIndex<[T]> for ops::RangeInclusive { if *self.end() == usize::MAX { slice_end_index_overflow_fail(); } - (*self.start()..self.end() + 1).index(slice) + self.into_slice_range().index(slice) } #[inline] @@ -413,7 +409,7 @@ unsafe impl SliceIndex<[T]> for ops::RangeInclusive { if *self.end() == usize::MAX { slice_end_index_overflow_fail(); } - (*self.start()..self.end() + 1).index_mut(slice) + self.into_slice_range().index_mut(slice) } } diff --git a/library/core/src/str/traits.rs b/library/core/src/str/traits.rs index af1ce007e8b7c..9cfb5a8998773 100644 --- a/library/core/src/str/traits.rs +++ b/library/core/src/str/traits.rs @@ -398,39 +398,35 @@ unsafe impl SliceIndex for ops::RangeInclusive { type Output = str; #[inline] fn get(self, slice: &str) -> Option<&Self::Output> { - if *self.end() == usize::MAX { None } else { (*self.start()..self.end() + 1).get(slice) } + if *self.end() == 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.start()..self.end() + 1).get_mut(slice) - } + if *self.end() == usize::MAX { None } else { self.into_slice_range().get_mut(slice) } } #[inline] unsafe fn get_unchecked(self, slice: *const str) -> *const Self::Output { // SAFETY: the caller must uphold the safety contract for `get_unchecked`. - unsafe { (*self.start()..self.end() + 1).get_unchecked(slice) } + unsafe { self.into_slice_range().get_unchecked(slice) } } #[inline] unsafe fn get_unchecked_mut(self, slice: *mut str) -> *mut Self::Output { // SAFETY: the caller must uphold the safety contract for `get_unchecked_mut`. - unsafe { (*self.start()..self.end() + 1).get_unchecked_mut(slice) } + unsafe { self.into_slice_range().get_unchecked_mut(slice) } } #[inline] fn index(self, slice: &str) -> &Self::Output { if *self.end() == usize::MAX { str_index_overflow_fail(); } - (*self.start()..self.end() + 1).index(slice) + self.into_slice_range().index(slice) } #[inline] fn index_mut(self, slice: &mut str) -> &mut Self::Output { if *self.end() == usize::MAX { str_index_overflow_fail(); } - (*self.start()..self.end() + 1).index_mut(slice) + self.into_slice_range().index_mut(slice) } } diff --git a/library/core/tests/slice.rs b/library/core/tests/slice.rs index ac5c9353ccb46..9ccc5a08dcbea 100644 --- a/library/core/tests/slice.rs +++ b/library/core/tests/slice.rs @@ -1341,6 +1341,14 @@ mod slice_index { message: "out of range"; } + in mod rangeinclusive_len { + data: [0, 1, 2, 3, 4, 5]; + + good: data[0..=5] == [0, 1, 2, 3, 4, 5]; + bad: data[0..=6]; + message: "out of range"; + } + in mod range_len_len { data: [0, 1, 2, 3, 4, 5]; @@ -1358,6 +1366,28 @@ mod slice_index { } } + panic_cases! { + in mod rangeinclusive_exhausted { + data: [0, 1, 2, 3, 4, 5]; + + good: data[0..=5] == [0, 1, 2, 3, 4, 5]; + good: data[{ + let mut iter = 0..=5; + iter.by_ref().count(); // exhaust it + iter + }] == []; + + // 0..=6 is out of range before exhaustion, so it + // stands to reason that it still would be after. + bad: data[{ + let mut iter = 0..=6; + iter.by_ref().count(); // exhaust it + iter + }]; + message: "out of range"; + } + } + panic_cases! { in mod range_neg_width { data: [0, 1, 2, 3, 4, 5]; diff --git a/library/std/src/keyword_docs.rs b/library/std/src/keyword_docs.rs index a4bbb18da5983..9b704ee9ecab2 100644 --- a/library/std/src/keyword_docs.rs +++ b/library/std/src/keyword_docs.rs @@ -346,7 +346,7 @@ mod else_keyword {} /// When data follows along with a variant, such as with rust's built-in [`Option`] type, the data /// is added as the type describes, for example `Option::Some(123)`. The same follows with /// struct-like variants, with things looking like `ComplexEnum::LotsOfThings { usual_struct_stuff: -/// true, blah: "hello!".to_string(), }`. Empty Enums are similar to () in that they cannot be +/// true, blah: "hello!".to_string(), }`. Empty Enums are similar to [`!`] in that they cannot be /// instantiated at all, and are used mainly to mess with the type system in interesting ways. /// /// For more information, take a look at the [Rust Book] or the [Reference] @@ -354,6 +354,7 @@ mod else_keyword {} /// [ADT]: https://en.wikipedia.org/wiki/Algebraic_data_type /// [Rust Book]: ../book/ch06-01-defining-an-enum.html /// [Reference]: ../reference/items/enumerations.html +/// [`!`]: primitive.never.html mod enum_keyword {} #[doc(keyword = "extern")] diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs index 22cfd0c56431d..3834e50e3fa11 100644 --- a/src/bootstrap/flags.rs +++ b/src/bootstrap/flags.rs @@ -232,7 +232,13 @@ To learn more about a subcommand, run `./x.py -h`", match subcommand.as_str() { "test" | "t" => { opts.optflag("", "no-fail-fast", "Run all tests regardless of failure"); - opts.optmulti("", "test-args", "extra arguments", "ARGS"); + opts.optmulti( + "", + "test-args", + "extra arguments to be passed for the test tool being used \ + (e.g. libtest, compiletest or rustdoc)", + "ARGS", + ); opts.optmulti( "", "rustc-args", diff --git a/src/doc/unstable-book/src/language-features/inline-const.md b/src/doc/unstable-book/src/language-features/inline-const.md new file mode 100644 index 0000000000000..00e1c79ca3ff3 --- /dev/null +++ b/src/doc/unstable-book/src/language-features/inline-const.md @@ -0,0 +1,45 @@ +# `inline_const` + +The tracking issue for this feature is: [#76001] + +------ + +This feature allows you to use inline constant expressions. For example, you can +turn this code: + +```rust +# fn add_one(x: i32) -> i32 { x + 1 } +const MY_COMPUTATION: i32 = 1 + 2 * 3 / 4; + +fn main() { + let x = add_one(MY_COMPUTATION); +} +``` + +into this code: + +```rust +#![feature(inline_const)] + +# fn add_one(x: i32) -> i32 { x + 1 } +fn main() { + let x = add_one(const { 1 + 2 * 3 / 4 }); +} +``` + +You can also use inline constant expressions in patterns: + +```rust +#![feature(inline_const)] + +const fn one() -> i32 { 1 } + +let some_int = 3; +match some_int { + const { 1 + 2 } => println!("Matched 1 + 2"), + const { one() } => println!("Matched const fn returning 1"), + _ => println!("Didn't match anything :("), +} +``` + +[#76001]: https://github.com/rust-lang/rust/issues/76001 diff --git a/src/librustdoc/html/static/storage.js b/src/librustdoc/html/static/storage.js index a027d6845ea21..ef734f260afd5 100644 --- a/src/librustdoc/html/static/storage.js +++ b/src/librustdoc/html/static/storage.js @@ -94,6 +94,12 @@ function switchTheme(styleElem, mainStyleElem, newTheme, saveTheme) { var fullNewTheme = newTheme + resourcesSuffix + ".css"; var newHref = mainStyleElem.href.replace(fullBasicCss, fullNewTheme); + // If this new value comes from a system setting or from the previously + // saved theme, no need to save it. + if (saveTheme === true) { + updateLocalStorage("rustdoc-theme", newTheme); + } + if (styleElem.href === newHref) { return; } @@ -112,11 +118,6 @@ function switchTheme(styleElem, mainStyleElem, newTheme, saveTheme) { }); if (found === true) { styleElem.href = newHref; - // If this new value comes from a system setting or from the previously - // saved theme, no need to save it. - if (saveTheme === true) { - updateLocalStorage("rustdoc-theme", newTheme); - } } } diff --git a/src/test/ui/const-generics/infer/issue-77092.stderr b/src/test/ui/const-generics/infer/issue-77092.stderr index e84ff8baeea53..63facbf3b8c0f 100644 --- a/src/test/ui/const-generics/infer/issue-77092.stderr +++ b/src/test/ui/const-generics/infer/issue-77092.stderr @@ -2,7 +2,7 @@ error[E0282]: type annotations needed --> $DIR/issue-77092.rs:13:26 | LL | println!("{:?}", take_array_from_mut(&mut arr, i)); - | ^^^^^^^^^^^^^^^^^^^ cannot infer the value of the constant `{_: usize}` + | ^^^^^^^^^^^^^^^^^^^ cannot infer the value of const parameter `N` declared on the function `take_array_from_mut` error: aborting due to previous error diff --git a/src/test/ui/macros/issue-77475.rs b/src/test/ui/macros/issue-77475.rs new file mode 100644 index 0000000000000..7b32a33ea4f17 --- /dev/null +++ b/src/test/ui/macros/issue-77475.rs @@ -0,0 +1,10 @@ +// check-pass +// Regression test of #77475, this used to be ICE. + +#![feature(decl_macro)] + +use crate as _; + +pub macro ice(){} + +fn main() {}