1
Fork 0

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:
bors 2020-10-24 21:42:39 +00:00
commit f58ffc9381
66 changed files with 1421 additions and 823 deletions

View file

@ -1366,9 +1366,9 @@ dependencies = [
[[package]] [[package]]
name = "hermit-abi" name = "hermit-abi"
version = "0.1.15" version = "0.1.17"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3deed196b6e7f9e44a2ae8d94225d80302d81208b1bb673fd21fe634645c85a9" checksum = "5aca5565f760fb5b220e499d72710ed156fdb74e631659e99377d9ebfbd13ae8"
dependencies = [ dependencies = [
"compiler_builtins", "compiler_builtins",
"libc", "libc",

View file

@ -1,6 +1,7 @@
use super::{DirectedGraph, WithNumNodes, WithStartNode, WithSuccessors}; use super::{DirectedGraph, WithNumNodes, WithStartNode, WithSuccessors};
use rustc_index::bit_set::BitSet; use rustc_index::bit_set::BitSet;
use rustc_index::vec::IndexVec; use rustc_index::vec::IndexVec;
use std::ops::ControlFlow;
#[cfg(test)] #[cfg(test)]
mod tests; 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. /// The status of a node in the depth-first search.
/// ///
/// See the documentation of `TriColorDepthFirstSearch` to see how a node's status is updated /// See the documentation of `TriColorDepthFirstSearch` to see how a node's status is updated

View file

@ -111,17 +111,6 @@ cfg_if! {
type Profiler = measureme::Profiler<SerializationSink>; 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! { bitflags::bitflags! {
struct EventFilter: u32 { struct EventFilter: u32 {
const GENERIC_ACTIVITIES = 1 << 0; const GENERIC_ACTIVITIES = 1 << 0;

View file

@ -263,6 +263,7 @@ language_item_table! {
// is required to define it somewhere. Additionally, there are restrictions on crates that use // is required to define it somewhere. Additionally, there are restrictions on crates that use
// a weak lang item, but do not have it defined. // a weak lang item, but do not have it defined.
Panic, sym::panic, panic_fn, Target::Fn; 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; PanicBoundsCheck, sym::panic_bounds_check, panic_bounds_check_fn, Target::Fn;
PanicInfo, sym::panic_info, panic_info, Target::Struct; PanicInfo, sym::panic_info, panic_info, Target::Struct;
PanicLocation, sym::panic_location, panic_location, Target::Struct; PanicLocation, sym::panic_location, panic_location, Target::Struct;

View file

@ -190,7 +190,11 @@ impl<T: Parse> Parse for List<T> {
} }
/// A named group containing queries. /// 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 { struct Group {
#[allow(unused)]
name: Ident, name: Ident,
queries: List<Query>, queries: List<Query>,
} }
@ -417,12 +421,9 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream {
let mut query_stream = quote! {}; let mut query_stream = quote! {};
let mut query_description_stream = quote! {}; let mut query_description_stream = quote! {};
let mut dep_node_def_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! {}; let mut cached_queries = quote! {};
for group in groups.0 { for group in groups.0 {
let mut group_stream = quote! {};
for mut query in group.queries.0 { for mut query in group.queries.0 {
let modifiers = process_modifiers(&mut query); let modifiers = process_modifiers(&mut query);
let name = &query.name; let name = &query.name;
@ -437,22 +438,6 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream {
cached_queries.extend(quote! { cached_queries.extend(quote! {
#name, #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(); let mut attributes = Vec::new();
@ -485,9 +470,9 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream {
let attribute_stream = quote! {#(#attributes),*}; let attribute_stream = quote! {#(#attributes),*};
let doc_comments = query.doc_comments.iter(); let doc_comments = query.doc_comments.iter();
// Add the query to the group // Add the query to the group
group_stream.extend(quote! { query_stream.extend(quote! {
#(#doc_comments)* #(#doc_comments)*
[#attribute_stream] fn #name: #name(#arg) #result, [#attribute_stream] fn #name(#arg) #result,
}); });
// Create a dep node for the query // Create a dep node for the query
@ -495,37 +480,10 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream {
[#attribute_stream] #name(#arg), [#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); 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! { TokenStream::from(quote! {
macro_rules! rustc_query_append { macro_rules! rustc_query_append {
([$($macro:tt)*][$($other:tt)*]) => { ([$($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_rules! rustc_cached_queries {
($($macro:tt)*) => { ($($macro:tt)*) => {
$($macro)*(#cached_queries); $($macro)*(#cached_queries);
@ -562,14 +511,5 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream {
} }
#query_description_stream #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
_ => (),
}
}
}
}) })
} }

View file

@ -2036,13 +2036,13 @@ direct_interners! {
macro_rules! slice_interners { macro_rules! slice_interners {
($($field:ident: $method:ident($ty:ty)),+ $(,)?) => ( ($($field:ident: $method:ident($ty:ty)),+ $(,)?) => (
$(impl<'tcx> TyCtxt<'tcx> { impl<'tcx> TyCtxt<'tcx> {
pub fn $method(self, v: &[$ty]) -> &'tcx List<$ty> { $(pub fn $method(self, v: &[$ty]) -> &'tcx List<$ty> {
self.interners.$field.intern_ref(v, || { self.interners.$field.intern_ref(v, || {
Interned(List::from_arena(&*self.arena, v)) Interned(List::from_arena(&*self.arena, v))
}).0 }).0
}
})+ })+
}
); );
} }

View file

@ -34,7 +34,6 @@ use crate::ty::util::AlwaysRequiresDrop;
use crate::ty::{self, AdtSizedConstraint, CrateInherentImpls, ParamEnvAnd, Ty, TyCtxt}; use crate::ty::{self, AdtSizedConstraint, CrateInherentImpls, ParamEnvAnd, Ty, TyCtxt};
use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fingerprint::Fingerprint;
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap}; 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::stable_hasher::StableVec;
use rustc_data_structures::svh::Svh; use rustc_data_structures::svh::Svh;
use rustc_data_structures::sync::Lrc; 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; 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 // These are inputs that are expected to be pre-allocated and that
// should therefore always be red or green already. // should therefore always be red or green already.
DepKind::CrateMetadata | 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 // We don't have enough information to reconstruct the query key of
// these. // these.
DepKind::CompileCodegenUnit => { DepKind::CompileCodegenUnit |
// Forcing this makes no sense.
DepKind::Null => {
bug!("force_from_dep_node: encountered {:?}", dep_node) 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 false
} }
pub(crate) fn try_load_from_on_disk_cache<'tcx>(tcx: TyCtxt<'tcx>, dep_node: &DepNode) { 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 { mod sealed {

View file

@ -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 { macro_rules! query_helper_param_ty {
(DefId) => { impl IntoQueryParam<DefId> }; (DefId) => { impl IntoQueryParam<DefId> };
($K:ty) => { $K }; ($K:ty) => { $K };
} }
macro_rules! define_queries_inner { macro_rules! define_queries {
(<$tcx:tt> (<$tcx:tt>
$($(#[$attr:meta])* category<$category:tt> $($(#[$attr:meta])*
[$($modifiers:tt)*] fn $name:ident: $node:ident($($K:tt)*) -> $V:ty,)*) => { [$($modifiers:tt)*] fn $name:ident($($K:tt)*) -> $V:ty,)*) => {
use std::mem; use std::mem;
use crate::{ use crate::{
@ -268,7 +258,6 @@ macro_rules! define_queries_inner {
rustc_data_structures::stable_hasher::StableHasher, rustc_data_structures::stable_hasher::StableHasher,
ich::StableHashingContext ich::StableHashingContext
}; };
use rustc_data_structures::profiling::ProfileCategory;
define_queries_struct! { define_queries_struct! {
tcx: $tcx, tcx: $tcx,
@ -362,13 +351,12 @@ macro_rules! define_queries_inner {
as QueryStorage as QueryStorage
>::Stored; >::Stored;
const NAME: &'static str = stringify!($name); const NAME: &'static str = stringify!($name);
const CATEGORY: ProfileCategory = $category;
} }
impl<$tcx> QueryAccessors<TyCtxt<$tcx>> for queries::$name<$tcx> { impl<$tcx> QueryAccessors<TyCtxt<$tcx>> for queries::$name<$tcx> {
const ANON: bool = is_anon!([$($modifiers)*]); const ANON: bool = is_anon!([$($modifiers)*]);
const EVAL_ALWAYS: bool = is_eval_always!([$($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]); type Cache = query_storage!([$($modifiers)*][$($K)*, $V]);

View file

@ -120,13 +120,13 @@ pub fn print_stats(tcx: TyCtxt<'_>) {
} }
macro_rules! print_stats { macro_rules! print_stats {
(<$tcx:tt> $($category:tt { (<$tcx:tt>
$($(#[$attr:meta])* [$($modifiers:tt)*] fn $name:ident: $node:ident($K:ty) -> $V:ty,)* $($(#[$attr:meta])* [$($modifiers:tt)*] fn $name:ident($K:ty) -> $V:ty,)*
},)*) => { ) => {
fn query_stats(tcx: TyCtxt<'_>) -> Vec<QueryStats> { fn query_stats(tcx: TyCtxt<'_>) -> Vec<QueryStats> {
let mut queries = Vec::new(); let mut queries = Vec::new();
$($( $(
queries.push(stats::< queries.push(stats::<
crate::dep_graph::DepKind, crate::dep_graph::DepKind,
<TyCtxt<'_> as QueryContext>::Query, <TyCtxt<'_> as QueryContext>::Query,
@ -135,7 +135,7 @@ macro_rules! print_stats {
stringify!($name), stringify!($name),
&tcx.queries.$name, &tcx.queries.$name,
)); ));
)*)* )*
queries queries
} }

View file

@ -70,9 +70,10 @@ impl<'mir, 'tcx> InterpCx<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>> {
) -> InterpResult<'tcx> { ) -> InterpResult<'tcx> {
let def_id = instance.def_id(); let def_id = instance.def_id();
if Some(def_id) == self.tcx.lang_items().panic_fn() 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() || Some(def_id) == self.tcx.lang_items().begin_panic_fn()
{ {
// &'static str // &str
assert!(args.len() == 1); assert!(args.len() == 1);
let msg_place = self.deref_operand(args[0])?; let msg_place = self.deref_operand(args[0])?;

View file

@ -74,7 +74,9 @@ impl ConstCx<'mir, 'tcx> {
/// Returns `true` if this `DefId` points to one of the official `panic` lang items. /// 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 { 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 { pub fn allow_internal_unstable(tcx: TyCtxt<'tcx>, def_id: DefId, feature_gate: Symbol) -> bool {

View file

@ -38,19 +38,16 @@ pub struct MatchBranchSimplification;
impl<'tcx> MirPass<'tcx> for MatchBranchSimplification { impl<'tcx> MirPass<'tcx> for MatchBranchSimplification {
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
// FIXME: This optimization can result in unsoundness, because it introduces if tcx.sess.opts.debugging_opts.mir_opt_level <= 1 {
// 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 {
return; return;
} }
let param_env = tcx.param_env(body.source.def_id()); 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() { 'outer: for bb_idx in bbs.indices() {
let (discr, val, switch_ty, first, second) = match bbs[bb_idx].terminator().kind { let (discr, val, switch_ty, first, second) = match bbs[bb_idx].terminator().kind {
TerminatorKind::SwitchInt { TerminatorKind::SwitchInt {
discr: Operand::Copy(ref place) | Operand::Move(ref place), discr: ref discr @ (Operand::Copy(_) | Operand::Move(_)),
switch_ty, switch_ty,
ref targets, ref targets,
.. ..
@ -59,7 +56,7 @@ impl<'tcx> MirPass<'tcx> for MatchBranchSimplification {
if target == targets.otherwise() { if target == targets.otherwise() {
continue; continue;
} }
(place, value, switch_ty, target, targets.otherwise()) (discr, value, switch_ty, target, targets.otherwise())
} }
// Only optimize switch int statements // Only optimize switch int statements
_ => continue, _ => continue,
@ -99,6 +96,10 @@ impl<'tcx> MirPass<'tcx> for MatchBranchSimplification {
// Take ownership of items now that we know we can optimize. // Take ownership of items now that we know we can optimize.
let discr = discr.clone(); 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, // We already checked that first and second are different blocks,
// and bb_idx has a different terminator from both of them. // and bb_idx has a different terminator from both of them.
let (from, first, second) = bbs.pick3_mut(bb_idx, first, second); 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, rustc_span::DUMMY_SP,
); );
let op = if f_b { BinOp::Eq } else { BinOp::Ne }; 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 { Statement {
source_info: f.source_info, source_info: f.source_info,
kind: StatementKind::Assign(box (*lhs, rhs)), kind: StatementKind::Assign(box (*lhs, rhs)),
@ -138,7 +143,16 @@ impl<'tcx> MirPass<'tcx> for MatchBranchSimplification {
_ => unreachable!(), _ => 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.extend(new_stmts);
from.statements
.push(Statement { source_info, kind: StatementKind::StorageDead(discr_local) });
from.terminator_mut().kind = first.terminator().kind.clone(); from.terminator_mut().kind = first.terminator().kind.clone();
} }
} }

View file

@ -1,5 +1,5 @@
use rustc_data_structures::graph::iterate::{ use rustc_data_structures::graph::iterate::{
ControlFlow, NodeStatus, TriColorDepthFirstSearch, TriColorVisitor, NodeStatus, TriColorDepthFirstSearch, TriColorVisitor,
}; };
use rustc_hir::intravisit::FnKind; use rustc_hir::intravisit::FnKind;
use rustc_middle::hir::map::blocks::FnLikeNode; 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_middle::ty::{self, AssocItem, AssocItemContainer, Instance, TyCtxt};
use rustc_session::lint::builtin::UNCONDITIONAL_RECURSION; use rustc_session::lint::builtin::UNCONDITIONAL_RECURSION;
use rustc_span::Span; use rustc_span::Span;
use std::ops::ControlFlow;
crate fn check<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) { crate fn check<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
let def_id = body.source.def_id().expect_local(); let def_id = body.source.def_id().expect_local();

View file

@ -302,10 +302,9 @@ use super::{FieldPat, Pat, PatKind, PatRange};
use rustc_arena::TypedArena; use rustc_arena::TypedArena;
use rustc_attr::{SignedInt, UnsignedInt}; use rustc_attr::{SignedInt, UnsignedInt};
use rustc_errors::ErrorReported;
use rustc_hir::def_id::DefId; use rustc_hir::def_id::DefId;
use rustc_hir::{HirId, RangeEnd}; 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::mir::Field;
use rustc_middle::ty::layout::IntegerExt; use rustc_middle::ty::layout::IntegerExt;
use rustc_middle::ty::{self, Const, Ty, TyCtxt}; 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 rustc_target::abi::{Integer, Size, VariantIdx};
use smallvec::{smallvec, SmallVec}; use smallvec::{smallvec, SmallVec};
use std::borrow::Cow;
use std::cmp::{self, max, min, Ordering}; use std::cmp::{self, max, min, Ordering};
use std::convert::TryInto;
use std::fmt; use std::fmt;
use std::iter::{FromIterator, IntoIterator}; use std::iter::{FromIterator, IntoIterator};
use std::ops::RangeInclusive; use std::ops::RangeInclusive;
crate fn expand_pattern<'a, 'tcx>(cx: &MatchCheckCtxt<'a, 'tcx>, pat: Pat<'tcx>) -> Pat<'tcx> { crate fn expand_pattern<'tcx>(pat: Pat<'tcx>) -> Pat<'tcx> {
LiteralExpander { tcx: cx.tcx, param_env: cx.param_env }.fold_pattern(&pat) LiteralExpander.fold_pattern(&pat)
} }
struct LiteralExpander<'tcx> { struct LiteralExpander;
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
}
impl<'tcx> LiteralExpander<'tcx> { impl<'tcx> PatternFolder<'tcx> for LiteralExpander {
/// 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> {
fn fold_pattern(&mut self, pat: &Pat<'tcx>) -> Pat<'tcx> { fn fold_pattern(&mut self, pat: &Pat<'tcx>) -> Pat<'tcx> {
debug!("fold_pattern {:?} {:?} {:?}", pat, pat.ty.kind(), pat.kind); debug!("fold_pattern {:?} {:?} {:?}", pat, pat.ty.kind(), pat.kind);
match (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::Binding { subpattern: Some(ref s), .. }) => s.fold_with(self),
(_, &PatKind::AscribeUserType { subpattern: ref s, .. }) => s.fold_with(self), (_, &PatKind::AscribeUserType { subpattern: ref s, .. }) => s.fold_with(self),
_ => pat.super_fold_with(self), _ => pat.super_fold_with(self),
@ -500,9 +412,15 @@ impl<'p, 'tcx> PatStack<'p, 'tcx> {
cx: &mut MatchCheckCtxt<'p, 'tcx>, cx: &mut MatchCheckCtxt<'p, 'tcx>,
constructor: &Constructor<'tcx>, constructor: &Constructor<'tcx>,
ctor_wild_subpatterns: &Fields<'p, 'tcx>, ctor_wild_subpatterns: &Fields<'p, 'tcx>,
is_my_head_ctor: bool,
) -> Option<PatStack<'p, 'tcx>> { ) -> Option<PatStack<'p, 'tcx>> {
let new_fields = let new_fields = specialize_one_pattern(
specialize_one_pattern(cx, self.head(), constructor, ctor_wild_subpatterns)?; cx,
self.head(),
constructor,
ctor_wild_subpatterns,
is_my_head_ctor,
)?;
Some(new_fields.push_on_patstack(&self.0[1..])) Some(new_fields.push_on_patstack(&self.0[1..]))
} }
} }
@ -680,6 +598,7 @@ impl<'p, 'tcx> Matrix<'p, 'tcx> {
cx, cx,
constructor, constructor,
ctor_wild_subpatterns, ctor_wild_subpatterns,
false,
) )
}) })
.collect() .collect()
@ -705,7 +624,9 @@ impl<'p, 'tcx> Matrix<'p, 'tcx> {
SpecializationCache::Incompatible => self SpecializationCache::Incompatible => self
.patterns .patterns
.iter() .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(), .collect(),
} }
} }
@ -725,6 +646,7 @@ impl<'p, 'tcx> Matrix<'p, 'tcx> {
/// +++++++++++++++++++++++++++++ /// +++++++++++++++++++++++++++++
/// + _ + [_, _, tail @ ..] + /// + _ + [_, _, tail @ ..] +
/// +++++++++++++++++++++++++++++ /// +++++++++++++++++++++++++++++
/// ```
impl<'p, 'tcx> fmt::Debug for Matrix<'p, 'tcx> { impl<'p, 'tcx> fmt::Debug for Matrix<'p, 'tcx> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "\n")?; write!(f, "\n")?;
@ -926,42 +848,30 @@ enum Constructor<'tcx> {
Single, Single,
/// Enum variants. /// Enum variants.
Variant(DefId), Variant(DefId),
/// Literal values.
ConstantValue(&'tcx ty::Const<'tcx>),
/// Ranges of integer literal values (`2`, `2..=5` or `2..5`). /// Ranges of integer literal values (`2`, `2..=5` or `2..5`).
IntRange(IntRange<'tcx>), IntRange(IntRange<'tcx>),
/// Ranges of floating-point literal values (`2.0..=5.2`). /// Ranges of floating-point literal values (`2.0..=5.2`).
FloatRange(&'tcx ty::Const<'tcx>, &'tcx ty::Const<'tcx>, RangeEnd), 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. /// Array and slice patterns.
Slice(Slice), 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. /// Fake extra constructor for enums that aren't allowed to be matched exhaustively.
NonExhaustive, NonExhaustive,
} }
impl<'tcx> Constructor<'tcx> { impl<'tcx> Constructor<'tcx> {
fn is_slice(&self) -> bool { fn variant_index_for_adt(&self, adt: &'tcx ty::AdtDef) -> VariantIdx {
match self {
Slice(_) => true,
_ => false,
}
}
fn variant_index_for_adt<'a>(
&self,
cx: &MatchCheckCtxt<'a, 'tcx>,
adt: &'tcx ty::AdtDef,
) -> VariantIdx {
match *self { match *self {
Variant(id) => adt.variant_index_with_id(id), Variant(id) => adt.variant_index_with_id(id),
Single => { Single => {
assert!(!adt.is_enum()); assert!(!adt.is_enum());
VariantIdx::new(0) 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), _ => bug!("bad constructor {:?} for adt {:?}", self, adt),
} }
} }
@ -975,7 +885,7 @@ impl<'tcx> Constructor<'tcx> {
match self { match self {
// Those constructors can only match themselves. // 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()] } if other_ctors.iter().any(|c| c == self) { vec![] } else { vec![self.clone()] }
} }
&Slice(slice) => { &Slice(slice) => {
@ -983,8 +893,6 @@ impl<'tcx> Constructor<'tcx> {
.iter() .iter()
.filter_map(|c: &Constructor<'_>| match c { .filter_map(|c: &Constructor<'_>| match c {
Slice(slice) => Some(*slice), Slice(slice) => Some(*slice),
// FIXME(oli-obk): implement `deref` for `ConstValue`
ConstantValue(..) => None,
_ => bug!("bad slice pattern constructor {:?}", c), _ => bug!("bad slice pattern constructor {:?}", c),
}) })
.map(Slice::value_kind); .map(Slice::value_kind);
@ -1048,6 +956,7 @@ impl<'tcx> Constructor<'tcx> {
} }
// This constructor is never covered by anything else // This constructor is never covered by anything else
NonExhaustive => vec![NonExhaustive], NonExhaustive => vec![NonExhaustive],
Opaque => bug!("unexpected opaque ctor {:?} found in all_ctors", self),
} }
} }
@ -1087,7 +996,7 @@ impl<'tcx> Constructor<'tcx> {
PatKind::Variant { PatKind::Variant {
adt_def: adt, adt_def: adt,
substs, substs,
variant_index: self.variant_index_for_adt(cx, adt), variant_index: self.variant_index_for_adt(adt),
subpatterns, subpatterns,
} }
} else { } else {
@ -1126,10 +1035,11 @@ impl<'tcx> Constructor<'tcx> {
PatKind::Slice { prefix, slice: Some(wild), suffix } 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 }), &FloatRange(lo, hi, end) => PatKind::Range(PatRange { lo, hi, end }),
IntRange(range) => return range.to_pat(cx.tcx), IntRange(range) => return range.to_pat(cx.tcx),
NonExhaustive => PatKind::Wild, NonExhaustive => PatKind::Wild,
Opaque => bug!("we should not try to apply an opaque constructor {:?}", self),
}; };
Pat { ty, span: DUMMY_SP, kind: Box::new(pat) } 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)) 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. /// Convenience; internal use.
fn wildcards_from_tys( fn wildcards_from_tys(
cx: &MatchCheckCtxt<'p, 'tcx>, cx: &MatchCheckCtxt<'p, 'tcx>,
@ -1239,7 +1143,7 @@ impl<'p, 'tcx> Fields<'p, 'tcx> {
// Use T as the sub pattern type of Box<T>. // Use T as the sub pattern type of Box<T>.
Fields::from_single_pattern(wildcard_from_ty(substs.type_at(0))) Fields::from_single_pattern(wildcard_from_ty(substs.type_at(0)))
} else { } 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. // Whether we must not match the fields of this variant exhaustively.
let is_non_exhaustive = let is_non_exhaustive =
variant.is_field_list_non_exhaustive() && !adt.did.is_local(); 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), _ => 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); debug!("Fields::wildcards({:?}, {:?}) = {:#?}", constructor, ty, ret);
ret ret
@ -1600,9 +1504,7 @@ fn all_constructors<'a, 'tcx>(
) )
}; };
match *pcx.ty.kind() { match *pcx.ty.kind() {
ty::Bool => { ty::Bool => vec![make_range(0, 1)],
[true, false].iter().map(|&b| ConstantValue(ty::Const::from_bool(cx.tcx, b))).collect()
}
ty::Array(ref sub_ty, len) if len.try_eval_usize(cx.tcx, cx.param_env).is_some() => { 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); let len = len.eval_usize(cx.tcx, cx.param_env);
if len != 0 && cx.is_uninhabited(sub_ty) { if len != 0 && cx.is_uninhabited(sub_ty) {
@ -1717,7 +1619,7 @@ impl<'tcx> IntRange<'tcx> {
#[inline] #[inline]
fn is_integral(ty: Ty<'_>) -> bool { fn is_integral(ty: Ty<'_>) -> bool {
match ty.kind() { match ty.kind() {
ty::Char | ty::Int(_) | ty::Uint(_) => true, ty::Char | ty::Int(_) | ty::Uint(_) | ty::Bool => true,
_ => false, _ => false,
} }
} }
@ -1739,6 +1641,7 @@ impl<'tcx> IntRange<'tcx> {
#[inline] #[inline]
fn integral_size_and_signed_bias(tcx: TyCtxt<'tcx>, ty: Ty<'_>) -> Option<(Size, u128)> { fn integral_size_and_signed_bias(tcx: TyCtxt<'tcx>, ty: Ty<'_>) -> Option<(Size, u128)> {
match *ty.kind() { match *ty.kind() {
ty::Bool => Some((Size::from_bytes(1), 0)),
ty::Char => Some((Size::from_bytes(4), 0)), ty::Char => Some((Size::from_bytes(4), 0)),
ty::Int(ity) => { ty::Int(ity) => {
let size = Integer::from_attr(&tcx, SignedInt(ity)).size(); 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. // We cache the result of `Fields::wildcards` because it is used a lot.
let ctor_wild_subpatterns = Fields::wildcards(cx, &ctor, ty); let ctor_wild_subpatterns = Fields::wildcards(cx, &ctor, ty);
let matrix = matrix.specialize_constructor(cx, &ctor, &ctor_wild_subpatterns); 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(|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)) .map(|u| u.apply_constructor(cx, &ctor, ty, &ctor_wild_subpatterns))
.unwrap_or(NotUseful) .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) { if let Some(int_range) = IntRange::from_const(tcx, param_env, value, pat.span) {
Some(IntRange(int_range)) Some(IntRange(int_range))
} else { } else {
match (value.val, &value.ty.kind()) { match value.ty.kind() {
(_, ty::Array(_, n)) => { ty::Float(_) => Some(FloatRange(value, value, RangeEnd::Included)),
let len = n.eval_usize(tcx, param_env); ty::Ref(_, t, _) if t.is_str() => Some(Str(value)),
Some(Slice(Slice { array_len: Some(len), kind: FixedLen(len) })) // All constants that can be structurally matched have already been expanded
} // into the corresponding `Pat`s by `const_to_pat`. Constants that remain are
(ty::ConstKind::Value(ConstValue::Slice { start, end, .. }), ty::Slice(_)) => { // opaque.
let len = (end - start) as u64; _ => Some(Opaque),
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)),
} }
} }
} }
@ -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 /// For exhaustive integer matching, some constructors are grouped within other constructors
/// (namely integer typed values are grouped within ranges). However, when specialising these /// (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 /// 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 /// This is the main specialization step. It expands the pattern
/// into `arity` patterns based on the constructor. For most patterns, the step is trivial, /// 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. /// 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>, pat: &'p Pat<'tcx>,
constructor: &Constructor<'tcx>, constructor: &Constructor<'tcx>,
ctor_wild_subpatterns: &Fields<'p, '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>> { ) -> Option<Fields<'p, 'tcx>> {
if let NonExhaustive = constructor { 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() { if !pat.is_wildcard() {
return None; return None;
} }
return Some(Fields::empty()); 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 { let result = match *pat.kind {
PatKind::AscribeUserType { .. } => bug!(), // Handled by `expand_pattern` 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::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 { .. } => { PatKind::Constant { .. } | PatKind::Range { .. } => {
// If the constructor is a: match constructor {
// - Single value: add a row if the pattern contains the constructor. IntRange(ctor) => {
// - Range: add a row if the constructor intersects the pattern.
if let IntRange(ctor) = constructor {
let pat = IntRange::from_pat(cx.tcx, cx.param_env, pat)?; let pat = IntRange::from_pat(cx.tcx, cx.param_env, pat)?;
ctor.intersection(cx.tcx, &pat)?; ctor.intersection(cx.tcx, &pat)?;
// Constructor splitting should ensure that all intersections we encounter // Constructor splitting should ensure that all intersections we encounter
// are actually inclusions. // are actually inclusions.
assert!(ctor.is_subrange(&pat)); assert!(ctor.is_subrange(&pat));
} else { }
// Fallback for non-ranges and ranges that involve FloatRange(ctor_from, ctor_to, ctor_end) => {
// floating-point numbers, which are not conveniently handled let (pat_from, pat_to, pat_end, ty) = match *pat.kind {
// by `IntRange`. For these cases, the constructor may not be a PatKind::Constant { value } => (value, value, RangeEnd::Included, value.ty),
// range so intersection actually devolves into being covered PatKind::Range(PatRange { lo, hi, end }) => (lo, hi, end, lo.ty),
// by the pattern. _ => unreachable!(), // This is ensured by the branch we're in
constructor_covered_by_range(cx.tcx, cx.param_env, constructor, pat)?; };
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()) 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)); let suffix = suffix.iter().enumerate().map(|(i, p)| (arity - suffix.len() + i, p));
Some(ctor_wild_subpatterns.replace_fields_indexed(prefix.chain(suffix))) 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), _ => span_bug!(pat.span, "unexpected ctor {:?} for slice pat", constructor),
}, },

View file

@ -137,7 +137,7 @@ impl<'tcx> MatchVisitor<'_, 'tcx> {
patcx.include_lint_checks(); patcx.include_lint_checks();
let pattern = patcx.lower_pattern(pat); let pattern = patcx.lower_pattern(pat);
let pattern_ty = pattern.ty; 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() { if !patcx.errors.is_empty() {
*have_errors = true; *have_errors = true;
patcx.report_inlining_errors(pat.span); patcx.report_inlining_errors(pat.span);

View file

@ -387,14 +387,16 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
// `&str` and `&[u8]` are represented as `ConstValue::Slice`, let's keep using this // `&str` and `&[u8]` are represented as `ConstValue::Slice`, let's keep using this
// optimization for now. // optimization for now.
ty::Str => PatKind::Constant { value: cv }, 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 // `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. // matching against references, you can only use byte string literals.
// FIXME: clean this up, likely by permitting array patterns when matching on slices // The typechecker has a special case for byte string literals, by treating them
ty::Array(elem_ty, _) if elem_ty == tcx.types.u8 => PatKind::Constant { value: cv }, // 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` // 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 // changes the type from slice to array, we need to keep the original type in the
// array patterns. // pattern.
ty::Slice(..) => { ty::Slice(..) => {
let old = self.behind_reference.replace(true); let old = self.behind_reference.replace(true);
let array = tcx.deref_const(self.param_env.and(cv)); let array = tcx.deref_const(self.param_env.and(cv));

View file

@ -158,6 +158,13 @@ crate enum PatKind<'tcx> {
subpattern: Pat<'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 { Constant {
value: &'tcx ty::Const<'tcx>, value: &'tcx ty::Const<'tcx>,
}, },

View file

@ -5,7 +5,6 @@ use crate::dep_graph::SerializedDepNodeIndex;
use crate::query::caches::QueryCache; use crate::query::caches::QueryCache;
use crate::query::plumbing::CycleError; use crate::query::plumbing::CycleError;
use crate::query::{QueryContext, QueryState}; use crate::query::{QueryContext, QueryState};
use rustc_data_structures::profiling::ProfileCategory;
use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fingerprint::Fingerprint;
use std::borrow::Cow; use std::borrow::Cow;
@ -14,7 +13,6 @@ use std::hash::Hash;
pub trait QueryConfig { pub trait QueryConfig {
const NAME: &'static str; const NAME: &'static str;
const CATEGORY: ProfileCategory;
type Key: Eq + Hash + Clone + Debug; type Key: Eq + Hash + Clone + Debug;
type Value; type Value;

View file

@ -19,7 +19,7 @@ use rustc_feature::is_builtin_attr_name;
use rustc_hir::def::{self, DefKind, NonMacroAttrKind}; use rustc_hir::def::{self, DefKind, NonMacroAttrKind};
use rustc_hir::def_id; use rustc_hir::def_id;
use rustc_middle::middle::stability; 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::lint::builtin::UNUSED_MACROS;
use rustc_session::Session; use rustc_session::Session;
use rustc_span::edition::Edition; use rustc_span::edition::Edition;
@ -885,11 +885,11 @@ impl<'a> Resolver<'a> {
initial_res: Option<Res>, initial_res: Option<Res>,
res: Res| { res: Res| {
if let Some(initial_res) = initial_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 // Make sure compilation does not succeed if preferred macro resolution
// has changed after the macro had been expanded. In theory all such // has changed after the macro had been expanded. In theory all such
// situations should be reported as ambiguity errors, so this is a bug. // situations should be reported as errors, so this is a bug.
span_bug!(span, "inconsistent resolution for a macro"); this.session.delay_span_bug(span, "inconsistent resolution for a macro");
} }
} else { } else {
// It's possible that the macro was unresolved (indeterminate) and silently // It's possible that the macro was unresolved (indeterminate) and silently

View file

@ -777,6 +777,7 @@ symbols! {
panic_info, panic_info,
panic_location, panic_location,
panic_runtime, panic_runtime,
panic_str,
panic_unwind, panic_unwind,
param_attrs, param_attrs,
parent_trait, parent_trait,

View file

@ -121,7 +121,10 @@ where
// contains unbound type parameters. It could be a slight // contains unbound type parameters. It could be a slight
// optimization to stop iterating early. // optimization to stop iterating early.
if let Err(errors) = fulfill_cx.select_all_or_error(infcx) { 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); let result = infcx.resolve_vars_if_possible(result);

View file

@ -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> { struct AbstractConstBuilder<'a, 'tcx> {
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
body: &'a mir::Body<'tcx>, body: &'a mir::Body<'tcx>,
/// The current WIP node tree. /// 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>, locals: IndexVec<mir::Local, NodeId>,
/// We only allow field accesses if they access /// We only allow field accesses if they access
/// the result of a checked operation. /// the result of a checked operation.
@ -274,6 +286,27 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
Ok(Some(builder)) 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( fn place_to_local(
&mut self, &mut self,
span: Span, span: Span,
@ -311,7 +344,7 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
let local = self.place_to_local(span, p)?; let local = self.place_to_local(span, p)?;
Ok(self.locals[local]) 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> { fn build_statement(&mut self, stmt: &mir::Statement<'tcx>) -> Result<(), ErrorReported> {
debug!("AbstractConstBuilder: stmt={:?}", stmt); debug!("AbstractConstBuilder: stmt={:?}", stmt);
let span = stmt.source_info.span;
match stmt.kind { match stmt.kind {
StatementKind::Assign(box (ref place, ref rvalue)) => { 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 { match *rvalue {
Rvalue::Use(ref operand) => { Rvalue::Use(ref operand) => {
self.locals[local] = self.locals[local] = self.operand_to_node(span, operand)?;
self.operand_to_node(stmt.source_info.span, operand)?;
Ok(()) Ok(())
} }
Rvalue::BinaryOp(op, ref lhs, ref rhs) if Self::check_binop(op) => { Rvalue::BinaryOp(op, ref lhs, ref rhs) if Self::check_binop(op) => {
let lhs = self.operand_to_node(stmt.source_info.span, lhs)?; let lhs = self.operand_to_node(span, lhs)?;
let rhs = self.operand_to_node(stmt.source_info.span, rhs)?; let rhs = self.operand_to_node(span, rhs)?;
self.locals[local] = self.nodes.push(Node::Binop(op, lhs, rhs)); self.locals[local] = self.add_node(Node::Binop(op, lhs, rhs), span);
if op.is_checkable() { if op.is_checkable() {
bug!("unexpected unchecked checkable binary operation"); bug!("unexpected unchecked checkable binary operation");
} else { } else {
@ -356,18 +389,18 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
} }
} }
Rvalue::CheckedBinaryOp(op, ref lhs, ref rhs) if Self::check_binop(op) => { Rvalue::CheckedBinaryOp(op, ref lhs, ref rhs) if Self::check_binop(op) => {
let lhs = self.operand_to_node(stmt.source_info.span, lhs)?; let lhs = self.operand_to_node(span, lhs)?;
let rhs = self.operand_to_node(stmt.source_info.span, rhs)?; let rhs = self.operand_to_node(span, rhs)?;
self.locals[local] = self.nodes.push(Node::Binop(op, lhs, rhs)); self.locals[local] = self.add_node(Node::Binop(op, lhs, rhs), span);
self.checked_op_locals.insert(local); self.checked_op_locals.insert(local);
Ok(()) Ok(())
} }
Rvalue::UnaryOp(op, ref operand) if Self::check_unop(op) => { Rvalue::UnaryOp(op, ref operand) if Self::check_unop(op) => {
let operand = self.operand_to_node(stmt.source_info.span, operand)?; let operand = self.operand_to_node(span, operand)?;
self.locals[local] = self.nodes.push(Node::UnaryOp(op, operand)); self.locals[local] = self.add_node(Node::UnaryOp(op, operand), span);
Ok(()) 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. // 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)) .map(|arg| self.operand_to_node(terminator.source_info.span, arg))
.collect::<Result<Vec<NodeId>, _>>()?, .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)) 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, .. } => { TerminatorKind::Assert { ref cond, expected: false, target, .. } => {
let p = match cond { let p = match cond {
mir::Operand::Copy(p) | mir::Operand::Move(p) => p, 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); const ONE_FIELD: mir::Field = mir::Field::from_usize(1);
debug!("proj: {:?}", p.projection); 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. // Only allow asserts checking the result of a checked operation.
if self.checked_op_locals.contains(p.local) { if self.checked_op_locals.contains(p.local) {
return Ok(Some(target)); return Ok(Some(target));
@ -457,7 +494,13 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
if let Some(next) = self.build_terminator(block.terminator())? { if let Some(next) = self.build_terminator(block.terminator())? {
block = &self.body.basic_blocks()[next]; block = &self.body.basic_blocks()[next];
} else { } 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)));
} }
} }
} }

View file

@ -372,7 +372,7 @@ pub fn handle_alloc_error(layout: Layout) -> ! {
unsafe { oom_impl(layout) } unsafe { oom_impl(layout) }
} }
#[cfg(not(any(test, bootstrap)))] #[cfg(not(any(target_os = "hermit", test, bootstrap)))]
#[doc(hidden)] #[doc(hidden)]
#[allow(unused_attributes)] #[allow(unused_attributes)]
#[unstable(feature = "alloc_internals", issue = "none")] #[unstable(feature = "alloc_internals", issue = "none")]

View file

@ -1280,7 +1280,7 @@ where
#[inline] #[inline]
fn find<T, B>( fn find<T, B>(
f: &mut impl FnMut(T) -> Option<B>, f: &mut impl FnMut(T) -> Option<B>,
) -> impl FnMut((), T) -> ControlFlow<(), B> + '_ { ) -> impl FnMut((), T) -> ControlFlow<B> + '_ {
move |(), x| match f(x) { move |(), x| match f(x) {
Some(x) => ControlFlow::Break(x), Some(x) => ControlFlow::Break(x),
None => ControlFlow::CONTINUE, None => ControlFlow::CONTINUE,
@ -2059,7 +2059,7 @@ where
flag: &'a mut bool, flag: &'a mut bool,
p: &'a mut impl FnMut(&T) -> bool, p: &'a mut impl FnMut(&T) -> bool,
mut fold: impl FnMut(Acc, T) -> R + 'a, 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| { move |acc, x| {
if p(&x) { if p(&x) {
ControlFlow::from_try(fold(acc, x)) ControlFlow::from_try(fold(acc, x))
@ -2372,7 +2372,7 @@ where
fn check<T, Acc, R: Try<Ok = Acc>>( fn check<T, Acc, R: Try<Ok = Acc>>(
mut n: usize, mut n: usize,
mut fold: impl FnMut(Acc, T) -> R, mut fold: impl FnMut(Acc, T) -> R,
) -> impl FnMut(Acc, T) -> ControlFlow<Acc, R> { ) -> impl FnMut(Acc, T) -> ControlFlow<R, Acc> {
move |acc, x| { move |acc, x| {
n -= 1; n -= 1;
let r = fold(acc, x); let r = fold(acc, x);
@ -2496,7 +2496,7 @@ where
fn check<'a, T, Acc, R: Try<Ok = Acc>>( fn check<'a, T, Acc, R: Try<Ok = Acc>>(
n: &'a mut usize, n: &'a mut usize,
mut fold: impl FnMut(Acc, T) -> R + 'a, 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| { move |acc, x| {
*n -= 1; *n -= 1;
let r = fold(acc, x); let r = fold(acc, x);
@ -2681,7 +2681,7 @@ where
state: &'a mut St, state: &'a mut St,
f: &'a mut impl FnMut(&mut St, T) -> Option<B>, f: &'a mut impl FnMut(&mut St, T) -> Option<B>,
mut fold: impl FnMut(Acc, B) -> R + 'a, 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) { move |acc, x| match f(state, x) {
None => ControlFlow::Break(try { acc }), None => ControlFlow::Break(try { acc }),
Some(x) => ControlFlow::from_try(fold(acc, x)), Some(x) => ControlFlow::from_try(fold(acc, x)),

View file

@ -339,9 +339,7 @@ pub trait DoubleEndedIterator: Iterator {
P: FnMut(&Self::Item) -> bool, P: FnMut(&Self::Item) -> bool,
{ {
#[inline] #[inline]
fn check<T>( fn check<T>(mut predicate: impl FnMut(&T) -> bool) -> impl FnMut((), T) -> ControlFlow<T> {
mut predicate: impl FnMut(&T) -> bool,
) -> impl FnMut((), T) -> ControlFlow<(), T> {
move |(), x| { move |(), x| {
if predicate(&x) { ControlFlow::Break(x) } else { ControlFlow::CONTINUE } if predicate(&x) { ControlFlow::Break(x) } else { ControlFlow::CONTINUE }
} }

View file

@ -2109,7 +2109,7 @@ pub trait Iterator {
F: FnMut(Self::Item) -> bool, F: FnMut(Self::Item) -> bool,
{ {
#[inline] #[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| { move |(), x| {
if f(x) { ControlFlow::CONTINUE } else { ControlFlow::BREAK } if f(x) { ControlFlow::CONTINUE } else { ControlFlow::BREAK }
} }
@ -2162,7 +2162,7 @@ pub trait Iterator {
F: FnMut(Self::Item) -> bool, F: FnMut(Self::Item) -> bool,
{ {
#[inline] #[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| { move |(), x| {
if f(x) { ControlFlow::BREAK } else { ControlFlow::CONTINUE } if f(x) { ControlFlow::BREAK } else { ControlFlow::CONTINUE }
} }
@ -2222,9 +2222,7 @@ pub trait Iterator {
P: FnMut(&Self::Item) -> bool, P: FnMut(&Self::Item) -> bool,
{ {
#[inline] #[inline]
fn check<T>( fn check<T>(mut predicate: impl FnMut(&T) -> bool) -> impl FnMut((), T) -> ControlFlow<T> {
mut predicate: impl FnMut(&T) -> bool,
) -> impl FnMut((), T) -> ControlFlow<(), T> {
move |(), x| { move |(), x| {
if predicate(&x) { ControlFlow::Break(x) } else { ControlFlow::CONTINUE } if predicate(&x) { ControlFlow::Break(x) } else { ControlFlow::CONTINUE }
} }
@ -2255,9 +2253,7 @@ pub trait Iterator {
F: FnMut(Self::Item) -> Option<B>, F: FnMut(Self::Item) -> Option<B>,
{ {
#[inline] #[inline]
fn check<T, B>( fn check<T, B>(mut f: impl FnMut(T) -> Option<B>) -> impl FnMut((), T) -> ControlFlow<B> {
mut f: impl FnMut(T) -> Option<B>,
) -> impl FnMut((), T) -> ControlFlow<(), B> {
move |(), x| match f(x) { move |(), x| match f(x) {
Some(x) => ControlFlow::Break(x), Some(x) => ControlFlow::Break(x),
None => ControlFlow::CONTINUE, None => ControlFlow::CONTINUE,
@ -2296,7 +2292,7 @@ pub trait Iterator {
R: Try<Ok = bool>, R: Try<Ok = bool>,
{ {
#[inline] #[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 where
F: FnMut(&T) -> R, F: FnMut(&T) -> R,
R: Try<Ok = bool>, R: Try<Ok = bool>,

View file

@ -10,7 +10,7 @@ macro_rules! panic {
$crate::panicking::panic($msg) $crate::panicking::panic($msg)
); );
($msg:expr) => ( ($msg:expr) => (
$crate::panic!("{}", $crate::convert::identity::<&str>($msg)) $crate::panicking::panic_str($msg)
); );
($msg:expr,) => ( ($msg:expr,) => (
$crate::panic!($msg) $crate::panic!($msg)

View file

@ -3,7 +3,7 @@ use crate::ops::Try;
/// Used to make try_fold closures more like normal loops /// Used to make try_fold closures more like normal loops
#[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")] #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
#[derive(Debug, Clone, Copy, PartialEq)] #[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 in the loop, using the given value for the next iteration
Continue(C), Continue(C),
/// Exit the loop, yielding the given value /// 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")] #[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 Ok = C;
type Error = B; type Error = B;
#[inline] #[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. /// Returns `true` if this is a `Break` variant.
#[inline] #[inline]
#[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")] #[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`. /// Create a `ControlFlow` from any type implementing `Try`.
#[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")] #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
#[inline] #[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`, /// 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. /// 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(()); 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`, /// APIs like `try_for_each` don't need values with `Break`,
/// so this provides a way to avoid typing `(())`, if you prefer it. /// so this provides a way to avoid typing `(())`, if you prefer it.
/// ///

View file

@ -50,6 +50,13 @@ pub fn panic(expr: &'static str) -> ! {
panic_fmt(fmt::Arguments::new_v1(&[expr], &[])); 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] #[cold]
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))] #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
#[track_caller] #[track_caller]

View file

@ -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'] } 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] [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] [target.wasm32-wasi.dependencies]
wasi = { version = "0.9.0", features = ['rustc-dep-of-std'], default-features = false } wasi = { version = "0.9.0", features = ['rustc-dep-of-std'], default-features = false }

View file

@ -259,6 +259,7 @@
#![feature(exhaustive_patterns)] #![feature(exhaustive_patterns)]
#![feature(extend_one)] #![feature(extend_one)]
#![feature(external_doc)] #![feature(external_doc)]
#![feature(fmt_as_str)]
#![feature(fn_traits)] #![feature(fn_traits)]
#![feature(format_args_nl)] #![feature(format_args_nl)]
#![feature(gen_future)] #![feature(gen_future)]

View file

@ -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 loc = info.location().unwrap(); // The current implementation always returns Some
let msg = info.message().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 || { 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); rust_panic_with_hook(&mut PanicPayload::new(msg), info.message(), loc);
}
}) })
} }

View file

@ -1910,7 +1910,7 @@ extern "C" {
/// The resolution of the clock. /// The resolution of the clock.
#[inline] #[inline]
pub unsafe fn clock_res_get(clock_id_: clockid, resolution_: &mut timestamp) -> errno { 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. /// Obtains the time value of a clock.
@ -1934,7 +1934,7 @@ pub unsafe fn clock_time_get(
precision_: timestamp, precision_: timestamp,
time_: *mut timestamp, time_: *mut timestamp,
) -> errno { ) -> 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. /// 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. /// threads, all threads are woken up.
#[inline] #[inline]
pub unsafe fn condvar_signal(condvar_: *mut condvar, scope_: scope, nwaiters_: nthreads) -> errno { 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. /// 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. /// The file descriptor that needs to be closed.
#[inline] #[inline]
pub unsafe fn fd_close(fd_: fd) -> errno { pub unsafe fn fd_close(fd_: fd) -> errno {
cloudabi_sys_fd_close(fd_) unsafe { cloudabi_sys_fd_close(fd_) }
} }
/// Creates a file descriptor. /// Creates a file descriptor.
@ -1990,7 +1990,7 @@ pub unsafe fn fd_close(fd_: fd) -> errno {
/// The file descriptor that has been created. /// The file descriptor that has been created.
#[inline] #[inline]
pub unsafe fn fd_create1(type_: filetype, fd_: &mut fd) -> errno { 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. /// 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. /// The second file descriptor of the pair.
#[inline] #[inline]
pub unsafe fn fd_create2(type_: filetype, fd1_: &mut fd, fd2_: &mut fd) -> errno { 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. /// 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. /// needs to be synchronized to disk.
#[inline] #[inline]
pub unsafe fn fd_datasync(fd_: fd) -> errno { 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. /// Duplicates a file descriptor.
@ -2040,7 +2043,7 @@ pub unsafe fn fd_datasync(fd_: fd) -> errno {
/// The new file descriptor. /// The new file descriptor.
#[inline] #[inline]
pub unsafe fn fd_dup(from_: fd, fd_: &mut fd) -> errno { 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 /// 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. /// The number of bytes read.
#[inline] #[inline]
pub unsafe fn fd_pread(fd_: fd, iovs_: &[iovec], offset_: filesize, nread_: &mut usize) -> errno { 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 /// Writes to a file descriptor, without using and updating the
@ -2093,7 +2096,7 @@ pub unsafe fn fd_pwrite(
offset_: filesize, offset_: filesize,
nwritten_: &mut usize, nwritten_: &mut usize,
) -> errno { ) -> 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. /// Reads from a file descriptor.
@ -2112,7 +2115,7 @@ pub unsafe fn fd_pwrite(
/// The number of bytes read. /// The number of bytes read.
#[inline] #[inline]
pub unsafe fn fd_read(fd_: fd, iovs_: &[iovec], nread_: &mut usize) -> errno { 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 /// 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. /// overwritten.
#[inline] #[inline]
pub unsafe fn fd_replace(from_: fd, to_: fd) -> errno { 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. /// Moves the offset of the file descriptor.
@ -2166,7 +2169,7 @@ pub unsafe fn fd_seek(
whence_: whence, whence_: whence,
newoffset_: &mut filesize, newoffset_: &mut filesize,
) -> errno { ) -> errno {
cloudabi_sys_fd_seek(fd_, offset_, whence_, newoffset_) unsafe { cloudabi_sys_fd_seek(fd_, offset_, whence_, newoffset_) }
} }
/// Gets attributes of a file descriptor. /// Gets attributes of a file descriptor.
@ -2182,7 +2185,7 @@ pub unsafe fn fd_seek(
/// attributes are stored. /// attributes are stored.
#[inline] #[inline]
pub unsafe fn fd_stat_get(fd_: fd, buf_: *mut fdstat) -> errno { 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. /// Adjusts attributes of a file descriptor.
@ -2202,7 +2205,7 @@ pub unsafe fn fd_stat_get(fd_: fd, buf_: *mut fdstat) -> errno {
/// be adjusted. /// be adjusted.
#[inline] #[inline]
pub unsafe fn fd_stat_put(fd_: fd, buf_: *const fdstat, flags_: fdsflags) -> errno { 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. /// 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. /// and metadata needs to be synchronized to disk.
#[inline] #[inline]
pub unsafe fn fd_sync(fd_: fd) -> errno { pub unsafe fn fd_sync(fd_: fd) -> errno {
cloudabi_sys_fd_sync(fd_) unsafe { cloudabi_sys_fd_sync(fd_) }
} }
/// Writes to a file descriptor. /// Writes to a file descriptor.
@ -2233,7 +2236,7 @@ pub unsafe fn fd_sync(fd_: fd) -> errno {
/// The number of bytes written. /// The number of bytes written.
#[inline] #[inline]
pub unsafe fn fd_write(fd_: fd, iovs_: &[ciovec], nwritten_: &mut usize) -> errno { 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. /// 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. /// The advice.
#[inline] #[inline]
pub unsafe fn file_advise(fd_: fd, offset_: filesize, len_: filesize, advice_: advice) -> errno { 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. /// 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. /// The length of the area that is allocated.
#[inline] #[inline]
pub unsafe fn file_allocate(fd_: fd, offset_: filesize, len_: filesize) -> errno { 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. /// 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. /// Creates a directory.
#[inline] #[inline]
pub unsafe fn file_create(fd_: fd, path_: &[u8], type_: filetype) -> errno { 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. /// Creates a hard link.
@ -2320,7 +2323,7 @@ pub unsafe fn file_create(fd_: fd, path_: &[u8], type_: filetype) -> errno {
/// should be created. /// should be created.
#[inline] #[inline]
pub unsafe fn file_link(fd1_: lookup, path1_: &[u8], fd2_: fd, path2_: &[u8]) -> errno { 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. /// Opens a file.
@ -2362,7 +2365,7 @@ pub unsafe fn file_open(
fds_: *const fdstat, fds_: *const fdstat,
fd_: &mut fd, fd_: &mut fd,
) -> errno { ) -> 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. /// Reads directory entries from a directory.
@ -2402,7 +2405,7 @@ pub unsafe fn file_readdir(
cookie_: dircookie, cookie_: dircookie,
bufused_: &mut usize, bufused_: &mut usize,
) -> errno { ) -> 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. /// Reads the contents of a symbolic link.
@ -2425,6 +2428,7 @@ pub unsafe fn file_readdir(
/// The number of bytes placed in the buffer. /// The number of bytes placed in the buffer.
#[inline] #[inline]
pub unsafe fn file_readlink(fd_: fd, path_: &[u8], buf_: &mut [u8], bufused_: &mut usize) -> errno { pub unsafe fn file_readlink(fd_: fd, path_: &[u8], buf_: &mut [u8], bufused_: &mut usize) -> errno {
unsafe {
cloudabi_sys_file_readlink( cloudabi_sys_file_readlink(
fd_, fd_,
path_.as_ptr(), path_.as_ptr(),
@ -2434,6 +2438,7 @@ pub unsafe fn file_readlink(fd_: fd, path_: &[u8], buf_: &mut [u8], bufused_: &m
bufused_, bufused_,
) )
} }
}
/// Renames a file. /// Renames a file.
/// ///
@ -2456,6 +2461,7 @@ pub unsafe fn file_readlink(fd_: fd, path_: &[u8], buf_: &mut [u8], bufused_: &m
/// be renamed. /// be renamed.
#[inline] #[inline]
pub unsafe fn file_rename(fd1_: fd, path1_: &[u8], fd2_: fd, path2_: &[u8]) -> errno { pub unsafe fn file_rename(fd1_: fd, path1_: &[u8], fd2_: fd, path2_: &[u8]) -> errno {
unsafe {
cloudabi_sys_file_rename( cloudabi_sys_file_rename(
fd1_, fd1_,
path1_.as_ptr(), path1_.as_ptr(),
@ -2465,6 +2471,7 @@ pub unsafe fn file_rename(fd1_: fd, path1_: &[u8], fd2_: fd, path2_: &[u8]) -> e
path2_.len(), path2_.len(),
) )
} }
}
/// Gets attributes of a file by file descriptor. /// 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. /// stored.
#[inline] #[inline]
pub unsafe fn file_stat_fget(fd_: fd, buf_: *mut filestat) -> errno { 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. /// 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. /// be adjusted.
#[inline] #[inline]
pub unsafe fn file_stat_fput(fd_: fd, buf_: *const filestat, flags_: fsflags) -> errno { 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. /// 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. /// stored.
#[inline] #[inline]
pub unsafe fn file_stat_get(fd_: lookup, path_: &[u8], buf_: *mut filestat) -> errno { 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. /// Adjusts attributes of a file by path.
@ -2550,7 +2557,7 @@ pub unsafe fn file_stat_put(
buf_: *const filestat, buf_: *const filestat,
flags_: fsflags, flags_: fsflags,
) -> errno { ) -> 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. /// Creates a symbolic link.
@ -2569,7 +2576,7 @@ pub unsafe fn file_stat_put(
/// link should be created. /// link should be created.
#[inline] #[inline]
pub unsafe fn file_symlink(path1_: &[u8], fd_: fd, path2_: &[u8]) -> errno { 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. /// 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. /// Otherwise, unlink a file.
#[inline] #[inline]
pub unsafe fn file_unlink(fd_: fd, path_: &[u8], flags_: ulflags) -> errno { 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. /// Unlocks a write-locked userspace lock.
@ -2618,7 +2625,7 @@ pub unsafe fn file_unlink(fd_: fd, path_: &[u8], flags_: ulflags) -> errno {
/// shared memory. /// shared memory.
#[inline] #[inline]
pub unsafe fn lock_unlock(lock_: *mut lock, scope_: scope) -> errno { 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. /// 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. /// The advice.
#[inline] #[inline]
pub unsafe fn mem_advise(mapping_: &mut [u8], advice_: advice) -> errno { 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 /// Creates a memory mapping, making the contents of a file
@ -2682,7 +2689,7 @@ pub unsafe fn mem_map(
off_: filesize, off_: filesize,
mem_: &mut *mut (), mem_: &mut *mut (),
) -> errno { ) -> 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. /// Changes the protection of a memory mapping.
@ -2696,7 +2703,7 @@ pub unsafe fn mem_map(
/// New protection options. /// New protection options.
#[inline] #[inline]
pub unsafe fn mem_protect(mapping_: &mut [u8], prot_: mprot) -> errno { 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. /// 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. /// The method of synchronization.
#[inline] #[inline]
pub unsafe fn mem_sync(mapping_: &mut [u8], flags_: msflags) -> errno { 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. /// 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. /// The pages that needs to be unmapped.
#[inline] #[inline]
pub unsafe fn mem_unmap(mapping_: &mut [u8]) -> errno { 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. /// Concurrently polls for the occurrence of a set of events.
@ -2746,7 +2753,7 @@ pub unsafe fn poll(
nsubscriptions_: usize, nsubscriptions_: usize,
nevents_: *mut usize, nevents_: *mut usize,
) -> errno { ) -> errno {
cloudabi_sys_poll(in_, out_, nsubscriptions_, nevents_) unsafe { cloudabi_sys_poll(in_, out_, nsubscriptions_, nevents_) }
} }
/// Replaces the process by a new executable. /// Replaces the process by a new executable.
@ -2784,7 +2791,7 @@ pub unsafe fn poll(
/// execution. /// execution.
#[inline] #[inline]
pub unsafe fn proc_exec(fd_: fd, data_: &[u8], fds_: &[fd]) -> errno { 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. /// 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). /// through [`event.union.proc_terminate.exitcode`](struct.event_proc_terminate.html#structfield.exitcode).
#[inline] #[inline]
pub unsafe fn proc_exit(rval_: exitcode) -> ! { 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. /// Forks the process of the calling thread.
@ -2822,7 +2829,7 @@ pub unsafe fn proc_exit(rval_: exitcode) -> ! {
/// initial thread of the child process. /// initial thread of the child process.
#[inline] #[inline]
pub unsafe fn proc_fork(fd_: &mut fd, tid_: &mut tid) -> errno { 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. /// 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). /// [`event.union.proc_terminate.signal`](struct.event_proc_terminate.html#structfield.signal).
#[inline] #[inline]
pub unsafe fn proc_raise(sig_: signal) -> errno { 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. /// Obtains random data from the kernel random number generator.
@ -2853,7 +2860,7 @@ pub unsafe fn proc_raise(sig_: signal) -> errno {
/// data. /// data.
#[inline] #[inline]
pub unsafe fn random_get(buf_: &mut [u8]) -> errno { 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. /// Receives a message on a socket.
@ -2871,7 +2878,7 @@ pub unsafe fn random_get(buf_: &mut [u8]) -> errno {
/// Output parameters. /// Output parameters.
#[inline] #[inline]
pub unsafe fn sock_recv(sock_: fd, in_: *const recv_in, out_: *mut recv_out) -> errno { 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. /// 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. /// Output parameters.
#[inline] #[inline]
pub unsafe fn sock_send(sock_: fd, in_: *const send_in, out_: *mut send_out) -> errno { 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. /// 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. /// down.
#[inline] #[inline]
pub unsafe fn sock_shutdown(sock_: fd, how_: sdflags) -> errno { 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. /// 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. /// The thread ID of the new thread.
#[inline] #[inline]
pub unsafe fn thread_create(attr_: *mut threadattr, tid_: &mut tid) -> errno { 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. /// Terminates the calling thread.
@ -2937,11 +2944,11 @@ pub unsafe fn thread_create(attr_: *mut threadattr, tid_: &mut tid) -> errno {
/// shared memory. /// shared memory.
#[inline] #[inline]
pub unsafe fn thread_exit(lock_: *mut lock, scope_: scope) -> ! { 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. /// Temporarily yields execution of the calling thread.
#[inline] #[inline]
pub unsafe fn thread_yield() -> errno { pub unsafe fn thread_yield() -> errno {
cloudabi_sys_thread_yield() unsafe { cloudabi_sys_thread_yield() }
} }

View file

@ -1,3 +1,5 @@
#![deny(unsafe_op_in_unsafe_fn)]
use crate::io::ErrorKind; use crate::io::ErrorKind;
use crate::mem; use crate::mem;

View file

@ -103,7 +103,9 @@ impl ReentrantMutex {
}; };
let mut event = MaybeUninit::<abi::event>::uninit(); let mut event = MaybeUninit::<abi::event>::uninit();
let mut nevents = MaybeUninit::<usize>::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"); assert_eq!(ret, abi::errno::SUCCESS, "Failed to acquire mutex");
let event = event.assume_init(); let event = event.assume_init();
assert_eq!(event.error, abi::errno::SUCCESS, "Failed to acquire mutex"); assert_eq!(event.error, abi::errno::SUCCESS, "Failed to acquire mutex");

View file

@ -334,10 +334,6 @@ impl File {
pub fn set_permissions(&self, _perm: FilePermissions) -> io::Result<()> { pub fn set_permissions(&self, _perm: FilePermissions) -> io::Result<()> {
Err(Error::from_raw_os_error(22)) Err(Error::from_raw_os_error(22))
} }
pub fn diverge(&self) -> ! {
loop {}
}
} }
impl DirBuilder { impl DirBuilder {

View file

@ -31,6 +31,7 @@ pub mod net;
pub mod os; pub mod os;
pub mod path; pub mod path;
pub mod pipe; pub mod pipe;
#[path = "../unsupported/process.rs"]
pub mod process; pub mod process;
pub mod rwlock; pub mod rwlock;
pub mod stack_overflow; pub mod stack_overflow;

View file

@ -1,44 +1,214 @@
use crate::cell::UnsafeCell;
use crate::collections::VecDeque;
use crate::ffi::c_void; use crate::ffi::c_void;
use crate::ops::{Deref, DerefMut, Drop};
use crate::ptr; use crate::ptr;
use crate::sync::atomic::{spin_loop_hint, AtomicUsize, Ordering};
use crate::sys::hermit::abi; use crate::sys::hermit::abi;
pub struct Mutex { /// This type provides a lock based on busy waiting to realize mutual exclusion
inner: *const c_void, ///
/// # 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 Send for Mutex {}
unsafe impl Sync for Mutex {} unsafe impl Sync for Mutex {}
impl Mutex { impl Mutex {
pub const fn new() -> Mutex { pub const fn new() -> Mutex {
Mutex { inner: ptr::null() } Mutex { inner: Spinlock::new(MutexInner::new()) }
} }
#[inline] #[inline]
pub unsafe fn init(&mut self) { 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] #[inline]
pub unsafe fn lock(&self) { 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] #[inline]
pub unsafe fn unlock(&self) { 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] #[inline]
pub unsafe fn try_lock(&self) -> bool { pub unsafe fn try_lock(&self) -> bool {
let result = abi::sem_trywait(self.inner); let mut guard = self.inner.lock();
result == 0 if guard.locked == false {
guard.locked = true;
}
guard.locked
} }
#[inline] #[inline]
pub unsafe fn destroy(&self) { pub unsafe fn destroy(&self) {}
let _ = abi::sem_destroy(self.inner);
}
} }
pub struct ReentrantMutex { pub struct ReentrantMutex {

View file

@ -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 {}
}
}

View file

@ -89,6 +89,7 @@ cfg_if::cfg_if! {
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
pub use self::ext as windows_ext; pub use self::ext as windows_ext;
} else if #[cfg(any(target_os = "cloudabi", } else if #[cfg(any(target_os = "cloudabi",
target_os = "hermit",
target_arch = "wasm32", target_arch = "wasm32",
all(target_vendor = "fortanix", target_env = "sgx")))] { all(target_vendor = "fortanix", target_env = "sgx")))] {
// On CloudABI and wasm right now the shim below doesn't compile, so // On CloudABI and wasm right now the shim below doesn't compile, so

View file

@ -10,6 +10,7 @@
let mut _8: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:35:9: 35:10 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 _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 _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 { scope 1 {
debug a => _2; // in scope 1 at $DIR/matches_reduce_branches.rs:13:9: 13:10 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 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(_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 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 - 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 + StorageLive(_11); // scope 4 at $DIR/matches_reduce_branches.rs:19:9: 19:10
+ _3 = Eq(_1, const 7_i32); // scope 4 at $DIR/matches_reduce_branches.rs:21:13: 21:21 + _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 + _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 + _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 + goto -> bb3; // scope 4 at $DIR/matches_reduce_branches.rs:19:9: 19:10
} }

View file

@ -10,6 +10,7 @@
let mut _8: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:35:9: 35:10 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 _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 _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 { scope 1 {
debug a => _2; // in scope 1 at $DIR/matches_reduce_branches.rs:13:9: 13:10 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 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(_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 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 - 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 + StorageLive(_11); // scope 4 at $DIR/matches_reduce_branches.rs:19:9: 19:10
+ _3 = Eq(_1, const 7_i32); // scope 4 at $DIR/matches_reduce_branches.rs:21:13: 21:21 + _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 + _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 + _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 + goto -> bb3; // scope 4 at $DIR/matches_reduce_branches.rs:19:9: 19:10
} }

View file

@ -6,12 +6,16 @@
let mut _0: (); // return place in scope 0 at $DIR/matches_reduce_branches.rs:6:25: 6:25 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 _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 _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: { bb0: {
StorageLive(_2); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL 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 _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 - 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 + goto -> bb3; // scope 0 at $DIR/matches_reduce_branches.rs:7:22: 7:26
} }

View file

@ -6,12 +6,16 @@
let mut _0: (); // return place in scope 0 at $DIR/matches_reduce_branches.rs:6:25: 6:25 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 _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 _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: { bb0: {
StorageLive(_2); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL 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 _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 - 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 + goto -> bb3; // scope 0 at $DIR/matches_reduce_branches.rs:7:22: 7:26
} }

View file

@ -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
}
}

View file

@ -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
}
}

View file

@ -1,7 +1,7 @@
// compile-flags: -Zunsound-mir-opts
// EMIT_MIR_FOR_EACH_BIT_WIDTH // EMIT_MIR_FOR_EACH_BIT_WIDTH
// EMIT_MIR matches_reduce_branches.foo.MatchBranchSimplification.diff // EMIT_MIR matches_reduce_branches.foo.MatchBranchSimplification.diff
// EMIT_MIR matches_reduce_branches.bar.MatchBranchSimplification.diff // EMIT_MIR matches_reduce_branches.bar.MatchBranchSimplification.diff
// EMIT_MIR matches_reduce_branches.match_nested_if.MatchBranchSimplification.diff
fn foo(bar: Option<()>) { fn foo(bar: Option<()>) {
if matches!(bar, None) { if matches!(bar, None) {
@ -35,9 +35,17 @@ fn bar(i: i32) -> (bool, bool, bool, bool) {
(a, b, c, d) (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() { fn main() {
let _ = foo(None); let _ = foo(None);
let _ = foo(Some(())); let _ = foo(Some(()));
let _ = bar(0); let _ = bar(0);
let _ = match_nested_if();
} }

View file

@ -8,61 +8,52 @@
let mut _3: isize; // in scope 0 at $DIR/not_equal_false.rs:4:17: 4:21 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 _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 _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: { bb0: {
StorageLive(_2); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL 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 _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: { bb1: {
_0 = const true; // scope 0 at $DIR/not_equal_false.rs:4:5: 4:46 _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: { bb2: {
_0 = const false; // 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
goto -> bb4; // scope 0 at $DIR/not_equal_false.rs:4:5: 4:46 _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: { 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(_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 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 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: { bb5: {
_2 = const false; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL StorageLive(_8); // scope 0 at $DIR/not_equal_false.rs:4:5: 4:46
goto -> bb7; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL _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
bb6: { StorageDead(_8); // scope 0 at $DIR/not_equal_false.rs:4:5: 4:46
_2 = const true; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL goto -> bb3; // scope 0 at $DIR/not_equal_false.rs:4:5: 4:46
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
} }
} }

View file

@ -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>();
}

View file

@ -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>();
}

View file

@ -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

View file

@ -1,6 +1,8 @@
#![feature(const_panic)] #![feature(const_panic)]
#![crate_type = "lib"] #![crate_type = "lib"]
const MSG: &str = "hello";
const Z: () = std::panic!("cheese"); const Z: () = std::panic!("cheese");
//~^ ERROR any use of this value will cause an error //~^ ERROR any use of this value will cause an error
@ -12,6 +14,9 @@ const Y: () = std::unreachable!();
const X: () = std::unimplemented!(); const X: () = std::unimplemented!();
//~^ ERROR any use of this value will cause an error //~^ 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"); const Z_CORE: () = core::panic!("cheese");
//~^ ERROR any use of this value will cause an error //~^ ERROR any use of this value will cause an error
@ -24,3 +29,6 @@ const Y_CORE: () = core::unreachable!();
const X_CORE: () = core::unimplemented!(); const X_CORE: () = core::unimplemented!();
//~^ ERROR any use of this value will cause an error //~^ 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

View file

@ -1,83 +1,103 @@
error: any use of this value will cause an error 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"); 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: `#[deny(const_err)]` on by default
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) = 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 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!(); 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) = 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 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!(); 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) = 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 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!(); 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) = 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 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"); 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) = 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 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!(); 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) = 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 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!(); 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) = 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 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!(); 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) = 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

View 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 => {}
}
}

View 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
}
}

View 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

View file

@ -53,8 +53,8 @@ enum LR_NonZero {
fn test_panic_msg<T>(op: impl (FnOnce() -> T) + panic::UnwindSafe, msg: &str) { fn test_panic_msg<T>(op: impl (FnOnce() -> T) + panic::UnwindSafe, msg: &str) {
let err = panic::catch_unwind(op).err(); let err = panic::catch_unwind(op).err();
assert_eq!( assert_eq!(
err.as_ref().and_then(|a| a.downcast_ref::<String>()).map(|s| &**s), err.as_ref().and_then(|a| a.downcast_ref::<&str>()),
Some(msg) Some(&msg)
); );
} }

View 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`

View 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`.

View 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!();

View file

@ -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

View 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 => {}
_ => {}
}
}

View 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

View file

@ -7,11 +7,11 @@ LL | match buf {
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = 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]` = 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 --> $DIR/match-byte-array-patterns-2.rs:10:11
| |
LL | match buf { 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 = 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]` = note: the matched value is of type `&[u8]`