Auto merge of #78319 - jonas-schievink:rollup-vzj8a6l, r=jonas-schievink
Rollup of 15 pull requests Successful merges: - #76649 (Add a spin loop hint for Arc::downgrade) - #77392 (add `insert` to `Option`) - #77716 (Revert "Allow dynamic linking for iOS/tvOS targets.") - #78109 (Check for exhaustion in RangeInclusive::contains and slicing) - #78198 (Simplify assert terminator only if condition evaluates to expected value) - #78243 (--test-args flag description) - #78249 (improve const infer error) - #78250 (Document inline-const) - #78264 (Add regression test for issue-77475) - #78274 (Update description of Empty Enum for accuracy) - #78278 (move `visit_predicate` into `TypeVisitor`) - #78292 (Loop instead of recursion) - #78293 (Always store Rustdoc theme when it's changed) - #78300 (Make codegen coverage_context optional, and check) - #78307 (Revert "Set .llvmbc and .llvmcmd sections as allocatable") Failed merges: r? `@ghost`
This commit is contained in:
commit
89fdb30892
@ -10,82 +10,90 @@
|
||||
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)
|
||||
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),
|
||||
}
|
||||
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)
|
||||
}
|
||||
// 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)
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -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());
|
||||
}
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -26,7 +26,10 @@
|
||||
/// 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;
|
||||
|
@ -64,17 +64,22 @@ fn add_counter_region(
|
||||
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 @@ fn add_counter_expression_region(
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -10,19 +10,19 @@ pub fn codegen_coverage(&self, bx: &mut Bx, coverage: Coverage) {
|
||||
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);
|
||||
|
@ -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 @@ fn add_counter_expression_region(
|
||||
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;
|
||||
}
|
||||
|
@ -175,19 +175,15 @@ fn tag() -> &'static str {
|
||||
impl<'tcx> UnifyValue for ConstVarValue<'tcx> {
|
||||
type Error = (&'tcx ty::Const<'tcx>, &'tcx ty::Const<'tcx>);
|
||||
|
||||
fn unify_values(value1: &Self, value2: &Self) -> Result<Self, Self::Error> {
|
||||
let (val, span) = match (value1.val, value2.val) {
|
||||
fn unify_values(&value1: &Self, &value2: &Self) -> Result<Self, Self::Error> {
|
||||
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 @@ fn unify_values(value1: &Self, value2: &Self) -> Result<Self, Self::Error> {
|
||||
// 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,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -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 @@ fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool {
|
||||
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 @@ fn visit_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> bool {
|
||||
_ => 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 @@ fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> bool {
|
||||
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 @@ fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> bool {
|
||||
predicate.inner.flags.intersects(self.flags)
|
||||
}
|
||||
}
|
||||
|
||||
/// Collects all the late-bound regions at the innermost binding level
|
||||
/// into a hash set.
|
||||
struct LateBoundRegionsCollector {
|
||||
|
@ -1040,16 +1040,6 @@ fn has_type_flags(&self, flags: ty::TypeFlags) -> bool {
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) trait PredicateVisitor<'tcx>: TypeVisitor<'tcx> {
|
||||
fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> bool;
|
||||
}
|
||||
|
||||
impl<T: TypeVisitor<'tcx>> 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<ty::Predicate<'tcx>> {
|
||||
fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
|
||||
fold_list(*self, folder, |tcx, v| tcx.intern_predicates(v))
|
||||
|
@ -49,9 +49,10 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
||||
}
|
||||
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 }
|
||||
}
|
||||
|
@ -34,6 +34,7 @@ fn link_env_remove(arch: Arch) -> Vec<String> {
|
||||
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,
|
||||
|
@ -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)]
|
||||
|
@ -10,6 +10,7 @@
|
||||
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 @@ pub fn downgrade(this: &Self) -> Weak<T> {
|
||||
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;
|
||||
}
|
||||
|
@ -529,6 +529,13 @@ fn test_slice_fail() {
|
||||
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 @@ fn test_slice_fail() {
|
||||
}
|
||||
}
|
||||
|
||||
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";
|
||||
|
@ -446,6 +446,20 @@ pub fn into_inner(self) -> (Idx, Idx) {
|
||||
}
|
||||
}
|
||||
|
||||
impl RangeInclusive<usize> {
|
||||
/// 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<usize> {
|
||||
// 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<Idx: fmt::Debug> fmt::Debug for RangeInclusive<Idx> {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
@ -479,6 +493,16 @@ impl<Idx: PartialOrd<Idx>> RangeInclusive<Idx> {
|
||||
/// 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<U>(&self, item: &U) -> bool
|
||||
where
|
||||
@ -881,7 +905,13 @@ fn start_bound(&self) -> Bound<&T> {
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -562,6 +562,36 @@ pub fn ok_or_else<E, F: FnOnce() -> E>(self, err: F) -> Result<T, E> {
|
||||
}
|
||||
}
|
||||
|
||||
/// 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 @@ pub fn xor(self, optb: Option<T>) -> Option<T> {
|
||||
// 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 @@ pub fn xor(self, optb: Option<T>) -> Option<T> {
|
||||
/// ```
|
||||
#[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 @@ pub fn get_or_insert_with<F: FnOnce() -> T>(&mut self, f: F) -> &mut T {
|
||||
*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() },
|
||||
|
@ -376,28 +376,24 @@ unsafe impl<T> SliceIndex<[T]> for ops::RangeInclusive<usize> {
|
||||
|
||||
#[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 @@ fn index(self, slice: &[T]) -> &[T] {
|
||||
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 @@ fn index_mut(self, slice: &mut [T]) -> &mut [T] {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -398,39 +398,35 @@ unsafe impl SliceIndex<str> for ops::RangeInclusive<usize> {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1341,6 +1341,14 @@ fn simple() {
|
||||
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 @@ fn simple() {
|
||||
}
|
||||
}
|
||||
|
||||
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];
|
||||
|
@ -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")]
|
||||
|
@ -232,7 +232,13 @@ pub fn parse(args: &[String]) -> Flags {
|
||||
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",
|
||||
|
45
src/doc/unstable-book/src/language-features/inline-const.md
Normal file
45
src/doc/unstable-book/src/language-features/inline-const.md
Normal file
@ -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
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
10
src/test/ui/macros/issue-77475.rs
Normal file
10
src/test/ui/macros/issue-77475.rs
Normal file
@ -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() {}
|
Loading…
Reference in New Issue
Block a user