diff --git a/Cargo.lock b/Cargo.lock index 1cfe57da6974d..c34a325a47492 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2722,6 +2722,7 @@ dependencies = [ "rustc_errors 0.0.0", "rustc_mir 0.0.0", "syntax 0.0.0", + "syntax_ext 0.0.0", "syntax_pos 0.0.0", ] diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index 79c2b89522dbf..bd2349161f74a 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -302,7 +302,7 @@ impl_stable_hash_for!(struct ty::FieldDef { impl_stable_hash_for!( impl<'tcx> for enum mir::interpret::ConstValue<'tcx> [ mir::interpret::ConstValue ] { Scalar(val), - ScalarPair(a, b), + Slice(a, b), ByRef(id, alloc, offset), } ); diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index cc0dd71738fce..04d454702921b 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -104,6 +104,7 @@ use ty::query::{Providers, queries}; use lint; use errors::Applicability; use util::nodemap::{NodeMap, HirIdMap, HirIdSet}; +use rustc_data_structures::fx::FxHashMap; use std::collections::VecDeque; use std::{fmt, u32}; @@ -1446,7 +1447,7 @@ fn check_local<'a, 'tcx>(this: &mut Liveness<'a, 'tcx>, local: &'tcx hir::Local) 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(span, id, ln, var); + this.warn_about_unused(vec![span], id, ln, var); }) } } @@ -1455,12 +1456,29 @@ fn check_local<'a, 'tcx>(this: &mut Liveness<'a, 'tcx>, local: &'tcx hir::Local) } fn check_arm<'a, 'tcx>(this: &mut Liveness<'a, 'tcx>, arm: &'tcx hir::Arm) { - // 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 - this.arm_pats_bindings(arm.pats.first().map(|p| &**p), |this, ln, var, sp, id| { - this.warn_about_unused(sp, id, ln, var); - }); + // 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: FxHashMap)> = 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); } @@ -1551,7 +1569,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { let var = self.variable(hir_id, sp); // Ignore unused self. if ident.name != keywords::SelfLower.name() { - if !self.warn_about_unused(sp, hir_id, entry_ln, var) { + 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); } @@ -1563,14 +1581,14 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { 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(sp, id, ln, var) { + if !this.warn_about_unused(vec![sp], id, ln, var) { this.warn_about_dead_assign(sp, id, ln, var); } }) } fn warn_about_unused(&self, - sp: Span, + spans: Vec, hir_id: HirId, ln: LiveNode, var: Variable) @@ -1587,33 +1605,36 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { self.assigned_on_exit(ln, var).is_some() }; - let suggest_underscore_msg = format!("consider using `_{}` instead", name); - if is_assigned { - self.ir.tcx - .lint_hir_note(lint::builtin::UNUSED_VARIABLES, hir_id, sp, - &format!("variable `{}` is assigned to, but never used", - name), - &suggest_underscore_msg); + self.ir.tcx.lint_hir_note( + lint::builtin::UNUSED_VARIABLES, + hir_id, + spans.clone(), + &format!("variable `{}` is assigned to, but never used", name), + &format!("consider using `_{}` instead", name), + ); } else if name != "self" { - let msg = format!("unused variable: `{}`", name); - let mut err = self.ir.tcx - .struct_span_lint_hir(lint::builtin::UNUSED_VARIABLES, hir_id, sp, &msg); + 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) { - err.span_suggestion( - sp, + err.multipart_suggestion( "try ignoring the field", - format!("{}: _", name), - Applicability::MachineApplicable, + spans.iter().map(|span| (*span, format!("{}: _", name))).collect(), + Applicability::MachineApplicable ); } else { - err.span_suggestion_short( - sp, - &suggest_underscore_msg, - format!("_{}", name), + err.multipart_suggestion( + "consider prefixing with an underscore", + spans.iter().map(|span| (*span, format!("_{}", name))).collect(), Applicability::MachineApplicable, ); } + err.emit() } } @@ -1623,11 +1644,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { } } - fn warn_about_dead_assign(&self, - sp: Span, - hir_id: HirId, - ln: LiveNode, - var: Variable) { + fn warn_about_dead_assign(&self, sp: 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); } diff --git a/src/librustc/mir/interpret/pointer.rs b/src/librustc/mir/interpret/pointer.rs index a046825f088bb..498c0b5b917e9 100644 --- a/src/librustc/mir/interpret/pointer.rs +++ b/src/librustc/mir/interpret/pointer.rs @@ -76,6 +76,8 @@ pub struct Pointer { pub tag: Tag, } +static_assert!(POINTER_SIZE: ::std::mem::size_of::() == 16); + /// Produces a `Pointer` which points to the beginning of the Allocation impl From for Pointer { #[inline(always)] diff --git a/src/librustc/mir/interpret/value.rs b/src/librustc/mir/interpret/value.rs index 76eb43e73d166..4ac84bcfd1903 100644 --- a/src/librustc/mir/interpret/value.rs +++ b/src/librustc/mir/interpret/value.rs @@ -22,22 +22,28 @@ pub enum ConstValue<'tcx> { /// Not using the enum `Value` to encode that this must not be `Undef` Scalar(Scalar), - /// Used only for *fat pointers* with layout::abi::ScalarPair + /// Used only for slices and strings (`&[T]`, `&str`, `*const [T]`, `*mut str`, `Box`, ...) /// - /// Needed for pattern matching code related to slices and strings. - ScalarPair(Scalar, Scalar), + /// Empty slices don't necessarily have an address backed by an `AllocId`, thus we also need to + /// enable integer pointers. The `Scalar` type covers exactly those two cases. While we could + /// create dummy-`AllocId`s, the additional code effort for the conversions doesn't seem worth + /// it. + Slice(Scalar, u64), /// An allocation + offset into the allocation. /// Invariant: The AllocId matches the allocation. ByRef(AllocId, &'tcx Allocation, Size), } +#[cfg(target_arch = "x86_64")] +static_assert!(CONST_SIZE: ::std::mem::size_of::>() == 40); + impl<'tcx> ConstValue<'tcx> { #[inline] pub fn try_to_scalar(&self) -> Option { match *self { ConstValue::ByRef(..) | - ConstValue::ScalarPair(..) => None, + ConstValue::Slice(..) => None, ConstValue::Scalar(val) => Some(val), } } @@ -56,17 +62,8 @@ impl<'tcx> ConstValue<'tcx> { pub fn new_slice( val: Scalar, len: u64, - cx: &impl HasDataLayout ) -> Self { - ConstValue::ScalarPair(val, Scalar::Bits { - bits: len as u128, - size: cx.data_layout().pointer_size.bytes() as u8, - }) - } - - #[inline] - pub fn new_dyn_trait(val: Scalar, vtable: Pointer) -> Self { - ConstValue::ScalarPair(val, Scalar::Ptr(vtable)) + ConstValue::Slice(val, len) } } @@ -90,6 +87,9 @@ pub enum Scalar { Ptr(Pointer), } +#[cfg(target_arch = "x86_64")] +static_assert!(SCALAR_SIZE: ::std::mem::size_of::() == 24); + impl fmt::Display for Scalar { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index f824ab7e5b395..82083b4f69964 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -2702,23 +2702,21 @@ pub fn fmt_const_val(f: &mut impl Write, const_val: ty::Const<'_>) -> fmt::Resul return write!(f, "{}", item_path_str(did)); } // print string literals - if let ConstValue::ScalarPair(ptr, len) = value { + if let ConstValue::Slice(ptr, len) = value { if let Scalar::Ptr(ptr) = ptr { - if let Scalar::Bits { bits: len, .. } = len { - if let Ref(_, &ty::TyS { sty: Str, .. }, _) = ty.sty { - return ty::tls::with(|tcx| { - let alloc = tcx.alloc_map.lock().get(ptr.alloc_id); - if let Some(interpret::AllocKind::Memory(alloc)) = alloc { - assert_eq!(len as usize as u128, len); - let slice = - &alloc.bytes[(ptr.offset.bytes() as usize)..][..(len as usize)]; - let s = ::std::str::from_utf8(slice).expect("non utf8 str from miri"); - write!(f, "{:?}", s) - } else { - write!(f, "pointer to erroneous constant {:?}, {:?}", ptr, len) - } - }); - } + if let Ref(_, &ty::TyS { sty: Str, .. }, _) = ty.sty { + return ty::tls::with(|tcx| { + let alloc = tcx.alloc_map.lock().get(ptr.alloc_id); + if let Some(interpret::AllocKind::Memory(alloc)) = alloc { + assert_eq!(len as usize as u64, len); + let slice = + &alloc.bytes[(ptr.offset.bytes() as usize)..][..(len as usize)]; + let s = ::std::str::from_utf8(slice).expect("non utf8 str from miri"); + write!(f, "{:?}", s) + } else { + write!(f, "pointer to erroneous constant {:?}, {:?}", ptr, len) + } + }); } } } diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 4c8f81411163c..a0da7cf2137d0 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -1767,7 +1767,7 @@ macro_rules! nop_list_lift { impl<'a, 'tcx> Lift<'tcx> for &'a List<$ty> { type Lifted = &'tcx List<$lifted>; fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option { - if self.is_empty() { + if self.is_empty() { return Some(List::empty()); } if tcx.interners.arena.in_arena(*self as *const _) { diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index 258470bf6f860..28f5a65374d98 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -498,7 +498,7 @@ impl<'a, 'tcx> Lift<'tcx> for ConstValue<'a> { fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option { match *self { ConstValue::Scalar(x) => Some(ConstValue::Scalar(x)), - ConstValue::ScalarPair(x, y) => Some(ConstValue::ScalarPair(x, y)), + ConstValue::Slice(x, y) => Some(ConstValue::Slice(x, y)), ConstValue::ByRef(x, alloc, z) => Some(ConstValue::ByRef( x, alloc.lift_to_tcx(tcx)?, z, )), diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index b98369b62ea37..671a0fc2d5d7a 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -2063,6 +2063,9 @@ pub enum LazyConst<'tcx> { Evaluated(Const<'tcx>), } +#[cfg(target_arch = "x86_64")] +static_assert!(LAZY_CONST_SIZE: ::std::mem::size_of::>() == 56); + impl<'tcx> LazyConst<'tcx> { pub fn map_evaluated(self, f: impl FnOnce(Const<'tcx>) -> Option) -> Option { match self { @@ -2089,6 +2092,9 @@ pub struct Const<'tcx> { pub val: ConstValue<'tcx>, } +#[cfg(target_arch = "x86_64")] +static_assert!(CONST_SIZE: ::std::mem::size_of::>() == 48); + impl<'tcx> Const<'tcx> { #[inline] pub fn from_scalar( diff --git a/src/librustc_codegen_ssa/mir/operand.rs b/src/librustc_codegen_ssa/mir/operand.rs index 2026e042ef0eb..8aad4c1f6e1c0 100644 --- a/src/librustc_codegen_ssa/mir/operand.rs +++ b/src/librustc_codegen_ssa/mir/operand.rs @@ -88,9 +88,9 @@ impl<'a, 'tcx: 'a, V: CodegenObject> OperandRef<'tcx, V> { ); OperandValue::Immediate(llval) }, - ConstValue::ScalarPair(a, b) => { - let (a_scalar, b_scalar) = match layout.abi { - layout::Abi::ScalarPair(ref a, ref b) => (a, b), + ConstValue::Slice(a, b) => { + let a_scalar = match layout.abi { + layout::Abi::ScalarPair(ref a, _) => a, _ => bug!("from_const: invalid ScalarPair layout: {:#?}", layout) }; let a_llval = bx.cx().scalar_to_backend( @@ -98,11 +98,7 @@ impl<'a, 'tcx: 'a, V: CodegenObject> OperandRef<'tcx, V> { a_scalar, bx.cx().scalar_pair_element_backend_type(layout, 0, true), ); - let b_llval = bx.cx().scalar_to_backend( - b, - b_scalar, - bx.cx().scalar_pair_element_backend_type(layout, 1, true), - ); + let b_llval = bx.cx().const_usize(b); OperandValue::Pair(a_llval, b_llval) }, ConstValue::ByRef(_, alloc, offset) => { diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 88dac42997f36..f5e5f1f5c0b95 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -1017,6 +1017,10 @@ where krate = ReplaceBodyWithLoop::new(sess).fold_crate(krate); } + let (has_proc_macro_decls, has_global_allocator) = time(sess, "AST validation", || { + ast_validation::check_crate(sess, &krate) + }); + // If we're in rustdoc we're always compiling as an rlib, but that'll trip a // bunch of checks in the `modify` function below. For now just skip this // step entirely if we're rustdoc as it's not too useful anyway. @@ -1031,6 +1035,7 @@ where &mut resolver, krate, is_proc_macro_crate, + has_proc_macro_decls, is_test_crate, num_crate_types, sess.diagnostic(), @@ -1038,16 +1043,18 @@ where }); } - // Expand global allocators, which are treated as an in-tree proc macro - krate = time(sess, "creating allocators", || { - allocator::expand::modify( - &sess.parse_sess, - &mut resolver, - krate, - crate_name.to_string(), - sess.diagnostic(), - ) - }); + if has_global_allocator { + // Expand global allocators, which are treated as an in-tree proc macro + krate = time(sess, "creating allocators", || { + allocator::expand::modify( + &sess.parse_sess, + &mut resolver, + krate, + crate_name.to_string(), + sess.diagnostic(), + ) + }); + } // Done with macro expansion! @@ -1065,10 +1072,6 @@ where println!("{}", json::as_json(&krate)); } - time(sess, "AST validation", || { - ast_validation::check_crate(sess, &krate) - }); - time(sess, "name resolution", || { resolver.resolve_crate(&krate); }); diff --git a/src/librustc_mir/const_eval.rs b/src/librustc_mir/const_eval.rs index 9ed480a9af5bb..f83a930353b73 100644 --- a/src/librustc_mir/const_eval.rs +++ b/src/librustc_mir/const_eval.rs @@ -67,14 +67,11 @@ pub fn op_to_const<'tcx>( op: OpTy<'tcx>, may_normalize: bool, ) -> EvalResult<'tcx, ty::Const<'tcx>> { - // We do not normalize just any data. Only scalar layout and fat pointers. + // We do not normalize just any data. Only scalar layout and slices. let normalize = may_normalize && match op.layout.abi { layout::Abi::Scalar(..) => true, - layout::Abi::ScalarPair(..) => { - // Must be a fat pointer - op.layout.ty.builtin_deref(true).is_some() - }, + layout::Abi::ScalarPair(..) => op.layout.ty.is_slice(), _ => false, }; let normalized_op = if normalize { @@ -103,7 +100,7 @@ pub fn op_to_const<'tcx>( Ok(Immediate::Scalar(x)) => ConstValue::Scalar(x.not_undef()?), Ok(Immediate::ScalarPair(a, b)) => - ConstValue::ScalarPair(a.not_undef()?, b.not_undef()?), + ConstValue::Slice(a.not_undef()?, b.to_usize(ecx)?), }; Ok(ty::Const { val, ty: op.layout.ty }) } diff --git a/src/librustc_mir/hair/constant.rs b/src/librustc_mir/hair/constant.rs index f63c3e2ff6142..21c471d49ee66 100644 --- a/src/librustc_mir/hair/constant.rs +++ b/src/librustc_mir/hair/constant.rs @@ -35,13 +35,13 @@ crate fn lit_to_const<'a, 'gcx, 'tcx>( LitKind::Str(ref s, _) => { let s = s.as_str(); let id = tcx.allocate_bytes(s.as_bytes()); - ConstValue::new_slice(Scalar::Ptr(id.into()), s.len() as u64, &tcx) + ConstValue::new_slice(Scalar::Ptr(id.into()), s.len() as u64) }, LitKind::Err(ref s) => { let s = s.as_str(); let id = tcx.allocate_bytes(s.as_bytes()); return Ok(ty::Const { - val: ConstValue::new_slice(Scalar::Ptr(id.into()), s.len() as u64, &tcx), + val: ConstValue::new_slice(Scalar::Ptr(id.into()), s.len() as u64), ty: tcx.types.err, }); }, diff --git a/src/librustc_mir/hair/pattern/_match.rs b/src/librustc_mir/hair/pattern/_match.rs index 9cc5c93de41d8..7f5b1a761d261 100644 --- a/src/librustc_mir/hair/pattern/_match.rs +++ b/src/librustc_mir/hair/pattern/_match.rs @@ -221,13 +221,16 @@ impl<'a, 'tcx> LiteralExpander<'a, 'tcx> { // unsize array to slice if pattern is array but match value or other patterns are slice (ConstValue::Scalar(Scalar::Ptr(p)), ty::Array(t, n), ty::Slice(u)) => { assert_eq!(t, u); - ConstValue::ScalarPair( + ConstValue::Slice( Scalar::Ptr(p), - n.map_evaluated(|val| val.val.try_to_scalar()).unwrap(), + n.map_evaluated(|val| val.val.try_to_scalar()) + .unwrap() + .to_usize(&self.tcx) + .unwrap(), ) }, // fat pointers stay the same - (ConstValue::ScalarPair(..), _, _) => val, + (ConstValue::Slice(..), _, _) => val, // FIXME(oli-obk): this is reachable for `const FOO: &&&u32 = &&&42;` being used _ => bug!("cannot deref {:#?}, {} -> {}", val, crty, rty), } @@ -788,9 +791,9 @@ fn max_slice_length<'p, 'a: 'p, 'tcx: 'a, I>( max_fixed_len, n.unwrap_usize(cx.tcx), ), - (ConstValue::ScalarPair(_, n), ty::Slice(_)) => max_fixed_len = cmp::max( + (ConstValue::Slice(_, n), ty::Slice(_)) => max_fixed_len = cmp::max( max_fixed_len, - n.to_usize(&cx.tcx).unwrap(), + n, ), _ => {}, } @@ -1432,7 +1435,7 @@ fn slice_pat_covered_by_const<'tcx>( alloc.get_bytes(&tcx, ptr, Size::from_bytes(n)).unwrap() }, // a slice fat pointer to a zero length slice - (ConstValue::ScalarPair(Scalar::Bits { .. }, n), ty::Slice(t)) => { + (ConstValue::Slice(Scalar::Bits { .. }, 0), ty::Slice(t)) => { if *t != tcx.types.u8 { // FIXME(oli-obk): can't mix const patterns with slice patterns and get // any sort of exhaustiveness/unreachable check yet @@ -1440,11 +1443,10 @@ fn slice_pat_covered_by_const<'tcx>( // are definitely unreachable. return Ok(false); } - assert_eq!(n.to_usize(&tcx).unwrap(), 0); &[] }, // - (ConstValue::ScalarPair(Scalar::Ptr(ptr), n), ty::Slice(t)) => { + (ConstValue::Slice(Scalar::Ptr(ptr), n), ty::Slice(t)) => { if *t != tcx.types.u8 { // FIXME(oli-obk): can't mix const patterns with slice patterns and get // any sort of exhaustiveness/unreachable check yet @@ -1452,7 +1454,6 @@ fn slice_pat_covered_by_const<'tcx>( // are definitely unreachable. return Ok(false); } - let n = n.to_usize(&tcx).unwrap(); tcx.alloc_map .lock() .unwrap_memory(ptr.alloc_id) @@ -1784,12 +1785,12 @@ fn specialize<'p, 'a: 'p, 'tcx: 'a>( }, ty::TyKind::Slice(t) => { match value.val { - ConstValue::ScalarPair(ptr, n) => ( + ConstValue::Slice(ptr, n) => ( ptr.to_ptr().ok().map(|ptr| ( ptr, cx.tcx.alloc_map.lock().unwrap_memory(ptr.alloc_id), )), - n.to_bits(cx.tcx.data_layout.pointer_size).unwrap() as u64, + n, t, ), _ => span_bug!( diff --git a/src/librustc_mir/hair/pattern/mod.rs b/src/librustc_mir/hair/pattern/mod.rs index 06a50f35be1cf..7d48cdc1d8aef 100644 --- a/src/librustc_mir/hair/pattern/mod.rs +++ b/src/librustc_mir/hair/pattern/mod.rs @@ -1218,25 +1218,21 @@ pub fn compare_const_vals<'a, 'gcx, 'tcx>( if let ty::Str = ty.value.sty { match (a.val, b.val) { ( - ConstValue::ScalarPair( + ConstValue::Slice( Scalar::Ptr(ptr_a), len_a, ), - ConstValue::ScalarPair( + ConstValue::Slice( Scalar::Ptr(ptr_b), len_b, ), ) if ptr_a.offset.bytes() == 0 && ptr_b.offset.bytes() == 0 => { - if let Ok(len_a) = len_a.to_bits(tcx.data_layout.pointer_size) { - if let Ok(len_b) = len_b.to_bits(tcx.data_layout.pointer_size) { - if len_a == len_b { - let map = tcx.alloc_map.lock(); - let alloc_a = map.unwrap_memory(ptr_a.alloc_id); - let alloc_b = map.unwrap_memory(ptr_b.alloc_id); - if alloc_a.bytes.len() as u128 == len_a { - return from_bool(alloc_a == alloc_b); - } - } + if len_a == len_b { + let map = tcx.alloc_map.lock(); + let alloc_a = map.unwrap_memory(ptr_a.alloc_id); + let alloc_b = map.unwrap_memory(ptr_b.alloc_id); + if alloc_a.bytes.len() as u64 == len_a { + return from_bool(alloc_a == alloc_b); } } } diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs index 8741571342f83..e4bee24c88cfa 100644 --- a/src/librustc_mir/interpret/operand.rs +++ b/src/librustc_mir/interpret/operand.rs @@ -555,10 +555,10 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> MemPlace::from_ptr(Pointer::new(id, offset), alloc.align) ).with_default_tag()) }, - ConstValue::ScalarPair(a, b) => + ConstValue::Slice(a, b) => Ok(Operand::Immediate(Immediate::ScalarPair( a.into(), - b.into(), + Scalar::from_uint(b, self.tcx.data_layout.pointer_size).into(), )).with_default_tag()), ConstValue::Scalar(x) => Ok(Operand::Immediate(Immediate::Scalar(x.into())).with_default_tag()), diff --git a/src/librustc_mir/monomorphize/collector.rs b/src/librustc_mir/monomorphize/collector.rs index bc63f8b6ac854..e713ab17c3af5 100644 --- a/src/librustc_mir/monomorphize/collector.rs +++ b/src/librustc_mir/monomorphize/collector.rs @@ -1254,12 +1254,7 @@ fn collect_const<'a, 'tcx>( debug!("visiting const {:?}", constant); match constant.val { - ConstValue::ScalarPair(Scalar::Ptr(a), Scalar::Ptr(b)) => { - collect_miri(tcx, a.alloc_id, output); - collect_miri(tcx, b.alloc_id, output); - } - ConstValue::ScalarPair(_, Scalar::Ptr(ptr)) | - ConstValue::ScalarPair(Scalar::Ptr(ptr), _) | + ConstValue::Slice(Scalar::Ptr(ptr), _) | ConstValue::Scalar(Scalar::Ptr(ptr)) => collect_miri(tcx, ptr.alloc_id, output), ConstValue::ByRef(_id, alloc, _offset) => { diff --git a/src/librustc_passes/Cargo.toml b/src/librustc_passes/Cargo.toml index 2babb93eedbcf..f5154a033af8d 100644 --- a/src/librustc_passes/Cargo.toml +++ b/src/librustc_passes/Cargo.toml @@ -14,5 +14,6 @@ rustc = { path = "../librustc" } rustc_mir = { path = "../librustc_mir"} rustc_data_structures = { path = "../librustc_data_structures" } syntax = { path = "../libsyntax" } +syntax_ext = { path = "../libsyntax_ext" } syntax_pos = { path = "../libsyntax_pos" } rustc_errors = { path = "../librustc_errors" } diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs index 3b6328f320f78..3deb2ff8d8a0b 100644 --- a/src/librustc_passes/ast_validation.rs +++ b/src/librustc_passes/ast_validation.rs @@ -15,12 +15,15 @@ use syntax::source_map::Spanned; use syntax::symbol::keywords; use syntax::ptr::P; use syntax::visit::{self, Visitor}; +use syntax_ext::proc_macro_decls::is_proc_macro_attr; use syntax_pos::Span; use errors; use errors::Applicability; struct AstValidator<'a> { session: &'a Session, + has_proc_macro_decls: bool, + has_global_allocator: bool, // Used to ban nested `impl Trait`, e.g., `impl Into`. // Nested `impl Trait` _is_ allowed in associated type position, @@ -367,6 +370,14 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } fn visit_item(&mut self, item: &'a Item) { + if item.attrs.iter().any(|attr| is_proc_macro_attr(attr) ) { + self.has_proc_macro_decls = true; + } + + if attr::contains_name(&item.attrs, "global_allocator") { + self.has_global_allocator = true; + } + match item.node { ItemKind::Impl(unsafety, polarity, _, _, Some(..), ref ty, ref impl_items) => { self.invalid_visibility(&item.vis, None); @@ -590,10 +601,15 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } } -pub fn check_crate(session: &Session, krate: &Crate) { - visit::walk_crate(&mut AstValidator { +pub fn check_crate(session: &Session, krate: &Crate) -> (bool, bool) { + let mut validator = AstValidator { session, + has_proc_macro_decls: false, + has_global_allocator: false, outer_impl_trait: None, is_impl_trait_banned: false, - }, krate) + }; + visit::walk_crate(&mut validator, krate); + + (validator.has_proc_macro_decls, validator.has_global_allocator) } diff --git a/src/librustc_passes/lib.rs b/src/librustc_passes/lib.rs index a181bc7e9b480..76605c58a7889 100644 --- a/src/librustc_passes/lib.rs +++ b/src/librustc_passes/lib.rs @@ -22,6 +22,7 @@ extern crate rustc_data_structures; extern crate log; #[macro_use] extern crate syntax; +extern crate syntax_ext; extern crate syntax_pos; extern crate rustc_errors as errors; diff --git a/src/libsyntax_ext/proc_macro_decls.rs b/src/libsyntax_ext/proc_macro_decls.rs index 1d272712cacc8..46c502965eea8 100644 --- a/src/libsyntax_ext/proc_macro_decls.rs +++ b/src/libsyntax_ext/proc_macro_decls.rs @@ -48,6 +48,7 @@ pub fn modify(sess: &ParseSess, resolver: &mut dyn (::syntax::ext::base::Resolver), mut krate: ast::Crate, is_proc_macro_crate: bool, + has_proc_macro_decls: bool, is_test_crate: bool, num_crate_types: usize, handler: &errors::Handler) -> ast::Crate { @@ -64,7 +65,9 @@ pub fn modify(sess: &ParseSess, is_proc_macro_crate, is_test_crate, }; - visit::walk_crate(&mut collect, &krate); + if has_proc_macro_decls || is_proc_macro_crate { + visit::walk_crate(&mut collect, &krate); + } (collect.derives, collect.attr_macros, collect.bang_macros) }; @@ -85,7 +88,7 @@ pub fn modify(sess: &ParseSess, krate } -fn is_proc_macro_attr(attr: &ast::Attribute) -> bool { +pub fn is_proc_macro_attr(attr: &ast::Attribute) -> bool { PROC_MACRO_KINDS.iter().any(|kind| attr.check_name(kind)) } diff --git a/src/test/ui/issues/issue-17999.stderr b/src/test/ui/issues/issue-17999.stderr index 3f32dc1540232..51c0c757a80c1 100644 --- a/src/test/ui/issues/issue-17999.stderr +++ b/src/test/ui/issues/issue-17999.stderr @@ -2,7 +2,7 @@ error: unused variable: `x` --> $DIR/issue-17999.rs:5:13 | LL | let x = (); //~ ERROR: unused variable: `x` - | ^ help: consider using `_x` instead + | ^ help: consider prefixing with an underscore: `_x` | note: lint level defined here --> $DIR/issue-17999.rs:1:9 @@ -14,7 +14,7 @@ error: unused variable: `a` --> $DIR/issue-17999.rs:7:13 | LL | a => {} //~ ERROR: unused variable: `a` - | ^ help: consider using `_a` instead + | ^ help: consider prefixing with an underscore: `_a` error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-22599.stderr b/src/test/ui/issues/issue-22599.stderr index 5c2ed7455f132..bc4949da6f785 100644 --- a/src/test/ui/issues/issue-22599.stderr +++ b/src/test/ui/issues/issue-22599.stderr @@ -2,7 +2,7 @@ error: unused variable: `a` --> $DIR/issue-22599.rs:8:19 | LL | v = match 0 { a => 0 }; //~ ERROR: unused variable: `a` - | ^ help: consider using `_a` instead + | ^ help: consider prefixing with an underscore: `_a` | note: lint level defined here --> $DIR/issue-22599.rs:1:9 diff --git a/src/test/ui/issues/issue-56685.rs b/src/test/ui/issues/issue-56685.rs new file mode 100644 index 0000000000000..f320c99ed15d1 --- /dev/null +++ b/src/test/ui/issues/issue-56685.rs @@ -0,0 +1,44 @@ +#![allow(dead_code)] +#![deny(unused_variables)] + +// This test aims to check that unused variable suggestions update bindings in all +// match arms. + +fn main() { + enum E { + A(i32,), + B(i32,), + } + + match E::A(1) { + E::A(x) | E::B(x) => {} + //~^ ERROR unused variable: `x` + } + + enum F { + A(i32, i32,), + B(i32, i32,), + C(i32, i32,), + } + + let _ = match F::A(1, 2) { + F::A(x, y) | F::B(x, y) => { y }, + //~^ ERROR unused variable: `x` + F::C(a, b) => { 3 } + //~^ ERROR unused variable: `a` + //~^^ ERROR unused variable: `b` + }; + + let _ = if let F::A(x, y) | F::B(x, y) = F::A(1, 2) { + //~^ ERROR unused variable: `x` + y + } else { + 3 + }; + + while let F::A(x, y) | F::B(x, y) = F::A(1, 2) { + //~^ ERROR unused variable: `x` + let _ = y; + break; + } +} diff --git a/src/test/ui/issues/issue-56685.stderr b/src/test/ui/issues/issue-56685.stderr new file mode 100644 index 0000000000000..02b2d41d235ce --- /dev/null +++ b/src/test/ui/issues/issue-56685.stderr @@ -0,0 +1,60 @@ +error: unused variable: `x` + --> $DIR/issue-56685.rs:14:14 + | +LL | E::A(x) | E::B(x) => {} + | ^ ^ + | +note: lint level defined here + --> $DIR/issue-56685.rs:2:9 + | +LL | #![deny(unused_variables)] + | ^^^^^^^^^^^^^^^^ +help: consider prefixing with an underscore + | +LL | E::A(_x) | E::B(_x) => {} + | ^^ ^^ + +error: unused variable: `x` + --> $DIR/issue-56685.rs:25:14 + | +LL | F::A(x, y) | F::B(x, y) => { y }, + | ^ ^ +help: consider prefixing with an underscore + | +LL | F::A(_x, y) | F::B(_x, y) => { y }, + | ^^ ^^ + +error: unused variable: `b` + --> $DIR/issue-56685.rs:27:17 + | +LL | F::C(a, b) => { 3 } + | ^ help: consider prefixing with an underscore: `_b` + +error: unused variable: `a` + --> $DIR/issue-56685.rs:27:14 + | +LL | F::C(a, b) => { 3 } + | ^ help: consider prefixing with an underscore: `_a` + +error: unused variable: `x` + --> $DIR/issue-56685.rs:32:25 + | +LL | let _ = if let F::A(x, y) | F::B(x, y) = F::A(1, 2) { + | ^ ^ +help: consider prefixing with an underscore + | +LL | let _ = if let F::A(_x, y) | F::B(_x, y) = F::A(1, 2) { + | ^^ ^^ + +error: unused variable: `x` + --> $DIR/issue-56685.rs:39:20 + | +LL | while let F::A(x, y) | F::B(x, y) = F::A(1, 2) { + | ^ ^ +help: consider prefixing with an underscore + | +LL | while let F::A(_x, y) | F::B(_x, y) = F::A(1, 2) { + | ^^ ^^ + +error: aborting due to 6 previous errors + diff --git a/src/test/ui/lint/issue-47390-unused-variable-in-struct-pattern.stderr b/src/test/ui/lint/issue-47390-unused-variable-in-struct-pattern.stderr index ab12aef2474f3..8fd98e0a3db2e 100644 --- a/src/test/ui/lint/issue-47390-unused-variable-in-struct-pattern.stderr +++ b/src/test/ui/lint/issue-47390-unused-variable-in-struct-pattern.stderr @@ -2,7 +2,7 @@ warning: unused variable: `i_think_continually` --> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:26:9 | LL | let i_think_continually = 2; - | ^^^^^^^^^^^^^^^^^^^ help: consider using `_i_think_continually` instead + | ^^^^^^^^^^^^^^^^^^^ help: consider prefixing with an underscore: `_i_think_continually` | note: lint level defined here --> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:5:9 @@ -15,19 +15,19 @@ warning: unused variable: `mut_unused_var` --> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:33:13 | LL | let mut mut_unused_var = 1; - | ^^^^^^^^^^^^^^ help: consider using `_mut_unused_var` instead + | ^^^^^^^^^^^^^^ help: consider prefixing with an underscore: `_mut_unused_var` warning: unused variable: `var` --> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:35:14 | LL | let (mut var, unused_var) = (1, 2); - | ^^^ help: consider using `_var` instead + | ^^^ help: consider prefixing with an underscore: `_var` warning: unused variable: `unused_var` --> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:35:19 | LL | let (mut var, unused_var) = (1, 2); - | ^^^^^^^^^^ help: consider using `_unused_var` instead + | ^^^^^^^^^^ 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 diff --git a/src/test/ui/lint/lint-removed-allow.stderr b/src/test/ui/lint/lint-removed-allow.stderr index 3af983165eb17..f796a14d63796 100644 --- a/src/test/ui/lint/lint-removed-allow.stderr +++ b/src/test/ui/lint/lint-removed-allow.stderr @@ -2,7 +2,7 @@ error: unused variable: `unused` --> $DIR/lint-removed-allow.rs:8:17 | LL | fn main() { let unused = (); } //~ ERROR unused - | ^^^^^^ help: consider using `_unused` instead + | ^^^^^^ help: consider prefixing with an underscore: `_unused` | note: lint level defined here --> $DIR/lint-removed-allow.rs:7:8 diff --git a/src/test/ui/lint/lint-removed-cmdline.stderr b/src/test/ui/lint/lint-removed-cmdline.stderr index 191509c5a180c..d46ef6b9237fd 100644 --- a/src/test/ui/lint/lint-removed-cmdline.stderr +++ b/src/test/ui/lint/lint-removed-cmdline.stderr @@ -6,7 +6,7 @@ error: unused variable: `unused` --> $DIR/lint-removed-cmdline.rs:12:17 | LL | fn main() { let unused = (); } - | ^^^^^^ help: consider using `_unused` instead + | ^^^^^^ help: consider prefixing with an underscore: `_unused` | note: lint level defined here --> $DIR/lint-removed-cmdline.rs:11:8 diff --git a/src/test/ui/lint/lint-removed.stderr b/src/test/ui/lint/lint-removed.stderr index 34fa85b0d8b9f..55f010348fe1e 100644 --- a/src/test/ui/lint/lint-removed.stderr +++ b/src/test/ui/lint/lint-removed.stderr @@ -10,7 +10,7 @@ error: unused variable: `unused` --> $DIR/lint-removed.rs:8:17 | LL | fn main() { let unused = (); } //~ ERROR unused - | ^^^^^^ help: consider using `_unused` instead + | ^^^^^^ help: consider prefixing with an underscore: `_unused` | note: lint level defined here --> $DIR/lint-removed.rs:7:8 diff --git a/src/test/ui/lint/lint-renamed-allow.stderr b/src/test/ui/lint/lint-renamed-allow.stderr index 390b4c3f38abd..b2eeeae8f8e6d 100644 --- a/src/test/ui/lint/lint-renamed-allow.stderr +++ b/src/test/ui/lint/lint-renamed-allow.stderr @@ -2,7 +2,7 @@ error: unused variable: `unused` --> $DIR/lint-renamed-allow.rs:8:17 | LL | fn main() { let unused = (); } //~ ERROR unused - | ^^^^^^ help: consider using `_unused` instead + | ^^^^^^ help: consider prefixing with an underscore: `_unused` | note: lint level defined here --> $DIR/lint-renamed-allow.rs:7:8 diff --git a/src/test/ui/lint/lint-renamed-cmdline.stderr b/src/test/ui/lint/lint-renamed-cmdline.stderr index 78a05bdc89f01..6247ee0aff833 100644 --- a/src/test/ui/lint/lint-renamed-cmdline.stderr +++ b/src/test/ui/lint/lint-renamed-cmdline.stderr @@ -6,7 +6,7 @@ error: unused variable: `unused` --> $DIR/lint-renamed-cmdline.rs:8:17 | LL | fn main() { let unused = (); } - | ^^^^^^ help: consider using `_unused` instead + | ^^^^^^ help: consider prefixing with an underscore: `_unused` | note: lint level defined here --> $DIR/lint-renamed-cmdline.rs:7:8 diff --git a/src/test/ui/lint/lint-renamed.stderr b/src/test/ui/lint/lint-renamed.stderr index 1296fef5a4c63..b140a93ab38bd 100644 --- a/src/test/ui/lint/lint-renamed.stderr +++ b/src/test/ui/lint/lint-renamed.stderr @@ -10,7 +10,7 @@ error: unused variable: `unused` --> $DIR/lint-renamed.rs:4:17 | LL | fn main() { let unused = (); } //~ ERROR unused - | ^^^^^^ help: consider using `_unused` instead + | ^^^^^^ help: consider prefixing with an underscore: `_unused` | note: lint level defined here --> $DIR/lint-renamed.rs:3:8 diff --git a/src/test/ui/lint/lint-uppercase-variables.stderr b/src/test/ui/lint/lint-uppercase-variables.stderr index 0741179c4a4dd..f2267f351ddda 100644 --- a/src/test/ui/lint/lint-uppercase-variables.stderr +++ b/src/test/ui/lint/lint-uppercase-variables.stderr @@ -8,7 +8,7 @@ warning: unused variable: `Foo` --> $DIR/lint-uppercase-variables.rs:22:9 | LL | Foo => {} - | ^^^ help: consider using `_Foo` instead + | ^^^ help: consider prefixing with an underscore: `_Foo` | note: lint level defined here --> $DIR/lint-uppercase-variables.rs:1:9 diff --git a/src/test/ui/liveness/liveness-unused.stderr b/src/test/ui/liveness/liveness-unused.stderr index 17cdacb859f02..49795faa59c8d 100644 --- a/src/test/ui/liveness/liveness-unused.stderr +++ b/src/test/ui/liveness/liveness-unused.stderr @@ -15,7 +15,7 @@ error: unused variable: `x` --> $DIR/liveness-unused.rs:8:7 | LL | fn f1(x: isize) { - | ^ help: consider using `_x` instead + | ^ help: consider prefixing with an underscore: `_x` | note: lint level defined here --> $DIR/liveness-unused.rs:2:9 @@ -27,19 +27,19 @@ error: unused variable: `x` --> $DIR/liveness-unused.rs:12:8 | LL | fn f1b(x: &mut isize) { - | ^ help: consider using `_x` instead + | ^ help: consider prefixing with an underscore: `_x` error: unused variable: `x` --> $DIR/liveness-unused.rs:20:9 | LL | let x: isize; - | ^ help: consider using `_x` instead + | ^ help: consider prefixing with an underscore: `_x` error: unused variable: `x` --> $DIR/liveness-unused.rs:25:9 | LL | let x = 3; - | ^ help: consider using `_x` instead + | ^ help: consider prefixing with an underscore: `_x` error: variable `x` is assigned to, but never used --> $DIR/liveness-unused.rs:30:13 @@ -74,25 +74,25 @@ error: unused variable: `i` --> $DIR/liveness-unused.rs:59:12 | LL | Some(i) => { - | ^ help: consider using `_i` instead + | ^ help: consider prefixing with an underscore: `_i` error: unused variable: `x` --> $DIR/liveness-unused.rs:79:9 | LL | for x in 1..10 { } - | ^ help: consider using `_x` instead + | ^ help: consider prefixing with an underscore: `_x` error: unused variable: `x` --> $DIR/liveness-unused.rs:84:10 | LL | for (x, _) in [1, 2, 3].iter().enumerate() { } - | ^ help: consider using `_x` instead + | ^ help: consider prefixing with an underscore: `_x` error: unused variable: `x` --> $DIR/liveness-unused.rs:89:13 | LL | for (_, x) in [1, 2, 3].iter().enumerate() { - | ^ help: consider using `_x` instead + | ^ help: consider prefixing with an underscore: `_x` error: variable `x` is assigned to, but never used --> $DIR/liveness-unused.rs:112:9 diff --git a/src/test/ui/never-assign-dead-code.stderr b/src/test/ui/never-assign-dead-code.stderr index c59fd938e8326..bcc20a0d703c0 100644 --- a/src/test/ui/never-assign-dead-code.stderr +++ b/src/test/ui/never-assign-dead-code.stderr @@ -21,7 +21,7 @@ warning: unused variable: `x` --> $DIR/never-assign-dead-code.rs:9:9 | LL | let x: ! = panic!("aah"); //~ WARN unused - | ^ help: consider using `_x` instead + | ^ help: consider prefixing with an underscore: `_x` | note: lint level defined here --> $DIR/never-assign-dead-code.rs:5:9 diff --git a/src/test/ui/proc-macro/attributes-included.stderr b/src/test/ui/proc-macro/attributes-included.stderr index ea5be5a3be0e5..87b6fb9539fb4 100644 --- a/src/test/ui/proc-macro/attributes-included.stderr +++ b/src/test/ui/proc-macro/attributes-included.stderr @@ -2,7 +2,7 @@ warning: unused variable: `a` --> $DIR/attributes-included.rs:17:9 | LL | let a: i32 = "foo"; //~ WARN: unused variable - | ^ help: consider using `_a` instead + | ^ help: consider prefixing with an underscore: `_a` | note: lint level defined here --> $DIR/attributes-included.rs:4:9 diff --git a/src/test/ui/span/issue-24690.stderr b/src/test/ui/span/issue-24690.stderr index f052f866c901b..964e323b83ed4 100644 --- a/src/test/ui/span/issue-24690.stderr +++ b/src/test/ui/span/issue-24690.stderr @@ -2,7 +2,7 @@ warning: unused variable: `theOtherTwo` --> $DIR/issue-24690.rs:13:9 | LL | let theOtherTwo = 2; //~ WARN should have a snake case name - | ^^^^^^^^^^^ help: consider using `_theOtherTwo` instead + | ^^^^^^^^^^^ help: consider prefixing with an underscore: `_theOtherTwo` | note: lint level defined here --> $DIR/issue-24690.rs:8:9