Auto merge of #64766 - Centril:rollup-gdy5jr6, r=Centril
Rollup of 6 pull requests Successful merges: - #62975 (Almost fully deprecate hir::map::Map.hir_to_node_id) - #64386 (use `sign` variable in abs and wrapping_abs methods) - #64508 (or-patterns: Push `PatKind/PatternKind::Or` at top level to HIR & HAIR) - #64738 (Add const-eval support for SIMD types, insert, and extract) - #64759 (Refactor mbe a tiny bit) - #64764 (Master is now 1.40 ) Failed merges: r? @ghost
This commit is contained in:
commit
6c2c29c432
@ -13,7 +13,7 @@ use build_helper::output;
|
||||
use crate::Build;
|
||||
|
||||
// The version number
|
||||
pub const CFG_RELEASE_NUM: &str = "1.39.0";
|
||||
pub const CFG_RELEASE_NUM: &str = "1.40.0";
|
||||
|
||||
pub struct GitInfo {
|
||||
inner: Option<Info>,
|
||||
|
@ -240,7 +240,6 @@ pub(crate) unsafe fn box_free<T: ?Sized>(ptr: Unique<T>) {
|
||||
#[stable(feature = "global_alloc", since = "1.28.0")]
|
||||
#[rustc_allocator_nounwind]
|
||||
pub fn handle_alloc_error(layout: Layout) -> ! {
|
||||
#[cfg_attr(bootstrap, allow(improper_ctypes))]
|
||||
extern "Rust" {
|
||||
#[lang = "oom"]
|
||||
fn oom_impl(layout: Layout) -> !;
|
||||
|
@ -117,7 +117,6 @@
|
||||
#![feature(allocator_internals)]
|
||||
#![feature(on_unimplemented)]
|
||||
#![feature(rustc_const_unstable)]
|
||||
#![cfg_attr(bootstrap, feature(const_vec_new))]
|
||||
#![feature(slice_partition_dedup)]
|
||||
#![feature(maybe_uninit_extra, maybe_uninit_slice)]
|
||||
#![feature(alloc_layout_extra)]
|
||||
|
@ -369,7 +369,6 @@ impl String {
|
||||
/// ```
|
||||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_string_new"))]
|
||||
pub const fn new() -> String {
|
||||
String { vec: Vec::new() }
|
||||
}
|
||||
|
@ -291,7 +291,7 @@ use crate::raw_vec::RawVec;
|
||||
/// [`reserve`]: ../../std/vec/struct.Vec.html#method.reserve
|
||||
/// [owned slice]: ../../std/boxed/struct.Box.html
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[cfg_attr(all(not(bootstrap), not(test)), rustc_diagnostic_item = "vec_type")]
|
||||
#[cfg_attr(not(test), rustc_diagnostic_item = "vec_type")]
|
||||
pub struct Vec<T> {
|
||||
buf: RawVec<T>,
|
||||
len: usize,
|
||||
@ -314,7 +314,6 @@ impl<T> Vec<T> {
|
||||
/// ```
|
||||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_vec_new"))]
|
||||
pub const fn new() -> Vec<T> {
|
||||
Vec {
|
||||
buf: RawVec::NEW,
|
||||
|
@ -1,6 +1,5 @@
|
||||
//! impl bool {}
|
||||
|
||||
#[cfg(not(bootstrap))]
|
||||
#[lang = "bool"]
|
||||
impl bool {
|
||||
/// Returns `Some(t)` if the `bool` is `true`, or `None` otherwise.
|
||||
|
@ -135,7 +135,6 @@ pub trait Clone : Sized {
|
||||
|
||||
/// Derive macro generating an impl of the trait `Clone`.
|
||||
#[rustc_builtin_macro]
|
||||
#[cfg_attr(bootstrap, rustc_macro_transparency = "semitransparent")]
|
||||
#[stable(feature = "builtin_macro_prelude", since = "1.38.0")]
|
||||
#[allow_internal_unstable(core_intrinsics, derive_clone_copy)]
|
||||
pub macro Clone($item:item) { /* compiler built-in */ }
|
||||
|
@ -210,7 +210,6 @@ pub trait PartialEq<Rhs: ?Sized = Self> {
|
||||
|
||||
/// Derive macro generating an impl of the trait `PartialEq`.
|
||||
#[rustc_builtin_macro]
|
||||
#[cfg_attr(bootstrap, rustc_macro_transparency = "semitransparent")]
|
||||
#[stable(feature = "builtin_macro_prelude", since = "1.38.0")]
|
||||
#[allow_internal_unstable(core_intrinsics)]
|
||||
pub macro PartialEq($item:item) { /* compiler built-in */ }
|
||||
@ -273,7 +272,6 @@ pub trait Eq: PartialEq<Self> {
|
||||
|
||||
/// Derive macro generating an impl of the trait `Eq`.
|
||||
#[rustc_builtin_macro]
|
||||
#[cfg_attr(bootstrap, rustc_macro_transparency = "semitransparent")]
|
||||
#[stable(feature = "builtin_macro_prelude", since = "1.38.0")]
|
||||
#[allow_internal_unstable(core_intrinsics, derive_eq)]
|
||||
pub macro Eq($item:item) { /* compiler built-in */ }
|
||||
@ -624,7 +622,6 @@ pub trait Ord: Eq + PartialOrd<Self> {
|
||||
|
||||
/// Derive macro generating an impl of the trait `Ord`.
|
||||
#[rustc_builtin_macro]
|
||||
#[cfg_attr(bootstrap, rustc_macro_transparency = "semitransparent")]
|
||||
#[stable(feature = "builtin_macro_prelude", since = "1.38.0")]
|
||||
#[allow_internal_unstable(core_intrinsics)]
|
||||
pub macro Ord($item:item) { /* compiler built-in */ }
|
||||
@ -873,7 +870,6 @@ pub trait PartialOrd<Rhs: ?Sized = Self>: PartialEq<Rhs> {
|
||||
|
||||
/// Derive macro generating an impl of the trait `PartialOrd`.
|
||||
#[rustc_builtin_macro]
|
||||
#[cfg_attr(bootstrap, rustc_macro_transparency = "semitransparent")]
|
||||
#[stable(feature = "builtin_macro_prelude", since = "1.38.0")]
|
||||
#[allow_internal_unstable(core_intrinsics)]
|
||||
pub macro PartialOrd($item:item) { /* compiler built-in */ }
|
||||
|
@ -117,7 +117,6 @@ pub trait Default: Sized {
|
||||
|
||||
/// Derive macro generating an impl of the trait `Default`.
|
||||
#[rustc_builtin_macro]
|
||||
#[cfg_attr(bootstrap, rustc_macro_transparency = "semitransparent")]
|
||||
#[stable(feature = "builtin_macro_prelude", since = "1.38.0")]
|
||||
#[allow_internal_unstable(core_intrinsics)]
|
||||
pub macro Default($item:item) { /* compiler built-in */ }
|
||||
|
@ -518,8 +518,7 @@ impl Display for Arguments<'_> {
|
||||
label="`{Self}` cannot be formatted using `{{:?}}` because it doesn't implement `{Debug}`",
|
||||
)]
|
||||
#[doc(alias = "{:?}")]
|
||||
#[cfg_attr(bootstrap, lang = "debug_trait")]
|
||||
#[cfg_attr(not(bootstrap), rustc_diagnostic_item = "debug_trait")]
|
||||
#[rustc_diagnostic_item = "debug_trait"]
|
||||
pub trait Debug {
|
||||
/// Formats the value using the given formatter.
|
||||
///
|
||||
@ -550,7 +549,6 @@ pub trait Debug {
|
||||
pub(crate) mod macros {
|
||||
/// Derive macro generating an impl of the trait `Debug`.
|
||||
#[rustc_builtin_macro]
|
||||
#[cfg_attr(bootstrap, rustc_macro_transparency = "semitransparent")]
|
||||
#[stable(feature = "builtin_macro_prelude", since = "1.38.0")]
|
||||
#[allow_internal_unstable(core_intrinsics)]
|
||||
pub macro Debug($item:item) { /* compiler built-in */ }
|
||||
|
@ -202,7 +202,6 @@ pub trait Hash {
|
||||
pub(crate) mod macros {
|
||||
/// Derive macro generating an impl of the trait `Hash`.
|
||||
#[rustc_builtin_macro]
|
||||
#[cfg_attr(bootstrap, rustc_macro_transparency = "semitransparent")]
|
||||
#[stable(feature = "builtin_macro_prelude", since = "1.38.0")]
|
||||
#[allow_internal_unstable(core_intrinsics)]
|
||||
pub macro Hash($item:item) { /* compiler built-in */ }
|
||||
|
@ -1299,38 +1299,16 @@ extern "rust-intrinsic" {
|
||||
/// The stabilized versions of this intrinsic are available on the integer
|
||||
/// primitives via the `wrapping_add` method. For example,
|
||||
/// [`std::u32::wrapping_add`](../../std/primitive.u32.html#method.wrapping_add)
|
||||
#[cfg(bootstrap)]
|
||||
pub fn overflowing_add<T>(a: T, b: T) -> T;
|
||||
/// Returns (a - b) mod 2<sup>N</sup>, where N is the width of T in bits.
|
||||
/// The stabilized versions of this intrinsic are available on the integer
|
||||
/// primitives via the `wrapping_sub` method. For example,
|
||||
/// [`std::u32::wrapping_sub`](../../std/primitive.u32.html#method.wrapping_sub)
|
||||
#[cfg(bootstrap)]
|
||||
pub fn overflowing_sub<T>(a: T, b: T) -> T;
|
||||
/// Returns (a * b) mod 2<sup>N</sup>, where N is the width of T in bits.
|
||||
/// The stabilized versions of this intrinsic are available on the integer
|
||||
/// primitives via the `wrapping_mul` method. For example,
|
||||
/// [`std::u32::wrapping_mul`](../../std/primitive.u32.html#method.wrapping_mul)
|
||||
#[cfg(bootstrap)]
|
||||
pub fn overflowing_mul<T>(a: T, b: T) -> T;
|
||||
|
||||
/// Returns (a + b) mod 2<sup>N</sup>, where N is the width of T in bits.
|
||||
/// The stabilized versions of this intrinsic are available on the integer
|
||||
/// primitives via the `wrapping_add` method. For example,
|
||||
/// [`std::u32::wrapping_add`](../../std/primitive.u32.html#method.wrapping_add)
|
||||
#[cfg(not(bootstrap))]
|
||||
pub fn wrapping_add<T>(a: T, b: T) -> T;
|
||||
/// Returns (a - b) mod 2<sup>N</sup>, where N is the width of T in bits.
|
||||
/// The stabilized versions of this intrinsic are available on the integer
|
||||
/// primitives via the `wrapping_sub` method. For example,
|
||||
/// [`std::u32::wrapping_sub`](../../std/primitive.u32.html#method.wrapping_sub)
|
||||
#[cfg(not(bootstrap))]
|
||||
pub fn wrapping_sub<T>(a: T, b: T) -> T;
|
||||
/// Returns (a * b) mod 2<sup>N</sup>, where N is the width of T in bits.
|
||||
/// The stabilized versions of this intrinsic are available on the integer
|
||||
/// primitives via the `wrapping_mul` method. For example,
|
||||
/// [`std::u32::wrapping_mul`](../../std/primitive.u32.html#method.wrapping_mul)
|
||||
#[cfg(not(bootstrap))]
|
||||
pub fn wrapping_mul<T>(a: T, b: T) -> T;
|
||||
|
||||
/// Computes `a + b`, while saturating at numeric bounds.
|
||||
|
@ -87,7 +87,6 @@
|
||||
#![feature(link_llvm_intrinsics)]
|
||||
#![feature(never_type)]
|
||||
#![feature(nll)]
|
||||
#![cfg_attr(bootstrap, feature(bind_by_move_pattern_guards))]
|
||||
#![feature(exhaustive_patterns)]
|
||||
#![feature(no_core)]
|
||||
#![feature(on_unimplemented)]
|
||||
@ -120,9 +119,6 @@
|
||||
#![feature(rtm_target_feature)]
|
||||
#![feature(f16c_target_feature)]
|
||||
#![feature(hexagon_target_feature)]
|
||||
#![cfg_attr(bootstrap, feature(const_slice_len))]
|
||||
#![cfg_attr(bootstrap, feature(const_str_as_bytes))]
|
||||
#![cfg_attr(bootstrap, feature(const_str_len))]
|
||||
#![feature(const_int_conversion)]
|
||||
#![feature(const_transmute)]
|
||||
#![feature(non_exhaustive)]
|
||||
|
@ -1236,10 +1236,8 @@ pub(crate) mod builtin {
|
||||
pub macro test($item:item) { /* compiler built-in */ }
|
||||
|
||||
/// Attribute macro applied to a function to turn it into a benchmark test.
|
||||
#[cfg_attr(not(bootstrap), unstable(soft, feature = "test", issue = "50297",
|
||||
reason = "`bench` is a part of custom test frameworks which are unstable"))]
|
||||
#[cfg_attr(bootstrap, unstable(feature = "test", issue = "50297",
|
||||
reason = "`bench` is a part of custom test frameworks which are unstable"))]
|
||||
#[unstable(soft, feature = "test", issue = "50297",
|
||||
reason = "`bench` is a part of custom test frameworks which are unstable")]
|
||||
#[allow_internal_unstable(test, rustc_attrs)]
|
||||
#[rustc_builtin_macro]
|
||||
pub macro bench($item:item) { /* compiler built-in */ }
|
||||
|
@ -290,7 +290,6 @@ pub trait Copy : Clone {
|
||||
|
||||
/// Derive macro generating an impl of the trait `Copy`.
|
||||
#[rustc_builtin_macro]
|
||||
#[cfg_attr(bootstrap, rustc_macro_transparency = "semitransparent")]
|
||||
#[stable(feature = "builtin_macro_prelude", since = "1.38.0")]
|
||||
#[allow_internal_unstable(core_intrinsics, derive_clone_copy)]
|
||||
pub macro Copy($item:item) { /* compiler built-in */ }
|
||||
|
@ -1112,13 +1112,7 @@ $EndFeature, "
|
||||
without modifying the original"]
|
||||
#[inline]
|
||||
pub const fn wrapping_add(self, rhs: Self) -> Self {
|
||||
#[cfg(bootstrap)] {
|
||||
intrinsics::overflowing_add(self, rhs)
|
||||
}
|
||||
|
||||
#[cfg(not(bootstrap))] {
|
||||
intrinsics::wrapping_add(self, rhs)
|
||||
}
|
||||
intrinsics::wrapping_add(self, rhs)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1141,13 +1135,7 @@ $EndFeature, "
|
||||
without modifying the original"]
|
||||
#[inline]
|
||||
pub const fn wrapping_sub(self, rhs: Self) -> Self {
|
||||
#[cfg(bootstrap)] {
|
||||
intrinsics::overflowing_sub(self, rhs)
|
||||
}
|
||||
|
||||
#[cfg(not(bootstrap))] {
|
||||
intrinsics::wrapping_sub(self, rhs)
|
||||
}
|
||||
intrinsics::wrapping_sub(self, rhs)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1169,13 +1157,7 @@ $EndFeature, "
|
||||
without modifying the original"]
|
||||
#[inline]
|
||||
pub const fn wrapping_mul(self, rhs: Self) -> Self {
|
||||
#[cfg(bootstrap)] {
|
||||
intrinsics::overflowing_mul(self, rhs)
|
||||
}
|
||||
|
||||
#[cfg(not(bootstrap))] {
|
||||
intrinsics::wrapping_mul(self, rhs)
|
||||
}
|
||||
intrinsics::wrapping_mul(self, rhs)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1402,7 +1384,16 @@ $EndFeature, "
|
||||
#[stable(feature = "no_panic_abs", since = "1.13.0")]
|
||||
#[inline]
|
||||
pub const fn wrapping_abs(self) -> Self {
|
||||
(self ^ (self >> ($BITS - 1))).wrapping_sub(self >> ($BITS - 1))
|
||||
// sign is -1 (all ones) for negative numbers, 0 otherwise.
|
||||
let sign = self >> ($BITS - 1);
|
||||
// For positive self, sign == 0 so the expression is simply
|
||||
// (self ^ 0).wrapping_sub(0) == self == abs(self).
|
||||
//
|
||||
// For negative self, self ^ sign == self ^ all_ones.
|
||||
// But all_ones ^ self == all_ones - self == -1 - self.
|
||||
// So for negative numbers, (self ^ sign).wrapping_sub(sign) is
|
||||
// (-1 - self).wrapping_sub(-1) == -self == abs(self).
|
||||
(self ^ sign).wrapping_sub(sign)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1761,7 +1752,7 @@ $EndFeature, "
|
||||
#[stable(feature = "no_panic_abs", since = "1.13.0")]
|
||||
#[inline]
|
||||
pub const fn overflowing_abs(self) -> (Self, bool) {
|
||||
(self ^ (self >> ($BITS - 1))).overflowing_sub(self >> ($BITS - 1))
|
||||
(self.wrapping_abs(), self == Self::min_value())
|
||||
}
|
||||
}
|
||||
|
||||
@ -1969,7 +1960,21 @@ $EndFeature, "
|
||||
// Note that the #[inline] above means that the overflow
|
||||
// semantics of the subtraction depend on the crate we're being
|
||||
// inlined into.
|
||||
(self ^ (self >> ($BITS - 1))) - (self >> ($BITS - 1))
|
||||
|
||||
// sign is -1 (all ones) for negative numbers, 0 otherwise.
|
||||
let sign = self >> ($BITS - 1);
|
||||
// For positive self, sign == 0 so the expression is simply
|
||||
// (self ^ 0) - 0 == self == abs(self).
|
||||
//
|
||||
// For negative self, self ^ sign == self ^ all_ones.
|
||||
// But all_ones ^ self == all_ones - self == -1 - self.
|
||||
// So for negative numbers, (self ^ sign) - sign is
|
||||
// (-1 - self) - -1 == -self == abs(self).
|
||||
//
|
||||
// The subtraction overflows when self is min_value(), because
|
||||
// (-1 - min_value()) - -1 is max_value() - -1 which overflows.
|
||||
// This is exactly when we want self.abs() to overflow.
|
||||
(self ^ sign) - sign
|
||||
}
|
||||
}
|
||||
|
||||
@ -3040,13 +3045,7 @@ $EndFeature, "
|
||||
without modifying the original"]
|
||||
#[inline]
|
||||
pub const fn wrapping_add(self, rhs: Self) -> Self {
|
||||
#[cfg(bootstrap)] {
|
||||
intrinsics::overflowing_add(self, rhs)
|
||||
}
|
||||
|
||||
#[cfg(not(bootstrap))] {
|
||||
intrinsics::wrapping_add(self, rhs)
|
||||
}
|
||||
intrinsics::wrapping_add(self, rhs)
|
||||
}
|
||||
}
|
||||
|
||||
@ -3068,13 +3067,7 @@ $EndFeature, "
|
||||
without modifying the original"]
|
||||
#[inline]
|
||||
pub const fn wrapping_sub(self, rhs: Self) -> Self {
|
||||
#[cfg(bootstrap)] {
|
||||
intrinsics::overflowing_sub(self, rhs)
|
||||
}
|
||||
|
||||
#[cfg(not(bootstrap))] {
|
||||
intrinsics::wrapping_sub(self, rhs)
|
||||
}
|
||||
intrinsics::wrapping_sub(self, rhs)
|
||||
}
|
||||
}
|
||||
|
||||
@ -3097,13 +3090,7 @@ $EndFeature, "
|
||||
without modifying the original"]
|
||||
#[inline]
|
||||
pub const fn wrapping_mul(self, rhs: Self) -> Self {
|
||||
#[cfg(bootstrap)] {
|
||||
intrinsics::overflowing_mul(self, rhs)
|
||||
}
|
||||
|
||||
#[cfg(not(bootstrap))] {
|
||||
intrinsics::wrapping_mul(self, rhs)
|
||||
}
|
||||
intrinsics::wrapping_mul(self, rhs)
|
||||
}
|
||||
|
||||
doc_comment! {
|
||||
|
@ -71,7 +71,6 @@ pub fn panic_fmt(fmt: fmt::Arguments<'_>, file_line_col: &(&'static str, u32, u3
|
||||
}
|
||||
|
||||
// NOTE This function never crosses the FFI boundary; it's a Rust-to-Rust call
|
||||
#[cfg_attr(bootstrap, allow(improper_ctypes))]
|
||||
extern "Rust" {
|
||||
#[lang = "panic_impl"]
|
||||
fn panic_impl(pi: &PanicInfo<'_>) -> !;
|
||||
|
@ -62,9 +62,8 @@ impl<T> [T] {
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[inline]
|
||||
#[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_slice_len"))]
|
||||
// SAFETY: const sound because we transmute out the length field as a usize (which it must be)
|
||||
#[cfg_attr(not(bootstrap), allow_internal_unstable(const_fn_union))]
|
||||
#[allow_internal_unstable(const_fn_union)]
|
||||
pub const fn len(&self) -> usize {
|
||||
unsafe {
|
||||
crate::ptr::Repr { rust: self }.raw.len
|
||||
@ -81,7 +80,6 @@ impl<T> [T] {
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[inline]
|
||||
#[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_slice_len"))]
|
||||
pub const fn is_empty(&self) -> bool {
|
||||
self.len() == 0
|
||||
}
|
||||
|
@ -2090,7 +2090,6 @@ impl str {
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[inline]
|
||||
#[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_str_len"))]
|
||||
pub const fn len(&self) -> usize {
|
||||
self.as_bytes().len()
|
||||
}
|
||||
@ -2110,7 +2109,6 @@ impl str {
|
||||
/// ```
|
||||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_str_len"))]
|
||||
pub const fn is_empty(&self) -> bool {
|
||||
self.len() == 0
|
||||
}
|
||||
@ -2168,9 +2166,8 @@ impl str {
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[inline(always)]
|
||||
#[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_str_as_bytes"))]
|
||||
// SAFETY: const sound because we transmute two types with the same layout
|
||||
#[cfg_attr(not(bootstrap), allow_internal_unstable(const_fn_union))]
|
||||
#[allow_internal_unstable(const_fn_union)]
|
||||
pub const fn as_bytes(&self) -> &[u8] {
|
||||
#[repr(C)]
|
||||
union Slices<'a> {
|
||||
|
@ -227,7 +227,7 @@ pub mod token_stream {
|
||||
/// To quote `$` itself, use `$$`.
|
||||
#[unstable(feature = "proc_macro_quote", issue = "54722")]
|
||||
#[allow_internal_unstable(proc_macro_def_site)]
|
||||
#[cfg_attr(not(bootstrap), rustc_builtin_macro)]
|
||||
#[rustc_builtin_macro]
|
||||
pub macro quote ($($t:tt)*) { /* compiler built-in */ }
|
||||
|
||||
#[unstable(feature = "proc_macro_internals", issue = "27812")]
|
||||
|
@ -1103,7 +1103,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) {
|
||||
|
||||
pub fn walk_arm<'v, V: Visitor<'v>>(visitor: &mut V, arm: &'v Arm) {
|
||||
visitor.visit_id(arm.hir_id);
|
||||
walk_list!(visitor, visit_pat, &arm.pats);
|
||||
visitor.visit_pat(&arm.pat);
|
||||
if let Some(ref g) = arm.guard {
|
||||
match g {
|
||||
Guard::If(ref e) => visitor.visit_expr(e),
|
||||
|
@ -97,7 +97,7 @@ pub struct LoweringContext<'a> {
|
||||
|
||||
trait_impls: BTreeMap<DefId, Vec<hir::HirId>>,
|
||||
|
||||
modules: BTreeMap<NodeId, hir::ModuleItems>,
|
||||
modules: BTreeMap<hir::HirId, hir::ModuleItems>,
|
||||
|
||||
generator_kind: Option<hir::GeneratorKind>,
|
||||
|
||||
@ -141,7 +141,7 @@ pub struct LoweringContext<'a> {
|
||||
/// vector.
|
||||
in_scope_lifetimes: Vec<ParamName>,
|
||||
|
||||
current_module: NodeId,
|
||||
current_module: hir::HirId,
|
||||
|
||||
type_def_lifetime_params: DefIdMap<usize>,
|
||||
|
||||
@ -262,7 +262,7 @@ pub fn lower_crate(
|
||||
is_in_dyn_type: false,
|
||||
anonymous_lifetime_mode: AnonymousLifetimeMode::PassThrough,
|
||||
type_def_lifetime_params: Default::default(),
|
||||
current_module: CRATE_NODE_ID,
|
||||
current_module: hir::CRATE_HIR_ID,
|
||||
current_hir_id_owner: vec![(CRATE_DEF_INDEX, 0)],
|
||||
item_local_id_counters: Default::default(),
|
||||
node_id_to_hir_id: IndexVec::new(),
|
||||
@ -434,35 +434,6 @@ impl<'a> LoweringContext<'a> {
|
||||
visit::walk_pat(self, p)
|
||||
}
|
||||
|
||||
// HACK(or_patterns; Centril | dlrobertson): Avoid creating
|
||||
// HIR nodes for `PatKind::Or` for the top level of a `ast::Arm`.
|
||||
// This is a temporary hack that should go away once we push down
|
||||
// `arm.pats: HirVec<P<Pat>>` -> `arm.pat: P<Pat>` to HIR. // Centril
|
||||
fn visit_arm(&mut self, arm: &'tcx Arm) {
|
||||
match &arm.pat.node {
|
||||
PatKind::Or(pats) => pats.iter().for_each(|p| self.visit_pat(p)),
|
||||
_ => self.visit_pat(&arm.pat),
|
||||
}
|
||||
walk_list!(self, visit_expr, &arm.guard);
|
||||
self.visit_expr(&arm.body);
|
||||
walk_list!(self, visit_attribute, &arm.attrs);
|
||||
}
|
||||
|
||||
// HACK(or_patterns; Centril | dlrobertson): Same as above. // Centril
|
||||
fn visit_expr(&mut self, e: &'tcx Expr) {
|
||||
if let ExprKind::Let(pat, scrutinee) = &e.node {
|
||||
walk_list!(self, visit_attribute, e.attrs.iter());
|
||||
match &pat.node {
|
||||
PatKind::Or(pats) => pats.iter().for_each(|p| self.visit_pat(p)),
|
||||
_ => self.visit_pat(&pat),
|
||||
}
|
||||
self.visit_expr(scrutinee);
|
||||
self.visit_expr_post(e);
|
||||
return;
|
||||
}
|
||||
visit::walk_expr(self, e)
|
||||
}
|
||||
|
||||
fn visit_item(&mut self, item: &'tcx Item) {
|
||||
let hir_id = self.lctx.allocate_hir_id_counter(item.id);
|
||||
|
||||
|
@ -247,14 +247,14 @@ impl LoweringContext<'_> {
|
||||
// 4. The return type of the block is `bool` which seems like what the user wanted.
|
||||
let scrutinee = self.lower_expr(scrutinee);
|
||||
let then_arm = {
|
||||
let pat = self.lower_pat_top_hack(pat);
|
||||
let pat = self.lower_pat(pat);
|
||||
let expr = self.expr_bool(span, true);
|
||||
self.arm(pat, P(expr))
|
||||
};
|
||||
let else_arm = {
|
||||
let pat = self.pat_wild(span);
|
||||
let expr = self.expr_bool(span, false);
|
||||
self.arm(hir_vec![pat], P(expr))
|
||||
self.arm(pat, P(expr))
|
||||
};
|
||||
hir::ExprKind::Match(
|
||||
P(scrutinee),
|
||||
@ -278,7 +278,7 @@ impl LoweringContext<'_> {
|
||||
None => (self.expr_block_empty(span), false),
|
||||
Some(els) => (self.lower_expr(els), true),
|
||||
};
|
||||
let else_arm = self.arm(hir_vec![else_pat], P(else_expr));
|
||||
let else_arm = self.arm(else_pat, P(else_expr));
|
||||
|
||||
// Handle then + scrutinee:
|
||||
let then_expr = self.lower_block_expr(then);
|
||||
@ -286,7 +286,7 @@ impl LoweringContext<'_> {
|
||||
// `<pat> => <then>`:
|
||||
ExprKind::Let(ref pat, ref scrutinee) => {
|
||||
let scrutinee = self.lower_expr(scrutinee);
|
||||
let pat = self.lower_pat_top_hack(pat);
|
||||
let pat = self.lower_pat(pat);
|
||||
(pat, scrutinee, hir::MatchSource::IfLetDesugar { contains_else_clause })
|
||||
}
|
||||
// `true => <then>`:
|
||||
@ -303,7 +303,7 @@ impl LoweringContext<'_> {
|
||||
// let temporaries live outside of `cond`.
|
||||
let cond = self.expr_drop_temps(span_block, P(cond), ThinVec::new());
|
||||
let pat = self.pat_bool(span, true);
|
||||
(hir_vec![pat], cond, hir::MatchSource::IfDesugar { contains_else_clause })
|
||||
(pat, cond, hir::MatchSource::IfDesugar { contains_else_clause })
|
||||
}
|
||||
};
|
||||
let then_arm = self.arm(then_pat, P(then_expr));
|
||||
@ -327,7 +327,7 @@ impl LoweringContext<'_> {
|
||||
let else_arm = {
|
||||
let else_pat = self.pat_wild(span);
|
||||
let else_expr = self.expr_break(span, ThinVec::new());
|
||||
self.arm(hir_vec![else_pat], else_expr)
|
||||
self.arm(else_pat, else_expr)
|
||||
};
|
||||
|
||||
// Handle then + scrutinee:
|
||||
@ -343,7 +343,7 @@ impl LoweringContext<'_> {
|
||||
// }
|
||||
// }
|
||||
let scrutinee = self.with_loop_condition_scope(|t| t.lower_expr(scrutinee));
|
||||
let pat = self.lower_pat_top_hack(pat);
|
||||
let pat = self.lower_pat(pat);
|
||||
(pat, scrutinee, hir::MatchSource::WhileLetDesugar, hir::LoopSource::WhileLet)
|
||||
}
|
||||
_ => {
|
||||
@ -371,7 +371,7 @@ impl LoweringContext<'_> {
|
||||
let cond = self.expr_drop_temps(span_block, P(cond), ThinVec::new());
|
||||
// `true => <then>`:
|
||||
let pat = self.pat_bool(span, true);
|
||||
(hir_vec![pat], cond, hir::MatchSource::WhileDesugar, hir::LoopSource::While)
|
||||
(pat, cond, hir::MatchSource::WhileDesugar, hir::LoopSource::While)
|
||||
}
|
||||
};
|
||||
let then_arm = self.arm(then_pat, P(then_expr));
|
||||
@ -424,7 +424,7 @@ impl LoweringContext<'_> {
|
||||
hir::Arm {
|
||||
hir_id: self.next_id(),
|
||||
attrs: self.lower_attrs(&arm.attrs),
|
||||
pats: self.lower_pat_top_hack(&arm.pat),
|
||||
pat: self.lower_pat(&arm.pat),
|
||||
guard: match arm.guard {
|
||||
Some(ref x) => Some(hir::Guard::If(P(self.lower_expr(x)))),
|
||||
_ => None,
|
||||
@ -434,16 +434,6 @@ impl LoweringContext<'_> {
|
||||
}
|
||||
}
|
||||
|
||||
/// HACK(or_patterns; Centril | dlrobertson): For now we don't push down top level or-patterns
|
||||
/// `p | q` into `hir::PatKind::Or(...)` as post-lowering bits of the compiler are not ready
|
||||
/// to deal with it. This should by fixed by pushing it down to HIR and then HAIR.
|
||||
fn lower_pat_top_hack(&mut self, pat: &Pat) -> HirVec<P<hir::Pat>> {
|
||||
match pat.node {
|
||||
PatKind::Or(ref ps) => ps.iter().map(|x| self.lower_pat(x)).collect(),
|
||||
_ => hir_vec![self.lower_pat(pat)],
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn make_async_expr(
|
||||
&mut self,
|
||||
capture_clause: CaptureBy,
|
||||
@ -592,7 +582,7 @@ impl LoweringContext<'_> {
|
||||
);
|
||||
P(this.expr(await_span, expr_break, ThinVec::new()))
|
||||
});
|
||||
self.arm(hir_vec![ready_pat], break_x)
|
||||
self.arm(ready_pat, break_x)
|
||||
};
|
||||
|
||||
// `::std::task::Poll::Pending => {}`
|
||||
@ -603,7 +593,7 @@ impl LoweringContext<'_> {
|
||||
hir_vec![],
|
||||
);
|
||||
let empty_block = P(self.expr_block_empty(span));
|
||||
self.arm(hir_vec![pending_pat], empty_block)
|
||||
self.arm(pending_pat, empty_block)
|
||||
};
|
||||
|
||||
let inner_match_stmt = {
|
||||
@ -645,7 +635,7 @@ impl LoweringContext<'_> {
|
||||
});
|
||||
|
||||
// mut pinned => loop { ... }
|
||||
let pinned_arm = self.arm(hir_vec![pinned_pat], loop_expr);
|
||||
let pinned_arm = self.arm(pinned_pat, loop_expr);
|
||||
|
||||
// match <expr> {
|
||||
// mut pinned => loop { .. }
|
||||
@ -1079,7 +1069,7 @@ impl LoweringContext<'_> {
|
||||
ThinVec::new(),
|
||||
));
|
||||
let some_pat = self.pat_some(pat.span, val_pat);
|
||||
self.arm(hir_vec![some_pat], assign)
|
||||
self.arm(some_pat, assign)
|
||||
};
|
||||
|
||||
// `::std::option::Option::None => break`
|
||||
@ -1087,7 +1077,7 @@ impl LoweringContext<'_> {
|
||||
let break_expr =
|
||||
self.with_loop_scope(e.id, |this| this.expr_break(e.span, ThinVec::new()));
|
||||
let pat = self.pat_none(e.span);
|
||||
self.arm(hir_vec![pat], break_expr)
|
||||
self.arm(pat, break_expr)
|
||||
};
|
||||
|
||||
// `mut iter`
|
||||
@ -1158,7 +1148,7 @@ impl LoweringContext<'_> {
|
||||
});
|
||||
|
||||
// `mut iter => { ... }`
|
||||
let iter_arm = self.arm(hir_vec![iter_pat], loop_expr);
|
||||
let iter_arm = self.arm(iter_pat, loop_expr);
|
||||
|
||||
// `match ::std::iter::IntoIterator::into_iter(<head>) { ... }`
|
||||
let into_iter_expr = {
|
||||
@ -1244,7 +1234,7 @@ impl LoweringContext<'_> {
|
||||
ThinVec::from(attrs.clone()),
|
||||
));
|
||||
let ok_pat = self.pat_ok(span, val_pat);
|
||||
self.arm(hir_vec![ok_pat], val_expr)
|
||||
self.arm(ok_pat, val_expr)
|
||||
};
|
||||
|
||||
// `Err(err) => #[allow(unreachable_code)]
|
||||
@ -1279,7 +1269,7 @@ impl LoweringContext<'_> {
|
||||
};
|
||||
|
||||
let err_pat = self.pat_err(try_span, err_local);
|
||||
self.arm(hir_vec![err_pat], ret_expr)
|
||||
self.arm(err_pat, ret_expr)
|
||||
};
|
||||
|
||||
hir::ExprKind::Match(
|
||||
@ -1474,14 +1464,11 @@ impl LoweringContext<'_> {
|
||||
}
|
||||
}
|
||||
|
||||
/// HACK(or_patterns; Centril | dlrobertson): For now we don't push down top level or-patterns
|
||||
/// `p | q` into `hir::PatKind::Or(...)` as post-lowering bits of the compiler are not ready
|
||||
/// to deal with it. This should by fixed by pushing it down to HIR and then HAIR.
|
||||
fn arm(&mut self, pats: HirVec<P<hir::Pat>>, expr: P<hir::Expr>) -> hir::Arm {
|
||||
fn arm(&mut self, pat: P<hir::Pat>, expr: P<hir::Expr>) -> hir::Arm {
|
||||
hir::Arm {
|
||||
hir_id: self.next_id(),
|
||||
attrs: hir_vec![],
|
||||
pats,
|
||||
pat,
|
||||
guard: None,
|
||||
span: expr.span,
|
||||
body: expr,
|
||||
|
@ -45,14 +45,16 @@ impl<'tcx, 'interner> ItemLowerer<'tcx, 'interner> {
|
||||
|
||||
impl<'tcx, 'interner> Visitor<'tcx> for ItemLowerer<'tcx, 'interner> {
|
||||
fn visit_mod(&mut self, m: &'tcx Mod, _s: Span, _attrs: &[Attribute], n: NodeId) {
|
||||
self.lctx.modules.insert(n, hir::ModuleItems {
|
||||
let hir_id = self.lctx.lower_node_id(n);
|
||||
|
||||
self.lctx.modules.insert(hir_id, hir::ModuleItems {
|
||||
items: BTreeSet::new(),
|
||||
trait_items: BTreeSet::new(),
|
||||
impl_items: BTreeSet::new(),
|
||||
});
|
||||
|
||||
let old = self.lctx.current_module;
|
||||
self.lctx.current_module = n;
|
||||
self.lctx.current_module = hir_id;
|
||||
visit::walk_mod(self, m);
|
||||
self.lctx.current_module = old;
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ pub fn check_crate(hir_map: &hir::map::Map<'_>) {
|
||||
let errors = Lock::new(Vec::new());
|
||||
|
||||
par_iter(&hir_map.krate().modules).for_each(|(module_id, _)| {
|
||||
let local_def_id = hir_map.local_def_id_from_node_id(*module_id);
|
||||
let local_def_id = hir_map.local_def_id(*module_id);
|
||||
hir_map.visit_item_likes_in_module(local_def_id, &mut OuterVisitor {
|
||||
hir_map,
|
||||
errors: &errors,
|
||||
|
@ -536,9 +536,7 @@ impl<'hir> Map<'hir> {
|
||||
// in the expect_* calls the loops below
|
||||
self.read(hir_id);
|
||||
|
||||
let node_id = self.hir_to_node_id[&hir_id];
|
||||
|
||||
let module = &self.forest.krate.modules[&node_id];
|
||||
let module = &self.forest.krate.modules[&hir_id];
|
||||
|
||||
for id in &module.items {
|
||||
visitor.visit_item(self.expect_item(*id));
|
||||
|
@ -766,7 +766,7 @@ pub struct Crate {
|
||||
|
||||
/// A list of modules written out in the order in which they
|
||||
/// appear in the crate. This includes the main crate module.
|
||||
pub modules: BTreeMap<NodeId, ModuleItems>,
|
||||
pub modules: BTreeMap<HirId, ModuleItems>,
|
||||
}
|
||||
|
||||
impl Crate {
|
||||
@ -882,44 +882,61 @@ impl fmt::Debug for Pat {
|
||||
|
||||
impl Pat {
|
||||
// FIXME(#19596) this is a workaround, but there should be a better way
|
||||
fn walk_<G>(&self, it: &mut G) -> bool
|
||||
where G: FnMut(&Pat) -> bool
|
||||
{
|
||||
fn walk_short_(&self, it: &mut impl FnMut(&Pat) -> bool) -> bool {
|
||||
if !it(self) {
|
||||
return false;
|
||||
}
|
||||
|
||||
match self.node {
|
||||
PatKind::Binding(.., Some(ref p)) => p.walk_(it),
|
||||
PatKind::Struct(_, ref fields, _) => {
|
||||
fields.iter().all(|field| field.pat.walk_(it))
|
||||
}
|
||||
PatKind::TupleStruct(_, ref s, _) | PatKind::Tuple(ref s, _) => {
|
||||
s.iter().all(|p| p.walk_(it))
|
||||
}
|
||||
PatKind::Or(ref pats) => pats.iter().all(|p| p.walk_(it)),
|
||||
PatKind::Box(ref s) | PatKind::Ref(ref s, _) => {
|
||||
s.walk_(it)
|
||||
}
|
||||
PatKind::Slice(ref before, ref slice, ref after) => {
|
||||
use PatKind::*;
|
||||
match &self.node {
|
||||
Wild | Lit(_) | Range(..) | Binding(.., None) | Path(_) => true,
|
||||
Box(s) | Ref(s, _) | Binding(.., Some(s)) => s.walk_short_(it),
|
||||
Struct(_, fields, _) => fields.iter().all(|field| field.pat.walk_short_(it)),
|
||||
TupleStruct(_, s, _) | Tuple(s, _) | Or(s) => s.iter().all(|p| p.walk_short_(it)),
|
||||
Slice(before, slice, after) => {
|
||||
before.iter()
|
||||
.chain(slice.iter())
|
||||
.chain(after.iter())
|
||||
.all(|p| p.walk_(it))
|
||||
}
|
||||
PatKind::Wild |
|
||||
PatKind::Lit(_) |
|
||||
PatKind::Range(..) |
|
||||
PatKind::Binding(..) |
|
||||
PatKind::Path(_) => {
|
||||
true
|
||||
.all(|p| p.walk_short_(it))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn walk<F>(&self, mut it: F) -> bool
|
||||
where F: FnMut(&Pat) -> bool
|
||||
{
|
||||
/// Walk the pattern in left-to-right order,
|
||||
/// short circuiting (with `.all(..)`) if `false` is returned.
|
||||
///
|
||||
/// Note that when visiting e.g. `Tuple(ps)`,
|
||||
/// if visiting `ps[0]` returns `false`,
|
||||
/// then `ps[1]` will not be visited.
|
||||
pub fn walk_short(&self, mut it: impl FnMut(&Pat) -> bool) -> bool {
|
||||
self.walk_short_(&mut it)
|
||||
}
|
||||
|
||||
// FIXME(#19596) this is a workaround, but there should be a better way
|
||||
fn walk_(&self, it: &mut impl FnMut(&Pat) -> bool) {
|
||||
if !it(self) {
|
||||
return;
|
||||
}
|
||||
|
||||
use PatKind::*;
|
||||
match &self.node {
|
||||
Wild | Lit(_) | Range(..) | Binding(.., None) | Path(_) => {},
|
||||
Box(s) | Ref(s, _) | Binding(.., Some(s)) => s.walk_(it),
|
||||
Struct(_, fields, _) => fields.iter().for_each(|field| field.pat.walk_(it)),
|
||||
TupleStruct(_, s, _) | Tuple(s, _) | Or(s) => s.iter().for_each(|p| p.walk_(it)),
|
||||
Slice(before, slice, after) => {
|
||||
before.iter()
|
||||
.chain(slice.iter())
|
||||
.chain(after.iter())
|
||||
.for_each(|p| p.walk_(it))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Walk the pattern in left-to-right order.
|
||||
///
|
||||
/// If `it(pat)` returns `false`, the children are not visited.
|
||||
pub fn walk(&self, mut it: impl FnMut(&Pat) -> bool) {
|
||||
self.walk_(&mut it)
|
||||
}
|
||||
}
|
||||
@ -1259,21 +1276,32 @@ pub struct Local {
|
||||
}
|
||||
|
||||
/// Represents a single arm of a `match` expression, e.g.
|
||||
/// `<pats> (if <guard>) => <body>`.
|
||||
/// `<pat> (if <guard>) => <body>`.
|
||||
#[derive(RustcEncodable, RustcDecodable, Debug, HashStable)]
|
||||
pub struct Arm {
|
||||
#[stable_hasher(ignore)]
|
||||
pub hir_id: HirId,
|
||||
pub span: Span,
|
||||
pub attrs: HirVec<Attribute>,
|
||||
/// Multiple patterns can be combined with `|`
|
||||
pub pats: HirVec<P<Pat>>,
|
||||
/// If this pattern and the optional guard matches, then `body` is evaluated.
|
||||
pub pat: P<Pat>,
|
||||
/// Optional guard clause.
|
||||
pub guard: Option<Guard>,
|
||||
/// The expression the arm evaluates to if this arm matches.
|
||||
pub body: P<Expr>,
|
||||
}
|
||||
|
||||
impl Arm {
|
||||
// HACK(or_patterns; Centril | dlrobertson): Remove this and
|
||||
// correctly handle each case in which this method is used.
|
||||
pub fn top_pats_hack(&self) -> &[P<Pat>] {
|
||||
match &self.pat.node {
|
||||
PatKind::Or(pats) => pats,
|
||||
_ => std::slice::from_ref(&self.pat),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(RustcEncodable, RustcDecodable, Debug, HashStable)]
|
||||
pub enum Guard {
|
||||
If(P<Expr>),
|
||||
|
@ -66,9 +66,7 @@ impl hir::Pat {
|
||||
|
||||
/// Call `f` on every "binding" in a pattern, e.g., on `a` in
|
||||
/// `match foo() { Some(a) => (), None => () }`
|
||||
pub fn each_binding<F>(&self, mut f: F)
|
||||
where F: FnMut(hir::BindingAnnotation, HirId, Span, ast::Ident),
|
||||
{
|
||||
pub fn each_binding(&self, mut f: impl FnMut(hir::BindingAnnotation, HirId, Span, ast::Ident)) {
|
||||
self.walk(|p| {
|
||||
if let PatKind::Binding(binding_mode, _, ident, _) = p.node {
|
||||
f(binding_mode, p.hir_id, p.span, ident);
|
||||
@ -77,35 +75,57 @@ impl hir::Pat {
|
||||
});
|
||||
}
|
||||
|
||||
/// Call `f` on every "binding" in a pattern, e.g., on `a` in
|
||||
/// `match foo() { Some(a) => (), None => () }`.
|
||||
///
|
||||
/// When encountering an or-pattern `p_0 | ... | p_n` only `p_0` will be visited.
|
||||
pub fn each_binding_or_first(
|
||||
&self,
|
||||
f: &mut impl FnMut(hir::BindingAnnotation, HirId, Span, ast::Ident),
|
||||
) {
|
||||
self.walk(|p| match &p.node {
|
||||
PatKind::Or(ps) => {
|
||||
ps[0].each_binding_or_first(f);
|
||||
false
|
||||
},
|
||||
PatKind::Binding(bm, _, ident, _) => {
|
||||
f(*bm, p.hir_id, p.span, *ident);
|
||||
true
|
||||
}
|
||||
_ => true,
|
||||
})
|
||||
}
|
||||
|
||||
/// Checks if the pattern contains any patterns that bind something to
|
||||
/// an ident, e.g., `foo`, or `Foo(foo)` or `foo @ Bar(..)`.
|
||||
pub fn contains_bindings(&self) -> bool {
|
||||
let mut contains_bindings = false;
|
||||
self.walk(|p| {
|
||||
if let PatKind::Binding(..) = p.node {
|
||||
contains_bindings = true;
|
||||
false // there's at least one binding, can short circuit now.
|
||||
} else {
|
||||
true
|
||||
}
|
||||
});
|
||||
contains_bindings
|
||||
self.satisfies(|p| match p.node {
|
||||
PatKind::Binding(..) => true,
|
||||
_ => false,
|
||||
})
|
||||
}
|
||||
|
||||
/// Checks if the pattern contains any patterns that bind something to
|
||||
/// an ident or wildcard, e.g., `foo`, or `Foo(_)`, `foo @ Bar(..)`,
|
||||
pub fn contains_bindings_or_wild(&self) -> bool {
|
||||
let mut contains_bindings = false;
|
||||
self.walk(|p| {
|
||||
match p.node {
|
||||
PatKind::Binding(..) | PatKind::Wild => {
|
||||
contains_bindings = true;
|
||||
false // there's at least one binding/wildcard, can short circuit now.
|
||||
}
|
||||
_ => true
|
||||
self.satisfies(|p| match p.node {
|
||||
PatKind::Binding(..) | PatKind::Wild => true,
|
||||
_ => false,
|
||||
})
|
||||
}
|
||||
|
||||
/// Checks if the pattern satisfies the given predicate on some sub-pattern.
|
||||
fn satisfies(&self, pred: impl Fn(&Self) -> bool) -> bool {
|
||||
let mut satisfies = false;
|
||||
self.walk_short(|p| {
|
||||
if pred(p) {
|
||||
satisfies = true;
|
||||
false // Found one, can short circuit now.
|
||||
} else {
|
||||
true
|
||||
}
|
||||
});
|
||||
contains_bindings
|
||||
satisfies
|
||||
}
|
||||
|
||||
pub fn simple_ident(&self) -> Option<ast::Ident> {
|
||||
@ -119,20 +139,20 @@ impl hir::Pat {
|
||||
/// Returns variants that are necessary to exist for the pattern to match.
|
||||
pub fn necessary_variants(&self) -> Vec<DefId> {
|
||||
let mut variants = vec![];
|
||||
self.walk(|p| {
|
||||
match p.node {
|
||||
PatKind::Path(hir::QPath::Resolved(_, ref path)) |
|
||||
PatKind::TupleStruct(hir::QPath::Resolved(_, ref path), ..) |
|
||||
PatKind::Struct(hir::QPath::Resolved(_, ref path), ..) => {
|
||||
match path.res {
|
||||
Res::Def(DefKind::Variant, id) => variants.push(id),
|
||||
Res::Def(DefKind::Ctor(CtorOf::Variant, ..), id) => variants.push(id),
|
||||
_ => ()
|
||||
}
|
||||
self.walk(|p| match &p.node {
|
||||
PatKind::Or(_) => false,
|
||||
PatKind::Path(hir::QPath::Resolved(_, path)) |
|
||||
PatKind::TupleStruct(hir::QPath::Resolved(_, path), ..) |
|
||||
PatKind::Struct(hir::QPath::Resolved(_, path), ..) => {
|
||||
if let Res::Def(DefKind::Variant, id)
|
||||
| Res::Def(DefKind::Ctor(CtorOf::Variant, ..), id)
|
||||
= path.res
|
||||
{
|
||||
variants.push(id);
|
||||
}
|
||||
_ => ()
|
||||
true
|
||||
}
|
||||
true
|
||||
_ => true,
|
||||
});
|
||||
variants.sort();
|
||||
variants.dedup();
|
||||
@ -148,33 +168,14 @@ impl hir::Pat {
|
||||
let mut result = None;
|
||||
self.each_binding(|annotation, _, _, _| {
|
||||
match annotation {
|
||||
hir::BindingAnnotation::Ref => {
|
||||
match result {
|
||||
None | Some(hir::MutImmutable) => result = Some(hir::MutImmutable),
|
||||
_ => (),
|
||||
}
|
||||
hir::BindingAnnotation::Ref => match result {
|
||||
None | Some(hir::MutImmutable) => result = Some(hir::MutImmutable),
|
||||
_ => {}
|
||||
}
|
||||
hir::BindingAnnotation::RefMut => result = Some(hir::MutMutable),
|
||||
_ => (),
|
||||
_ => {}
|
||||
}
|
||||
});
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
impl hir::Arm {
|
||||
/// Checks if the patterns for this arm contain any `ref` or `ref mut`
|
||||
/// bindings, and if yes whether its containing mutable ones or just immutables ones.
|
||||
pub fn contains_explicit_ref_binding(&self) -> Option<hir::Mutability> {
|
||||
// FIXME(tschottdorf): contains_explicit_ref_binding() must be removed
|
||||
// for #42640 (default match binding modes).
|
||||
//
|
||||
// See #44848.
|
||||
self.pats.iter()
|
||||
.filter_map(|pat| pat.contains_explicit_ref_binding())
|
||||
.max_by_key(|m| match *m {
|
||||
hir::MutMutable => 1,
|
||||
hir::MutImmutable => 0,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -1790,16 +1790,7 @@ impl<'a> State<'a> {
|
||||
self.ann.pre(self, AnnNode::Arm(arm));
|
||||
self.ibox(0);
|
||||
self.print_outer_attributes(&arm.attrs);
|
||||
let mut first = true;
|
||||
for p in &arm.pats {
|
||||
if first {
|
||||
first = false;
|
||||
} else {
|
||||
self.s.space();
|
||||
self.word_space("|");
|
||||
}
|
||||
self.print_pat(&p);
|
||||
}
|
||||
self.print_pat(&arm.pat);
|
||||
self.s.space();
|
||||
if let Some(ref g) = arm.guard {
|
||||
match g {
|
||||
|
@ -1510,7 +1510,7 @@ pub fn check_crate<'tcx, T: for<'a> LateLintPass<'a, 'tcx>>(
|
||||
time(tcx.sess, "module lints", || {
|
||||
// Run per-module lints
|
||||
par_iter(&tcx.hir().krate().modules).for_each(|(&module, _)| {
|
||||
tcx.ensure().lint_mod(tcx.hir().local_def_id_from_node_id(module));
|
||||
tcx.ensure().lint_mod(tcx.hir().local_def_id(module));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -259,19 +259,13 @@ impl<'a, 'tcx> Visitor<'tcx> for MarkSymbolVisitor<'a, 'tcx> {
|
||||
}
|
||||
|
||||
fn visit_arm(&mut self, arm: &'tcx hir::Arm) {
|
||||
if arm.pats.len() == 1 {
|
||||
let variants = arm.pats[0].necessary_variants();
|
||||
|
||||
// Inside the body, ignore constructions of variants
|
||||
// necessary for the pattern to match. Those construction sites
|
||||
// can't be reached unless the variant is constructed elsewhere.
|
||||
let len = self.ignore_variant_stack.len();
|
||||
self.ignore_variant_stack.extend_from_slice(&variants);
|
||||
intravisit::walk_arm(self, arm);
|
||||
self.ignore_variant_stack.truncate(len);
|
||||
} else {
|
||||
intravisit::walk_arm(self, arm);
|
||||
}
|
||||
// Inside the body, ignore constructions of variants
|
||||
// necessary for the pattern to match. Those construction sites
|
||||
// can't be reached unless the variant is constructed elsewhere.
|
||||
let len = self.ignore_variant_stack.len();
|
||||
self.ignore_variant_stack.extend(arm.pat.necessary_variants());
|
||||
intravisit::walk_arm(self, arm);
|
||||
self.ignore_variant_stack.truncate(len);
|
||||
}
|
||||
|
||||
fn visit_pat(&mut self, pat: &'tcx hir::Pat) {
|
||||
|
@ -779,16 +779,12 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
|
||||
|
||||
fn arm_move_mode(&mut self, discr_cmt: mc::cmt<'tcx>, arm: &hir::Arm) -> TrackMatchMode {
|
||||
let mut mode = Unknown;
|
||||
for pat in &arm.pats {
|
||||
self.determine_pat_move_mode(discr_cmt.clone(), &pat, &mut mode);
|
||||
}
|
||||
self.determine_pat_move_mode(discr_cmt.clone(), &arm.pat, &mut mode);
|
||||
mode
|
||||
}
|
||||
|
||||
fn walk_arm(&mut self, discr_cmt: mc::cmt<'tcx>, arm: &hir::Arm, mode: MatchMode) {
|
||||
for pat in &arm.pats {
|
||||
self.walk_pat(discr_cmt.clone(), &pat, mode);
|
||||
}
|
||||
self.walk_pat(discr_cmt.clone(), &arm.pat, mode);
|
||||
|
||||
if let Some(hir::Guard::If(ref e)) = arm.guard {
|
||||
self.consume_expr(e)
|
||||
|
@ -96,7 +96,11 @@
|
||||
use self::LiveNodeKind::*;
|
||||
use self::VarKind::*;
|
||||
|
||||
use crate::hir;
|
||||
use crate::hir::{Expr, HirId};
|
||||
use crate::hir::def::*;
|
||||
use crate::hir::def_id::DefId;
|
||||
use crate::hir::intravisit::{self, Visitor, FnKind, NestedVisitorMap};
|
||||
use crate::hir::Node;
|
||||
use crate::hir::ptr::P;
|
||||
use crate::ty::{self, TyCtxt};
|
||||
@ -105,20 +109,16 @@ use crate::lint;
|
||||
use crate::util::nodemap::{HirIdMap, HirIdSet};
|
||||
|
||||
use errors::Applicability;
|
||||
use std::collections::{BTreeMap, VecDeque};
|
||||
use rustc_data_structures::fx::FxIndexMap;
|
||||
use std::collections::VecDeque;
|
||||
use std::{fmt, u32};
|
||||
use std::io::prelude::*;
|
||||
use std::io;
|
||||
use std::rc::Rc;
|
||||
use syntax::ast;
|
||||
use syntax::symbol::{kw, sym};
|
||||
use syntax::symbol::sym;
|
||||
use syntax_pos::Span;
|
||||
|
||||
use crate::hir;
|
||||
use crate::hir::{Expr, HirId};
|
||||
use crate::hir::def_id::DefId;
|
||||
use crate::hir::intravisit::{self, Visitor, FnKind, NestedVisitorMap};
|
||||
|
||||
#[derive(Copy, Clone, PartialEq)]
|
||||
struct Variable(u32);
|
||||
|
||||
@ -404,7 +404,7 @@ fn visit_fn<'tcx>(
|
||||
lsets.warn_about_unused_args(body, entry_ln);
|
||||
}
|
||||
|
||||
fn add_from_pat<'tcx>(ir: &mut IrMaps<'tcx>, pat: &P<hir::Pat>) {
|
||||
fn add_from_pat(ir: &mut IrMaps<'_>, pat: &P<hir::Pat>) {
|
||||
// For struct patterns, take note of which fields used shorthand
|
||||
// (`x` rather than `x: x`).
|
||||
let mut shorthand_field_ids = HirIdSet::default();
|
||||
@ -412,26 +412,21 @@ fn add_from_pat<'tcx>(ir: &mut IrMaps<'tcx>, pat: &P<hir::Pat>) {
|
||||
pats.push_back(pat);
|
||||
while let Some(pat) = pats.pop_front() {
|
||||
use crate::hir::PatKind::*;
|
||||
match pat.node {
|
||||
Binding(_, _, _, ref inner_pat) => {
|
||||
match &pat.node {
|
||||
Binding(.., inner_pat) => {
|
||||
pats.extend(inner_pat.iter());
|
||||
}
|
||||
Struct(_, ref fields, _) => {
|
||||
for field in fields {
|
||||
if field.is_shorthand {
|
||||
shorthand_field_ids.insert(field.pat.hir_id);
|
||||
}
|
||||
}
|
||||
Struct(_, fields, _) => {
|
||||
let ids = fields.iter().filter(|f| f.is_shorthand).map(|f| f.pat.hir_id);
|
||||
shorthand_field_ids.extend(ids);
|
||||
}
|
||||
Ref(ref inner_pat, _) |
|
||||
Box(ref inner_pat) => {
|
||||
Ref(inner_pat, _) | Box(inner_pat) => {
|
||||
pats.push_back(inner_pat);
|
||||
}
|
||||
TupleStruct(_, ref inner_pats, _) |
|
||||
Tuple(ref inner_pats, _) => {
|
||||
TupleStruct(_, inner_pats, _) | Tuple(inner_pats, _) | Or(inner_pats) => {
|
||||
pats.extend(inner_pats.iter());
|
||||
}
|
||||
Slice(ref pre_pats, ref inner_pat, ref post_pats) => {
|
||||
Slice(pre_pats, inner_pat, post_pats) => {
|
||||
pats.extend(pre_pats.iter());
|
||||
pats.extend(inner_pat.iter());
|
||||
pats.extend(post_pats.iter());
|
||||
@ -440,7 +435,7 @@ fn add_from_pat<'tcx>(ir: &mut IrMaps<'tcx>, pat: &P<hir::Pat>) {
|
||||
}
|
||||
}
|
||||
|
||||
pat.each_binding(|_bm, hir_id, _sp, ident| {
|
||||
pat.each_binding(|_, hir_id, _, ident| {
|
||||
ir.add_live_node_for_node(hir_id, VarDefNode(ident.span));
|
||||
ir.add_variable(Local(LocalInfo {
|
||||
id: hir_id,
|
||||
@ -456,9 +451,7 @@ fn visit_local<'tcx>(ir: &mut IrMaps<'tcx>, local: &'tcx hir::Local) {
|
||||
}
|
||||
|
||||
fn visit_arm<'tcx>(ir: &mut IrMaps<'tcx>, arm: &'tcx hir::Arm) {
|
||||
for pat in &arm.pats {
|
||||
add_from_pat(ir, pat);
|
||||
}
|
||||
add_from_pat(ir, &arm.pat);
|
||||
intravisit::walk_arm(ir, arm);
|
||||
}
|
||||
|
||||
@ -734,35 +727,15 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
|
||||
self.ir.variable(hir_id, span)
|
||||
}
|
||||
|
||||
fn pat_bindings<F>(&mut self, pat: &hir::Pat, mut f: F) where
|
||||
F: FnMut(&mut Liveness<'a, 'tcx>, LiveNode, Variable, Span, HirId),
|
||||
{
|
||||
pat.each_binding(|_bm, hir_id, sp, n| {
|
||||
let ln = self.live_node(hir_id, sp);
|
||||
let var = self.variable(hir_id, n.span);
|
||||
f(self, ln, var, n.span, hir_id);
|
||||
})
|
||||
}
|
||||
|
||||
fn arm_pats_bindings<F>(&mut self, pat: Option<&hir::Pat>, f: F) where
|
||||
F: FnMut(&mut Liveness<'a, 'tcx>, LiveNode, Variable, Span, HirId),
|
||||
{
|
||||
if let Some(pat) = pat {
|
||||
self.pat_bindings(pat, f);
|
||||
}
|
||||
}
|
||||
|
||||
fn define_bindings_in_pat(&mut self, pat: &hir::Pat, succ: LiveNode)
|
||||
-> LiveNode {
|
||||
self.define_bindings_in_arm_pats(Some(pat), succ)
|
||||
}
|
||||
|
||||
fn define_bindings_in_arm_pats(&mut self, pat: Option<&hir::Pat>, succ: LiveNode)
|
||||
-> LiveNode {
|
||||
let mut succ = succ;
|
||||
self.arm_pats_bindings(pat, |this, ln, var, _sp, _id| {
|
||||
this.init_from_succ(ln, succ);
|
||||
this.define(ln, var);
|
||||
fn define_bindings_in_pat(&mut self, pat: &hir::Pat, mut succ: LiveNode) -> LiveNode {
|
||||
// In an or-pattern, only consider the first pattern; any later patterns
|
||||
// must have the same bindings, and we also consider the first pattern
|
||||
// to be the "authoritative" set of ids.
|
||||
pat.each_binding_or_first(&mut |_, hir_id, pat_sp, ident| {
|
||||
let ln = self.live_node(hir_id, pat_sp);
|
||||
let var = self.variable(hir_id, ident.span);
|
||||
self.init_from_succ(ln, succ);
|
||||
self.define(ln, var);
|
||||
succ = ln;
|
||||
});
|
||||
succ
|
||||
@ -1076,12 +1049,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
|
||||
arm.guard.as_ref().map(|hir::Guard::If(e)| &**e),
|
||||
body_succ
|
||||
);
|
||||
// only consider the first pattern; any later patterns must have
|
||||
// the same bindings, and we also consider the first pattern to be
|
||||
// the "authoritative" set of ids
|
||||
let arm_succ =
|
||||
self.define_bindings_in_arm_pats(arm.pats.first().map(|p| &**p),
|
||||
guard_succ);
|
||||
let arm_succ = self.define_bindings_in_pat(&arm.pat, guard_succ);
|
||||
self.merge_from_succ(ln, arm_succ, first_merge);
|
||||
first_merge = false;
|
||||
};
|
||||
@ -1388,74 +1356,36 @@ impl<'a, 'tcx> Visitor<'tcx> for Liveness<'a, 'tcx> {
|
||||
NestedVisitorMap::None
|
||||
}
|
||||
|
||||
fn visit_local(&mut self, l: &'tcx hir::Local) {
|
||||
check_local(self, l);
|
||||
fn visit_local(&mut self, local: &'tcx hir::Local) {
|
||||
self.check_unused_vars_in_pat(&local.pat, None, |spans, hir_id, ln, var| {
|
||||
if local.init.is_some() {
|
||||
self.warn_about_dead_assign(spans, hir_id, ln, var);
|
||||
}
|
||||
});
|
||||
|
||||
intravisit::walk_local(self, local);
|
||||
}
|
||||
|
||||
fn visit_expr(&mut self, ex: &'tcx Expr) {
|
||||
check_expr(self, ex);
|
||||
}
|
||||
fn visit_arm(&mut self, a: &'tcx hir::Arm) {
|
||||
check_arm(self, a);
|
||||
|
||||
fn visit_arm(&mut self, arm: &'tcx hir::Arm) {
|
||||
self.check_unused_vars_in_pat(&arm.pat, None, |_, _, _, _| {});
|
||||
intravisit::walk_arm(self, arm);
|
||||
}
|
||||
}
|
||||
|
||||
fn check_local<'a, 'tcx>(this: &mut Liveness<'a, 'tcx>, local: &'tcx hir::Local) {
|
||||
match local.init {
|
||||
Some(_) => {
|
||||
this.warn_about_unused_or_dead_vars_in_pat(&local.pat);
|
||||
},
|
||||
None => {
|
||||
this.pat_bindings(&local.pat, |this, ln, var, sp, id| {
|
||||
let span = local.pat.simple_ident().map_or(sp, |ident| ident.span);
|
||||
this.warn_about_unused(vec![span], id, ln, var);
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
intravisit::walk_local(this, local);
|
||||
}
|
||||
|
||||
fn check_arm<'a, 'tcx>(this: &mut Liveness<'a, 'tcx>, arm: &'tcx hir::Arm) {
|
||||
// Only consider the variable from the first pattern; any later patterns must have
|
||||
// the same bindings, and we also consider the first pattern to be the "authoritative" set of
|
||||
// ids. However, we should take the spans of variables with the same name from the later
|
||||
// patterns so the suggestions to prefix with underscores will apply to those too.
|
||||
let mut vars: BTreeMap<String, (LiveNode, Variable, HirId, Vec<Span>)> = Default::default();
|
||||
|
||||
for pat in &arm.pats {
|
||||
this.arm_pats_bindings(Some(&*pat), |this, ln, var, sp, id| {
|
||||
let name = this.ir.variable_name(var);
|
||||
vars.entry(name)
|
||||
.and_modify(|(.., spans)| {
|
||||
spans.push(sp);
|
||||
})
|
||||
.or_insert_with(|| {
|
||||
(ln, var, id, vec![sp])
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
for (_, (ln, var, id, spans)) in vars {
|
||||
this.warn_about_unused(spans, id, ln, var);
|
||||
}
|
||||
|
||||
intravisit::walk_arm(this, arm);
|
||||
}
|
||||
|
||||
fn check_expr<'a, 'tcx>(this: &mut Liveness<'a, 'tcx>, expr: &'tcx Expr) {
|
||||
fn check_expr<'tcx>(this: &mut Liveness<'_, 'tcx>, expr: &'tcx Expr) {
|
||||
match expr.node {
|
||||
hir::ExprKind::Assign(ref l, _) => {
|
||||
this.check_place(&l);
|
||||
|
||||
intravisit::walk_expr(this, expr);
|
||||
}
|
||||
|
||||
hir::ExprKind::AssignOp(_, ref l, _) => {
|
||||
if !this.tables.is_method_call(expr) {
|
||||
this.check_place(&l);
|
||||
}
|
||||
|
||||
intravisit::walk_expr(this, expr);
|
||||
}
|
||||
|
||||
hir::ExprKind::InlineAsm(ref ia, ref outputs, ref inputs) => {
|
||||
@ -1470,8 +1400,6 @@ fn check_expr<'a, 'tcx>(this: &mut Liveness<'a, 'tcx>, expr: &'tcx Expr) {
|
||||
}
|
||||
this.visit_expr(output);
|
||||
}
|
||||
|
||||
intravisit::walk_expr(this, expr);
|
||||
}
|
||||
|
||||
// no correctness conditions related to liveness
|
||||
@ -1484,13 +1412,13 @@ fn check_expr<'a, 'tcx>(this: &mut Liveness<'a, 'tcx>, expr: &'tcx Expr) {
|
||||
hir::ExprKind::Lit(_) | hir::ExprKind::Block(..) | hir::ExprKind::AddrOf(..) |
|
||||
hir::ExprKind::Struct(..) | hir::ExprKind::Repeat(..) |
|
||||
hir::ExprKind::Closure(..) | hir::ExprKind::Path(_) | hir::ExprKind::Yield(..) |
|
||||
hir::ExprKind::Box(..) | hir::ExprKind::Type(..) | hir::ExprKind::Err => {
|
||||
intravisit::walk_expr(this, expr);
|
||||
}
|
||||
hir::ExprKind::Box(..) | hir::ExprKind::Type(..) | hir::ExprKind::Err => {}
|
||||
}
|
||||
|
||||
intravisit::walk_expr(this, expr);
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Liveness<'a, 'tcx> {
|
||||
impl<'tcx> Liveness<'_, 'tcx> {
|
||||
fn check_place(&mut self, expr: &'tcx Expr) {
|
||||
match expr.node {
|
||||
hir::ExprKind::Path(hir::QPath::Resolved(_, ref path)) => {
|
||||
@ -1503,7 +1431,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
|
||||
// as being used.
|
||||
let ln = self.live_node(expr.hir_id, expr.span);
|
||||
let var = self.variable(var_hid, expr.span);
|
||||
self.warn_about_dead_assign(expr.span, expr.hir_id, ln, var);
|
||||
self.warn_about_dead_assign(vec![expr.span], expr.hir_id, ln, var);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1525,109 +1453,112 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
|
||||
}
|
||||
|
||||
fn warn_about_unused_args(&self, body: &hir::Body, entry_ln: LiveNode) {
|
||||
for param in &body.params {
|
||||
param.pat.each_binding(|_bm, hir_id, _, ident| {
|
||||
let sp = ident.span;
|
||||
let var = self.variable(hir_id, sp);
|
||||
// Ignore unused self.
|
||||
if ident.name != kw::SelfLower {
|
||||
if !self.warn_about_unused(vec![sp], hir_id, entry_ln, var) {
|
||||
if self.live_on_entry(entry_ln, var).is_none() {
|
||||
self.report_dead_assign(hir_id, sp, var, true);
|
||||
}
|
||||
}
|
||||
for p in &body.params {
|
||||
self.check_unused_vars_in_pat(&p.pat, Some(entry_ln), |spans, hir_id, ln, var| {
|
||||
if self.live_on_entry(ln, var).is_none() {
|
||||
self.report_dead_assign(hir_id, spans, var, true);
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
fn warn_about_unused_or_dead_vars_in_pat(&mut self, pat: &hir::Pat) {
|
||||
self.pat_bindings(pat, |this, ln, var, sp, id| {
|
||||
if !this.warn_about_unused(vec![sp], id, ln, var) {
|
||||
this.warn_about_dead_assign(sp, id, ln, var);
|
||||
fn check_unused_vars_in_pat(
|
||||
&self,
|
||||
pat: &hir::Pat,
|
||||
entry_ln: Option<LiveNode>,
|
||||
on_used_on_entry: impl Fn(Vec<Span>, HirId, LiveNode, Variable),
|
||||
) {
|
||||
// In an or-pattern, only consider the variable; any later patterns must have the same
|
||||
// bindings, and we also consider the first pattern to be the "authoritative" set of ids.
|
||||
// However, we should take the spans of variables with the same name from the later
|
||||
// patterns so the suggestions to prefix with underscores will apply to those too.
|
||||
let mut vars: FxIndexMap<String, (LiveNode, Variable, HirId, Vec<Span>)> = <_>::default();
|
||||
|
||||
pat.each_binding(|_, hir_id, pat_sp, ident| {
|
||||
let ln = entry_ln.unwrap_or_else(|| self.live_node(hir_id, pat_sp));
|
||||
let var = self.variable(hir_id, ident.span);
|
||||
vars.entry(self.ir.variable_name(var))
|
||||
.and_modify(|(.., spans)| spans.push(ident.span))
|
||||
.or_insert_with(|| (ln, var, hir_id, vec![ident.span]));
|
||||
});
|
||||
|
||||
for (_, (ln, var, id, spans)) in vars {
|
||||
if self.used_on_entry(ln, var) {
|
||||
on_used_on_entry(spans, id, ln, var);
|
||||
} else {
|
||||
self.report_unused(spans, id, ln, var);
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn warn_about_unused(&self,
|
||||
spans: Vec<Span>,
|
||||
hir_id: HirId,
|
||||
ln: LiveNode,
|
||||
var: Variable)
|
||||
-> bool {
|
||||
if !self.used_on_entry(ln, var) {
|
||||
let r = self.should_warn(var);
|
||||
if let Some(name) = r {
|
||||
// annoying: for parameters in funcs like `fn(x: i32)
|
||||
// {ret}`, there is only one node, so asking about
|
||||
// assigned_on_exit() is not meaningful.
|
||||
let is_assigned = if ln == self.s.exit_ln {
|
||||
false
|
||||
} else {
|
||||
self.assigned_on_exit(ln, var).is_some()
|
||||
};
|
||||
fn report_unused(&self, spans: Vec<Span>, hir_id: HirId, ln: LiveNode, var: Variable) {
|
||||
if let Some(name) = self.should_warn(var).filter(|name| name != "self") {
|
||||
// annoying: for parameters in funcs like `fn(x: i32)
|
||||
// {ret}`, there is only one node, so asking about
|
||||
// assigned_on_exit() is not meaningful.
|
||||
let is_assigned = if ln == self.s.exit_ln {
|
||||
false
|
||||
} else {
|
||||
self.assigned_on_exit(ln, var).is_some()
|
||||
};
|
||||
|
||||
if is_assigned {
|
||||
self.ir.tcx.lint_hir_note(
|
||||
lint::builtin::UNUSED_VARIABLES,
|
||||
hir_id,
|
||||
spans,
|
||||
&format!("variable `{}` is assigned to, but never used", name),
|
||||
&format!("consider using `_{}` instead", name),
|
||||
);
|
||||
} else if name != "self" {
|
||||
let mut err = self.ir.tcx.struct_span_lint_hir(
|
||||
lint::builtin::UNUSED_VARIABLES,
|
||||
hir_id,
|
||||
spans.clone(),
|
||||
&format!("unused variable: `{}`", name),
|
||||
);
|
||||
if is_assigned {
|
||||
self.ir.tcx.lint_hir_note(
|
||||
lint::builtin::UNUSED_VARIABLES,
|
||||
hir_id,
|
||||
spans,
|
||||
&format!("variable `{}` is assigned to, but never used", name),
|
||||
&format!("consider using `_{}` instead", name),
|
||||
);
|
||||
} else {
|
||||
let mut err = self.ir.tcx.struct_span_lint_hir(
|
||||
lint::builtin::UNUSED_VARIABLES,
|
||||
hir_id,
|
||||
spans.clone(),
|
||||
&format!("unused variable: `{}`", name),
|
||||
);
|
||||
|
||||
if self.ir.variable_is_shorthand(var) {
|
||||
if let Node::Binding(pat) = self.ir.tcx.hir().get(hir_id) {
|
||||
// Handle `ref` and `ref mut`.
|
||||
let spans = spans.iter()
|
||||
.map(|_span| (pat.span, format!("{}: _", name)))
|
||||
.collect();
|
||||
if self.ir.variable_is_shorthand(var) {
|
||||
if let Node::Binding(pat) = self.ir.tcx.hir().get(hir_id) {
|
||||
// Handle `ref` and `ref mut`.
|
||||
let spans = spans.iter()
|
||||
.map(|_span| (pat.span, format!("{}: _", name)))
|
||||
.collect();
|
||||
|
||||
err.multipart_suggestion(
|
||||
"try ignoring the field",
|
||||
spans,
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
err.multipart_suggestion(
|
||||
"consider prefixing with an underscore",
|
||||
spans.iter().map(|span| (*span, format!("_{}", name))).collect(),
|
||||
"try ignoring the field",
|
||||
spans,
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
|
||||
err.emit()
|
||||
} else {
|
||||
err.multipart_suggestion(
|
||||
"consider prefixing with an underscore",
|
||||
spans.iter().map(|span| (*span, format!("_{}", name))).collect(),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
|
||||
err.emit()
|
||||
}
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn warn_about_dead_assign(&self, sp: Span, hir_id: HirId, ln: LiveNode, var: Variable) {
|
||||
fn warn_about_dead_assign(&self, spans: Vec<Span>, hir_id: HirId, ln: LiveNode, var: Variable) {
|
||||
if self.live_on_exit(ln, var).is_none() {
|
||||
self.report_dead_assign(hir_id, sp, var, false);
|
||||
self.report_dead_assign(hir_id, spans, var, false);
|
||||
}
|
||||
}
|
||||
|
||||
fn report_dead_assign(&self, hir_id: HirId, sp: Span, var: Variable, is_argument: bool) {
|
||||
fn report_dead_assign(&self, hir_id: HirId, spans: Vec<Span>, var: Variable, is_param: bool) {
|
||||
if let Some(name) = self.should_warn(var) {
|
||||
if is_argument {
|
||||
self.ir.tcx.struct_span_lint_hir(lint::builtin::UNUSED_ASSIGNMENTS, hir_id, sp,
|
||||
if is_param {
|
||||
self.ir.tcx.struct_span_lint_hir(lint::builtin::UNUSED_ASSIGNMENTS, hir_id, spans,
|
||||
&format!("value passed to `{}` is never read", name))
|
||||
.help("maybe it is overwritten before being read?")
|
||||
.emit();
|
||||
} else {
|
||||
self.ir.tcx.struct_span_lint_hir(lint::builtin::UNUSED_ASSIGNMENTS, hir_id, sp,
|
||||
self.ir.tcx.struct_span_lint_hir(lint::builtin::UNUSED_ASSIGNMENTS, hir_id, spans,
|
||||
&format!("value assigned to `{}` is never read", name))
|
||||
.help("maybe it is overwritten before being read?")
|
||||
.emit();
|
||||
|
@ -974,7 +974,7 @@ pub struct FreeRegionInfo {
|
||||
///
|
||||
/// [rustc guide]: https://rust-lang.github.io/rustc-guide/ty.html
|
||||
#[derive(Copy, Clone)]
|
||||
#[cfg_attr(not(bootstrap), rustc_diagnostic_item = "TyCtxt")]
|
||||
#[rustc_diagnostic_item = "TyCtxt"]
|
||||
pub struct TyCtxt<'tcx> {
|
||||
gcx: &'tcx GlobalCtxt<'tcx>,
|
||||
}
|
||||
|
@ -581,7 +581,7 @@ impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for ty::TyS<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(not(bootstrap), rustc_diagnostic_item = "Ty")]
|
||||
#[rustc_diagnostic_item = "Ty"]
|
||||
pub type Ty<'tcx> = &'tcx TyS<'tcx>;
|
||||
|
||||
impl<'tcx> rustc_serialize::UseSpecializedEncodable for Ty<'tcx> {}
|
||||
|
@ -86,7 +86,7 @@ impl BoundRegion {
|
||||
/// AST structure in `libsyntax/ast.rs` as well.
|
||||
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash,
|
||||
RustcEncodable, RustcDecodable, HashStable, Debug)]
|
||||
#[cfg_attr(not(bootstrap), rustc_diagnostic_item = "TyKind")]
|
||||
#[rustc_diagnostic_item = "TyKind"]
|
||||
pub enum TyKind<'tcx> {
|
||||
/// The primitive boolean type. Written as `bool`.
|
||||
Bool,
|
||||
|
@ -390,7 +390,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
|
||||
// patterns and the guard (if there is one) in the arm.
|
||||
let bindings_exit = self.add_dummy_node(&[]);
|
||||
|
||||
for pat in &arm.pats {
|
||||
for pat in arm.top_pats_hack() {
|
||||
// Visit the pattern, coming from the discriminant exit
|
||||
let mut pat_exit = self.pat(&pat, discr_exit);
|
||||
|
||||
|
@ -905,10 +905,10 @@ fn analysis(tcx: TyCtxt<'_>, cnum: CrateNum) -> Result<()> {
|
||||
});
|
||||
}, {
|
||||
par_iter(&tcx.hir().krate().modules).for_each(|(&module, _)| {
|
||||
tcx.ensure().check_mod_loops(tcx.hir().local_def_id_from_node_id(module));
|
||||
tcx.ensure().check_mod_attrs(tcx.hir().local_def_id_from_node_id(module));
|
||||
tcx.ensure().check_mod_unstable_api_usage(
|
||||
tcx.hir().local_def_id_from_node_id(module));
|
||||
let local_def_id = tcx.hir().local_def_id(module);
|
||||
tcx.ensure().check_mod_loops(local_def_id);
|
||||
tcx.ensure().check_mod_attrs(local_def_id);
|
||||
tcx.ensure().check_mod_unstable_api_usage(local_def_id);
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -931,9 +931,10 @@ fn analysis(tcx: TyCtxt<'_>, cnum: CrateNum) -> Result<()> {
|
||||
// "not all control paths return a value" is reported here.
|
||||
//
|
||||
// maybe move the check to a MIR pass?
|
||||
tcx.ensure().check_mod_liveness(tcx.hir().local_def_id_from_node_id(module));
|
||||
let local_def_id = tcx.hir().local_def_id(module);
|
||||
|
||||
tcx.ensure().check_mod_intrinsics(tcx.hir().local_def_id_from_node_id(module));
|
||||
tcx.ensure().check_mod_liveness(local_def_id);
|
||||
tcx.ensure().check_mod_intrinsics(local_def_id);
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -993,7 +994,7 @@ fn analysis(tcx: TyCtxt<'_>, cnum: CrateNum) -> Result<()> {
|
||||
}, {
|
||||
time(sess, "privacy checking modules", || {
|
||||
par_iter(&tcx.hir().krate().modules).for_each(|(&module, _)| {
|
||||
tcx.ensure().check_mod_privacy(tcx.hir().local_def_id_from_node_id(module));
|
||||
tcx.ensure().check_mod_privacy(tcx.hir().local_def_id(module));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -142,7 +142,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
// Step 2. Create the otherwise and prebinding blocks.
|
||||
|
||||
// create binding start block for link them by false edges
|
||||
let candidate_count = arms.iter().map(|c| c.patterns.len()).sum::<usize>();
|
||||
let candidate_count = arms.iter().map(|c| c.top_pats_hack().len()).sum::<usize>();
|
||||
let pre_binding_blocks: Vec<_> = (0..candidate_count)
|
||||
.map(|_| self.cfg.start_new_block())
|
||||
.collect();
|
||||
@ -159,7 +159,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
.map(|arm| {
|
||||
let arm_has_guard = arm.guard.is_some();
|
||||
match_has_guard |= arm_has_guard;
|
||||
let arm_candidates: Vec<_> = arm.patterns
|
||||
let arm_candidates: Vec<_> = arm.top_pats_hack()
|
||||
.iter()
|
||||
.zip(candidate_pre_binding_blocks.by_ref())
|
||||
.map(
|
||||
@ -238,7 +238,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
let scope = this.declare_bindings(
|
||||
None,
|
||||
arm.span,
|
||||
&arm.patterns[0],
|
||||
&arm.top_pats_hack()[0],
|
||||
ArmHasGuard(arm.guard.is_some()),
|
||||
Some((Some(&scrutinee_place), scrutinee_span)),
|
||||
);
|
||||
|
@ -860,9 +860,9 @@ impl ToBorrowKind for hir::Mutability {
|
||||
}
|
||||
}
|
||||
|
||||
fn convert_arm<'a, 'tcx>(cx: &mut Cx<'a, 'tcx>, arm: &'tcx hir::Arm) -> Arm<'tcx> {
|
||||
fn convert_arm<'tcx>(cx: &mut Cx<'_, 'tcx>, arm: &'tcx hir::Arm) -> Arm<'tcx> {
|
||||
Arm {
|
||||
patterns: arm.pats.iter().map(|p| cx.pattern_from_hir(p)).collect(),
|
||||
pattern: cx.pattern_from_hir(&arm.pat),
|
||||
guard: match arm.guard {
|
||||
Some(hir::Guard::If(ref e)) => Some(Guard::If(e.to_ref())),
|
||||
_ => None,
|
||||
|
@ -293,7 +293,7 @@ pub struct FruInfo<'tcx> {
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Arm<'tcx> {
|
||||
pub patterns: Vec<Pattern<'tcx>>,
|
||||
pub pattern: Pattern<'tcx>,
|
||||
pub guard: Option<Guard<'tcx>>,
|
||||
pub body: ExprRef<'tcx>,
|
||||
pub lint_level: LintLevel,
|
||||
@ -301,6 +301,17 @@ pub struct Arm<'tcx> {
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
impl Arm<'tcx> {
|
||||
// HACK(or_patterns; Centril | dlrobertson): Remove this and
|
||||
// correctly handle each case in which this method is used.
|
||||
pub fn top_pats_hack(&self) -> &[Pattern<'tcx>] {
|
||||
match &*self.pattern.kind {
|
||||
PatternKind::Or { pats } => pats,
|
||||
_ => std::slice::from_ref(&self.pattern),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum Guard<'tcx> {
|
||||
If(ExprRef<'tcx>),
|
||||
|
@ -14,7 +14,6 @@ use rustc_errors::{Applicability, DiagnosticBuilder};
|
||||
use rustc::hir::def::*;
|
||||
use rustc::hir::def_id::DefId;
|
||||
use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
|
||||
use rustc::hir::ptr::P;
|
||||
use rustc::hir::{self, Pat, PatKind};
|
||||
|
||||
use smallvec::smallvec;
|
||||
@ -76,7 +75,7 @@ impl<'tcx> Visitor<'tcx> for MatchVisitor<'_, 'tcx> {
|
||||
});
|
||||
|
||||
// Check legality of move bindings and `@` patterns.
|
||||
self.check_patterns(false, slice::from_ref(&loc.pat));
|
||||
self.check_patterns(false, &loc.pat);
|
||||
}
|
||||
|
||||
fn visit_body(&mut self, body: &'tcx hir::Body) {
|
||||
@ -84,7 +83,7 @@ impl<'tcx> Visitor<'tcx> for MatchVisitor<'_, 'tcx> {
|
||||
|
||||
for param in &body.params {
|
||||
self.check_irrefutable(¶m.pat, "function argument");
|
||||
self.check_patterns(false, slice::from_ref(¶m.pat));
|
||||
self.check_patterns(false, ¶m.pat);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -122,11 +121,9 @@ impl PatternContext<'_, '_> {
|
||||
}
|
||||
|
||||
impl<'tcx> MatchVisitor<'_, 'tcx> {
|
||||
fn check_patterns(&mut self, has_guard: bool, pats: &[P<Pat>]) {
|
||||
check_legality_of_move_bindings(self, has_guard, pats);
|
||||
for pat in pats {
|
||||
check_legality_of_bindings_in_at_patterns(self, pat);
|
||||
}
|
||||
fn check_patterns(&mut self, has_guard: bool, pat: &Pat) {
|
||||
check_legality_of_move_bindings(self, has_guard, pat);
|
||||
check_legality_of_bindings_in_at_patterns(self, pat);
|
||||
}
|
||||
|
||||
fn check_match(
|
||||
@ -137,7 +134,7 @@ impl<'tcx> MatchVisitor<'_, 'tcx> {
|
||||
) {
|
||||
for arm in arms {
|
||||
// First, check legality of move bindings.
|
||||
self.check_patterns(arm.guard.is_some(), &arm.pats);
|
||||
self.check_patterns(arm.guard.is_some(), &arm.pat);
|
||||
|
||||
// Second, if there is a guard on each arm, make sure it isn't
|
||||
// assigning or borrowing anything mutably.
|
||||
@ -146,9 +143,7 @@ impl<'tcx> MatchVisitor<'_, 'tcx> {
|
||||
}
|
||||
|
||||
// Third, perform some lints.
|
||||
for pat in &arm.pats {
|
||||
check_for_bindings_named_same_as_variants(self, pat);
|
||||
}
|
||||
check_for_bindings_named_same_as_variants(self, &arm.pat);
|
||||
}
|
||||
|
||||
let module = self.tcx.hir().get_module_parent(scrut.hir_id);
|
||||
@ -156,7 +151,7 @@ impl<'tcx> MatchVisitor<'_, 'tcx> {
|
||||
let mut have_errors = false;
|
||||
|
||||
let inlined_arms : Vec<(Vec<_>, _)> = arms.iter().map(|arm| (
|
||||
arm.pats.iter().map(|pat| {
|
||||
arm.top_pats_hack().iter().map(|pat| {
|
||||
let mut patcx = PatternContext::new(self.tcx,
|
||||
self.param_env.and(self.identity_substs),
|
||||
self.tables);
|
||||
@ -545,78 +540,60 @@ fn maybe_point_at_variant(ty: Ty<'_>, patterns: &[Pattern<'_>]) -> Vec<Span> {
|
||||
covered
|
||||
}
|
||||
|
||||
// Legality of move bindings checking
|
||||
fn check_legality_of_move_bindings(
|
||||
cx: &mut MatchVisitor<'_, '_>,
|
||||
has_guard: bool,
|
||||
pats: &[P<Pat>],
|
||||
) {
|
||||
// Check the legality of legality of by-move bindings.
|
||||
fn check_legality_of_move_bindings(cx: &mut MatchVisitor<'_, '_>, has_guard: bool, pat: &Pat) {
|
||||
let mut by_ref_span = None;
|
||||
for pat in pats {
|
||||
pat.each_binding(|_, hir_id, span, _path| {
|
||||
if let Some(&bm) = cx.tables.pat_binding_modes().get(hir_id) {
|
||||
if let ty::BindByReference(..) = bm {
|
||||
by_ref_span = Some(span);
|
||||
pat.each_binding(|_, hir_id, span, _| {
|
||||
if let Some(&bm) = cx.tables.pat_binding_modes().get(hir_id) {
|
||||
if let ty::BindByReference(..) = bm {
|
||||
by_ref_span = Some(span);
|
||||
}
|
||||
} else {
|
||||
cx.tcx.sess.delay_span_bug(pat.span, "missing binding mode");
|
||||
}
|
||||
});
|
||||
|
||||
let span_vec = &mut Vec::new();
|
||||
let mut check_move = |p: &Pat, sub: Option<&Pat>| {
|
||||
// Check legality of moving out of the enum.
|
||||
//
|
||||
// `x @ Foo(..)` is legal, but `x @ Foo(y)` isn't.
|
||||
if sub.map_or(false, |p| p.contains_bindings()) {
|
||||
struct_span_err!(cx.tcx.sess, p.span, E0007, "cannot bind by-move with sub-bindings")
|
||||
.span_label(p.span, "binds an already bound by-move value by moving it")
|
||||
.emit();
|
||||
} else if !has_guard && by_ref_span.is_some() {
|
||||
span_vec.push(p.span);
|
||||
}
|
||||
};
|
||||
|
||||
pat.walk(|p| {
|
||||
if let PatKind::Binding(.., sub) = &p.node {
|
||||
if let Some(&bm) = cx.tables.pat_binding_modes().get(p.hir_id) {
|
||||
if let ty::BindByValue(..) = bm {
|
||||
let pat_ty = cx.tables.node_type(p.hir_id);
|
||||
if !pat_ty.is_copy_modulo_regions(cx.tcx, cx.param_env, pat.span) {
|
||||
check_move(p, sub.as_deref());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
cx.tcx.sess.delay_span_bug(pat.span, "missing binding mode");
|
||||
}
|
||||
})
|
||||
}
|
||||
let span_vec = &mut Vec::new();
|
||||
let check_move = |
|
||||
cx: &mut MatchVisitor<'_, '_>,
|
||||
p: &Pat,
|
||||
sub: Option<&Pat>,
|
||||
span_vec: &mut Vec<Span>,
|
||||
| {
|
||||
// check legality of moving out of the enum
|
||||
|
||||
// x @ Foo(..) is legal, but x @ Foo(y) isn't.
|
||||
if sub.map_or(false, |p| p.contains_bindings()) {
|
||||
struct_span_err!(cx.tcx.sess, p.span, E0007,
|
||||
"cannot bind by-move with sub-bindings")
|
||||
.span_label(p.span, "binds an already bound by-move value by moving it")
|
||||
.emit();
|
||||
} else if !has_guard {
|
||||
if let Some(_by_ref_span) = by_ref_span {
|
||||
span_vec.push(p.span);
|
||||
}
|
||||
}
|
||||
};
|
||||
true
|
||||
});
|
||||
|
||||
for pat in pats {
|
||||
pat.walk(|p| {
|
||||
if let PatKind::Binding(_, _, _, ref sub) = p.node {
|
||||
if let Some(&bm) = cx.tables.pat_binding_modes().get(p.hir_id) {
|
||||
match bm {
|
||||
ty::BindByValue(..) => {
|
||||
let pat_ty = cx.tables.node_type(p.hir_id);
|
||||
if !pat_ty.is_copy_modulo_regions(cx.tcx, cx.param_env, pat.span) {
|
||||
check_move(cx, p, sub.as_ref().map(|p| &**p), span_vec);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
} else {
|
||||
cx.tcx.sess.delay_span_bug(pat.span, "missing binding mode");
|
||||
}
|
||||
}
|
||||
true
|
||||
});
|
||||
}
|
||||
if !span_vec.is_empty(){
|
||||
let span = MultiSpan::from_spans(span_vec.clone());
|
||||
if !span_vec.is_empty() {
|
||||
let mut err = struct_span_err!(
|
||||
cx.tcx.sess,
|
||||
span,
|
||||
MultiSpan::from_spans(span_vec.clone()),
|
||||
E0009,
|
||||
"cannot bind by-move and by-ref in the same pattern",
|
||||
);
|
||||
if let Some(by_ref_span) = by_ref_span {
|
||||
err.span_label(by_ref_span, "both by-ref and by-move used");
|
||||
}
|
||||
for span in span_vec.iter(){
|
||||
for span in span_vec.iter() {
|
||||
err.span_label(*span, "by-move pattern here");
|
||||
}
|
||||
err.emit();
|
||||
@ -627,7 +604,7 @@ fn check_legality_of_move_bindings(
|
||||
/// because of the way rvalues are handled in the borrow check. (See issue
|
||||
/// #14587.)
|
||||
fn check_legality_of_bindings_in_at_patterns(cx: &MatchVisitor<'_, '_>, pat: &Pat) {
|
||||
AtBindingPatternVisitor { cx: cx, bindings_allowed: true }.visit_pat(pat);
|
||||
AtBindingPatternVisitor { cx, bindings_allowed: true }.visit_pat(pat);
|
||||
}
|
||||
|
||||
struct AtBindingPatternVisitor<'a, 'b, 'tcx> {
|
||||
|
@ -239,7 +239,52 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
"transmute" => {
|
||||
self.copy_op_transmute(args[0], dest)?;
|
||||
}
|
||||
"simd_insert" => {
|
||||
let index = self.read_scalar(args[1])?.to_u32()? as u64;
|
||||
let scalar = args[2];
|
||||
let input = args[0];
|
||||
let (len, e_ty) = self.read_vector_ty(input);
|
||||
assert!(
|
||||
index < len,
|
||||
"Index `{}` must be in bounds of vector type `{}`: `[0, {})`",
|
||||
index, e_ty, len
|
||||
);
|
||||
assert_eq!(
|
||||
input.layout, dest.layout,
|
||||
"Return type `{}` must match vector type `{}`",
|
||||
dest.layout.ty, input.layout.ty
|
||||
);
|
||||
assert_eq!(
|
||||
scalar.layout.ty, e_ty,
|
||||
"Scalar type `{}` must match vector element type `{}`",
|
||||
scalar.layout.ty, e_ty
|
||||
);
|
||||
|
||||
for i in 0..len {
|
||||
let place = self.place_field(dest, i)?;
|
||||
let value = if i == index {
|
||||
scalar
|
||||
} else {
|
||||
self.operand_field(input, i)?
|
||||
};
|
||||
self.copy_op(value, place)?;
|
||||
}
|
||||
}
|
||||
"simd_extract" => {
|
||||
let index = self.read_scalar(args[1])?.to_u32()? as _;
|
||||
let (len, e_ty) = self.read_vector_ty(args[0]);
|
||||
assert!(
|
||||
index < len,
|
||||
"index `{}` is out-of-bounds of vector type `{}` with length `{}`",
|
||||
index, e_ty, len
|
||||
);
|
||||
assert_eq!(
|
||||
e_ty, dest.layout.ty,
|
||||
"Return type `{}` must match vector element type `{}`",
|
||||
dest.layout.ty, e_ty
|
||||
);
|
||||
self.copy_op(self.operand_field(args[0], index)?, dest)?;
|
||||
}
|
||||
_ => return Ok(false),
|
||||
}
|
||||
|
||||
|
@ -335,6 +335,17 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Read vector length and element type
|
||||
pub fn read_vector_ty(
|
||||
&self, op: OpTy<'tcx, M::PointerTag>
|
||||
) -> (u64, &rustc::ty::TyS<'tcx>) {
|
||||
if let layout::Abi::Vector { .. } = op.layout.abi {
|
||||
(op.layout.ty.simd_size(*self.tcx) as _, op.layout.ty.simd_type(*self.tcx))
|
||||
} else {
|
||||
bug!("Type `{}` is not a SIMD vector type", op.layout.ty)
|
||||
}
|
||||
}
|
||||
|
||||
/// Read a scalar from a place
|
||||
pub fn read_scalar(
|
||||
&self,
|
||||
|
@ -249,9 +249,6 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
|
||||
match instance.def {
|
||||
ty::InstanceDef::Intrinsic(..) => {
|
||||
if caller_abi != Abi::RustIntrinsic {
|
||||
throw_unsup!(FunctionAbiMismatch(caller_abi, Abi::RustIntrinsic))
|
||||
}
|
||||
// The intrinsic itself cannot diverge, so if we got here without a return
|
||||
// place... (can happen e.g., for transmute returning `!`)
|
||||
let dest = match dest {
|
||||
|
@ -6,6 +6,7 @@ Rust MIR: a lowered representation of Rust. Also: an experiment!
|
||||
|
||||
#![feature(nll)]
|
||||
#![feature(in_band_lifetimes)]
|
||||
#![feature(inner_deref)]
|
||||
#![feature(slice_patterns)]
|
||||
#![feature(box_patterns)]
|
||||
#![feature(box_syntax)]
|
||||
|
@ -557,6 +557,8 @@ impl Qualif for IsNotPromotable {
|
||||
| "saturating_add"
|
||||
| "saturating_sub"
|
||||
| "transmute"
|
||||
| "simd_insert"
|
||||
| "simd_extract"
|
||||
=> return true,
|
||||
|
||||
_ => {}
|
||||
|
@ -8,7 +8,6 @@
|
||||
|
||||
#![feature(in_band_lifetimes)]
|
||||
#![feature(nll)]
|
||||
#![cfg_attr(bootstrap, feature(bind_by_move_pattern_guards))]
|
||||
|
||||
#![recursion_limit="256"]
|
||||
|
||||
|
@ -499,19 +499,15 @@ fn check_expr_kind<'a, 'tcx>(
|
||||
}
|
||||
|
||||
// Conditional control flow (possible to implement).
|
||||
hir::ExprKind::Match(ref expr, ref hirvec_arm, ref _match_source) => {
|
||||
hir::ExprKind::Match(ref expr, ref arms, ref _match_source) => {
|
||||
// Compute the most demanding borrow from all the arms'
|
||||
// patterns and set that on the discriminator.
|
||||
let mut mut_borrow = false;
|
||||
for pat in hirvec_arm.iter().flat_map(|arm| &arm.pats) {
|
||||
mut_borrow = v.remove_mut_rvalue_borrow(pat);
|
||||
}
|
||||
if mut_borrow {
|
||||
if arms.iter().fold(false, |_, arm| v.remove_mut_rvalue_borrow(&arm.pat)) {
|
||||
v.mut_rvalue_borrows.insert(expr.hir_id);
|
||||
}
|
||||
|
||||
let _ = v.check_expr(expr);
|
||||
for index in hirvec_arm.iter() {
|
||||
for index in arms.iter() {
|
||||
let _ = v.check_expr(&*index.body);
|
||||
if let Some(hir::Guard::If(ref expr)) = index.guard {
|
||||
let _ = v.check_expr(&expr);
|
||||
|
@ -58,11 +58,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
// collection into `Vec`), so we get types for all bindings.
|
||||
let all_arm_pats_diverge: Vec<_> = arms.iter().map(|arm| {
|
||||
let mut all_pats_diverge = Diverges::WarnedAlways;
|
||||
for p in &arm.pats {
|
||||
self.diverges.set(Diverges::Maybe);
|
||||
self.check_pat_top(&p, discrim_ty, Some(discrim.span));
|
||||
all_pats_diverge &= self.diverges.get();
|
||||
}
|
||||
self.diverges.set(Diverges::Maybe);
|
||||
self.check_pat_top(&arm.pat, discrim_ty, Some(discrim.span));
|
||||
all_pats_diverge &= self.diverges.get();
|
||||
|
||||
// As discussed with @eddyb, this is for disabling unreachable_code
|
||||
// warnings on patterns (they're now subsumed by unreachable_patterns
|
||||
@ -428,11 +426,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
//
|
||||
// See #44848.
|
||||
let contains_ref_bindings = arms.iter()
|
||||
.filter_map(|a| a.contains_explicit_ref_binding())
|
||||
.max_by_key(|m| match *m {
|
||||
hir::MutMutable => 1,
|
||||
hir::MutImmutable => 0,
|
||||
});
|
||||
.filter_map(|a| a.pat.contains_explicit_ref_binding())
|
||||
.max_by_key(|m| match *m {
|
||||
hir::MutMutable => 1,
|
||||
hir::MutImmutable => 0,
|
||||
});
|
||||
|
||||
if let Some(m) = contains_ref_bindings {
|
||||
self.check_expr_with_needs(discrim, Needs::maybe_mut_place(m))
|
||||
|
@ -97,11 +97,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
self.check_pat_struct(pat, qpath, fields, *etc, expected, def_bm, discrim_span)
|
||||
}
|
||||
PatKind::Or(pats) => {
|
||||
let expected_ty = self.structurally_resolved_type(pat.span, expected);
|
||||
for pat in pats {
|
||||
self.check_pat(pat, expected, def_bm, discrim_span);
|
||||
}
|
||||
expected_ty
|
||||
expected
|
||||
}
|
||||
PatKind::Tuple(elements, ddpos) => {
|
||||
self.check_pat_tuple(pat.span, elements, *ddpos, expected, def_bm, discrim_span)
|
||||
@ -208,7 +207,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
match pat.node {
|
||||
PatKind::Struct(..) |
|
||||
PatKind::TupleStruct(..) |
|
||||
PatKind::Or(_) |
|
||||
PatKind::Tuple(..) |
|
||||
PatKind::Box(_) |
|
||||
PatKind::Range(..) |
|
||||
@ -226,6 +224,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
_ => true,
|
||||
}
|
||||
}
|
||||
// FIXME(or_patterns; Centril | dlrobertson): To keep things compiling
|
||||
// for or-patterns at the top level, we need to make `p_0 | ... | p_n`
|
||||
// a "non reference pattern". For example the following currently compiles:
|
||||
// ```
|
||||
// match &1 {
|
||||
// e @ &(1...2) | e @ &(3...4) => {}
|
||||
// _ => {}
|
||||
// }
|
||||
// ```
|
||||
//
|
||||
// We should consider whether we should do something special in nested or-patterns.
|
||||
PatKind::Or(_) |
|
||||
PatKind::Wild |
|
||||
PatKind::Binding(..) |
|
||||
PatKind::Ref(..) => false,
|
||||
@ -426,12 +436,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
// If the binding is like `ref x | ref const x | ref mut x`
|
||||
// then `x` is assigned a value of type `&M T` where M is the
|
||||
// mutability and T is the expected type.
|
||||
let region_ty = self.new_ref_ty(pat.span, mutbl, expected);
|
||||
|
||||
//
|
||||
// `x` is assigned a value of type `&M T`, hence `&M T <: typeof(x)`
|
||||
// is required. However, we use equality, which is stronger.
|
||||
// See (note_1) for an explanation.
|
||||
region_ty
|
||||
self.new_ref_ty(pat.span, mutbl, expected)
|
||||
}
|
||||
// Otherwise, the type of x is the expected type `T`.
|
||||
ty::BindByValue(_) => {
|
||||
|
@ -488,9 +488,7 @@ impl<'a, 'tcx> Visitor<'tcx> for RegionCtxt<'a, 'tcx> {
|
||||
|
||||
fn visit_arm(&mut self, arm: &'tcx hir::Arm) {
|
||||
// see above
|
||||
for p in &arm.pats {
|
||||
self.constrain_bindings_in_pat(p);
|
||||
}
|
||||
self.constrain_bindings_in_pat(&arm.pat);
|
||||
intravisit::walk_arm(self, arm);
|
||||
}
|
||||
|
||||
@ -1069,9 +1067,7 @@ impl<'a, 'tcx> RegionCtxt<'a, 'tcx> {
|
||||
let discr_cmt = Rc::new(ignore_err!(self.with_mc(|mc| mc.cat_expr(discr))));
|
||||
debug!("discr_cmt={:?}", discr_cmt);
|
||||
for arm in arms {
|
||||
for root_pat in &arm.pats {
|
||||
self.link_pattern(discr_cmt.clone(), &root_pat);
|
||||
}
|
||||
self.link_pattern(discr_cmt.clone(), &arm.pat);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -54,7 +54,7 @@ pub fn impl_wf_check(tcx: TyCtxt<'_>) {
|
||||
// but it's one that we must perform earlier than the rest of
|
||||
// WfCheck.
|
||||
for &module in tcx.hir().krate().modules.keys() {
|
||||
tcx.ensure().check_mod_impl_wf(tcx.hir().local_def_id_from_node_id(module));
|
||||
tcx.ensure().check_mod_impl_wf(tcx.hir().local_def_id(module));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -303,7 +303,7 @@ pub fn check_crate(tcx: TyCtxt<'_>) -> Result<(), ErrorReported> {
|
||||
tcx.sess.track_errors(|| {
|
||||
time(tcx.sess, "type collecting", || {
|
||||
for &module in tcx.hir().krate().modules.keys() {
|
||||
tcx.ensure().collect_mod_item_types(tcx.hir().local_def_id_from_node_id(module));
|
||||
tcx.ensure().collect_mod_item_types(tcx.hir().local_def_id(module));
|
||||
}
|
||||
});
|
||||
})?;
|
||||
@ -338,7 +338,7 @@ pub fn check_crate(tcx: TyCtxt<'_>) -> Result<(), ErrorReported> {
|
||||
|
||||
time(tcx.sess, "item-types checking", || {
|
||||
for &module in tcx.hir().krate().modules.keys() {
|
||||
tcx.ensure().check_mod_item_types(tcx.hir().local_def_id_from_node_id(module));
|
||||
tcx.ensure().check_mod_item_types(tcx.hir().local_def_id(module));
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -1,7 +1,6 @@
|
||||
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/",
|
||||
html_playground_url = "https://play.rust-lang.org/")]
|
||||
|
||||
#![cfg_attr(bootstrap, feature(bind_by_move_pattern_guards))]
|
||||
#![feature(rustc_private)]
|
||||
#![feature(arbitrary_self_types)]
|
||||
#![feature(box_patterns)]
|
||||
|
@ -238,7 +238,6 @@
|
||||
#![feature(array_error_internals)]
|
||||
#![feature(asm)]
|
||||
#![feature(associated_type_bounds)]
|
||||
#![cfg_attr(bootstrap, feature(bind_by_move_pattern_guards))]
|
||||
#![feature(box_syntax)]
|
||||
#![feature(c_variadic)]
|
||||
#![feature(cfg_target_has_atomic)]
|
||||
|
@ -413,18 +413,6 @@ fn nameize<I: Iterator<Item = NamedMatch>>(
|
||||
Success(ret_val)
|
||||
}
|
||||
|
||||
/// Generates an appropriate parsing failure message. For EOF, this is "unexpected end...". For
|
||||
/// other tokens, this is "unexpected token...".
|
||||
crate fn parse_failure_msg(tok: &Token) -> String {
|
||||
match tok.kind {
|
||||
token::Eof => "unexpected end of macro invocation".to_string(),
|
||||
_ => format!(
|
||||
"no rules expected the token `{}`",
|
||||
pprust::token_to_string(tok)
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
/// Performs a token equality check, ignoring syntax context (that is, an unhygienic comparison)
|
||||
fn token_name_eq(t1: &Token, t2: &Token) -> bool {
|
||||
if let (Some((ident1, is_raw1)), Some((ident2, is_raw2))) = (t1.ident(), t2.ident()) {
|
||||
|
@ -6,7 +6,7 @@ use crate::ext::base::{SyntaxExtension, SyntaxExtensionKind};
|
||||
use crate::ext::expand::{AstFragment, AstFragmentKind};
|
||||
use crate::ext::mbe;
|
||||
use crate::ext::mbe::macro_check;
|
||||
use crate::ext::mbe::macro_parser::{parse, parse_failure_msg};
|
||||
use crate::ext::mbe::macro_parser::parse;
|
||||
use crate::ext::mbe::macro_parser::{Error, Failure, Success};
|
||||
use crate::ext::mbe::macro_parser::{MatchedNonterminal, MatchedSeq, NamedParseResult};
|
||||
use crate::ext::mbe::transcribe::transcribe;
|
||||
@ -15,6 +15,7 @@ use crate::parse::parser::Parser;
|
||||
use crate::parse::token::TokenKind::*;
|
||||
use crate::parse::token::{self, NtTT, Token};
|
||||
use crate::parse::{Directory, ParseSess};
|
||||
use crate::print::pprust;
|
||||
use crate::symbol::{kw, sym, Symbol};
|
||||
use crate::tokenstream::{DelimSpan, TokenStream, TokenTree};
|
||||
|
||||
@ -371,10 +372,6 @@ pub fn compile_declarative_macro(
|
||||
tt.clone().into(),
|
||||
true,
|
||||
sess,
|
||||
features,
|
||||
&def.attrs,
|
||||
edition,
|
||||
def.id,
|
||||
)
|
||||
.pop()
|
||||
.unwrap();
|
||||
@ -398,10 +395,6 @@ pub fn compile_declarative_macro(
|
||||
tt.clone().into(),
|
||||
false,
|
||||
sess,
|
||||
features,
|
||||
&def.attrs,
|
||||
edition,
|
||||
def.id,
|
||||
)
|
||||
.pop()
|
||||
.unwrap();
|
||||
@ -1184,3 +1177,15 @@ impl TokenTree {
|
||||
parse(cx.parse_sess(), tts, mtch, Some(directory), true)
|
||||
}
|
||||
}
|
||||
|
||||
/// Generates an appropriate parsing failure message. For EOF, this is "unexpected end...". For
|
||||
/// other tokens, this is "unexpected token...".
|
||||
fn parse_failure_msg(tok: &Token) -> String {
|
||||
match tok.kind {
|
||||
token::Eof => "unexpected end of macro invocation".to_string(),
|
||||
_ => format!(
|
||||
"no rules expected the token `{}`",
|
||||
pprust::token_to_string(tok),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
@ -1,18 +1,15 @@
|
||||
use crate::ast;
|
||||
use crate::ast::NodeId;
|
||||
use crate::ext::mbe::macro_parser;
|
||||
use crate::ext::mbe::{TokenTree, KleeneOp, KleeneToken, SequenceRepetition, Delimited};
|
||||
use crate::feature_gate::Features;
|
||||
use crate::parse::token::{self, Token};
|
||||
use crate::parse::ParseSess;
|
||||
use crate::print::pprust;
|
||||
use crate::symbol::kw;
|
||||
use crate::tokenstream;
|
||||
|
||||
use syntax_pos::{edition::Edition, Span};
|
||||
use syntax_pos::Span;
|
||||
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
use std::iter::Peekable;
|
||||
|
||||
/// Takes a `tokenstream::TokenStream` and returns a `Vec<self::TokenTree>`. Specifically, this
|
||||
/// takes a generic `TokenStream`, such as is used in the rest of the compiler, and returns a
|
||||
@ -39,17 +36,13 @@ pub(super) fn parse(
|
||||
input: tokenstream::TokenStream,
|
||||
expect_matchers: bool,
|
||||
sess: &ParseSess,
|
||||
features: &Features,
|
||||
attrs: &[ast::Attribute],
|
||||
edition: Edition,
|
||||
macro_node_id: NodeId,
|
||||
) -> Vec<TokenTree> {
|
||||
// Will contain the final collection of `self::TokenTree`
|
||||
let mut result = Vec::new();
|
||||
|
||||
// For each token tree in `input`, parse the token into a `self::TokenTree`, consuming
|
||||
// additional trees if need be.
|
||||
let mut trees = input.trees().peekable();
|
||||
let mut trees = input.trees();
|
||||
while let Some(tree) = trees.next() {
|
||||
// Given the parsed tree, if there is a metavar and we are expecting matchers, actually
|
||||
// parse out the matcher (i.e., in `$id:ident` this would parse the `:` and `ident`).
|
||||
@ -58,10 +51,6 @@ pub(super) fn parse(
|
||||
&mut trees,
|
||||
expect_matchers,
|
||||
sess,
|
||||
features,
|
||||
attrs,
|
||||
edition,
|
||||
macro_node_id,
|
||||
);
|
||||
match tree {
|
||||
TokenTree::MetaVar(start_sp, ident) if expect_matchers => {
|
||||
@ -109,13 +98,9 @@ pub(super) fn parse(
|
||||
/// unstable features or not.
|
||||
fn parse_tree(
|
||||
tree: tokenstream::TokenTree,
|
||||
trees: &mut Peekable<impl Iterator<Item = tokenstream::TokenTree>>,
|
||||
trees: &mut impl Iterator<Item = tokenstream::TokenTree>,
|
||||
expect_matchers: bool,
|
||||
sess: &ParseSess,
|
||||
features: &Features,
|
||||
attrs: &[ast::Attribute],
|
||||
edition: Edition,
|
||||
macro_node_id: NodeId,
|
||||
) -> TokenTree {
|
||||
// Depending on what `tree` is, we could be parsing different parts of a macro
|
||||
match tree {
|
||||
@ -135,10 +120,6 @@ fn parse_tree(
|
||||
tts.into(),
|
||||
expect_matchers,
|
||||
sess,
|
||||
features,
|
||||
attrs,
|
||||
edition,
|
||||
macro_node_id,
|
||||
);
|
||||
// Get the Kleene operator and optional separator
|
||||
let (separator, kleene) = parse_sep_and_kleene_op(trees, span.entire(), sess);
|
||||
@ -192,10 +173,6 @@ fn parse_tree(
|
||||
tts.into(),
|
||||
expect_matchers,
|
||||
sess,
|
||||
features,
|
||||
attrs,
|
||||
edition,
|
||||
macro_node_id,
|
||||
),
|
||||
}),
|
||||
),
|
||||
@ -244,7 +221,7 @@ fn parse_kleene_op(
|
||||
/// operator and separator, then a tuple with `(separator, KleeneOp)` is returned. Otherwise, an
|
||||
/// error with the appropriate span is emitted to `sess` and a dummy value is returned.
|
||||
fn parse_sep_and_kleene_op(
|
||||
input: &mut Peekable<impl Iterator<Item = tokenstream::TokenTree>>,
|
||||
input: &mut impl Iterator<Item = tokenstream::TokenTree>,
|
||||
span: Span,
|
||||
sess: &ParseSess,
|
||||
) -> (Option<Token>, KleeneToken) {
|
||||
|
@ -7,7 +7,6 @@
|
||||
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/",
|
||||
test(attr(deny(warnings))))]
|
||||
|
||||
#![cfg_attr(bootstrap, feature(bind_by_move_pattern_guards))]
|
||||
#![feature(box_syntax)]
|
||||
#![feature(const_fn)]
|
||||
#![feature(const_transmute)]
|
||||
|
@ -834,8 +834,6 @@ pub fn walk_param<'a, V: Visitor<'a>>(visitor: &mut V, param: &'a Param) {
|
||||
|
||||
pub fn walk_arm<'a, V: Visitor<'a>>(visitor: &mut V, arm: &'a Arm) {
|
||||
visitor.visit_pat(&arm.pat);
|
||||
// NOTE(or_patterns; Centril | dlrobertson):
|
||||
// If you change this, also change the hack in `lowering.rs`.
|
||||
walk_list!(visitor, visit_expr, &arm.guard);
|
||||
visitor.visit_expr(&arm.body);
|
||||
walk_list!(visitor, visit_attribute, &arm.attrs);
|
||||
|
@ -12,7 +12,7 @@
|
||||
# source tarball for a stable release you'll likely see `1.x.0` for rustc and
|
||||
# `0.x.0` for Cargo where they were released on `date`.
|
||||
|
||||
date: 2019-08-13
|
||||
date: 2019-09-25
|
||||
rustc: beta
|
||||
cargo: beta
|
||||
|
||||
|
53
src/test/ui/consts/const-eval/simd/insert_extract.rs
Normal file
53
src/test/ui/consts/const-eval/simd/insert_extract.rs
Normal file
@ -0,0 +1,53 @@
|
||||
// run-pass
|
||||
#![feature(const_fn)]
|
||||
#![feature(repr_simd)]
|
||||
#![feature(platform_intrinsics)]
|
||||
#![allow(non_camel_case_types)]
|
||||
|
||||
#[repr(simd)] struct i8x1(i8);
|
||||
#[repr(simd)] struct u16x2(u16, u16);
|
||||
#[repr(simd)] struct f32x3(f32, f32, f32);
|
||||
|
||||
extern "platform-intrinsic" {
|
||||
fn simd_insert<T, U>(x: T, idx: u32, val: U) -> T;
|
||||
fn simd_extract<T, U>(x: T, idx: u32) -> U;
|
||||
}
|
||||
|
||||
fn main() {
|
||||
{
|
||||
const U: i8x1 = i8x1(13);
|
||||
const V: i8x1 = unsafe { simd_insert(U, 0_u32, 42_i8) };
|
||||
const X0: i8 = V.0;
|
||||
const Y0: i8 = unsafe { simd_extract(V, 0) };
|
||||
assert_eq!(X0, 42);
|
||||
assert_eq!(Y0, 42);
|
||||
}
|
||||
{
|
||||
const U: u16x2 = u16x2(13, 14);
|
||||
const V: u16x2 = unsafe { simd_insert(U, 1_u32, 42_u16) };
|
||||
const X0: u16 = V.0;
|
||||
const X1: u16 = V.1;
|
||||
const Y0: u16 = unsafe { simd_extract(V, 0) };
|
||||
const Y1: u16 = unsafe { simd_extract(V, 1) };
|
||||
assert_eq!(X0, 13);
|
||||
assert_eq!(X1, 42);
|
||||
assert_eq!(Y0, 13);
|
||||
assert_eq!(Y1, 42);
|
||||
}
|
||||
{
|
||||
const U: f32x3 = f32x3(13., 14., 15.);
|
||||
const V: f32x3 = unsafe { simd_insert(U, 1_u32, 42_f32) };
|
||||
const X0: f32 = V.0;
|
||||
const X1: f32 = V.1;
|
||||
const X2: f32 = V.2;
|
||||
const Y0: f32 = unsafe { simd_extract(V, 0) };
|
||||
const Y1: f32 = unsafe { simd_extract(V, 1) };
|
||||
const Y2: f32 = unsafe { simd_extract(V, 2) };
|
||||
assert_eq!(X0, 13.);
|
||||
assert_eq!(X1, 42.);
|
||||
assert_eq!(X2, 15.);
|
||||
assert_eq!(Y0, 13.);
|
||||
assert_eq!(Y1, 42.);
|
||||
assert_eq!(Y2, 15.);
|
||||
}
|
||||
}
|
@ -33,6 +33,9 @@ fn main() {
|
||||
let mut mut_unused_var = 1;
|
||||
|
||||
let (mut var, unused_var) = (1, 2);
|
||||
// NOTE: `var` comes after `unused_var` lexicographically yet the warning
|
||||
// for `var` will be emitted before the one for `unused_var`. We use an
|
||||
// `IndexMap` to ensure this is the case instead of a `BTreeMap`.
|
||||
|
||||
if let SoulHistory { corridors_of_light,
|
||||
mut hours_are_suns,
|
||||
|
@ -30,13 +30,13 @@ LL | let (mut var, unused_var) = (1, 2);
|
||||
| ^^^^^^^^^^ help: consider prefixing with an underscore: `_unused_var`
|
||||
|
||||
warning: unused variable: `corridors_of_light`
|
||||
--> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:37:26
|
||||
--> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:40:26
|
||||
|
|
||||
LL | if let SoulHistory { corridors_of_light,
|
||||
| ^^^^^^^^^^^^^^^^^^ help: try ignoring the field: `corridors_of_light: _`
|
||||
|
||||
warning: variable `hours_are_suns` is assigned to, but never used
|
||||
--> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:38:30
|
||||
--> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:41:30
|
||||
|
|
||||
LL | mut hours_are_suns,
|
||||
| ^^^^^^^^^^^^^^
|
||||
@ -44,7 +44,7 @@ LL | mut hours_are_suns,
|
||||
= note: consider using `_hours_are_suns` instead
|
||||
|
||||
warning: value assigned to `hours_are_suns` is never read
|
||||
--> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:40:9
|
||||
--> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:43:9
|
||||
|
|
||||
LL | hours_are_suns = false;
|
||||
| ^^^^^^^^^^^^^^
|
||||
@ -58,43 +58,43 @@ LL | #![warn(unused)] // UI tests pass `-A unused` (#43896)
|
||||
= help: maybe it is overwritten before being read?
|
||||
|
||||
warning: unused variable: `fire`
|
||||
--> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:44:32
|
||||
--> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:47:32
|
||||
|
|
||||
LL | let LovelyAmbition { lips, fire } = the_spirit;
|
||||
| ^^^^ help: try ignoring the field: `fire: _`
|
||||
|
||||
warning: unused variable: `case`
|
||||
--> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:53:23
|
||||
--> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:56:23
|
||||
|
|
||||
LL | Large::Suit { case } => {}
|
||||
| ^^^^ help: try ignoring the field: `case: _`
|
||||
|
||||
warning: unused variable: `case`
|
||||
--> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:58:24
|
||||
--> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:61:24
|
||||
|
|
||||
LL | &Large::Suit { case } => {}
|
||||
| ^^^^ help: try ignoring the field: `case: _`
|
||||
|
||||
warning: unused variable: `case`
|
||||
--> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:63:27
|
||||
--> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:66:27
|
||||
|
|
||||
LL | box Large::Suit { case } => {}
|
||||
| ^^^^ help: try ignoring the field: `case: _`
|
||||
|
||||
warning: unused variable: `case`
|
||||
--> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:68:24
|
||||
--> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:71:24
|
||||
|
|
||||
LL | (Large::Suit { case },) => {}
|
||||
| ^^^^ help: try ignoring the field: `case: _`
|
||||
|
||||
warning: unused variable: `case`
|
||||
--> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:73:24
|
||||
--> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:76:24
|
||||
|
|
||||
LL | [Large::Suit { case }] => {}
|
||||
| ^^^^ help: try ignoring the field: `case: _`
|
||||
|
||||
warning: unused variable: `case`
|
||||
--> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:78:29
|
||||
--> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:81:29
|
||||
|
|
||||
LL | Tuple(Large::Suit { case }, ()) => {}
|
||||
| ^^^^ help: try ignoring the field: `case: _`
|
||||
|
Loading…
Reference in New Issue
Block a user