diff --git a/Cargo.lock b/Cargo.lock index 94fbd52bcf0d7..7f1ff2b980493 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -626,9 +626,9 @@ dependencies = [ [[package]] name = "compiler_builtins" -version = "0.1.35" +version = "0.1.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3fcd8aba10d17504c87ef12d4f62ef404c6a4703d16682a9eb5543e6cf24455" +checksum = "7cd0782e0a7da7598164153173e5a5d4d9b1da094473c98dce0ff91406112369" dependencies = [ "cc", "rustc-std-workspace-core", @@ -1366,9 +1366,9 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.1.15" +version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3deed196b6e7f9e44a2ae8d94225d80302d81208b1bb673fd21fe634645c85a9" +checksum = "5aca5565f760fb5b220e499d72710ed156fdb74e631659e99377d9ebfbd13ae8" dependencies = [ "compiler_builtins", "libc", diff --git a/compiler/rustc_data_structures/src/profiling.rs b/compiler/rustc_data_structures/src/profiling.rs index 363879cbb1d19..0ae3c75fcc2cb 100644 --- a/compiler/rustc_data_structures/src/profiling.rs +++ b/compiler/rustc_data_structures/src/profiling.rs @@ -111,17 +111,6 @@ cfg_if! { type Profiler = measureme::Profiler; -#[derive(Clone, Copy, Debug, PartialEq, Eq, Ord, PartialOrd)] -pub enum ProfileCategory { - Parsing, - Expansion, - TypeChecking, - BorrowChecking, - Codegen, - Linking, - Other, -} - bitflags::bitflags! { struct EventFilter: u32 { const GENERIC_ACTIVITIES = 1 << 0; diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index 04912fe409679..ccb6a3322efb5 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -601,6 +601,9 @@ declare_features! ( /// Allow anonymous constants from an inline `const` block (active, inline_const, "1.49.0", Some(76001), None), + /// Enables `#[cfg(panic = "...")]` config key. + (active, cfg_panic, "1.49.0", Some(77443), None), + // ------------------------------------------------------------------------- // feature-group-end: actual feature gates // ------------------------------------------------------------------------- diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 83aa1f62106cb..ae95b8e422594 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -33,6 +33,7 @@ const GATED_CFGS: &[GatedCfg] = &[ ), (sym::sanitize, sym::cfg_sanitize, cfg_fn!(cfg_sanitize)), (sym::version, sym::cfg_version, cfg_fn!(cfg_version)), + (sym::panic, sym::cfg_panic, cfg_fn!(cfg_panic)), ]; /// Find a gated cfg determined by the `pred`icate which is given the cfg's name. diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index 5e4c03bec83dc..3e4eb9eafd7f9 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -263,6 +263,7 @@ language_item_table! { // is required to define it somewhere. Additionally, there are restrictions on crates that use // a weak lang item, but do not have it defined. Panic, sym::panic, panic_fn, Target::Fn; + PanicStr, sym::panic_str, panic_str, Target::Fn; PanicBoundsCheck, sym::panic_bounds_check, panic_bounds_check_fn, Target::Fn; PanicInfo, sym::panic_info, panic_info, Target::Struct; PanicLocation, sym::panic_location, panic_location, Target::Struct; diff --git a/compiler/rustc_macros/src/query.rs b/compiler/rustc_macros/src/query.rs index e7c054653accb..fd85919636949 100644 --- a/compiler/rustc_macros/src/query.rs +++ b/compiler/rustc_macros/src/query.rs @@ -190,7 +190,11 @@ impl Parse for List { } /// A named group containing queries. +/// +/// For now, the name is not used any more, but the capability remains interesting for future +/// developments of the query system. struct Group { + #[allow(unused)] name: Ident, queries: List, } @@ -417,12 +421,9 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream { let mut query_stream = quote! {}; let mut query_description_stream = quote! {}; let mut dep_node_def_stream = quote! {}; - let mut dep_node_force_stream = quote! {}; - let mut try_load_from_on_disk_cache_stream = quote! {}; let mut cached_queries = quote! {}; for group in groups.0 { - let mut group_stream = quote! {}; for mut query in group.queries.0 { let modifiers = process_modifiers(&mut query); let name = &query.name; @@ -437,22 +438,6 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream { cached_queries.extend(quote! { #name, }); - - try_load_from_on_disk_cache_stream.extend(quote! { - ::rustc_middle::dep_graph::DepKind::#name => { - if <#arg as DepNodeParams>>::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>>::recover($tcx, $dep_node).unwrap(); - if queries::#name::cache_on_disk($tcx, &key, None) { - let _ = $tcx.#name(key); - } - } - } - }); } let mut attributes = Vec::new(); @@ -485,9 +470,9 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream { let attribute_stream = quote! {#(#attributes),*}; let doc_comments = query.doc_comments.iter(); // Add the query to the group - group_stream.extend(quote! { + query_stream.extend(quote! { #(#doc_comments)* - [#attribute_stream] fn #name: #name(#arg) #result, + [#attribute_stream] fn #name(#arg) #result, }); // Create a dep node for the query @@ -495,37 +480,10 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream { [#attribute_stream] #name(#arg), }); - // Add a match arm to force the query given the dep node - dep_node_force_stream.extend(quote! { - ::rustc_middle::dep_graph::DepKind::#name => { - if <#arg as DepNodeParams>>::can_reconstruct_query_key() { - if let Some(key) = <#arg as DepNodeParams>>::recover($tcx, $dep_node) { - force_query::, _>( - $tcx, - key, - DUMMY_SP, - *$dep_node - ); - return true; - } - } - } - }); - add_query_description_impl(&query, modifiers, &mut query_description_stream); } - let name = &group.name; - query_stream.extend(quote! { - #name { #group_stream }, - }); } - dep_node_force_stream.extend(quote! { - ::rustc_middle::dep_graph::DepKind::Null => { - bug!("Cannot force dep node: {:?}", $dep_node) - } - }); - TokenStream::from(quote! { macro_rules! rustc_query_append { ([$($macro:tt)*][$($other:tt)*]) => { @@ -546,15 +504,6 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream { ); } } - macro_rules! rustc_dep_node_force { - ([$dep_node:expr, $tcx:expr] $($other:tt)*) => { - match $dep_node.kind { - $($other)* - - #dep_node_force_stream - } - } - } macro_rules! rustc_cached_queries { ($($macro:tt)*) => { $($macro)*(#cached_queries); @@ -562,14 +511,5 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream { } #query_description_stream - - macro_rules! rustc_dep_node_try_load_from_on_disk_cache { - ($dep_node:expr, $tcx:expr) => { - match $dep_node.kind { - #try_load_from_on_disk_cache_stream - _ => (), - } - } - } }) } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index ab92e5b745bcd..f6ea6743a0e04 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -2036,13 +2036,13 @@ direct_interners! { macro_rules! slice_interners { ($($field:ident: $method:ident($ty:ty)),+ $(,)?) => ( - $(impl<'tcx> TyCtxt<'tcx> { - pub fn $method(self, v: &[$ty]) -> &'tcx List<$ty> { + impl<'tcx> TyCtxt<'tcx> { + $(pub fn $method(self, v: &[$ty]) -> &'tcx List<$ty> { self.interners.$field.intern_ref(v, || { Interned(List::from_arena(&*self.arena, v)) }).0 - } - })+ + })+ + } ); } diff --git a/compiler/rustc_middle/src/ty/query/mod.rs b/compiler/rustc_middle/src/ty/query/mod.rs index d3a7412ef14e7..7ba4d5a14dffb 100644 --- a/compiler/rustc_middle/src/ty/query/mod.rs +++ b/compiler/rustc_middle/src/ty/query/mod.rs @@ -34,7 +34,6 @@ use crate::ty::util::AlwaysRequiresDrop; use crate::ty::{self, AdtSizedConstraint, CrateInherentImpls, ParamEnvAnd, Ty, TyCtxt}; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap}; -use rustc_data_structures::profiling::ProfileCategory::*; use rustc_data_structures::stable_hasher::StableVec; use rustc_data_structures::svh::Svh; use rustc_data_structures::sync::Lrc; @@ -169,26 +168,71 @@ pub fn force_from_dep_node<'tcx>(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> bool return false; } - rustc_dep_node_force!([dep_node, tcx] - // These are inputs that are expected to be pre-allocated and that - // should therefore always be red or green already. - DepKind::CrateMetadata | + macro_rules! force_from_dep_node { + ($($(#[$attr:meta])* [$($modifiers:tt)*] $name:ident($K:ty),)*) => { + match dep_node.kind { + // These are inputs that are expected to be pre-allocated and that + // should therefore always be red or green already. + DepKind::CrateMetadata | - // These are anonymous nodes. - DepKind::TraitSelect | + // These are anonymous nodes. + DepKind::TraitSelect | - // We don't have enough information to reconstruct the query key of - // these. - DepKind::CompileCodegenUnit => { - bug!("force_from_dep_node: encountered {:?}", dep_node) + // We don't have enough information to reconstruct the query key of + // these. + DepKind::CompileCodegenUnit | + + // Forcing this makes no sense. + DepKind::Null => { + bug!("force_from_dep_node: encountered {:?}", dep_node) + } + + $(DepKind::$name => { + debug_assert!(<$K as DepNodeParams>>::can_reconstruct_query_key()); + + if let Some(key) = <$K as DepNodeParams>>::recover(tcx, dep_node) { + force_query::, _>( + tcx, + key, + DUMMY_SP, + *dep_node + ); + return true; + } + })* + } } - ); + } + + rustc_dep_node_append! { [force_from_dep_node!][] } false } pub(crate) fn try_load_from_on_disk_cache<'tcx>(tcx: TyCtxt<'tcx>, dep_node: &DepNode) { - rustc_dep_node_try_load_from_on_disk_cache!(dep_node, tcx) + macro_rules! try_load_from_on_disk_cache { + ($($name:ident,)*) => { + match dep_node.kind { + $(DepKind::$name => { + if as DepNodeParams>>::can_reconstruct_query_key() { + debug_assert!(tcx.dep_graph + .node_color(dep_node) + .map(|c| c.is_green()) + .unwrap_or(false)); + + let key = as DepNodeParams>>::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 { diff --git a/compiler/rustc_middle/src/ty/query/plumbing.rs b/compiler/rustc_middle/src/ty/query/plumbing.rs index 1a8aacc486986..d038695283c10 100644 --- a/compiler/rustc_middle/src/ty/query/plumbing.rs +++ b/compiler/rustc_middle/src/ty/query/plumbing.rs @@ -242,25 +242,15 @@ macro_rules! hash_result { }; } -macro_rules! define_queries { - (<$tcx:tt> $($category:tt { - $($(#[$attr:meta])* [$($modifiers:tt)*] fn $name:ident: $node:ident($($K:tt)*) -> $V:ty,)* - },)*) => { - define_queries_inner! { <$tcx> - $($( $(#[$attr])* category<$category> [$($modifiers)*] fn $name: $node($($K)*) -> $V,)*)* - } - } -} - macro_rules! query_helper_param_ty { (DefId) => { impl IntoQueryParam }; ($K:ty) => { $K }; } -macro_rules! define_queries_inner { +macro_rules! define_queries { (<$tcx:tt> - $($(#[$attr:meta])* category<$category:tt> - [$($modifiers:tt)*] fn $name:ident: $node:ident($($K:tt)*) -> $V:ty,)*) => { + $($(#[$attr:meta])* + [$($modifiers:tt)*] fn $name:ident($($K:tt)*) -> $V:ty,)*) => { use std::mem; use crate::{ @@ -268,7 +258,6 @@ macro_rules! define_queries_inner { rustc_data_structures::stable_hasher::StableHasher, ich::StableHashingContext }; - use rustc_data_structures::profiling::ProfileCategory; define_queries_struct! { tcx: $tcx, @@ -362,13 +351,12 @@ macro_rules! define_queries_inner { as QueryStorage >::Stored; const NAME: &'static str = stringify!($name); - const CATEGORY: ProfileCategory = $category; } impl<$tcx> QueryAccessors> for queries::$name<$tcx> { const ANON: bool = is_anon!([$($modifiers)*]); const EVAL_ALWAYS: bool = is_eval_always!([$($modifiers)*]); - const DEP_KIND: dep_graph::DepKind = dep_graph::DepKind::$node; + const DEP_KIND: dep_graph::DepKind = dep_graph::DepKind::$name; type Cache = query_storage!([$($modifiers)*][$($K)*, $V]); diff --git a/compiler/rustc_middle/src/ty/query/stats.rs b/compiler/rustc_middle/src/ty/query/stats.rs index 877f88d380a39..e0b44ce23c912 100644 --- a/compiler/rustc_middle/src/ty/query/stats.rs +++ b/compiler/rustc_middle/src/ty/query/stats.rs @@ -120,13 +120,13 @@ pub fn print_stats(tcx: TyCtxt<'_>) { } macro_rules! print_stats { - (<$tcx:tt> $($category:tt { - $($(#[$attr:meta])* [$($modifiers:tt)*] fn $name:ident: $node:ident($K:ty) -> $V:ty,)* - },)*) => { + (<$tcx:tt> + $($(#[$attr:meta])* [$($modifiers:tt)*] fn $name:ident($K:ty) -> $V:ty,)* + ) => { fn query_stats(tcx: TyCtxt<'_>) -> Vec { let mut queries = Vec::new(); - $($( + $( queries.push(stats::< crate::dep_graph::DepKind, as QueryContext>::Query, @@ -135,7 +135,7 @@ macro_rules! print_stats { stringify!($name), &tcx.queries.$name, )); - )*)* + )* queries } diff --git a/compiler/rustc_mir/src/const_eval/machine.rs b/compiler/rustc_mir/src/const_eval/machine.rs index 73ca7e0d471ca..7e2cae094811a 100644 --- a/compiler/rustc_mir/src/const_eval/machine.rs +++ b/compiler/rustc_mir/src/const_eval/machine.rs @@ -70,9 +70,10 @@ impl<'mir, 'tcx> InterpCx<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>> { ) -> InterpResult<'tcx> { let def_id = instance.def_id(); if Some(def_id) == self.tcx.lang_items().panic_fn() + || Some(def_id) == self.tcx.lang_items().panic_str() || Some(def_id) == self.tcx.lang_items().begin_panic_fn() { - // &'static str + // &str assert!(args.len() == 1); let msg_place = self.deref_operand(args[0])?; diff --git a/compiler/rustc_mir/src/transform/check_consts/mod.rs b/compiler/rustc_mir/src/transform/check_consts/mod.rs index 33815ceba620b..b93d63b4fddb9 100644 --- a/compiler/rustc_mir/src/transform/check_consts/mod.rs +++ b/compiler/rustc_mir/src/transform/check_consts/mod.rs @@ -74,7 +74,9 @@ impl ConstCx<'mir, 'tcx> { /// Returns `true` if this `DefId` points to one of the official `panic` lang items. pub fn is_lang_panic_fn(tcx: TyCtxt<'tcx>, def_id: DefId) -> bool { - Some(def_id) == tcx.lang_items().panic_fn() || Some(def_id) == tcx.lang_items().begin_panic_fn() + Some(def_id) == tcx.lang_items().panic_fn() + || Some(def_id) == tcx.lang_items().panic_str() + || Some(def_id) == tcx.lang_items().begin_panic_fn() } pub fn allow_internal_unstable(tcx: TyCtxt<'tcx>, def_id: DefId, feature_gate: Symbol) -> bool { diff --git a/compiler/rustc_mir/src/transform/match_branches.rs b/compiler/rustc_mir/src/transform/match_branches.rs index 0f9b2ff5ab81e..06690dcbf6eb7 100644 --- a/compiler/rustc_mir/src/transform/match_branches.rs +++ b/compiler/rustc_mir/src/transform/match_branches.rs @@ -38,19 +38,16 @@ pub struct MatchBranchSimplification; impl<'tcx> MirPass<'tcx> for MatchBranchSimplification { fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - // FIXME: This optimization can result in unsoundness, because it introduces - // additional uses of a place holding the discriminant value without ensuring that - // it is valid to do so. - if !tcx.sess.opts.debugging_opts.unsound_mir_opts { + if tcx.sess.opts.debugging_opts.mir_opt_level <= 1 { return; } let param_env = tcx.param_env(body.source.def_id()); - let bbs = body.basic_blocks_mut(); + let (bbs, local_decls) = body.basic_blocks_and_local_decls_mut(); 'outer: for bb_idx in bbs.indices() { let (discr, val, switch_ty, first, second) = match bbs[bb_idx].terminator().kind { TerminatorKind::SwitchInt { - discr: Operand::Copy(ref place) | Operand::Move(ref place), + discr: ref discr @ (Operand::Copy(_) | Operand::Move(_)), switch_ty, ref targets, .. @@ -59,7 +56,7 @@ impl<'tcx> MirPass<'tcx> for MatchBranchSimplification { if target == targets.otherwise() { continue; } - (place, value, switch_ty, target, targets.otherwise()) + (discr, value, switch_ty, target, targets.otherwise()) } // Only optimize switch int statements _ => continue, @@ -99,6 +96,10 @@ impl<'tcx> MirPass<'tcx> for MatchBranchSimplification { // Take ownership of items now that we know we can optimize. let discr = discr.clone(); + // Introduce a temporary for the discriminant value. + let source_info = bbs[bb_idx].terminator().source_info; + let discr_local = local_decls.push(LocalDecl::new(switch_ty, source_info.span)); + // We already checked that first and second are different blocks, // and bb_idx has a different terminator from both of them. let (from, first, second) = bbs.pick3_mut(bb_idx, first, second); @@ -127,7 +128,11 @@ impl<'tcx> MirPass<'tcx> for MatchBranchSimplification { rustc_span::DUMMY_SP, ); let op = if f_b { BinOp::Eq } else { BinOp::Ne }; - let rhs = Rvalue::BinaryOp(op, Operand::Copy(discr.clone()), const_cmp); + let rhs = Rvalue::BinaryOp( + op, + Operand::Copy(Place::from(discr_local)), + const_cmp, + ); Statement { source_info: f.source_info, kind: StatementKind::Assign(box (*lhs, rhs)), @@ -138,7 +143,16 @@ impl<'tcx> MirPass<'tcx> for MatchBranchSimplification { _ => unreachable!(), } }); + + from.statements + .push(Statement { source_info, kind: StatementKind::StorageLive(discr_local) }); + from.statements.push(Statement { + source_info, + kind: StatementKind::Assign(box (Place::from(discr_local), Rvalue::Use(discr))), + }); from.statements.extend(new_stmts); + from.statements + .push(Statement { source_info, kind: StatementKind::StorageDead(discr_local) }); from.terminator_mut().kind = first.terminator().kind.clone(); } } diff --git a/compiler/rustc_mir_build/src/thir/pattern/_match.rs b/compiler/rustc_mir_build/src/thir/pattern/_match.rs index 7216d1305fd4b..0449e14983150 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/_match.rs @@ -302,10 +302,9 @@ use super::{FieldPat, Pat, PatKind, PatRange}; use rustc_arena::TypedArena; use rustc_attr::{SignedInt, UnsignedInt}; -use rustc_errors::ErrorReported; use rustc_hir::def_id::DefId; use rustc_hir::{HirId, RangeEnd}; -use rustc_middle::mir::interpret::{truncate, AllocId, ConstValue, Pointer, Scalar}; +use rustc_middle::mir::interpret::{truncate, ConstValue}; use rustc_middle::mir::Field; use rustc_middle::ty::layout::IntegerExt; use rustc_middle::ty::{self, Const, Ty, TyCtxt}; @@ -314,108 +313,21 @@ use rustc_span::{Span, DUMMY_SP}; use rustc_target::abi::{Integer, Size, VariantIdx}; use smallvec::{smallvec, SmallVec}; -use std::borrow::Cow; use std::cmp::{self, max, min, Ordering}; -use std::convert::TryInto; use std::fmt; use std::iter::{FromIterator, IntoIterator}; use std::ops::RangeInclusive; -crate fn expand_pattern<'a, 'tcx>(cx: &MatchCheckCtxt<'a, 'tcx>, pat: Pat<'tcx>) -> Pat<'tcx> { - LiteralExpander { tcx: cx.tcx, param_env: cx.param_env }.fold_pattern(&pat) +crate fn expand_pattern<'tcx>(pat: Pat<'tcx>) -> Pat<'tcx> { + LiteralExpander.fold_pattern(&pat) } -struct LiteralExpander<'tcx> { - tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, -} +struct LiteralExpander; -impl<'tcx> LiteralExpander<'tcx> { - /// Derefs `val` and potentially unsizes the value if `crty` is an array and `rty` a slice. - /// - /// `crty` and `rty` can differ because you can use array constants in the presence of slice - /// patterns. So the pattern may end up being a slice, but the constant is an array. We convert - /// the array to a slice in that case. - fn fold_const_value_deref( - &mut self, - val: ConstValue<'tcx>, - // the pattern's pointee type - rty: Ty<'tcx>, - // the constant's pointee type - crty: Ty<'tcx>, - ) -> ConstValue<'tcx> { - debug!("fold_const_value_deref {:?} {:?} {:?}", val, rty, crty); - match (val, &crty.kind(), &rty.kind()) { - // the easy case, deref a reference - (ConstValue::Scalar(p), x, y) if x == y => { - match p { - Scalar::Ptr(p) => { - let alloc = self.tcx.global_alloc(p.alloc_id).unwrap_memory(); - ConstValue::ByRef { alloc, offset: p.offset } - } - Scalar::Raw { .. } => { - let layout = self.tcx.layout_of(self.param_env.and(rty)).unwrap(); - if layout.is_zst() { - // Deref of a reference to a ZST is a nop. - ConstValue::Scalar(Scalar::zst()) - } else { - // FIXME(oli-obk): this is reachable for `const FOO: &&&u32 = &&&42;` - bug!("cannot deref {:#?}, {} -> {}", val, crty, rty); - } - } - } - } - // unsize array to slice if pattern is array but match value or other patterns are slice - (ConstValue::Scalar(Scalar::Ptr(p)), ty::Array(t, n), ty::Slice(u)) => { - assert_eq!(t, u); - ConstValue::Slice { - data: self.tcx.global_alloc(p.alloc_id).unwrap_memory(), - start: p.offset.bytes().try_into().unwrap(), - end: n.eval_usize(self.tcx, ty::ParamEnv::empty()).try_into().unwrap(), - } - } - // fat pointers stay the same - (ConstValue::Slice { .. }, _, _) - | (_, ty::Slice(_), ty::Slice(_)) - | (_, ty::Str, ty::Str) => val, - // FIXME(oli-obk): this is reachable for `const FOO: &&&u32 = &&&42;` being used - _ => bug!("cannot deref {:#?}, {} -> {}", val, crty, rty), - } - } -} - -impl<'tcx> PatternFolder<'tcx> for LiteralExpander<'tcx> { +impl<'tcx> PatternFolder<'tcx> for LiteralExpander { fn fold_pattern(&mut self, pat: &Pat<'tcx>) -> Pat<'tcx> { debug!("fold_pattern {:?} {:?} {:?}", pat, pat.ty.kind(), pat.kind); match (pat.ty.kind(), &*pat.kind) { - (&ty::Ref(_, rty, _), &PatKind::Constant { value: Const { val, ty: const_ty } }) - if const_ty.is_ref() => - { - let crty = - if let ty::Ref(_, crty, _) = const_ty.kind() { crty } else { unreachable!() }; - if let ty::ConstKind::Value(val) = val { - Pat { - ty: pat.ty, - span: pat.span, - kind: box PatKind::Deref { - subpattern: Pat { - ty: rty, - span: pat.span, - kind: box PatKind::Constant { - value: Const::from_value( - self.tcx, - self.fold_const_value_deref(*val, rty, crty), - rty, - ), - }, - }, - }, - } - } else { - bug!("cannot deref {:#?}, {} -> {}", val, crty, rty) - } - } - (_, &PatKind::Binding { subpattern: Some(ref s), .. }) => s.fold_with(self), (_, &PatKind::AscribeUserType { subpattern: ref s, .. }) => s.fold_with(self), _ => pat.super_fold_with(self), @@ -500,9 +412,15 @@ impl<'p, 'tcx> PatStack<'p, 'tcx> { cx: &mut MatchCheckCtxt<'p, 'tcx>, constructor: &Constructor<'tcx>, ctor_wild_subpatterns: &Fields<'p, 'tcx>, + is_my_head_ctor: bool, ) -> Option> { - let new_fields = - specialize_one_pattern(cx, self.head(), constructor, ctor_wild_subpatterns)?; + let new_fields = specialize_one_pattern( + cx, + self.head(), + constructor, + ctor_wild_subpatterns, + is_my_head_ctor, + )?; Some(new_fields.push_on_patstack(&self.0[1..])) } } @@ -680,6 +598,7 @@ impl<'p, 'tcx> Matrix<'p, 'tcx> { cx, constructor, ctor_wild_subpatterns, + false, ) }) .collect() @@ -705,7 +624,9 @@ impl<'p, 'tcx> Matrix<'p, 'tcx> { SpecializationCache::Incompatible => self .patterns .iter() - .filter_map(|r| r.specialize_constructor(cx, constructor, ctor_wild_subpatterns)) + .filter_map(|r| { + r.specialize_constructor(cx, constructor, ctor_wild_subpatterns, false) + }) .collect(), } } @@ -725,6 +646,7 @@ impl<'p, 'tcx> Matrix<'p, 'tcx> { /// +++++++++++++++++++++++++++++ /// + _ + [_, _, tail @ ..] + /// +++++++++++++++++++++++++++++ +/// ``` impl<'p, 'tcx> fmt::Debug for Matrix<'p, 'tcx> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "\n")?; @@ -926,42 +848,30 @@ enum Constructor<'tcx> { Single, /// Enum variants. Variant(DefId), - /// Literal values. - ConstantValue(&'tcx ty::Const<'tcx>), /// Ranges of integer literal values (`2`, `2..=5` or `2..5`). IntRange(IntRange<'tcx>), /// Ranges of floating-point literal values (`2.0..=5.2`). FloatRange(&'tcx ty::Const<'tcx>, &'tcx ty::Const<'tcx>, RangeEnd), + /// String literals. Strings are not quite the same as `&[u8]` so we treat them separately. + Str(&'tcx ty::Const<'tcx>), /// Array and slice patterns. Slice(Slice), + /// Constants that must not be matched structurally. They are treated as black + /// boxes for the purposes of exhaustiveness: we must not inspect them, and they + /// don't count towards making a match exhaustive. + Opaque, /// Fake extra constructor for enums that aren't allowed to be matched exhaustively. NonExhaustive, } impl<'tcx> Constructor<'tcx> { - fn is_slice(&self) -> bool { - match self { - Slice(_) => true, - _ => false, - } - } - - fn variant_index_for_adt<'a>( - &self, - cx: &MatchCheckCtxt<'a, 'tcx>, - adt: &'tcx ty::AdtDef, - ) -> VariantIdx { + fn variant_index_for_adt(&self, adt: &'tcx ty::AdtDef) -> VariantIdx { match *self { Variant(id) => adt.variant_index_with_id(id), Single => { assert!(!adt.is_enum()); VariantIdx::new(0) } - ConstantValue(c) => cx - .tcx - .destructure_const(cx.param_env.and(c)) - .variant - .expect("destructed const of adt without variant id"), _ => bug!("bad constructor {:?} for adt {:?}", self, adt), } } @@ -975,7 +885,7 @@ impl<'tcx> Constructor<'tcx> { match self { // Those constructors can only match themselves. - Single | Variant(_) | ConstantValue(..) | FloatRange(..) => { + Single | Variant(_) | Str(..) | FloatRange(..) => { if other_ctors.iter().any(|c| c == self) { vec![] } else { vec![self.clone()] } } &Slice(slice) => { @@ -983,8 +893,6 @@ impl<'tcx> Constructor<'tcx> { .iter() .filter_map(|c: &Constructor<'_>| match c { Slice(slice) => Some(*slice), - // FIXME(oli-obk): implement `deref` for `ConstValue` - ConstantValue(..) => None, _ => bug!("bad slice pattern constructor {:?}", c), }) .map(Slice::value_kind); @@ -1048,6 +956,7 @@ impl<'tcx> Constructor<'tcx> { } // This constructor is never covered by anything else NonExhaustive => vec![NonExhaustive], + Opaque => bug!("unexpected opaque ctor {:?} found in all_ctors", self), } } @@ -1087,7 +996,7 @@ impl<'tcx> Constructor<'tcx> { PatKind::Variant { adt_def: adt, substs, - variant_index: self.variant_index_for_adt(cx, adt), + variant_index: self.variant_index_for_adt(adt), subpatterns, } } else { @@ -1126,10 +1035,11 @@ impl<'tcx> Constructor<'tcx> { PatKind::Slice { prefix, slice: Some(wild), suffix } } }, - &ConstantValue(value) => PatKind::Constant { value }, + &Str(value) => PatKind::Constant { value }, &FloatRange(lo, hi, end) => PatKind::Range(PatRange { lo, hi, end }), IntRange(range) => return range.to_pat(cx.tcx), NonExhaustive => PatKind::Wild, + Opaque => bug!("we should not try to apply an opaque constructor {:?}", self), }; Pat { ty, span: DUMMY_SP, kind: Box::new(pat) } @@ -1204,12 +1114,6 @@ impl<'p, 'tcx> Fields<'p, 'tcx> { Fields::Slice(std::slice::from_ref(pat)) } - /// Construct a new `Fields` from the given patterns. You must be sure those patterns can't - /// contain fields that need to be filtered out. When in doubt, prefer `replace_fields`. - fn from_slice_unfiltered(pats: &'p [Pat<'tcx>]) -> Self { - Fields::Slice(pats) - } - /// Convenience; internal use. fn wildcards_from_tys( cx: &MatchCheckCtxt<'p, 'tcx>, @@ -1239,7 +1143,7 @@ impl<'p, 'tcx> Fields<'p, 'tcx> { // Use T as the sub pattern type of Box. Fields::from_single_pattern(wildcard_from_ty(substs.type_at(0))) } else { - let variant = &adt.variants[constructor.variant_index_for_adt(cx, adt)]; + let variant = &adt.variants[constructor.variant_index_for_adt(adt)]; // Whether we must not match the fields of this variant exhaustively. let is_non_exhaustive = variant.is_field_list_non_exhaustive() && !adt.did.is_local(); @@ -1287,7 +1191,7 @@ impl<'p, 'tcx> Fields<'p, 'tcx> { } _ => bug!("bad slice pattern {:?} {:?}", constructor, ty), }, - ConstantValue(..) | FloatRange(..) | IntRange(..) | NonExhaustive => Fields::empty(), + Str(..) | FloatRange(..) | IntRange(..) | NonExhaustive | Opaque => Fields::empty(), }; debug!("Fields::wildcards({:?}, {:?}) = {:#?}", constructor, ty, ret); ret @@ -1600,9 +1504,7 @@ fn all_constructors<'a, 'tcx>( ) }; match *pcx.ty.kind() { - ty::Bool => { - [true, false].iter().map(|&b| ConstantValue(ty::Const::from_bool(cx.tcx, b))).collect() - } + ty::Bool => vec![make_range(0, 1)], ty::Array(ref sub_ty, len) if len.try_eval_usize(cx.tcx, cx.param_env).is_some() => { let len = len.eval_usize(cx.tcx, cx.param_env); if len != 0 && cx.is_uninhabited(sub_ty) { @@ -1717,7 +1619,7 @@ impl<'tcx> IntRange<'tcx> { #[inline] fn is_integral(ty: Ty<'_>) -> bool { match ty.kind() { - ty::Char | ty::Int(_) | ty::Uint(_) => true, + ty::Char | ty::Int(_) | ty::Uint(_) | ty::Bool => true, _ => false, } } @@ -1739,6 +1641,7 @@ impl<'tcx> IntRange<'tcx> { #[inline] fn integral_size_and_signed_bias(tcx: TyCtxt<'tcx>, ty: Ty<'_>) -> Option<(Size, u128)> { match *ty.kind() { + ty::Bool => Some((Size::from_bytes(1), 0)), ty::Char => Some((Size::from_bytes(4), 0)), ty::Int(ity) => { let size = Integer::from_attr(&tcx, SignedInt(ity)).size(); @@ -2230,7 +2133,7 @@ fn is_useful_specialized<'p, 'tcx>( // We cache the result of `Fields::wildcards` because it is used a lot. let ctor_wild_subpatterns = Fields::wildcards(cx, &ctor, ty); let matrix = matrix.specialize_constructor(cx, &ctor, &ctor_wild_subpatterns); - v.specialize_constructor(cx, &ctor, &ctor_wild_subpatterns) + v.specialize_constructor(cx, &ctor, &ctor_wild_subpatterns, true) .map(|v| is_useful(cx, &matrix, &v, witness_preference, hir_id, is_under_guard, false)) .map(|u| u.apply_constructor(cx, &ctor, ty, &ctor_wild_subpatterns)) .unwrap_or(NotUseful) @@ -2255,18 +2158,13 @@ fn pat_constructor<'tcx>( if let Some(int_range) = IntRange::from_const(tcx, param_env, value, pat.span) { Some(IntRange(int_range)) } else { - match (value.val, &value.ty.kind()) { - (_, ty::Array(_, n)) => { - let len = n.eval_usize(tcx, param_env); - Some(Slice(Slice { array_len: Some(len), kind: FixedLen(len) })) - } - (ty::ConstKind::Value(ConstValue::Slice { start, end, .. }), ty::Slice(_)) => { - let len = (end - start) as u64; - Some(Slice(Slice { array_len: None, kind: FixedLen(len) })) - } - // FIXME(oli-obk): implement `deref` for `ConstValue` - // (ty::ConstKind::Value(ConstValue::ByRef { .. }), ty::Slice(_)) => { ... } - _ => Some(ConstantValue(value)), + match value.ty.kind() { + ty::Float(_) => Some(FloatRange(value, value, RangeEnd::Included)), + ty::Ref(_, t, _) if t.is_str() => Some(Str(value)), + // All constants that can be structurally matched have already been expanded + // into the corresponding `Pat`s by `const_to_pat`. Constants that remain are + // opaque. + _ => Some(Opaque), } } } @@ -2302,75 +2200,6 @@ fn pat_constructor<'tcx>( } } -// checks whether a constant is equal to a user-written slice pattern. Only supports byte slices, -// meaning all other types will compare unequal and thus equal patterns often do not cause the -// second pattern to lint about unreachable match arms. -fn slice_pat_covered_by_const<'tcx>( - tcx: TyCtxt<'tcx>, - _span: Span, - const_val: &'tcx ty::Const<'tcx>, - prefix: &[Pat<'tcx>], - slice: &Option>, - suffix: &[Pat<'tcx>], - param_env: ty::ParamEnv<'tcx>, -) -> Result { - let const_val_val = if let ty::ConstKind::Value(val) = const_val.val { - val - } else { - bug!( - "slice_pat_covered_by_const: {:#?}, {:#?}, {:#?}, {:#?}", - const_val, - prefix, - slice, - suffix, - ) - }; - - let data: &[u8] = match (const_val_val, &const_val.ty.kind()) { - (ConstValue::ByRef { offset, alloc, .. }, ty::Array(t, n)) => { - assert_eq!(*t, tcx.types.u8); - let n = n.eval_usize(tcx, param_env); - let ptr = Pointer::new(AllocId(0), offset); - alloc.get_bytes(&tcx, ptr, Size::from_bytes(n)).unwrap() - } - (ConstValue::Slice { data, start, end }, ty::Slice(t)) => { - assert_eq!(*t, tcx.types.u8); - let ptr = Pointer::new(AllocId(0), Size::from_bytes(start)); - data.get_bytes(&tcx, ptr, Size::from_bytes(end - start)).unwrap() - } - // FIXME(oli-obk): create a way to extract fat pointers from ByRef - (_, ty::Slice(_)) => return Ok(false), - _ => bug!( - "slice_pat_covered_by_const: {:#?}, {:#?}, {:#?}, {:#?}", - const_val, - prefix, - slice, - suffix, - ), - }; - - let pat_len = prefix.len() + suffix.len(); - if data.len() < pat_len || (slice.is_none() && data.len() > pat_len) { - return Ok(false); - } - - for (ch, pat) in data[..prefix.len()] - .iter() - .zip(prefix) - .chain(data[data.len() - suffix.len()..].iter().zip(suffix)) - { - if let box PatKind::Constant { value } = pat.kind { - let b = value.eval_bits(tcx, param_env, pat.ty); - assert_eq!(b as u8 as u128, b); - if b as u8 != *ch { - return Ok(false); - } - } - } - - Ok(true) -} - /// For exhaustive integer matching, some constructors are grouped within other constructors /// (namely integer typed values are grouped within ranges). However, when specialising these /// constructors, we want to be specialising for the underlying constructors (the integers), not @@ -2668,35 +2497,6 @@ fn lint_overlapping_patterns<'tcx>( } } -fn constructor_covered_by_range<'tcx>( - tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, - ctor: &Constructor<'tcx>, - pat: &Pat<'tcx>, -) -> Option<()> { - if let Single = ctor { - return Some(()); - } - - let (pat_from, pat_to, pat_end, ty) = match *pat.kind { - PatKind::Constant { value } => (value, value, RangeEnd::Included, value.ty), - PatKind::Range(PatRange { lo, hi, end }) => (lo, hi, end, lo.ty), - _ => bug!("`constructor_covered_by_range` called with {:?}", pat), - }; - let (ctor_from, ctor_to, ctor_end) = match *ctor { - ConstantValue(value) => (value, value, RangeEnd::Included), - FloatRange(from, to, ctor_end) => (from, to, ctor_end), - _ => bug!("`constructor_covered_by_range` called with {:?}", ctor), - }; - trace!("constructor_covered_by_range {:#?}, {:#?}, {:#?}, {}", ctor, pat_from, pat_to, ty); - - let to = compare_const_vals(tcx, ctor_to, pat_to, param_env, ty)?; - let from = compare_const_vals(tcx, ctor_from, pat_from, param_env, ty)?; - let intersects = (from == Ordering::Greater || from == Ordering::Equal) - && (to == Ordering::Less || (pat_end == ctor_end && to == Ordering::Equal)); - if intersects { Some(()) } else { None } -} - /// This is the main specialization step. It expands the pattern /// into `arity` patterns based on the constructor. For most patterns, the step is trivial, /// for instance tuple patterns are flattened and box patterns expand into their inner pattern. @@ -2713,15 +2513,43 @@ fn specialize_one_pattern<'p, 'tcx>( pat: &'p Pat<'tcx>, constructor: &Constructor<'tcx>, ctor_wild_subpatterns: &Fields<'p, 'tcx>, + is_its_own_ctor: bool, // Whether `ctor` is known to be derived from `pat` ) -> Option> { if let NonExhaustive = constructor { - // Only a wildcard pattern can match the special extra constructor + // Only a wildcard pattern can match the special extra constructor. if !pat.is_wildcard() { return None; } return Some(Fields::empty()); } + if let Opaque = constructor { + // Only a wildcard pattern can match an opaque constant, unless we're specializing the + // value against its own constructor. That happens when we call + // `v.specialize_constructor(ctor)` with `ctor` obtained from `pat_constructor(v.head())`. + // For example, in the following match, when we are dealing with the third branch, we will + // specialize with an `Opaque` ctor. We want to ignore the second branch because opaque + // constants should not be inspected, but we don't want to ignore the current (third) + // branch, as that would cause us to always conclude that such a branch is unreachable. + // ```rust + // #[derive(PartialEq)] + // struct Foo(i32); + // impl Eq for Foo {} + // const FOO: Foo = Foo(42); + // + // match (Foo(0), true) { + // (_, true) => {} + // (FOO, true) => {} + // (FOO, false) => {} + // } + // ``` + if is_its_own_ctor || pat.is_wildcard() { + return Some(Fields::empty()); + } else { + return None; + } + } + let result = match *pat.kind { PatKind::AscribeUserType { .. } => bug!(), // Handled by `expand_pattern` @@ -2741,93 +2569,52 @@ fn specialize_one_pattern<'p, 'tcx>( PatKind::Deref { ref subpattern } => Some(Fields::from_single_pattern(subpattern)), - PatKind::Constant { value } if constructor.is_slice() => { - // We extract an `Option` for the pointer because slices of zero - // elements don't necessarily point to memory, they are usually - // just integers. The only time they should be pointing to memory - // is when they are subslices of nonzero slices. - let (alloc, offset, n, ty) = match value.ty.kind() { - ty::Array(t, n) => { - let n = n.eval_usize(cx.tcx, cx.param_env); - // Shortcut for `n == 0` where no matter what `alloc` and `offset` we produce, - // the result would be exactly what we early return here. - if n == 0 { - if ctor_wild_subpatterns.len() as u64 != n { - return None; - } - return Some(Fields::empty()); - } - match value.val { - ty::ConstKind::Value(ConstValue::ByRef { offset, alloc, .. }) => { - (Cow::Borrowed(alloc), offset, n, t) - } - _ => span_bug!(pat.span, "array pattern is {:?}", value,), + PatKind::Constant { .. } | PatKind::Range { .. } => { + match constructor { + IntRange(ctor) => { + let pat = IntRange::from_pat(cx.tcx, cx.param_env, pat)?; + ctor.intersection(cx.tcx, &pat)?; + // Constructor splitting should ensure that all intersections we encounter + // are actually inclusions. + assert!(ctor.is_subrange(&pat)); + } + FloatRange(ctor_from, ctor_to, ctor_end) => { + let (pat_from, pat_to, pat_end, ty) = match *pat.kind { + PatKind::Constant { value } => (value, value, RangeEnd::Included, value.ty), + PatKind::Range(PatRange { lo, hi, end }) => (lo, hi, end, lo.ty), + _ => unreachable!(), // This is ensured by the branch we're in + }; + let to = compare_const_vals(cx.tcx, ctor_to, pat_to, cx.param_env, ty)?; + let from = compare_const_vals(cx.tcx, ctor_from, pat_from, cx.param_env, ty)?; + let intersects = (from == Ordering::Greater || from == Ordering::Equal) + && (to == Ordering::Less + || (pat_end == *ctor_end && to == Ordering::Equal)); + if !intersects { + return None; } } - 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; - } + Str(ctor_value) => { + let pat_value = match *pat.kind { + PatKind::Constant { value } => value, _ => span_bug!( pat.span, - "slice pattern constant must be scalar pair but is {:?}", - value, + "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; } } - _ => span_bug!( - pat.span, - "unexpected const-val {:?} with ctor {:?}", - value, - constructor, - ), - }; - if ctor_wild_subpatterns.len() as u64 != n { - return None; - } - - // Convert a constant slice/array pattern to a list of patterns. - let layout = cx.tcx.layout_of(cx.param_env.and(ty)).ok()?; - let ptr = Pointer::new(AllocId(0), offset); - let pats = cx.pattern_arena.alloc_from_iter((0..n).filter_map(|i| { - let ptr = ptr.offset(layout.size * i, &cx.tcx).ok()?; - let scalar = alloc.read_scalar(&cx.tcx, ptr, layout.size).ok()?; - let scalar = scalar.check_init().ok()?; - let value = ty::Const::from_scalar(cx.tcx, scalar, ty); - let pattern = Pat { ty, span: pat.span, kind: box PatKind::Constant { value } }; - Some(pattern) - })); - // Ensure none of the dereferences failed. - if pats.len() as u64 != n { - return None; - } - Some(Fields::from_slice_unfiltered(pats)) - } - - PatKind::Constant { .. } | PatKind::Range { .. } => { - // If the constructor is a: - // - Single value: add a row if the pattern contains the constructor. - // - Range: add a row if the constructor intersects the pattern. - if let IntRange(ctor) = constructor { - let pat = IntRange::from_pat(cx.tcx, cx.param_env, pat)?; - ctor.intersection(cx.tcx, &pat)?; - // Constructor splitting should ensure that all intersections we encounter - // are actually inclusions. - assert!(ctor.is_subrange(&pat)); - } else { - // Fallback for non-ranges and ranges that involve - // floating-point numbers, which are not conveniently handled - // by `IntRange`. For these cases, the constructor may not be a - // range so intersection actually devolves into being covered - // by the pattern. - constructor_covered_by_range(cx.tcx, cx.param_env, constructor, pat)?; + _ => { + // If we reach here, we must be trying to inspect an opaque constant. Thus we skip + // the row. + return None; + } } Some(Fields::empty()) } @@ -2850,21 +2637,6 @@ fn specialize_one_pattern<'p, 'tcx>( let suffix = suffix.iter().enumerate().map(|(i, p)| (arity - suffix.len() + i, p)); Some(ctor_wild_subpatterns.replace_fields_indexed(prefix.chain(suffix))) } - ConstantValue(cv) => { - match slice_pat_covered_by_const( - cx.tcx, - pat.span, - cv, - prefix, - slice, - suffix, - cx.param_env, - ) { - Ok(true) => Some(Fields::empty()), - Ok(false) => None, - Err(ErrorReported) => None, - } - } _ => span_bug!(pat.span, "unexpected ctor {:?} for slice pat", constructor), }, diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index 69de7c7e2ee0b..30b700a1d4f63 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -137,7 +137,7 @@ impl<'tcx> MatchVisitor<'_, 'tcx> { patcx.include_lint_checks(); let pattern = patcx.lower_pattern(pat); let pattern_ty = pattern.ty; - let pattern: &_ = cx.pattern_arena.alloc(expand_pattern(cx, pattern)); + let pattern: &_ = cx.pattern_arena.alloc(expand_pattern(pattern)); if !patcx.errors.is_empty() { *have_errors = true; patcx.report_inlining_errors(pat.span); diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs index a203b3a142863..6370f8c375b2a 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs @@ -387,14 +387,16 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { // `&str` and `&[u8]` are represented as `ConstValue::Slice`, let's keep using this // optimization for now. ty::Str => PatKind::Constant { value: cv }, - ty::Slice(elem_ty) if elem_ty == tcx.types.u8 => PatKind::Constant { value: cv }, // `b"foo"` produces a `&[u8; 3]`, but you can't use constants of array type when // matching against references, you can only use byte string literals. - // FIXME: clean this up, likely by permitting array patterns when matching on slices - ty::Array(elem_ty, _) if elem_ty == tcx.types.u8 => PatKind::Constant { value: cv }, + // The typechecker has a special case for byte string literals, by treating them + // as slices. This means we turn `&[T; N]` constants into slice patterns, which + // has no negative effects on pattern matching, even if we're actually matching on + // arrays. + ty::Array(..) | // Cannot merge this with the catch all branch below, because the `const_deref` - // changes the type from slice to array, and slice patterns behave differently from - // array patterns. + // changes the type from slice to array, we need to keep the original type in the + // pattern. ty::Slice(..) => { let old = self.behind_reference.replace(true); let array = tcx.deref_const(self.param_env.and(cv)); diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index b05ddb3b46452..25e187243416d 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -158,6 +158,13 @@ crate enum PatKind<'tcx> { subpattern: Pat<'tcx>, }, + /// One of the following: + /// * `&str`, which will be handled as a string pattern and thus exhaustiveness + /// checking will detect if you use the same string twice in different patterns. + /// * integer, bool, char or float, which will be handled by exhaustivenes to cover exactly + /// its own value, similar to `&str`, but these values are much simpler. + /// * Opaque constants, that must not be matched structurally. So anything that does not derive + /// `PartialEq` and `Eq`. Constant { value: &'tcx ty::Const<'tcx>, }, diff --git a/compiler/rustc_query_system/src/query/config.rs b/compiler/rustc_query_system/src/query/config.rs index 6c9849e8708b7..0f0684b354791 100644 --- a/compiler/rustc_query_system/src/query/config.rs +++ b/compiler/rustc_query_system/src/query/config.rs @@ -5,7 +5,6 @@ use crate::dep_graph::SerializedDepNodeIndex; use crate::query::caches::QueryCache; use crate::query::plumbing::CycleError; use crate::query::{QueryContext, QueryState}; -use rustc_data_structures::profiling::ProfileCategory; use rustc_data_structures::fingerprint::Fingerprint; use std::borrow::Cow; @@ -14,7 +13,6 @@ use std::hash::Hash; pub trait QueryConfig { const NAME: &'static str; - const CATEGORY: ProfileCategory; type Key: Eq + Hash + Clone + Debug; type Value; diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index f33bebf99d6e1..768120f6b4dd4 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -793,6 +793,9 @@ pub fn default_configuration(sess: &Session) -> CrateConfig { } } + let panic_strategy = sess.panic_strategy(); + ret.insert((sym::panic, Some(panic_strategy.desc_symbol()))); + for s in sess.opts.debugging_opts.sanitizer { let symbol = Symbol::intern(&s.to_string()); ret.insert((sym::sanitize, Some(symbol))); diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 9cf530d57c0b1..579b1ddd954a7 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -323,6 +323,7 @@ symbols! { cfg_attr, cfg_attr_multi, cfg_doctest, + cfg_panic, cfg_sanitize, cfg_target_feature, cfg_target_has_atomic, @@ -777,6 +778,7 @@ symbols! { panic_info, panic_location, panic_runtime, + panic_str, panic_unwind, param_attrs, parent_trait, diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 1d3e61c499208..5041a57ef57a2 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -37,6 +37,7 @@ use crate::spec::abi::{lookup as lookup_abi, Abi}; use crate::spec::crt_objects::{CrtObjects, CrtObjectsFallback}; use rustc_serialize::json::{Json, ToJson}; +use rustc_span::symbol::{sym, Symbol}; use std::collections::BTreeMap; use std::path::{Path, PathBuf}; use std::str::FromStr; @@ -174,6 +175,13 @@ impl PanicStrategy { PanicStrategy::Abort => "abort", } } + + pub fn desc_symbol(&self) -> Symbol { + match *self { + PanicStrategy::Unwind => sym::unwind, + PanicStrategy::Abort => sym::abort, + } + } } impl ToJson for PanicStrategy { diff --git a/compiler/rustc_trait_selection/src/traits/codegen.rs b/compiler/rustc_trait_selection/src/traits/codegen.rs index 05e6c4804ff65..3cb6ec8626186 100644 --- a/compiler/rustc_trait_selection/src/traits/codegen.rs +++ b/compiler/rustc_trait_selection/src/traits/codegen.rs @@ -121,7 +121,10 @@ where // contains unbound type parameters. It could be a slight // optimization to stop iterating early. if let Err(errors) = fulfill_cx.select_all_or_error(infcx) { - bug!("Encountered errors `{:?}` resolving bounds after type-checking", errors); + infcx.tcx.sess.delay_span_bug( + rustc_span::DUMMY_SP, + &format!("Encountered errors `{:?}` resolving bounds after type-checking", errors), + ); } let result = infcx.resolve_vars_if_possible(result); diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index 1e1eb16faf407..c79b2624f8cb0 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -223,11 +223,23 @@ impl AbstractConst<'tcx> { } } +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +struct WorkNode<'tcx> { + node: Node<'tcx>, + span: Span, + used: bool, +} + struct AbstractConstBuilder<'a, 'tcx> { tcx: TyCtxt<'tcx>, body: &'a mir::Body<'tcx>, /// The current WIP node tree. - nodes: IndexVec>, + /// + /// 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>, locals: IndexVec, /// We only allow field accesses if they access /// the result of a checked operation. @@ -274,6 +286,27 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { Ok(Some(builder)) } + fn add_node(&mut self, node: Node<'tcx>, span: Span) -> NodeId { + // Mark used nodes. + match node { + Node::Leaf(_) => (), + Node::Binop(_, lhs, rhs) => { + self.nodes[lhs].used = true; + self.nodes[rhs].used = true; + } + Node::UnaryOp(_, input) => { + self.nodes[input].used = true; + } + Node::FunctionCall(func, nodes) => { + self.nodes[func].used = true; + nodes.iter().for_each(|&n| self.nodes[n].used = true); + } + } + + // Nodes start as unused. + self.nodes.push(WorkNode { node, span, used: false }) + } + fn place_to_local( &mut self, span: Span, @@ -311,7 +344,7 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { let local = self.place_to_local(span, p)?; Ok(self.locals[local]) } - mir::Operand::Constant(ct) => Ok(self.nodes.push(Node::Leaf(ct.literal))), + mir::Operand::Constant(ct) => Ok(self.add_node(Node::Leaf(ct.literal), span)), } } @@ -336,19 +369,19 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { fn build_statement(&mut self, stmt: &mir::Statement<'tcx>) -> Result<(), ErrorReported> { debug!("AbstractConstBuilder: stmt={:?}", stmt); + let span = stmt.source_info.span; match stmt.kind { StatementKind::Assign(box (ref place, ref rvalue)) => { - let local = self.place_to_local(stmt.source_info.span, place)?; + let local = self.place_to_local(span, place)?; match *rvalue { Rvalue::Use(ref operand) => { - self.locals[local] = - self.operand_to_node(stmt.source_info.span, operand)?; + self.locals[local] = self.operand_to_node(span, operand)?; Ok(()) } Rvalue::BinaryOp(op, ref lhs, ref rhs) if Self::check_binop(op) => { - let lhs = self.operand_to_node(stmt.source_info.span, lhs)?; - let rhs = self.operand_to_node(stmt.source_info.span, rhs)?; - self.locals[local] = self.nodes.push(Node::Binop(op, lhs, rhs)); + let lhs = self.operand_to_node(span, lhs)?; + let rhs = self.operand_to_node(span, rhs)?; + self.locals[local] = self.add_node(Node::Binop(op, lhs, rhs), span); if op.is_checkable() { bug!("unexpected unchecked checkable binary operation"); } else { @@ -356,18 +389,18 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { } } Rvalue::CheckedBinaryOp(op, ref lhs, ref rhs) if Self::check_binop(op) => { - let lhs = self.operand_to_node(stmt.source_info.span, lhs)?; - let rhs = self.operand_to_node(stmt.source_info.span, rhs)?; - self.locals[local] = self.nodes.push(Node::Binop(op, lhs, rhs)); + let lhs = self.operand_to_node(span, lhs)?; + let rhs = self.operand_to_node(span, rhs)?; + self.locals[local] = self.add_node(Node::Binop(op, lhs, rhs), span); self.checked_op_locals.insert(local); Ok(()) } Rvalue::UnaryOp(op, ref operand) if Self::check_unop(op) => { - let operand = self.operand_to_node(stmt.source_info.span, operand)?; - self.locals[local] = self.nodes.push(Node::UnaryOp(op, operand)); + let operand = self.operand_to_node(span, operand)?; + self.locals[local] = self.add_node(Node::UnaryOp(op, operand), span); Ok(()) } - _ => self.error(Some(stmt.source_info.span), "unsupported rvalue")?, + _ => self.error(Some(span), "unsupported rvalue")?, } } // These are not actually relevant for us here, so we can ignore them. @@ -415,13 +448,9 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { .map(|arg| self.operand_to_node(terminator.source_info.span, arg)) .collect::, _>>()?, ); - self.locals[local] = self.nodes.push(Node::FunctionCall(func, args)); + self.locals[local] = self.add_node(Node::FunctionCall(func, args), fn_span); Ok(Some(target)) } - // We only allow asserts for checked operations. - // - // These asserts seem to all have the form `!_local.0` so - // we only allow exactly that. TerminatorKind::Assert { ref cond, expected: false, target, .. } => { let p = match cond { mir::Operand::Copy(p) | mir::Operand::Move(p) => p, @@ -430,7 +459,15 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { const ONE_FIELD: mir::Field = mir::Field::from_usize(1); debug!("proj: {:?}", p.projection); - if let &[mir::ProjectionElem::Field(ONE_FIELD, _)] = p.projection.as_ref() { + if let Some(p) = p.as_local() { + debug_assert!(!self.checked_op_locals.contains(p)); + // Mark locals directly used in asserts as used. + // + // This is needed because division does not use `CheckedBinop` but instead + // adds an explicit assert for `divisor != 0`. + self.nodes[self.locals[p]].used = true; + return Ok(Some(target)); + } else if let &[mir::ProjectionElem::Field(ONE_FIELD, _)] = p.projection.as_ref() { // Only allow asserts checking the result of a checked operation. if self.checked_op_locals.contains(p.local) { return Ok(Some(target)); @@ -457,7 +494,13 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { if let Some(next) = self.build_terminator(block.terminator())? { block = &self.body.basic_blocks()[next]; } else { - return Ok(self.tcx.arena.alloc_from_iter(self.nodes)); + assert_eq!(self.locals[mir::RETURN_PLACE], self.nodes.last().unwrap()); + self.nodes[self.locals[mir::RETURN_PLACE]].used = true; + if let Some(&unused) = self.nodes.iter().find(|n| !n.used) { + self.error(Some(unused.span), "dead code")?; + } + + return Ok(self.tcx.arena.alloc_from_iter(self.nodes.into_iter().map(|n| n.node))); } } } diff --git a/library/alloc/src/alloc.rs b/library/alloc/src/alloc.rs index 109c3a0e68302..dd7dcfbc4aa45 100644 --- a/library/alloc/src/alloc.rs +++ b/library/alloc/src/alloc.rs @@ -372,7 +372,7 @@ pub fn handle_alloc_error(layout: Layout) -> ! { unsafe { oom_impl(layout) } } -#[cfg(not(any(test, bootstrap)))] +#[cfg(not(any(target_os = "hermit", test, bootstrap)))] #[doc(hidden)] #[allow(unused_attributes)] #[unstable(feature = "alloc_internals", issue = "none")] diff --git a/library/backtrace b/library/backtrace index a6dd47bd588c8..8b8ea53b56f51 160000 --- a/library/backtrace +++ b/library/backtrace @@ -1 +1 @@ -Subproject commit a6dd47bd588c882e735675a1379d2b61719fa380 +Subproject commit 8b8ea53b56f519dd7780defdd4254daaec892584 diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index 4c62c16f5063c..ac45e819cf67a 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -10,7 +10,7 @@ macro_rules! panic { $crate::panicking::panic($msg) ); ($msg:expr) => ( - $crate::panic!("{}", $crate::convert::identity::<&str>($msg)) + $crate::panicking::panic_str($msg) ); ($msg:expr,) => ( $crate::panic!($msg) diff --git a/library/core/src/panicking.rs b/library/core/src/panicking.rs index 15fd638bef8ad..09dd19b8f5f93 100644 --- a/library/core/src/panicking.rs +++ b/library/core/src/panicking.rs @@ -50,6 +50,13 @@ pub fn panic(expr: &'static str) -> ! { panic_fmt(fmt::Arguments::new_v1(&[expr], &[])); } +#[inline] +#[track_caller] +#[cfg_attr(not(bootstrap), lang = "panic_str")] // needed for const-evaluated panics +pub fn panic_str(expr: &str) -> ! { + panic_fmt(format_args!("{}", expr)); +} + #[cold] #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))] #[track_caller] diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index 47b59d4a6772c..5925aa87a3f13 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -42,7 +42,7 @@ dlmalloc = { version = "0.1", features = ['rustc-dep-of-std'] } fortanix-sgx-abi = { version = "0.3.2", features = ['rustc-dep-of-std'] } [target.'cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_os = "hermit"))'.dependencies] -hermit-abi = { version = "0.1.15", features = ['rustc-dep-of-std'] } +hermit-abi = { version = "0.1.17", features = ['rustc-dep-of-std'] } [target.wasm32-wasi.dependencies] wasi = { version = "0.9.0", features = ['rustc-dep-of-std'], default-features = false } diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 30e7a7f3c3b10..3da0ebdd4982a 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -259,6 +259,7 @@ #![feature(exhaustive_patterns)] #![feature(extend_one)] #![feature(external_doc)] +#![feature(fmt_as_str)] #![feature(fn_traits)] #![feature(format_args_nl)] #![feature(gen_future)] diff --git a/library/std/src/panicking.rs b/library/std/src/panicking.rs index 8dceb12de87b8..221ae809e23a2 100644 --- a/library/std/src/panicking.rs +++ b/library/std/src/panicking.rs @@ -478,10 +478,26 @@ pub fn begin_panic_handler(info: &PanicInfo<'_>) -> ! { } } + struct StrPanicPayload(&'static str); + + unsafe impl BoxMeUp for StrPanicPayload { + fn take_box(&mut self) -> *mut (dyn Any + Send) { + Box::into_raw(Box::new(self.0)) + } + + fn get(&mut self) -> &(dyn Any + Send) { + &self.0 + } + } + let loc = info.location().unwrap(); // The current implementation always returns Some let msg = info.message().unwrap(); // The current implementation always returns Some crate::sys_common::backtrace::__rust_end_short_backtrace(move || { - rust_panic_with_hook(&mut PanicPayload::new(msg), info.message(), loc); + 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); + } }) } diff --git a/library/std/src/sys/hermit/fs.rs b/library/std/src/sys/hermit/fs.rs index 82ccab1462ba8..829d4c943f11b 100644 --- a/library/std/src/sys/hermit/fs.rs +++ b/library/std/src/sys/hermit/fs.rs @@ -334,10 +334,6 @@ impl File { pub fn set_permissions(&self, _perm: FilePermissions) -> io::Result<()> { Err(Error::from_raw_os_error(22)) } - - pub fn diverge(&self) -> ! { - loop {} - } } impl DirBuilder { diff --git a/library/std/src/sys/hermit/mod.rs b/library/std/src/sys/hermit/mod.rs index 8eaf07e52d69a..af05310a8d3ab 100644 --- a/library/std/src/sys/hermit/mod.rs +++ b/library/std/src/sys/hermit/mod.rs @@ -31,6 +31,7 @@ pub mod net; pub mod os; pub mod path; pub mod pipe; +#[path = "../unsupported/process.rs"] pub mod process; pub mod rwlock; pub mod stack_overflow; diff --git a/library/std/src/sys/hermit/mutex.rs b/library/std/src/sys/hermit/mutex.rs index 3d4813209cbc4..f988a019cfedb 100644 --- a/library/std/src/sys/hermit/mutex.rs +++ b/library/std/src/sys/hermit/mutex.rs @@ -1,44 +1,214 @@ +use crate::cell::UnsafeCell; +use crate::collections::VecDeque; use crate::ffi::c_void; +use crate::ops::{Deref, DerefMut, Drop}; use crate::ptr; +use crate::sync::atomic::{spin_loop_hint, AtomicUsize, Ordering}; use crate::sys::hermit::abi; +/// This type provides a lock based on busy waiting to realize mutual exclusion +/// +/// # Description +/// +/// This structure behaves a lot like a common mutex. There are some differences: +/// +/// - By using busy waiting, it can be used outside the runtime. +/// - It is a so called ticket lock and is completly fair. +#[cfg_attr(target_arch = "x86_64", repr(align(128)))] +#[cfg_attr(not(target_arch = "x86_64"), repr(align(64)))] +struct Spinlock { + queue: AtomicUsize, + dequeue: AtomicUsize, + data: UnsafeCell, +} + +unsafe impl Sync for Spinlock {} +unsafe impl Send for Spinlock {} + +/// 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 Spinlock { + pub const fn new(user_data: T) -> Spinlock { + 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 Default for Spinlock { + fn default() -> Spinlock { + 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>; 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 { + 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 { + 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: *const c_void, + inner: Spinlock, } +pub type MovableMutex = Box; + unsafe impl Send for Mutex {} unsafe impl Sync for Mutex {} impl Mutex { pub const fn new() -> Mutex { - Mutex { inner: ptr::null() } + Mutex { inner: Spinlock::new(MutexInner::new()) } } #[inline] pub unsafe fn init(&mut self) { - let _ = abi::sem_init(&mut self.inner as *mut *const c_void, 1); + self.inner = Spinlock::new(MutexInner::new()); } #[inline] pub unsafe fn lock(&self) { - let _ = abi::sem_timedwait(self.inner, 0); + loop { + let mut guard = self.inner.lock(); + if guard.locked == false { + guard.locked = true; + return; + } else { + let prio = abi::get_priority(); + let id = abi::getpid(); + + guard.blocked_task.push(prio, id); + abi::block_current_task(); + drop(guard); + abi::yield_now(); + } + } } #[inline] pub unsafe fn unlock(&self) { - let _ = abi::sem_post(self.inner); + let mut guard = self.inner.lock(); + guard.locked = false; + if let Some(tid) = guard.blocked_task.pop() { + abi::wakeup_task(tid); + } } #[inline] pub unsafe fn try_lock(&self) -> bool { - let result = abi::sem_trywait(self.inner); - result == 0 + let mut guard = self.inner.lock(); + if guard.locked == false { + guard.locked = true; + } + guard.locked } #[inline] - pub unsafe fn destroy(&self) { - let _ = abi::sem_destroy(self.inner); - } + pub unsafe fn destroy(&self) {} } pub struct ReentrantMutex { diff --git a/library/std/src/sys/hermit/process.rs b/library/std/src/sys/hermit/process.rs deleted file mode 100644 index 4702e5c549228..0000000000000 --- a/library/std/src/sys/hermit/process.rs +++ /dev/null @@ -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, - pub stdout: Option, - pub stderr: Option, -} - -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 for Stdio { - fn from(pipe: AnonPipe) -> Stdio { - pipe.diverge() - } -} - -impl From 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 { - 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 { - match self.0 {} - } - - pub fn try_wait(&mut self) -> io::Result> { - match self.0 {} - } -} diff --git a/library/std/src/sys/mod.rs b/library/std/src/sys/mod.rs index 7b5fac922d08a..b4628b649117e 100644 --- a/library/std/src/sys/mod.rs +++ b/library/std/src/sys/mod.rs @@ -89,6 +89,7 @@ cfg_if::cfg_if! { #[stable(feature = "rust1", since = "1.0.0")] pub use self::ext as windows_ext; } else if #[cfg(any(target_os = "cloudabi", + target_os = "hermit", target_arch = "wasm32", all(target_vendor = "fortanix", target_env = "sgx")))] { // On CloudABI and wasm right now the shim below doesn't compile, so diff --git a/src/doc/unstable-book/src/language-features/cfg-panic.md b/src/doc/unstable-book/src/language-features/cfg-panic.md new file mode 100644 index 0000000000000..f5b73128ad6c2 --- /dev/null +++ b/src/doc/unstable-book/src/language-features/cfg-panic.md @@ -0,0 +1,38 @@ +# `cfg_panic` + +The tracking issue for this feature is: [#77443] + +[#77443]: https://github.com/rust-lang/rust/issues/77443 + +------------------------ + +The `cfg_panic` feature makes it possible to execute different code +depending on the panic strategy. + +Possible values at the moment are `"unwind"` or `"abort"`, although +it is possible that new panic strategies may be added to Rust in the +future. + +## Examples + +```rust +#![feature(cfg_panic)] + +#[cfg(panic = "unwind")] +fn a() { + // ... +} + +#[cfg(not(panic = "unwind"))] +fn a() { + // ... +} + +fn b() { + if cfg!(panic = "abort") { + // ... + } else { + // ... + } +} +``` diff --git a/src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.32bit.diff b/src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.32bit.diff index 648cf241cbaba..d3a29aa5d51c1 100644 --- a/src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.32bit.diff +++ b/src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.32bit.diff @@ -10,6 +10,7 @@ let mut _8: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:35:9: 35:10 let mut _9: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:35:12: 35:13 let mut _10: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:35:15: 35:16 ++ let mut _11: i32; // in scope 0 at $DIR/matches_reduce_branches.rs:19:9: 19:10 scope 1 { debug a => _2; // in scope 1 at $DIR/matches_reduce_branches.rs:13:9: 13:10 let _3: bool; // in scope 1 at $DIR/matches_reduce_branches.rs:14:9: 14:10 @@ -33,10 +34,13 @@ StorageLive(_5); // scope 3 at $DIR/matches_reduce_branches.rs:16:9: 16:10 StorageLive(_6); // scope 4 at $DIR/matches_reduce_branches.rs:18:5: 33:6 - switchInt(_1) -> [7_i32: bb2, otherwise: bb1]; // scope 4 at $DIR/matches_reduce_branches.rs:19:9: 19:10 -+ _2 = Ne(_1, const 7_i32); // scope 4 at $DIR/matches_reduce_branches.rs:20:13: 20:22 -+ _3 = Eq(_1, const 7_i32); // scope 4 at $DIR/matches_reduce_branches.rs:21:13: 21:21 ++ StorageLive(_11); // scope 4 at $DIR/matches_reduce_branches.rs:19:9: 19:10 ++ _11 = _1; // scope 4 at $DIR/matches_reduce_branches.rs:19:9: 19:10 ++ _2 = Ne(_11, const 7_i32); // scope 4 at $DIR/matches_reduce_branches.rs:20:13: 20:22 ++ _3 = Eq(_11, const 7_i32); // scope 4 at $DIR/matches_reduce_branches.rs:21:13: 21:21 + _4 = const false; // scope 4 at $DIR/matches_reduce_branches.rs:22:13: 22:22 + _5 = const true; // scope 4 at $DIR/matches_reduce_branches.rs:23:13: 23:21 ++ StorageDead(_11); // scope 4 at $DIR/matches_reduce_branches.rs:19:9: 19:10 + goto -> bb3; // scope 4 at $DIR/matches_reduce_branches.rs:19:9: 19:10 } diff --git a/src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.64bit.diff b/src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.64bit.diff index 648cf241cbaba..d3a29aa5d51c1 100644 --- a/src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.64bit.diff +++ b/src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.64bit.diff @@ -10,6 +10,7 @@ let mut _8: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:35:9: 35:10 let mut _9: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:35:12: 35:13 let mut _10: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:35:15: 35:16 ++ let mut _11: i32; // in scope 0 at $DIR/matches_reduce_branches.rs:19:9: 19:10 scope 1 { debug a => _2; // in scope 1 at $DIR/matches_reduce_branches.rs:13:9: 13:10 let _3: bool; // in scope 1 at $DIR/matches_reduce_branches.rs:14:9: 14:10 @@ -33,10 +34,13 @@ StorageLive(_5); // scope 3 at $DIR/matches_reduce_branches.rs:16:9: 16:10 StorageLive(_6); // scope 4 at $DIR/matches_reduce_branches.rs:18:5: 33:6 - switchInt(_1) -> [7_i32: bb2, otherwise: bb1]; // scope 4 at $DIR/matches_reduce_branches.rs:19:9: 19:10 -+ _2 = Ne(_1, const 7_i32); // scope 4 at $DIR/matches_reduce_branches.rs:20:13: 20:22 -+ _3 = Eq(_1, const 7_i32); // scope 4 at $DIR/matches_reduce_branches.rs:21:13: 21:21 ++ StorageLive(_11); // scope 4 at $DIR/matches_reduce_branches.rs:19:9: 19:10 ++ _11 = _1; // scope 4 at $DIR/matches_reduce_branches.rs:19:9: 19:10 ++ _2 = Ne(_11, const 7_i32); // scope 4 at $DIR/matches_reduce_branches.rs:20:13: 20:22 ++ _3 = Eq(_11, const 7_i32); // scope 4 at $DIR/matches_reduce_branches.rs:21:13: 21:21 + _4 = const false; // scope 4 at $DIR/matches_reduce_branches.rs:22:13: 22:22 + _5 = const true; // scope 4 at $DIR/matches_reduce_branches.rs:23:13: 23:21 ++ StorageDead(_11); // scope 4 at $DIR/matches_reduce_branches.rs:19:9: 19:10 + goto -> bb3; // scope 4 at $DIR/matches_reduce_branches.rs:19:9: 19:10 } diff --git a/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.32bit.diff b/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.32bit.diff index a52abfb1a727d..ba963e3fe920b 100644 --- a/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.32bit.diff +++ b/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.32bit.diff @@ -6,12 +6,16 @@ let mut _0: (); // return place in scope 0 at $DIR/matches_reduce_branches.rs:6:25: 6:25 let mut _2: bool; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL let mut _3: isize; // in scope 0 at $DIR/matches_reduce_branches.rs:7:22: 7:26 ++ let mut _4: isize; // in scope 0 at $DIR/matches_reduce_branches.rs:7:22: 7:26 bb0: { StorageLive(_2); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL _3 = discriminant(_1); // scope 0 at $DIR/matches_reduce_branches.rs:7:22: 7:26 - switchInt(move _3) -> [0_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/matches_reduce_branches.rs:7:22: 7:26 -+ _2 = Eq(_3, const 0_isize); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL ++ StorageLive(_4); // scope 0 at $DIR/matches_reduce_branches.rs:7:22: 7:26 ++ _4 = move _3; // scope 0 at $DIR/matches_reduce_branches.rs:7:22: 7:26 ++ _2 = Eq(_4, const 0_isize); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL ++ StorageDead(_4); // scope 0 at $DIR/matches_reduce_branches.rs:7:22: 7:26 + goto -> bb3; // scope 0 at $DIR/matches_reduce_branches.rs:7:22: 7:26 } diff --git a/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.64bit.diff b/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.64bit.diff index a52abfb1a727d..ba963e3fe920b 100644 --- a/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.64bit.diff +++ b/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.64bit.diff @@ -6,12 +6,16 @@ let mut _0: (); // return place in scope 0 at $DIR/matches_reduce_branches.rs:6:25: 6:25 let mut _2: bool; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL let mut _3: isize; // in scope 0 at $DIR/matches_reduce_branches.rs:7:22: 7:26 ++ let mut _4: isize; // in scope 0 at $DIR/matches_reduce_branches.rs:7:22: 7:26 bb0: { StorageLive(_2); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL _3 = discriminant(_1); // scope 0 at $DIR/matches_reduce_branches.rs:7:22: 7:26 - switchInt(move _3) -> [0_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/matches_reduce_branches.rs:7:22: 7:26 -+ _2 = Eq(_3, const 0_isize); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL ++ StorageLive(_4); // scope 0 at $DIR/matches_reduce_branches.rs:7:22: 7:26 ++ _4 = move _3; // scope 0 at $DIR/matches_reduce_branches.rs:7:22: 7:26 ++ _2 = Eq(_4, const 0_isize); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL ++ StorageDead(_4); // scope 0 at $DIR/matches_reduce_branches.rs:7:22: 7:26 + goto -> bb3; // scope 0 at $DIR/matches_reduce_branches.rs:7:22: 7:26 } diff --git a/src/test/mir-opt/matches_reduce_branches.match_nested_if.MatchBranchSimplification.32bit.diff b/src/test/mir-opt/matches_reduce_branches.match_nested_if.MatchBranchSimplification.32bit.diff new file mode 100644 index 0000000000000..1f46d3777bed8 --- /dev/null +++ b/src/test/mir-opt/matches_reduce_branches.match_nested_if.MatchBranchSimplification.32bit.diff @@ -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 + } + } + diff --git a/src/test/mir-opt/matches_reduce_branches.match_nested_if.MatchBranchSimplification.64bit.diff b/src/test/mir-opt/matches_reduce_branches.match_nested_if.MatchBranchSimplification.64bit.diff new file mode 100644 index 0000000000000..1f46d3777bed8 --- /dev/null +++ b/src/test/mir-opt/matches_reduce_branches.match_nested_if.MatchBranchSimplification.64bit.diff @@ -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 + } + } + diff --git a/src/test/mir-opt/matches_reduce_branches.rs b/src/test/mir-opt/matches_reduce_branches.rs index 54b79a84263fe..e95a62aeeb0b9 100644 --- a/src/test/mir-opt/matches_reduce_branches.rs +++ b/src/test/mir-opt/matches_reduce_branches.rs @@ -1,7 +1,7 @@ -// compile-flags: -Zunsound-mir-opts // EMIT_MIR_FOR_EACH_BIT_WIDTH // EMIT_MIR matches_reduce_branches.foo.MatchBranchSimplification.diff // EMIT_MIR matches_reduce_branches.bar.MatchBranchSimplification.diff +// EMIT_MIR matches_reduce_branches.match_nested_if.MatchBranchSimplification.diff fn foo(bar: Option<()>) { if matches!(bar, None) { @@ -35,9 +35,17 @@ fn bar(i: i32) -> (bool, bool, bool, bool) { (a, b, c, d) } +fn match_nested_if() -> bool { + let val = match () { + () if if if if true {true} else {false} {true} else {false} {true} else {false} => true, + _ => false, + }; + val +} fn main() { let _ = foo(None); let _ = foo(Some(())); let _ = bar(0); + let _ = match_nested_if(); } diff --git a/src/test/mir-opt/not_equal_false.opt.InstCombine.diff b/src/test/mir-opt/not_equal_false.opt.InstCombine.diff index 39830946aebd6..dc3a6a36d9eef 100644 --- a/src/test/mir-opt/not_equal_false.opt.InstCombine.diff +++ b/src/test/mir-opt/not_equal_false.opt.InstCombine.diff @@ -8,61 +8,52 @@ let mut _3: isize; // in scope 0 at $DIR/not_equal_false.rs:4:17: 4:21 let mut _4: bool; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL let mut _5: isize; // in scope 0 at $DIR/not_equal_false.rs:4:38: 4:45 + let mut _6: isize; // in scope 0 at $DIR/not_equal_false.rs:4:17: 4:21 + let mut _7: isize; // in scope 0 at $DIR/not_equal_false.rs:4:38: 4:45 + let mut _8: bool; // in scope 0 at $DIR/not_equal_false.rs:4:5: 4:46 bb0: { StorageLive(_2); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL _3 = discriminant(_1); // scope 0 at $DIR/not_equal_false.rs:4:17: 4:21 - switchInt(move _3) -> [0_isize: bb6, otherwise: bb5]; // scope 0 at $DIR/not_equal_false.rs:4:17: 4:21 + StorageLive(_6); // scope 0 at $DIR/not_equal_false.rs:4:17: 4:21 + _6 = move _3; // scope 0 at $DIR/not_equal_false.rs:4:17: 4:21 + _2 = Eq(_6, const 0_isize); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageDead(_6); // scope 0 at $DIR/not_equal_false.rs:4:17: 4:21 + goto -> bb4; // scope 0 at $DIR/not_equal_false.rs:4:17: 4:21 } bb1: { _0 = const true; // scope 0 at $DIR/not_equal_false.rs:4:5: 4:46 - goto -> bb4; // scope 0 at $DIR/not_equal_false.rs:4:5: 4:46 + goto -> bb3; // scope 0 at $DIR/not_equal_false.rs:4:5: 4:46 } bb2: { - _0 = const false; // scope 0 at $DIR/not_equal_false.rs:4:5: 4:46 - goto -> bb4; // scope 0 at $DIR/not_equal_false.rs:4:5: 4:46 - } - - 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 + 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 } - bb4: { + bb3: { StorageDead(_4); // scope 0 at $DIR/not_equal_false.rs:4:45: 4:46 StorageDead(_2); // scope 0 at $DIR/not_equal_false.rs:4:45: 4:46 return; // scope 0 at $DIR/not_equal_false.rs:5:2: 5:2 } - bb5: { - _2 = const false; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - goto -> bb7; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - } - - bb6: { - _2 = const true; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - goto -> bb7; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - } - - bb7: { - switchInt(move _2) -> [false: bb3, otherwise: bb1]; // scope 0 at $DIR/not_equal_false.rs:4:5: 4:46 - } - - bb8: { - _4 = const false; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - goto -> bb10; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - } - - bb9: { - _4 = const true; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - goto -> bb10; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + bb4: { + switchInt(move _2) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/not_equal_false.rs:4:5: 4:46 } - bb10: { - switchInt(move _4) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/not_equal_false.rs:4:5: 4:46 + bb5: { + StorageLive(_8); // scope 0 at $DIR/not_equal_false.rs:4:5: 4:46 + _8 = move _4; // scope 0 at $DIR/not_equal_false.rs:4:5: 4:46 +- _0 = Ne(_8, const false); // scope 0 at $DIR/not_equal_false.rs:4:5: 4:46 ++ _0 = _8; // scope 0 at $DIR/not_equal_false.rs:4:5: 4:46 + StorageDead(_8); // scope 0 at $DIR/not_equal_false.rs:4:5: 4:46 + goto -> bb3; // scope 0 at $DIR/not_equal_false.rs:4:5: 4:46 } } diff --git a/src/test/ui/cfg/cfg-panic-abort.rs b/src/test/ui/cfg/cfg-panic-abort.rs new file mode 100644 index 0000000000000..9b88eff12ed38 --- /dev/null +++ b/src/test/ui/cfg/cfg-panic-abort.rs @@ -0,0 +1,16 @@ +// build-pass +// compile-flags: -C panic=abort +// no-prefer-dynamic +#![feature(cfg_panic)] + +#[cfg(panic = "unwind")] +pub fn bad() -> i32 { } + +#[cfg(not(panic = "abort"))] +pub fn bad() -> i32 { } + +#[cfg(panic = "some_imaginary_future_panic_handler")] +pub fn bad() -> i32 { } + +#[cfg(panic = "abort")] +pub fn main() { } diff --git a/src/test/ui/cfg/cfg-panic.rs b/src/test/ui/cfg/cfg-panic.rs new file mode 100644 index 0000000000000..7e496bc221785 --- /dev/null +++ b/src/test/ui/cfg/cfg-panic.rs @@ -0,0 +1,14 @@ +// build-pass +#![feature(cfg_panic)] + +#[cfg(panic = "abort")] +pub fn bad() -> i32 { } + +#[cfg(not(panic = "unwind"))] +pub fn bad() -> i32 { } + +#[cfg(panic = "some_imaginary_future_panic_handler")] +pub fn bad() -> i32 { } + +#[cfg(panic = "unwind")] +pub fn main() { } diff --git a/src/test/ui/const-generics/const_evaluatable_checked/division.rs b/src/test/ui/const-generics/const_evaluatable_checked/division.rs new file mode 100644 index 0000000000000..71a5f2d347201 --- /dev/null +++ b/src/test/ui/const-generics/const_evaluatable_checked/division.rs @@ -0,0 +1,11 @@ +// run-pass +#![feature(const_generics, const_evaluatable_checked)] +#![allow(incomplete_features)] + +fn with_bound() where [u8; N / 2]: Sized { + let _: [u8; N / 2] = [0; N / 2]; +} + +fn main() { + with_bound::<4>(); +} diff --git a/src/test/ui/const-generics/const_evaluatable_checked/unused_expr.rs b/src/test/ui/const-generics/const_evaluatable_checked/unused_expr.rs new file mode 100644 index 0000000000000..9c603c57a4818 --- /dev/null +++ b/src/test/ui/const-generics/const_evaluatable_checked/unused_expr.rs @@ -0,0 +1,25 @@ +#![feature(const_generics, const_evaluatable_checked)] +#![allow(incomplete_features)] + +fn add() -> [u8; { N + 1; 5 }] { + //~^ ERROR overly complex generic constant + todo!() +} + +fn div() -> [u8; { N / 1; 5 }] { + //~^ ERROR overly complex generic constant + todo!() +} + +const fn foo(n: usize) {} + +fn fn_call() -> [u8; { foo(N); 5 }] { + //~^ ERROR overly complex generic constant + todo!() +} + +fn main() { + add::<12>(); + div::<9>(); + fn_call::<14>(); +} diff --git a/src/test/ui/const-generics/const_evaluatable_checked/unused_expr.stderr b/src/test/ui/const-generics/const_evaluatable_checked/unused_expr.stderr new file mode 100644 index 0000000000000..1687dbbcbe3f8 --- /dev/null +++ b/src/test/ui/const-generics/const_evaluatable_checked/unused_expr.stderr @@ -0,0 +1,32 @@ +error: overly complex generic constant + --> $DIR/unused_expr.rs:4:34 + | +LL | fn add() -> [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() -> [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() -> [u8; { foo(N); 5 }] { + | ^^------^^^^^ + | | + | dead code + | + = help: consider moving this anonymous constant into a `const` function + +error: aborting due to 3 previous errors + diff --git a/src/test/ui/consts/const-eval/const_panic.rs b/src/test/ui/consts/const-eval/const_panic.rs index ada9feec8971e..799c185fb8e4b 100644 --- a/src/test/ui/consts/const-eval/const_panic.rs +++ b/src/test/ui/consts/const-eval/const_panic.rs @@ -1,6 +1,8 @@ #![feature(const_panic)] #![crate_type = "lib"] +const MSG: &str = "hello"; + const Z: () = std::panic!("cheese"); //~^ ERROR any use of this value will cause an error @@ -12,6 +14,9 @@ const Y: () = std::unreachable!(); const X: () = std::unimplemented!(); //~^ ERROR any use of this value will cause an error +// +const W: () = std::panic!(MSG); +//~^ ERROR any use of this value will cause an error const Z_CORE: () = core::panic!("cheese"); //~^ ERROR any use of this value will cause an error @@ -24,3 +29,6 @@ const Y_CORE: () = core::unreachable!(); const X_CORE: () = core::unimplemented!(); //~^ ERROR any use of this value will cause an error + +const W_CORE: () = core::panic!(MSG); +//~^ ERROR any use of this value will cause an error diff --git a/src/test/ui/consts/const-eval/const_panic.stderr b/src/test/ui/consts/const-eval/const_panic.stderr index e4ca1f4fa26a2..c2711952d5837 100644 --- a/src/test/ui/consts/const-eval/const_panic.stderr +++ b/src/test/ui/consts/const-eval/const_panic.stderr @@ -1,83 +1,103 @@ error: any use of this value will cause an error - --> $DIR/const_panic.rs:4:15 + --> $DIR/const_panic.rs:6:15 | LL | const Z: () = std::panic!("cheese"); | --------------^^^^^^^^^^^^^^^^^^^^^- | | - | the evaluated program panicked at 'cheese', $DIR/const_panic.rs:4:15 + | the evaluated program panicked at 'cheese', $DIR/const_panic.rs:6:15 | = note: `#[deny(const_err)]` on by default = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: any use of this value will cause an error - --> $DIR/const_panic.rs:7:16 + --> $DIR/const_panic.rs:9:16 | LL | const Z2: () = std::panic!(); | ---------------^^^^^^^^^^^^^- | | - | the evaluated program panicked at 'explicit panic', $DIR/const_panic.rs:7:16 + | the evaluated program panicked at 'explicit panic', $DIR/const_panic.rs:9:16 | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: any use of this value will cause an error - --> $DIR/const_panic.rs:10:15 + --> $DIR/const_panic.rs:12:15 | LL | const Y: () = std::unreachable!(); | --------------^^^^^^^^^^^^^^^^^^^- | | - | the evaluated program panicked at 'internal error: entered unreachable code', $DIR/const_panic.rs:10:15 + | the evaluated program panicked at 'internal error: entered unreachable code', $DIR/const_panic.rs:12:15 | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: any use of this value will cause an error - --> $DIR/const_panic.rs:13:15 + --> $DIR/const_panic.rs:15:15 | LL | const X: () = std::unimplemented!(); | --------------^^^^^^^^^^^^^^^^^^^^^- | | - | the evaluated program panicked at 'not implemented', $DIR/const_panic.rs:13:15 + | the evaluated program panicked at 'not implemented', $DIR/const_panic.rs:15:15 | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: any use of this value will cause an error - --> $DIR/const_panic.rs:16:20 + --> $DIR/const_panic.rs:18:15 + | +LL | const W: () = std::panic!(MSG); + | --------------^^^^^^^^^^^^^^^^- + | | + | the evaluated program panicked at 'hello', $DIR/const_panic.rs:18:15 + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> $DIR/const_panic.rs:21:20 | LL | const Z_CORE: () = core::panic!("cheese"); | -------------------^^^^^^^^^^^^^^^^^^^^^^- | | - | the evaluated program panicked at 'cheese', $DIR/const_panic.rs:16:20 + | the evaluated program panicked at 'cheese', $DIR/const_panic.rs:21:20 | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: any use of this value will cause an error - --> $DIR/const_panic.rs:19:21 + --> $DIR/const_panic.rs:24:21 | LL | const Z2_CORE: () = core::panic!(); | --------------------^^^^^^^^^^^^^^- | | - | the evaluated program panicked at 'explicit panic', $DIR/const_panic.rs:19:21 + | the evaluated program panicked at 'explicit panic', $DIR/const_panic.rs:24:21 | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: any use of this value will cause an error - --> $DIR/const_panic.rs:22:20 + --> $DIR/const_panic.rs:27:20 | LL | const Y_CORE: () = core::unreachable!(); | -------------------^^^^^^^^^^^^^^^^^^^^- | | - | the evaluated program panicked at 'internal error: entered unreachable code', $DIR/const_panic.rs:22:20 + | the evaluated program panicked at 'internal error: entered unreachable code', $DIR/const_panic.rs:27:20 | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: any use of this value will cause an error - --> $DIR/const_panic.rs:25:20 + --> $DIR/const_panic.rs:30:20 | LL | const X_CORE: () = core::unimplemented!(); | -------------------^^^^^^^^^^^^^^^^^^^^^^- | | - | the evaluated program panicked at 'not implemented', $DIR/const_panic.rs:25:20 + | the evaluated program panicked at 'not implemented', $DIR/const_panic.rs:30:20 + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: 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 8 previous errors +error: aborting due to 10 previous errors diff --git a/src/test/ui/issues/issue-44333.rs b/src/test/ui/consts/const_in_pattern/issue-44333.rs similarity index 100% rename from src/test/ui/issues/issue-44333.rs rename to src/test/ui/consts/const_in_pattern/issue-44333.rs diff --git a/src/test/ui/issues/issue-44333.stderr b/src/test/ui/consts/const_in_pattern/issue-44333.stderr similarity index 100% rename from src/test/ui/issues/issue-44333.stderr rename to src/test/ui/consts/const_in_pattern/issue-44333.stderr diff --git a/src/test/ui/consts/const_in_pattern/issue-53708.rs b/src/test/ui/consts/const_in_pattern/issue-53708.rs new file mode 100644 index 0000000000000..355ba63790f3b --- /dev/null +++ b/src/test/ui/consts/const_in_pattern/issue-53708.rs @@ -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 => {} + } +} diff --git a/src/test/ui/consts/const_in_pattern/issue-78057.rs b/src/test/ui/consts/const_in_pattern/issue-78057.rs new file mode 100644 index 0000000000000..69cf8404da18e --- /dev/null +++ b/src/test/ui/consts/const_in_pattern/issue-78057.rs @@ -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 + } +} diff --git a/src/test/ui/consts/const_in_pattern/issue-78057.stderr b/src/test/ui/consts/const_in_pattern/issue-78057.stderr new file mode 100644 index 0000000000000..0d49d0e96c854 --- /dev/null +++ b/src/test/ui/consts/const_in_pattern/issue-78057.stderr @@ -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 + diff --git a/src/test/ui/consts/control-flow/assert.panic.stderr b/src/test/ui/consts/control-flow/assert.const_panic.stderr similarity index 100% rename from src/test/ui/consts/control-flow/assert.panic.stderr rename to src/test/ui/consts/control-flow/assert.const_panic.stderr diff --git a/src/test/ui/consts/control-flow/assert.rs b/src/test/ui/consts/control-flow/assert.rs index 30cd31ee8a734..90017fee19337 100644 --- a/src/test/ui/consts/control-flow/assert.rs +++ b/src/test/ui/consts/control-flow/assert.rs @@ -1,14 +1,14 @@ // Test that `assert` works when `const_panic` is enabled. -// revisions: stock panic +// revisions: stock const_panic -#![cfg_attr(panic, feature(const_panic))] +#![cfg_attr(const_panic, feature(const_panic))] const _: () = assert!(true); //[stock]~^ ERROR panicking in constants is unstable const _: () = assert!(false); //[stock]~^ ERROR panicking in constants is unstable -//[panic]~^^ ERROR any use of this value will cause an error +//[const_panic]~^^ ERROR any use of this value will cause an error fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-cfg-panic.rs b/src/test/ui/feature-gates/feature-gate-cfg-panic.rs new file mode 100644 index 0000000000000..1508374d94266 --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-cfg-panic.rs @@ -0,0 +1,11 @@ +#[cfg(panic = "unwind")] +//~^ ERROR `cfg(panic)` is experimental and subject to change +fn foo() -> bool { true } +#[cfg(not(panic = "unwind"))] +//~^ ERROR `cfg(panic)` is experimental and subject to change +fn foo() -> bool { false } + + +fn main() { + assert!(foo()); +} diff --git a/src/test/ui/feature-gates/feature-gate-cfg-panic.stderr b/src/test/ui/feature-gates/feature-gate-cfg-panic.stderr new file mode 100644 index 0000000000000..ea5cd54fa90f0 --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-cfg-panic.stderr @@ -0,0 +1,21 @@ +error[E0658]: `cfg(panic)` is experimental and subject to change + --> $DIR/feature-gate-cfg-panic.rs:1:7 + | +LL | #[cfg(panic = "unwind")] + | ^^^^^^^^^^^^^^^^ + | + = note: see issue #77443 for more information + = help: add `#![feature(cfg_panic)]` to the crate attributes to enable + +error[E0658]: `cfg(panic)` is experimental and subject to change + --> $DIR/feature-gate-cfg-panic.rs:4:11 + | +LL | #[cfg(not(panic = "unwind"))] + | ^^^^^^^^^^^^^^^^ + | + = note: see issue #77443 for more information + = help: add `#![feature(cfg_panic)]` to the crate attributes to enable + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/fmt/format-args-capture.rs b/src/test/ui/fmt/format-args-capture.rs index 7490632110c85..c883ee6bb7afe 100644 --- a/src/test/ui/fmt/format-args-capture.rs +++ b/src/test/ui/fmt/format-args-capture.rs @@ -1,13 +1,16 @@ // run-pass -// ignore-wasm32 -// ignore-wasm64 #![feature(format_args_capture)] +#![feature(cfg_panic)] fn main() { named_argument_takes_precedence_to_captured(); - panic_with_single_argument_does_not_get_formatted(); - panic_with_multiple_arguments_is_formatted(); formatting_parameters_can_be_captured(); + + #[cfg(not(panic = "abort"))] + { + panic_with_single_argument_does_not_get_formatted(); + panic_with_multiple_arguments_is_formatted(); + } } fn named_argument_takes_precedence_to_captured() { diff --git a/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs b/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs index 24474cabf1e37..4a91198ab9f6f 100644 --- a/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs +++ b/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs @@ -53,8 +53,8 @@ enum LR_NonZero { fn test_panic_msg(op: impl (FnOnce() -> T) + panic::UnwindSafe, msg: &str) { let err = panic::catch_unwind(op).err(); assert_eq!( - err.as_ref().and_then(|a| a.downcast_ref::()).map(|s| &**s), - Some(msg) + err.as_ref().and_then(|a| a.downcast_ref::<&str>()), + Some(&msg) ); } diff --git a/src/test/ui/issues/issue-68696-catch-during-unwind.rs b/src/test/ui/issues/issue-68696-catch-during-unwind.rs index d042bed225d17..f25a78f59cd20 100644 --- a/src/test/ui/issues/issue-68696-catch-during-unwind.rs +++ b/src/test/ui/issues/issue-68696-catch-during-unwind.rs @@ -4,8 +4,7 @@ // entering the catch_unwind. // // run-pass -// ignore-wasm no panic support -// ignore-emscripten no panic support +#![feature(cfg_panic)] use std::panic::catch_unwind; @@ -19,6 +18,7 @@ impl Drop for Guard { } fn main() { + #[cfg(panic = "unwind")] let _ = catch_unwind(|| { let _guard = Guard::default(); panic!(); diff --git a/src/test/ui/issues/issue-77919.rs b/src/test/ui/issues/issue-77919.rs new file mode 100644 index 0000000000000..9b04d5ee0008d --- /dev/null +++ b/src/test/ui/issues/issue-77919.rs @@ -0,0 +1,13 @@ +fn main() { + [1; >::VAL]; //~ ERROR evaluation of constant value failed +} +trait TypeVal { + const VAL: T; //~ ERROR any use of this value will cause an error +} +struct Five; +struct Multiply { + _n: PhantomData, //~ ERROR cannot find type `PhantomData` in this scope +} +impl TypeVal for Multiply where N: TypeVal {} +//~^ ERROR cannot find type `VAL` in this scope +//~| ERROR not all trait items implemented, missing: `VAL` diff --git a/src/test/ui/issues/issue-77919.stderr b/src/test/ui/issues/issue-77919.stderr new file mode 100644 index 0000000000000..129af00644fff --- /dev/null +++ b/src/test/ui/issues/issue-77919.stderr @@ -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 TypeVal for Multiply where N: TypeVal {} + | - ^^^ 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 TypeVal for Multiply where N: TypeVal {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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; >::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`. diff --git a/src/test/ui/pattern/usefulness/consts-opaque.rs b/src/test/ui/pattern/usefulness/consts-opaque.rs new file mode 100644 index 0000000000000..f87f96e34fccd --- /dev/null +++ b/src/test/ui/pattern/usefulness/consts-opaque.rs @@ -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 => {} + _ => {} + } +} diff --git a/src/test/ui/pattern/usefulness/consts-opaque.stderr b/src/test/ui/pattern/usefulness/consts-opaque.stderr new file mode 100644 index 0000000000000..f10166d5a3580 --- /dev/null +++ b/src/test/ui/pattern/usefulness/consts-opaque.stderr @@ -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 + +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 + diff --git a/src/test/ui/pattern/usefulness/match-byte-array-patterns-2.stderr b/src/test/ui/pattern/usefulness/match-byte-array-patterns-2.stderr index ffc8433403fd5..7968f9713ff22 100644 --- a/src/test/ui/pattern/usefulness/match-byte-array-patterns-2.stderr +++ b/src/test/ui/pattern/usefulness/match-byte-array-patterns-2.stderr @@ -7,11 +7,11 @@ LL | match buf { = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `&[u8; 4]` -error[E0004]: non-exhaustive patterns: `&[]`, `&[_]`, `&[_, _]` and 2 more not covered +error[E0004]: non-exhaustive patterns: `&[0_u8..=64_u8, _, _, _]` and `&[66_u8..=u8::MAX, _, _, _]` not covered --> $DIR/match-byte-array-patterns-2.rs:10:11 | LL | match buf { - | ^^^ patterns `&[]`, `&[_]`, `&[_, _]` and 2 more not covered + | ^^^ patterns `&[0_u8..=64_u8, _, _, _]` and `&[66_u8..=u8::MAX, _, _, _]` not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `&[u8]` diff --git a/src/test/ui/test-attrs/test-allow-fail-attr.rs b/src/test/ui/test-attrs/test-allow-fail-attr.rs index 1a478460efc6c..29ce9f7c2e94f 100644 --- a/src/test/ui/test-attrs/test-allow-fail-attr.rs +++ b/src/test/ui/test-attrs/test-allow-fail-attr.rs @@ -1,11 +1,12 @@ // run-pass -// ignore-wasm32-bare compiled with panic=abort by default // compile-flags: --test #![feature(allow_fail)] +#![feature(cfg_panic)] #[test] #[allow_fail] fn test1() { + #[cfg(not(panic = "abort"))] panic!(); }