Auto merge of #78334 - jonas-schievink:rollup-z0gzbmm, r=jonas-schievink
Rollup of 12 pull requests Successful merges: - #75115 (`#[deny(unsafe_op_in_unsafe_fn)]` in sys/cloudabi) - #76614 (change the order of type arguments on ControlFlow) - #77610 (revise Hermit's mutex interface to support the behaviour of StaticMutex) - #77830 (Simplify query proc-macros) - #77930 (Do not ICE with TraitPredicates containing [type error]) - #78069 (Fix const core::panic!(non_literal_str).) - #78072 (Cleanup constant matching in exhaustiveness checking) - #78119 (Throw core::panic!("message") as &str instead of String.) - #78191 (Introduce a temporary for discriminant value in MatchBranchSimplification) - #78272 (const_evaluatable_checked: deal with unused nodes + div) - #78318 (TyCtxt: generate single impl block with `slice_interners` macro) - #78327 (resolve: Relax macro resolution consistency check to account for any errors) Failed merges: r? `@ghost`
This commit is contained in:
commit
f58ffc9381
66 changed files with 1421 additions and 823 deletions
|
@ -1366,9 +1366,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.1.15"
|
||||
version = "0.1.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3deed196b6e7f9e44a2ae8d94225d80302d81208b1bb673fd21fe634645c85a9"
|
||||
checksum = "5aca5565f760fb5b220e499d72710ed156fdb74e631659e99377d9ebfbd13ae8"
|
||||
dependencies = [
|
||||
"compiler_builtins",
|
||||
"libc",
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use super::{DirectedGraph, WithNumNodes, WithStartNode, WithSuccessors};
|
||||
use rustc_index::bit_set::BitSet;
|
||||
use rustc_index::vec::IndexVec;
|
||||
use std::ops::ControlFlow;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
@ -86,10 +87,6 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
/// Allows searches to terminate early with a value.
|
||||
// FIXME (#75744): remove the alias once the generics are in a better order and `C=()`.
|
||||
pub type ControlFlow<T> = std::ops::ControlFlow<(), T>;
|
||||
|
||||
/// The status of a node in the depth-first search.
|
||||
///
|
||||
/// See the documentation of `TriColorDepthFirstSearch` to see how a node's status is updated
|
||||
|
|
|
@ -111,17 +111,6 @@ cfg_if! {
|
|||
|
||||
type Profiler = measureme::Profiler<SerializationSink>;
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Ord, PartialOrd)]
|
||||
pub enum ProfileCategory {
|
||||
Parsing,
|
||||
Expansion,
|
||||
TypeChecking,
|
||||
BorrowChecking,
|
||||
Codegen,
|
||||
Linking,
|
||||
Other,
|
||||
}
|
||||
|
||||
bitflags::bitflags! {
|
||||
struct EventFilter: u32 {
|
||||
const GENERIC_ACTIVITIES = 1 << 0;
|
||||
|
|
|
@ -263,6 +263,7 @@ language_item_table! {
|
|||
// is required to define it somewhere. Additionally, there are restrictions on crates that use
|
||||
// a weak lang item, but do not have it defined.
|
||||
Panic, sym::panic, panic_fn, Target::Fn;
|
||||
PanicStr, sym::panic_str, panic_str, Target::Fn;
|
||||
PanicBoundsCheck, sym::panic_bounds_check, panic_bounds_check_fn, Target::Fn;
|
||||
PanicInfo, sym::panic_info, panic_info, Target::Struct;
|
||||
PanicLocation, sym::panic_location, panic_location, Target::Struct;
|
||||
|
|
|
@ -190,7 +190,11 @@ impl<T: Parse> Parse for List<T> {
|
|||
}
|
||||
|
||||
/// A named group containing queries.
|
||||
///
|
||||
/// For now, the name is not used any more, but the capability remains interesting for future
|
||||
/// developments of the query system.
|
||||
struct Group {
|
||||
#[allow(unused)]
|
||||
name: Ident,
|
||||
queries: List<Query>,
|
||||
}
|
||||
|
@ -417,12 +421,9 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream {
|
|||
let mut query_stream = quote! {};
|
||||
let mut query_description_stream = quote! {};
|
||||
let mut dep_node_def_stream = quote! {};
|
||||
let mut dep_node_force_stream = quote! {};
|
||||
let mut try_load_from_on_disk_cache_stream = quote! {};
|
||||
let mut cached_queries = quote! {};
|
||||
|
||||
for group in groups.0 {
|
||||
let mut group_stream = quote! {};
|
||||
for mut query in group.queries.0 {
|
||||
let modifiers = process_modifiers(&mut query);
|
||||
let name = &query.name;
|
||||
|
@ -437,22 +438,6 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream {
|
|||
cached_queries.extend(quote! {
|
||||
#name,
|
||||
});
|
||||
|
||||
try_load_from_on_disk_cache_stream.extend(quote! {
|
||||
::rustc_middle::dep_graph::DepKind::#name => {
|
||||
if <#arg as DepNodeParams<TyCtxt<'_>>>::can_reconstruct_query_key() {
|
||||
debug_assert!($tcx.dep_graph
|
||||
.node_color($dep_node)
|
||||
.map(|c| c.is_green())
|
||||
.unwrap_or(false));
|
||||
|
||||
let key = <#arg as DepNodeParams<TyCtxt<'_>>>::recover($tcx, $dep_node).unwrap();
|
||||
if queries::#name::cache_on_disk($tcx, &key, None) {
|
||||
let _ = $tcx.#name(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
let mut attributes = Vec::new();
|
||||
|
@ -485,9 +470,9 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream {
|
|||
let attribute_stream = quote! {#(#attributes),*};
|
||||
let doc_comments = query.doc_comments.iter();
|
||||
// Add the query to the group
|
||||
group_stream.extend(quote! {
|
||||
query_stream.extend(quote! {
|
||||
#(#doc_comments)*
|
||||
[#attribute_stream] fn #name: #name(#arg) #result,
|
||||
[#attribute_stream] fn #name(#arg) #result,
|
||||
});
|
||||
|
||||
// Create a dep node for the query
|
||||
|
@ -495,37 +480,10 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream {
|
|||
[#attribute_stream] #name(#arg),
|
||||
});
|
||||
|
||||
// Add a match arm to force the query given the dep node
|
||||
dep_node_force_stream.extend(quote! {
|
||||
::rustc_middle::dep_graph::DepKind::#name => {
|
||||
if <#arg as DepNodeParams<TyCtxt<'_>>>::can_reconstruct_query_key() {
|
||||
if let Some(key) = <#arg as DepNodeParams<TyCtxt<'_>>>::recover($tcx, $dep_node) {
|
||||
force_query::<crate::ty::query::queries::#name<'_>, _>(
|
||||
$tcx,
|
||||
key,
|
||||
DUMMY_SP,
|
||||
*$dep_node
|
||||
);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
add_query_description_impl(&query, modifiers, &mut query_description_stream);
|
||||
}
|
||||
let name = &group.name;
|
||||
query_stream.extend(quote! {
|
||||
#name { #group_stream },
|
||||
});
|
||||
}
|
||||
|
||||
dep_node_force_stream.extend(quote! {
|
||||
::rustc_middle::dep_graph::DepKind::Null => {
|
||||
bug!("Cannot force dep node: {:?}", $dep_node)
|
||||
}
|
||||
});
|
||||
|
||||
TokenStream::from(quote! {
|
||||
macro_rules! rustc_query_append {
|
||||
([$($macro:tt)*][$($other:tt)*]) => {
|
||||
|
@ -546,15 +504,6 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream {
|
|||
);
|
||||
}
|
||||
}
|
||||
macro_rules! rustc_dep_node_force {
|
||||
([$dep_node:expr, $tcx:expr] $($other:tt)*) => {
|
||||
match $dep_node.kind {
|
||||
$($other)*
|
||||
|
||||
#dep_node_force_stream
|
||||
}
|
||||
}
|
||||
}
|
||||
macro_rules! rustc_cached_queries {
|
||||
($($macro:tt)*) => {
|
||||
$($macro)*(#cached_queries);
|
||||
|
@ -562,14 +511,5 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream {
|
|||
}
|
||||
|
||||
#query_description_stream
|
||||
|
||||
macro_rules! rustc_dep_node_try_load_from_on_disk_cache {
|
||||
($dep_node:expr, $tcx:expr) => {
|
||||
match $dep_node.kind {
|
||||
#try_load_from_on_disk_cache_stream
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
@ -2036,13 +2036,13 @@ direct_interners! {
|
|||
|
||||
macro_rules! slice_interners {
|
||||
($($field:ident: $method:ident($ty:ty)),+ $(,)?) => (
|
||||
$(impl<'tcx> TyCtxt<'tcx> {
|
||||
pub fn $method(self, v: &[$ty]) -> &'tcx List<$ty> {
|
||||
impl<'tcx> TyCtxt<'tcx> {
|
||||
$(pub fn $method(self, v: &[$ty]) -> &'tcx List<$ty> {
|
||||
self.interners.$field.intern_ref(v, || {
|
||||
Interned(List::from_arena(&*self.arena, v))
|
||||
}).0
|
||||
}
|
||||
})+
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -34,7 +34,6 @@ use crate::ty::util::AlwaysRequiresDrop;
|
|||
use crate::ty::{self, AdtSizedConstraint, CrateInherentImpls, ParamEnvAnd, Ty, TyCtxt};
|
||||
use rustc_data_structures::fingerprint::Fingerprint;
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
|
||||
use rustc_data_structures::profiling::ProfileCategory::*;
|
||||
use rustc_data_structures::stable_hasher::StableVec;
|
||||
use rustc_data_structures::svh::Svh;
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
|
@ -169,7 +168,9 @@ pub fn force_from_dep_node<'tcx>(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> bool
|
|||
return false;
|
||||
}
|
||||
|
||||
rustc_dep_node_force!([dep_node, tcx]
|
||||
macro_rules! force_from_dep_node {
|
||||
($($(#[$attr:meta])* [$($modifiers:tt)*] $name:ident($K:ty),)*) => {
|
||||
match dep_node.kind {
|
||||
// These are inputs that are expected to be pre-allocated and that
|
||||
// should therefore always be red or green already.
|
||||
DepKind::CrateMetadata |
|
||||
|
@ -179,16 +180,59 @@ pub fn force_from_dep_node<'tcx>(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> bool
|
|||
|
||||
// We don't have enough information to reconstruct the query key of
|
||||
// these.
|
||||
DepKind::CompileCodegenUnit => {
|
||||
DepKind::CompileCodegenUnit |
|
||||
|
||||
// Forcing this makes no sense.
|
||||
DepKind::Null => {
|
||||
bug!("force_from_dep_node: encountered {:?}", dep_node)
|
||||
}
|
||||
|
||||
$(DepKind::$name => {
|
||||
debug_assert!(<$K as DepNodeParams<TyCtxt<'_>>>::can_reconstruct_query_key());
|
||||
|
||||
if let Some(key) = <$K as DepNodeParams<TyCtxt<'_>>>::recover(tcx, dep_node) {
|
||||
force_query::<queries::$name<'_>, _>(
|
||||
tcx,
|
||||
key,
|
||||
DUMMY_SP,
|
||||
*dep_node
|
||||
);
|
||||
return true;
|
||||
}
|
||||
})*
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rustc_dep_node_append! { [force_from_dep_node!][] }
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
pub(crate) fn try_load_from_on_disk_cache<'tcx>(tcx: TyCtxt<'tcx>, dep_node: &DepNode) {
|
||||
rustc_dep_node_try_load_from_on_disk_cache!(dep_node, tcx)
|
||||
macro_rules! try_load_from_on_disk_cache {
|
||||
($($name:ident,)*) => {
|
||||
match dep_node.kind {
|
||||
$(DepKind::$name => {
|
||||
if <query_keys::$name<'tcx> as DepNodeParams<TyCtxt<'_>>>::can_reconstruct_query_key() {
|
||||
debug_assert!(tcx.dep_graph
|
||||
.node_color(dep_node)
|
||||
.map(|c| c.is_green())
|
||||
.unwrap_or(false));
|
||||
|
||||
let key = <query_keys::$name<'tcx> as DepNodeParams<TyCtxt<'_>>>::recover(tcx, dep_node).unwrap();
|
||||
if queries::$name::cache_on_disk(tcx, &key, None) {
|
||||
let _ = tcx.$name(key);
|
||||
}
|
||||
}
|
||||
})*
|
||||
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rustc_cached_queries!(try_load_from_on_disk_cache!);
|
||||
}
|
||||
|
||||
mod sealed {
|
||||
|
|
|
@ -242,25 +242,15 @@ macro_rules! hash_result {
|
|||
};
|
||||
}
|
||||
|
||||
macro_rules! define_queries {
|
||||
(<$tcx:tt> $($category:tt {
|
||||
$($(#[$attr:meta])* [$($modifiers:tt)*] fn $name:ident: $node:ident($($K:tt)*) -> $V:ty,)*
|
||||
},)*) => {
|
||||
define_queries_inner! { <$tcx>
|
||||
$($( $(#[$attr])* category<$category> [$($modifiers)*] fn $name: $node($($K)*) -> $V,)*)*
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! query_helper_param_ty {
|
||||
(DefId) => { impl IntoQueryParam<DefId> };
|
||||
($K:ty) => { $K };
|
||||
}
|
||||
|
||||
macro_rules! define_queries_inner {
|
||||
macro_rules! define_queries {
|
||||
(<$tcx:tt>
|
||||
$($(#[$attr:meta])* category<$category:tt>
|
||||
[$($modifiers:tt)*] fn $name:ident: $node:ident($($K:tt)*) -> $V:ty,)*) => {
|
||||
$($(#[$attr:meta])*
|
||||
[$($modifiers:tt)*] fn $name:ident($($K:tt)*) -> $V:ty,)*) => {
|
||||
|
||||
use std::mem;
|
||||
use crate::{
|
||||
|
@ -268,7 +258,6 @@ macro_rules! define_queries_inner {
|
|||
rustc_data_structures::stable_hasher::StableHasher,
|
||||
ich::StableHashingContext
|
||||
};
|
||||
use rustc_data_structures::profiling::ProfileCategory;
|
||||
|
||||
define_queries_struct! {
|
||||
tcx: $tcx,
|
||||
|
@ -362,13 +351,12 @@ macro_rules! define_queries_inner {
|
|||
as QueryStorage
|
||||
>::Stored;
|
||||
const NAME: &'static str = stringify!($name);
|
||||
const CATEGORY: ProfileCategory = $category;
|
||||
}
|
||||
|
||||
impl<$tcx> QueryAccessors<TyCtxt<$tcx>> for queries::$name<$tcx> {
|
||||
const ANON: bool = is_anon!([$($modifiers)*]);
|
||||
const EVAL_ALWAYS: bool = is_eval_always!([$($modifiers)*]);
|
||||
const DEP_KIND: dep_graph::DepKind = dep_graph::DepKind::$node;
|
||||
const DEP_KIND: dep_graph::DepKind = dep_graph::DepKind::$name;
|
||||
|
||||
type Cache = query_storage!([$($modifiers)*][$($K)*, $V]);
|
||||
|
||||
|
|
|
@ -120,13 +120,13 @@ pub fn print_stats(tcx: TyCtxt<'_>) {
|
|||
}
|
||||
|
||||
macro_rules! print_stats {
|
||||
(<$tcx:tt> $($category:tt {
|
||||
$($(#[$attr:meta])* [$($modifiers:tt)*] fn $name:ident: $node:ident($K:ty) -> $V:ty,)*
|
||||
},)*) => {
|
||||
(<$tcx:tt>
|
||||
$($(#[$attr:meta])* [$($modifiers:tt)*] fn $name:ident($K:ty) -> $V:ty,)*
|
||||
) => {
|
||||
fn query_stats(tcx: TyCtxt<'_>) -> Vec<QueryStats> {
|
||||
let mut queries = Vec::new();
|
||||
|
||||
$($(
|
||||
$(
|
||||
queries.push(stats::<
|
||||
crate::dep_graph::DepKind,
|
||||
<TyCtxt<'_> as QueryContext>::Query,
|
||||
|
@ -135,7 +135,7 @@ macro_rules! print_stats {
|
|||
stringify!($name),
|
||||
&tcx.queries.$name,
|
||||
));
|
||||
)*)*
|
||||
)*
|
||||
|
||||
queries
|
||||
}
|
||||
|
|
|
@ -70,9 +70,10 @@ impl<'mir, 'tcx> InterpCx<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>> {
|
|||
) -> InterpResult<'tcx> {
|
||||
let def_id = instance.def_id();
|
||||
if Some(def_id) == self.tcx.lang_items().panic_fn()
|
||||
|| Some(def_id) == self.tcx.lang_items().panic_str()
|
||||
|| Some(def_id) == self.tcx.lang_items().begin_panic_fn()
|
||||
{
|
||||
// &'static str
|
||||
// &str
|
||||
assert!(args.len() == 1);
|
||||
|
||||
let msg_place = self.deref_operand(args[0])?;
|
||||
|
|
|
@ -74,7 +74,9 @@ impl ConstCx<'mir, 'tcx> {
|
|||
|
||||
/// Returns `true` if this `DefId` points to one of the official `panic` lang items.
|
||||
pub fn is_lang_panic_fn(tcx: TyCtxt<'tcx>, def_id: DefId) -> bool {
|
||||
Some(def_id) == tcx.lang_items().panic_fn() || Some(def_id) == tcx.lang_items().begin_panic_fn()
|
||||
Some(def_id) == tcx.lang_items().panic_fn()
|
||||
|| Some(def_id) == tcx.lang_items().panic_str()
|
||||
|| Some(def_id) == tcx.lang_items().begin_panic_fn()
|
||||
}
|
||||
|
||||
pub fn allow_internal_unstable(tcx: TyCtxt<'tcx>, def_id: DefId, feature_gate: Symbol) -> bool {
|
||||
|
|
|
@ -38,19 +38,16 @@ pub struct MatchBranchSimplification;
|
|||
|
||||
impl<'tcx> MirPass<'tcx> for MatchBranchSimplification {
|
||||
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
||||
// FIXME: This optimization can result in unsoundness, because it introduces
|
||||
// additional uses of a place holding the discriminant value without ensuring that
|
||||
// it is valid to do so.
|
||||
if !tcx.sess.opts.debugging_opts.unsound_mir_opts {
|
||||
if tcx.sess.opts.debugging_opts.mir_opt_level <= 1 {
|
||||
return;
|
||||
}
|
||||
|
||||
let param_env = tcx.param_env(body.source.def_id());
|
||||
let bbs = body.basic_blocks_mut();
|
||||
let (bbs, local_decls) = body.basic_blocks_and_local_decls_mut();
|
||||
'outer: for bb_idx in bbs.indices() {
|
||||
let (discr, val, switch_ty, first, second) = match bbs[bb_idx].terminator().kind {
|
||||
TerminatorKind::SwitchInt {
|
||||
discr: Operand::Copy(ref place) | Operand::Move(ref place),
|
||||
discr: ref discr @ (Operand::Copy(_) | Operand::Move(_)),
|
||||
switch_ty,
|
||||
ref targets,
|
||||
..
|
||||
|
@ -59,7 +56,7 @@ impl<'tcx> MirPass<'tcx> for MatchBranchSimplification {
|
|||
if target == targets.otherwise() {
|
||||
continue;
|
||||
}
|
||||
(place, value, switch_ty, target, targets.otherwise())
|
||||
(discr, value, switch_ty, target, targets.otherwise())
|
||||
}
|
||||
// Only optimize switch int statements
|
||||
_ => continue,
|
||||
|
@ -99,6 +96,10 @@ impl<'tcx> MirPass<'tcx> for MatchBranchSimplification {
|
|||
// Take ownership of items now that we know we can optimize.
|
||||
let discr = discr.clone();
|
||||
|
||||
// Introduce a temporary for the discriminant value.
|
||||
let source_info = bbs[bb_idx].terminator().source_info;
|
||||
let discr_local = local_decls.push(LocalDecl::new(switch_ty, source_info.span));
|
||||
|
||||
// We already checked that first and second are different blocks,
|
||||
// and bb_idx has a different terminator from both of them.
|
||||
let (from, first, second) = bbs.pick3_mut(bb_idx, first, second);
|
||||
|
@ -127,7 +128,11 @@ impl<'tcx> MirPass<'tcx> for MatchBranchSimplification {
|
|||
rustc_span::DUMMY_SP,
|
||||
);
|
||||
let op = if f_b { BinOp::Eq } else { BinOp::Ne };
|
||||
let rhs = Rvalue::BinaryOp(op, Operand::Copy(discr.clone()), const_cmp);
|
||||
let rhs = Rvalue::BinaryOp(
|
||||
op,
|
||||
Operand::Copy(Place::from(discr_local)),
|
||||
const_cmp,
|
||||
);
|
||||
Statement {
|
||||
source_info: f.source_info,
|
||||
kind: StatementKind::Assign(box (*lhs, rhs)),
|
||||
|
@ -138,7 +143,16 @@ impl<'tcx> MirPass<'tcx> for MatchBranchSimplification {
|
|||
_ => unreachable!(),
|
||||
}
|
||||
});
|
||||
|
||||
from.statements
|
||||
.push(Statement { source_info, kind: StatementKind::StorageLive(discr_local) });
|
||||
from.statements.push(Statement {
|
||||
source_info,
|
||||
kind: StatementKind::Assign(box (Place::from(discr_local), Rvalue::Use(discr))),
|
||||
});
|
||||
from.statements.extend(new_stmts);
|
||||
from.statements
|
||||
.push(Statement { source_info, kind: StatementKind::StorageDead(discr_local) });
|
||||
from.terminator_mut().kind = first.terminator().kind.clone();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use rustc_data_structures::graph::iterate::{
|
||||
ControlFlow, NodeStatus, TriColorDepthFirstSearch, TriColorVisitor,
|
||||
NodeStatus, TriColorDepthFirstSearch, TriColorVisitor,
|
||||
};
|
||||
use rustc_hir::intravisit::FnKind;
|
||||
use rustc_middle::hir::map::blocks::FnLikeNode;
|
||||
|
@ -8,6 +8,7 @@ use rustc_middle::ty::subst::{GenericArg, InternalSubsts};
|
|||
use rustc_middle::ty::{self, AssocItem, AssocItemContainer, Instance, TyCtxt};
|
||||
use rustc_session::lint::builtin::UNCONDITIONAL_RECURSION;
|
||||
use rustc_span::Span;
|
||||
use std::ops::ControlFlow;
|
||||
|
||||
crate fn check<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
|
||||
let def_id = body.source.def_id().expect_local();
|
||||
|
|
|
@ -302,10 +302,9 @@ use super::{FieldPat, Pat, PatKind, PatRange};
|
|||
|
||||
use rustc_arena::TypedArena;
|
||||
use rustc_attr::{SignedInt, UnsignedInt};
|
||||
use rustc_errors::ErrorReported;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::{HirId, RangeEnd};
|
||||
use rustc_middle::mir::interpret::{truncate, AllocId, ConstValue, Pointer, Scalar};
|
||||
use rustc_middle::mir::interpret::{truncate, ConstValue};
|
||||
use rustc_middle::mir::Field;
|
||||
use rustc_middle::ty::layout::IntegerExt;
|
||||
use rustc_middle::ty::{self, Const, Ty, TyCtxt};
|
||||
|
@ -314,108 +313,21 @@ use rustc_span::{Span, DUMMY_SP};
|
|||
use rustc_target::abi::{Integer, Size, VariantIdx};
|
||||
|
||||
use smallvec::{smallvec, SmallVec};
|
||||
use std::borrow::Cow;
|
||||
use std::cmp::{self, max, min, Ordering};
|
||||
use std::convert::TryInto;
|
||||
use std::fmt;
|
||||
use std::iter::{FromIterator, IntoIterator};
|
||||
use std::ops::RangeInclusive;
|
||||
|
||||
crate fn expand_pattern<'a, 'tcx>(cx: &MatchCheckCtxt<'a, 'tcx>, pat: Pat<'tcx>) -> Pat<'tcx> {
|
||||
LiteralExpander { tcx: cx.tcx, param_env: cx.param_env }.fold_pattern(&pat)
|
||||
crate fn expand_pattern<'tcx>(pat: Pat<'tcx>) -> Pat<'tcx> {
|
||||
LiteralExpander.fold_pattern(&pat)
|
||||
}
|
||||
|
||||
struct LiteralExpander<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
}
|
||||
struct LiteralExpander;
|
||||
|
||||
impl<'tcx> LiteralExpander<'tcx> {
|
||||
/// Derefs `val` and potentially unsizes the value if `crty` is an array and `rty` a slice.
|
||||
///
|
||||
/// `crty` and `rty` can differ because you can use array constants in the presence of slice
|
||||
/// patterns. So the pattern may end up being a slice, but the constant is an array. We convert
|
||||
/// the array to a slice in that case.
|
||||
fn fold_const_value_deref(
|
||||
&mut self,
|
||||
val: ConstValue<'tcx>,
|
||||
// the pattern's pointee type
|
||||
rty: Ty<'tcx>,
|
||||
// the constant's pointee type
|
||||
crty: Ty<'tcx>,
|
||||
) -> ConstValue<'tcx> {
|
||||
debug!("fold_const_value_deref {:?} {:?} {:?}", val, rty, crty);
|
||||
match (val, &crty.kind(), &rty.kind()) {
|
||||
// the easy case, deref a reference
|
||||
(ConstValue::Scalar(p), x, y) if x == y => {
|
||||
match p {
|
||||
Scalar::Ptr(p) => {
|
||||
let alloc = self.tcx.global_alloc(p.alloc_id).unwrap_memory();
|
||||
ConstValue::ByRef { alloc, offset: p.offset }
|
||||
}
|
||||
Scalar::Raw { .. } => {
|
||||
let layout = self.tcx.layout_of(self.param_env.and(rty)).unwrap();
|
||||
if layout.is_zst() {
|
||||
// Deref of a reference to a ZST is a nop.
|
||||
ConstValue::Scalar(Scalar::zst())
|
||||
} else {
|
||||
// FIXME(oli-obk): this is reachable for `const FOO: &&&u32 = &&&42;`
|
||||
bug!("cannot deref {:#?}, {} -> {}", val, crty, rty);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// unsize array to slice if pattern is array but match value or other patterns are slice
|
||||
(ConstValue::Scalar(Scalar::Ptr(p)), ty::Array(t, n), ty::Slice(u)) => {
|
||||
assert_eq!(t, u);
|
||||
ConstValue::Slice {
|
||||
data: self.tcx.global_alloc(p.alloc_id).unwrap_memory(),
|
||||
start: p.offset.bytes().try_into().unwrap(),
|
||||
end: n.eval_usize(self.tcx, ty::ParamEnv::empty()).try_into().unwrap(),
|
||||
}
|
||||
}
|
||||
// fat pointers stay the same
|
||||
(ConstValue::Slice { .. }, _, _)
|
||||
| (_, ty::Slice(_), ty::Slice(_))
|
||||
| (_, ty::Str, ty::Str) => val,
|
||||
// FIXME(oli-obk): this is reachable for `const FOO: &&&u32 = &&&42;` being used
|
||||
_ => bug!("cannot deref {:#?}, {} -> {}", val, crty, rty),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> PatternFolder<'tcx> for LiteralExpander<'tcx> {
|
||||
impl<'tcx> PatternFolder<'tcx> for LiteralExpander {
|
||||
fn fold_pattern(&mut self, pat: &Pat<'tcx>) -> Pat<'tcx> {
|
||||
debug!("fold_pattern {:?} {:?} {:?}", pat, pat.ty.kind(), pat.kind);
|
||||
match (pat.ty.kind(), &*pat.kind) {
|
||||
(&ty::Ref(_, rty, _), &PatKind::Constant { value: Const { val, ty: const_ty } })
|
||||
if const_ty.is_ref() =>
|
||||
{
|
||||
let crty =
|
||||
if let ty::Ref(_, crty, _) = const_ty.kind() { crty } else { unreachable!() };
|
||||
if let ty::ConstKind::Value(val) = val {
|
||||
Pat {
|
||||
ty: pat.ty,
|
||||
span: pat.span,
|
||||
kind: box PatKind::Deref {
|
||||
subpattern: Pat {
|
||||
ty: rty,
|
||||
span: pat.span,
|
||||
kind: box PatKind::Constant {
|
||||
value: Const::from_value(
|
||||
self.tcx,
|
||||
self.fold_const_value_deref(*val, rty, crty),
|
||||
rty,
|
||||
),
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
} else {
|
||||
bug!("cannot deref {:#?}, {} -> {}", val, crty, rty)
|
||||
}
|
||||
}
|
||||
|
||||
(_, &PatKind::Binding { subpattern: Some(ref s), .. }) => s.fold_with(self),
|
||||
(_, &PatKind::AscribeUserType { subpattern: ref s, .. }) => s.fold_with(self),
|
||||
_ => pat.super_fold_with(self),
|
||||
|
@ -500,9 +412,15 @@ impl<'p, 'tcx> PatStack<'p, 'tcx> {
|
|||
cx: &mut MatchCheckCtxt<'p, 'tcx>,
|
||||
constructor: &Constructor<'tcx>,
|
||||
ctor_wild_subpatterns: &Fields<'p, 'tcx>,
|
||||
is_my_head_ctor: bool,
|
||||
) -> Option<PatStack<'p, 'tcx>> {
|
||||
let new_fields =
|
||||
specialize_one_pattern(cx, self.head(), constructor, ctor_wild_subpatterns)?;
|
||||
let new_fields = specialize_one_pattern(
|
||||
cx,
|
||||
self.head(),
|
||||
constructor,
|
||||
ctor_wild_subpatterns,
|
||||
is_my_head_ctor,
|
||||
)?;
|
||||
Some(new_fields.push_on_patstack(&self.0[1..]))
|
||||
}
|
||||
}
|
||||
|
@ -680,6 +598,7 @@ impl<'p, 'tcx> Matrix<'p, 'tcx> {
|
|||
cx,
|
||||
constructor,
|
||||
ctor_wild_subpatterns,
|
||||
false,
|
||||
)
|
||||
})
|
||||
.collect()
|
||||
|
@ -705,7 +624,9 @@ impl<'p, 'tcx> Matrix<'p, 'tcx> {
|
|||
SpecializationCache::Incompatible => self
|
||||
.patterns
|
||||
.iter()
|
||||
.filter_map(|r| r.specialize_constructor(cx, constructor, ctor_wild_subpatterns))
|
||||
.filter_map(|r| {
|
||||
r.specialize_constructor(cx, constructor, ctor_wild_subpatterns, false)
|
||||
})
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
|
@ -725,6 +646,7 @@ impl<'p, 'tcx> Matrix<'p, 'tcx> {
|
|||
/// +++++++++++++++++++++++++++++
|
||||
/// + _ + [_, _, tail @ ..] +
|
||||
/// +++++++++++++++++++++++++++++
|
||||
/// ```
|
||||
impl<'p, 'tcx> fmt::Debug for Matrix<'p, 'tcx> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "\n")?;
|
||||
|
@ -926,42 +848,30 @@ enum Constructor<'tcx> {
|
|||
Single,
|
||||
/// Enum variants.
|
||||
Variant(DefId),
|
||||
/// Literal values.
|
||||
ConstantValue(&'tcx ty::Const<'tcx>),
|
||||
/// Ranges of integer literal values (`2`, `2..=5` or `2..5`).
|
||||
IntRange(IntRange<'tcx>),
|
||||
/// Ranges of floating-point literal values (`2.0..=5.2`).
|
||||
FloatRange(&'tcx ty::Const<'tcx>, &'tcx ty::Const<'tcx>, RangeEnd),
|
||||
/// String literals. Strings are not quite the same as `&[u8]` so we treat them separately.
|
||||
Str(&'tcx ty::Const<'tcx>),
|
||||
/// Array and slice patterns.
|
||||
Slice(Slice),
|
||||
/// Constants that must not be matched structurally. They are treated as black
|
||||
/// boxes for the purposes of exhaustiveness: we must not inspect them, and they
|
||||
/// don't count towards making a match exhaustive.
|
||||
Opaque,
|
||||
/// Fake extra constructor for enums that aren't allowed to be matched exhaustively.
|
||||
NonExhaustive,
|
||||
}
|
||||
|
||||
impl<'tcx> Constructor<'tcx> {
|
||||
fn is_slice(&self) -> bool {
|
||||
match self {
|
||||
Slice(_) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn variant_index_for_adt<'a>(
|
||||
&self,
|
||||
cx: &MatchCheckCtxt<'a, 'tcx>,
|
||||
adt: &'tcx ty::AdtDef,
|
||||
) -> VariantIdx {
|
||||
fn variant_index_for_adt(&self, adt: &'tcx ty::AdtDef) -> VariantIdx {
|
||||
match *self {
|
||||
Variant(id) => adt.variant_index_with_id(id),
|
||||
Single => {
|
||||
assert!(!adt.is_enum());
|
||||
VariantIdx::new(0)
|
||||
}
|
||||
ConstantValue(c) => cx
|
||||
.tcx
|
||||
.destructure_const(cx.param_env.and(c))
|
||||
.variant
|
||||
.expect("destructed const of adt without variant id"),
|
||||
_ => bug!("bad constructor {:?} for adt {:?}", self, adt),
|
||||
}
|
||||
}
|
||||
|
@ -975,7 +885,7 @@ impl<'tcx> Constructor<'tcx> {
|
|||
|
||||
match self {
|
||||
// Those constructors can only match themselves.
|
||||
Single | Variant(_) | ConstantValue(..) | FloatRange(..) => {
|
||||
Single | Variant(_) | Str(..) | FloatRange(..) => {
|
||||
if other_ctors.iter().any(|c| c == self) { vec![] } else { vec![self.clone()] }
|
||||
}
|
||||
&Slice(slice) => {
|
||||
|
@ -983,8 +893,6 @@ impl<'tcx> Constructor<'tcx> {
|
|||
.iter()
|
||||
.filter_map(|c: &Constructor<'_>| match c {
|
||||
Slice(slice) => Some(*slice),
|
||||
// FIXME(oli-obk): implement `deref` for `ConstValue`
|
||||
ConstantValue(..) => None,
|
||||
_ => bug!("bad slice pattern constructor {:?}", c),
|
||||
})
|
||||
.map(Slice::value_kind);
|
||||
|
@ -1048,6 +956,7 @@ impl<'tcx> Constructor<'tcx> {
|
|||
}
|
||||
// This constructor is never covered by anything else
|
||||
NonExhaustive => vec![NonExhaustive],
|
||||
Opaque => bug!("unexpected opaque ctor {:?} found in all_ctors", self),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1087,7 +996,7 @@ impl<'tcx> Constructor<'tcx> {
|
|||
PatKind::Variant {
|
||||
adt_def: adt,
|
||||
substs,
|
||||
variant_index: self.variant_index_for_adt(cx, adt),
|
||||
variant_index: self.variant_index_for_adt(adt),
|
||||
subpatterns,
|
||||
}
|
||||
} else {
|
||||
|
@ -1126,10 +1035,11 @@ impl<'tcx> Constructor<'tcx> {
|
|||
PatKind::Slice { prefix, slice: Some(wild), suffix }
|
||||
}
|
||||
},
|
||||
&ConstantValue(value) => PatKind::Constant { value },
|
||||
&Str(value) => PatKind::Constant { value },
|
||||
&FloatRange(lo, hi, end) => PatKind::Range(PatRange { lo, hi, end }),
|
||||
IntRange(range) => return range.to_pat(cx.tcx),
|
||||
NonExhaustive => PatKind::Wild,
|
||||
Opaque => bug!("we should not try to apply an opaque constructor {:?}", self),
|
||||
};
|
||||
|
||||
Pat { ty, span: DUMMY_SP, kind: Box::new(pat) }
|
||||
|
@ -1204,12 +1114,6 @@ impl<'p, 'tcx> Fields<'p, 'tcx> {
|
|||
Fields::Slice(std::slice::from_ref(pat))
|
||||
}
|
||||
|
||||
/// Construct a new `Fields` from the given patterns. You must be sure those patterns can't
|
||||
/// contain fields that need to be filtered out. When in doubt, prefer `replace_fields`.
|
||||
fn from_slice_unfiltered(pats: &'p [Pat<'tcx>]) -> Self {
|
||||
Fields::Slice(pats)
|
||||
}
|
||||
|
||||
/// Convenience; internal use.
|
||||
fn wildcards_from_tys(
|
||||
cx: &MatchCheckCtxt<'p, 'tcx>,
|
||||
|
@ -1239,7 +1143,7 @@ impl<'p, 'tcx> Fields<'p, 'tcx> {
|
|||
// Use T as the sub pattern type of Box<T>.
|
||||
Fields::from_single_pattern(wildcard_from_ty(substs.type_at(0)))
|
||||
} else {
|
||||
let variant = &adt.variants[constructor.variant_index_for_adt(cx, adt)];
|
||||
let variant = &adt.variants[constructor.variant_index_for_adt(adt)];
|
||||
// Whether we must not match the fields of this variant exhaustively.
|
||||
let is_non_exhaustive =
|
||||
variant.is_field_list_non_exhaustive() && !adt.did.is_local();
|
||||
|
@ -1287,7 +1191,7 @@ impl<'p, 'tcx> Fields<'p, 'tcx> {
|
|||
}
|
||||
_ => bug!("bad slice pattern {:?} {:?}", constructor, ty),
|
||||
},
|
||||
ConstantValue(..) | FloatRange(..) | IntRange(..) | NonExhaustive => Fields::empty(),
|
||||
Str(..) | FloatRange(..) | IntRange(..) | NonExhaustive | Opaque => Fields::empty(),
|
||||
};
|
||||
debug!("Fields::wildcards({:?}, {:?}) = {:#?}", constructor, ty, ret);
|
||||
ret
|
||||
|
@ -1600,9 +1504,7 @@ fn all_constructors<'a, 'tcx>(
|
|||
)
|
||||
};
|
||||
match *pcx.ty.kind() {
|
||||
ty::Bool => {
|
||||
[true, false].iter().map(|&b| ConstantValue(ty::Const::from_bool(cx.tcx, b))).collect()
|
||||
}
|
||||
ty::Bool => vec![make_range(0, 1)],
|
||||
ty::Array(ref sub_ty, len) if len.try_eval_usize(cx.tcx, cx.param_env).is_some() => {
|
||||
let len = len.eval_usize(cx.tcx, cx.param_env);
|
||||
if len != 0 && cx.is_uninhabited(sub_ty) {
|
||||
|
@ -1717,7 +1619,7 @@ impl<'tcx> IntRange<'tcx> {
|
|||
#[inline]
|
||||
fn is_integral(ty: Ty<'_>) -> bool {
|
||||
match ty.kind() {
|
||||
ty::Char | ty::Int(_) | ty::Uint(_) => true,
|
||||
ty::Char | ty::Int(_) | ty::Uint(_) | ty::Bool => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
@ -1739,6 +1641,7 @@ impl<'tcx> IntRange<'tcx> {
|
|||
#[inline]
|
||||
fn integral_size_and_signed_bias(tcx: TyCtxt<'tcx>, ty: Ty<'_>) -> Option<(Size, u128)> {
|
||||
match *ty.kind() {
|
||||
ty::Bool => Some((Size::from_bytes(1), 0)),
|
||||
ty::Char => Some((Size::from_bytes(4), 0)),
|
||||
ty::Int(ity) => {
|
||||
let size = Integer::from_attr(&tcx, SignedInt(ity)).size();
|
||||
|
@ -2230,7 +2133,7 @@ fn is_useful_specialized<'p, 'tcx>(
|
|||
// We cache the result of `Fields::wildcards` because it is used a lot.
|
||||
let ctor_wild_subpatterns = Fields::wildcards(cx, &ctor, ty);
|
||||
let matrix = matrix.specialize_constructor(cx, &ctor, &ctor_wild_subpatterns);
|
||||
v.specialize_constructor(cx, &ctor, &ctor_wild_subpatterns)
|
||||
v.specialize_constructor(cx, &ctor, &ctor_wild_subpatterns, true)
|
||||
.map(|v| is_useful(cx, &matrix, &v, witness_preference, hir_id, is_under_guard, false))
|
||||
.map(|u| u.apply_constructor(cx, &ctor, ty, &ctor_wild_subpatterns))
|
||||
.unwrap_or(NotUseful)
|
||||
|
@ -2255,18 +2158,13 @@ fn pat_constructor<'tcx>(
|
|||
if let Some(int_range) = IntRange::from_const(tcx, param_env, value, pat.span) {
|
||||
Some(IntRange(int_range))
|
||||
} else {
|
||||
match (value.val, &value.ty.kind()) {
|
||||
(_, ty::Array(_, n)) => {
|
||||
let len = n.eval_usize(tcx, param_env);
|
||||
Some(Slice(Slice { array_len: Some(len), kind: FixedLen(len) }))
|
||||
}
|
||||
(ty::ConstKind::Value(ConstValue::Slice { start, end, .. }), ty::Slice(_)) => {
|
||||
let len = (end - start) as u64;
|
||||
Some(Slice(Slice { array_len: None, kind: FixedLen(len) }))
|
||||
}
|
||||
// FIXME(oli-obk): implement `deref` for `ConstValue`
|
||||
// (ty::ConstKind::Value(ConstValue::ByRef { .. }), ty::Slice(_)) => { ... }
|
||||
_ => Some(ConstantValue(value)),
|
||||
match value.ty.kind() {
|
||||
ty::Float(_) => Some(FloatRange(value, value, RangeEnd::Included)),
|
||||
ty::Ref(_, t, _) if t.is_str() => Some(Str(value)),
|
||||
// All constants that can be structurally matched have already been expanded
|
||||
// into the corresponding `Pat`s by `const_to_pat`. Constants that remain are
|
||||
// opaque.
|
||||
_ => Some(Opaque),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2302,75 +2200,6 @@ fn pat_constructor<'tcx>(
|
|||
}
|
||||
}
|
||||
|
||||
// checks whether a constant is equal to a user-written slice pattern. Only supports byte slices,
|
||||
// meaning all other types will compare unequal and thus equal patterns often do not cause the
|
||||
// second pattern to lint about unreachable match arms.
|
||||
fn slice_pat_covered_by_const<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
_span: Span,
|
||||
const_val: &'tcx ty::Const<'tcx>,
|
||||
prefix: &[Pat<'tcx>],
|
||||
slice: &Option<Pat<'tcx>>,
|
||||
suffix: &[Pat<'tcx>],
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
) -> Result<bool, ErrorReported> {
|
||||
let const_val_val = if let ty::ConstKind::Value(val) = const_val.val {
|
||||
val
|
||||
} else {
|
||||
bug!(
|
||||
"slice_pat_covered_by_const: {:#?}, {:#?}, {:#?}, {:#?}",
|
||||
const_val,
|
||||
prefix,
|
||||
slice,
|
||||
suffix,
|
||||
)
|
||||
};
|
||||
|
||||
let data: &[u8] = match (const_val_val, &const_val.ty.kind()) {
|
||||
(ConstValue::ByRef { offset, alloc, .. }, ty::Array(t, n)) => {
|
||||
assert_eq!(*t, tcx.types.u8);
|
||||
let n = n.eval_usize(tcx, param_env);
|
||||
let ptr = Pointer::new(AllocId(0), offset);
|
||||
alloc.get_bytes(&tcx, ptr, Size::from_bytes(n)).unwrap()
|
||||
}
|
||||
(ConstValue::Slice { data, start, end }, ty::Slice(t)) => {
|
||||
assert_eq!(*t, tcx.types.u8);
|
||||
let ptr = Pointer::new(AllocId(0), Size::from_bytes(start));
|
||||
data.get_bytes(&tcx, ptr, Size::from_bytes(end - start)).unwrap()
|
||||
}
|
||||
// FIXME(oli-obk): create a way to extract fat pointers from ByRef
|
||||
(_, ty::Slice(_)) => return Ok(false),
|
||||
_ => bug!(
|
||||
"slice_pat_covered_by_const: {:#?}, {:#?}, {:#?}, {:#?}",
|
||||
const_val,
|
||||
prefix,
|
||||
slice,
|
||||
suffix,
|
||||
),
|
||||
};
|
||||
|
||||
let pat_len = prefix.len() + suffix.len();
|
||||
if data.len() < pat_len || (slice.is_none() && data.len() > pat_len) {
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
for (ch, pat) in data[..prefix.len()]
|
||||
.iter()
|
||||
.zip(prefix)
|
||||
.chain(data[data.len() - suffix.len()..].iter().zip(suffix))
|
||||
{
|
||||
if let box PatKind::Constant { value } = pat.kind {
|
||||
let b = value.eval_bits(tcx, param_env, pat.ty);
|
||||
assert_eq!(b as u8 as u128, b);
|
||||
if b as u8 != *ch {
|
||||
return Ok(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
/// For exhaustive integer matching, some constructors are grouped within other constructors
|
||||
/// (namely integer typed values are grouped within ranges). However, when specialising these
|
||||
/// constructors, we want to be specialising for the underlying constructors (the integers), not
|
||||
|
@ -2668,35 +2497,6 @@ fn lint_overlapping_patterns<'tcx>(
|
|||
}
|
||||
}
|
||||
|
||||
fn constructor_covered_by_range<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
ctor: &Constructor<'tcx>,
|
||||
pat: &Pat<'tcx>,
|
||||
) -> Option<()> {
|
||||
if let Single = ctor {
|
||||
return Some(());
|
||||
}
|
||||
|
||||
let (pat_from, pat_to, pat_end, ty) = match *pat.kind {
|
||||
PatKind::Constant { value } => (value, value, RangeEnd::Included, value.ty),
|
||||
PatKind::Range(PatRange { lo, hi, end }) => (lo, hi, end, lo.ty),
|
||||
_ => bug!("`constructor_covered_by_range` called with {:?}", pat),
|
||||
};
|
||||
let (ctor_from, ctor_to, ctor_end) = match *ctor {
|
||||
ConstantValue(value) => (value, value, RangeEnd::Included),
|
||||
FloatRange(from, to, ctor_end) => (from, to, ctor_end),
|
||||
_ => bug!("`constructor_covered_by_range` called with {:?}", ctor),
|
||||
};
|
||||
trace!("constructor_covered_by_range {:#?}, {:#?}, {:#?}, {}", ctor, pat_from, pat_to, ty);
|
||||
|
||||
let to = compare_const_vals(tcx, ctor_to, pat_to, param_env, ty)?;
|
||||
let from = compare_const_vals(tcx, ctor_from, pat_from, param_env, ty)?;
|
||||
let intersects = (from == Ordering::Greater || from == Ordering::Equal)
|
||||
&& (to == Ordering::Less || (pat_end == ctor_end && to == Ordering::Equal));
|
||||
if intersects { Some(()) } else { None }
|
||||
}
|
||||
|
||||
/// This is the main specialization step. It expands the pattern
|
||||
/// into `arity` patterns based on the constructor. For most patterns, the step is trivial,
|
||||
/// for instance tuple patterns are flattened and box patterns expand into their inner pattern.
|
||||
|
@ -2713,15 +2513,43 @@ fn specialize_one_pattern<'p, 'tcx>(
|
|||
pat: &'p Pat<'tcx>,
|
||||
constructor: &Constructor<'tcx>,
|
||||
ctor_wild_subpatterns: &Fields<'p, 'tcx>,
|
||||
is_its_own_ctor: bool, // Whether `ctor` is known to be derived from `pat`
|
||||
) -> Option<Fields<'p, 'tcx>> {
|
||||
if let NonExhaustive = constructor {
|
||||
// Only a wildcard pattern can match the special extra constructor
|
||||
// Only a wildcard pattern can match the special extra constructor.
|
||||
if !pat.is_wildcard() {
|
||||
return None;
|
||||
}
|
||||
return Some(Fields::empty());
|
||||
}
|
||||
|
||||
if let Opaque = constructor {
|
||||
// Only a wildcard pattern can match an opaque constant, unless we're specializing the
|
||||
// value against its own constructor. That happens when we call
|
||||
// `v.specialize_constructor(ctor)` with `ctor` obtained from `pat_constructor(v.head())`.
|
||||
// For example, in the following match, when we are dealing with the third branch, we will
|
||||
// specialize with an `Opaque` ctor. We want to ignore the second branch because opaque
|
||||
// constants should not be inspected, but we don't want to ignore the current (third)
|
||||
// branch, as that would cause us to always conclude that such a branch is unreachable.
|
||||
// ```rust
|
||||
// #[derive(PartialEq)]
|
||||
// struct Foo(i32);
|
||||
// impl Eq for Foo {}
|
||||
// const FOO: Foo = Foo(42);
|
||||
//
|
||||
// match (Foo(0), true) {
|
||||
// (_, true) => {}
|
||||
// (FOO, true) => {}
|
||||
// (FOO, false) => {}
|
||||
// }
|
||||
// ```
|
||||
if is_its_own_ctor || pat.is_wildcard() {
|
||||
return Some(Fields::empty());
|
||||
} else {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
|
||||
let result = match *pat.kind {
|
||||
PatKind::AscribeUserType { .. } => bug!(), // Handled by `expand_pattern`
|
||||
|
||||
|
@ -2741,93 +2569,52 @@ fn specialize_one_pattern<'p, 'tcx>(
|
|||
|
||||
PatKind::Deref { ref subpattern } => Some(Fields::from_single_pattern(subpattern)),
|
||||
|
||||
PatKind::Constant { value } if constructor.is_slice() => {
|
||||
// We extract an `Option` for the pointer because slices of zero
|
||||
// elements don't necessarily point to memory, they are usually
|
||||
// just integers. The only time they should be pointing to memory
|
||||
// is when they are subslices of nonzero slices.
|
||||
let (alloc, offset, n, ty) = match value.ty.kind() {
|
||||
ty::Array(t, n) => {
|
||||
let n = n.eval_usize(cx.tcx, cx.param_env);
|
||||
// Shortcut for `n == 0` where no matter what `alloc` and `offset` we produce,
|
||||
// the result would be exactly what we early return here.
|
||||
if n == 0 {
|
||||
if ctor_wild_subpatterns.len() as u64 != n {
|
||||
return None;
|
||||
}
|
||||
return Some(Fields::empty());
|
||||
}
|
||||
match value.val {
|
||||
ty::ConstKind::Value(ConstValue::ByRef { offset, alloc, .. }) => {
|
||||
(Cow::Borrowed(alloc), offset, n, t)
|
||||
}
|
||||
_ => span_bug!(pat.span, "array pattern is {:?}", value,),
|
||||
}
|
||||
}
|
||||
ty::Slice(t) => {
|
||||
match value.val {
|
||||
ty::ConstKind::Value(ConstValue::Slice { data, start, end }) => {
|
||||
let offset = Size::from_bytes(start);
|
||||
let n = (end - start) as u64;
|
||||
(Cow::Borrowed(data), offset, n, t)
|
||||
}
|
||||
ty::ConstKind::Value(ConstValue::ByRef { .. }) => {
|
||||
// FIXME(oli-obk): implement `deref` for `ConstValue`
|
||||
return None;
|
||||
}
|
||||
_ => span_bug!(
|
||||
pat.span,
|
||||
"slice pattern constant must be scalar pair but is {:?}",
|
||||
value,
|
||||
),
|
||||
}
|
||||
}
|
||||
_ => span_bug!(
|
||||
pat.span,
|
||||
"unexpected const-val {:?} with ctor {:?}",
|
||||
value,
|
||||
constructor,
|
||||
),
|
||||
};
|
||||
if ctor_wild_subpatterns.len() as u64 != n {
|
||||
return None;
|
||||
}
|
||||
|
||||
// Convert a constant slice/array pattern to a list of patterns.
|
||||
let layout = cx.tcx.layout_of(cx.param_env.and(ty)).ok()?;
|
||||
let ptr = Pointer::new(AllocId(0), offset);
|
||||
let pats = cx.pattern_arena.alloc_from_iter((0..n).filter_map(|i| {
|
||||
let ptr = ptr.offset(layout.size * i, &cx.tcx).ok()?;
|
||||
let scalar = alloc.read_scalar(&cx.tcx, ptr, layout.size).ok()?;
|
||||
let scalar = scalar.check_init().ok()?;
|
||||
let value = ty::Const::from_scalar(cx.tcx, scalar, ty);
|
||||
let pattern = Pat { ty, span: pat.span, kind: box PatKind::Constant { value } };
|
||||
Some(pattern)
|
||||
}));
|
||||
// Ensure none of the dereferences failed.
|
||||
if pats.len() as u64 != n {
|
||||
return None;
|
||||
}
|
||||
Some(Fields::from_slice_unfiltered(pats))
|
||||
}
|
||||
|
||||
PatKind::Constant { .. } | PatKind::Range { .. } => {
|
||||
// If the constructor is a:
|
||||
// - Single value: add a row if the pattern contains the constructor.
|
||||
// - Range: add a row if the constructor intersects the pattern.
|
||||
if let IntRange(ctor) = constructor {
|
||||
match constructor {
|
||||
IntRange(ctor) => {
|
||||
let pat = IntRange::from_pat(cx.tcx, cx.param_env, pat)?;
|
||||
ctor.intersection(cx.tcx, &pat)?;
|
||||
// Constructor splitting should ensure that all intersections we encounter
|
||||
// are actually inclusions.
|
||||
assert!(ctor.is_subrange(&pat));
|
||||
} else {
|
||||
// Fallback for non-ranges and ranges that involve
|
||||
// floating-point numbers, which are not conveniently handled
|
||||
// by `IntRange`. For these cases, the constructor may not be a
|
||||
// range so intersection actually devolves into being covered
|
||||
// by the pattern.
|
||||
constructor_covered_by_range(cx.tcx, cx.param_env, constructor, pat)?;
|
||||
}
|
||||
FloatRange(ctor_from, ctor_to, ctor_end) => {
|
||||
let (pat_from, pat_to, pat_end, ty) = match *pat.kind {
|
||||
PatKind::Constant { value } => (value, value, RangeEnd::Included, value.ty),
|
||||
PatKind::Range(PatRange { lo, hi, end }) => (lo, hi, end, lo.ty),
|
||||
_ => unreachable!(), // This is ensured by the branch we're in
|
||||
};
|
||||
let to = compare_const_vals(cx.tcx, ctor_to, pat_to, cx.param_env, ty)?;
|
||||
let from = compare_const_vals(cx.tcx, ctor_from, pat_from, cx.param_env, ty)?;
|
||||
let intersects = (from == Ordering::Greater || from == Ordering::Equal)
|
||||
&& (to == Ordering::Less
|
||||
|| (pat_end == *ctor_end && to == Ordering::Equal));
|
||||
if !intersects {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
Str(ctor_value) => {
|
||||
let pat_value = match *pat.kind {
|
||||
PatKind::Constant { value } => value,
|
||||
_ => span_bug!(
|
||||
pat.span,
|
||||
"unexpected range pattern {:?} for constant value ctor",
|
||||
pat
|
||||
),
|
||||
};
|
||||
|
||||
// FIXME: there's probably a more direct way of comparing for equality
|
||||
if compare_const_vals(cx.tcx, ctor_value, pat_value, cx.param_env, pat.ty)?
|
||||
!= Ordering::Equal
|
||||
{
|
||||
return None;
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
// If we reach here, we must be trying to inspect an opaque constant. Thus we skip
|
||||
// the row.
|
||||
return None;
|
||||
}
|
||||
}
|
||||
Some(Fields::empty())
|
||||
}
|
||||
|
@ -2850,21 +2637,6 @@ fn specialize_one_pattern<'p, 'tcx>(
|
|||
let suffix = suffix.iter().enumerate().map(|(i, p)| (arity - suffix.len() + i, p));
|
||||
Some(ctor_wild_subpatterns.replace_fields_indexed(prefix.chain(suffix)))
|
||||
}
|
||||
ConstantValue(cv) => {
|
||||
match slice_pat_covered_by_const(
|
||||
cx.tcx,
|
||||
pat.span,
|
||||
cv,
|
||||
prefix,
|
||||
slice,
|
||||
suffix,
|
||||
cx.param_env,
|
||||
) {
|
||||
Ok(true) => Some(Fields::empty()),
|
||||
Ok(false) => None,
|
||||
Err(ErrorReported) => None,
|
||||
}
|
||||
}
|
||||
_ => span_bug!(pat.span, "unexpected ctor {:?} for slice pat", constructor),
|
||||
},
|
||||
|
||||
|
|
|
@ -137,7 +137,7 @@ impl<'tcx> MatchVisitor<'_, 'tcx> {
|
|||
patcx.include_lint_checks();
|
||||
let pattern = patcx.lower_pattern(pat);
|
||||
let pattern_ty = pattern.ty;
|
||||
let pattern: &_ = cx.pattern_arena.alloc(expand_pattern(cx, pattern));
|
||||
let pattern: &_ = cx.pattern_arena.alloc(expand_pattern(pattern));
|
||||
if !patcx.errors.is_empty() {
|
||||
*have_errors = true;
|
||||
patcx.report_inlining_errors(pat.span);
|
||||
|
|
|
@ -387,14 +387,16 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
|
|||
// `&str` and `&[u8]` are represented as `ConstValue::Slice`, let's keep using this
|
||||
// optimization for now.
|
||||
ty::Str => PatKind::Constant { value: cv },
|
||||
ty::Slice(elem_ty) if elem_ty == tcx.types.u8 => PatKind::Constant { value: cv },
|
||||
// `b"foo"` produces a `&[u8; 3]`, but you can't use constants of array type when
|
||||
// matching against references, you can only use byte string literals.
|
||||
// FIXME: clean this up, likely by permitting array patterns when matching on slices
|
||||
ty::Array(elem_ty, _) if elem_ty == tcx.types.u8 => PatKind::Constant { value: cv },
|
||||
// The typechecker has a special case for byte string literals, by treating them
|
||||
// as slices. This means we turn `&[T; N]` constants into slice patterns, which
|
||||
// has no negative effects on pattern matching, even if we're actually matching on
|
||||
// arrays.
|
||||
ty::Array(..) |
|
||||
// Cannot merge this with the catch all branch below, because the `const_deref`
|
||||
// changes the type from slice to array, and slice patterns behave differently from
|
||||
// array patterns.
|
||||
// changes the type from slice to array, we need to keep the original type in the
|
||||
// pattern.
|
||||
ty::Slice(..) => {
|
||||
let old = self.behind_reference.replace(true);
|
||||
let array = tcx.deref_const(self.param_env.and(cv));
|
||||
|
|
|
@ -158,6 +158,13 @@ crate enum PatKind<'tcx> {
|
|||
subpattern: Pat<'tcx>,
|
||||
},
|
||||
|
||||
/// One of the following:
|
||||
/// * `&str`, which will be handled as a string pattern and thus exhaustiveness
|
||||
/// checking will detect if you use the same string twice in different patterns.
|
||||
/// * integer, bool, char or float, which will be handled by exhaustivenes to cover exactly
|
||||
/// its own value, similar to `&str`, but these values are much simpler.
|
||||
/// * Opaque constants, that must not be matched structurally. So anything that does not derive
|
||||
/// `PartialEq` and `Eq`.
|
||||
Constant {
|
||||
value: &'tcx ty::Const<'tcx>,
|
||||
},
|
||||
|
|
|
@ -5,7 +5,6 @@ use crate::dep_graph::SerializedDepNodeIndex;
|
|||
use crate::query::caches::QueryCache;
|
||||
use crate::query::plumbing::CycleError;
|
||||
use crate::query::{QueryContext, QueryState};
|
||||
use rustc_data_structures::profiling::ProfileCategory;
|
||||
|
||||
use rustc_data_structures::fingerprint::Fingerprint;
|
||||
use std::borrow::Cow;
|
||||
|
@ -14,7 +13,6 @@ use std::hash::Hash;
|
|||
|
||||
pub trait QueryConfig {
|
||||
const NAME: &'static str;
|
||||
const CATEGORY: ProfileCategory;
|
||||
|
||||
type Key: Eq + Hash + Clone + Debug;
|
||||
type Value;
|
||||
|
|
|
@ -19,7 +19,7 @@ use rustc_feature::is_builtin_attr_name;
|
|||
use rustc_hir::def::{self, DefKind, NonMacroAttrKind};
|
||||
use rustc_hir::def_id;
|
||||
use rustc_middle::middle::stability;
|
||||
use rustc_middle::{span_bug, ty};
|
||||
use rustc_middle::ty;
|
||||
use rustc_session::lint::builtin::UNUSED_MACROS;
|
||||
use rustc_session::Session;
|
||||
use rustc_span::edition::Edition;
|
||||
|
@ -885,11 +885,11 @@ impl<'a> Resolver<'a> {
|
|||
initial_res: Option<Res>,
|
||||
res: Res| {
|
||||
if let Some(initial_res) = initial_res {
|
||||
if res != initial_res && res != Res::Err && this.ambiguity_errors.is_empty() {
|
||||
if res != initial_res {
|
||||
// Make sure compilation does not succeed if preferred macro resolution
|
||||
// has changed after the macro had been expanded. In theory all such
|
||||
// situations should be reported as ambiguity errors, so this is a bug.
|
||||
span_bug!(span, "inconsistent resolution for a macro");
|
||||
// situations should be reported as errors, so this is a bug.
|
||||
this.session.delay_span_bug(span, "inconsistent resolution for a macro");
|
||||
}
|
||||
} else {
|
||||
// It's possible that the macro was unresolved (indeterminate) and silently
|
||||
|
|
|
@ -777,6 +777,7 @@ symbols! {
|
|||
panic_info,
|
||||
panic_location,
|
||||
panic_runtime,
|
||||
panic_str,
|
||||
panic_unwind,
|
||||
param_attrs,
|
||||
parent_trait,
|
||||
|
|
|
@ -121,7 +121,10 @@ where
|
|||
// contains unbound type parameters. It could be a slight
|
||||
// optimization to stop iterating early.
|
||||
if let Err(errors) = fulfill_cx.select_all_or_error(infcx) {
|
||||
bug!("Encountered errors `{:?}` resolving bounds after type-checking", errors);
|
||||
infcx.tcx.sess.delay_span_bug(
|
||||
rustc_span::DUMMY_SP,
|
||||
&format!("Encountered errors `{:?}` resolving bounds after type-checking", errors),
|
||||
);
|
||||
}
|
||||
|
||||
let result = infcx.resolve_vars_if_possible(result);
|
||||
|
|
|
@ -223,11 +223,23 @@ impl AbstractConst<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
struct WorkNode<'tcx> {
|
||||
node: Node<'tcx>,
|
||||
span: Span,
|
||||
used: bool,
|
||||
}
|
||||
|
||||
struct AbstractConstBuilder<'a, 'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
body: &'a mir::Body<'tcx>,
|
||||
/// The current WIP node tree.
|
||||
nodes: IndexVec<NodeId, Node<'tcx>>,
|
||||
///
|
||||
/// We require all nodes to be used in the final abstract const,
|
||||
/// so we store this here. Note that we also consider nodes as used
|
||||
/// if they are mentioned in an assert, so some used nodes are never
|
||||
/// actually reachable by walking the [`AbstractConst`].
|
||||
nodes: IndexVec<NodeId, WorkNode<'tcx>>,
|
||||
locals: IndexVec<mir::Local, NodeId>,
|
||||
/// We only allow field accesses if they access
|
||||
/// the result of a checked operation.
|
||||
|
@ -274,6 +286,27 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
|
|||
Ok(Some(builder))
|
||||
}
|
||||
|
||||
fn add_node(&mut self, node: Node<'tcx>, span: Span) -> NodeId {
|
||||
// Mark used nodes.
|
||||
match node {
|
||||
Node::Leaf(_) => (),
|
||||
Node::Binop(_, lhs, rhs) => {
|
||||
self.nodes[lhs].used = true;
|
||||
self.nodes[rhs].used = true;
|
||||
}
|
||||
Node::UnaryOp(_, input) => {
|
||||
self.nodes[input].used = true;
|
||||
}
|
||||
Node::FunctionCall(func, nodes) => {
|
||||
self.nodes[func].used = true;
|
||||
nodes.iter().for_each(|&n| self.nodes[n].used = true);
|
||||
}
|
||||
}
|
||||
|
||||
// Nodes start as unused.
|
||||
self.nodes.push(WorkNode { node, span, used: false })
|
||||
}
|
||||
|
||||
fn place_to_local(
|
||||
&mut self,
|
||||
span: Span,
|
||||
|
@ -311,7 +344,7 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
|
|||
let local = self.place_to_local(span, p)?;
|
||||
Ok(self.locals[local])
|
||||
}
|
||||
mir::Operand::Constant(ct) => Ok(self.nodes.push(Node::Leaf(ct.literal))),
|
||||
mir::Operand::Constant(ct) => Ok(self.add_node(Node::Leaf(ct.literal), span)),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -336,19 +369,19 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
|
|||
|
||||
fn build_statement(&mut self, stmt: &mir::Statement<'tcx>) -> Result<(), ErrorReported> {
|
||||
debug!("AbstractConstBuilder: stmt={:?}", stmt);
|
||||
let span = stmt.source_info.span;
|
||||
match stmt.kind {
|
||||
StatementKind::Assign(box (ref place, ref rvalue)) => {
|
||||
let local = self.place_to_local(stmt.source_info.span, place)?;
|
||||
let local = self.place_to_local(span, place)?;
|
||||
match *rvalue {
|
||||
Rvalue::Use(ref operand) => {
|
||||
self.locals[local] =
|
||||
self.operand_to_node(stmt.source_info.span, operand)?;
|
||||
self.locals[local] = self.operand_to_node(span, operand)?;
|
||||
Ok(())
|
||||
}
|
||||
Rvalue::BinaryOp(op, ref lhs, ref rhs) if Self::check_binop(op) => {
|
||||
let lhs = self.operand_to_node(stmt.source_info.span, lhs)?;
|
||||
let rhs = self.operand_to_node(stmt.source_info.span, rhs)?;
|
||||
self.locals[local] = self.nodes.push(Node::Binop(op, lhs, rhs));
|
||||
let lhs = self.operand_to_node(span, lhs)?;
|
||||
let rhs = self.operand_to_node(span, rhs)?;
|
||||
self.locals[local] = self.add_node(Node::Binop(op, lhs, rhs), span);
|
||||
if op.is_checkable() {
|
||||
bug!("unexpected unchecked checkable binary operation");
|
||||
} else {
|
||||
|
@ -356,18 +389,18 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
Rvalue::CheckedBinaryOp(op, ref lhs, ref rhs) if Self::check_binop(op) => {
|
||||
let lhs = self.operand_to_node(stmt.source_info.span, lhs)?;
|
||||
let rhs = self.operand_to_node(stmt.source_info.span, rhs)?;
|
||||
self.locals[local] = self.nodes.push(Node::Binop(op, lhs, rhs));
|
||||
let lhs = self.operand_to_node(span, lhs)?;
|
||||
let rhs = self.operand_to_node(span, rhs)?;
|
||||
self.locals[local] = self.add_node(Node::Binop(op, lhs, rhs), span);
|
||||
self.checked_op_locals.insert(local);
|
||||
Ok(())
|
||||
}
|
||||
Rvalue::UnaryOp(op, ref operand) if Self::check_unop(op) => {
|
||||
let operand = self.operand_to_node(stmt.source_info.span, operand)?;
|
||||
self.locals[local] = self.nodes.push(Node::UnaryOp(op, operand));
|
||||
let operand = self.operand_to_node(span, operand)?;
|
||||
self.locals[local] = self.add_node(Node::UnaryOp(op, operand), span);
|
||||
Ok(())
|
||||
}
|
||||
_ => self.error(Some(stmt.source_info.span), "unsupported rvalue")?,
|
||||
_ => self.error(Some(span), "unsupported rvalue")?,
|
||||
}
|
||||
}
|
||||
// These are not actually relevant for us here, so we can ignore them.
|
||||
|
@ -415,13 +448,9 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
|
|||
.map(|arg| self.operand_to_node(terminator.source_info.span, arg))
|
||||
.collect::<Result<Vec<NodeId>, _>>()?,
|
||||
);
|
||||
self.locals[local] = self.nodes.push(Node::FunctionCall(func, args));
|
||||
self.locals[local] = self.add_node(Node::FunctionCall(func, args), fn_span);
|
||||
Ok(Some(target))
|
||||
}
|
||||
// We only allow asserts for checked operations.
|
||||
//
|
||||
// These asserts seem to all have the form `!_local.0` so
|
||||
// we only allow exactly that.
|
||||
TerminatorKind::Assert { ref cond, expected: false, target, .. } => {
|
||||
let p = match cond {
|
||||
mir::Operand::Copy(p) | mir::Operand::Move(p) => p,
|
||||
|
@ -430,7 +459,15 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
|
|||
|
||||
const ONE_FIELD: mir::Field = mir::Field::from_usize(1);
|
||||
debug!("proj: {:?}", p.projection);
|
||||
if let &[mir::ProjectionElem::Field(ONE_FIELD, _)] = p.projection.as_ref() {
|
||||
if let Some(p) = p.as_local() {
|
||||
debug_assert!(!self.checked_op_locals.contains(p));
|
||||
// Mark locals directly used in asserts as used.
|
||||
//
|
||||
// This is needed because division does not use `CheckedBinop` but instead
|
||||
// adds an explicit assert for `divisor != 0`.
|
||||
self.nodes[self.locals[p]].used = true;
|
||||
return Ok(Some(target));
|
||||
} else if let &[mir::ProjectionElem::Field(ONE_FIELD, _)] = p.projection.as_ref() {
|
||||
// Only allow asserts checking the result of a checked operation.
|
||||
if self.checked_op_locals.contains(p.local) {
|
||||
return Ok(Some(target));
|
||||
|
@ -457,7 +494,13 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
|
|||
if let Some(next) = self.build_terminator(block.terminator())? {
|
||||
block = &self.body.basic_blocks()[next];
|
||||
} else {
|
||||
return Ok(self.tcx.arena.alloc_from_iter(self.nodes));
|
||||
assert_eq!(self.locals[mir::RETURN_PLACE], self.nodes.last().unwrap());
|
||||
self.nodes[self.locals[mir::RETURN_PLACE]].used = true;
|
||||
if let Some(&unused) = self.nodes.iter().find(|n| !n.used) {
|
||||
self.error(Some(unused.span), "dead code")?;
|
||||
}
|
||||
|
||||
return Ok(self.tcx.arena.alloc_from_iter(self.nodes.into_iter().map(|n| n.node)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -372,7 +372,7 @@ pub fn handle_alloc_error(layout: Layout) -> ! {
|
|||
unsafe { oom_impl(layout) }
|
||||
}
|
||||
|
||||
#[cfg(not(any(test, bootstrap)))]
|
||||
#[cfg(not(any(target_os = "hermit", test, bootstrap)))]
|
||||
#[doc(hidden)]
|
||||
#[allow(unused_attributes)]
|
||||
#[unstable(feature = "alloc_internals", issue = "none")]
|
||||
|
|
|
@ -1280,7 +1280,7 @@ where
|
|||
#[inline]
|
||||
fn find<T, B>(
|
||||
f: &mut impl FnMut(T) -> Option<B>,
|
||||
) -> impl FnMut((), T) -> ControlFlow<(), B> + '_ {
|
||||
) -> impl FnMut((), T) -> ControlFlow<B> + '_ {
|
||||
move |(), x| match f(x) {
|
||||
Some(x) => ControlFlow::Break(x),
|
||||
None => ControlFlow::CONTINUE,
|
||||
|
@ -2059,7 +2059,7 @@ where
|
|||
flag: &'a mut bool,
|
||||
p: &'a mut impl FnMut(&T) -> bool,
|
||||
mut fold: impl FnMut(Acc, T) -> R + 'a,
|
||||
) -> impl FnMut(Acc, T) -> ControlFlow<Acc, R> + 'a {
|
||||
) -> impl FnMut(Acc, T) -> ControlFlow<R, Acc> + 'a {
|
||||
move |acc, x| {
|
||||
if p(&x) {
|
||||
ControlFlow::from_try(fold(acc, x))
|
||||
|
@ -2372,7 +2372,7 @@ where
|
|||
fn check<T, Acc, R: Try<Ok = Acc>>(
|
||||
mut n: usize,
|
||||
mut fold: impl FnMut(Acc, T) -> R,
|
||||
) -> impl FnMut(Acc, T) -> ControlFlow<Acc, R> {
|
||||
) -> impl FnMut(Acc, T) -> ControlFlow<R, Acc> {
|
||||
move |acc, x| {
|
||||
n -= 1;
|
||||
let r = fold(acc, x);
|
||||
|
@ -2496,7 +2496,7 @@ where
|
|||
fn check<'a, T, Acc, R: Try<Ok = Acc>>(
|
||||
n: &'a mut usize,
|
||||
mut fold: impl FnMut(Acc, T) -> R + 'a,
|
||||
) -> impl FnMut(Acc, T) -> ControlFlow<Acc, R> + 'a {
|
||||
) -> impl FnMut(Acc, T) -> ControlFlow<R, Acc> + 'a {
|
||||
move |acc, x| {
|
||||
*n -= 1;
|
||||
let r = fold(acc, x);
|
||||
|
@ -2681,7 +2681,7 @@ where
|
|||
state: &'a mut St,
|
||||
f: &'a mut impl FnMut(&mut St, T) -> Option<B>,
|
||||
mut fold: impl FnMut(Acc, B) -> R + 'a,
|
||||
) -> impl FnMut(Acc, T) -> ControlFlow<Acc, R> + 'a {
|
||||
) -> impl FnMut(Acc, T) -> ControlFlow<R, Acc> + 'a {
|
||||
move |acc, x| match f(state, x) {
|
||||
None => ControlFlow::Break(try { acc }),
|
||||
Some(x) => ControlFlow::from_try(fold(acc, x)),
|
||||
|
|
|
@ -339,9 +339,7 @@ pub trait DoubleEndedIterator: Iterator {
|
|||
P: FnMut(&Self::Item) -> bool,
|
||||
{
|
||||
#[inline]
|
||||
fn check<T>(
|
||||
mut predicate: impl FnMut(&T) -> bool,
|
||||
) -> impl FnMut((), T) -> ControlFlow<(), T> {
|
||||
fn check<T>(mut predicate: impl FnMut(&T) -> bool) -> impl FnMut((), T) -> ControlFlow<T> {
|
||||
move |(), x| {
|
||||
if predicate(&x) { ControlFlow::Break(x) } else { ControlFlow::CONTINUE }
|
||||
}
|
||||
|
|
|
@ -2109,7 +2109,7 @@ pub trait Iterator {
|
|||
F: FnMut(Self::Item) -> bool,
|
||||
{
|
||||
#[inline]
|
||||
fn check<T>(mut f: impl FnMut(T) -> bool) -> impl FnMut((), T) -> ControlFlow<(), ()> {
|
||||
fn check<T>(mut f: impl FnMut(T) -> bool) -> impl FnMut((), T) -> ControlFlow<()> {
|
||||
move |(), x| {
|
||||
if f(x) { ControlFlow::CONTINUE } else { ControlFlow::BREAK }
|
||||
}
|
||||
|
@ -2162,7 +2162,7 @@ pub trait Iterator {
|
|||
F: FnMut(Self::Item) -> bool,
|
||||
{
|
||||
#[inline]
|
||||
fn check<T>(mut f: impl FnMut(T) -> bool) -> impl FnMut((), T) -> ControlFlow<(), ()> {
|
||||
fn check<T>(mut f: impl FnMut(T) -> bool) -> impl FnMut((), T) -> ControlFlow<()> {
|
||||
move |(), x| {
|
||||
if f(x) { ControlFlow::BREAK } else { ControlFlow::CONTINUE }
|
||||
}
|
||||
|
@ -2222,9 +2222,7 @@ pub trait Iterator {
|
|||
P: FnMut(&Self::Item) -> bool,
|
||||
{
|
||||
#[inline]
|
||||
fn check<T>(
|
||||
mut predicate: impl FnMut(&T) -> bool,
|
||||
) -> impl FnMut((), T) -> ControlFlow<(), T> {
|
||||
fn check<T>(mut predicate: impl FnMut(&T) -> bool) -> impl FnMut((), T) -> ControlFlow<T> {
|
||||
move |(), x| {
|
||||
if predicate(&x) { ControlFlow::Break(x) } else { ControlFlow::CONTINUE }
|
||||
}
|
||||
|
@ -2255,9 +2253,7 @@ pub trait Iterator {
|
|||
F: FnMut(Self::Item) -> Option<B>,
|
||||
{
|
||||
#[inline]
|
||||
fn check<T, B>(
|
||||
mut f: impl FnMut(T) -> Option<B>,
|
||||
) -> impl FnMut((), T) -> ControlFlow<(), B> {
|
||||
fn check<T, B>(mut f: impl FnMut(T) -> Option<B>) -> impl FnMut((), T) -> ControlFlow<B> {
|
||||
move |(), x| match f(x) {
|
||||
Some(x) => ControlFlow::Break(x),
|
||||
None => ControlFlow::CONTINUE,
|
||||
|
@ -2296,7 +2292,7 @@ pub trait Iterator {
|
|||
R: Try<Ok = bool>,
|
||||
{
|
||||
#[inline]
|
||||
fn check<F, T, R>(mut f: F) -> impl FnMut((), T) -> ControlFlow<(), Result<T, R::Error>>
|
||||
fn check<F, T, R>(mut f: F) -> impl FnMut((), T) -> ControlFlow<Result<T, R::Error>>
|
||||
where
|
||||
F: FnMut(&T) -> R,
|
||||
R: Try<Ok = bool>,
|
||||
|
|
|
@ -10,7 +10,7 @@ macro_rules! panic {
|
|||
$crate::panicking::panic($msg)
|
||||
);
|
||||
($msg:expr) => (
|
||||
$crate::panic!("{}", $crate::convert::identity::<&str>($msg))
|
||||
$crate::panicking::panic_str($msg)
|
||||
);
|
||||
($msg:expr,) => (
|
||||
$crate::panic!($msg)
|
||||
|
|
|
@ -3,7 +3,7 @@ use crate::ops::Try;
|
|||
/// Used to make try_fold closures more like normal loops
|
||||
#[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
pub enum ControlFlow<C, B> {
|
||||
pub enum ControlFlow<B, C = ()> {
|
||||
/// Continue in the loop, using the given value for the next iteration
|
||||
Continue(C),
|
||||
/// Exit the loop, yielding the given value
|
||||
|
@ -11,7 +11,7 @@ pub enum ControlFlow<C, B> {
|
|||
}
|
||||
|
||||
#[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
|
||||
impl<C, B> Try for ControlFlow<C, B> {
|
||||
impl<B, C> Try for ControlFlow<B, C> {
|
||||
type Ok = C;
|
||||
type Error = B;
|
||||
#[inline]
|
||||
|
@ -31,7 +31,7 @@ impl<C, B> Try for ControlFlow<C, B> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<C, B> ControlFlow<C, B> {
|
||||
impl<B, C> ControlFlow<B, C> {
|
||||
/// Returns `true` if this is a `Break` variant.
|
||||
#[inline]
|
||||
#[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
|
||||
|
@ -58,7 +58,7 @@ impl<C, B> ControlFlow<C, B> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<R: Try> ControlFlow<R::Ok, R> {
|
||||
impl<R: Try> ControlFlow<R, R::Ok> {
|
||||
/// Create a `ControlFlow` from any type implementing `Try`.
|
||||
#[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
|
||||
#[inline]
|
||||
|
@ -80,7 +80,7 @@ impl<R: Try> ControlFlow<R::Ok, R> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<B> ControlFlow<(), B> {
|
||||
impl<B> ControlFlow<B, ()> {
|
||||
/// It's frequently the case that there's no value needed with `Continue`,
|
||||
/// so this provides a way to avoid typing `(())`, if you prefer it.
|
||||
///
|
||||
|
@ -102,7 +102,7 @@ impl<B> ControlFlow<(), B> {
|
|||
pub const CONTINUE: Self = ControlFlow::Continue(());
|
||||
}
|
||||
|
||||
impl<C> ControlFlow<C, ()> {
|
||||
impl<C> ControlFlow<(), C> {
|
||||
/// APIs like `try_for_each` don't need values with `Break`,
|
||||
/// so this provides a way to avoid typing `(())`, if you prefer it.
|
||||
///
|
||||
|
|
|
@ -50,6 +50,13 @@ pub fn panic(expr: &'static str) -> ! {
|
|||
panic_fmt(fmt::Arguments::new_v1(&[expr], &[]));
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[track_caller]
|
||||
#[cfg_attr(not(bootstrap), lang = "panic_str")] // needed for const-evaluated panics
|
||||
pub fn panic_str(expr: &str) -> ! {
|
||||
panic_fmt(format_args!("{}", expr));
|
||||
}
|
||||
|
||||
#[cold]
|
||||
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
|
||||
#[track_caller]
|
||||
|
|
|
@ -42,7 +42,7 @@ dlmalloc = { version = "0.1", features = ['rustc-dep-of-std'] }
|
|||
fortanix-sgx-abi = { version = "0.3.2", features = ['rustc-dep-of-std'] }
|
||||
|
||||
[target.'cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_os = "hermit"))'.dependencies]
|
||||
hermit-abi = { version = "0.1.15", features = ['rustc-dep-of-std'] }
|
||||
hermit-abi = { version = "0.1.17", features = ['rustc-dep-of-std'] }
|
||||
|
||||
[target.wasm32-wasi.dependencies]
|
||||
wasi = { version = "0.9.0", features = ['rustc-dep-of-std'], default-features = false }
|
||||
|
|
|
@ -259,6 +259,7 @@
|
|||
#![feature(exhaustive_patterns)]
|
||||
#![feature(extend_one)]
|
||||
#![feature(external_doc)]
|
||||
#![feature(fmt_as_str)]
|
||||
#![feature(fn_traits)]
|
||||
#![feature(format_args_nl)]
|
||||
#![feature(gen_future)]
|
||||
|
|
|
@ -478,10 +478,26 @@ pub fn begin_panic_handler(info: &PanicInfo<'_>) -> ! {
|
|||
}
|
||||
}
|
||||
|
||||
struct StrPanicPayload(&'static str);
|
||||
|
||||
unsafe impl BoxMeUp for StrPanicPayload {
|
||||
fn take_box(&mut self) -> *mut (dyn Any + Send) {
|
||||
Box::into_raw(Box::new(self.0))
|
||||
}
|
||||
|
||||
fn get(&mut self) -> &(dyn Any + Send) {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
let loc = info.location().unwrap(); // The current implementation always returns Some
|
||||
let msg = info.message().unwrap(); // The current implementation always returns Some
|
||||
crate::sys_common::backtrace::__rust_end_short_backtrace(move || {
|
||||
if let Some(msg) = msg.as_str() {
|
||||
rust_panic_with_hook(&mut StrPanicPayload(msg), info.message(), loc);
|
||||
} else {
|
||||
rust_panic_with_hook(&mut PanicPayload::new(msg), info.message(), loc);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -1910,7 +1910,7 @@ extern "C" {
|
|||
/// The resolution of the clock.
|
||||
#[inline]
|
||||
pub unsafe fn clock_res_get(clock_id_: clockid, resolution_: &mut timestamp) -> errno {
|
||||
cloudabi_sys_clock_res_get(clock_id_, resolution_)
|
||||
unsafe { cloudabi_sys_clock_res_get(clock_id_, resolution_) }
|
||||
}
|
||||
|
||||
/// Obtains the time value of a clock.
|
||||
|
@ -1934,7 +1934,7 @@ pub unsafe fn clock_time_get(
|
|||
precision_: timestamp,
|
||||
time_: *mut timestamp,
|
||||
) -> errno {
|
||||
cloudabi_sys_clock_time_get(clock_id_, precision_, time_)
|
||||
unsafe { cloudabi_sys_clock_time_get(clock_id_, precision_, time_) }
|
||||
}
|
||||
|
||||
/// Wakes up threads waiting on a userspace condition variable.
|
||||
|
@ -1961,7 +1961,7 @@ pub unsafe fn clock_time_get(
|
|||
/// threads, all threads are woken up.
|
||||
#[inline]
|
||||
pub unsafe fn condvar_signal(condvar_: *mut condvar, scope_: scope, nwaiters_: nthreads) -> errno {
|
||||
cloudabi_sys_condvar_signal(condvar_, scope_, nwaiters_)
|
||||
unsafe { cloudabi_sys_condvar_signal(condvar_, scope_, nwaiters_) }
|
||||
}
|
||||
|
||||
/// Closes a file descriptor.
|
||||
|
@ -1972,7 +1972,7 @@ pub unsafe fn condvar_signal(condvar_: *mut condvar, scope_: scope, nwaiters_: n
|
|||
/// The file descriptor that needs to be closed.
|
||||
#[inline]
|
||||
pub unsafe fn fd_close(fd_: fd) -> errno {
|
||||
cloudabi_sys_fd_close(fd_)
|
||||
unsafe { cloudabi_sys_fd_close(fd_) }
|
||||
}
|
||||
|
||||
/// Creates a file descriptor.
|
||||
|
@ -1990,7 +1990,7 @@ pub unsafe fn fd_close(fd_: fd) -> errno {
|
|||
/// The file descriptor that has been created.
|
||||
#[inline]
|
||||
pub unsafe fn fd_create1(type_: filetype, fd_: &mut fd) -> errno {
|
||||
cloudabi_sys_fd_create1(type_, fd_)
|
||||
unsafe { cloudabi_sys_fd_create1(type_, fd_) }
|
||||
}
|
||||
|
||||
/// Creates a pair of file descriptors.
|
||||
|
@ -2013,7 +2013,8 @@ pub unsafe fn fd_create1(type_: filetype, fd_: &mut fd) -> errno {
|
|||
/// The second file descriptor of the pair.
|
||||
#[inline]
|
||||
pub unsafe fn fd_create2(type_: filetype, fd1_: &mut fd, fd2_: &mut fd) -> errno {
|
||||
cloudabi_sys_fd_create2(type_, fd1_, fd2_)
|
||||
// SAFETY: the caller must uphold the safety contract for `cloudabi_sys_fd_create2`.
|
||||
unsafe { cloudabi_sys_fd_create2(type_, fd1_, fd2_) }
|
||||
}
|
||||
|
||||
/// Synchronizes the data of a file to disk.
|
||||
|
@ -2025,7 +2026,9 @@ pub unsafe fn fd_create2(type_: filetype, fd1_: &mut fd, fd2_: &mut fd) -> errno
|
|||
/// needs to be synchronized to disk.
|
||||
#[inline]
|
||||
pub unsafe fn fd_datasync(fd_: fd) -> errno {
|
||||
cloudabi_sys_fd_datasync(fd_)
|
||||
// SAFETY: the caller must guarantee that `fd` is valid
|
||||
// for synchronization.
|
||||
unsafe { cloudabi_sys_fd_datasync(fd_) }
|
||||
}
|
||||
|
||||
/// Duplicates a file descriptor.
|
||||
|
@ -2040,7 +2043,7 @@ pub unsafe fn fd_datasync(fd_: fd) -> errno {
|
|||
/// The new file descriptor.
|
||||
#[inline]
|
||||
pub unsafe fn fd_dup(from_: fd, fd_: &mut fd) -> errno {
|
||||
cloudabi_sys_fd_dup(from_, fd_)
|
||||
unsafe { cloudabi_sys_fd_dup(from_, fd_) }
|
||||
}
|
||||
|
||||
/// Reads from a file descriptor, without using and updating the
|
||||
|
@ -2064,7 +2067,7 @@ pub unsafe fn fd_dup(from_: fd, fd_: &mut fd) -> errno {
|
|||
/// The number of bytes read.
|
||||
#[inline]
|
||||
pub unsafe fn fd_pread(fd_: fd, iovs_: &[iovec], offset_: filesize, nread_: &mut usize) -> errno {
|
||||
cloudabi_sys_fd_pread(fd_, iovs_.as_ptr(), iovs_.len(), offset_, nread_)
|
||||
unsafe { cloudabi_sys_fd_pread(fd_, iovs_.as_ptr(), iovs_.len(), offset_, nread_) }
|
||||
}
|
||||
|
||||
/// Writes to a file descriptor, without using and updating the
|
||||
|
@ -2093,7 +2096,7 @@ pub unsafe fn fd_pwrite(
|
|||
offset_: filesize,
|
||||
nwritten_: &mut usize,
|
||||
) -> errno {
|
||||
cloudabi_sys_fd_pwrite(fd_, iovs_.as_ptr(), iovs_.len(), offset_, nwritten_)
|
||||
unsafe { cloudabi_sys_fd_pwrite(fd_, iovs_.as_ptr(), iovs_.len(), offset_, nwritten_) }
|
||||
}
|
||||
|
||||
/// Reads from a file descriptor.
|
||||
|
@ -2112,7 +2115,7 @@ pub unsafe fn fd_pwrite(
|
|||
/// The number of bytes read.
|
||||
#[inline]
|
||||
pub unsafe fn fd_read(fd_: fd, iovs_: &[iovec], nread_: &mut usize) -> errno {
|
||||
cloudabi_sys_fd_read(fd_, iovs_.as_ptr(), iovs_.len(), nread_)
|
||||
unsafe { cloudabi_sys_fd_read(fd_, iovs_.as_ptr(), iovs_.len(), nread_) }
|
||||
}
|
||||
|
||||
/// Atomically replaces a file descriptor by a copy of another
|
||||
|
@ -2138,7 +2141,7 @@ pub unsafe fn fd_read(fd_: fd, iovs_: &[iovec], nread_: &mut usize) -> errno {
|
|||
/// overwritten.
|
||||
#[inline]
|
||||
pub unsafe fn fd_replace(from_: fd, to_: fd) -> errno {
|
||||
cloudabi_sys_fd_replace(from_, to_)
|
||||
unsafe { cloudabi_sys_fd_replace(from_, to_) }
|
||||
}
|
||||
|
||||
/// Moves the offset of the file descriptor.
|
||||
|
@ -2166,7 +2169,7 @@ pub unsafe fn fd_seek(
|
|||
whence_: whence,
|
||||
newoffset_: &mut filesize,
|
||||
) -> errno {
|
||||
cloudabi_sys_fd_seek(fd_, offset_, whence_, newoffset_)
|
||||
unsafe { cloudabi_sys_fd_seek(fd_, offset_, whence_, newoffset_) }
|
||||
}
|
||||
|
||||
/// Gets attributes of a file descriptor.
|
||||
|
@ -2182,7 +2185,7 @@ pub unsafe fn fd_seek(
|
|||
/// attributes are stored.
|
||||
#[inline]
|
||||
pub unsafe fn fd_stat_get(fd_: fd, buf_: *mut fdstat) -> errno {
|
||||
cloudabi_sys_fd_stat_get(fd_, buf_)
|
||||
unsafe { cloudabi_sys_fd_stat_get(fd_, buf_) }
|
||||
}
|
||||
|
||||
/// Adjusts attributes of a file descriptor.
|
||||
|
@ -2202,7 +2205,7 @@ pub unsafe fn fd_stat_get(fd_: fd, buf_: *mut fdstat) -> errno {
|
|||
/// be adjusted.
|
||||
#[inline]
|
||||
pub unsafe fn fd_stat_put(fd_: fd, buf_: *const fdstat, flags_: fdsflags) -> errno {
|
||||
cloudabi_sys_fd_stat_put(fd_, buf_, flags_)
|
||||
unsafe { cloudabi_sys_fd_stat_put(fd_, buf_, flags_) }
|
||||
}
|
||||
|
||||
/// Synchronizes the data and metadata of a file to disk.
|
||||
|
@ -2214,7 +2217,7 @@ pub unsafe fn fd_stat_put(fd_: fd, buf_: *const fdstat, flags_: fdsflags) -> err
|
|||
/// and metadata needs to be synchronized to disk.
|
||||
#[inline]
|
||||
pub unsafe fn fd_sync(fd_: fd) -> errno {
|
||||
cloudabi_sys_fd_sync(fd_)
|
||||
unsafe { cloudabi_sys_fd_sync(fd_) }
|
||||
}
|
||||
|
||||
/// Writes to a file descriptor.
|
||||
|
@ -2233,7 +2236,7 @@ pub unsafe fn fd_sync(fd_: fd) -> errno {
|
|||
/// The number of bytes written.
|
||||
#[inline]
|
||||
pub unsafe fn fd_write(fd_: fd, iovs_: &[ciovec], nwritten_: &mut usize) -> errno {
|
||||
cloudabi_sys_fd_write(fd_, iovs_.as_ptr(), iovs_.len(), nwritten_)
|
||||
unsafe { cloudabi_sys_fd_write(fd_, iovs_.as_ptr(), iovs_.len(), nwritten_) }
|
||||
}
|
||||
|
||||
/// Provides file advisory information on a file descriptor.
|
||||
|
@ -2256,7 +2259,7 @@ pub unsafe fn fd_write(fd_: fd, iovs_: &[ciovec], nwritten_: &mut usize) -> errn
|
|||
/// The advice.
|
||||
#[inline]
|
||||
pub unsafe fn file_advise(fd_: fd, offset_: filesize, len_: filesize, advice_: advice) -> errno {
|
||||
cloudabi_sys_file_advise(fd_, offset_, len_, advice_)
|
||||
unsafe { cloudabi_sys_file_advise(fd_, offset_, len_, advice_) }
|
||||
}
|
||||
|
||||
/// Forces the allocation of space in a file.
|
||||
|
@ -2275,7 +2278,7 @@ pub unsafe fn file_advise(fd_: fd, offset_: filesize, len_: filesize, advice_: a
|
|||
/// The length of the area that is allocated.
|
||||
#[inline]
|
||||
pub unsafe fn file_allocate(fd_: fd, offset_: filesize, len_: filesize) -> errno {
|
||||
cloudabi_sys_file_allocate(fd_, offset_, len_)
|
||||
unsafe { cloudabi_sys_file_allocate(fd_, offset_, len_) }
|
||||
}
|
||||
|
||||
/// Creates a file of a specified type.
|
||||
|
@ -2296,7 +2299,7 @@ pub unsafe fn file_allocate(fd_: fd, offset_: filesize, len_: filesize) -> errno
|
|||
/// Creates a directory.
|
||||
#[inline]
|
||||
pub unsafe fn file_create(fd_: fd, path_: &[u8], type_: filetype) -> errno {
|
||||
cloudabi_sys_file_create(fd_, path_.as_ptr(), path_.len(), type_)
|
||||
unsafe { cloudabi_sys_file_create(fd_, path_.as_ptr(), path_.len(), type_)}
|
||||
}
|
||||
|
||||
/// Creates a hard link.
|
||||
|
@ -2320,7 +2323,7 @@ pub unsafe fn file_create(fd_: fd, path_: &[u8], type_: filetype) -> errno {
|
|||
/// should be created.
|
||||
#[inline]
|
||||
pub unsafe fn file_link(fd1_: lookup, path1_: &[u8], fd2_: fd, path2_: &[u8]) -> errno {
|
||||
cloudabi_sys_file_link(fd1_, path1_.as_ptr(), path1_.len(), fd2_, path2_.as_ptr(), path2_.len())
|
||||
unsafe { cloudabi_sys_file_link(fd1_, path1_.as_ptr(), path1_.len(), fd2_, path2_.as_ptr(), path2_.len()) }
|
||||
}
|
||||
|
||||
/// Opens a file.
|
||||
|
@ -2362,7 +2365,7 @@ pub unsafe fn file_open(
|
|||
fds_: *const fdstat,
|
||||
fd_: &mut fd,
|
||||
) -> errno {
|
||||
cloudabi_sys_file_open(dirfd_, path_.as_ptr(), path_.len(), oflags_, fds_, fd_)
|
||||
unsafe { cloudabi_sys_file_open(dirfd_, path_.as_ptr(), path_.len(), oflags_, fds_, fd_) }
|
||||
}
|
||||
|
||||
/// Reads directory entries from a directory.
|
||||
|
@ -2402,7 +2405,7 @@ pub unsafe fn file_readdir(
|
|||
cookie_: dircookie,
|
||||
bufused_: &mut usize,
|
||||
) -> errno {
|
||||
cloudabi_sys_file_readdir(fd_, buf_.as_mut_ptr() as *mut (), buf_.len(), cookie_, bufused_)
|
||||
unsafe { cloudabi_sys_file_readdir(fd_, buf_.as_mut_ptr() as *mut (), buf_.len(), cookie_, bufused_) }
|
||||
}
|
||||
|
||||
/// Reads the contents of a symbolic link.
|
||||
|
@ -2425,6 +2428,7 @@ pub unsafe fn file_readdir(
|
|||
/// The number of bytes placed in the buffer.
|
||||
#[inline]
|
||||
pub unsafe fn file_readlink(fd_: fd, path_: &[u8], buf_: &mut [u8], bufused_: &mut usize) -> errno {
|
||||
unsafe {
|
||||
cloudabi_sys_file_readlink(
|
||||
fd_,
|
||||
path_.as_ptr(),
|
||||
|
@ -2434,6 +2438,7 @@ pub unsafe fn file_readlink(fd_: fd, path_: &[u8], buf_: &mut [u8], bufused_: &m
|
|||
bufused_,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// Renames a file.
|
||||
///
|
||||
|
@ -2456,6 +2461,7 @@ pub unsafe fn file_readlink(fd_: fd, path_: &[u8], buf_: &mut [u8], bufused_: &m
|
|||
/// be renamed.
|
||||
#[inline]
|
||||
pub unsafe fn file_rename(fd1_: fd, path1_: &[u8], fd2_: fd, path2_: &[u8]) -> errno {
|
||||
unsafe {
|
||||
cloudabi_sys_file_rename(
|
||||
fd1_,
|
||||
path1_.as_ptr(),
|
||||
|
@ -2465,6 +2471,7 @@ pub unsafe fn file_rename(fd1_: fd, path1_: &[u8], fd2_: fd, path2_: &[u8]) -> e
|
|||
path2_.len(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// Gets attributes of a file by file descriptor.
|
||||
///
|
||||
|
@ -2479,7 +2486,7 @@ pub unsafe fn file_rename(fd1_: fd, path1_: &[u8], fd2_: fd, path2_: &[u8]) -> e
|
|||
/// stored.
|
||||
#[inline]
|
||||
pub unsafe fn file_stat_fget(fd_: fd, buf_: *mut filestat) -> errno {
|
||||
cloudabi_sys_file_stat_fget(fd_, buf_)
|
||||
unsafe { cloudabi_sys_file_stat_fget(fd_, buf_) }
|
||||
}
|
||||
|
||||
/// Adjusts attributes of a file by file descriptor.
|
||||
|
@ -2499,7 +2506,7 @@ pub unsafe fn file_stat_fget(fd_: fd, buf_: *mut filestat) -> errno {
|
|||
/// be adjusted.
|
||||
#[inline]
|
||||
pub unsafe fn file_stat_fput(fd_: fd, buf_: *const filestat, flags_: fsflags) -> errno {
|
||||
cloudabi_sys_file_stat_fput(fd_, buf_, flags_)
|
||||
unsafe { cloudabi_sys_file_stat_fput(fd_, buf_, flags_) }
|
||||
}
|
||||
|
||||
/// Gets attributes of a file by path.
|
||||
|
@ -2520,7 +2527,7 @@ pub unsafe fn file_stat_fput(fd_: fd, buf_: *const filestat, flags_: fsflags) ->
|
|||
/// stored.
|
||||
#[inline]
|
||||
pub unsafe fn file_stat_get(fd_: lookup, path_: &[u8], buf_: *mut filestat) -> errno {
|
||||
cloudabi_sys_file_stat_get(fd_, path_.as_ptr(), path_.len(), buf_)
|
||||
unsafe { cloudabi_sys_file_stat_get(fd_, path_.as_ptr(), path_.len(), buf_) }
|
||||
}
|
||||
|
||||
/// Adjusts attributes of a file by path.
|
||||
|
@ -2550,7 +2557,7 @@ pub unsafe fn file_stat_put(
|
|||
buf_: *const filestat,
|
||||
flags_: fsflags,
|
||||
) -> errno {
|
||||
cloudabi_sys_file_stat_put(fd_, path_.as_ptr(), path_.len(), buf_, flags_)
|
||||
unsafe { cloudabi_sys_file_stat_put(fd_, path_.as_ptr(), path_.len(), buf_, flags_) }
|
||||
}
|
||||
|
||||
/// Creates a symbolic link.
|
||||
|
@ -2569,7 +2576,7 @@ pub unsafe fn file_stat_put(
|
|||
/// link should be created.
|
||||
#[inline]
|
||||
pub unsafe fn file_symlink(path1_: &[u8], fd_: fd, path2_: &[u8]) -> errno {
|
||||
cloudabi_sys_file_symlink(path1_.as_ptr(), path1_.len(), fd_, path2_.as_ptr(), path2_.len())
|
||||
unsafe { cloudabi_sys_file_symlink(path1_.as_ptr(), path1_.len(), fd_, path2_.as_ptr(), path2_.len()) }
|
||||
}
|
||||
|
||||
/// Unlinks a file, or removes a directory.
|
||||
|
@ -2591,7 +2598,7 @@ pub unsafe fn file_symlink(path1_: &[u8], fd_: fd, path2_: &[u8]) -> errno {
|
|||
/// Otherwise, unlink a file.
|
||||
#[inline]
|
||||
pub unsafe fn file_unlink(fd_: fd, path_: &[u8], flags_: ulflags) -> errno {
|
||||
cloudabi_sys_file_unlink(fd_, path_.as_ptr(), path_.len(), flags_)
|
||||
unsafe { cloudabi_sys_file_unlink(fd_, path_.as_ptr(), path_.len(), flags_) }
|
||||
}
|
||||
|
||||
/// Unlocks a write-locked userspace lock.
|
||||
|
@ -2618,7 +2625,7 @@ pub unsafe fn file_unlink(fd_: fd, path_: &[u8], flags_: ulflags) -> errno {
|
|||
/// shared memory.
|
||||
#[inline]
|
||||
pub unsafe fn lock_unlock(lock_: *mut lock, scope_: scope) -> errno {
|
||||
cloudabi_sys_lock_unlock(lock_, scope_)
|
||||
unsafe { cloudabi_sys_lock_unlock(lock_, scope_) }
|
||||
}
|
||||
|
||||
/// Provides memory advisory information on a region of memory.
|
||||
|
@ -2633,7 +2640,7 @@ pub unsafe fn lock_unlock(lock_: *mut lock, scope_: scope) -> errno {
|
|||
/// The advice.
|
||||
#[inline]
|
||||
pub unsafe fn mem_advise(mapping_: &mut [u8], advice_: advice) -> errno {
|
||||
cloudabi_sys_mem_advise(mapping_.as_mut_ptr() as *mut (), mapping_.len(), advice_)
|
||||
unsafe { cloudabi_sys_mem_advise(mapping_.as_mut_ptr() as *mut (), mapping_.len(), advice_) }
|
||||
}
|
||||
|
||||
/// Creates a memory mapping, making the contents of a file
|
||||
|
@ -2682,7 +2689,7 @@ pub unsafe fn mem_map(
|
|||
off_: filesize,
|
||||
mem_: &mut *mut (),
|
||||
) -> errno {
|
||||
cloudabi_sys_mem_map(addr_, len_, prot_, flags_, fd_, off_, mem_)
|
||||
unsafe { cloudabi_sys_mem_map(addr_, len_, prot_, flags_, fd_, off_, mem_) }
|
||||
}
|
||||
|
||||
/// Changes the protection of a memory mapping.
|
||||
|
@ -2696,7 +2703,7 @@ pub unsafe fn mem_map(
|
|||
/// New protection options.
|
||||
#[inline]
|
||||
pub unsafe fn mem_protect(mapping_: &mut [u8], prot_: mprot) -> errno {
|
||||
cloudabi_sys_mem_protect(mapping_.as_mut_ptr() as *mut (), mapping_.len(), prot_)
|
||||
unsafe { cloudabi_sys_mem_protect(mapping_.as_mut_ptr() as *mut (), mapping_.len(), prot_) }
|
||||
}
|
||||
|
||||
/// Synchronizes a region of memory with its physical storage.
|
||||
|
@ -2710,7 +2717,7 @@ pub unsafe fn mem_protect(mapping_: &mut [u8], prot_: mprot) -> errno {
|
|||
/// The method of synchronization.
|
||||
#[inline]
|
||||
pub unsafe fn mem_sync(mapping_: &mut [u8], flags_: msflags) -> errno {
|
||||
cloudabi_sys_mem_sync(mapping_.as_mut_ptr() as *mut (), mapping_.len(), flags_)
|
||||
unsafe { cloudabi_sys_mem_sync(mapping_.as_mut_ptr() as *mut (), mapping_.len(), flags_) }
|
||||
}
|
||||
|
||||
/// Unmaps a region of memory.
|
||||
|
@ -2721,7 +2728,7 @@ pub unsafe fn mem_sync(mapping_: &mut [u8], flags_: msflags) -> errno {
|
|||
/// The pages that needs to be unmapped.
|
||||
#[inline]
|
||||
pub unsafe fn mem_unmap(mapping_: &mut [u8]) -> errno {
|
||||
cloudabi_sys_mem_unmap(mapping_.as_mut_ptr() as *mut (), mapping_.len())
|
||||
unsafe { cloudabi_sys_mem_unmap(mapping_.as_mut_ptr() as *mut (), mapping_.len()) }
|
||||
}
|
||||
|
||||
/// Concurrently polls for the occurrence of a set of events.
|
||||
|
@ -2746,7 +2753,7 @@ pub unsafe fn poll(
|
|||
nsubscriptions_: usize,
|
||||
nevents_: *mut usize,
|
||||
) -> errno {
|
||||
cloudabi_sys_poll(in_, out_, nsubscriptions_, nevents_)
|
||||
unsafe { cloudabi_sys_poll(in_, out_, nsubscriptions_, nevents_) }
|
||||
}
|
||||
|
||||
/// Replaces the process by a new executable.
|
||||
|
@ -2784,7 +2791,7 @@ pub unsafe fn poll(
|
|||
/// execution.
|
||||
#[inline]
|
||||
pub unsafe fn proc_exec(fd_: fd, data_: &[u8], fds_: &[fd]) -> errno {
|
||||
cloudabi_sys_proc_exec(fd_, data_.as_ptr() as *const (), data_.len(), fds_.as_ptr(), fds_.len())
|
||||
unsafe { cloudabi_sys_proc_exec(fd_, data_.as_ptr() as *const (), data_.len(), fds_.as_ptr(), fds_.len()) }
|
||||
}
|
||||
|
||||
/// Terminates the process normally.
|
||||
|
@ -2797,7 +2804,7 @@ pub unsafe fn proc_exec(fd_: fd, data_: &[u8], fds_: &[fd]) -> errno {
|
|||
/// through [`event.union.proc_terminate.exitcode`](struct.event_proc_terminate.html#structfield.exitcode).
|
||||
#[inline]
|
||||
pub unsafe fn proc_exit(rval_: exitcode) -> ! {
|
||||
cloudabi_sys_proc_exit(rval_)
|
||||
unsafe { cloudabi_sys_proc_exit(rval_) }
|
||||
}
|
||||
|
||||
/// Forks the process of the calling thread.
|
||||
|
@ -2822,7 +2829,7 @@ pub unsafe fn proc_exit(rval_: exitcode) -> ! {
|
|||
/// initial thread of the child process.
|
||||
#[inline]
|
||||
pub unsafe fn proc_fork(fd_: &mut fd, tid_: &mut tid) -> errno {
|
||||
cloudabi_sys_proc_fork(fd_, tid_)
|
||||
unsafe { cloudabi_sys_proc_fork(fd_, tid_) }
|
||||
}
|
||||
|
||||
/// Sends a signal to the process of the calling thread.
|
||||
|
@ -2837,7 +2844,7 @@ pub unsafe fn proc_fork(fd_: &mut fd, tid_: &mut tid) -> errno {
|
|||
/// [`event.union.proc_terminate.signal`](struct.event_proc_terminate.html#structfield.signal).
|
||||
#[inline]
|
||||
pub unsafe fn proc_raise(sig_: signal) -> errno {
|
||||
cloudabi_sys_proc_raise(sig_)
|
||||
unsafe { cloudabi_sys_proc_raise(sig_) }
|
||||
}
|
||||
|
||||
/// Obtains random data from the kernel random number generator.
|
||||
|
@ -2853,7 +2860,7 @@ pub unsafe fn proc_raise(sig_: signal) -> errno {
|
|||
/// data.
|
||||
#[inline]
|
||||
pub unsafe fn random_get(buf_: &mut [u8]) -> errno {
|
||||
cloudabi_sys_random_get(buf_.as_mut_ptr() as *mut (), buf_.len())
|
||||
unsafe { cloudabi_sys_random_get(buf_.as_mut_ptr() as *mut (), buf_.len()) }
|
||||
}
|
||||
|
||||
/// Receives a message on a socket.
|
||||
|
@ -2871,7 +2878,7 @@ pub unsafe fn random_get(buf_: &mut [u8]) -> errno {
|
|||
/// Output parameters.
|
||||
#[inline]
|
||||
pub unsafe fn sock_recv(sock_: fd, in_: *const recv_in, out_: *mut recv_out) -> errno {
|
||||
cloudabi_sys_sock_recv(sock_, in_, out_)
|
||||
unsafe { cloudabi_sys_sock_recv(sock_, in_, out_) }
|
||||
}
|
||||
|
||||
/// Sends a message on a socket.
|
||||
|
@ -2888,7 +2895,7 @@ pub unsafe fn sock_recv(sock_: fd, in_: *const recv_in, out_: *mut recv_out) ->
|
|||
/// Output parameters.
|
||||
#[inline]
|
||||
pub unsafe fn sock_send(sock_: fd, in_: *const send_in, out_: *mut send_out) -> errno {
|
||||
cloudabi_sys_sock_send(sock_, in_, out_)
|
||||
unsafe { cloudabi_sys_sock_send(sock_, in_, out_) }
|
||||
}
|
||||
|
||||
/// Shuts down socket send and receive channels.
|
||||
|
@ -2903,7 +2910,7 @@ pub unsafe fn sock_send(sock_: fd, in_: *const send_in, out_: *mut send_out) ->
|
|||
/// down.
|
||||
#[inline]
|
||||
pub unsafe fn sock_shutdown(sock_: fd, how_: sdflags) -> errno {
|
||||
cloudabi_sys_sock_shutdown(sock_, how_)
|
||||
unsafe { cloudabi_sys_sock_shutdown(sock_, how_) }
|
||||
}
|
||||
|
||||
/// Creates a new thread within the current process.
|
||||
|
@ -2917,7 +2924,7 @@ pub unsafe fn sock_shutdown(sock_: fd, how_: sdflags) -> errno {
|
|||
/// The thread ID of the new thread.
|
||||
#[inline]
|
||||
pub unsafe fn thread_create(attr_: *mut threadattr, tid_: &mut tid) -> errno {
|
||||
cloudabi_sys_thread_create(attr_, tid_)
|
||||
unsafe { cloudabi_sys_thread_create(attr_, tid_) }
|
||||
}
|
||||
|
||||
/// Terminates the calling thread.
|
||||
|
@ -2937,11 +2944,11 @@ pub unsafe fn thread_create(attr_: *mut threadattr, tid_: &mut tid) -> errno {
|
|||
/// shared memory.
|
||||
#[inline]
|
||||
pub unsafe fn thread_exit(lock_: *mut lock, scope_: scope) -> ! {
|
||||
cloudabi_sys_thread_exit(lock_, scope_)
|
||||
unsafe { cloudabi_sys_thread_exit(lock_, scope_) }
|
||||
}
|
||||
|
||||
/// Temporarily yields execution of the calling thread.
|
||||
#[inline]
|
||||
pub unsafe fn thread_yield() -> errno {
|
||||
cloudabi_sys_thread_yield()
|
||||
unsafe { cloudabi_sys_thread_yield() }
|
||||
}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#![deny(unsafe_op_in_unsafe_fn)]
|
||||
|
||||
use crate::io::ErrorKind;
|
||||
use crate::mem;
|
||||
|
||||
|
|
|
@ -103,7 +103,9 @@ impl ReentrantMutex {
|
|||
};
|
||||
let mut event = MaybeUninit::<abi::event>::uninit();
|
||||
let mut nevents = MaybeUninit::<usize>::uninit();
|
||||
let ret = abi::poll(&subscription, event.as_mut_ptr(), 1, nevents.as_mut_ptr());
|
||||
// SAFE: The caller must to ensure that `event` and `nevents` are initialized.
|
||||
let ret =
|
||||
unsafe { abi::poll(&subscription, event.as_mut_ptr(), 1, nevents.as_mut_ptr()) };
|
||||
assert_eq!(ret, abi::errno::SUCCESS, "Failed to acquire mutex");
|
||||
let event = event.assume_init();
|
||||
assert_eq!(event.error, abi::errno::SUCCESS, "Failed to acquire mutex");
|
||||
|
|
|
@ -334,10 +334,6 @@ impl File {
|
|||
pub fn set_permissions(&self, _perm: FilePermissions) -> io::Result<()> {
|
||||
Err(Error::from_raw_os_error(22))
|
||||
}
|
||||
|
||||
pub fn diverge(&self) -> ! {
|
||||
loop {}
|
||||
}
|
||||
}
|
||||
|
||||
impl DirBuilder {
|
||||
|
|
|
@ -31,6 +31,7 @@ pub mod net;
|
|||
pub mod os;
|
||||
pub mod path;
|
||||
pub mod pipe;
|
||||
#[path = "../unsupported/process.rs"]
|
||||
pub mod process;
|
||||
pub mod rwlock;
|
||||
pub mod stack_overflow;
|
||||
|
|
|
@ -1,44 +1,214 @@
|
|||
use crate::cell::UnsafeCell;
|
||||
use crate::collections::VecDeque;
|
||||
use crate::ffi::c_void;
|
||||
use crate::ops::{Deref, DerefMut, Drop};
|
||||
use crate::ptr;
|
||||
use crate::sync::atomic::{spin_loop_hint, AtomicUsize, Ordering};
|
||||
use crate::sys::hermit::abi;
|
||||
|
||||
pub struct Mutex {
|
||||
inner: *const c_void,
|
||||
/// This type provides a lock based on busy waiting to realize mutual exclusion
|
||||
///
|
||||
/// # Description
|
||||
///
|
||||
/// This structure behaves a lot like a common mutex. There are some differences:
|
||||
///
|
||||
/// - By using busy waiting, it can be used outside the runtime.
|
||||
/// - It is a so called ticket lock and is completly fair.
|
||||
#[cfg_attr(target_arch = "x86_64", repr(align(128)))]
|
||||
#[cfg_attr(not(target_arch = "x86_64"), repr(align(64)))]
|
||||
struct Spinlock<T: ?Sized> {
|
||||
queue: AtomicUsize,
|
||||
dequeue: AtomicUsize,
|
||||
data: UnsafeCell<T>,
|
||||
}
|
||||
|
||||
unsafe impl<T: ?Sized + Send> Sync for Spinlock<T> {}
|
||||
unsafe impl<T: ?Sized + Send> Send for Spinlock<T> {}
|
||||
|
||||
/// A guard to which the protected data can be accessed
|
||||
///
|
||||
/// When the guard falls out of scope it will release the lock.
|
||||
struct SpinlockGuard<'a, T: ?Sized + 'a> {
|
||||
dequeue: &'a AtomicUsize,
|
||||
data: &'a mut T,
|
||||
}
|
||||
|
||||
impl<T> Spinlock<T> {
|
||||
pub const fn new(user_data: T) -> Spinlock<T> {
|
||||
Spinlock {
|
||||
queue: AtomicUsize::new(0),
|
||||
dequeue: AtomicUsize::new(1),
|
||||
data: UnsafeCell::new(user_data),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn obtain_lock(&self) {
|
||||
let ticket = self.queue.fetch_add(1, Ordering::SeqCst) + 1;
|
||||
while self.dequeue.load(Ordering::SeqCst) != ticket {
|
||||
spin_loop_hint();
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn lock(&self) -> SpinlockGuard<'_, T> {
|
||||
self.obtain_lock();
|
||||
SpinlockGuard { dequeue: &self.dequeue, data: &mut *self.data.get() }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ?Sized + Default> Default for Spinlock<T> {
|
||||
fn default() -> Spinlock<T> {
|
||||
Spinlock::new(Default::default())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: ?Sized> Deref for SpinlockGuard<'a, T> {
|
||||
type Target = T;
|
||||
fn deref(&self) -> &T {
|
||||
&*self.data
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: ?Sized> DerefMut for SpinlockGuard<'a, T> {
|
||||
fn deref_mut(&mut self) -> &mut T {
|
||||
&mut *self.data
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: ?Sized> Drop for SpinlockGuard<'a, T> {
|
||||
/// The dropping of the SpinlockGuard will release the lock it was created from.
|
||||
fn drop(&mut self) {
|
||||
self.dequeue.fetch_add(1, Ordering::SeqCst);
|
||||
}
|
||||
}
|
||||
|
||||
/// Realize a priority queue for tasks
|
||||
struct PriorityQueue {
|
||||
queues: [Option<VecDeque<abi::Tid>>; abi::NO_PRIORITIES],
|
||||
prio_bitmap: u64,
|
||||
}
|
||||
|
||||
impl PriorityQueue {
|
||||
pub const fn new() -> PriorityQueue {
|
||||
PriorityQueue {
|
||||
queues: [
|
||||
None, None, None, None, None, None, None, None, None, None, None, None, None, None,
|
||||
None, None, None, None, None, None, None, None, None, None, None, None, None, None,
|
||||
None, None, None,
|
||||
],
|
||||
prio_bitmap: 0,
|
||||
}
|
||||
}
|
||||
|
||||
/// Add a task id by its priority to the queue
|
||||
pub fn push(&mut self, prio: abi::Priority, id: abi::Tid) {
|
||||
let i: usize = prio.into().into();
|
||||
self.prio_bitmap |= (1 << i) as u64;
|
||||
if let Some(queue) = &mut self.queues[i] {
|
||||
queue.push_back(id);
|
||||
} else {
|
||||
let mut queue = VecDeque::new();
|
||||
queue.push_back(id);
|
||||
self.queues[i] = Some(queue);
|
||||
}
|
||||
}
|
||||
|
||||
fn pop_from_queue(&mut self, queue_index: usize) -> Option<abi::Tid> {
|
||||
if let Some(queue) = &mut self.queues[queue_index] {
|
||||
let id = queue.pop_front();
|
||||
|
||||
if queue.is_empty() {
|
||||
self.prio_bitmap &= !(1 << queue_index as u64);
|
||||
}
|
||||
|
||||
id
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Pop the task handle with the highest priority from the queue
|
||||
pub fn pop(&mut self) -> Option<abi::Tid> {
|
||||
for i in 0..abi::NO_PRIORITIES {
|
||||
if self.prio_bitmap & (1 << i) != 0 {
|
||||
return self.pop_from_queue(i);
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
struct MutexInner {
|
||||
locked: bool,
|
||||
blocked_task: PriorityQueue,
|
||||
}
|
||||
|
||||
impl MutexInner {
|
||||
pub const fn new() -> MutexInner {
|
||||
MutexInner { locked: false, blocked_task: PriorityQueue::new() }
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Mutex {
|
||||
inner: Spinlock<MutexInner>,
|
||||
}
|
||||
|
||||
pub type MovableMutex = Box<Mutex>;
|
||||
|
||||
unsafe impl Send for Mutex {}
|
||||
unsafe impl Sync for Mutex {}
|
||||
|
||||
impl Mutex {
|
||||
pub const fn new() -> Mutex {
|
||||
Mutex { inner: ptr::null() }
|
||||
Mutex { inner: Spinlock::new(MutexInner::new()) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn init(&mut self) {
|
||||
let _ = abi::sem_init(&mut self.inner as *mut *const c_void, 1);
|
||||
self.inner = Spinlock::new(MutexInner::new());
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn lock(&self) {
|
||||
let _ = abi::sem_timedwait(self.inner, 0);
|
||||
loop {
|
||||
let mut guard = self.inner.lock();
|
||||
if guard.locked == false {
|
||||
guard.locked = true;
|
||||
return;
|
||||
} else {
|
||||
let prio = abi::get_priority();
|
||||
let id = abi::getpid();
|
||||
|
||||
guard.blocked_task.push(prio, id);
|
||||
abi::block_current_task();
|
||||
drop(guard);
|
||||
abi::yield_now();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn unlock(&self) {
|
||||
let _ = abi::sem_post(self.inner);
|
||||
let mut guard = self.inner.lock();
|
||||
guard.locked = false;
|
||||
if let Some(tid) = guard.blocked_task.pop() {
|
||||
abi::wakeup_task(tid);
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn try_lock(&self) -> bool {
|
||||
let result = abi::sem_trywait(self.inner);
|
||||
result == 0
|
||||
let mut guard = self.inner.lock();
|
||||
if guard.locked == false {
|
||||
guard.locked = true;
|
||||
}
|
||||
guard.locked
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn destroy(&self) {
|
||||
let _ = abi::sem_destroy(self.inner);
|
||||
}
|
||||
pub unsafe fn destroy(&self) {}
|
||||
}
|
||||
|
||||
pub struct ReentrantMutex {
|
||||
|
|
|
@ -1,149 +0,0 @@
|
|||
use crate::ffi::OsStr;
|
||||
use crate::fmt;
|
||||
use crate::io;
|
||||
use crate::sys::fs::File;
|
||||
use crate::sys::pipe::AnonPipe;
|
||||
use crate::sys::{unsupported, Void};
|
||||
use crate::sys_common::process::CommandEnv;
|
||||
|
||||
pub use crate::ffi::OsString as EnvKey;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Command
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
pub struct Command {
|
||||
env: CommandEnv,
|
||||
}
|
||||
|
||||
// passed back to std::process with the pipes connected to the child, if any
|
||||
// were requested
|
||||
pub struct StdioPipes {
|
||||
pub stdin: Option<AnonPipe>,
|
||||
pub stdout: Option<AnonPipe>,
|
||||
pub stderr: Option<AnonPipe>,
|
||||
}
|
||||
|
||||
pub enum Stdio {
|
||||
Inherit,
|
||||
Null,
|
||||
MakePipe,
|
||||
}
|
||||
|
||||
impl Command {
|
||||
pub fn new(_program: &OsStr) -> Command {
|
||||
Command { env: Default::default() }
|
||||
}
|
||||
|
||||
pub fn arg(&mut self, _arg: &OsStr) {}
|
||||
|
||||
pub fn env_mut(&mut self) -> &mut CommandEnv {
|
||||
&mut self.env
|
||||
}
|
||||
|
||||
pub fn cwd(&mut self, _dir: &OsStr) {}
|
||||
|
||||
pub fn stdin(&mut self, _stdin: Stdio) {}
|
||||
|
||||
pub fn stdout(&mut self, _stdout: Stdio) {}
|
||||
|
||||
pub fn stderr(&mut self, _stderr: Stdio) {}
|
||||
|
||||
pub fn spawn(
|
||||
&mut self,
|
||||
_default: Stdio,
|
||||
_needs_stdin: bool,
|
||||
) -> io::Result<(Process, StdioPipes)> {
|
||||
unsupported()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<AnonPipe> for Stdio {
|
||||
fn from(pipe: AnonPipe) -> Stdio {
|
||||
pipe.diverge()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<File> for Stdio {
|
||||
fn from(file: File) -> Stdio {
|
||||
file.diverge()
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Command {
|
||||
fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ExitStatus(Void);
|
||||
|
||||
impl ExitStatus {
|
||||
pub fn success(&self) -> bool {
|
||||
match self.0 {}
|
||||
}
|
||||
|
||||
pub fn code(&self) -> Option<i32> {
|
||||
match self.0 {}
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for ExitStatus {
|
||||
fn clone(&self) -> ExitStatus {
|
||||
match self.0 {}
|
||||
}
|
||||
}
|
||||
|
||||
impl Copy for ExitStatus {}
|
||||
|
||||
impl PartialEq for ExitStatus {
|
||||
fn eq(&self, _other: &ExitStatus) -> bool {
|
||||
match self.0 {}
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for ExitStatus {}
|
||||
|
||||
impl fmt::Debug for ExitStatus {
|
||||
fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self.0 {}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for ExitStatus {
|
||||
fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self.0 {}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
|
||||
pub struct ExitCode(bool);
|
||||
|
||||
impl ExitCode {
|
||||
pub const SUCCESS: ExitCode = ExitCode(false);
|
||||
pub const FAILURE: ExitCode = ExitCode(true);
|
||||
|
||||
pub fn as_i32(&self) -> i32 {
|
||||
self.0 as i32
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Process(Void);
|
||||
|
||||
impl Process {
|
||||
pub fn id(&self) -> u32 {
|
||||
match self.0 {}
|
||||
}
|
||||
|
||||
pub fn kill(&mut self) -> io::Result<()> {
|
||||
match self.0 {}
|
||||
}
|
||||
|
||||
pub fn wait(&mut self) -> io::Result<ExitStatus> {
|
||||
match self.0 {}
|
||||
}
|
||||
|
||||
pub fn try_wait(&mut self) -> io::Result<Option<ExitStatus>> {
|
||||
match self.0 {}
|
||||
}
|
||||
}
|
|
@ -89,6 +89,7 @@ cfg_if::cfg_if! {
|
|||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub use self::ext as windows_ext;
|
||||
} else if #[cfg(any(target_os = "cloudabi",
|
||||
target_os = "hermit",
|
||||
target_arch = "wasm32",
|
||||
all(target_vendor = "fortanix", target_env = "sgx")))] {
|
||||
// On CloudABI and wasm right now the shim below doesn't compile, so
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
let mut _8: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:35:9: 35:10
|
||||
let mut _9: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:35:12: 35:13
|
||||
let mut _10: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:35:15: 35:16
|
||||
+ let mut _11: i32; // in scope 0 at $DIR/matches_reduce_branches.rs:19:9: 19:10
|
||||
scope 1 {
|
||||
debug a => _2; // in scope 1 at $DIR/matches_reduce_branches.rs:13:9: 13:10
|
||||
let _3: bool; // in scope 1 at $DIR/matches_reduce_branches.rs:14:9: 14:10
|
||||
|
@ -33,10 +34,13 @@
|
|||
StorageLive(_5); // scope 3 at $DIR/matches_reduce_branches.rs:16:9: 16:10
|
||||
StorageLive(_6); // scope 4 at $DIR/matches_reduce_branches.rs:18:5: 33:6
|
||||
- switchInt(_1) -> [7_i32: bb2, otherwise: bb1]; // scope 4 at $DIR/matches_reduce_branches.rs:19:9: 19:10
|
||||
+ _2 = Ne(_1, const 7_i32); // scope 4 at $DIR/matches_reduce_branches.rs:20:13: 20:22
|
||||
+ _3 = Eq(_1, const 7_i32); // scope 4 at $DIR/matches_reduce_branches.rs:21:13: 21:21
|
||||
+ StorageLive(_11); // scope 4 at $DIR/matches_reduce_branches.rs:19:9: 19:10
|
||||
+ _11 = _1; // scope 4 at $DIR/matches_reduce_branches.rs:19:9: 19:10
|
||||
+ _2 = Ne(_11, const 7_i32); // scope 4 at $DIR/matches_reduce_branches.rs:20:13: 20:22
|
||||
+ _3 = Eq(_11, const 7_i32); // scope 4 at $DIR/matches_reduce_branches.rs:21:13: 21:21
|
||||
+ _4 = const false; // scope 4 at $DIR/matches_reduce_branches.rs:22:13: 22:22
|
||||
+ _5 = const true; // scope 4 at $DIR/matches_reduce_branches.rs:23:13: 23:21
|
||||
+ StorageDead(_11); // scope 4 at $DIR/matches_reduce_branches.rs:19:9: 19:10
|
||||
+ goto -> bb3; // scope 4 at $DIR/matches_reduce_branches.rs:19:9: 19:10
|
||||
}
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
let mut _8: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:35:9: 35:10
|
||||
let mut _9: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:35:12: 35:13
|
||||
let mut _10: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:35:15: 35:16
|
||||
+ let mut _11: i32; // in scope 0 at $DIR/matches_reduce_branches.rs:19:9: 19:10
|
||||
scope 1 {
|
||||
debug a => _2; // in scope 1 at $DIR/matches_reduce_branches.rs:13:9: 13:10
|
||||
let _3: bool; // in scope 1 at $DIR/matches_reduce_branches.rs:14:9: 14:10
|
||||
|
@ -33,10 +34,13 @@
|
|||
StorageLive(_5); // scope 3 at $DIR/matches_reduce_branches.rs:16:9: 16:10
|
||||
StorageLive(_6); // scope 4 at $DIR/matches_reduce_branches.rs:18:5: 33:6
|
||||
- switchInt(_1) -> [7_i32: bb2, otherwise: bb1]; // scope 4 at $DIR/matches_reduce_branches.rs:19:9: 19:10
|
||||
+ _2 = Ne(_1, const 7_i32); // scope 4 at $DIR/matches_reduce_branches.rs:20:13: 20:22
|
||||
+ _3 = Eq(_1, const 7_i32); // scope 4 at $DIR/matches_reduce_branches.rs:21:13: 21:21
|
||||
+ StorageLive(_11); // scope 4 at $DIR/matches_reduce_branches.rs:19:9: 19:10
|
||||
+ _11 = _1; // scope 4 at $DIR/matches_reduce_branches.rs:19:9: 19:10
|
||||
+ _2 = Ne(_11, const 7_i32); // scope 4 at $DIR/matches_reduce_branches.rs:20:13: 20:22
|
||||
+ _3 = Eq(_11, const 7_i32); // scope 4 at $DIR/matches_reduce_branches.rs:21:13: 21:21
|
||||
+ _4 = const false; // scope 4 at $DIR/matches_reduce_branches.rs:22:13: 22:22
|
||||
+ _5 = const true; // scope 4 at $DIR/matches_reduce_branches.rs:23:13: 23:21
|
||||
+ StorageDead(_11); // scope 4 at $DIR/matches_reduce_branches.rs:19:9: 19:10
|
||||
+ goto -> bb3; // scope 4 at $DIR/matches_reduce_branches.rs:19:9: 19:10
|
||||
}
|
||||
|
||||
|
|
|
@ -6,12 +6,16 @@
|
|||
let mut _0: (); // return place in scope 0 at $DIR/matches_reduce_branches.rs:6:25: 6:25
|
||||
let mut _2: bool; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
|
||||
let mut _3: isize; // in scope 0 at $DIR/matches_reduce_branches.rs:7:22: 7:26
|
||||
+ let mut _4: isize; // in scope 0 at $DIR/matches_reduce_branches.rs:7:22: 7:26
|
||||
|
||||
bb0: {
|
||||
StorageLive(_2); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
|
||||
_3 = discriminant(_1); // scope 0 at $DIR/matches_reduce_branches.rs:7:22: 7:26
|
||||
- switchInt(move _3) -> [0_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/matches_reduce_branches.rs:7:22: 7:26
|
||||
+ _2 = Eq(_3, const 0_isize); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
|
||||
+ StorageLive(_4); // scope 0 at $DIR/matches_reduce_branches.rs:7:22: 7:26
|
||||
+ _4 = move _3; // scope 0 at $DIR/matches_reduce_branches.rs:7:22: 7:26
|
||||
+ _2 = Eq(_4, const 0_isize); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
|
||||
+ StorageDead(_4); // scope 0 at $DIR/matches_reduce_branches.rs:7:22: 7:26
|
||||
+ goto -> bb3; // scope 0 at $DIR/matches_reduce_branches.rs:7:22: 7:26
|
||||
}
|
||||
|
||||
|
|
|
@ -6,12 +6,16 @@
|
|||
let mut _0: (); // return place in scope 0 at $DIR/matches_reduce_branches.rs:6:25: 6:25
|
||||
let mut _2: bool; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
|
||||
let mut _3: isize; // in scope 0 at $DIR/matches_reduce_branches.rs:7:22: 7:26
|
||||
+ let mut _4: isize; // in scope 0 at $DIR/matches_reduce_branches.rs:7:22: 7:26
|
||||
|
||||
bb0: {
|
||||
StorageLive(_2); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
|
||||
_3 = discriminant(_1); // scope 0 at $DIR/matches_reduce_branches.rs:7:22: 7:26
|
||||
- switchInt(move _3) -> [0_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/matches_reduce_branches.rs:7:22: 7:26
|
||||
+ _2 = Eq(_3, const 0_isize); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
|
||||
+ StorageLive(_4); // scope 0 at $DIR/matches_reduce_branches.rs:7:22: 7:26
|
||||
+ _4 = move _3; // scope 0 at $DIR/matches_reduce_branches.rs:7:22: 7:26
|
||||
+ _2 = Eq(_4, const 0_isize); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
|
||||
+ StorageDead(_4); // scope 0 at $DIR/matches_reduce_branches.rs:7:22: 7:26
|
||||
+ goto -> bb3; // scope 0 at $DIR/matches_reduce_branches.rs:7:22: 7:26
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,116 @@
|
|||
- // MIR for `match_nested_if` before MatchBranchSimplification
|
||||
+ // MIR for `match_nested_if` after MatchBranchSimplification
|
||||
|
||||
fn match_nested_if() -> bool {
|
||||
let mut _0: bool; // return place in scope 0 at $DIR/matches_reduce_branches.rs:38:25: 38:29
|
||||
let _1: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:39:9: 39:12
|
||||
let mut _2: (); // in scope 0 at $DIR/matches_reduce_branches.rs:39:21: 39:23
|
||||
let mut _3: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:40:15: 40:88
|
||||
let mut _4: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:40:18: 40:68
|
||||
let mut _5: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:40:21: 40:48
|
||||
let mut _6: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:40:24: 40:28
|
||||
+ let mut _7: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:40:21: 40:48
|
||||
+ let mut _8: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:40:18: 40:68
|
||||
+ let mut _9: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:40:15: 40:88
|
||||
+ let mut _10: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:40:15: 40:88
|
||||
scope 1 {
|
||||
debug val => _1; // in scope 1 at $DIR/matches_reduce_branches.rs:39:9: 39:12
|
||||
}
|
||||
|
||||
bb0: {
|
||||
StorageLive(_1); // scope 0 at $DIR/matches_reduce_branches.rs:39:9: 39:12
|
||||
StorageLive(_2); // scope 0 at $DIR/matches_reduce_branches.rs:39:21: 39:23
|
||||
StorageLive(_3); // scope 0 at $DIR/matches_reduce_branches.rs:40:15: 40:88
|
||||
StorageLive(_4); // scope 0 at $DIR/matches_reduce_branches.rs:40:18: 40:68
|
||||
StorageLive(_5); // scope 0 at $DIR/matches_reduce_branches.rs:40:21: 40:48
|
||||
StorageLive(_6); // scope 0 at $DIR/matches_reduce_branches.rs:40:24: 40:28
|
||||
_6 = const true; // scope 0 at $DIR/matches_reduce_branches.rs:40:24: 40:28
|
||||
- switchInt(_6) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/matches_reduce_branches.rs:40:21: 40:48
|
||||
+ StorageLive(_7); // scope 0 at $DIR/matches_reduce_branches.rs:40:21: 40:48
|
||||
+ _7 = _6; // scope 0 at $DIR/matches_reduce_branches.rs:40:21: 40:48
|
||||
+ _5 = Ne(_7, const false); // scope 0 at $DIR/matches_reduce_branches.rs:40:42: 40:47
|
||||
+ StorageDead(_7); // scope 0 at $DIR/matches_reduce_branches.rs:40:21: 40:48
|
||||
+ goto -> bb3; // scope 0 at $DIR/matches_reduce_branches.rs:40:21: 40:48
|
||||
}
|
||||
|
||||
bb1: {
|
||||
_5 = const true; // scope 0 at $DIR/matches_reduce_branches.rs:40:30: 40:34
|
||||
goto -> bb3; // scope 0 at $DIR/matches_reduce_branches.rs:40:21: 40:48
|
||||
}
|
||||
|
||||
bb2: {
|
||||
_5 = const false; // scope 0 at $DIR/matches_reduce_branches.rs:40:42: 40:47
|
||||
goto -> bb3; // scope 0 at $DIR/matches_reduce_branches.rs:40:21: 40:48
|
||||
}
|
||||
|
||||
bb3: {
|
||||
StorageDead(_6); // scope 0 at $DIR/matches_reduce_branches.rs:40:47: 40:48
|
||||
- switchInt(_5) -> [false: bb4, otherwise: bb5]; // scope 0 at $DIR/matches_reduce_branches.rs:40:18: 40:68
|
||||
+ StorageLive(_8); // scope 0 at $DIR/matches_reduce_branches.rs:40:18: 40:68
|
||||
+ _8 = _5; // scope 0 at $DIR/matches_reduce_branches.rs:40:18: 40:68
|
||||
+ _4 = Ne(_8, const false); // scope 0 at $DIR/matches_reduce_branches.rs:40:62: 40:67
|
||||
+ StorageDead(_8); // scope 0 at $DIR/matches_reduce_branches.rs:40:18: 40:68
|
||||
+ goto -> bb6; // scope 0 at $DIR/matches_reduce_branches.rs:40:18: 40:68
|
||||
}
|
||||
|
||||
bb4: {
|
||||
_4 = const false; // scope 0 at $DIR/matches_reduce_branches.rs:40:62: 40:67
|
||||
goto -> bb6; // scope 0 at $DIR/matches_reduce_branches.rs:40:18: 40:68
|
||||
}
|
||||
|
||||
bb5: {
|
||||
_4 = const true; // scope 0 at $DIR/matches_reduce_branches.rs:40:50: 40:54
|
||||
goto -> bb6; // scope 0 at $DIR/matches_reduce_branches.rs:40:18: 40:68
|
||||
}
|
||||
|
||||
bb6: {
|
||||
StorageDead(_5); // scope 0 at $DIR/matches_reduce_branches.rs:40:67: 40:68
|
||||
- switchInt(_4) -> [false: bb7, otherwise: bb8]; // scope 0 at $DIR/matches_reduce_branches.rs:40:15: 40:88
|
||||
+ StorageLive(_9); // scope 0 at $DIR/matches_reduce_branches.rs:40:15: 40:88
|
||||
+ _9 = _4; // scope 0 at $DIR/matches_reduce_branches.rs:40:15: 40:88
|
||||
+ _3 = Ne(_9, const false); // scope 0 at $DIR/matches_reduce_branches.rs:40:82: 40:87
|
||||
+ StorageDead(_9); // scope 0 at $DIR/matches_reduce_branches.rs:40:15: 40:88
|
||||
+ goto -> bb9; // scope 0 at $DIR/matches_reduce_branches.rs:40:15: 40:88
|
||||
}
|
||||
|
||||
bb7: {
|
||||
_3 = const false; // scope 0 at $DIR/matches_reduce_branches.rs:40:82: 40:87
|
||||
goto -> bb9; // scope 0 at $DIR/matches_reduce_branches.rs:40:15: 40:88
|
||||
}
|
||||
|
||||
bb8: {
|
||||
_3 = const true; // scope 0 at $DIR/matches_reduce_branches.rs:40:70: 40:74
|
||||
goto -> bb9; // scope 0 at $DIR/matches_reduce_branches.rs:40:15: 40:88
|
||||
}
|
||||
|
||||
bb9: {
|
||||
StorageDead(_4); // scope 0 at $DIR/matches_reduce_branches.rs:40:87: 40:88
|
||||
- switchInt(move _3) -> [false: bb11, otherwise: bb10]; // scope 0 at $DIR/matches_reduce_branches.rs:40:15: 40:88
|
||||
+ StorageLive(_10); // scope 0 at $DIR/matches_reduce_branches.rs:40:15: 40:88
|
||||
+ _10 = move _3; // scope 0 at $DIR/matches_reduce_branches.rs:40:15: 40:88
|
||||
+ StorageDead(_3); // scope 0 at $DIR/matches_reduce_branches.rs:40:95: 40:96
|
||||
+ _1 = Ne(_10, const false); // scope 0 at $DIR/matches_reduce_branches.rs:41:14: 41:19
|
||||
+ StorageDead(_10); // scope 0 at $DIR/matches_reduce_branches.rs:40:15: 40:88
|
||||
+ goto -> bb12; // scope 0 at $DIR/matches_reduce_branches.rs:40:15: 40:88
|
||||
}
|
||||
|
||||
bb10: {
|
||||
StorageDead(_3); // scope 0 at $DIR/matches_reduce_branches.rs:40:95: 40:96
|
||||
_1 = const true; // scope 0 at $DIR/matches_reduce_branches.rs:40:92: 40:96
|
||||
goto -> bb12; // scope 0 at $DIR/matches_reduce_branches.rs:39:15: 42:6
|
||||
}
|
||||
|
||||
bb11: {
|
||||
StorageDead(_3); // scope 0 at $DIR/matches_reduce_branches.rs:40:95: 40:96
|
||||
_1 = const false; // scope 0 at $DIR/matches_reduce_branches.rs:41:14: 41:19
|
||||
goto -> bb12; // scope 0 at $DIR/matches_reduce_branches.rs:39:15: 42:6
|
||||
}
|
||||
|
||||
bb12: {
|
||||
StorageDead(_2); // scope 0 at $DIR/matches_reduce_branches.rs:42:6: 42:7
|
||||
_0 = _1; // scope 1 at $DIR/matches_reduce_branches.rs:43:5: 43:8
|
||||
StorageDead(_1); // scope 0 at $DIR/matches_reduce_branches.rs:44:1: 44:2
|
||||
return; // scope 0 at $DIR/matches_reduce_branches.rs:44:2: 44:2
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,116 @@
|
|||
- // MIR for `match_nested_if` before MatchBranchSimplification
|
||||
+ // MIR for `match_nested_if` after MatchBranchSimplification
|
||||
|
||||
fn match_nested_if() -> bool {
|
||||
let mut _0: bool; // return place in scope 0 at $DIR/matches_reduce_branches.rs:38:25: 38:29
|
||||
let _1: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:39:9: 39:12
|
||||
let mut _2: (); // in scope 0 at $DIR/matches_reduce_branches.rs:39:21: 39:23
|
||||
let mut _3: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:40:15: 40:88
|
||||
let mut _4: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:40:18: 40:68
|
||||
let mut _5: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:40:21: 40:48
|
||||
let mut _6: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:40:24: 40:28
|
||||
+ let mut _7: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:40:21: 40:48
|
||||
+ let mut _8: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:40:18: 40:68
|
||||
+ let mut _9: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:40:15: 40:88
|
||||
+ let mut _10: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:40:15: 40:88
|
||||
scope 1 {
|
||||
debug val => _1; // in scope 1 at $DIR/matches_reduce_branches.rs:39:9: 39:12
|
||||
}
|
||||
|
||||
bb0: {
|
||||
StorageLive(_1); // scope 0 at $DIR/matches_reduce_branches.rs:39:9: 39:12
|
||||
StorageLive(_2); // scope 0 at $DIR/matches_reduce_branches.rs:39:21: 39:23
|
||||
StorageLive(_3); // scope 0 at $DIR/matches_reduce_branches.rs:40:15: 40:88
|
||||
StorageLive(_4); // scope 0 at $DIR/matches_reduce_branches.rs:40:18: 40:68
|
||||
StorageLive(_5); // scope 0 at $DIR/matches_reduce_branches.rs:40:21: 40:48
|
||||
StorageLive(_6); // scope 0 at $DIR/matches_reduce_branches.rs:40:24: 40:28
|
||||
_6 = const true; // scope 0 at $DIR/matches_reduce_branches.rs:40:24: 40:28
|
||||
- switchInt(_6) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/matches_reduce_branches.rs:40:21: 40:48
|
||||
+ StorageLive(_7); // scope 0 at $DIR/matches_reduce_branches.rs:40:21: 40:48
|
||||
+ _7 = _6; // scope 0 at $DIR/matches_reduce_branches.rs:40:21: 40:48
|
||||
+ _5 = Ne(_7, const false); // scope 0 at $DIR/matches_reduce_branches.rs:40:42: 40:47
|
||||
+ StorageDead(_7); // scope 0 at $DIR/matches_reduce_branches.rs:40:21: 40:48
|
||||
+ goto -> bb3; // scope 0 at $DIR/matches_reduce_branches.rs:40:21: 40:48
|
||||
}
|
||||
|
||||
bb1: {
|
||||
_5 = const true; // scope 0 at $DIR/matches_reduce_branches.rs:40:30: 40:34
|
||||
goto -> bb3; // scope 0 at $DIR/matches_reduce_branches.rs:40:21: 40:48
|
||||
}
|
||||
|
||||
bb2: {
|
||||
_5 = const false; // scope 0 at $DIR/matches_reduce_branches.rs:40:42: 40:47
|
||||
goto -> bb3; // scope 0 at $DIR/matches_reduce_branches.rs:40:21: 40:48
|
||||
}
|
||||
|
||||
bb3: {
|
||||
StorageDead(_6); // scope 0 at $DIR/matches_reduce_branches.rs:40:47: 40:48
|
||||
- switchInt(_5) -> [false: bb4, otherwise: bb5]; // scope 0 at $DIR/matches_reduce_branches.rs:40:18: 40:68
|
||||
+ StorageLive(_8); // scope 0 at $DIR/matches_reduce_branches.rs:40:18: 40:68
|
||||
+ _8 = _5; // scope 0 at $DIR/matches_reduce_branches.rs:40:18: 40:68
|
||||
+ _4 = Ne(_8, const false); // scope 0 at $DIR/matches_reduce_branches.rs:40:62: 40:67
|
||||
+ StorageDead(_8); // scope 0 at $DIR/matches_reduce_branches.rs:40:18: 40:68
|
||||
+ goto -> bb6; // scope 0 at $DIR/matches_reduce_branches.rs:40:18: 40:68
|
||||
}
|
||||
|
||||
bb4: {
|
||||
_4 = const false; // scope 0 at $DIR/matches_reduce_branches.rs:40:62: 40:67
|
||||
goto -> bb6; // scope 0 at $DIR/matches_reduce_branches.rs:40:18: 40:68
|
||||
}
|
||||
|
||||
bb5: {
|
||||
_4 = const true; // scope 0 at $DIR/matches_reduce_branches.rs:40:50: 40:54
|
||||
goto -> bb6; // scope 0 at $DIR/matches_reduce_branches.rs:40:18: 40:68
|
||||
}
|
||||
|
||||
bb6: {
|
||||
StorageDead(_5); // scope 0 at $DIR/matches_reduce_branches.rs:40:67: 40:68
|
||||
- switchInt(_4) -> [false: bb7, otherwise: bb8]; // scope 0 at $DIR/matches_reduce_branches.rs:40:15: 40:88
|
||||
+ StorageLive(_9); // scope 0 at $DIR/matches_reduce_branches.rs:40:15: 40:88
|
||||
+ _9 = _4; // scope 0 at $DIR/matches_reduce_branches.rs:40:15: 40:88
|
||||
+ _3 = Ne(_9, const false); // scope 0 at $DIR/matches_reduce_branches.rs:40:82: 40:87
|
||||
+ StorageDead(_9); // scope 0 at $DIR/matches_reduce_branches.rs:40:15: 40:88
|
||||
+ goto -> bb9; // scope 0 at $DIR/matches_reduce_branches.rs:40:15: 40:88
|
||||
}
|
||||
|
||||
bb7: {
|
||||
_3 = const false; // scope 0 at $DIR/matches_reduce_branches.rs:40:82: 40:87
|
||||
goto -> bb9; // scope 0 at $DIR/matches_reduce_branches.rs:40:15: 40:88
|
||||
}
|
||||
|
||||
bb8: {
|
||||
_3 = const true; // scope 0 at $DIR/matches_reduce_branches.rs:40:70: 40:74
|
||||
goto -> bb9; // scope 0 at $DIR/matches_reduce_branches.rs:40:15: 40:88
|
||||
}
|
||||
|
||||
bb9: {
|
||||
StorageDead(_4); // scope 0 at $DIR/matches_reduce_branches.rs:40:87: 40:88
|
||||
- switchInt(move _3) -> [false: bb11, otherwise: bb10]; // scope 0 at $DIR/matches_reduce_branches.rs:40:15: 40:88
|
||||
+ StorageLive(_10); // scope 0 at $DIR/matches_reduce_branches.rs:40:15: 40:88
|
||||
+ _10 = move _3; // scope 0 at $DIR/matches_reduce_branches.rs:40:15: 40:88
|
||||
+ StorageDead(_3); // scope 0 at $DIR/matches_reduce_branches.rs:40:95: 40:96
|
||||
+ _1 = Ne(_10, const false); // scope 0 at $DIR/matches_reduce_branches.rs:41:14: 41:19
|
||||
+ StorageDead(_10); // scope 0 at $DIR/matches_reduce_branches.rs:40:15: 40:88
|
||||
+ goto -> bb12; // scope 0 at $DIR/matches_reduce_branches.rs:40:15: 40:88
|
||||
}
|
||||
|
||||
bb10: {
|
||||
StorageDead(_3); // scope 0 at $DIR/matches_reduce_branches.rs:40:95: 40:96
|
||||
_1 = const true; // scope 0 at $DIR/matches_reduce_branches.rs:40:92: 40:96
|
||||
goto -> bb12; // scope 0 at $DIR/matches_reduce_branches.rs:39:15: 42:6
|
||||
}
|
||||
|
||||
bb11: {
|
||||
StorageDead(_3); // scope 0 at $DIR/matches_reduce_branches.rs:40:95: 40:96
|
||||
_1 = const false; // scope 0 at $DIR/matches_reduce_branches.rs:41:14: 41:19
|
||||
goto -> bb12; // scope 0 at $DIR/matches_reduce_branches.rs:39:15: 42:6
|
||||
}
|
||||
|
||||
bb12: {
|
||||
StorageDead(_2); // scope 0 at $DIR/matches_reduce_branches.rs:42:6: 42:7
|
||||
_0 = _1; // scope 1 at $DIR/matches_reduce_branches.rs:43:5: 43:8
|
||||
StorageDead(_1); // scope 0 at $DIR/matches_reduce_branches.rs:44:1: 44:2
|
||||
return; // scope 0 at $DIR/matches_reduce_branches.rs:44:2: 44:2
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
// compile-flags: -Zunsound-mir-opts
|
||||
// EMIT_MIR_FOR_EACH_BIT_WIDTH
|
||||
// EMIT_MIR matches_reduce_branches.foo.MatchBranchSimplification.diff
|
||||
// EMIT_MIR matches_reduce_branches.bar.MatchBranchSimplification.diff
|
||||
// EMIT_MIR matches_reduce_branches.match_nested_if.MatchBranchSimplification.diff
|
||||
|
||||
fn foo(bar: Option<()>) {
|
||||
if matches!(bar, None) {
|
||||
|
@ -35,9 +35,17 @@ fn bar(i: i32) -> (bool, bool, bool, bool) {
|
|||
(a, b, c, d)
|
||||
}
|
||||
|
||||
fn match_nested_if() -> bool {
|
||||
let val = match () {
|
||||
() if if if if true {true} else {false} {true} else {false} {true} else {false} => true,
|
||||
_ => false,
|
||||
};
|
||||
val
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let _ = foo(None);
|
||||
let _ = foo(Some(()));
|
||||
let _ = bar(0);
|
||||
let _ = match_nested_if();
|
||||
}
|
||||
|
|
|
@ -8,61 +8,52 @@
|
|||
let mut _3: isize; // in scope 0 at $DIR/not_equal_false.rs:4:17: 4:21
|
||||
let mut _4: bool; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
|
||||
let mut _5: isize; // in scope 0 at $DIR/not_equal_false.rs:4:38: 4:45
|
||||
let mut _6: isize; // in scope 0 at $DIR/not_equal_false.rs:4:17: 4:21
|
||||
let mut _7: isize; // in scope 0 at $DIR/not_equal_false.rs:4:38: 4:45
|
||||
let mut _8: bool; // in scope 0 at $DIR/not_equal_false.rs:4:5: 4:46
|
||||
|
||||
bb0: {
|
||||
StorageLive(_2); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
|
||||
_3 = discriminant(_1); // scope 0 at $DIR/not_equal_false.rs:4:17: 4:21
|
||||
switchInt(move _3) -> [0_isize: bb6, otherwise: bb5]; // scope 0 at $DIR/not_equal_false.rs:4:17: 4:21
|
||||
StorageLive(_6); // scope 0 at $DIR/not_equal_false.rs:4:17: 4:21
|
||||
_6 = move _3; // scope 0 at $DIR/not_equal_false.rs:4:17: 4:21
|
||||
_2 = Eq(_6, const 0_isize); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
|
||||
StorageDead(_6); // scope 0 at $DIR/not_equal_false.rs:4:17: 4:21
|
||||
goto -> bb4; // scope 0 at $DIR/not_equal_false.rs:4:17: 4:21
|
||||
}
|
||||
|
||||
bb1: {
|
||||
_0 = const true; // scope 0 at $DIR/not_equal_false.rs:4:5: 4:46
|
||||
goto -> bb4; // scope 0 at $DIR/not_equal_false.rs:4:5: 4:46
|
||||
goto -> bb3; // scope 0 at $DIR/not_equal_false.rs:4:5: 4:46
|
||||
}
|
||||
|
||||
bb2: {
|
||||
_0 = const false; // scope 0 at $DIR/not_equal_false.rs:4:5: 4:46
|
||||
goto -> bb4; // scope 0 at $DIR/not_equal_false.rs:4:5: 4:46
|
||||
StorageLive(_4); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
|
||||
_5 = discriminant(_1); // scope 0 at $DIR/not_equal_false.rs:4:38: 4:45
|
||||
StorageLive(_7); // scope 0 at $DIR/not_equal_false.rs:4:38: 4:45
|
||||
_7 = move _5; // scope 0 at $DIR/not_equal_false.rs:4:38: 4:45
|
||||
_4 = Eq(_7, const 1_isize); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
|
||||
StorageDead(_7); // scope 0 at $DIR/not_equal_false.rs:4:38: 4:45
|
||||
goto -> bb5; // scope 0 at $DIR/not_equal_false.rs:4:38: 4:45
|
||||
}
|
||||
|
||||
bb3: {
|
||||
StorageLive(_4); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
|
||||
_5 = discriminant(_1); // scope 0 at $DIR/not_equal_false.rs:4:38: 4:45
|
||||
switchInt(move _5) -> [1_isize: bb9, otherwise: bb8]; // scope 0 at $DIR/not_equal_false.rs:4:38: 4:45
|
||||
}
|
||||
|
||||
bb4: {
|
||||
StorageDead(_4); // scope 0 at $DIR/not_equal_false.rs:4:45: 4:46
|
||||
StorageDead(_2); // scope 0 at $DIR/not_equal_false.rs:4:45: 4:46
|
||||
return; // scope 0 at $DIR/not_equal_false.rs:5:2: 5:2
|
||||
}
|
||||
|
||||
bb4: {
|
||||
switchInt(move _2) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/not_equal_false.rs:4:5: 4:46
|
||||
}
|
||||
|
||||
bb5: {
|
||||
_2 = const false; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
|
||||
goto -> bb7; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
|
||||
}
|
||||
|
||||
bb6: {
|
||||
_2 = const true; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
|
||||
goto -> bb7; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
|
||||
}
|
||||
|
||||
bb7: {
|
||||
switchInt(move _2) -> [false: bb3, otherwise: bb1]; // scope 0 at $DIR/not_equal_false.rs:4:5: 4:46
|
||||
}
|
||||
|
||||
bb8: {
|
||||
_4 = const false; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
|
||||
goto -> bb10; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
|
||||
}
|
||||
|
||||
bb9: {
|
||||
_4 = const true; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
|
||||
goto -> bb10; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
|
||||
}
|
||||
|
||||
bb10: {
|
||||
switchInt(move _4) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/not_equal_false.rs:4:5: 4:46
|
||||
StorageLive(_8); // scope 0 at $DIR/not_equal_false.rs:4:5: 4:46
|
||||
_8 = move _4; // scope 0 at $DIR/not_equal_false.rs:4:5: 4:46
|
||||
- _0 = Ne(_8, const false); // scope 0 at $DIR/not_equal_false.rs:4:5: 4:46
|
||||
+ _0 = _8; // scope 0 at $DIR/not_equal_false.rs:4:5: 4:46
|
||||
StorageDead(_8); // scope 0 at $DIR/not_equal_false.rs:4:5: 4:46
|
||||
goto -> bb3; // scope 0 at $DIR/not_equal_false.rs:4:5: 4:46
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
// run-pass
|
||||
#![feature(const_generics, const_evaluatable_checked)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
fn with_bound<const N: usize>() where [u8; N / 2]: Sized {
|
||||
let _: [u8; N / 2] = [0; N / 2];
|
||||
}
|
||||
|
||||
fn main() {
|
||||
with_bound::<4>();
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
#![feature(const_generics, const_evaluatable_checked)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
fn add<const N: usize>() -> [u8; { N + 1; 5 }] {
|
||||
//~^ ERROR overly complex generic constant
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn div<const N: usize>() -> [u8; { N / 1; 5 }] {
|
||||
//~^ ERROR overly complex generic constant
|
||||
todo!()
|
||||
}
|
||||
|
||||
const fn foo(n: usize) {}
|
||||
|
||||
fn fn_call<const N: usize>() -> [u8; { foo(N); 5 }] {
|
||||
//~^ ERROR overly complex generic constant
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn main() {
|
||||
add::<12>();
|
||||
div::<9>();
|
||||
fn_call::<14>();
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
error: overly complex generic constant
|
||||
--> $DIR/unused_expr.rs:4:34
|
||||
|
|
||||
LL | fn add<const N: usize>() -> [u8; { N + 1; 5 }] {
|
||||
| ^^-----^^^^^
|
||||
| |
|
||||
| dead code
|
||||
|
|
||||
= help: consider moving this anonymous constant into a `const` function
|
||||
|
||||
error: overly complex generic constant
|
||||
--> $DIR/unused_expr.rs:9:34
|
||||
|
|
||||
LL | fn div<const N: usize>() -> [u8; { N / 1; 5 }] {
|
||||
| ^^-----^^^^^
|
||||
| |
|
||||
| dead code
|
||||
|
|
||||
= help: consider moving this anonymous constant into a `const` function
|
||||
|
||||
error: overly complex generic constant
|
||||
--> $DIR/unused_expr.rs:16:38
|
||||
|
|
||||
LL | fn fn_call<const N: usize>() -> [u8; { foo(N); 5 }] {
|
||||
| ^^------^^^^^
|
||||
| |
|
||||
| dead code
|
||||
|
|
||||
= help: consider moving this anonymous constant into a `const` function
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
|
@ -1,6 +1,8 @@
|
|||
#![feature(const_panic)]
|
||||
#![crate_type = "lib"]
|
||||
|
||||
const MSG: &str = "hello";
|
||||
|
||||
const Z: () = std::panic!("cheese");
|
||||
//~^ ERROR any use of this value will cause an error
|
||||
|
||||
|
@ -12,6 +14,9 @@ const Y: () = std::unreachable!();
|
|||
|
||||
const X: () = std::unimplemented!();
|
||||
//~^ ERROR any use of this value will cause an error
|
||||
//
|
||||
const W: () = std::panic!(MSG);
|
||||
//~^ ERROR any use of this value will cause an error
|
||||
|
||||
const Z_CORE: () = core::panic!("cheese");
|
||||
//~^ ERROR any use of this value will cause an error
|
||||
|
@ -24,3 +29,6 @@ const Y_CORE: () = core::unreachable!();
|
|||
|
||||
const X_CORE: () = core::unimplemented!();
|
||||
//~^ ERROR any use of this value will cause an error
|
||||
|
||||
const W_CORE: () = core::panic!(MSG);
|
||||
//~^ ERROR any use of this value will cause an error
|
||||
|
|
|
@ -1,83 +1,103 @@
|
|||
error: any use of this value will cause an error
|
||||
--> $DIR/const_panic.rs:4:15
|
||||
--> $DIR/const_panic.rs:6:15
|
||||
|
|
||||
LL | const Z: () = std::panic!("cheese");
|
||||
| --------------^^^^^^^^^^^^^^^^^^^^^-
|
||||
| |
|
||||
| the evaluated program panicked at 'cheese', $DIR/const_panic.rs:4:15
|
||||
| the evaluated program panicked at 'cheese', $DIR/const_panic.rs:6:15
|
||||
|
|
||||
= note: `#[deny(const_err)]` on by default
|
||||
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: any use of this value will cause an error
|
||||
--> $DIR/const_panic.rs:7:16
|
||||
--> $DIR/const_panic.rs:9:16
|
||||
|
|
||||
LL | const Z2: () = std::panic!();
|
||||
| ---------------^^^^^^^^^^^^^-
|
||||
| |
|
||||
| the evaluated program panicked at 'explicit panic', $DIR/const_panic.rs:7:16
|
||||
| the evaluated program panicked at 'explicit panic', $DIR/const_panic.rs:9:16
|
||||
|
|
||||
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: any use of this value will cause an error
|
||||
--> $DIR/const_panic.rs:10:15
|
||||
--> $DIR/const_panic.rs:12:15
|
||||
|
|
||||
LL | const Y: () = std::unreachable!();
|
||||
| --------------^^^^^^^^^^^^^^^^^^^-
|
||||
| |
|
||||
| the evaluated program panicked at 'internal error: entered unreachable code', $DIR/const_panic.rs:10:15
|
||||
| the evaluated program panicked at 'internal error: entered unreachable code', $DIR/const_panic.rs:12:15
|
||||
|
|
||||
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: any use of this value will cause an error
|
||||
--> $DIR/const_panic.rs:13:15
|
||||
--> $DIR/const_panic.rs:15:15
|
||||
|
|
||||
LL | const X: () = std::unimplemented!();
|
||||
| --------------^^^^^^^^^^^^^^^^^^^^^-
|
||||
| |
|
||||
| the evaluated program panicked at 'not implemented', $DIR/const_panic.rs:13:15
|
||||
| the evaluated program panicked at 'not implemented', $DIR/const_panic.rs:15:15
|
||||
|
|
||||
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: any use of this value will cause an error
|
||||
--> $DIR/const_panic.rs:16:20
|
||||
--> $DIR/const_panic.rs:18:15
|
||||
|
|
||||
LL | const W: () = std::panic!(MSG);
|
||||
| --------------^^^^^^^^^^^^^^^^-
|
||||
| |
|
||||
| the evaluated program panicked at 'hello', $DIR/const_panic.rs:18:15
|
||||
|
|
||||
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: any use of this value will cause an error
|
||||
--> $DIR/const_panic.rs:21:20
|
||||
|
|
||||
LL | const Z_CORE: () = core::panic!("cheese");
|
||||
| -------------------^^^^^^^^^^^^^^^^^^^^^^-
|
||||
| |
|
||||
| the evaluated program panicked at 'cheese', $DIR/const_panic.rs:16:20
|
||||
| the evaluated program panicked at 'cheese', $DIR/const_panic.rs:21:20
|
||||
|
|
||||
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: any use of this value will cause an error
|
||||
--> $DIR/const_panic.rs:19:21
|
||||
--> $DIR/const_panic.rs:24:21
|
||||
|
|
||||
LL | const Z2_CORE: () = core::panic!();
|
||||
| --------------------^^^^^^^^^^^^^^-
|
||||
| |
|
||||
| the evaluated program panicked at 'explicit panic', $DIR/const_panic.rs:19:21
|
||||
| the evaluated program panicked at 'explicit panic', $DIR/const_panic.rs:24:21
|
||||
|
|
||||
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: any use of this value will cause an error
|
||||
--> $DIR/const_panic.rs:22:20
|
||||
--> $DIR/const_panic.rs:27:20
|
||||
|
|
||||
LL | const Y_CORE: () = core::unreachable!();
|
||||
| -------------------^^^^^^^^^^^^^^^^^^^^-
|
||||
| |
|
||||
| the evaluated program panicked at 'internal error: entered unreachable code', $DIR/const_panic.rs:22:20
|
||||
| the evaluated program panicked at 'internal error: entered unreachable code', $DIR/const_panic.rs:27:20
|
||||
|
|
||||
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: any use of this value will cause an error
|
||||
--> $DIR/const_panic.rs:25:20
|
||||
--> $DIR/const_panic.rs:30:20
|
||||
|
|
||||
LL | const X_CORE: () = core::unimplemented!();
|
||||
| -------------------^^^^^^^^^^^^^^^^^^^^^^-
|
||||
| |
|
||||
| the evaluated program panicked at 'not implemented', $DIR/const_panic.rs:25:20
|
||||
| the evaluated program panicked at 'not implemented', $DIR/const_panic.rs:30:20
|
||||
|
|
||||
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: aborting due to 8 previous errors
|
||||
error: any use of this value will cause an error
|
||||
--> $DIR/const_panic.rs:33:20
|
||||
|
|
||||
LL | const W_CORE: () = core::panic!(MSG);
|
||||
| -------------------^^^^^^^^^^^^^^^^^-
|
||||
| |
|
||||
| the evaluated program panicked at 'hello', $DIR/const_panic.rs:33:20
|
||||
|
|
||||
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: aborting due to 10 previous errors
|
||||
|
||||
|
|
11
src/test/ui/consts/const_in_pattern/issue-53708.rs
Normal file
11
src/test/ui/consts/const_in_pattern/issue-53708.rs
Normal file
|
@ -0,0 +1,11 @@
|
|||
// check-pass
|
||||
// https://github.com/rust-lang/rust/issues/53708
|
||||
#[derive(PartialEq, Eq)]
|
||||
struct S;
|
||||
|
||||
fn main() {
|
||||
const C: &S = &S;
|
||||
match C {
|
||||
C => {}
|
||||
}
|
||||
}
|
17
src/test/ui/consts/const_in_pattern/issue-78057.rs
Normal file
17
src/test/ui/consts/const_in_pattern/issue-78057.rs
Normal file
|
@ -0,0 +1,17 @@
|
|||
#![deny(unreachable_patterns)]
|
||||
|
||||
#[derive(PartialEq)]
|
||||
struct Opaque(i32);
|
||||
|
||||
impl Eq for Opaque {}
|
||||
|
||||
const FOO: Opaque = Opaque(42);
|
||||
|
||||
fn main() {
|
||||
match FOO {
|
||||
FOO => {},
|
||||
//~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]`
|
||||
_ => {}
|
||||
//~^ ERROR unreachable pattern
|
||||
}
|
||||
}
|
20
src/test/ui/consts/const_in_pattern/issue-78057.stderr
Normal file
20
src/test/ui/consts/const_in_pattern/issue-78057.stderr
Normal file
|
@ -0,0 +1,20 @@
|
|||
error: to use a constant of type `Opaque` in a pattern, `Opaque` must be annotated with `#[derive(PartialEq, Eq)]`
|
||||
--> $DIR/issue-78057.rs:12:9
|
||||
|
|
||||
LL | FOO => {},
|
||||
| ^^^
|
||||
|
||||
error: unreachable pattern
|
||||
--> $DIR/issue-78057.rs:14:9
|
||||
|
|
||||
LL | _ => {}
|
||||
| ^
|
||||
|
|
||||
note: the lint level is defined here
|
||||
--> $DIR/issue-78057.rs:1:9
|
||||
|
|
||||
LL | #![deny(unreachable_patterns)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
|
@ -53,8 +53,8 @@ enum LR_NonZero {
|
|||
fn test_panic_msg<T>(op: impl (FnOnce() -> T) + panic::UnwindSafe, msg: &str) {
|
||||
let err = panic::catch_unwind(op).err();
|
||||
assert_eq!(
|
||||
err.as_ref().and_then(|a| a.downcast_ref::<String>()).map(|s| &**s),
|
||||
Some(msg)
|
||||
err.as_ref().and_then(|a| a.downcast_ref::<&str>()),
|
||||
Some(&msg)
|
||||
);
|
||||
}
|
||||
|
||||
|
|
13
src/test/ui/issues/issue-77919.rs
Normal file
13
src/test/ui/issues/issue-77919.rs
Normal file
|
@ -0,0 +1,13 @@
|
|||
fn main() {
|
||||
[1; <Multiply<Five, Five>>::VAL]; //~ ERROR evaluation of constant value failed
|
||||
}
|
||||
trait TypeVal<T> {
|
||||
const VAL: T; //~ ERROR any use of this value will cause an error
|
||||
}
|
||||
struct Five;
|
||||
struct Multiply<N, M> {
|
||||
_n: PhantomData, //~ ERROR cannot find type `PhantomData` in this scope
|
||||
}
|
||||
impl<N, M> TypeVal<usize> for Multiply<N, M> where N: TypeVal<VAL> {}
|
||||
//~^ ERROR cannot find type `VAL` in this scope
|
||||
//~| ERROR not all trait items implemented, missing: `VAL`
|
46
src/test/ui/issues/issue-77919.stderr
Normal file
46
src/test/ui/issues/issue-77919.stderr
Normal file
|
@ -0,0 +1,46 @@
|
|||
error[E0412]: cannot find type `PhantomData` in this scope
|
||||
--> $DIR/issue-77919.rs:9:9
|
||||
|
|
||||
LL | _n: PhantomData,
|
||||
| ^^^^^^^^^^^ not found in this scope
|
||||
|
|
||||
help: consider importing this struct
|
||||
|
|
||||
LL | use std::marker::PhantomData;
|
||||
|
|
||||
|
||||
error[E0412]: cannot find type `VAL` in this scope
|
||||
--> $DIR/issue-77919.rs:11:63
|
||||
|
|
||||
LL | impl<N, M> TypeVal<usize> for Multiply<N, M> where N: TypeVal<VAL> {}
|
||||
| - ^^^ not found in this scope
|
||||
| |
|
||||
| help: you might be missing a type parameter: `, VAL`
|
||||
|
||||
error[E0046]: not all trait items implemented, missing: `VAL`
|
||||
--> $DIR/issue-77919.rs:11:1
|
||||
|
|
||||
LL | const VAL: T;
|
||||
| ------------- `VAL` from trait
|
||||
...
|
||||
LL | impl<N, M> TypeVal<usize> for Multiply<N, M> where N: TypeVal<VAL> {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `VAL` in implementation
|
||||
|
||||
error: any use of this value will cause an error
|
||||
--> $DIR/issue-77919.rs:5:5
|
||||
|
|
||||
LL | const VAL: T;
|
||||
| ^^^^^^^^^^^^^ no MIR body is available for DefId(0:7 ~ issue_77919[317d]::TypeVal::VAL)
|
||||
|
|
||||
= note: `#[deny(const_err)]` on by default
|
||||
|
||||
error[E0080]: evaluation of constant value failed
|
||||
--> $DIR/issue-77919.rs:2:9
|
||||
|
|
||||
LL | [1; <Multiply<Five, Five>>::VAL];
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ referenced constant has errors
|
||||
|
||||
error: aborting due to 5 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0046, E0080, E0412.
|
||||
For more information about an error, try `rustc --explain E0046`.
|
12
src/test/ui/macros/issue-78325-inconsistent-resolution.rs
Normal file
12
src/test/ui/macros/issue-78325-inconsistent-resolution.rs
Normal file
|
@ -0,0 +1,12 @@
|
|||
macro_rules! define_other_core {
|
||||
( ) => {
|
||||
extern crate std as core;
|
||||
//~^ ERROR macro-expanded `extern crate` items cannot shadow names passed with `--extern`
|
||||
};
|
||||
}
|
||||
|
||||
fn main() {
|
||||
core::panic!();
|
||||
}
|
||||
|
||||
define_other_core!();
|
|
@ -0,0 +1,13 @@
|
|||
error: macro-expanded `extern crate` items cannot shadow names passed with `--extern`
|
||||
--> $DIR/issue-78325-inconsistent-resolution.rs:3:9
|
||||
|
|
||||
LL | extern crate std as core;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
...
|
||||
LL | define_other_core!();
|
||||
| --------------------- in this macro invocation
|
||||
|
|
||||
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: aborting due to previous error
|
||||
|
114
src/test/ui/pattern/usefulness/consts-opaque.rs
Normal file
114
src/test/ui/pattern/usefulness/consts-opaque.rs
Normal file
|
@ -0,0 +1,114 @@
|
|||
// This file tests the exhaustiveness algorithm on opaque constants. Most of the examples give
|
||||
// unnecessary warnings because const_to_pat.rs converts a constant pattern to a wildcard when the
|
||||
// constant is not allowed as a pattern. This is an edge case so we may not care to fix it.
|
||||
// See also https://github.com/rust-lang/rust/issues/78057
|
||||
|
||||
#![deny(unreachable_patterns)]
|
||||
|
||||
#[derive(PartialEq)]
|
||||
struct Foo(i32);
|
||||
impl Eq for Foo {}
|
||||
const FOO: Foo = Foo(42);
|
||||
const FOO_REF: &Foo = &Foo(42);
|
||||
const FOO_REF_REF: &&Foo = &&Foo(42);
|
||||
|
||||
#[derive(PartialEq)]
|
||||
struct Bar;
|
||||
impl Eq for Bar {}
|
||||
const BAR: Bar = Bar;
|
||||
|
||||
#[derive(PartialEq)]
|
||||
enum Baz {
|
||||
Baz1,
|
||||
Baz2
|
||||
}
|
||||
impl Eq for Baz {}
|
||||
const BAZ: Baz = Baz::Baz1;
|
||||
|
||||
type Quux = fn(usize, usize) -> usize;
|
||||
fn quux(a: usize, b: usize) -> usize { a + b }
|
||||
const QUUX: Quux = quux;
|
||||
|
||||
fn main() {
|
||||
match FOO {
|
||||
FOO => {}
|
||||
//~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]`
|
||||
_ => {} // should not be emitting unreachable warning
|
||||
//~^ ERROR unreachable pattern
|
||||
}
|
||||
|
||||
match FOO_REF {
|
||||
FOO_REF => {}
|
||||
//~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]`
|
||||
Foo(_) => {} // should not be emitting unreachable warning
|
||||
//~^ ERROR unreachable pattern
|
||||
}
|
||||
|
||||
// This used to cause an ICE (https://github.com/rust-lang/rust/issues/78071)
|
||||
match FOO_REF_REF {
|
||||
FOO_REF_REF => {}
|
||||
//~^ WARNING must be annotated with `#[derive(PartialEq, Eq)]`
|
||||
//~| WARNING this was previously accepted by the compiler but is being phased out
|
||||
Foo(_) => {}
|
||||
}
|
||||
|
||||
match BAR {
|
||||
Bar => {}
|
||||
BAR => {} // should not be emitting unreachable warning
|
||||
//~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]`
|
||||
//~| ERROR unreachable pattern
|
||||
_ => {}
|
||||
//~^ ERROR unreachable pattern
|
||||
}
|
||||
|
||||
match BAR {
|
||||
BAR => {}
|
||||
//~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]`
|
||||
Bar => {} // should not be emitting unreachable warning
|
||||
//~^ ERROR unreachable pattern
|
||||
_ => {}
|
||||
//~^ ERROR unreachable pattern
|
||||
}
|
||||
|
||||
match BAR {
|
||||
BAR => {}
|
||||
//~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]`
|
||||
BAR => {} // should not be emitting unreachable warning
|
||||
//~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]`
|
||||
//~| ERROR unreachable pattern
|
||||
_ => {} // should not be emitting unreachable warning
|
||||
//~^ ERROR unreachable pattern
|
||||
}
|
||||
|
||||
match BAZ {
|
||||
BAZ => {}
|
||||
//~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]`
|
||||
Baz::Baz1 => {} // should not be emitting unreachable warning
|
||||
//~^ ERROR unreachable pattern
|
||||
_ => {}
|
||||
//~^ ERROR unreachable pattern
|
||||
}
|
||||
|
||||
match BAZ {
|
||||
Baz::Baz1 => {}
|
||||
BAZ => {}
|
||||
//~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]`
|
||||
_ => {}
|
||||
//~^ ERROR unreachable pattern
|
||||
}
|
||||
|
||||
match BAZ {
|
||||
BAZ => {}
|
||||
//~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]`
|
||||
Baz::Baz2 => {} // should not be emitting unreachable warning
|
||||
//~^ ERROR unreachable pattern
|
||||
_ => {} // should not be emitting unreachable warning
|
||||
//~^ ERROR unreachable pattern
|
||||
}
|
||||
|
||||
match QUUX {
|
||||
QUUX => {}
|
||||
QUUX => {}
|
||||
_ => {}
|
||||
}
|
||||
}
|
158
src/test/ui/pattern/usefulness/consts-opaque.stderr
Normal file
158
src/test/ui/pattern/usefulness/consts-opaque.stderr
Normal file
|
@ -0,0 +1,158 @@
|
|||
error: to use a constant of type `Foo` in a pattern, `Foo` must be annotated with `#[derive(PartialEq, Eq)]`
|
||||
--> $DIR/consts-opaque.rs:34:9
|
||||
|
|
||||
LL | FOO => {}
|
||||
| ^^^
|
||||
|
||||
error: unreachable pattern
|
||||
--> $DIR/consts-opaque.rs:36:9
|
||||
|
|
||||
LL | _ => {} // should not be emitting unreachable warning
|
||||
| ^
|
||||
|
|
||||
note: the lint level is defined here
|
||||
--> $DIR/consts-opaque.rs:6:9
|
||||
|
|
||||
LL | #![deny(unreachable_patterns)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: to use a constant of type `Foo` in a pattern, `Foo` must be annotated with `#[derive(PartialEq, Eq)]`
|
||||
--> $DIR/consts-opaque.rs:41:9
|
||||
|
|
||||
LL | FOO_REF => {}
|
||||
| ^^^^^^^
|
||||
|
||||
error: unreachable pattern
|
||||
--> $DIR/consts-opaque.rs:43:9
|
||||
|
|
||||
LL | Foo(_) => {} // should not be emitting unreachable warning
|
||||
| ^^^^^^
|
||||
|
||||
warning: to use a constant of type `Foo` in a pattern, `Foo` must be annotated with `#[derive(PartialEq, Eq)]`
|
||||
--> $DIR/consts-opaque.rs:49:9
|
||||
|
|
||||
LL | FOO_REF_REF => {}
|
||||
| ^^^^^^^^^^^
|
||||
|
|
||||
= note: `#[warn(indirect_structural_match)]` on by default
|
||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
= note: for more information, see issue #62411 <https://github.com/rust-lang/rust/issues/62411>
|
||||
|
||||
error: to use a constant of type `Bar` in a pattern, `Bar` must be annotated with `#[derive(PartialEq, Eq)]`
|
||||
--> $DIR/consts-opaque.rs:57:9
|
||||
|
|
||||
LL | BAR => {} // should not be emitting unreachable warning
|
||||
| ^^^
|
||||
|
||||
error: unreachable pattern
|
||||
--> $DIR/consts-opaque.rs:57:9
|
||||
|
|
||||
LL | Bar => {}
|
||||
| --- matches any value
|
||||
LL | BAR => {} // should not be emitting unreachable warning
|
||||
| ^^^ unreachable pattern
|
||||
|
||||
error: unreachable pattern
|
||||
--> $DIR/consts-opaque.rs:60:9
|
||||
|
|
||||
LL | Bar => {}
|
||||
| --- matches any value
|
||||
...
|
||||
LL | _ => {}
|
||||
| ^ unreachable pattern
|
||||
|
||||
error: to use a constant of type `Bar` in a pattern, `Bar` must be annotated with `#[derive(PartialEq, Eq)]`
|
||||
--> $DIR/consts-opaque.rs:65:9
|
||||
|
|
||||
LL | BAR => {}
|
||||
| ^^^
|
||||
|
||||
error: unreachable pattern
|
||||
--> $DIR/consts-opaque.rs:67:9
|
||||
|
|
||||
LL | Bar => {} // should not be emitting unreachable warning
|
||||
| ^^^
|
||||
|
||||
error: unreachable pattern
|
||||
--> $DIR/consts-opaque.rs:69:9
|
||||
|
|
||||
LL | Bar => {} // should not be emitting unreachable warning
|
||||
| --- matches any value
|
||||
LL |
|
||||
LL | _ => {}
|
||||
| ^ unreachable pattern
|
||||
|
||||
error: to use a constant of type `Bar` in a pattern, `Bar` must be annotated with `#[derive(PartialEq, Eq)]`
|
||||
--> $DIR/consts-opaque.rs:74:9
|
||||
|
|
||||
LL | BAR => {}
|
||||
| ^^^
|
||||
|
||||
error: to use a constant of type `Bar` in a pattern, `Bar` must be annotated with `#[derive(PartialEq, Eq)]`
|
||||
--> $DIR/consts-opaque.rs:76:9
|
||||
|
|
||||
LL | BAR => {} // should not be emitting unreachable warning
|
||||
| ^^^
|
||||
|
||||
error: unreachable pattern
|
||||
--> $DIR/consts-opaque.rs:76:9
|
||||
|
|
||||
LL | BAR => {} // should not be emitting unreachable warning
|
||||
| ^^^
|
||||
|
||||
error: unreachable pattern
|
||||
--> $DIR/consts-opaque.rs:79:9
|
||||
|
|
||||
LL | _ => {} // should not be emitting unreachable warning
|
||||
| ^
|
||||
|
||||
error: to use a constant of type `Baz` in a pattern, `Baz` must be annotated with `#[derive(PartialEq, Eq)]`
|
||||
--> $DIR/consts-opaque.rs:84:9
|
||||
|
|
||||
LL | BAZ => {}
|
||||
| ^^^
|
||||
|
||||
error: unreachable pattern
|
||||
--> $DIR/consts-opaque.rs:86:9
|
||||
|
|
||||
LL | Baz::Baz1 => {} // should not be emitting unreachable warning
|
||||
| ^^^^^^^^^
|
||||
|
||||
error: unreachable pattern
|
||||
--> $DIR/consts-opaque.rs:88:9
|
||||
|
|
||||
LL | _ => {}
|
||||
| ^
|
||||
|
||||
error: to use a constant of type `Baz` in a pattern, `Baz` must be annotated with `#[derive(PartialEq, Eq)]`
|
||||
--> $DIR/consts-opaque.rs:94:9
|
||||
|
|
||||
LL | BAZ => {}
|
||||
| ^^^
|
||||
|
||||
error: unreachable pattern
|
||||
--> $DIR/consts-opaque.rs:96:9
|
||||
|
|
||||
LL | _ => {}
|
||||
| ^
|
||||
|
||||
error: to use a constant of type `Baz` in a pattern, `Baz` must be annotated with `#[derive(PartialEq, Eq)]`
|
||||
--> $DIR/consts-opaque.rs:101:9
|
||||
|
|
||||
LL | BAZ => {}
|
||||
| ^^^
|
||||
|
||||
error: unreachable pattern
|
||||
--> $DIR/consts-opaque.rs:103:9
|
||||
|
|
||||
LL | Baz::Baz2 => {} // should not be emitting unreachable warning
|
||||
| ^^^^^^^^^
|
||||
|
||||
error: unreachable pattern
|
||||
--> $DIR/consts-opaque.rs:105:9
|
||||
|
|
||||
LL | _ => {} // should not be emitting unreachable warning
|
||||
| ^
|
||||
|
||||
error: aborting due to 22 previous errors; 1 warning emitted
|
||||
|
|
@ -7,11 +7,11 @@ LL | match buf {
|
|||
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
|
||||
= note: the matched value is of type `&[u8; 4]`
|
||||
|
||||
error[E0004]: non-exhaustive patterns: `&[]`, `&[_]`, `&[_, _]` and 2 more not covered
|
||||
error[E0004]: non-exhaustive patterns: `&[0_u8..=64_u8, _, _, _]` and `&[66_u8..=u8::MAX, _, _, _]` not covered
|
||||
--> $DIR/match-byte-array-patterns-2.rs:10:11
|
||||
|
|
||||
LL | match buf {
|
||||
| ^^^ patterns `&[]`, `&[_]`, `&[_, _]` and 2 more not covered
|
||||
| ^^^ patterns `&[0_u8..=64_u8, _, _, _]` and `&[66_u8..=u8::MAX, _, _, _]` not covered
|
||||
|
|
||||
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
|
||||
= note: the matched value is of type `&[u8]`
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue