Snapshot binaries are currently built and tested on several platforms:
-| Platform / Architecture | x86 | x86_64 |
-|--------------------------|-----|--------|
-| Windows (7, 8, 10, ...) | ✓ | ✓ |
-| Linux (2.6.18 or later) | ✓ | ✓ |
-| OSX (10.7 Lion or later) | ✓ | ✓ |
+| Platform / Architecture | x86 | x86_64 |
+|----------------------------|-----|--------|
+| Windows (7, 8, 10, ...) | ✓ | ✓ |
+| Linux (2.6.18 or later) | ✓ | ✓ |
+| macOS (10.7 Lion or later) | ✓ | ✓ |
You may find that other platforms work, but these are our officially
supported build environments that are most likely to work.
/// 'XID_Start' is a Unicode Derived Property specified in
/// [UAX #31](http://unicode.org/reports/tr31/#NFKC_Modifications),
/// mostly similar to `ID_Start` but modified for closure under `NFKx`.
- #[unstable(feature = "rustc_private",
- reason = "mainly needed for compiler internals",
- issue = "27812")]
- #[inline]
+ #[cfg_attr(bootstrap,
+ unstable(feature = "rustc_private",
+ reason = "mainly needed for compiler internals",
+ issue = "27812"))]
+ #[cfg_attr(not(bootstrap),
+ unstable(feature = "unicode_internals", issue = "0"))]
pub fn is_xid_start(self) -> bool {
derived_property::XID_Start(self)
}
/// 'XID_Continue' is a Unicode Derived Property specified in
/// [UAX #31](http://unicode.org/reports/tr31/#NFKC_Modifications),
/// mostly similar to 'ID_Continue' but modified for closure under NFKx.
- #[unstable(feature = "rustc_private",
- reason = "mainly needed for compiler internals",
- issue = "27812")]
+ #[cfg_attr(bootstrap,
+ unstable(feature = "rustc_private",
+ reason = "mainly needed for compiler internals",
+ issue = "27812"))]
+ #[cfg_attr(not(bootstrap),
+ unstable(feature = "unicode_internals", issue = "0"))]
#[inline]
pub fn is_xid_continue(self) -> bool {
derived_property::XID_Continue(self)
/// Checks whether the regions of memory starting at `src` and `dst` of size
/// `count * size_of::<T>()` overlap.
+#[cfg(not(miri))] // Cannot compare with `>` across allocations in Miri
fn overlaps<T>(src: *const T, dst: *const T, count: usize) -> bool {
let src_usize = src as usize;
let dst_usize = dst as usize;
debug_assert!(is_aligned_and_not_null(src), "attempt to copy from unaligned or null pointer");
debug_assert!(is_aligned_and_not_null(dst), "attempt to copy to unaligned or null pointer");
+ #[cfg(not(miri))]
debug_assert!(!overlaps(src, dst, count), "attempt to copy to overlapping memory");
copy_nonoverlapping(src, dst, count)
}
/// assert!(v.contains(&30));
/// assert!(!v.contains(&50));
/// ```
+ ///
+ /// If you do not have an `&T`, but just an `&U` such that `T: Borrow<U>`
+ /// (e.g. `String: Borrow<str>`), you can use `iter().any`:
+ ///
+ /// ```
+ /// let v = [String::from("hello"), String::from("world")]; // slice of `String`
+ /// assert!(v.iter().any(|e| e == "hello")); // search with `&str`
+ /// assert!(!v.iter().any(|e| e == "hi"));
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn contains(&self, x: &T) -> bool
where T: PartialEq
#![feature(nll)]
#![feature(rustc_private)]
+#![feature(unicode_internals)]
pub use Piece::*;
pub use Position::*;
}
}
- span_bug!(
+ // Errors in earlier passes can yield error variables without
+ // resolution errors here; delay ICE in favor of those errors.
+ self.tcx().sess.delay_span_bug(
self.var_infos[node_idx].origin.span(),
- "collect_error_for_expanding_node() could not find \
- error for var {:?} in universe {:?}, lower_bounds={:#?}, \
- upper_bounds={:#?}",
- node_idx,
- node_universe,
- lower_bounds,
- upper_bounds
- );
+ &format!("collect_error_for_expanding_node() could not find \
+ error for var {:?} in universe {:?}, lower_bounds={:#?}, \
+ upper_bounds={:#?}",
+ node_idx,
+ node_universe,
+ lower_bounds,
+ upper_bounds));
}
fn collect_concrete_regions(
pub type AssertMessage<'tcx> = InterpError<'tcx, mir::Operand<'tcx>>;
+#[derive(Clone, RustcEncodable, RustcDecodable, HashStable)]
+pub enum PanicMessage<O> {
+ Panic {
+ msg: Symbol,
+ line: u32,
+ col: u32,
+ file: Symbol,
+ },
+ BoundsCheck {
+ len: O,
+ index: O,
+ },
+ Overflow(mir::BinOp),
+ OverflowNeg,
+ DivisionByZero,
+ RemainderByZero,
+}
+
#[derive(Clone, RustcEncodable, RustcDecodable, HashStable)]
pub enum InterpError<'tcx, O> {
/// This variant is used by machines to signal their own errors that do not
Unimplemented(String),
DerefFunctionPointer,
ExecuteMemory,
- BoundsCheck { len: O, index: O },
- Overflow(mir::BinOp),
- OverflowNeg,
- DivisionByZero,
- RemainderByZero,
Intrinsic(String),
InvalidChar(u128),
StackFrameLimitReached,
HeapAllocZeroBytes,
HeapAllocNonPowerOfTwoAlignment(u64),
Unreachable,
- Panic {
- msg: Symbol,
- line: u32,
- col: u32,
- file: Symbol,
- },
+ Panic(PanicMessage<O>),
ReadFromReturnPointer,
PathNotFound(Vec<String>),
UnimplementedTraitSelection,
"tried to dereference a function pointer",
ExecuteMemory =>
"tried to treat a memory pointer as a function pointer",
- BoundsCheck{..} =>
- "array index out of bounds",
Intrinsic(..) =>
"intrinsic failed",
NoMirFor(..) =>
two",
Unreachable =>
"entered unreachable code",
- Panic { .. } =>
+ Panic(PanicMessage::Panic{..}) =>
"the evaluated program panicked",
+ Panic(PanicMessage::BoundsCheck{..}) =>
+ "array index out of bounds",
+ Panic(PanicMessage::Overflow(mir::BinOp::Add)) =>
+ "attempt to add with overflow",
+ Panic(PanicMessage::Overflow(mir::BinOp::Sub)) =>
+ "attempt to subtract with overflow",
+ Panic(PanicMessage::Overflow(mir::BinOp::Mul)) =>
+ "attempt to multiply with overflow",
+ Panic(PanicMessage::Overflow(mir::BinOp::Div)) =>
+ "attempt to divide with overflow",
+ Panic(PanicMessage::Overflow(mir::BinOp::Rem)) =>
+ "attempt to calculate the remainder with overflow",
+ Panic(PanicMessage::OverflowNeg) =>
+ "attempt to negate with overflow",
+ Panic(PanicMessage::Overflow(mir::BinOp::Shr)) =>
+ "attempt to shift right with overflow",
+ Panic(PanicMessage::Overflow(mir::BinOp::Shl)) =>
+ "attempt to shift left with overflow",
+ Panic(PanicMessage::Overflow(op)) =>
+ bug!("{:?} cannot overflow", op),
+ Panic(PanicMessage::DivisionByZero) =>
+ "attempt to divide by zero",
+ Panic(PanicMessage::RemainderByZero) =>
+ "attempt to calculate the remainder with a divisor of zero",
ReadFromReturnPointer =>
"tried to read from the return pointer",
PathNotFound(_) =>
"encountered overly generic constant",
ReferencedConstant =>
"referenced constant has errors",
- Overflow(mir::BinOp::Add) => "attempt to add with overflow",
- Overflow(mir::BinOp::Sub) => "attempt to subtract with overflow",
- Overflow(mir::BinOp::Mul) => "attempt to multiply with overflow",
- Overflow(mir::BinOp::Div) => "attempt to divide with overflow",
- Overflow(mir::BinOp::Rem) => "attempt to calculate the remainder with overflow",
- OverflowNeg => "attempt to negate with overflow",
- Overflow(mir::BinOp::Shr) => "attempt to shift right with overflow",
- Overflow(mir::BinOp::Shl) => "attempt to shift left with overflow",
- Overflow(op) => bug!("{:?} cannot overflow", op),
- DivisionByZero => "attempt to divide by zero",
- RemainderByZero => "attempt to calculate the remainder with a divisor of zero",
GeneratorResumedAfterReturn => "generator resumed after completion",
GeneratorResumedAfterPanic => "generator resumed after panicking",
InfiniteLoop =>
callee_ty, caller_ty),
FunctionArgCountMismatch =>
write!(f, "tried to call a function with incorrect number of arguments"),
- BoundsCheck { ref len, ref index } =>
- write!(f, "index out of bounds: the len is {:?} but the index is {:?}", len, index),
ReallocatedWrongMemoryKind(ref old, ref new) =>
write!(f, "tried to reallocate memory from {} to {}", old, new),
DeallocatedWrongMemoryKind(ref old, ref new) =>
write!(f, "incorrect alloc info: expected size {} and align {}, \
got size {} and align {}",
size.bytes(), align.bytes(), size2.bytes(), align2.bytes()),
- Panic { ref msg, line, col, ref file } =>
+ Panic(PanicMessage::Panic { ref msg, line, col, ref file }) =>
write!(f, "the evaluated program panicked at '{}', {}:{}:{}", msg, file, line, col),
+ Panic(PanicMessage::BoundsCheck { ref len, ref index }) =>
+ write!(f, "index out of bounds: the len is {:?} but the index is {:?}", len, index),
InvalidDiscriminant(val) =>
write!(f, "encountered invalid enum discriminant {}", val),
Exit(code) =>
pub use self::error::{
InterpErrorInfo, InterpResult, InterpError, AssertMessage, ConstEvalErr, struct_error,
- FrameInfo, ConstEvalRawResult, ConstEvalResult, ErrorHandled,
+ FrameInfo, ConstEvalRawResult, ConstEvalResult, ErrorHandled, PanicMessage
};
pub use self::value::{Scalar, ScalarMaybeUndef, RawConst, ConstValue};
use rustc_macros::HashStable;
use super::{
- AllocId, InterpResult,
+ AllocId, InterpResult, PanicMessage
};
/// Used by `check_in_alloc` to indicate context of check
#[inline]
fn offset<'tcx>(&self, val: u64, i: u64) -> InterpResult<'tcx, u64> {
let (res, over) = self.overflowing_offset(val, i);
- if over { err!(Overflow(mir::BinOp::Add)) } else { Ok(res) }
+ if over { err!(Panic(PanicMessage::Overflow(mir::BinOp::Add))) } else { Ok(res) }
}
#[inline]
fn signed_offset<'tcx>(&self, val: u64, i: i64) -> InterpResult<'tcx, u64> {
let (res, over) = self.overflowing_signed_offset(val, i128::from(i));
- if over { err!(Overflow(mir::BinOp::Add)) } else { Ok(res) }
+ if over { err!(Panic(PanicMessage::Overflow(mir::BinOp::Add))) } else { Ok(res) }
}
}
use crate::hir::def::{CtorKind, Namespace};
use crate::hir::def_id::DefId;
use crate::hir::{self, InlineAsm as HirInlineAsm};
-use crate::mir::interpret::{ConstValue, InterpError, Scalar};
+use crate::mir::interpret::{ConstValue, PanicMessage, InterpError::Panic, Scalar};
use crate::mir::visit::MirVisitable;
use crate::rustc_serialize as serialize;
use crate::ty::adjustment::PointerCast;
iterate_over2(place_base, place_projection, &Projections::Empty, op)
}
- pub fn as_place_ref(&self) -> PlaceRef<'_, 'tcx> {
+ pub fn as_ref(&self) -> PlaceRef<'_, 'tcx> {
PlaceRef {
base: &self.base,
projection: &self.projection,
}
}
Assert { ref cond, expected, ref msg, target, cleanup } => {
- let msg = if let InterpError::BoundsCheck { ref len, ref index } = *msg {
- InterpError::BoundsCheck {
+ let msg = if let Panic(PanicMessage::BoundsCheck { ref len, ref index }) = *msg {
+ Panic(PanicMessage::BoundsCheck {
len: len.fold_with(folder),
index: index.fold_with(folder),
- }
+ })
} else {
msg.clone()
};
}
Assert { ref cond, ref msg, .. } => {
if cond.visit_with(visitor) {
- if let InterpError::BoundsCheck { ref len, ref index } = *msg {
+ if let Panic(PanicMessage::BoundsCheck { ref len, ref index }) = *msg {
len.visit_with(visitor) || index.visit_with(visitor)
} else {
false
msg: & $($mutability)? AssertMessage<'tcx>,
location: Location) {
use crate::mir::interpret::InterpError::*;
- if let BoundsCheck { len, index } = msg {
+ use crate::mir::interpret::PanicMessage::BoundsCheck;
+ if let Panic(BoundsCheck { len, index }) = msg {
self.visit_operand(len, location);
self.visit_operand(index, location);
}
if self.found {
self.handler
- .span_err(item.span, "cannot define more than one #[global_allocator]");
+ .span_err(item.span, "cannot define more than one `#[global_allocator]`");
return smallvec![item];
}
self.found = true;
AllocatorTy::Unit => (self.cx.ty(self.span, TyKind::Tup(Vec::new())), expr),
AllocatorTy::Layout | AllocatorTy::Usize | AllocatorTy::Ptr => {
- panic!("can't convert AllocatorTy to an output")
+ panic!("can't convert `AllocatorTy` to an output")
}
}
}
context: PlaceContext,
location: Location) {
debug!("visit_place(place={:?}, context={:?})", place, context);
- self.process_place(&place.as_place_ref(), context, location);
+ self.process_place(&place.as_ref(), context, location);
}
fn visit_local(&mut self,
use rustc::ty::{self, Ty, TypeFoldable, Instance};
use rustc::ty::layout::{self, LayoutOf, HasTyCtxt, FnTypeExt};
use rustc::mir::{self, Place, PlaceBase, Static, StaticKind};
-use rustc::mir::interpret::InterpError;
+use rustc::mir::interpret::{InterpError, PanicMessage};
use rustc_target::abi::call::{ArgType, FnType, PassMode, IgnoreMode};
use rustc_target::spec::abi::Abi;
use crate::base;
PassMode::Direct(_) | PassMode::Pair(..) => {
let op =
- self.codegen_consume(&mut bx, &mir::Place::RETURN_PLACE.as_place_ref());
+ self.codegen_consume(&mut bx, &mir::Place::RETURN_PLACE.as_ref());
if let Ref(llval, _, align) = op.val {
bx.load(llval, align)
} else {
return
}
- let place = self.codegen_place(&mut bx, &location.as_place_ref());
+ let place = self.codegen_place(&mut bx, &location.as_ref());
let (args1, args2);
let mut args = if let Some(llextra) = place.llextra {
args2 = [place.llval, llextra];
// checked operation, just a comparison with the minimum
// value, so we have to check for the assert message.
if !bx.check_overflow() {
- if let mir::interpret::InterpError::OverflowNeg = *msg {
+ if let InterpError::Panic(PanicMessage::OverflowNeg) = *msg {
const_cond = Some(expected);
}
}
// Put together the arguments to the panic entry point.
let (lang_item, args) = match *msg {
- InterpError::BoundsCheck { ref len, ref index } => {
+ InterpError::Panic(PanicMessage::BoundsCheck { ref len, ref index }) => {
let len = self.codegen_operand(&mut bx, len).immediate();
let index = self.codegen_operand(&mut bx, index).immediate();
LocalRef::Place(place) => self.codegen_transmute_into(bx, src, place),
LocalRef::UnsizedPlace(_) => bug!("transmute must not involve unsized locals"),
LocalRef::Operand(None) => {
- let dst_layout = bx.layout_of(self.monomorphized_place_ty(&dst.as_place_ref()));
+ let dst_layout = bx.layout_of(self.monomorphized_place_ty(&dst.as_ref()));
assert!(!dst_layout.ty.has_erasable_regions());
let place = PlaceRef::alloca(bx, dst_layout, "transmute_temp");
place.storage_live(bx);
}
}
} else {
- let dst = self.codegen_place(bx, &dst.as_place_ref());
+ let dst = self.codegen_place(bx, &dst.as_ref());
self.codegen_transmute_into(bx, src, dst);
}
}
match *operand {
mir::Operand::Copy(ref place) |
mir::Operand::Move(ref place) => {
- self.codegen_consume(bx, &place.as_place_ref())
+ self.codegen_consume(bx, &place.as_ref())
}
mir::Operand::Constant(ref constant) => {
}
mir::Rvalue::Ref(_, bk, ref place) => {
- let cg_place = self.codegen_place(&mut bx, &place.as_place_ref());
+ let cg_place = self.codegen_place(&mut bx, &place.as_ref());
let ty = cg_place.layout.ty;
mir::Rvalue::Discriminant(ref place) => {
let discr_ty = rvalue.ty(&*self.mir, bx.tcx());
- let discr = self.codegen_place(&mut bx, &place.as_place_ref())
+ let discr = self.codegen_place(&mut bx, &place.as_ref())
.codegen_get_discr(&mut bx, discr_ty);
(bx, OperandRef {
val: OperandValue::Immediate(discr),
}
}
// use common size calculation for non zero-sized types
- let cg_value = self.codegen_place(bx, &place.as_place_ref());
+ let cg_value = self.codegen_place(bx, &place.as_ref());
cg_value.len(bx.cx())
}
}
}
} else {
- let cg_dest = self.codegen_place(&mut bx, &place.as_place_ref());
+ let cg_dest = self.codegen_place(&mut bx, &place.as_ref());
self.codegen_rvalue(bx, cg_dest, rvalue)
}
}
mir::StatementKind::SetDiscriminant{ref place, variant_index} => {
- self.codegen_place(&mut bx, &place.as_place_ref())
+ self.codegen_place(&mut bx, &place.as_ref())
.codegen_set_discr(&mut bx, variant_index);
bx
}
}
mir::StatementKind::InlineAsm(ref asm) => {
let outputs = asm.outputs.iter().map(|output| {
- self.codegen_place(&mut bx, &output.as_place_ref())
+ self.codegen_place(&mut bx, &output.as_ref())
}).collect();
let input_vals = asm.inputs.iter()
// We want to be able to build this crate with a stable compiler, so feature
-// flags should optional.
-#![cfg_attr(not(feature = "unicode-xid"), feature(rustc_private))]
+// flags should be optional.
#![cfg_attr(not(feature = "unicode-xid"), feature(unicode_internals))]
mod cursor;
+pub mod unescape;
use crate::cursor::{Cursor, EOF_CHAR};
--- /dev/null
+//! Utilities for validating string and char literals and turning them into
+//! values they represent.
+
+use std::str::Chars;
+use std::ops::Range;
+
+#[derive(Debug, PartialEq, Eq)]
+pub enum EscapeError {
+ ZeroChars,
+ MoreThanOneChar,
+
+ LoneSlash,
+ InvalidEscape,
+ BareCarriageReturn,
+ BareCarriageReturnInRawString,
+ EscapeOnlyChar,
+
+ TooShortHexEscape,
+ InvalidCharInHexEscape,
+ OutOfRangeHexEscape,
+
+ NoBraceInUnicodeEscape,
+ InvalidCharInUnicodeEscape,
+ EmptyUnicodeEscape,
+ UnclosedUnicodeEscape,
+ LeadingUnderscoreUnicodeEscape,
+ OverlongUnicodeEscape,
+ LoneSurrogateUnicodeEscape,
+ OutOfRangeUnicodeEscape,
+
+ UnicodeEscapeInByte,
+ NonAsciiCharInByte,
+ NonAsciiCharInByteString,
+}
+
+/// Takes a contents of a char literal (without quotes), and returns an
+/// unescaped char or an error
+pub fn unescape_char(literal_text: &str) -> Result<char, (usize, EscapeError)> {
+ let mut chars = literal_text.chars();
+ unescape_char_or_byte(&mut chars, Mode::Char)
+ .map_err(|err| (literal_text.len() - chars.as_str().len(), err))
+}
+
+/// Takes a contents of a string literal (without quotes) and produces a
+/// sequence of escaped characters or errors.
+pub fn unescape_str<F>(literal_text: &str, callback: &mut F)
+where
+ F: FnMut(Range<usize>, Result<char, EscapeError>),
+{
+ unescape_str_or_byte_str(literal_text, Mode::Str, callback)
+}
+
+pub fn unescape_byte(literal_text: &str) -> Result<u8, (usize, EscapeError)> {
+ let mut chars = literal_text.chars();
+ unescape_char_or_byte(&mut chars, Mode::Byte)
+ .map(byte_from_char)
+ .map_err(|err| (literal_text.len() - chars.as_str().len(), err))
+}
+
+/// Takes a contents of a string literal (without quotes) and produces a
+/// sequence of escaped characters or errors.
+pub fn unescape_byte_str<F>(literal_text: &str, callback: &mut F)
+where
+ F: FnMut(Range<usize>, Result<u8, EscapeError>),
+{
+ unescape_str_or_byte_str(literal_text, Mode::ByteStr, &mut |range, char| {
+ callback(range, char.map(byte_from_char))
+ })
+}
+
+/// Takes a contents of a string literal (without quotes) and produces a
+/// sequence of characters or errors.
+/// NOTE: Raw strings do not perform any explicit character escaping, here we
+/// only translate CRLF to LF and produce errors on bare CR.
+pub fn unescape_raw_str<F>(literal_text: &str, callback: &mut F)
+where
+ F: FnMut(Range<usize>, Result<char, EscapeError>),
+{
+ unescape_raw_str_or_byte_str(literal_text, Mode::Str, callback)
+}
+
+/// Takes a contents of a string literal (without quotes) and produces a
+/// sequence of characters or errors.
+/// NOTE: Raw strings do not perform any explicit character escaping, here we
+/// only translate CRLF to LF and produce errors on bare CR.
+pub fn unescape_raw_byte_str<F>(literal_text: &str, callback: &mut F)
+where
+ F: FnMut(Range<usize>, Result<u8, EscapeError>),
+{
+ unescape_raw_str_or_byte_str(literal_text, Mode::ByteStr, &mut |range, char| {
+ callback(range, char.map(byte_from_char))
+ })
+}
+
+#[derive(Debug, Clone, Copy)]
+pub enum Mode {
+ Char,
+ Str,
+ Byte,
+ ByteStr,
+}
+
+impl Mode {
+ pub fn in_single_quotes(self) -> bool {
+ match self {
+ Mode::Char | Mode::Byte => true,
+ Mode::Str | Mode::ByteStr => false,
+ }
+ }
+
+ pub fn in_double_quotes(self) -> bool {
+ !self.in_single_quotes()
+ }
+
+ pub fn is_bytes(self) -> bool {
+ match self {
+ Mode::Byte | Mode::ByteStr => true,
+ Mode::Char | Mode::Str => false,
+ }
+ }
+}
+
+
+fn scan_escape(first_char: char, chars: &mut Chars<'_>, mode: Mode) -> Result<char, EscapeError> {
+ if first_char != '\\' {
+ return match first_char {
+ '\t' | '\n' => Err(EscapeError::EscapeOnlyChar),
+ '\r' => Err(if chars.clone().next() == Some('\n') {
+ EscapeError::EscapeOnlyChar
+ } else {
+ EscapeError::BareCarriageReturn
+ }),
+ '\'' if mode.in_single_quotes() => Err(EscapeError::EscapeOnlyChar),
+ '"' if mode.in_double_quotes() => Err(EscapeError::EscapeOnlyChar),
+ _ => {
+ if mode.is_bytes() && !first_char.is_ascii() {
+ return Err(EscapeError::NonAsciiCharInByte);
+ }
+ Ok(first_char)
+ }
+ };
+ }
+
+ let second_char = chars.next().ok_or(EscapeError::LoneSlash)?;
+
+ let res = match second_char {
+ '"' => '"',
+ 'n' => '\n',
+ 'r' => '\r',
+ 't' => '\t',
+ '\\' => '\\',
+ '\'' => '\'',
+ '0' => '\0',
+
+ 'x' => {
+ let hi = chars.next().ok_or(EscapeError::TooShortHexEscape)?;
+ let hi = hi.to_digit(16).ok_or(EscapeError::InvalidCharInHexEscape)?;
+
+ let lo = chars.next().ok_or(EscapeError::TooShortHexEscape)?;
+ let lo = lo.to_digit(16).ok_or(EscapeError::InvalidCharInHexEscape)?;
+
+ let value = hi * 16 + lo;
+
+ if !mode.is_bytes() && !is_ascii(value) {
+ return Err(EscapeError::OutOfRangeHexEscape);
+ }
+ let value = value as u8;
+
+ value as char
+ }
+
+ 'u' => {
+ if chars.next() != Some('{') {
+ return Err(EscapeError::NoBraceInUnicodeEscape);
+ }
+
+ let mut n_digits = 1;
+ let mut value: u32 = match chars.next().ok_or(EscapeError::UnclosedUnicodeEscape)? {
+ '_' => return Err(EscapeError::LeadingUnderscoreUnicodeEscape),
+ '}' => return Err(EscapeError::EmptyUnicodeEscape),
+ c => c.to_digit(16).ok_or(EscapeError::InvalidCharInUnicodeEscape)?,
+ };
+
+ loop {
+ match chars.next() {
+ None => return Err(EscapeError::UnclosedUnicodeEscape),
+ Some('_') => continue,
+ Some('}') => {
+ if n_digits > 6 {
+ return Err(EscapeError::OverlongUnicodeEscape);
+ }
+ if mode.is_bytes() {
+ return Err(EscapeError::UnicodeEscapeInByte);
+ }
+
+ break std::char::from_u32(value).ok_or_else(|| {
+ if value > 0x10FFFF {
+ EscapeError::OutOfRangeUnicodeEscape
+ } else {
+ EscapeError::LoneSurrogateUnicodeEscape
+ }
+ })?;
+ }
+ Some(c) => {
+ let digit = c.to_digit(16).ok_or(EscapeError::InvalidCharInUnicodeEscape)?;
+ n_digits += 1;
+ if n_digits > 6 {
+ continue;
+ }
+ let digit = digit as u32;
+ value = value * 16 + digit;
+ }
+ };
+ }
+ }
+ _ => return Err(EscapeError::InvalidEscape),
+ };
+ Ok(res)
+}
+
+fn unescape_char_or_byte(chars: &mut Chars<'_>, mode: Mode) -> Result<char, EscapeError> {
+ let first_char = chars.next().ok_or(EscapeError::ZeroChars)?;
+ let res = scan_escape(first_char, chars, mode)?;
+ if chars.next().is_some() {
+ return Err(EscapeError::MoreThanOneChar);
+ }
+ Ok(res)
+}
+
+/// Takes a contents of a string literal (without quotes) and produces a
+/// sequence of escaped characters or errors.
+fn unescape_str_or_byte_str<F>(src: &str, mode: Mode, callback: &mut F)
+where
+ F: FnMut(Range<usize>, Result<char, EscapeError>),
+{
+ assert!(mode.in_double_quotes());
+ let initial_len = src.len();
+ let mut chars = src.chars();
+ while let Some(first_char) = chars.next() {
+ let start = initial_len - chars.as_str().len() - first_char.len_utf8();
+
+ let unescaped_char = match first_char {
+ '\\' => {
+ let (second_char, third_char) = {
+ let mut chars = chars.clone();
+ (chars.next(), chars.next())
+ };
+ match (second_char, third_char) {
+ (Some('\n'), _) | (Some('\r'), Some('\n')) => {
+ skip_ascii_whitespace(&mut chars);
+ continue;
+ }
+ _ => scan_escape(first_char, &mut chars, mode),
+ }
+ }
+ '\r' => {
+ let second_char = chars.clone().next();
+ if second_char == Some('\n') {
+ chars.next();
+ Ok('\n')
+ } else {
+ scan_escape(first_char, &mut chars, mode)
+ }
+ }
+ '\n' => Ok('\n'),
+ '\t' => Ok('\t'),
+ _ => scan_escape(first_char, &mut chars, mode),
+ };
+ let end = initial_len - chars.as_str().len();
+ callback(start..end, unescaped_char);
+ }
+
+ fn skip_ascii_whitespace(chars: &mut Chars<'_>) {
+ let str = chars.as_str();
+ let first_non_space = str
+ .bytes()
+ .position(|b| b != b' ' && b != b'\t' && b != b'\n' && b != b'\r')
+ .unwrap_or(str.len());
+ *chars = str[first_non_space..].chars()
+ }
+}
+
+/// Takes a contents of a string literal (without quotes) and produces a
+/// sequence of characters or errors.
+/// NOTE: Raw strings do not perform any explicit character escaping, here we
+/// only translate CRLF to LF and produce errors on bare CR.
+fn unescape_raw_str_or_byte_str<F>(literal_text: &str, mode: Mode, callback: &mut F)
+where
+ F: FnMut(Range<usize>, Result<char, EscapeError>),
+{
+ assert!(mode.in_double_quotes());
+ let initial_len = literal_text.len();
+
+ let mut chars = literal_text.chars();
+ while let Some(curr) = chars.next() {
+ let start = initial_len - chars.as_str().len() - curr.len_utf8();
+
+ let result = match (curr, chars.clone().next()) {
+ ('\r', Some('\n')) => {
+ chars.next();
+ Ok('\n')
+ },
+ ('\r', _) => Err(EscapeError::BareCarriageReturnInRawString),
+ (c, _) if mode.is_bytes() && !c.is_ascii() =>
+ Err(EscapeError::NonAsciiCharInByteString),
+ (c, _) => Ok(c),
+ };
+ let end = initial_len - chars.as_str().len();
+
+ callback(start..end, result);
+ }
+}
+
+fn byte_from_char(c: char) -> u8 {
+ let res = c as u32;
+ assert!(res <= u8::max_value() as u32, "guaranteed because of Mode::Byte(Str)");
+ res as u8
+}
+
+fn is_ascii(x: u32) -> bool {
+ x <= 0x7F
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn test_unescape_char_bad() {
+ fn check(literal_text: &str, expected_error: EscapeError) {
+ let actual_result = unescape_char(literal_text).map_err(|(_offset, err)| err);
+ assert_eq!(actual_result, Err(expected_error));
+ }
+
+ check("", EscapeError::ZeroChars);
+ check(r"\", EscapeError::LoneSlash);
+
+ check("\n", EscapeError::EscapeOnlyChar);
+ check("\r\n", EscapeError::EscapeOnlyChar);
+ check("\t", EscapeError::EscapeOnlyChar);
+ check("'", EscapeError::EscapeOnlyChar);
+ check("\r", EscapeError::BareCarriageReturn);
+
+ check("spam", EscapeError::MoreThanOneChar);
+ check(r"\x0ff", EscapeError::MoreThanOneChar);
+ check(r#"\"a"#, EscapeError::MoreThanOneChar);
+ check(r"\na", EscapeError::MoreThanOneChar);
+ check(r"\ra", EscapeError::MoreThanOneChar);
+ check(r"\ta", EscapeError::MoreThanOneChar);
+ check(r"\\a", EscapeError::MoreThanOneChar);
+ check(r"\'a", EscapeError::MoreThanOneChar);
+ check(r"\0a", EscapeError::MoreThanOneChar);
+ check(r"\u{0}x", EscapeError::MoreThanOneChar);
+ check(r"\u{1F63b}}", EscapeError::MoreThanOneChar);
+
+ check(r"\v", EscapeError::InvalidEscape);
+ check(r"\💩", EscapeError::InvalidEscape);
+ check(r"\●", EscapeError::InvalidEscape);
+
+ check(r"\x", EscapeError::TooShortHexEscape);
+ check(r"\x0", EscapeError::TooShortHexEscape);
+ check(r"\xf", EscapeError::TooShortHexEscape);
+ check(r"\xa", EscapeError::TooShortHexEscape);
+ check(r"\xx", EscapeError::InvalidCharInHexEscape);
+ check(r"\xы", EscapeError::InvalidCharInHexEscape);
+ check(r"\x🦀", EscapeError::InvalidCharInHexEscape);
+ check(r"\xtt", EscapeError::InvalidCharInHexEscape);
+ check(r"\xff", EscapeError::OutOfRangeHexEscape);
+ check(r"\xFF", EscapeError::OutOfRangeHexEscape);
+ check(r"\x80", EscapeError::OutOfRangeHexEscape);
+
+ check(r"\u", EscapeError::NoBraceInUnicodeEscape);
+ check(r"\u[0123]", EscapeError::NoBraceInUnicodeEscape);
+ check(r"\u{0x}", EscapeError::InvalidCharInUnicodeEscape);
+ check(r"\u{", EscapeError::UnclosedUnicodeEscape);
+ check(r"\u{0000", EscapeError::UnclosedUnicodeEscape);
+ check(r"\u{}", EscapeError::EmptyUnicodeEscape);
+ check(r"\u{_0000}", EscapeError::LeadingUnderscoreUnicodeEscape);
+ check(r"\u{0000000}", EscapeError::OverlongUnicodeEscape);
+ check(r"\u{FFFFFF}", EscapeError::OutOfRangeUnicodeEscape);
+ check(r"\u{ffffff}", EscapeError::OutOfRangeUnicodeEscape);
+ check(r"\u{ffffff}", EscapeError::OutOfRangeUnicodeEscape);
+
+ check(r"\u{DC00}", EscapeError::LoneSurrogateUnicodeEscape);
+ check(r"\u{DDDD}", EscapeError::LoneSurrogateUnicodeEscape);
+ check(r"\u{DFFF}", EscapeError::LoneSurrogateUnicodeEscape);
+
+ check(r"\u{D800}", EscapeError::LoneSurrogateUnicodeEscape);
+ check(r"\u{DAAA}", EscapeError::LoneSurrogateUnicodeEscape);
+ check(r"\u{DBFF}", EscapeError::LoneSurrogateUnicodeEscape);
+ }
+
+ #[test]
+ fn test_unescape_char_good() {
+ fn check(literal_text: &str, expected_char: char) {
+ let actual_result = unescape_char(literal_text);
+ assert_eq!(actual_result, Ok(expected_char));
+ }
+
+ check("a", 'a');
+ check("ы", 'ы');
+ check("🦀", '🦀');
+
+ check(r#"\""#, '"');
+ check(r"\n", '\n');
+ check(r"\r", '\r');
+ check(r"\t", '\t');
+ check(r"\\", '\\');
+ check(r"\'", '\'');
+ check(r"\0", '\0');
+
+ check(r"\x00", '\0');
+ check(r"\x5a", 'Z');
+ check(r"\x5A", 'Z');
+ check(r"\x7f", 127 as char);
+
+ check(r"\u{0}", '\0');
+ check(r"\u{000000}", '\0');
+ check(r"\u{41}", 'A');
+ check(r"\u{0041}", 'A');
+ check(r"\u{00_41}", 'A');
+ check(r"\u{4__1__}", 'A');
+ check(r"\u{1F63b}", '😻');
+ }
+
+ #[test]
+ fn test_unescape_str_good() {
+ fn check(literal_text: &str, expected: &str) {
+ let mut buf = Ok(String::with_capacity(literal_text.len()));
+ unescape_str(literal_text, &mut |range, c| {
+ if let Ok(b) = &mut buf {
+ match c {
+ Ok(c) => b.push(c),
+ Err(e) => buf = Err((range, e)),
+ }
+ }
+ });
+ let buf = buf.as_ref().map(|it| it.as_ref());
+ assert_eq!(buf, Ok(expected))
+ }
+
+ check("foo", "foo");
+ check("", "");
+ check(" \t\n\r\n", " \t\n\n");
+
+ check("hello \\\n world", "hello world");
+ check("hello \\\r\n world", "hello world");
+ check("thread's", "thread's")
+ }
+
+ #[test]
+ fn test_unescape_byte_bad() {
+ fn check(literal_text: &str, expected_error: EscapeError) {
+ let actual_result = unescape_byte(literal_text).map_err(|(_offset, err)| err);
+ assert_eq!(actual_result, Err(expected_error));
+ }
+
+ check("", EscapeError::ZeroChars);
+ check(r"\", EscapeError::LoneSlash);
+
+ check("\n", EscapeError::EscapeOnlyChar);
+ check("\r\n", EscapeError::EscapeOnlyChar);
+ check("\t", EscapeError::EscapeOnlyChar);
+ check("'", EscapeError::EscapeOnlyChar);
+ check("\r", EscapeError::BareCarriageReturn);
+
+ check("spam", EscapeError::MoreThanOneChar);
+ check(r"\x0ff", EscapeError::MoreThanOneChar);
+ check(r#"\"a"#, EscapeError::MoreThanOneChar);
+ check(r"\na", EscapeError::MoreThanOneChar);
+ check(r"\ra", EscapeError::MoreThanOneChar);
+ check(r"\ta", EscapeError::MoreThanOneChar);
+ check(r"\\a", EscapeError::MoreThanOneChar);
+ check(r"\'a", EscapeError::MoreThanOneChar);
+ check(r"\0a", EscapeError::MoreThanOneChar);
+
+ check(r"\v", EscapeError::InvalidEscape);
+ check(r"\💩", EscapeError::InvalidEscape);
+ check(r"\●", EscapeError::InvalidEscape);
+
+ check(r"\x", EscapeError::TooShortHexEscape);
+ check(r"\x0", EscapeError::TooShortHexEscape);
+ check(r"\xa", EscapeError::TooShortHexEscape);
+ check(r"\xf", EscapeError::TooShortHexEscape);
+ check(r"\xx", EscapeError::InvalidCharInHexEscape);
+ check(r"\xы", EscapeError::InvalidCharInHexEscape);
+ check(r"\x🦀", EscapeError::InvalidCharInHexEscape);
+ check(r"\xtt", EscapeError::InvalidCharInHexEscape);
+
+ check(r"\u", EscapeError::NoBraceInUnicodeEscape);
+ check(r"\u[0123]", EscapeError::NoBraceInUnicodeEscape);
+ check(r"\u{0x}", EscapeError::InvalidCharInUnicodeEscape);
+ check(r"\u{", EscapeError::UnclosedUnicodeEscape);
+ check(r"\u{0000", EscapeError::UnclosedUnicodeEscape);
+ check(r"\u{}", EscapeError::EmptyUnicodeEscape);
+ check(r"\u{_0000}", EscapeError::LeadingUnderscoreUnicodeEscape);
+ check(r"\u{0000000}", EscapeError::OverlongUnicodeEscape);
+
+ check("ы", EscapeError::NonAsciiCharInByte);
+ check("🦀", EscapeError::NonAsciiCharInByte);
+
+ check(r"\u{0}", EscapeError::UnicodeEscapeInByte);
+ check(r"\u{000000}", EscapeError::UnicodeEscapeInByte);
+ check(r"\u{41}", EscapeError::UnicodeEscapeInByte);
+ check(r"\u{0041}", EscapeError::UnicodeEscapeInByte);
+ check(r"\u{00_41}", EscapeError::UnicodeEscapeInByte);
+ check(r"\u{4__1__}", EscapeError::UnicodeEscapeInByte);
+ check(r"\u{1F63b}", EscapeError::UnicodeEscapeInByte);
+ check(r"\u{0}x", EscapeError::UnicodeEscapeInByte);
+ check(r"\u{1F63b}}", EscapeError::UnicodeEscapeInByte);
+ check(r"\u{FFFFFF}", EscapeError::UnicodeEscapeInByte);
+ check(r"\u{ffffff}", EscapeError::UnicodeEscapeInByte);
+ check(r"\u{ffffff}", EscapeError::UnicodeEscapeInByte);
+ check(r"\u{DC00}", EscapeError::UnicodeEscapeInByte);
+ check(r"\u{DDDD}", EscapeError::UnicodeEscapeInByte);
+ check(r"\u{DFFF}", EscapeError::UnicodeEscapeInByte);
+ check(r"\u{D800}", EscapeError::UnicodeEscapeInByte);
+ check(r"\u{DAAA}", EscapeError::UnicodeEscapeInByte);
+ check(r"\u{DBFF}", EscapeError::UnicodeEscapeInByte);
+ }
+
+ #[test]
+ fn test_unescape_byte_good() {
+ fn check(literal_text: &str, expected_byte: u8) {
+ let actual_result = unescape_byte(literal_text);
+ assert_eq!(actual_result, Ok(expected_byte));
+ }
+
+ check("a", b'a');
+
+ check(r#"\""#, b'"');
+ check(r"\n", b'\n');
+ check(r"\r", b'\r');
+ check(r"\t", b'\t');
+ check(r"\\", b'\\');
+ check(r"\'", b'\'');
+ check(r"\0", b'\0');
+
+ check(r"\x00", b'\0');
+ check(r"\x5a", b'Z');
+ check(r"\x5A", b'Z');
+ check(r"\x7f", 127);
+ check(r"\x80", 128);
+ check(r"\xff", 255);
+ check(r"\xFF", 255);
+ }
+
+ #[test]
+ fn test_unescape_byte_str_good() {
+ fn check(literal_text: &str, expected: &[u8]) {
+ let mut buf = Ok(Vec::with_capacity(literal_text.len()));
+ unescape_byte_str(literal_text, &mut |range, c| {
+ if let Ok(b) = &mut buf {
+ match c {
+ Ok(c) => b.push(c),
+ Err(e) => buf = Err((range, e)),
+ }
+ }
+ });
+ let buf = buf.as_ref().map(|it| it.as_ref());
+ assert_eq!(buf, Ok(expected))
+ }
+
+ check("foo", b"foo");
+ check("", b"");
+ check(" \t\n\r\n", b" \t\n\n");
+
+ check("hello \\\n world", b"hello world");
+ check("hello \\\r\n world", b"hello world");
+ check("thread's", b"thread's")
+ }
+
+ #[test]
+ fn test_unescape_raw_str() {
+ fn check(literal: &str, expected: &[(Range<usize>, Result<char, EscapeError>)]) {
+ let mut unescaped = Vec::with_capacity(literal.len());
+ unescape_raw_str(literal, &mut |range, res| unescaped.push((range, res)));
+ assert_eq!(unescaped, expected);
+ }
+
+ check("\r\n", &[(0..2, Ok('\n'))]);
+ check("\r", &[(0..1, Err(EscapeError::BareCarriageReturnInRawString))]);
+ check("\rx", &[(0..1, Err(EscapeError::BareCarriageReturnInRawString)), (1..2, Ok('x'))]);
+ }
+
+ #[test]
+ fn test_unescape_raw_byte_str() {
+ fn check(literal: &str, expected: &[(Range<usize>, Result<u8, EscapeError>)]) {
+ let mut unescaped = Vec::with_capacity(literal.len());
+ unescape_raw_byte_str(literal, &mut |range, res| unescaped.push((range, res)));
+ assert_eq!(unescaped, expected);
+ }
+
+ check("\r\n", &[(0..2, Ok(byte_from_char('\n')))]);
+ check("\r", &[(0..1, Err(EscapeError::BareCarriageReturnInRawString))]);
+ check("🦀", &[(0..4, Err(EscapeError::NonAsciiCharInByteString))]);
+ check(
+ "🦀a",
+ &[(0..4, Err(EscapeError::NonAsciiCharInByteString)), (4..5, Ok(byte_from_char('a')))],
+ );
+ }
+}
let is_partial_move = move_site_vec.iter().any(|move_site| {
let move_out = self.move_data.moves[(*move_site).moi];
let moved_place = &self.move_data.move_paths[move_out.path].place;
- used_place != moved_place.as_place_ref()
- && used_place.is_prefix_of(moved_place.as_place_ref())
+ used_place != moved_place.as_ref()
+ && used_place.is_prefix_of(moved_place.as_ref())
});
for move_site in &move_site_vec {
let move_out = self.move_data.moves[(*move_site).moi];
let moved_place = &self.move_data.move_paths[move_out.path].place;
- let move_spans = self.move_spans(moved_place.as_place_ref(), move_out.source);
+ let move_spans = self.move_spans(moved_place.as_ref(), move_out.source);
let move_span = move_spans.args_or_use();
let move_msg = if move_spans.for_closure() {
let ty = place.ty(self.body, self.infcx.tcx).ty;
let opt_name =
- self.describe_place_with_options(place.as_place_ref(), IncludingDowncast(true));
+ self.describe_place_with_options(place.as_ref(), IncludingDowncast(true));
let note_msg = match opt_name {
Some(ref name) => format!("`{}`", name),
None => "value".to_owned(),
"report_move_out_while_borrowed: location={:?} place={:?} span={:?} borrow={:?}",
location, place, span, borrow
);
- let value_msg = match self.describe_place(place.as_place_ref()) {
+ let value_msg = match self.describe_place(place.as_ref()) {
Some(name) => format!("`{}`", name),
None => "value".to_owned(),
};
- let borrow_msg = match self.describe_place(borrow.borrowed_place.as_place_ref()) {
+ let borrow_msg = match self.describe_place(borrow.borrowed_place.as_ref()) {
Some(name) => format!("`{}`", name),
None => "value".to_owned(),
};
let borrow_spans = self.retrieve_borrow_spans(borrow);
let borrow_span = borrow_spans.args_or_use();
- let move_spans = self.move_spans(place.as_place_ref(), location);
+ let move_spans = self.move_spans(place.as_ref(), location);
let span = move_spans.args_or_use();
let mut err = self.cannot_move_when_borrowed(
span,
- &self.describe_place(place.as_place_ref()).unwrap_or_else(|| "_".to_owned()),
+ &self.describe_place(place.as_ref()).unwrap_or_else(|| "_".to_owned()),
);
err.span_label(borrow_span, format!("borrow of {} occurs here", borrow_msg));
err.span_label(span, format!("move out of {} occurs here", value_msg));
// Conflicting borrows are reported separately, so only check for move
// captures.
- let use_spans = self.move_spans(place.as_place_ref(), location);
+ let use_spans = self.move_spans(place.as_ref(), location);
let span = use_spans.var_or_use();
let mut err = self.cannot_use_when_mutably_borrowed(
span,
- &self.describe_place(place.as_place_ref()).unwrap_or_else(|| "_".to_owned()),
+ &self.describe_place(place.as_ref()).unwrap_or_else(|| "_".to_owned()),
borrow_span,
- &self.describe_place(borrow.borrowed_place.as_place_ref())
+ &self.describe_place(borrow.borrowed_place.as_ref())
.unwrap_or_else(|| "_".to_owned()),
);
borrow_spans.var_span_label(&mut err, {
let place = &borrow.borrowed_place;
let desc_place =
- self.describe_place(place.as_place_ref()).unwrap_or_else(|| "_".to_owned());
+ self.describe_place(place.as_ref()).unwrap_or_else(|| "_".to_owned());
format!("borrow occurs due to use of `{}`{}", desc_place, borrow_spans.describe())
});
);
} else {
let borrow_place = &issued_borrow.borrowed_place;
- let borrow_place_desc = self.describe_place(borrow_place.as_place_ref())
+ let borrow_place_desc = self.describe_place(borrow_place.as_ref())
.unwrap_or_else(|| "_".to_owned());
issued_spans.var_span_label(
&mut err,
return Some((
describe_base_place,
- describe_place(first_borrowed_place.as_place_ref()),
- describe_place(second_borrowed_place.as_place_ref()),
+ describe_place(first_borrowed_place.as_ref()),
+ describe_place(second_borrowed_place.as_ref()),
union_ty.to_string(),
));
}
// If we didn't find a field access into a union, or both places match, then
// only return the description of the first place.
(
- describe_place(first_borrowed_place.as_place_ref()),
+ describe_place(first_borrowed_place.as_ref()),
"".to_string(),
"".to_string(),
"".to_string(),
);
let drop_span = place_span.1;
- let root_place = self.prefixes(borrow.borrowed_place.as_place_ref(), PrefixSet::All)
+ let root_place = self.prefixes(borrow.borrowed_place.as_ref(), PrefixSet::All)
.last()
.unwrap();
}, borrow_span));
if let StorageDeadOrDrop::Destructor(dropped_ty) =
- self.classify_drop_access_kind(borrow.borrowed_place.as_place_ref())
+ self.classify_drop_access_kind(borrow.borrowed_place.as_ref())
{
// If a borrow of path `B` conflicts with drop of `D` (and
// we're not in the uninteresting case where `B` is a
// prefix of `D`), then report this as a more interesting
// destructor conflict.
- if !borrow.borrowed_place.as_place_ref().is_prefix_of(place_span.0.as_place_ref()) {
+ if !borrow.borrowed_place.as_ref().is_prefix_of(place_span.0.as_ref()) {
self.report_borrow_conflicts_with_destructor(
location, borrow, place_span, kind, dropped_ty,
);
}
}
- let place_desc = self.describe_place(borrow.borrowed_place.as_place_ref());
+ let place_desc = self.describe_place(borrow.borrowed_place.as_ref());
let kind_place = kind.filter(|_| place_desc.is_some()).map(|k| (k, place_span.0));
let explanation = self.explain_why_borrow_contains_point(location, &borrow, kind_place);
let mut err = self.cannot_borrow_across_destructor(borrow_span);
- let what_was_dropped = match self.describe_place(place.as_place_ref()) {
+ let what_was_dropped = match self.describe_place(place.as_ref()) {
Some(name) => format!("`{}`", name.as_str()),
None => String::from("temporary value"),
};
- let label = match self.describe_place(borrow.borrowed_place.as_place_ref()) {
+ let label = match self.describe_place(borrow.borrowed_place.as_ref()) {
Some(borrowed) => format!(
"here, drop of {D} needs exclusive access to `{B}`, \
because the type `{T}` implements the `Drop` trait",
format!("`{}` is borrowed here", place_desc),
)
} else {
- let root_place = self.prefixes(borrow.borrowed_place.as_place_ref(),
+ let root_place = self.prefixes(borrow.borrowed_place.as_ref(),
PrefixSet::All)
.last()
.unwrap();
let mut err = self.cannot_mutate_in_match_guard(
span,
loan_span,
- &self.describe_place(place.as_place_ref()).unwrap_or_else(|| "_".to_owned()),
+ &self.describe_place(place.as_ref()).unwrap_or_else(|| "_".to_owned()),
"assign",
);
loan_spans.var_span_label(
let mut err = self.cannot_assign_to_borrowed(
span,
loan_span,
- &self.describe_place(place.as_place_ref()).unwrap_or_else(|| "_".to_owned()),
+ &self.describe_place(place.as_ref()).unwrap_or_else(|| "_".to_owned()),
);
loan_spans.var_span_label(
is_user_variable: None,
..
})
- | None => (self.describe_place(place.as_place_ref()), assigned_span),
- Some(decl) => (self.describe_place(err_place.as_place_ref()), decl.source_info.span),
+ | None => (self.describe_place(place.as_ref()), assigned_span),
+ Some(decl) => (self.describe_place(err_place.as_ref()), decl.source_info.span),
};
let mut err = self.cannot_reassign_immutable(
def_id, is_generator, places
);
if let Some((args_span, var_span)) = self.closure_span(
- *def_id, Place::from(target).as_place_ref(), places
+ *def_id, Place::from(target).as_ref(), places
) {
return ClosureUse {
is_generator,
for (upvar, place) in self.infcx.tcx.upvars(def_id)?.values().zip(places) {
match place {
Operand::Copy(place) |
- Operand::Move(place) if target_place == place.as_place_ref() => {
+ Operand::Move(place) if target_place == place.as_ref() => {
debug!("closure_span: found captured local {:?}", place);
return Some((*args_span, upvar.span));
},
self.check_if_path_or_subpath_is_moved(
location,
InitializationRequiringAction::Use,
- (place.as_place_ref(), span),
+ (place.as_ref(), span),
flow_state,
);
}
self.check_if_path_or_subpath_is_moved(
location,
InitializationRequiringAction::Use,
- (output.as_place_ref(), o.span),
+ (output.as_ref(), o.span),
flow_state,
);
} else {
cleanup: _,
} => {
self.consume_operand(loc, (cond, span), flow_state);
- use rustc::mir::interpret::InterpError::BoundsCheck;
- if let BoundsCheck { ref len, ref index } = *msg {
+ use rustc::mir::interpret::{InterpError::Panic, PanicMessage};
+ if let Panic(PanicMessage::BoundsCheck { ref len, ref index }) = *msg {
self.consume_operand(loc, (len, span), flow_state);
self.consume_operand(loc, (index, span), flow_state);
}
self.check_if_path_or_subpath_is_moved(
location,
InitializationRequiringAction::Update,
- (place_span.0.as_place_ref(), place_span.1),
+ (place_span.0.as_ref(), place_span.1),
flow_state,
);
}
self.check_if_path_or_subpath_is_moved(
location,
action,
- (place.as_place_ref(), span),
+ (place.as_ref(), span),
flow_state,
);
}
self.check_if_path_or_subpath_is_moved(
location,
InitializationRequiringAction::Use,
- (place.as_place_ref(), span),
+ (place.as_ref(), span),
flow_state,
);
}
fn propagate_closure_used_mut_upvar(&mut self, operand: &Operand<'tcx>) {
let propagate_closure_used_mut_place = |this: &mut Self, place: &Place<'tcx>| {
if place.projection.is_some() {
- if let Some(field) = this.is_upvar_field_projection(place.as_place_ref()) {
+ if let Some(field) = this.is_upvar_field_projection(place.as_ref()) {
this.used_mut_upvars.push(field);
}
} else if let PlaceBase::Local(local) = place.base {
self.check_if_path_or_subpath_is_moved(
location,
InitializationRequiringAction::Use,
- (place.as_place_ref(), span),
+ (place.as_ref(), span),
flow_state,
);
}
self.check_if_path_or_subpath_is_moved(
location,
InitializationRequiringAction::Use,
- (place.as_place_ref(), span),
+ (place.as_ref(), span),
flow_state,
);
}
) {
debug!("check_for_invalidation_at_exit({:?})", borrow);
let place = &borrow.borrowed_place;
- let root_place = self.prefixes(place.as_place_ref(), PrefixSet::All).last().unwrap();
+ let root_place = self.prefixes(place.as_ref(), PrefixSet::All).last().unwrap();
// FIXME(nll-rfc#40): do more precise destructor tracking here. For now
// we just know that all locals are dropped at function exit (otherwise
}
}
- let move_spans = self.move_spans(original_path.as_place_ref(), location);
+ let move_spans = self.move_spans(original_path.as_ref(), location);
grouped_errors.push(GroupedMoveError::OtherIllegalMove {
use_spans: move_spans,
original_path,
let from_simple_let = match_place.is_none();
let match_place = match_place.as_ref().unwrap_or(move_from);
- match self.move_data.rev_lookup.find(match_place.as_place_ref()) {
+ match self.move_data.rev_lookup.find(match_place.as_ref()) {
// Error with the match place
LookupResult::Parent(_) => {
for ge in &mut *grouped_errors {
}
// Error with the pattern
LookupResult::Exact(_) => {
- let mpi = match self.move_data.rev_lookup.find(move_from.as_place_ref()) {
+ let mpi = match self.move_data.rev_lookup.find(move_from.as_ref()) {
LookupResult::Parent(Some(mpi)) => mpi,
// move_from should be a projection from match_place.
_ => unreachable!("Probably not unreachable..."),
};
debug!("report: original_path={:?} span={:?}, kind={:?} \
original_path.is_upvar_field_projection={:?}", original_path, span, kind,
- self.is_upvar_field_projection(original_path.as_place_ref()));
+ self.is_upvar_field_projection(original_path.as_ref()));
(
match kind {
IllegalMoveOriginKind::Static => {
span: Span
) -> DiagnosticBuilder<'a> {
let description = if place.projection.is_none() {
- format!("static item `{}`", self.describe_place(place.as_place_ref()).unwrap())
+ format!("static item `{}`", self.describe_place(place.as_ref()).unwrap())
} else {
let mut base_static = &place.projection;
while let Some(box Projection { base: Some(ref proj), .. }) = base_static {
format!(
"`{:?}` as `{:?}` is a static item",
- self.describe_place(place.as_place_ref()).unwrap(),
+ self.describe_place(place.as_ref()).unwrap(),
self.describe_place(base_static).unwrap(),
)
};
// borrow to provide feedback about why this
// was a move rather than a copy.
let ty = deref_target_place.ty(self.body, self.infcx.tcx).ty;
- let upvar_field = self.prefixes(move_place.as_place_ref(), PrefixSet::All)
+ let upvar_field = self.prefixes(move_place.as_ref(), PrefixSet::All)
.find_map(|p| self.is_upvar_field_projection(p));
let deref_base = match deref_target_place.projection {
let upvar_name = upvar.name;
let upvar_span = self.infcx.tcx.hir().span(upvar_hir_id);
- let place_name = self.describe_place(move_place.as_place_ref()).unwrap();
+ let place_name = self.describe_place(move_place.as_ref()).unwrap();
let place_description = if self
- .is_upvar_field_projection(move_place.as_place_ref())
+ .is_upvar_field_projection(move_place.as_ref())
.is_some()
{
format!("`{}`, a {}", place_name, capture_description)
_ => {
let source = self.borrowed_content_source(deref_base);
match (
- self.describe_place(move_place.as_place_ref()),
+ self.describe_place(move_place.as_ref()),
source.describe_for_named_place(),
) {
(Some(place_desc), Some(source_desc)) => {
if binds_to.is_empty() {
let place_ty = move_from.ty(self.body, self.infcx.tcx).ty;
- let place_desc = match self.describe_place(move_from.as_place_ref()) {
+ let place_desc = match self.describe_place(move_from.as_ref()) {
Some(desc) => format!("`{}`", desc),
None => format!("value"),
};
GroupedMoveError::OtherIllegalMove { ref original_path, use_spans, .. } => {
let span = use_spans.var_or_use();
let place_ty = original_path.ty(self.body, self.infcx.tcx).ty;
- let place_desc = match self.describe_place(original_path.as_place_ref()) {
+ let place_desc = match self.describe_place(original_path.as_ref()) {
Some(desc) => format!("`{}`", desc),
None => format!("value"),
};
let item_msg;
let reason;
let mut opt_source = None;
- let access_place_desc = self.describe_place(access_place.as_place_ref());
+ let access_place_desc = self.describe_place(access_place.as_ref());
debug!("report_mutability_error: access_place_desc={:?}", access_place_desc);
match the_place_err {
));
item_msg = format!("`{}`", access_place_desc.unwrap());
- if self.is_upvar_field_projection(access_place.as_place_ref()).is_some() {
+ if self.is_upvar_field_projection(access_place.as_ref()).is_some() {
reason = ", as it is not declared as mutable".to_string();
} else {
let name = self.upvars[upvar_index.index()].name;
));
reason =
- if self.is_upvar_field_projection(access_place.as_place_ref()).is_some() {
+ if self.is_upvar_field_projection(access_place.as_ref()).is_some() {
", as it is a captured variable in a `Fn` closure".to_string()
} else {
", as `Fn` closures cannot mutate their captured variables".to_string()
format!(
"mutable borrow occurs due to use of `{}` in closure",
// always Some() if the message is printed.
- self.describe_place(access_place.as_place_ref()).unwrap_or_default(),
+ self.describe_place(access_place.as_ref()).unwrap_or_default(),
)
);
borrow_span
Some(Cause::LiveVar(local, location)) => {
let span = body.source_info(location).span;
let spans = self
- .move_spans(Place::from(local).as_place_ref(), location)
+ .move_spans(Place::from(local).as_ref(), location)
.or_else(|| self.borrow_spans(span, location));
let borrow_location = location;
);
if let Some(region_name) = region_name {
let opt_place_desc =
- self.describe_place(borrow.borrowed_place.as_place_ref());
+ self.describe_place(borrow.borrowed_place.as_ref());
BorrowExplanation::MustBeValidFor {
category,
from_closure,
cleanup: _,
} => {
self.consume_operand(location, cond);
- use rustc::mir::interpret::InterpError::BoundsCheck;
- if let BoundsCheck { ref len, ref index } = *msg {
+ use rustc::mir::interpret::{InterpError::Panic, PanicMessage::BoundsCheck};
+ if let Panic(BoundsCheck { ref len, ref index }) = *msg {
self.consume_operand(location, len);
self.consume_operand(location, index);
}
use rustc::infer::outlives::env::RegionBoundPairs;
use rustc::infer::{InferCtxt, InferOk, LateBoundRegionConversionTime, NLLRegionVariableOrigin};
use rustc::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
-use rustc::mir::interpret::{InterpError::BoundsCheck, ConstValue};
+use rustc::mir::interpret::{InterpError::Panic, ConstValue, PanicMessage};
use rustc::mir::tcx::PlaceTy;
use rustc::mir::visit::{PlaceContext, Visitor, NonMutatingUseContext};
use rustc::mir::*;
span_mirbug!(self, term, "bad Assert ({:?}, not bool", cond_ty);
}
- if let BoundsCheck { ref len, ref index } = *msg {
+ if let Panic(PanicMessage::BoundsCheck { ref len, ref index }) = *msg {
if len.ty(body, tcx) != tcx.types.usize {
span_mirbug!(self, len, "bounds-check length non-usize {:?}", len)
}
body,
&borrowed.borrowed_place,
borrowed.kind,
- place.as_place_ref(),
+ place.as_ref(),
access,
places_conflict::PlaceConflictBias::Overlap,
) {
body,
borrow_place,
BorrowKind::Mut { allow_two_phase_borrow: true },
- access_place.as_place_ref(),
+ access_place.as_ref(),
AccessDepth::Deep,
bias,
)
use crate::build::ForGuard::{OutsideGuard, RefWithinGuard};
use crate::build::{BlockAnd, BlockAndExtension, Builder};
use crate::hair::*;
-use rustc::mir::interpret::InterpError::BoundsCheck;
+use rustc::mir::interpret::{InterpError::Panic, PanicMessage::BoundsCheck};
use rustc::mir::*;
use rustc::ty::{CanonicalUserTypeAnnotation, Variance};
),
);
- let msg = BoundsCheck {
+ let msg = Panic(BoundsCheck {
len: Operand::Move(len),
index: Operand::Copy(Place::from(idx)),
- };
+ });
let success = this.assert(block, Operand::Move(lt), true, msg, expr_span);
success.and(slice.index(idx))
}
use crate::build::{BlockAnd, BlockAndExtension, Builder};
use crate::hair::*;
use rustc::middle::region;
-use rustc::mir::interpret::InterpError;
+use rustc::mir::interpret::{InterpError::Panic, PanicMessage};
use rustc::mir::*;
use rustc::ty::{self, CanonicalUserTypeAnnotation, Ty, UpvarSubsts};
use syntax_pos::Span;
block,
Operand::Move(is_min),
false,
- InterpError::OverflowNeg,
+ Panic(PanicMessage::OverflowNeg),
expr_span,
);
}
let val = result_value.clone().field(val_fld, ty);
let of = result_value.field(of_fld, bool_ty);
- let err = InterpError::Overflow(op);
+ let err = Panic(PanicMessage::Overflow(op));
block = self.assert(block, Operand::Move(of), false, err, span);
// and 2. there are two possible failure cases, divide-by-zero and overflow.
let (zero_err, overflow_err) = if op == BinOp::Div {
- (InterpError::DivisionByZero, InterpError::Overflow(op))
+ (Panic(PanicMessage::DivisionByZero), Panic(PanicMessage::Overflow(op)))
} else {
- (InterpError::RemainderByZero, InterpError::Overflow(op))
+ (Panic(PanicMessage::RemainderByZero), Panic(PanicMessage::Overflow(op)))
};
// Check for / 0
prefix_cursor = base;
}
- all_fake_borrows.push(place.as_place_ref());
+ all_fake_borrows.push(place.as_ref());
}
// Deduplicate and ensure a deterministic order.
let move_data = &ctxt.move_data;
for arg in body.args_iter() {
let place = mir::Place::from(arg);
- let lookup_result = move_data.rev_lookup.find(place.as_place_ref());
+ let lookup_result = move_data.rev_lookup.find(place.as_ref());
on_lookup_result_bits(tcx, body, move_data,
lookup_result,
|mpi| callback(mpi, DropFlagState::Present));
// when a call returns successfully, that means we need to set
// the bits for that dest_place to 1 (initialized).
on_lookup_result_bits(self.tcx, self.body, self.move_data(),
- self.move_data().rev_lookup.find(dest_place.as_place_ref()),
+ self.move_data().rev_lookup.find(dest_place.as_ref()),
|mpi| { in_out.insert(mpi); });
}
}
// when a call returns successfully, that means we need to set
// the bits for that dest_place to 0 (initialized).
on_lookup_result_bits(self.tcx, self.body, self.move_data(),
- self.move_data().rev_lookup.find(dest_place.as_place_ref()),
+ self.move_data().rev_lookup.find(dest_place.as_ref()),
|mpi| { in_out.remove(mpi); });
}
}
// when a call returns successfully, that means we need to set
// the bits for that dest_place to 1 (initialized).
on_lookup_result_bits(self.tcx, self.body, self.move_data(),
- self.move_data().rev_lookup.find(dest_place.as_place_ref()),
+ self.move_data().rev_lookup.find(dest_place.as_ref()),
|mpi| { in_out.insert(mpi); });
}
}
// move-path for the interior so it will be separate from
// the exterior.
self.create_move_path(&place.clone().deref());
- self.gather_init(place.as_place_ref(), InitKind::Shallow);
+ self.gather_init(place.as_ref(), InitKind::Shallow);
} else {
- self.gather_init(place.as_place_ref(), InitKind::Deep);
+ self.gather_init(place.as_ref(), InitKind::Deep);
}
self.gather_rvalue(rval);
}
StatementKind::InlineAsm(ref asm) => {
for (output, kind) in asm.outputs.iter().zip(&asm.asm.outputs) {
if !kind.is_indirect {
- self.gather_init(output.as_place_ref(), InitKind::Deep);
+ self.gather_init(output.as_ref(), InitKind::Deep);
}
}
for (_, input) in asm.inputs.iter() {
TerminatorKind::DropAndReplace { ref location, ref value, .. } => {
self.create_move_path(location);
self.gather_operand(value);
- self.gather_init(location.as_place_ref(), InitKind::Deep);
+ self.gather_init(location.as_ref(), InitKind::Deep);
}
TerminatorKind::Call {
ref func,
}
if let Some((ref destination, _bb)) = *destination {
self.create_move_path(destination);
- self.gather_init(destination.as_place_ref(), InitKind::NonPanicPathOnly);
+ self.gather_init(destination.as_ref(), InitKind::NonPanicPathOnly);
}
}
}
use rustc::ty::layout::{LayoutOf, Primitive, Size};
use rustc::mir::BinOp;
use rustc::mir::interpret::{
- InterpResult, InterpError, Scalar,
+ InterpResult, InterpError, Scalar, PanicMessage,
};
use super::{
let file = Symbol::intern(self.read_str(file_place)?);
let line = self.read_scalar(line.into())?.to_u32()?;
let col = self.read_scalar(col.into())?.to_u32()?;
- return Err(InterpError::Panic { msg, file, line, col }.into());
+ return Err(InterpError::Panic(PanicMessage::Panic { msg, file, line, col }).into());
} else if Some(def_id) == self.tcx.lang_items().begin_panic_fn() {
assert!(args.len() == 2);
// &'static str, &(&'static str, u32, u32)
let file = Symbol::intern(self.read_str(file_place)?);
let line = self.read_scalar(line.into())?.to_u32()?;
let col = self.read_scalar(col.into())?.to_u32()?;
- return Err(InterpError::Panic { msg, file, line, col }.into());
+ return Err(InterpError::Panic(PanicMessage::Panic { msg, file, line, col }).into());
} else {
return Ok(false);
}
use rustc::ty::{self, layout::TyLayout};
use syntax::ast::FloatTy;
use rustc_apfloat::Float;
-use rustc::mir::interpret::{InterpResult, Scalar};
+use rustc::mir::interpret::{InterpResult, PanicMessage, Scalar};
use super::{InterpCx, PlaceTy, Immediate, Machine, ImmTy};
return Ok((Scalar::from_bool(op(&l, &r)), false));
}
let op: Option<fn(i128, i128) -> (i128, bool)> = match bin_op {
- Div if r == 0 => return err!(DivisionByZero),
- Rem if r == 0 => return err!(RemainderByZero),
+ Div if r == 0 => return err!(Panic(PanicMessage::DivisionByZero)),
+ Rem if r == 0 => return err!(Panic(PanicMessage::RemainderByZero)),
Div => Some(i128::overflowing_div),
Rem => Some(i128::overflowing_rem),
Add => Some(i128::overflowing_add),
Add => u128::overflowing_add,
Sub => u128::overflowing_sub,
Mul => u128::overflowing_mul,
- Div if r == 0 => return err!(DivisionByZero),
- Rem if r == 0 => return err!(RemainderByZero),
+ Div if r == 0 => return err!(Panic(PanicMessage::DivisionByZero)),
+ Rem if r == 0 => return err!(Panic(PanicMessage::RemainderByZero)),
Div => u128::overflowing_div,
Rem => u128::overflowing_rem,
_ => bug!(),
use super::{
GlobalId, AllocId, Allocation, Scalar, InterpResult, Pointer, PointerArithmetic,
- InterpCx, Machine, AllocMap, AllocationExtra,
+ InterpCx, Machine, AllocMap, AllocationExtra, PanicMessage,
RawConst, Immediate, ImmTy, ScalarMaybeUndef, Operand, OpTy, MemoryKind, LocalValue
};
// This can be violated because this runs during promotion on code where the
// type system has not yet ensured that such things don't happen.
debug!("tried to access element {} of array/slice with length {}", field, len);
- return err!(BoundsCheck { len, index: field });
+ return err!(Panic(PanicMessage::BoundsCheck { len, index: field }));
}
stride * field
}
use rustc_target::spec::abi::Abi;
use super::{
- InterpResult, PointerArithmetic, InterpError, Scalar,
+ InterpResult, PointerArithmetic, InterpError, Scalar, PanicMessage,
InterpCx, Machine, Immediate, OpTy, ImmTy, PlaceTy, MPlaceTy, StackPopCleanup, FnVal,
};
// Compute error message
use rustc::mir::interpret::InterpError::*;
return match *msg {
- BoundsCheck { ref len, ref index } => {
+ Panic(PanicMessage::BoundsCheck { ref len, ref index }) => {
let len = self.read_immediate(self.eval_operand(len, None)?)
.expect("can't eval len").to_scalar()?
.to_bits(self.memory().pointer_size())? as u64;
let index = self.read_immediate(self.eval_operand(index, None)?)
.expect("can't eval index").to_scalar()?
.to_bits(self.memory().pointer_size())? as u64;
- err!(BoundsCheck { len, index })
+ err!(Panic(PanicMessage::BoundsCheck { len, index }))
}
- Overflow(op) => Err(Overflow(op).into()),
- OverflowNeg => Err(OverflowNeg.into()),
- DivisionByZero => Err(DivisionByZero.into()),
- RemainderByZero => Err(RemainderByZero.into()),
+ Panic(PanicMessage::Overflow(op)) =>
+ Err(Panic(PanicMessage::Overflow(op)).into()),
+ Panic(PanicMessage::OverflowNeg) =>
+ Err(Panic(PanicMessage::OverflowNeg).into()),
+ Panic(PanicMessage::DivisionByZero) =>
+ Err(Panic(PanicMessage::DivisionByZero).into()),
+ Panic(PanicMessage::RemainderByZero) =>
+ Err(Panic(PanicMessage::RemainderByZero).into()),
GeneratorResumedAfterReturn |
GeneratorResumedAfterPanic => unimplemented!(),
_ => bug!(),
let needs_retag = |place: &Place<'tcx>| {
// FIXME: Instead of giving up for unstable places, we should introduce
// a temporary and retag on that.
- is_stable(place.as_place_ref())
+ is_stable(place.as_ref())
&& may_have_reference(place.ty(&*local_decls, tcx).ty, tcx)
};
use rustc::mir::visit::{
Visitor, PlaceContext, MutatingUseContext, MutVisitor, NonMutatingUseContext,
};
-use rustc::mir::interpret::{InterpError, Scalar, GlobalId, InterpResult};
+use rustc::mir::interpret::{InterpError::Panic, Scalar, GlobalId, InterpResult, PanicMessage};
use rustc::ty::{self, Instance, ParamEnv, Ty, TyCtxt};
use syntax_pos::{Span, DUMMY_SP};
use rustc::ty::subst::InternalSubsts;
// FIXME: implement
=> {},
- | Panic { .. }
- | BoundsCheck{..}
- | Overflow(_)
- | OverflowNeg
- | DivisionByZero
- | RemainderByZero
+ | Panic(_)
=> {
diagnostic.report_as_lint(
self.ecx.tcx,
// Need to do overflow check here: For actual CTFE, MIR
// generation emits code that does this before calling the op.
if prim.to_bits()? == (1 << (prim.layout.size.bits() - 1)) {
- return err!(OverflowNeg);
+ return err!(Panic(PanicMessage::OverflowNeg));
}
}
UnOp::Not => {
)
} else {
if overflow {
- let err = InterpError::Overflow(op).into();
+ let err = Panic(PanicMessage::Overflow(op)).into();
let _: Option<()> = self.use_ecx(source_info, |_| Err(err));
return None;
}
.expect("some part of a failing const eval must be local");
use rustc::mir::interpret::InterpError::*;
let msg = match msg {
- Overflow(_) |
- OverflowNeg |
- DivisionByZero |
- RemainderByZero => msg.description().to_owned(),
- BoundsCheck { ref len, ref index } => {
+ Panic(PanicMessage::Overflow(_)) |
+ Panic(PanicMessage::OverflowNeg) |
+ Panic(PanicMessage::DivisionByZero) |
+ Panic(PanicMessage::RemainderByZero) => msg.description().to_owned(),
+ Panic(PanicMessage::BoundsCheck { ref len, ref index }) => {
let len = self
.eval_operand(len, source_info)
.expect("len must be const");
init_data.apply_location(tcx, body, env, loc);
}
- let path = match env.move_data.rev_lookup.find(location.as_place_ref()) {
+ let path = match env.move_data.rev_lookup.find(location.as_ref()) {
LookupResult::Exact(e) => e,
LookupResult::Parent(..) => {
debug!("find_dead_unwinds: has parent; skipping");
statement_index: data.statements.len()
});
- let path = self.move_data().rev_lookup.find(location.as_place_ref());
+ let path = self.move_data().rev_lookup.find(location.as_ref());
debug!("collect_drop_flags: {:?}, place {:?} ({:?})",
bb, location, path);
match terminator.kind {
TerminatorKind::Drop { ref location, target, unwind } => {
let init_data = self.initialization_data_at(loc);
- match self.move_data().rev_lookup.find(location.as_place_ref()) {
+ match self.move_data().rev_lookup.find(location.as_ref()) {
LookupResult::Exact(path) => {
elaborate_drop(
&mut Elaborator {
is_cleanup: false,
});
- match self.move_data().rev_lookup.find(location.as_place_ref()) {
+ match self.move_data().rev_lookup.find(location.as_ref()) {
LookupResult::Exact(path) => {
debug!("elaborate_drop_and_replace({:?}) - tracked {:?}", terminator, path);
let init_data = self.initialization_data_at(loc);
assert!(!self.patch.is_patched(bb));
let loc = Location { block: tgt, statement_index: 0 };
- let path = self.move_data().rev_lookup.find(place.as_place_ref());
+ let path = self.move_data().rev_lookup.find(place.as_ref());
on_lookup_result_bits(
self.tcx, self.body, self.move_data(), path,
|child| self.set_drop_flag(loc, child, DropFlagState::Present)
assert!(!self.patch.is_patched(bb));
let loc = Location { block: bb, statement_index: data.statements.len() };
- let path = self.move_data().rev_lookup.find(place.as_place_ref());
+ let path = self.move_data().rev_lookup.find(place.as_ref());
on_lookup_result_bits(
self.tcx, self.body, self.move_data(), path,
|child| self.set_drop_flag(loc, child, DropFlagState::Present)
fn in_operand(cx: &ConstCx<'_, 'tcx>, operand: &Operand<'tcx>) -> bool {
match *operand {
Operand::Copy(ref place) |
- Operand::Move(ref place) => Self::in_place(cx, place.as_place_ref()),
+ Operand::Move(ref place) => Self::in_place(cx, place.as_ref()),
Operand::Constant(ref constant) => {
if let ConstValue::Unevaluated(def_id, _) = constant.literal.val {
Rvalue::NullaryOp(..) => false,
Rvalue::Discriminant(ref place) |
- Rvalue::Len(ref place) => Self::in_place(cx, place.as_place_ref()),
+ Rvalue::Len(ref place) => Self::in_place(cx, place.as_ref()),
Rvalue::Use(ref operand) |
Rvalue::Repeat(ref operand, _) |
}
}
- Self::in_place(cx, place.as_place_ref())
+ Self::in_place(cx, place.as_ref())
}
Rvalue::Aggregate(_, ref operands) => {
if place == peek_arg_place {
if let mir::Rvalue::Ref(_, mir::BorrowKind::Shared, ref peeking_at_place) = **rvalue {
// Okay, our search is over.
- match move_data.rev_lookup.find(peeking_at_place.as_place_ref()) {
+ match move_data.rev_lookup.find(peeking_at_place.as_ref()) {
LookupResult::Exact(peek_mpi) => {
let bit_state = on_entry.contains(peek_mpi);
debug!("rustc_peek({:?} = &{:?}) bit_state: {}",
}
}
- let lhs_mpi = move_data.rev_lookup.find(place.as_place_ref());
+ let lhs_mpi = move_data.rev_lookup.find(place.as_ref());
debug!("rustc_peek: computing effect on place: {:?} ({:?}) in stmt: {:?}",
place, lhs_mpi, stmt);
base.cpu = "x86-64".to_string();
base.max_atomic_width = Some(64);
base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-mx32".to_string());
- // BUG: temporarily workaround #59674
- base.stack_probes = false;
+ base.stack_probes = true;
base.has_elf_tls = false;
// BUG(GabrielMajeri): disabling the PLT on x86_64 Linux with x32 ABI
// breaks code gen. See LLVM bug 36743
Applicability::MaybeIncorrect,
);
} else {
- err.span_label(span, format!("variant not found in `{}`", qself_ty));
+ err.span_label(
+ assoc_ident.span,
+ format!("variant not found in `{}`", qself_ty),
+ );
}
if let Some(sp) = tcx.hir().span_if_local(adt_def.did) {
fn primary_body_of(
tcx: TyCtxt<'_>,
id: hir::HirId,
-) -> Option<(hir::BodyId, Option<&hir::FnHeader>, Option<&hir::FnDecl>)> {
+) -> Option<(hir::BodyId, Option<&hir::Ty>, Option<&hir::FnHeader>, Option<&hir::FnDecl>)> {
match tcx.hir().get(id) {
Node::Item(item) => {
match item.node {
- hir::ItemKind::Const(_, body) |
- hir::ItemKind::Static(_, _, body) =>
- Some((body, None, None)),
+ hir::ItemKind::Const(ref ty, body) |
+ hir::ItemKind::Static(ref ty, _, body) =>
+ Some((body, Some(ty), None, None)),
hir::ItemKind::Fn(ref decl, ref header, .., body) =>
- Some((body, Some(header), Some(decl))),
+ Some((body, None, Some(header), Some(decl))),
_ =>
None,
}
}
Node::TraitItem(item) => {
match item.node {
- hir::TraitItemKind::Const(_, Some(body)) =>
- Some((body, None, None)),
+ hir::TraitItemKind::Const(ref ty, Some(body)) =>
+ Some((body, Some(ty), None, None)),
hir::TraitItemKind::Method(ref sig, hir::TraitMethod::Provided(body)) =>
- Some((body, Some(&sig.header), Some(&sig.decl))),
+ Some((body, None, Some(&sig.header), Some(&sig.decl))),
_ =>
None,
}
}
Node::ImplItem(item) => {
match item.node {
- hir::ImplItemKind::Const(_, body) =>
- Some((body, None, None)),
+ hir::ImplItemKind::Const(ref ty, body) =>
+ Some((body, Some(ty), None, None)),
hir::ImplItemKind::Method(ref sig, body) =>
- Some((body, Some(&sig.header), Some(&sig.decl))),
+ Some((body, None, Some(&sig.header), Some(&sig.decl))),
_ =>
None,
}
}
- Node::AnonConst(constant) => Some((constant.body, None, None)),
+ Node::AnonConst(constant) => Some((constant.body, None, None, None)),
_ => None,
}
}
let span = tcx.hir().span(id);
// Figure out what primary body this item has.
- let (body_id, fn_header, fn_decl) = primary_body_of(tcx, id)
+ let (body_id, body_ty, fn_header, fn_decl) = primary_body_of(tcx, id)
.unwrap_or_else(|| {
span_bug!(span, "can't type-check body of {:?}", def_id);
});
fcx
} else {
let fcx = FnCtxt::new(&inh, param_env, body.value.hir_id);
- let expected_type = tcx.type_of(def_id);
+ let expected_type = body_ty.and_then(|ty| match ty.node {
+ hir::TyKind::Infer => Some(AstConv::ast_ty_to_ty(&fcx, ty)),
+ _ => None
+ }).unwrap_or_else(|| tcx.type_of(def_id));
let expected_type = fcx.normalize_associated_types_in(body.value.span, &expected_type);
fcx.require_type_is_sized(expected_type, body.value.span, traits::ConstSized);
checked_type_of(tcx, def_id, true).unwrap()
}
+fn infer_placeholder_type(
+ tcx: TyCtxt<'_>,
+ def_id: DefId,
+ body_id: hir::BodyId,
+ span: Span,
+) -> Ty<'_> {
+ let ty = tcx.typeck_tables_of(def_id).node_type(body_id.hir_id);
+ let mut diag = bad_placeholder_type(tcx, span);
+ if ty != tcx.types.err {
+ diag.span_suggestion(
+ span,
+ "replace `_` with the correct type",
+ ty.to_string(),
+ Applicability::MaybeIncorrect,
+ );
+ }
+ diag.emit();
+ ty
+}
+
/// Same as [`type_of`] but returns [`Option`] instead of failing.
///
/// If you want to fail anyway, you can set the `fail` parameter to true, but in this case,
let substs = InternalSubsts::identity_for_item(tcx, def_id);
tcx.mk_fn_def(def_id, substs)
}
- TraitItemKind::Const(ref ty, _) | TraitItemKind::Type(_, Some(ref ty)) => icx.to_ty(ty),
+ TraitItemKind::Const(ref ty, body_id) => {
+ body_id.and_then(|body_id| {
+ if let hir::TyKind::Infer = ty.node {
+ Some(infer_placeholder_type(tcx, def_id, body_id, ty.span))
+ } else {
+ None
+ }
+ }).unwrap_or_else(|| icx.to_ty(ty))
+ },
+ TraitItemKind::Type(_, Some(ref ty)) => icx.to_ty(ty),
TraitItemKind::Type(_, None) => {
if !fail {
return None;
let substs = InternalSubsts::identity_for_item(tcx, def_id);
tcx.mk_fn_def(def_id, substs)
}
- ImplItemKind::Const(ref ty, _) => icx.to_ty(ty),
+ ImplItemKind::Const(ref ty, body_id) => {
+ if let hir::TyKind::Infer = ty.node {
+ infer_placeholder_type(tcx, def_id, body_id, ty.span)
+ } else {
+ icx.to_ty(ty)
+ }
+ },
ImplItemKind::Existential(_) => {
if tcx
.impl_trait_ref(tcx.hir().get_parent_did(hir_id))
Node::Item(item) => {
match item.node {
- ItemKind::Static(ref t, ..)
- | ItemKind::Const(ref t, _)
- | ItemKind::Ty(ref t, _)
- | ItemKind::Impl(.., ref t, _) => icx.to_ty(t),
+ ItemKind::Static(ref ty, .., body_id)
+ | ItemKind::Const(ref ty, body_id) => {
+ if let hir::TyKind::Infer = ty.node {
+ infer_placeholder_type(tcx, def_id, body_id, ty.span)
+ } else {
+ icx.to_ty(ty)
+ }
+ },
+ ItemKind::Ty(ref ty, _)
+ | ItemKind::Impl(.., ref ty, _) => icx.to_ty(ty),
ItemKind::Fn(..) => {
let substs = InternalSubsts::identity_for_item(tcx, def_id);
tcx.mk_fn_def(def_id, substs)
#![feature(inner_deref)]
#![feature(never_type)]
#![feature(mem_take)]
+#![feature(unicode_internals)]
#![recursion_limit="256"]
// no-tracking-issue-start
+ // Allows using compiler's own crates.
+ (active, rustc_private, "1.0.0", Some(27812), None),
+
// Allows using the `rust-intrinsic`'s "ABI".
(active, intrinsics, "1.0.0", None, None),
self, Arg, BinOpKind, BindingMode, BlockCheckMode, Expr, ExprKind, Ident, Item, ItemKind,
Mutability, Pat, PatKind, PathSegment, QSelf, Ty, TyKind, VariantData,
};
+use crate::feature_gate::{feature_err, UnstableFeatures};
use crate::parse::{SeqSep, PResult, Parser, ParseSess};
use crate::parse::parser::{BlockMode, PathStyle, SemiColonMode, TokenType, TokenExpectType};
use crate::parse::token::{self, TokenKind};
self.token.is_keyword(kw::Return) ||
self.token.is_keyword(kw::While)
);
- let cm = self.sess.source_map();
- match (cm.lookup_line(self.token.span.lo()), cm.lookup_line(sp.lo())) {
+ let sm = self.sess.source_map();
+ match (sm.lookup_line(self.token.span.lo()), sm.lookup_line(sp.lo())) {
(Ok(ref a), Ok(ref b)) if a.line != b.line && is_semi_suggestable => {
// The spans are in different lines, expected `;` and found `let` or `return`.
// High likelihood that it is only a missing `;`.
err.span_label(self.token.span, "unexpected token");
}
}
+ self.maybe_annotate_with_ascription(&mut err, false);
Err(err)
}
+ pub fn maybe_annotate_with_ascription(
+ &self,
+ err: &mut DiagnosticBuilder<'_>,
+ maybe_expected_semicolon: bool,
+ ) {
+ if let Some((sp, likely_path)) = self.last_type_ascription {
+ let sm = self.sess.source_map();
+ let next_pos = sm.lookup_char_pos(self.token.span.lo());
+ let op_pos = sm.lookup_char_pos(sp.hi());
+
+ if likely_path {
+ err.span_suggestion(
+ sp,
+ "maybe write a path separator here",
+ "::".to_string(),
+ match self.sess.unstable_features {
+ UnstableFeatures::Disallow => Applicability::MachineApplicable,
+ _ => Applicability::MaybeIncorrect,
+ },
+ );
+ } else if op_pos.line != next_pos.line && maybe_expected_semicolon {
+ err.span_suggestion(
+ sp,
+ "try using a semicolon",
+ ";".to_string(),
+ Applicability::MaybeIncorrect,
+ );
+ } else if let UnstableFeatures::Disallow = self.sess.unstable_features {
+ err.span_label(sp, "tried to parse a type due to this");
+ } else {
+ err.span_label(sp, "tried to parse a type due to this type ascription");
+ }
+ if let UnstableFeatures::Disallow = self.sess.unstable_features {
+ // Give extra information about type ascription only if it's a nightly compiler.
+ } else {
+ err.note("`#![feature(type_ascription)]` lets you annotate an expression with a \
+ type: `<expr>: <type>`");
+ err.note("for more information, see \
+ https://github.com/rust-lang/rust/issues/23416");
+ }
+ }
+ }
+
/// Eats and discards tokens until one of `kets` is encountered. Respects token trees,
/// passes through any errors encountered. Used for error recovery.
crate fn eat_to_tokens(&mut self, kets: &[&TokenKind]) {
.collect::<Vec<_>>();
if !discriminant_spans.is_empty() && has_fields {
- let mut err = crate::feature_gate::feature_err(
+ let mut err = feature_err(
sess,
sym::arbitrary_enum_discriminant,
discriminant_spans.clone(),
return Ok(recovered);
}
}
- let cm = self.sess.source_map();
- match (cm.lookup_line(prev_sp.lo()), cm.lookup_line(sp.lo())) {
+ let sm = self.sess.source_map();
+ match (sm.lookup_line(prev_sp.lo()), sm.lookup_line(sp.lo())) {
(Ok(ref a), Ok(ref b)) if a.line == b.line => {
// When the spans are in the same line, it means that the only content
// between them is whitespace, point only at the found token.
self.look_ahead(2, |t| t.is_ident()) ||
self.look_ahead(1, |t| t == &token::Colon) && // `foo:bar:baz`
self.look_ahead(2, |t| t.is_ident()) ||
- self.look_ahead(1, |t| t == &token::ModSep) && // `foo:bar::baz`
- self.look_ahead(2, |t| t.is_ident())
- }
-
- crate fn bad_type_ascription(
- &self,
- err: &mut DiagnosticBuilder<'a>,
- lhs_span: Span,
- cur_op_span: Span,
- next_sp: Span,
- maybe_path: bool,
- ) {
- err.span_label(self.token.span, "expecting a type here because of type ascription");
- let cm = self.sess.source_map();
- let next_pos = cm.lookup_char_pos(next_sp.lo());
- let op_pos = cm.lookup_char_pos(cur_op_span.hi());
- if op_pos.line != next_pos.line {
- err.span_suggestion(
- cur_op_span,
- "try using a semicolon",
- ";".to_string(),
- Applicability::MaybeIncorrect,
- );
- } else {
- if maybe_path {
- err.span_suggestion(
- cur_op_span,
- "maybe you meant to write a path separator here",
- "::".to_string(),
- Applicability::MaybeIncorrect,
- );
- } else {
- err.note("`#![feature(type_ascription)]` lets you annotate an \
- expression with a type: `<expr>: <type>`")
- .span_note(
- lhs_span,
- "this expression expects an ascribed type after the colon",
- )
- .help("this might be indicative of a syntax error elsewhere");
- }
- }
+ self.look_ahead(1, |t| t == &token::ModSep) &&
+ (self.look_ahead(2, |t| t.is_ident()) || // `foo:bar::baz`
+ self.look_ahead(2, |t| t == &token::Lt)) // `foo:bar::<baz>`
}
crate fn recover_seq_parse_error(
use crate::parse::ParseSess;
use crate::parse::token::{self, Token, TokenKind};
use crate::symbol::{sym, Symbol};
-use crate::parse::unescape;
use crate::parse::unescape_error_reporting::{emit_unescape_error, push_escaped_char};
use errors::{FatalError, Diagnostic, DiagnosticBuilder};
use syntax_pos::{BytePos, Pos, Span, NO_EXPANSION};
use rustc_lexer::Base;
+use rustc_lexer::unescape;
use std::borrow::Cow;
use std::char;
use crate::parse::parser::Parser;
use crate::parse::PResult;
use crate::parse::token::{self, Token, TokenKind};
-use crate::parse::unescape::{unescape_char, unescape_byte};
-use crate::parse::unescape::{unescape_str, unescape_byte_str};
-use crate::parse::unescape::{unescape_raw_str, unescape_raw_byte_str};
use crate::print::pprust;
use crate::symbol::{kw, sym, Symbol};
use crate::tokenstream::{TokenStream, TokenTree};
use log::debug;
use rustc_data_structures::sync::Lrc;
use syntax_pos::Span;
+use rustc_lexer::unescape::{unescape_char, unescape_byte};
+use rustc_lexer::unescape::{unescape_str, unescape_byte_str};
+use rustc_lexer::unescape::{unescape_raw_str, unescape_raw_byte_str};
use std::ascii;
crate mod classify;
crate mod diagnostics;
crate mod literal;
-crate mod unescape;
crate mod unescape_error_reporting;
/// Info about a parsing session.
/// error.
crate unclosed_delims: Vec<UnmatchedBrace>,
crate last_unexpected_token_span: Option<Span>,
+ crate last_type_ascription: Option<(Span, bool /* likely path typo */)>,
/// If present, this `Parser` is not parsing Rust code but rather a macro call.
crate subparser_name: Option<&'static str>,
}
max_angle_bracket_count: 0,
unclosed_delims: Vec::new(),
last_unexpected_token_span: None,
+ last_type_ascription: None,
subparser_name,
};
}
} else {
let msg = format!("expected type, found {}", self.this_token_descr());
- return Err(self.fatal(&msg));
+ let mut err = self.fatal(&msg);
+ err.span_label(self.token.span, "expected type");
+ self.maybe_annotate_with_ascription(&mut err, true);
+ return Err(err);
};
let span = lo.to(self.prev_span);
}
/// Parses an associative expression with operators of at least `min_prec` precedence.
- fn parse_assoc_expr_with(&mut self,
- min_prec: usize,
- lhs: LhsExpr)
- -> PResult<'a, P<Expr>> {
+ fn parse_assoc_expr_with(
+ &mut self,
+ min_prec: usize,
+ lhs: LhsExpr,
+ ) -> PResult<'a, P<Expr>> {
let mut lhs = if let LhsExpr::AlreadyParsed(expr) = lhs {
expr
} else {
self.parse_prefix_expr(attrs)?
}
};
+ let last_type_ascription_set = self.last_type_ascription.is_some();
match (self.expr_is_complete(&lhs), AssocOp::from_token(&self.token)) {
(true, None) => {
+ self.last_type_ascription = None;
// Semi-statement forms are odd. See https://github.com/rust-lang/rust/issues/29071
return Ok(lhs);
}
// If the next token is a keyword, then the tokens above *are* unambiguously incorrect:
// `if x { a } else { b } && if y { c } else { d }`
if !self.look_ahead(1, |t| t.is_reserved_ident()) => {
+ self.last_type_ascription = None;
// These cases are ambiguous and can't be identified in the parser alone
let sp = self.sess.source_map().start_point(self.token.span);
self.sess.ambiguous_block_expr_parse.borrow_mut().insert(sp, lhs.span);
return Ok(lhs);
}
(true, Some(ref op)) if !op.can_continue_expr_unambiguously() => {
+ self.last_type_ascription = None;
return Ok(lhs);
}
(true, Some(_)) => {
continue
} else if op == AssocOp::Colon {
let maybe_path = self.could_ascription_be_path(&lhs.node);
- let next_sp = self.token.span;
+ self.last_type_ascription = Some((self.prev_span, maybe_path));
- lhs = match self.parse_assoc_op_cast(lhs, lhs_span, ExprKind::Type) {
- Ok(lhs) => lhs,
- Err(mut err) => {
- self.bad_type_ascription(
- &mut err,
- lhs_span,
- cur_op_span,
- next_sp,
- maybe_path,
- );
- return Err(err);
- }
- };
+ lhs = self.parse_assoc_op_cast(lhs, lhs_span, ExprKind::Type)?;
continue
} else if op == AssocOp::DotDot || op == AssocOp::DotDotEq {
// If we didn’t have to handle `x..`/`x..=`, it would be pretty easy to
if let Fixity::None = fixity { break }
}
+ if last_type_ascription_set {
+ self.last_type_ascription = None;
+ }
Ok(lhs)
}
+++ /dev/null
-//! Utilities for validating string and char literals and turning them into
-//! values they represent.
-
-use std::str::Chars;
-use std::ops::Range;
-
-#[derive(Debug, PartialEq, Eq)]
-pub(crate) enum EscapeError {
- ZeroChars,
- MoreThanOneChar,
-
- LoneSlash,
- InvalidEscape,
- BareCarriageReturn,
- BareCarriageReturnInRawString,
- EscapeOnlyChar,
-
- TooShortHexEscape,
- InvalidCharInHexEscape,
- OutOfRangeHexEscape,
-
- NoBraceInUnicodeEscape,
- InvalidCharInUnicodeEscape,
- EmptyUnicodeEscape,
- UnclosedUnicodeEscape,
- LeadingUnderscoreUnicodeEscape,
- OverlongUnicodeEscape,
- LoneSurrogateUnicodeEscape,
- OutOfRangeUnicodeEscape,
-
- UnicodeEscapeInByte,
- NonAsciiCharInByte,
- NonAsciiCharInByteString,
-}
-
-/// Takes a contents of a char literal (without quotes), and returns an
-/// unescaped char or an error
-pub(crate) fn unescape_char(literal_text: &str) -> Result<char, (usize, EscapeError)> {
- let mut chars = literal_text.chars();
- unescape_char_or_byte(&mut chars, Mode::Char)
- .map_err(|err| (literal_text.len() - chars.as_str().len(), err))
-}
-
-/// Takes a contents of a string literal (without quotes) and produces a
-/// sequence of escaped characters or errors.
-pub(crate) fn unescape_str<F>(literal_text: &str, callback: &mut F)
-where
- F: FnMut(Range<usize>, Result<char, EscapeError>),
-{
- unescape_str_or_byte_str(literal_text, Mode::Str, callback)
-}
-
-pub(crate) fn unescape_byte(literal_text: &str) -> Result<u8, (usize, EscapeError)> {
- let mut chars = literal_text.chars();
- unescape_char_or_byte(&mut chars, Mode::Byte)
- .map(byte_from_char)
- .map_err(|err| (literal_text.len() - chars.as_str().len(), err))
-}
-
-/// Takes a contents of a string literal (without quotes) and produces a
-/// sequence of escaped characters or errors.
-pub(crate) fn unescape_byte_str<F>(literal_text: &str, callback: &mut F)
-where
- F: FnMut(Range<usize>, Result<u8, EscapeError>),
-{
- unescape_str_or_byte_str(literal_text, Mode::ByteStr, &mut |range, char| {
- callback(range, char.map(byte_from_char))
- })
-}
-
-/// Takes a contents of a string literal (without quotes) and produces a
-/// sequence of characters or errors.
-/// NOTE: Raw strings do not perform any explicit character escaping, here we
-/// only translate CRLF to LF and produce errors on bare CR.
-pub(crate) fn unescape_raw_str<F>(literal_text: &str, callback: &mut F)
-where
- F: FnMut(Range<usize>, Result<char, EscapeError>),
-{
- unescape_raw_str_or_byte_str(literal_text, Mode::Str, callback)
-}
-
-/// Takes a contents of a string literal (without quotes) and produces a
-/// sequence of characters or errors.
-/// NOTE: Raw strings do not perform any explicit character escaping, here we
-/// only translate CRLF to LF and produce errors on bare CR.
-pub(crate) fn unescape_raw_byte_str<F>(literal_text: &str, callback: &mut F)
-where
- F: FnMut(Range<usize>, Result<u8, EscapeError>),
-{
- unescape_raw_str_or_byte_str(literal_text, Mode::ByteStr, &mut |range, char| {
- callback(range, char.map(byte_from_char))
- })
-}
-
-#[derive(Debug, Clone, Copy)]
-pub(crate) enum Mode {
- Char,
- Str,
- Byte,
- ByteStr,
-}
-
-impl Mode {
- fn in_single_quotes(self) -> bool {
- match self {
- Mode::Char | Mode::Byte => true,
- Mode::Str | Mode::ByteStr => false,
- }
- }
-
- pub(crate) fn in_double_quotes(self) -> bool {
- !self.in_single_quotes()
- }
-
- pub(crate) fn is_bytes(self) -> bool {
- match self {
- Mode::Byte | Mode::ByteStr => true,
- Mode::Char | Mode::Str => false,
- }
- }
-}
-
-
-fn scan_escape(first_char: char, chars: &mut Chars<'_>, mode: Mode) -> Result<char, EscapeError> {
- if first_char != '\\' {
- return match first_char {
- '\t' | '\n' => Err(EscapeError::EscapeOnlyChar),
- '\r' => Err(if chars.clone().next() == Some('\n') {
- EscapeError::EscapeOnlyChar
- } else {
- EscapeError::BareCarriageReturn
- }),
- '\'' if mode.in_single_quotes() => Err(EscapeError::EscapeOnlyChar),
- '"' if mode.in_double_quotes() => Err(EscapeError::EscapeOnlyChar),
- _ => {
- if mode.is_bytes() && !first_char.is_ascii() {
- return Err(EscapeError::NonAsciiCharInByte);
- }
- Ok(first_char)
- }
- };
- }
-
- let second_char = chars.next().ok_or(EscapeError::LoneSlash)?;
-
- let res = match second_char {
- '"' => '"',
- 'n' => '\n',
- 'r' => '\r',
- 't' => '\t',
- '\\' => '\\',
- '\'' => '\'',
- '0' => '\0',
-
- 'x' => {
- let hi = chars.next().ok_or(EscapeError::TooShortHexEscape)?;
- let hi = hi.to_digit(16).ok_or(EscapeError::InvalidCharInHexEscape)?;
-
- let lo = chars.next().ok_or(EscapeError::TooShortHexEscape)?;
- let lo = lo.to_digit(16).ok_or(EscapeError::InvalidCharInHexEscape)?;
-
- let value = hi * 16 + lo;
-
- if !mode.is_bytes() && !is_ascii(value) {
- return Err(EscapeError::OutOfRangeHexEscape);
- }
- let value = value as u8;
-
- value as char
- }
-
- 'u' => {
- if chars.next() != Some('{') {
- return Err(EscapeError::NoBraceInUnicodeEscape);
- }
-
- let mut n_digits = 1;
- let mut value: u32 = match chars.next().ok_or(EscapeError::UnclosedUnicodeEscape)? {
- '_' => return Err(EscapeError::LeadingUnderscoreUnicodeEscape),
- '}' => return Err(EscapeError::EmptyUnicodeEscape),
- c => c.to_digit(16).ok_or(EscapeError::InvalidCharInUnicodeEscape)?,
- };
-
- loop {
- match chars.next() {
- None => return Err(EscapeError::UnclosedUnicodeEscape),
- Some('_') => continue,
- Some('}') => {
- if n_digits > 6 {
- return Err(EscapeError::OverlongUnicodeEscape);
- }
- if mode.is_bytes() {
- return Err(EscapeError::UnicodeEscapeInByte);
- }
-
- break std::char::from_u32(value).ok_or_else(|| {
- if value > 0x10FFFF {
- EscapeError::OutOfRangeUnicodeEscape
- } else {
- EscapeError::LoneSurrogateUnicodeEscape
- }
- })?;
- }
- Some(c) => {
- let digit = c.to_digit(16).ok_or(EscapeError::InvalidCharInUnicodeEscape)?;
- n_digits += 1;
- if n_digits > 6 {
- continue;
- }
- let digit = digit as u32;
- value = value * 16 + digit;
- }
- };
- }
- }
- _ => return Err(EscapeError::InvalidEscape),
- };
- Ok(res)
-}
-
-fn unescape_char_or_byte(chars: &mut Chars<'_>, mode: Mode) -> Result<char, EscapeError> {
- let first_char = chars.next().ok_or(EscapeError::ZeroChars)?;
- let res = scan_escape(first_char, chars, mode)?;
- if chars.next().is_some() {
- return Err(EscapeError::MoreThanOneChar);
- }
- Ok(res)
-}
-
-/// Takes a contents of a string literal (without quotes) and produces a
-/// sequence of escaped characters or errors.
-fn unescape_str_or_byte_str<F>(src: &str, mode: Mode, callback: &mut F)
-where
- F: FnMut(Range<usize>, Result<char, EscapeError>),
-{
- assert!(mode.in_double_quotes());
- let initial_len = src.len();
- let mut chars = src.chars();
- while let Some(first_char) = chars.next() {
- let start = initial_len - chars.as_str().len() - first_char.len_utf8();
-
- let unescaped_char = match first_char {
- '\\' => {
- let (second_char, third_char) = {
- let mut chars = chars.clone();
- (chars.next(), chars.next())
- };
- match (second_char, third_char) {
- (Some('\n'), _) | (Some('\r'), Some('\n')) => {
- skip_ascii_whitespace(&mut chars);
- continue;
- }
- _ => scan_escape(first_char, &mut chars, mode),
- }
- }
- '\r' => {
- let second_char = chars.clone().next();
- if second_char == Some('\n') {
- chars.next();
- Ok('\n')
- } else {
- scan_escape(first_char, &mut chars, mode)
- }
- }
- '\n' => Ok('\n'),
- '\t' => Ok('\t'),
- _ => scan_escape(first_char, &mut chars, mode),
- };
- let end = initial_len - chars.as_str().len();
- callback(start..end, unescaped_char);
- }
-
- fn skip_ascii_whitespace(chars: &mut Chars<'_>) {
- let str = chars.as_str();
- let first_non_space = str
- .bytes()
- .position(|b| b != b' ' && b != b'\t' && b != b'\n' && b != b'\r')
- .unwrap_or(str.len());
- *chars = str[first_non_space..].chars()
- }
-}
-
-/// Takes a contents of a string literal (without quotes) and produces a
-/// sequence of characters or errors.
-/// NOTE: Raw strings do not perform any explicit character escaping, here we
-/// only translate CRLF to LF and produce errors on bare CR.
-fn unescape_raw_str_or_byte_str<F>(literal_text: &str, mode: Mode, callback: &mut F)
-where
- F: FnMut(Range<usize>, Result<char, EscapeError>),
-{
- assert!(mode.in_double_quotes());
- let initial_len = literal_text.len();
-
- let mut chars = literal_text.chars();
- while let Some(curr) = chars.next() {
- let start = initial_len - chars.as_str().len() - curr.len_utf8();
-
- let result = match (curr, chars.clone().next()) {
- ('\r', Some('\n')) => {
- chars.next();
- Ok('\n')
- },
- ('\r', _) => Err(EscapeError::BareCarriageReturnInRawString),
- (c, _) if mode.is_bytes() && !c.is_ascii() =>
- Err(EscapeError::NonAsciiCharInByteString),
- (c, _) => Ok(c),
- };
- let end = initial_len - chars.as_str().len();
-
- callback(start..end, result);
- }
-}
-
-fn byte_from_char(c: char) -> u8 {
- let res = c as u32;
- assert!(res <= u8::max_value() as u32, "guaranteed because of Mode::Byte(Str)");
- res as u8
-}
-
-fn is_ascii(x: u32) -> bool {
- x <= 0x7F
-}
-
-#[cfg(test)]
-mod tests {
- use super::*;
-
- #[test]
- fn test_unescape_char_bad() {
- fn check(literal_text: &str, expected_error: EscapeError) {
- let actual_result = unescape_char(literal_text).map_err(|(_offset, err)| err);
- assert_eq!(actual_result, Err(expected_error));
- }
-
- check("", EscapeError::ZeroChars);
- check(r"\", EscapeError::LoneSlash);
-
- check("\n", EscapeError::EscapeOnlyChar);
- check("\r\n", EscapeError::EscapeOnlyChar);
- check("\t", EscapeError::EscapeOnlyChar);
- check("'", EscapeError::EscapeOnlyChar);
- check("\r", EscapeError::BareCarriageReturn);
-
- check("spam", EscapeError::MoreThanOneChar);
- check(r"\x0ff", EscapeError::MoreThanOneChar);
- check(r#"\"a"#, EscapeError::MoreThanOneChar);
- check(r"\na", EscapeError::MoreThanOneChar);
- check(r"\ra", EscapeError::MoreThanOneChar);
- check(r"\ta", EscapeError::MoreThanOneChar);
- check(r"\\a", EscapeError::MoreThanOneChar);
- check(r"\'a", EscapeError::MoreThanOneChar);
- check(r"\0a", EscapeError::MoreThanOneChar);
- check(r"\u{0}x", EscapeError::MoreThanOneChar);
- check(r"\u{1F63b}}", EscapeError::MoreThanOneChar);
-
- check(r"\v", EscapeError::InvalidEscape);
- check(r"\💩", EscapeError::InvalidEscape);
- check(r"\●", EscapeError::InvalidEscape);
-
- check(r"\x", EscapeError::TooShortHexEscape);
- check(r"\x0", EscapeError::TooShortHexEscape);
- check(r"\xf", EscapeError::TooShortHexEscape);
- check(r"\xa", EscapeError::TooShortHexEscape);
- check(r"\xx", EscapeError::InvalidCharInHexEscape);
- check(r"\xы", EscapeError::InvalidCharInHexEscape);
- check(r"\x🦀", EscapeError::InvalidCharInHexEscape);
- check(r"\xtt", EscapeError::InvalidCharInHexEscape);
- check(r"\xff", EscapeError::OutOfRangeHexEscape);
- check(r"\xFF", EscapeError::OutOfRangeHexEscape);
- check(r"\x80", EscapeError::OutOfRangeHexEscape);
-
- check(r"\u", EscapeError::NoBraceInUnicodeEscape);
- check(r"\u[0123]", EscapeError::NoBraceInUnicodeEscape);
- check(r"\u{0x}", EscapeError::InvalidCharInUnicodeEscape);
- check(r"\u{", EscapeError::UnclosedUnicodeEscape);
- check(r"\u{0000", EscapeError::UnclosedUnicodeEscape);
- check(r"\u{}", EscapeError::EmptyUnicodeEscape);
- check(r"\u{_0000}", EscapeError::LeadingUnderscoreUnicodeEscape);
- check(r"\u{0000000}", EscapeError::OverlongUnicodeEscape);
- check(r"\u{FFFFFF}", EscapeError::OutOfRangeUnicodeEscape);
- check(r"\u{ffffff}", EscapeError::OutOfRangeUnicodeEscape);
- check(r"\u{ffffff}", EscapeError::OutOfRangeUnicodeEscape);
-
- check(r"\u{DC00}", EscapeError::LoneSurrogateUnicodeEscape);
- check(r"\u{DDDD}", EscapeError::LoneSurrogateUnicodeEscape);
- check(r"\u{DFFF}", EscapeError::LoneSurrogateUnicodeEscape);
-
- check(r"\u{D800}", EscapeError::LoneSurrogateUnicodeEscape);
- check(r"\u{DAAA}", EscapeError::LoneSurrogateUnicodeEscape);
- check(r"\u{DBFF}", EscapeError::LoneSurrogateUnicodeEscape);
- }
-
- #[test]
- fn test_unescape_char_good() {
- fn check(literal_text: &str, expected_char: char) {
- let actual_result = unescape_char(literal_text);
- assert_eq!(actual_result, Ok(expected_char));
- }
-
- check("a", 'a');
- check("ы", 'ы');
- check("🦀", '🦀');
-
- check(r#"\""#, '"');
- check(r"\n", '\n');
- check(r"\r", '\r');
- check(r"\t", '\t');
- check(r"\\", '\\');
- check(r"\'", '\'');
- check(r"\0", '\0');
-
- check(r"\x00", '\0');
- check(r"\x5a", 'Z');
- check(r"\x5A", 'Z');
- check(r"\x7f", 127 as char);
-
- check(r"\u{0}", '\0');
- check(r"\u{000000}", '\0');
- check(r"\u{41}", 'A');
- check(r"\u{0041}", 'A');
- check(r"\u{00_41}", 'A');
- check(r"\u{4__1__}", 'A');
- check(r"\u{1F63b}", '😻');
- }
-
- #[test]
- fn test_unescape_str_good() {
- fn check(literal_text: &str, expected: &str) {
- let mut buf = Ok(String::with_capacity(literal_text.len()));
- unescape_str(literal_text, &mut |range, c| {
- if let Ok(b) = &mut buf {
- match c {
- Ok(c) => b.push(c),
- Err(e) => buf = Err((range, e)),
- }
- }
- });
- let buf = buf.as_ref().map(|it| it.as_ref());
- assert_eq!(buf, Ok(expected))
- }
-
- check("foo", "foo");
- check("", "");
- check(" \t\n\r\n", " \t\n\n");
-
- check("hello \\\n world", "hello world");
- check("hello \\\r\n world", "hello world");
- check("thread's", "thread's")
- }
-
- #[test]
- fn test_unescape_byte_bad() {
- fn check(literal_text: &str, expected_error: EscapeError) {
- let actual_result = unescape_byte(literal_text).map_err(|(_offset, err)| err);
- assert_eq!(actual_result, Err(expected_error));
- }
-
- check("", EscapeError::ZeroChars);
- check(r"\", EscapeError::LoneSlash);
-
- check("\n", EscapeError::EscapeOnlyChar);
- check("\r\n", EscapeError::EscapeOnlyChar);
- check("\t", EscapeError::EscapeOnlyChar);
- check("'", EscapeError::EscapeOnlyChar);
- check("\r", EscapeError::BareCarriageReturn);
-
- check("spam", EscapeError::MoreThanOneChar);
- check(r"\x0ff", EscapeError::MoreThanOneChar);
- check(r#"\"a"#, EscapeError::MoreThanOneChar);
- check(r"\na", EscapeError::MoreThanOneChar);
- check(r"\ra", EscapeError::MoreThanOneChar);
- check(r"\ta", EscapeError::MoreThanOneChar);
- check(r"\\a", EscapeError::MoreThanOneChar);
- check(r"\'a", EscapeError::MoreThanOneChar);
- check(r"\0a", EscapeError::MoreThanOneChar);
-
- check(r"\v", EscapeError::InvalidEscape);
- check(r"\💩", EscapeError::InvalidEscape);
- check(r"\●", EscapeError::InvalidEscape);
-
- check(r"\x", EscapeError::TooShortHexEscape);
- check(r"\x0", EscapeError::TooShortHexEscape);
- check(r"\xa", EscapeError::TooShortHexEscape);
- check(r"\xf", EscapeError::TooShortHexEscape);
- check(r"\xx", EscapeError::InvalidCharInHexEscape);
- check(r"\xы", EscapeError::InvalidCharInHexEscape);
- check(r"\x🦀", EscapeError::InvalidCharInHexEscape);
- check(r"\xtt", EscapeError::InvalidCharInHexEscape);
-
- check(r"\u", EscapeError::NoBraceInUnicodeEscape);
- check(r"\u[0123]", EscapeError::NoBraceInUnicodeEscape);
- check(r"\u{0x}", EscapeError::InvalidCharInUnicodeEscape);
- check(r"\u{", EscapeError::UnclosedUnicodeEscape);
- check(r"\u{0000", EscapeError::UnclosedUnicodeEscape);
- check(r"\u{}", EscapeError::EmptyUnicodeEscape);
- check(r"\u{_0000}", EscapeError::LeadingUnderscoreUnicodeEscape);
- check(r"\u{0000000}", EscapeError::OverlongUnicodeEscape);
-
- check("ы", EscapeError::NonAsciiCharInByte);
- check("🦀", EscapeError::NonAsciiCharInByte);
-
- check(r"\u{0}", EscapeError::UnicodeEscapeInByte);
- check(r"\u{000000}", EscapeError::UnicodeEscapeInByte);
- check(r"\u{41}", EscapeError::UnicodeEscapeInByte);
- check(r"\u{0041}", EscapeError::UnicodeEscapeInByte);
- check(r"\u{00_41}", EscapeError::UnicodeEscapeInByte);
- check(r"\u{4__1__}", EscapeError::UnicodeEscapeInByte);
- check(r"\u{1F63b}", EscapeError::UnicodeEscapeInByte);
- check(r"\u{0}x", EscapeError::UnicodeEscapeInByte);
- check(r"\u{1F63b}}", EscapeError::UnicodeEscapeInByte);
- check(r"\u{FFFFFF}", EscapeError::UnicodeEscapeInByte);
- check(r"\u{ffffff}", EscapeError::UnicodeEscapeInByte);
- check(r"\u{ffffff}", EscapeError::UnicodeEscapeInByte);
- check(r"\u{DC00}", EscapeError::UnicodeEscapeInByte);
- check(r"\u{DDDD}", EscapeError::UnicodeEscapeInByte);
- check(r"\u{DFFF}", EscapeError::UnicodeEscapeInByte);
- check(r"\u{D800}", EscapeError::UnicodeEscapeInByte);
- check(r"\u{DAAA}", EscapeError::UnicodeEscapeInByte);
- check(r"\u{DBFF}", EscapeError::UnicodeEscapeInByte);
- }
-
- #[test]
- fn test_unescape_byte_good() {
- fn check(literal_text: &str, expected_byte: u8) {
- let actual_result = unescape_byte(literal_text);
- assert_eq!(actual_result, Ok(expected_byte));
- }
-
- check("a", b'a');
-
- check(r#"\""#, b'"');
- check(r"\n", b'\n');
- check(r"\r", b'\r');
- check(r"\t", b'\t');
- check(r"\\", b'\\');
- check(r"\'", b'\'');
- check(r"\0", b'\0');
-
- check(r"\x00", b'\0');
- check(r"\x5a", b'Z');
- check(r"\x5A", b'Z');
- check(r"\x7f", 127);
- check(r"\x80", 128);
- check(r"\xff", 255);
- check(r"\xFF", 255);
- }
-
- #[test]
- fn test_unescape_byte_str_good() {
- fn check(literal_text: &str, expected: &[u8]) {
- let mut buf = Ok(Vec::with_capacity(literal_text.len()));
- unescape_byte_str(literal_text, &mut |range, c| {
- if let Ok(b) = &mut buf {
- match c {
- Ok(c) => b.push(c),
- Err(e) => buf = Err((range, e)),
- }
- }
- });
- let buf = buf.as_ref().map(|it| it.as_ref());
- assert_eq!(buf, Ok(expected))
- }
-
- check("foo", b"foo");
- check("", b"");
- check(" \t\n\r\n", b" \t\n\n");
-
- check("hello \\\n world", b"hello world");
- check("hello \\\r\n world", b"hello world");
- check("thread's", b"thread's")
- }
-
- #[test]
- fn test_unescape_raw_str() {
- fn check(literal: &str, expected: &[(Range<usize>, Result<char, EscapeError>)]) {
- let mut unescaped = Vec::with_capacity(literal.len());
- unescape_raw_str(literal, &mut |range, res| unescaped.push((range, res)));
- assert_eq!(unescaped, expected);
- }
-
- check("\r\n", &[(0..2, Ok('\n'))]);
- check("\r", &[(0..1, Err(EscapeError::BareCarriageReturnInRawString))]);
- check("\rx", &[(0..1, Err(EscapeError::BareCarriageReturnInRawString)), (1..2, Ok('x'))]);
- }
-
- #[test]
- fn test_unescape_raw_byte_str() {
- fn check(literal: &str, expected: &[(Range<usize>, Result<u8, EscapeError>)]) {
- let mut unescaped = Vec::with_capacity(literal.len());
- unescape_raw_byte_str(literal, &mut |range, res| unescaped.push((range, res)));
- assert_eq!(unescaped, expected);
- }
-
- check("\r\n", &[(0..2, Ok(byte_from_char('\n')))]);
- check("\r", &[(0..1, Err(EscapeError::BareCarriageReturnInRawString))]);
- check("🦀", &[(0..4, Err(EscapeError::NonAsciiCharInByteString))]);
- check(
- "🦀a",
- &[(0..4, Err(EscapeError::NonAsciiCharInByteString)), (4..5, Ok(byte_from_char('a')))],
- );
- }
-}
use std::ops::Range;
use std::iter::once;
+use rustc_lexer::unescape::{EscapeError, Mode};
use syntax_pos::{Span, BytePos};
use crate::errors::{Handler, Applicability};
-use super::unescape::{EscapeError, Mode};
-
pub(crate) fn emit_unescape_error(
handler: &Handler,
// interior part of the literal, without quotes
while p.token != token::Eof {
if !p.eat(&token::Comma) {
- return Err(ecx.struct_span_err(p.token.span, "expected token: `,`"));
+ let mut err = ecx.struct_span_err(p.token.span, "expected token: `,`");
+ err.span_label(p.token.span, "expected `,`");
+ p.maybe_annotate_with_ascription(&mut err, false);
+ return Err(err);
}
if p.token == token::Eof {
break;
#![feature(decl_macro)]
#![feature(nll)]
#![feature(rustc_diagnostic_macros)]
+#![feature(unicode_internals)]
#![recursion_limit="256"]
#
# This means that there's a small window of time (a few days) where artifacts
# are downloaded from dev-static.rust-lang.org instead of static.rust-lang.org.
-# In order to ease this transition we have an extra key is in this configuration
-# file below. When uncommented this will instruct the bootstrap.py script to
-# download from dev-static.rust-lang.org.
+# In order to ease this transition we have an extra key which is in the
+# configuration file below. When uncommented this will instruct the bootstrap.py
+# script to download from dev-static.rust-lang.org.
#
# This key is typically commented out at all times. If you're looking at a
# stable release tarball it should *definitely* be commented out. If you're
static A: System = System;
#[global_allocator]
static B: System = System;
-//~^ ERROR: cannot define more than one #[global_allocator]
+//~^ ERROR: cannot define more than one `#[global_allocator]`
fn main() {}
-error: cannot define more than one #[global_allocator]
+error: cannot define more than one `#[global_allocator]`
--> $DIR/two-allocators.rs:6:1
|
LL | static B: System = System;
--> $DIR/bad-format-args.rs:3:16
|
LL | format!("" 1);
- | ^
+ | ^ expected `,`
error: expected token: `,`
--> $DIR/bad-format-args.rs:4:19
|
LL | format!("", 1 1);
- | ^
+ | ^ expected `,`
error: aborting due to 3 previous errors
--> $DIR/E0121.rs:3:13
|
LL | static BAR: _ = "test";
- | ^ not allowed in type signatures
+ | ^
+ | |
+ | not allowed in type signatures
+ | help: replace `_` with the correct type: `&'static str`
error: aborting due to 2 previous errors
--- /dev/null
+#![feature(existential_type)]
+
+trait UnwrapItemsExt {
+ type Iter;
+ fn unwrap_items(self) -> Self::Iter;
+}
+
+impl<I, T, E> UnwrapItemsExt for I
+where
+ I: Iterator<Item = Result<T, E>>,
+ E: std::fmt::Debug,
+{
+ existential type Iter: Iterator<Item = T>;
+ //~^ ERROR: could not find defining uses
+
+ fn unwrap_items(self) -> Self::Iter {
+ //~^ ERROR: type parameter `T` is part of concrete type
+ //~| ERROR: type parameter `E` is part of concrete type
+ self.map(|x| x.unwrap())
+ }
+}
+
+fn main() {}
--- /dev/null
+error: type parameter `T` is part of concrete type but not used in parameter list for existential type
+ --> $DIR/issue-58887.rs:16:41
+ |
+LL | fn unwrap_items(self) -> Self::Iter {
+ | _________________________________________^
+LL | |
+LL | |
+LL | | self.map(|x| x.unwrap())
+LL | | }
+ | |_____^
+
+error: type parameter `E` is part of concrete type but not used in parameter list for existential type
+ --> $DIR/issue-58887.rs:16:41
+ |
+LL | fn unwrap_items(self) -> Self::Iter {
+ | _________________________________________^
+LL | |
+LL | |
+LL | | self.map(|x| x.unwrap())
+LL | | }
+ | |_____^
+
+error: could not find defining uses
+ --> $DIR/issue-58887.rs:13:5
+ |
+LL | existential type Iter: Iterator<Item = T>;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 3 previous errors
+
--- /dev/null
+// gate-test-rustc_private
+
+extern crate libc; //~ ERROR use of unstable library feature 'rustc_private'
+
+fn main() {}
--- /dev/null
+error[E0658]: use of unstable library feature 'rustc_private': this crate is being loaded from the sysroot, an unstable location; did you mean to load this crate from crates.io via `Cargo.toml` instead?
+ --> $DIR/rustc-private.rs:3:1
+ |
+LL | extern crate libc;
+ | ^^^^^^^^^^^^^^^^^^
+ |
+ = note: for more information, see https://github.com/rust-lang/rust/issues/27812
+ = help: add `#![feature(rustc_private)]` to the crate attributes to enable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0658`.
--- /dev/null
+trait T0<'a, A> {
+ type O;
+}
+
+struct L<T> {
+ f: T,
+}
+
+// explicitly named variants of what one would normally denote by the
+// unit type `()`. Why do this? So that we can differentiate them in
+// the diagnostic output.
+struct Unit1;
+struct Unit2;
+struct Unit3;
+struct Unit4;
+
+impl<'a, A, T> T0<'a, A> for L<T>
+where
+ T: FnMut(A) -> Unit3,
+{
+ type O = T::Output;
+}
+
+trait T1: for<'r> Ty<'r> {
+ fn m<'a, B: Ty<'a>, F>(&self, f: F) -> Unit1
+ where
+ F: for<'r> T0<'r, (<Self as Ty<'r>>::V,), O = <B as Ty<'r>>::V>,
+ {
+ unimplemented!();
+ }
+}
+
+trait Ty<'a> {
+ type V;
+}
+
+fn main() {
+ let v = Unit2.m(
+ //~^ ERROR type mismatch
+ //~| ERROR type mismatch
+ L {
+ f : |x| { drop(x); Unit4 }
+ });
+}
+
+impl<'a> Ty<'a> for Unit2 {
+ type V = &'a u8;
+}
+
+impl T1 for Unit2 {}
--- /dev/null
+error[E0271]: type mismatch resolving `for<'r> <L<[closure@$DIR/issue-62203-hrtb-ice.rs:42:17: 42:39]> as T0<'r, (<Unit2 as Ty<'r>>::V,)>>::O == <_ as Ty<'r>>::V`
+ --> $DIR/issue-62203-hrtb-ice.rs:38:19
+ |
+LL | let v = Unit2.m(
+ | ^ expected struct `Unit4`, found associated type
+ |
+ = note: expected type `Unit4`
+ found type `<_ as Ty<'_>>::V`
+
+error[E0271]: type mismatch resolving `<[closure@$DIR/issue-62203-hrtb-ice.rs:42:17: 42:39] as std::ops::FnOnce<((&u8,),)>>::Output == Unit3`
+ --> $DIR/issue-62203-hrtb-ice.rs:38:19
+ |
+LL | let v = Unit2.m(
+ | ^ expected struct `Unit4`, found struct `Unit3`
+ |
+ = note: expected type `Unit4`
+ found type `Unit3`
+ = note: required because of the requirements on the impl of `for<'r> T0<'r, (<Unit2 as Ty<'r>>::V,)>` for `L<[closure@$DIR/issue-62203-hrtb-ice.rs:42:17: 42:39]>`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0271`.
--> $DIR/issue-22644.rs:34:28
|
LL | println!("{}", a: &mut 4);
- | ^ expecting a type here because of type ascription
+ | - ^ expected type
+ | |
+ | tried to parse a type due to this type ascription
|
= note: `#![feature(type_ascription)]` lets you annotate an expression with a type: `<expr>: <type>`
-note: this expression expects an ascribed type after the colon
- --> $DIR/issue-22644.rs:34:20
- |
-LL | println!("{}", a: &mut 4);
- | ^
- = help: this might be indicative of a syntax error elsewhere
+ = note: for more information, see https://github.com/rust-lang/rust/issues/23416
error: aborting due to 9 previous errors
--> $DIR/issue-34255-1.rs:8:24
|
LL | Test::Drill(field: 42);
- | ^^ expecting a type here because of type ascription
+ | - ^^ expected type
+ | |
+ | tried to parse a type due to this type ascription
|
= note: `#![feature(type_ascription)]` lets you annotate an expression with a type: `<expr>: <type>`
-note: this expression expects an ascribed type after the colon
- --> $DIR/issue-34255-1.rs:8:17
- |
-LL | Test::Drill(field: 42);
- | ^^^^^
- = help: this might be indicative of a syntax error elsewhere
+ = note: for more information, see https://github.com/rust-lang/rust/issues/23416
error: aborting due to previous error
--> $DIR/issue-39616.rs:1:12
|
LL | fn foo(a: [0; 1]) {}
- | ^
+ | ^ expected type
error: expected one of `)`, `,`, `->`, `where`, or `{`, found `]`
--> $DIR/issue-39616.rs:1:16
| - help: try using a semicolon: `;`
...
LL | foo!(true);
- | ^^^^ expecting a type here because of type ascription
+ | ^^^^ expected type
+ |
+ = note: `#![feature(type_ascription)]` lets you annotate an expression with a type: `<expr>: <type>`
+ = note: for more information, see https://github.com/rust-lang/rust/issues/23416
error: aborting due to 2 previous errors
--> $DIR/lifetime_starts_expressions.rs:6:26
|
LL | loop { break 'label: loop { break 'label 42; }; }
- | ^^^^ expecting a type here because of type ascription
+ | - ^^^^ expected type
+ | |
+ | tried to parse a type due to this type ascription
|
= note: `#![feature(type_ascription)]` lets you annotate an expression with a type: `<expr>: <type>`
-note: this expression expects an ascribed type after the colon
- --> $DIR/lifetime_starts_expressions.rs:6:12
- |
-LL | loop { break 'label: loop { break 'label 42; }; }
- | ^^^^^^^^^^^^
- = help: this might be indicative of a syntax error elsewhere
+ = note: for more information, see https://github.com/rust-lang/rust/issues/23416
error: aborting due to 2 previous errors
--> $DIR/missing-comma.rs:19:19
|
LL | println!("{}" a);
- | ^
+ | ^ expected `,`
error: no rules expected the token `b`
--> $DIR/missing-comma.rs:21:12
--> $DIR/issue-33262.rs:4:22
|
LL | for i in 0..a as { }
- | ^
+ | ^ expected type
error: aborting due to previous error
--> $DIR/trait-object-macro-matcher.rs:9:8
|
LL | m!('static);
- | ^^^^^^^
+ | ^^^^^^^ expected type
error: aborting due to previous error
--> $DIR/recover-enum2.rs:6:18
|
LL | abc: {},
- | ^
+ | ^ expected type
error: expected one of `!`, `(`, `)`, `+`, `,`, `::`, or `<`, found `{`
--> $DIR/recover-enum2.rs:25:22
--> $DIR/recover-from-bad-variant.rs:7:26
|
LL | let x = Enum::Foo(a: 3, b: 4);
- | ^ expecting a type here because of type ascription
+ | - ^ expected type
+ | |
+ | tried to parse a type due to this type ascription
|
= note: `#![feature(type_ascription)]` lets you annotate an expression with a type: `<expr>: <type>`
-note: this expression expects an ascribed type after the colon
- --> $DIR/recover-from-bad-variant.rs:7:23
- |
-LL | let x = Enum::Foo(a: 3, b: 4);
- | ^
- = help: this might be indicative of a syntax error elsewhere
+ = note: for more information, see https://github.com/rust-lang/rust/issues/23416
error[E0532]: expected tuple struct/variant, found struct variant `Enum::Foo`
--> $DIR/recover-from-bad-variant.rs:10:9
--> $DIR/removed-syntax-mut-vec-ty.rs:1:11
|
LL | type v = [mut isize];
- | ^^^
+ | ^^^ expected type
error: aborting due to previous error
--> $DIR/removed-syntax-record.rs:1:10
|
LL | type t = { f: () };
- | ^
+ | ^ expected type
error: aborting due to previous error
--> $DIR/trait-object-lifetime-parens.rs:9:17
|
LL | let _: Box<('a) + Trait>;
- | - ^^
+ | - ^^ expected type
| |
| while parsing the type for `_`
| ---------- variant `Rombus` not found here
...
LL | println!("My shape is {:?}", Shape::Rombus{ size: 5});
- | -------^^^^^^
- | |
- | variant not found in `Shape`
+ | ^^^^^^ variant not found in `Shape`
error[E0599]: no variant or associated item named `Squareee` found for type `Shape` in the current scope
--> $DIR/suggest-variants.rs:15:12
--> $DIR/type-ascription-instead-of-method.rs:2:13
|
LL | Box:new("foo".to_string())
- | - ^^^^^ expecting a type here because of type ascription
+ | - ^^^^^ expected type
| |
- | help: maybe you meant to write a path separator here: `::`
+ | help: maybe write a path separator here: `::`
+ |
+ = note: `#![feature(type_ascription)]` lets you annotate an expression with a type: `<expr>: <type>`
+ = note: for more information, see https://github.com/rust-lang/rust/issues/23416
error: aborting due to previous error
--> $DIR/type-ascription-instead-of-variant.rs:2:25
|
LL | let _ = Option:Some("");
- | - ^^ expecting a type here because of type ascription
+ | - ^^ expected type
| |
- | help: maybe you meant to write a path separator here: `::`
+ | help: maybe write a path separator here: `::`
+ |
+ = note: `#![feature(type_ascription)]` lets you annotate an expression with a type: `<expr>: <type>`
+ = note: for more information, see https://github.com/rust-lang/rust/issues/23416
error: aborting due to previous error
--- /dev/null
+struct Reactor {
+ input_cells: Vec<usize>,
+}
+
+impl Reactor {
+ pub fn new() -> Self {
+ input_cells: Vec::new()
+ //~^ ERROR cannot find value `input_cells` in this scope
+ //~| ERROR parenthesized type parameters may only be used with a `Fn` trait
+ //~| ERROR wrong number of type arguments: expected 1, found 0
+ //~| WARNING this was previously accepted by the compiler but is being phased out
+ }
+}
+
+// This case isn't currently being handled gracefully, including for completeness.
--- /dev/null
+error[E0425]: cannot find value `input_cells` in this scope
+ --> $DIR/issue-34255-1.rs:7:9
+ |
+LL | input_cells: Vec::new()
+ | ^^^^^^^^^^^ a field by this name exists in `Self`
+
+error: parenthesized type parameters may only be used with a `Fn` trait
+ --> $DIR/issue-34255-1.rs:7:30
+ |
+LL | input_cells: Vec::new()
+ | ^^
+ |
+ = note: `#[deny(parenthesized_params_in_types_and_modules)]` on by default
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #42238 <https://github.com/rust-lang/rust/issues/42238>
+
+error[E0601]: `main` function not found in crate `issue_34255_1`
+ |
+ = note: consider adding a `main` function to `$DIR/issue-34255-1.rs`
+
+error[E0107]: wrong number of type arguments: expected 1, found 0
+ --> $DIR/issue-34255-1.rs:7:22
+ |
+LL | input_cells: Vec::new()
+ | ^^^^^^^^^^ expected 1 type argument
+
+error: aborting due to 4 previous errors
+
+Some errors have detailed explanations: E0107, E0425, E0601.
+For more information about an error, try `rustc --explain E0107`.
--- /dev/null
+fn main() {
+ let _ = Option:Some(vec![0, 1]); //~ ERROR expected type, found
+}
+
+// This case isn't currently being handled gracefully due to the macro invocation.
--- /dev/null
+error: expected type, found reserved keyword `box`
+ --> $DIR/issue-47666.rs:2:25
+ |
+LL | let _ = Option:Some(vec![0, 1]);
+ | ^^^^^^^^^^
+ | |
+ | expected type
+ | in this macro invocation
+ |
+ = note: this warning originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
+
+error: aborting due to previous error
+
--- /dev/null
+use std::collections::BTreeMap;
+
+fn main() {
+ println!("{}", std::mem:size_of::<BTreeMap<u32, u32>>());
+ //~^ ERROR expected token: `,`
+}
--- /dev/null
+error: expected token: `,`
+ --> $DIR/issue-54516.rs:4:58
+ |
+LL | println!("{}", std::mem:size_of::<BTreeMap<u32, u32>>());
+ | - ^ expected `,`
+ | |
+ | help: maybe write a path separator here: `::`
+ |
+ = note: `#![feature(type_ascription)]` lets you annotate an expression with a type: `<expr>: <type>`
+ = note: for more information, see https://github.com/rust-lang/rust/issues/23416
+
+error: aborting due to previous error
+
--- /dev/null
+fn main() {
+ let u: usize = std::mem:size_of::<u32>();
+ //~^ ERROR expected one of
+}
--- /dev/null
+error: expected one of `!`, `::`, or `;`, found `(`
+ --> $DIR/issue-60933.rs:2:43
+ |
+LL | let u: usize = std::mem:size_of::<u32>();
+ | - ^ expected one of `!`, `::`, or `;` here
+ | |
+ | help: maybe write a path separator here: `::`
+ |
+ = note: `#![feature(type_ascription)]` lets you annotate an expression with a type: `<expr>: <type>`
+ = note: for more information, see https://github.com/rust-lang/rust/issues/23416
+
+error: aborting due to previous error
+
--> $DIR/type-ascription-instead-of-initializer.rs:2:31
|
LL | let x: Vec::with_capacity(10, 20);
- | -- ^^
+ | -- ^^ expected type
| ||
| |help: use `=` if you meant to assign
| while parsing the type for `x`
LL | println!("test"):
| - help: try using a semicolon: `;`
LL | 0;
- | ^ expecting a type here because of type ascription
+ | ^ expected type
+ |
+ = note: `#![feature(type_ascription)]` lets you annotate an expression with a type: `<expr>: <type>`
+ = note: for more information, see https://github.com/rust-lang/rust/issues/23416
error: expected type, found `0`
--> $DIR/type-ascription-instead-of-statement-end.rs:9:23
|
LL | println!("test"): 0;
- | ^ expecting a type here because of type ascription
+ | - ^ expected type
+ | |
+ | tried to parse a type due to this type ascription
|
= note: `#![feature(type_ascription)]` lets you annotate an expression with a type: `<expr>: <type>`
-note: this expression expects an ascribed type after the colon
- --> $DIR/type-ascription-instead-of-statement-end.rs:9:5
- |
-LL | println!("test"): 0;
- | ^^^^^^^^^^^^^^^^
- = help: this might be indicative of a syntax error elsewhere
+ = note: for more information, see https://github.com/rust-lang/rust/issues/23416
error: aborting due to 2 previous errors
--> $DIR/typeck_type_placeholder_item.rs:11:15
|
LL | static TEST3: _ = "test";
- | ^ not allowed in type signatures
+ | ^
+ | |
+ | not allowed in type signatures
+ | help: replace `_` with the correct type: `&'static str`
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
--> $DIR/typeck_type_placeholder_item.rs:14:15
|
LL | static TEST4: _ = 145;
- | ^ not allowed in type signatures
+ | ^
+ | |
+ | not allowed in type signatures
+ | help: replace `_` with the correct type: `i32`
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
--> $DIR/typeck_type_placeholder_item.rs:17:16
--> $DIR/typeck_type_placeholder_item.rs:64:22
|
LL | static FN_TEST3: _ = "test";
- | ^ not allowed in type signatures
+ | ^
+ | |
+ | not allowed in type signatures
+ | help: replace `_` with the correct type: `&'static str`
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
--> $DIR/typeck_type_placeholder_item.rs:67:22
|
LL | static FN_TEST4: _ = 145;
- | ^ not allowed in type signatures
+ | ^
+ | |
+ | not allowed in type signatures
+ | help: replace `_` with the correct type: `i32`
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
--> $DIR/typeck_type_placeholder_item.rs:70:23
fn test1() -> _ { Some(42) }
//~^ ERROR the type placeholder `_` is not allowed within types on item signatures
+const TEST2: _ = 42u32;
+//~^ ERROR the type placeholder `_` is not allowed within types on item signatures
+
+const TEST3: _ = Some(42);
+//~^ ERROR the type placeholder `_` is not allowed within types on item signatures
+
+trait Test4 {
+ const TEST4: _ = 42;
+ //~^ ERROR the type placeholder `_` is not allowed within types on item signatures
+}
+
+struct Test5;
+
+impl Test5 {
+ const TEST5: _ = 13;
+ //~^ ERROR the type placeholder `_` is not allowed within types on item signatures
+}
+
pub fn main() {
let _: Option<usize> = test1();
let _: f64 = test1();
| not allowed in type signatures
| help: replace `_` with the correct return type: `std::option::Option<i32>`
-error: aborting due to previous error
+error[E0121]: the type placeholder `_` is not allowed within types on item signatures
+ --> $DIR/typeck_type_placeholder_item_help.rs:7:14
+ |
+LL | const TEST2: _ = 42u32;
+ | ^
+ | |
+ | not allowed in type signatures
+ | help: replace `_` with the correct type: `u32`
+
+error[E0121]: the type placeholder `_` is not allowed within types on item signatures
+ --> $DIR/typeck_type_placeholder_item_help.rs:10:14
+ |
+LL | const TEST3: _ = Some(42);
+ | ^
+ | |
+ | not allowed in type signatures
+ | help: replace `_` with the correct type: `std::option::Option<i32>`
+
+error[E0121]: the type placeholder `_` is not allowed within types on item signatures
+ --> $DIR/typeck_type_placeholder_item_help.rs:14:18
+ |
+LL | const TEST4: _ = 42;
+ | ^
+ | |
+ | not allowed in type signatures
+ | help: replace `_` with the correct type: `i32`
+
+error[E0121]: the type placeholder `_` is not allowed within types on item signatures
+ --> $DIR/typeck_type_placeholder_item_help.rs:21:18
+ |
+LL | const TEST5: _ = 13;
+ | ^
+ | |
+ | not allowed in type signatures
+ | help: replace `_` with the correct type: `i32`
+
+error: aborting due to 5 previous errors
For more information about this error, try `rustc --explain E0121`.
-Subproject commit b5ddc94bf02c641e5acbb08ae742014f40347f10
+Subproject commit b269bb07078446c9c153e0f2acaf83bf8f19b935