diff --git a/src/ci/scripts/install-msys2.sh b/src/ci/scripts/install-msys2.sh index 3a78ef209e4e5..9e899ba9d8947 100755 --- a/src/ci/scripts/install-msys2.sh +++ b/src/ci/scripts/install-msys2.sh @@ -12,10 +12,14 @@ IFS=$'\n\t' source "$(cd "$(dirname "$0")" && pwd)/../shared.sh" if isWindows; then - for RETRY_COUNT in 1 2 3 4 5 6 7 8 9 10; do - choco install msys2 \ - --params="/InstallDir:$(ciCheckoutPath)/msys2 /NoPath" -y --no-progress \ - && mkdir -p "$(ciCheckoutPath)/msys2/home/${USERNAME}" \ - && ciCommandAddPath "$(ciCheckoutPath)/msys2/usr/bin" && break - done + # Pre-followed the api/v2 URL to the CDN since the API can be a bit flakey + curl -sSL https://packages.chocolatey.org/msys2.20190524.0.0.20191030.nupkg > \ + msys2.nupkg + curl -sSL https://packages.chocolatey.org/chocolatey-core.extension.1.3.5.1.nupkg > \ + chocolatey-core.extension.nupkg + choco install -s . msys2 \ + --params="/InstallDir:$(ciCheckoutPath)/msys2 /NoPath" -y --no-progress + rm msys2.nupkg chocolatey-core.extension.nupkg + mkdir -p "$(ciCheckoutPath)/msys2/home/${USERNAME}" + ciCommandAddPath "$(ciCheckoutPath)/msys2/usr/bin" fi diff --git a/src/libcore/char/methods.rs b/src/libcore/char/methods.rs index bb6d6db57d214..fe5d16862a6a6 100644 --- a/src/libcore/char/methods.rs +++ b/src/libcore/char/methods.rs @@ -434,36 +434,35 @@ impl char { #[inline] pub fn encode_utf8(self, dst: &mut [u8]) -> &mut str { let code = self as u32; - // SAFETY: each arm checks the size of the slice and only uses `get_unchecked` unsafe ops - unsafe { - let len = if code < MAX_ONE_B && !dst.is_empty() { - *dst.get_unchecked_mut(0) = code as u8; - 1 - } else if code < MAX_TWO_B && dst.len() >= 2 { - *dst.get_unchecked_mut(0) = (code >> 6 & 0x1F) as u8 | TAG_TWO_B; - *dst.get_unchecked_mut(1) = (code & 0x3F) as u8 | TAG_CONT; - 2 - } else if code < MAX_THREE_B && dst.len() >= 3 { - *dst.get_unchecked_mut(0) = (code >> 12 & 0x0F) as u8 | TAG_THREE_B; - *dst.get_unchecked_mut(1) = (code >> 6 & 0x3F) as u8 | TAG_CONT; - *dst.get_unchecked_mut(2) = (code & 0x3F) as u8 | TAG_CONT; - 3 - } else if dst.len() >= 4 { - *dst.get_unchecked_mut(0) = (code >> 18 & 0x07) as u8 | TAG_FOUR_B; - *dst.get_unchecked_mut(1) = (code >> 12 & 0x3F) as u8 | TAG_CONT; - *dst.get_unchecked_mut(2) = (code >> 6 & 0x3F) as u8 | TAG_CONT; - *dst.get_unchecked_mut(3) = (code & 0x3F) as u8 | TAG_CONT; - 4 - } else { - panic!( - "encode_utf8: need {} bytes to encode U+{:X}, but the buffer has {}", - from_u32_unchecked(code).len_utf8(), - code, - dst.len(), - ) - }; - from_utf8_unchecked_mut(dst.get_unchecked_mut(..len)) - } + let len = self.len_utf8(); + match (len, &mut dst[..]) { + (1, [a, ..]) => { + *a = code as u8; + } + (2, [a, b, ..]) => { + *a = (code >> 6 & 0x1F) as u8 | TAG_TWO_B; + *b = (code & 0x3F) as u8 | TAG_CONT; + } + (3, [a, b, c, ..]) => { + *a = (code >> 12 & 0x0F) as u8 | TAG_THREE_B; + *b = (code >> 6 & 0x3F) as u8 | TAG_CONT; + *c = (code & 0x3F) as u8 | TAG_CONT; + } + (4, [a, b, c, d, ..]) => { + *a = (code >> 18 & 0x07) as u8 | TAG_FOUR_B; + *b = (code >> 12 & 0x3F) as u8 | TAG_CONT; + *c = (code >> 6 & 0x3F) as u8 | TAG_CONT; + *d = (code & 0x3F) as u8 | TAG_CONT; + } + _ => panic!( + "encode_utf8: need {} bytes to encode U+{:X}, but the buffer has {}", + len, + code, + dst.len(), + ), + }; + // SAFETY: We just wrote UTF-8 content in, so converting to str is fine. + unsafe { from_utf8_unchecked_mut(&mut dst[..len]) } } /// Encodes this character as UTF-16 into the provided `u16` buffer, diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index d12aebb87b975..7d11dd2800fd4 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -129,6 +129,7 @@ #![feature(associated_type_bounds)] #![feature(const_type_id)] #![feature(const_caller_location)] +#![feature(slice_patterns)] #[prelude_import] #[allow(unused)] diff --git a/src/librustc/mir/interpret/error.rs b/src/librustc/mir/interpret/error.rs index 843880200f3d7..51f0818fe0be1 100644 --- a/src/librustc/mir/interpret/error.rs +++ b/src/librustc/mir/interpret/error.rs @@ -432,6 +432,7 @@ pub enum UnsupportedOpInfo<'tcx> { HeapAllocNonPowerOfTwoAlignment(u64), ReadFromReturnPointer, PathNotFound(Vec), + TransmuteSizeDiff(Ty<'tcx>, Ty<'tcx>), } impl fmt::Debug for UnsupportedOpInfo<'tcx> { @@ -460,6 +461,11 @@ impl fmt::Debug for UnsupportedOpInfo<'tcx> { passing data of type {:?}", callee_ty, caller_ty ), + TransmuteSizeDiff(from_ty, to_ty) => write!( + f, + "tried to transmute from {:?} to {:?}, but their sizes differed", + from_ty, to_ty + ), FunctionRetMismatch(caller_ty, callee_ty) => write!( f, "tried to call a function with return type {:?} \ diff --git a/src/librustc/mir/interpret/value.rs b/src/librustc/mir/interpret/value.rs index 49b542af0a034..93f167cdb9e54 100644 --- a/src/librustc/mir/interpret/value.rs +++ b/src/librustc/mir/interpret/value.rs @@ -367,8 +367,9 @@ impl<'tcx, Tag> Scalar { } /// Do not call this method! Use either `assert_ptr` or `force_ptr`. + /// This method is intentionally private, do not make it public. #[inline] - pub fn to_ptr(self) -> InterpResult<'tcx, Pointer> { + fn to_ptr(self) -> InterpResult<'tcx, Pointer> { match self { Scalar::Raw { data: 0, .. } => throw_unsup!(InvalidNullPointerUsage), Scalar::Raw { .. } => throw_unsup!(ReadBytesAsPointer), @@ -544,12 +545,6 @@ impl<'tcx, Tag> ScalarMaybeUndef { } } - /// Do not call this method! Use either `assert_ptr` or `force_ptr`. - #[inline(always)] - pub fn to_ptr(self) -> InterpResult<'tcx, Pointer> { - self.not_undef()?.to_ptr() - } - /// Do not call this method! Use either `assert_bits` or `force_bits`. #[inline(always)] pub fn to_bits(self, target_size: Size) -> InterpResult<'tcx, u128> { diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 2ac2d789b2d34..42db64c791518 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -2373,7 +2373,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { let span = self.tcx.def_span(generator_did); // Do not ICE on closure typeck (#66868). - if let None = self.tcx.hir().as_local_hir_id(generator_did) { + if self.tcx.hir().as_local_hir_id(generator_did).is_none() { return false; } diff --git a/src/librustc/ty/relate.rs b/src/librustc/ty/relate.rs index 933358dce018b..120f05ba7d974 100644 --- a/src/librustc/ty/relate.rs +++ b/src/librustc/ty/relate.rs @@ -537,8 +537,8 @@ pub fn super_relate_consts>( Ok(ConstValue::Scalar(a_val)) } else if let ty::FnPtr(_) = a.ty.kind { let alloc_map = tcx.alloc_map.lock(); - let a_instance = alloc_map.unwrap_fn(a_val.to_ptr().unwrap().alloc_id); - let b_instance = alloc_map.unwrap_fn(b_val.to_ptr().unwrap().alloc_id); + let a_instance = alloc_map.unwrap_fn(a_val.assert_ptr().alloc_id); + let b_instance = alloc_map.unwrap_fn(b_val.assert_ptr().alloc_id); if a_instance == b_instance { Ok(ConstValue::Scalar(a_val)) } else { diff --git a/src/librustc_error_codes/error_codes.rs b/src/librustc_error_codes/error_codes.rs index 9c1bec39b29e2..fbcc976bd491e 100644 --- a/src/librustc_error_codes/error_codes.rs +++ b/src/librustc_error_codes/error_codes.rs @@ -346,6 +346,7 @@ E0622: include_str!("./error_codes/E0622.md"), E0623: include_str!("./error_codes/E0623.md"), E0624: include_str!("./error_codes/E0624.md"), E0626: include_str!("./error_codes/E0626.md"), +E0627: include_str!("./error_codes/E0627.md"), E0631: include_str!("./error_codes/E0631.md"), E0633: include_str!("./error_codes/E0633.md"), E0635: include_str!("./error_codes/E0635.md"), @@ -574,7 +575,6 @@ E0745: include_str!("./error_codes/E0745.md"), // E0612, // merged into E0609 // E0613, // Removed (merged with E0609) E0625, // thread-local statics cannot be accessed at compile-time - E0627, // yield statement outside of generator literal E0628, // generators cannot have explicit parameters E0629, // missing 'feature' (rustc_const_unstable) // rustc_const_unstable attribute must be paired with stable/unstable diff --git a/src/librustc_error_codes/error_codes/E0124.md b/src/librustc_error_codes/error_codes/E0124.md index a7836526a7dd4..8af7cb819cfaf 100644 --- a/src/librustc_error_codes/error_codes/E0124.md +++ b/src/librustc_error_codes/error_codes/E0124.md @@ -1,5 +1,6 @@ -You declared two fields of a struct with the same name. Erroneous code -example: +A struct was declared with two fields having the same name. + +Erroneous code example: ```compile_fail,E0124 struct Foo { diff --git a/src/librustc_error_codes/error_codes/E0128.md b/src/librustc_error_codes/error_codes/E0128.md index d0a4b32f9688e..6f8dfe3a73b9e 100644 --- a/src/librustc_error_codes/error_codes/E0128.md +++ b/src/librustc_error_codes/error_codes/E0128.md @@ -1,4 +1,5 @@ -Type parameter defaults can only use parameters that occur before them. +A type parameter with default value is using forward declared identifier. + Erroneous code example: ```compile_fail,E0128 @@ -7,11 +8,11 @@ struct Foo { field2: U, } // error: type parameters with a default cannot use forward declared -// identifiers +// identifiers ``` -Since type parameters are evaluated in-order, you may be able to fix this issue -by doing: +Type parameter defaults can only use parameters that occur before them. Since +type parameters are evaluated in-order, this issue could be fixed by doing: ``` struct Foo { diff --git a/src/librustc_error_codes/error_codes/E0627.md b/src/librustc_error_codes/error_codes/E0627.md new file mode 100644 index 0000000000000..21358e1e567dc --- /dev/null +++ b/src/librustc_error_codes/error_codes/E0627.md @@ -0,0 +1,30 @@ +A yield expression was used outside of the generator literal. + +Erroneous code example: + +```compile_fail,E0627 +#![feature(generators, generator_trait)] + +fn fake_generator() -> &'static str { + yield 1; + return "foo" +} + +fn main() { + let mut generator = fake_generator; +} +``` + +The error occurs because keyword `yield` can only be used inside the generator +literal. This can be fixed by constructing the generator correctly. + +``` +#![feature(generators, generator_trait)] + +fn main() { + let mut generator = || { + yield 1; + return "foo" + }; +} +``` diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index 4a6379e3bc155..0d136bd7d9cf9 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -1424,7 +1424,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } /// Reports an error if this is a borrow of local data. - /// This is called for all Yield statements on movable generators + /// This is called for all Yield expressions on movable generators fn check_for_local_borrow(&mut self, borrow: &BorrowData<'tcx>, yield_span: Span) { debug!("check_for_local_borrow({:?})", borrow); diff --git a/src/librustc_mir/borrow_check/path_utils.rs b/src/librustc_mir/borrow_check/path_utils.rs index ea541bd93bc94..23b4799643a6c 100644 --- a/src/librustc_mir/borrow_check/path_utils.rs +++ b/src/librustc_mir/borrow_check/path_utils.rs @@ -131,7 +131,7 @@ pub(super) fn is_active<'tcx>( } /// Determines if a given borrow is borrowing local data -/// This is called for all Yield statements on movable generators +/// This is called for all Yield expressions on movable generators pub(super) fn borrow_of_local_data(place: &Place<'_>) -> bool { match place.base { PlaceBase::Static(_) => false, diff --git a/src/librustc_mir/const_eval.rs b/src/librustc_mir/const_eval.rs index a2f066bee08d1..2afa39c3cad8b 100644 --- a/src/librustc_mir/const_eval.rs +++ b/src/librustc_mir/const_eval.rs @@ -85,7 +85,7 @@ fn op_to_const<'tcx>( }; let val = match immediate { Ok(mplace) => { - let ptr = mplace.ptr.to_ptr().unwrap(); + let ptr = mplace.ptr.assert_ptr(); let alloc = ecx.tcx.alloc_map.lock().unwrap_memory(ptr.alloc_id); ConstValue::ByRef { alloc, offset: ptr.offset } }, @@ -99,7 +99,7 @@ fn op_to_const<'tcx>( // comes from a constant so it can happen have `Undef`, because the indirect // memory that was read had undefined bytes. let mplace = op.assert_mem_place(); - let ptr = mplace.ptr.to_ptr().unwrap(); + let ptr = mplace.ptr.assert_ptr(); let alloc = ecx.tcx.alloc_map.lock().unwrap_memory(ptr.alloc_id); ConstValue::ByRef { alloc, offset: ptr.offset } }, @@ -626,7 +626,7 @@ fn validate_and_turn_into_const<'tcx>( // whether they become immediates. let def_id = cid.instance.def.def_id(); if tcx.is_static(def_id) || cid.promoted.is_some() { - let ptr = mplace.ptr.to_ptr()?; + let ptr = mplace.ptr.assert_ptr(); Ok(tcx.mk_const(ty::Const { val: ty::ConstKind::Value(ConstValue::ByRef { alloc: ecx.tcx.alloc_map.lock().unwrap_memory(ptr.alloc_id), diff --git a/src/librustc_mir/hair/pattern/_match.rs b/src/librustc_mir/hair/pattern/_match.rs index f267be812c3d2..c6efbe8833279 100644 --- a/src/librustc_mir/hair/pattern/_match.rs +++ b/src/librustc_mir/hair/pattern/_match.rs @@ -252,6 +252,7 @@ use syntax_pos::{Span, DUMMY_SP}; use arena::TypedArena; use smallvec::{smallvec, SmallVec}; +use std::borrow::Cow; use std::cmp::{self, max, min, Ordering}; use std::convert::TryInto; use std::fmt; @@ -260,11 +261,12 @@ use std::ops::RangeInclusive; use std::u128; pub fn expand_pattern<'a, 'tcx>(cx: &MatchCheckCtxt<'a, 'tcx>, pat: Pat<'tcx>) -> Pat<'tcx> { - LiteralExpander { tcx: cx.tcx }.fold_pattern(&pat) + LiteralExpander { tcx: cx.tcx, param_env: cx.param_env }.fold_pattern(&pat) } struct LiteralExpander<'tcx> { tcx: TyCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, } impl LiteralExpander<'tcx> { @@ -284,9 +286,23 @@ impl LiteralExpander<'tcx> { debug!("fold_const_value_deref {:?} {:?} {:?}", val, rty, crty); match (val, &crty.kind, &rty.kind) { // the easy case, deref a reference - (ConstValue::Scalar(Scalar::Ptr(p)), x, y) if x == y => { - let alloc = self.tcx.alloc_map.lock().unwrap_memory(p.alloc_id); - ConstValue::ByRef { alloc, offset: p.offset } + (ConstValue::Scalar(p), x, y) if x == y => { + match p { + Scalar::Ptr(p) => { + let alloc = self.tcx.alloc_map.lock().unwrap_memory(p.alloc_id); + ConstValue::ByRef { alloc, offset: p.offset } + } + Scalar::Raw { .. } => { + let layout = self.tcx.layout_of(self.param_env.and(rty)).unwrap(); + if layout.is_zst() { + // Deref of a reference to a ZST is a nop. + ConstValue::Scalar(Scalar::zst()) + } else { + // FIXME(oli-obk): this is reachable for `const FOO: &&&u32 = &&&42;` + bug!("cannot deref {:#?}, {} -> {}", val, crty, rty); + } + } + } } // unsize array to slice if pattern is array but match value or other patterns are slice (ConstValue::Scalar(Scalar::Ptr(p)), ty::Array(t, n), ty::Slice(u)) => { @@ -2348,16 +2364,30 @@ fn specialize_one_pattern<'p, 'tcx>( // just integers. The only time they should be pointing to memory // is when they are subslices of nonzero slices. let (alloc, offset, n, ty) = match value.ty.kind { - ty::Array(t, n) => match value.val { - ty::ConstKind::Value(ConstValue::ByRef { offset, alloc, .. }) => { - (alloc, offset, n.eval_usize(cx.tcx, cx.param_env), t) + ty::Array(t, n) => { + let n = n.eval_usize(cx.tcx, cx.param_env); + // Shortcut for `n == 0` where no matter what `alloc` and `offset` we produce, + // the result would be exactly what we early return here. + if n == 0 { + if ctor_wild_subpatterns.len() as u64 == 0 { + return Some(PatStack::from_slice(&[])); + } else { + return None; + } } - _ => span_bug!(pat.span, "array pattern is {:?}", value,), - }, + match value.val { + ty::ConstKind::Value(ConstValue::ByRef { offset, alloc, .. }) => { + (Cow::Borrowed(alloc), offset, n, t) + } + _ => span_bug!(pat.span, "array pattern is {:?}", value,), + } + } ty::Slice(t) => { match value.val { ty::ConstKind::Value(ConstValue::Slice { data, start, end }) => { - (data, Size::from_bytes(start as u64), (end - start) as u64, t) + let offset = Size::from_bytes(start as u64); + let n = (end - start) as u64; + (Cow::Borrowed(data), offset, n, t) } ty::ConstKind::Value(ConstValue::ByRef { .. }) => { // FIXME(oli-obk): implement `deref` for `ConstValue` diff --git a/src/librustc_mir/hair/pattern/mod.rs b/src/librustc_mir/hair/pattern/mod.rs index 869aeeba418da..a68ee3308bc23 100644 --- a/src/librustc_mir/hair/pattern/mod.rs +++ b/src/librustc_mir/hair/pattern/mod.rs @@ -993,6 +993,12 @@ pub fn compare_const_vals<'tcx>( return fallback(); } + // Early return for equal constants (so e.g. references to ZSTs can be compared, even if they + // are just integer addresses). + if a.val == b.val { + return from_bool(true); + } + let a_bits = a.try_eval_bits(tcx, param_env, ty); let b_bits = b.try_eval_bits(tcx, param_env, ty); diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index ad2af8d7aca52..766ef6ab6feac 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -20,8 +20,8 @@ use rustc_macros::HashStable; use syntax::source_map::{self, Span, DUMMY_SP}; use super::{ - Immediate, MPlaceTy, Machine, MemPlace, Memory, Operand, Place, PlaceTy, ScalarMaybeUndef, - StackPopInfo, + Immediate, MPlaceTy, Machine, MemPlace, Memory, OpTy, Operand, Place, PlaceTy, + ScalarMaybeUndef, StackPopInfo, }; pub struct InterpCx<'mir, 'tcx, M: Machine<'mir, 'tcx>> { @@ -118,7 +118,7 @@ pub struct LocalState<'tcx, Tag = (), Id = AllocId> { } /// Current value of a local variable -#[derive(Clone, PartialEq, Eq, Debug, HashStable)] // Miri debug-prints these +#[derive(Copy, Clone, PartialEq, Eq, Debug, HashStable)] // Miri debug-prints these pub enum LocalValue { /// This local is not currently alive, and cannot be used at all. Dead, @@ -743,7 +743,9 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // FIXME: should we tell the user that there was a local which was never written to? if let LocalValue::Live(Operand::Indirect(MemPlace { ptr, .. })) = local { trace!("deallocating local"); - let ptr = ptr.to_ptr()?; + // All locals have a backing allocation, even if the allocation is empty + // due to the local having ZST type. + let ptr = ptr.assert_ptr(); if log_enabled!(::log::Level::Trace) { self.memory.dump_alloc(ptr.alloc_id); } @@ -752,13 +754,33 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Ok(()) } + pub(super) fn const_eval( + &self, + gid: GlobalId<'tcx>, + ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { + let val = if self.tcx.is_static(gid.instance.def_id()) { + self.tcx.const_eval_poly(gid.instance.def_id())? + } else if let Some(promoted) = gid.promoted { + self.tcx.const_eval_promoted(gid.instance, promoted)? + } else { + self.tcx.const_eval_instance(self.param_env, gid.instance, Some(self.tcx.span))? + }; + // Even though `ecx.const_eval` is called from `eval_const_to_op` we can never have a + // recursion deeper than one level, because the `tcx.const_eval` above is guaranteed to not + // return `ConstValue::Unevaluated`, which is the only way that `eval_const_to_op` will call + // `ecx.const_eval`. + self.eval_const_to_op(val, None) + } + pub fn const_eval_raw( &self, gid: GlobalId<'tcx>, ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> { - // FIXME(oli-obk): make this check an assertion that it's not a static here - // FIXME(RalfJ, oli-obk): document that `Place::Static` can never be anything but a static - // and `ConstValue::Unevaluated` can never be a static + // For statics we pick `ParamEnv::reveal_all`, because statics don't have generics + // and thus don't care about the parameter environment. While we could just use + // `self.param_env`, that would mean we invoke the query to evaluate the static + // with different parameter environments, thus causing the static to be evaluated + // multiple times. let param_env = if self.tcx.is_static(gid.instance.def_id()) { ty::ParamEnv::reveal_all() } else { diff --git a/src/librustc_mir/interpret/intern.rs b/src/librustc_mir/interpret/intern.rs index c99f39977fe2e..9dbe685813ef2 100644 --- a/src/librustc_mir/interpret/intern.rs +++ b/src/librustc_mir/interpret/intern.rs @@ -188,14 +188,21 @@ impl<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx if let ty::Ref(_, referenced_ty, mutability) = ty.kind { let value = self.ecx.read_immediate(mplace.into())?; let mplace = self.ecx.ref_to_mplace(value)?; - // Handle trait object vtables + // Handle trait object vtables. if let ty::Dynamic(..) = self.ecx.tcx.struct_tail_erasing_lifetimes(referenced_ty, self.ecx.param_env).kind { - if let Ok(vtable) = mplace.meta.unwrap().to_ptr() { - // explitly choose `Immutable` here, since vtables are immutable, even - // if the reference of the fat pointer is mutable + // Validation has already errored on an invalid vtable pointer so we can safely not + // do anything if this is not a real pointer. + if let Scalar::Ptr(vtable) = mplace.meta.unwrap() { + // Explicitly choose `Immutable` here, since vtables are immutable, even + // if the reference of the fat pointer is mutable. self.intern_shallow(vtable.alloc_id, Mutability::Not, None)?; + } else { + self.ecx().tcx.sess.delay_span_bug( + syntax_pos::DUMMY_SP, + "vtables pointers cannot be integer pointers", + ); } } // Check if we have encountered this pointer+layout combination before. @@ -281,7 +288,9 @@ pub fn intern_const_alloc_recursive>( ecx, leftover_allocations, base_intern_mode, - ret.ptr.to_ptr()?.alloc_id, + // The outermost allocation must exist, because we allocated it with + // `Memory::allocate`. + ret.ptr.assert_ptr().alloc_id, base_mutability, Some(ret.layout.ty), )?; diff --git a/src/librustc_mir/interpret/intrinsics.rs b/src/librustc_mir/interpret/intrinsics.rs index 8e4dc87451c32..da7cff97ee2c2 100644 --- a/src/librustc_mir/interpret/intrinsics.rs +++ b/src/librustc_mir/interpret/intrinsics.rs @@ -5,7 +5,7 @@ use rustc::hir::def_id::DefId; use rustc::mir::{ self, - interpret::{ConstValue, InterpResult, Scalar}, + interpret::{ConstValue, GlobalId, InterpResult, Scalar}, BinOp, }; use rustc::ty; @@ -118,9 +118,8 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { | sym::size_of | sym::type_id | sym::type_name => { - let val = - self.tcx.const_eval_instance(self.param_env, instance, Some(self.tcx.span))?; - let val = self.eval_const_to_op(val, None)?; + let gid = GlobalId { instance, promoted: None }; + let val = self.const_eval(gid)?; self.copy_op(val, dest)?; } diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs index a89abe71c654f..def979b63b52a 100644 --- a/src/librustc_mir/interpret/operand.rs +++ b/src/librustc_mir/interpret/operand.rs @@ -578,7 +578,15 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { ty::ConstKind::Param(_) => throw_inval!(TooGeneric), ty::ConstKind::Unevaluated(def_id, substs) => { let instance = self.resolve(def_id, substs)?; - return Ok(OpTy::from(self.const_eval_raw(GlobalId { instance, promoted: None })?)); + // We use `const_eval` here and `const_eval_raw` elsewhere in mir interpretation. + // The reason we use `const_eval_raw` everywhere else is to prevent cycles during + // validation, because validation automatically reads through any references, thus + // potentially requiring the current static to be evaluated again. This is not a + // problem here, because we are building an operand which means an actual read is + // happening. + // FIXME(oli-obk): eliminate all the `const_eval_raw` usages when we get rid of + // `StaticKind` once and for all. + return self.const_eval(GlobalId { instance, promoted: None }); } ty::ConstKind::Infer(..) | ty::ConstKind::Bound(..) diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index 1141239e49a53..2c39799cb935a 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -942,8 +942,14 @@ where return self.copy_op(src, dest); } // We still require the sizes to match. - assert!(src.layout.size == dest.layout.size, - "Size mismatch when transmuting!\nsrc: {:#?}\ndest: {:#?}", src, dest); + if src.layout.size != dest.layout.size { + // FIXME: This should be an assert instead of an error, but if we transmute within an + // array length computation, `typeck` may not have yet been run and errored out. In fact + // most likey we *are* running `typeck` right now. Investigate whether we can bail out + // on `typeck_tables().has_errors` at all const eval entry points. + debug!("Size mismatch when transmuting!\nsrc: {:#?}\ndest: {:#?}", src, dest); + throw_unsup!(TransmuteSizeDiff(src.layout.ty, dest.layout.ty)); + } // Unsized copies rely on interpreting `src.meta` with `dest.layout`, we want // to avoid that here. assert!(!src.layout.is_unsized() && !dest.layout.is_unsized(), @@ -987,30 +993,20 @@ where let (mplace, size) = match place.place { Place::Local { frame, local } => { match self.stack[frame].locals[local].access_mut()? { - Ok(local_val) => { + Ok(&mut local_val) => { // We need to make an allocation. - // FIXME: Consider not doing anything for a ZST, and just returning - // a fake pointer? Are we even called for ZST? - - // We cannot hold on to the reference `local_val` while allocating, - // but we can hold on to the value in there. - let old_val = - if let LocalValue::Live(Operand::Immediate(value)) = *local_val { - Some(value) - } else { - None - }; // We need the layout of the local. We can NOT use the layout we got, // that might e.g., be an inner field of a struct with `Scalar` layout, // that has different alignment than the outer field. - // We also need to support unsized types, and hence cannot use `allocate`. let local_layout = self.layout_of_local(&self.stack[frame], local, None)?; + + // We also need to support unsized types, and hence cannot use `allocate`. let (size, align) = self.size_and_align_of(meta, local_layout)? .expect("Cannot allocate for non-dyn-sized type"); let ptr = self.memory.allocate(size, align, MemoryKind::Stack); let mplace = MemPlace { ptr: ptr.into(), align, meta }; - if let Some(value) = old_val { + if let LocalValue::Live(Operand::Immediate(value)) = local_val { // Preserve old value. // We don't have to validate as we can assume the local // was already valid for its type. diff --git a/src/librustc_typeck/check/expr.rs b/src/librustc_typeck/check/expr.rs index 5c602ad76cd32..e862971c9e2b3 100644 --- a/src/librustc_typeck/check/expr.rs +++ b/src/librustc_typeck/check/expr.rs @@ -1810,7 +1810,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.tcx.sess, expr.span, E0627, - "yield statement outside of generator literal" + "yield expression outside of generator literal" ) .emit(); } diff --git a/src/libstd/error.rs b/src/libstd/error.rs index 18ebd0f1a6755..0992e40121a7b 100644 --- a/src/libstd/error.rs +++ b/src/libstd/error.rs @@ -91,10 +91,6 @@ pub trait Error: Debug + Display { /// } /// /// impl Error for SuperError { - /// fn description(&self) -> &str { - /// "I'm the superhero of errors" - /// } - /// /// fn cause(&self) -> Option<&dyn Error> { /// Some(&self.side) /// } @@ -109,11 +105,7 @@ pub trait Error: Debug + Display { /// } /// } /// - /// impl Error for SuperErrorSideKick { - /// fn description(&self) -> &str { - /// "I'm SuperError side kick" - /// } - /// } + /// impl Error for SuperErrorSideKick {} /// /// fn get_super_error() -> Result<(), SuperError> { /// Err(SuperError { side: SuperErrorSideKick }) @@ -159,10 +151,6 @@ pub trait Error: Debug + Display { /// } /// /// impl Error for SuperError { - /// fn description(&self) -> &str { - /// "I'm the superhero of errors" - /// } - /// /// fn source(&self) -> Option<&(dyn Error + 'static)> { /// Some(&self.side) /// } @@ -177,11 +165,7 @@ pub trait Error: Debug + Display { /// } /// } /// - /// impl Error for SuperErrorSideKick { - /// fn description(&self) -> &str { - /// "I'm SuperError side kick" - /// } - /// } + /// impl Error for SuperErrorSideKick {} /// /// fn get_super_error() -> Result<(), SuperError> { /// Err(SuperError { side: SuperErrorSideKick }) @@ -261,11 +245,7 @@ impl<'a, E: Error + 'a> From for Box { /// } /// } /// - /// impl Error for AnError { - /// fn description(&self) -> &str { - /// "Description of an error" - /// } - /// } + /// impl Error for AnError {} /// /// let an_error = AnError; /// assert!(0 == mem::size_of_val(&an_error)); @@ -300,11 +280,7 @@ impl<'a, E: Error + Send + Sync + 'a> From for Box &str { - /// "Description of an error" - /// } - /// } + /// impl Error for AnError {} /// /// unsafe impl Send for AnError {} /// diff --git a/src/libstd/io/error.rs b/src/libstd/io/error.rs index c20bd3097b27d..efe839d1302fe 100644 --- a/src/libstd/io/error.rs +++ b/src/libstd/io/error.rs @@ -402,9 +402,7 @@ impl Error { /// } /// } /// - /// impl error::Error for MyError { - /// fn description(&self) -> &str { &self.v } - /// } + /// impl error::Error for MyError {} /// /// impl Display for MyError { /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { diff --git a/src/test/ui/const-generics/issues/issue-61747.rs b/src/test/ui/const-generics/issues/issue-61747.rs new file mode 100644 index 0000000000000..64674bb894e1f --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-61747.rs @@ -0,0 +1,16 @@ +// check-pass + +#![feature(const_generics)] +//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash + +struct Const; + +impl Const<{C}> { + fn successor() -> Const<{C + 1}> { + Const + } +} + +fn main() { + let _x: Const::<2> = Const::<1>::successor(); +} diff --git a/src/test/ui/const-generics/issues/issue-61747.stderr b/src/test/ui/const-generics/issues/issue-61747.stderr new file mode 100644 index 0000000000000..ccf36a7f805ec --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-61747.stderr @@ -0,0 +1,8 @@ +warning: the feature `const_generics` is incomplete and may cause the compiler to crash + --> $DIR/issue-61747.rs:3:12 + | +LL | #![feature(const_generics)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + diff --git a/src/test/ui/const-generics/issues/issue-66205.rs b/src/test/ui/const-generics/issues/issue-66205.rs new file mode 100644 index 0000000000000..2e47b4d1882f2 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-66205.rs @@ -0,0 +1,10 @@ +// check-pass + +#![allow(incomplete_features, dead_code, unconditional_recursion)] +#![feature(const_generics)] + +fn fact() { + fact::<{ N - 1 }>(); +} + +fn main() {} diff --git a/src/test/ui/consts/consts-in-patterns.rs b/src/test/ui/consts/consts-in-patterns.rs index ac6c5a5150688..ee1e3cc22f77d 100644 --- a/src/test/ui/consts/consts-in-patterns.rs +++ b/src/test/ui/consts/consts-in-patterns.rs @@ -1,7 +1,10 @@ // run-pass +#![feature(const_transmute)] const FOO: isize = 10; const BAR: isize = 3; +const ZST: &() = unsafe { std::mem::transmute(1usize) }; +const ZST_ARR: &[u8; 0] = unsafe { std::mem::transmute(1usize) }; const fn foo() -> isize { 4 } const BOO: isize = foo(); @@ -15,4 +18,14 @@ pub fn main() { _ => 3 }; assert_eq!(y, 2); + let z = match &() { + ZST => 9, + // FIXME: this should not be required + _ => 42, + }; + assert_eq!(z, 9); + let z = match b"" { + ZST_ARR => 10, + }; + assert_eq!(z, 10); } diff --git a/src/test/ui/consts/recursive-zst-static.rs b/src/test/ui/consts/recursive-zst-static.rs new file mode 100644 index 0000000000000..df7562bd9f5d2 --- /dev/null +++ b/src/test/ui/consts/recursive-zst-static.rs @@ -0,0 +1,7 @@ +// build-pass + +static FOO: () = FOO; + +fn main() { + FOO +} diff --git a/src/test/ui/consts/transmute-size-mismatch-before-typeck.rs b/src/test/ui/consts/transmute-size-mismatch-before-typeck.rs new file mode 100644 index 0000000000000..1235dd8dcbd98 --- /dev/null +++ b/src/test/ui/consts/transmute-size-mismatch-before-typeck.rs @@ -0,0 +1,15 @@ +#![feature(const_transmute)] + +fn main() { + match &b""[..] { + ZST => {} + //~^ ERROR could not evaluate constant pattern + } +} + +const ZST: &[u8] = unsafe { std::mem::transmute(1usize) }; +//~^ ERROR any use of this value will cause an error +//~| ERROR cannot transmute between types of different sizes + +// Once the `any use of this value will cause an error` disappears in this test, make sure to +// remove the `TransmuteSizeDiff` error variant and make its emitter site an assertion again. diff --git a/src/test/ui/consts/transmute-size-mismatch-before-typeck.stderr b/src/test/ui/consts/transmute-size-mismatch-before-typeck.stderr new file mode 100644 index 0000000000000..74de5dc9aaf82 --- /dev/null +++ b/src/test/ui/consts/transmute-size-mismatch-before-typeck.stderr @@ -0,0 +1,28 @@ +error: any use of this value will cause an error + --> $DIR/transmute-size-mismatch-before-typeck.rs:10:29 + | +LL | const ZST: &[u8] = unsafe { std::mem::transmute(1usize) }; + | ----------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^--- + | | + | tried to transmute from usize to &[u8], but their sizes differed + | + = note: `#[deny(const_err)]` on by default + +error: could not evaluate constant pattern + --> $DIR/transmute-size-mismatch-before-typeck.rs:5:9 + | +LL | ZST => {} + | ^^^ + +error[E0512]: cannot transmute between types of different sizes, or dependently-sized types + --> $DIR/transmute-size-mismatch-before-typeck.rs:10:29 + | +LL | const ZST: &[u8] = unsafe { std::mem::transmute(1usize) }; + | ^^^^^^^^^^^^^^^^^^^ + | + = note: source type: `usize` (64 bits) + = note: target type: `&'static [u8]` (128 bits) + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0512`. diff --git a/src/test/ui/feature-gates/feature-gate-generators.rs b/src/test/ui/feature-gates/feature-gate-generators.rs index 382d891feed84..931fee1347126 100644 --- a/src/test/ui/feature-gates/feature-gate-generators.rs +++ b/src/test/ui/feature-gates/feature-gate-generators.rs @@ -1,6 +1,6 @@ fn main() { yield true; //~ ERROR yield syntax is experimental - //~^ ERROR yield statement outside of generator literal + //~^ ERROR yield expression outside of generator literal } #[cfg(FALSE)] diff --git a/src/test/ui/feature-gates/feature-gate-generators.stderr b/src/test/ui/feature-gates/feature-gate-generators.stderr index 24b814b410c9d..4adc21efc6a21 100644 --- a/src/test/ui/feature-gates/feature-gate-generators.stderr +++ b/src/test/ui/feature-gates/feature-gate-generators.stderr @@ -25,7 +25,7 @@ LL | yield 0; = note: for more information, see https://github.com/rust-lang/rust/issues/43122 = help: add `#![feature(generators)]` to the crate attributes to enable -error[E0627]: yield statement outside of generator literal +error[E0627]: yield expression outside of generator literal --> $DIR/feature-gate-generators.rs:2:5 | LL | yield true; @@ -33,4 +33,5 @@ LL | yield true; error: aborting due to 4 previous errors -For more information about this error, try `rustc --explain E0658`. +Some errors have detailed explanations: E0627, E0658. +For more information about an error, try `rustc --explain E0627`. diff --git a/src/test/ui/generator/yield-in-const.rs b/src/test/ui/generator/yield-in-const.rs index f6f11b9cb13dd..fe5ca822ceca1 100644 --- a/src/test/ui/generator/yield-in-const.rs +++ b/src/test/ui/generator/yield-in-const.rs @@ -1,6 +1,6 @@ #![feature(generators)] const A: u8 = { yield 3u8; 3u8}; -//~^ ERROR yield statement outside +//~^ ERROR yield expression outside fn main() {} diff --git a/src/test/ui/generator/yield-in-const.stderr b/src/test/ui/generator/yield-in-const.stderr index 663bb70d7a07f..dcf4fe63e64bc 100644 --- a/src/test/ui/generator/yield-in-const.stderr +++ b/src/test/ui/generator/yield-in-const.stderr @@ -1,4 +1,4 @@ -error[E0627]: yield statement outside of generator literal +error[E0627]: yield expression outside of generator literal --> $DIR/yield-in-const.rs:3:17 | LL | const A: u8 = { yield 3u8; 3u8}; @@ -6,3 +6,4 @@ LL | const A: u8 = { yield 3u8; 3u8}; error: aborting due to previous error +For more information about this error, try `rustc --explain E0627`. diff --git a/src/test/ui/generator/yield-in-function.rs b/src/test/ui/generator/yield-in-function.rs index b737d3b224035..29b811621de1e 100644 --- a/src/test/ui/generator/yield-in-function.rs +++ b/src/test/ui/generator/yield-in-function.rs @@ -1,4 +1,4 @@ #![feature(generators)] fn main() { yield; } -//~^ ERROR yield statement outside +//~^ ERROR yield expression outside diff --git a/src/test/ui/generator/yield-in-function.stderr b/src/test/ui/generator/yield-in-function.stderr index e12b0e6843e41..51cce198ca3b4 100644 --- a/src/test/ui/generator/yield-in-function.stderr +++ b/src/test/ui/generator/yield-in-function.stderr @@ -1,4 +1,4 @@ -error[E0627]: yield statement outside of generator literal +error[E0627]: yield expression outside of generator literal --> $DIR/yield-in-function.rs:3:13 | LL | fn main() { yield; } @@ -6,3 +6,4 @@ LL | fn main() { yield; } error: aborting due to previous error +For more information about this error, try `rustc --explain E0627`. diff --git a/src/test/ui/generator/yield-in-static.rs b/src/test/ui/generator/yield-in-static.rs index 12c9ccea4cb78..d27fbb33ba10a 100644 --- a/src/test/ui/generator/yield-in-static.rs +++ b/src/test/ui/generator/yield-in-static.rs @@ -1,6 +1,6 @@ #![feature(generators)] static B: u8 = { yield 3u8; 3u8}; -//~^ ERROR yield statement outside +//~^ ERROR yield expression outside fn main() {} diff --git a/src/test/ui/generator/yield-in-static.stderr b/src/test/ui/generator/yield-in-static.stderr index 220520c3862ca..d867f3ad34528 100644 --- a/src/test/ui/generator/yield-in-static.stderr +++ b/src/test/ui/generator/yield-in-static.stderr @@ -1,4 +1,4 @@ -error[E0627]: yield statement outside of generator literal +error[E0627]: yield expression outside of generator literal --> $DIR/yield-in-static.rs:3:18 | LL | static B: u8 = { yield 3u8; 3u8}; @@ -6,3 +6,4 @@ LL | static B: u8 = { yield 3u8; 3u8}; error: aborting due to previous error +For more information about this error, try `rustc --explain E0627`. diff --git a/src/test/ui/generic-associated-types/issue-67424.rs b/src/test/ui/generic-associated-types/issue-67424.rs new file mode 100644 index 0000000000000..9b616b8abc2ee --- /dev/null +++ b/src/test/ui/generic-associated-types/issue-67424.rs @@ -0,0 +1,13 @@ +// Fixed by #67160 + +trait Trait1 { + type A; +} + +trait Trait2 { + type Type1: Trait1; + //~^ ERROR: generic associated types are unstable + //~| ERROR: type-generic associated types are not yet implemented +} + +fn main() {} diff --git a/src/test/ui/generic-associated-types/issue-67424.stderr b/src/test/ui/generic-associated-types/issue-67424.stderr new file mode 100644 index 0000000000000..59ff8ac0a3a70 --- /dev/null +++ b/src/test/ui/generic-associated-types/issue-67424.stderr @@ -0,0 +1,20 @@ +error[E0658]: generic associated types are unstable + --> $DIR/issue-67424.rs:8:5 + | +LL | type Type1: Trait1; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/44265 + = help: add `#![feature(generic_associated_types)]` to the crate attributes to enable + +error: type-generic associated types are not yet implemented + --> $DIR/issue-67424.rs:8:5 + | +LL | type Type1: Trait1; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/44265 + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/pattern/issue-66270-pat-struct-parser-recovery.rs b/src/test/ui/pattern/issue-66270-pat-struct-parser-recovery.rs new file mode 100644 index 0000000000000..48a8e04829a0a --- /dev/null +++ b/src/test/ui/pattern/issue-66270-pat-struct-parser-recovery.rs @@ -0,0 +1,14 @@ +// Regression test for #66270, fixed by #66246 + +struct Bug { + incorrect_field: 0, + //~^ ERROR expected type +} + +struct Empty {} + +fn main() { + let Bug { + any_field: Empty {}, + } = Bug {}; +} diff --git a/src/test/ui/pattern/issue-66270-pat-struct-parser-recovery.stderr b/src/test/ui/pattern/issue-66270-pat-struct-parser-recovery.stderr new file mode 100644 index 0000000000000..fef0f3c0e06ef --- /dev/null +++ b/src/test/ui/pattern/issue-66270-pat-struct-parser-recovery.stderr @@ -0,0 +1,8 @@ +error: expected type, found `0` + --> $DIR/issue-66270-pat-struct-parser-recovery.rs:4:22 + | +LL | incorrect_field: 0, + | ^ expected type + +error: aborting due to previous error +