Auto merge of #70653 - Centril:rollup-vh5x5e5, r=Centril
Rollup of 6 pull requests Successful merges: - #70511 (Add `-Z dump-mir-dataflow` flag for dumping dataflow results visualization) - #70522 (Improve error messages for raw strings (#60762)) - #70547 (Add `can_unwind` field to `FnAbi`) - #70591 (Ensure LLVM is in the link path for "fulldeps" tests) - #70627 (Use place directly its copy) - #70652 (Add git repo address to unstable book) Failed merges: - #70634 (Remove some reexports in `rustc_middle`) r? @ghost
This commit is contained in:
commit
235938d1ac
@ -21,7 +21,7 @@
|
||||
use crate::native;
|
||||
use crate::tool::{self, SourceType, Tool};
|
||||
use crate::toolstate::ToolState;
|
||||
use crate::util::{self, dylib_path, dylib_path_var};
|
||||
use crate::util::{self, add_link_lib_path, dylib_path, dylib_path_var};
|
||||
use crate::Crate as CargoCrate;
|
||||
use crate::{envify, DocTests, GitRepo, Mode};
|
||||
|
||||
@ -1178,6 +1178,15 @@ fn run(self, builder: &Builder<'_>) {
|
||||
cmd.arg("--system-llvm");
|
||||
}
|
||||
|
||||
// Tests that use compiler libraries may inherit the `-lLLVM` link
|
||||
// requirement, but the `-L` library path is not propagated across
|
||||
// separate compilations. We can add LLVM's library path to the
|
||||
// platform-specific environment variable as a workaround.
|
||||
if !builder.config.dry_run && suite.ends_with("fulldeps") {
|
||||
let llvm_libdir = output(Command::new(&llvm_config).arg("--libdir"));
|
||||
add_link_lib_path(vec![llvm_libdir.trim().into()], &mut cmd);
|
||||
}
|
||||
|
||||
// Only pass correct values for these flags for the `run-make` suite as it
|
||||
// requires that a C++ compiler was configured which isn't always the case.
|
||||
if !builder.config.dry_run && suite == "run-make-fulldeps" {
|
||||
|
@ -1,3 +1,6 @@
|
||||
[book]
|
||||
title = "The Rust Unstable Book"
|
||||
author = "The Rust Community"
|
||||
|
||||
[output.html]
|
||||
git-repository-url = "https://github.com/rust-lang/rust/tree/master/src/doc/unstable-book"
|
||||
|
@ -396,6 +396,11 @@ fn apply_attrs_llfn(&self, cx: &CodegenCx<'ll, 'tcx>, llfn: &'ll Value) {
|
||||
llvm::Attribute::NoReturn.apply_llfn(llvm::AttributePlace::Function, llfn);
|
||||
}
|
||||
|
||||
// FIXME(eddyb, wesleywiser): apply this to callsites as well?
|
||||
if !self.can_unwind {
|
||||
llvm::Attribute::NoUnwind.apply_llfn(llvm::AttributePlace::Function, llfn);
|
||||
}
|
||||
|
||||
let mut i = 0;
|
||||
let mut apply = |attrs: &ArgAttributes, ty: Option<&Type>| {
|
||||
attrs.apply_llfn(llvm::AttributePlace::Argument(i), llfn, ty);
|
||||
@ -431,6 +436,8 @@ fn apply_attrs_llfn(&self, cx: &CodegenCx<'ll, 'tcx>, llfn: &'ll Value) {
|
||||
}
|
||||
|
||||
fn apply_attrs_callsite(&self, bx: &mut Builder<'a, 'll, 'tcx>, callsite: &'ll Value) {
|
||||
// FIXME(wesleywiser, eddyb): We should apply `nounwind` and `noreturn` as appropriate to this callsite.
|
||||
|
||||
let mut i = 0;
|
||||
let mut apply = |attrs: &ArgAttributes, ty: Option<&Type>| {
|
||||
attrs.apply_callsite(llvm::AttributePlace::Argument(i), callsite, ty);
|
||||
|
@ -10,13 +10,10 @@
|
||||
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
|
||||
use rustc_middle::ty::layout::HasTyCtxt;
|
||||
use rustc_middle::ty::query::Providers;
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||
use rustc_middle::ty::{self, TyCtxt};
|
||||
use rustc_session::config::{OptLevel, Sanitizer};
|
||||
use rustc_session::Session;
|
||||
use rustc_target::abi::call::Conv;
|
||||
use rustc_target::spec::PanicStrategy;
|
||||
|
||||
use crate::abi::FnAbi;
|
||||
use crate::attributes;
|
||||
use crate::llvm::AttributePlace::Function;
|
||||
use crate::llvm::{self, Attribute};
|
||||
@ -77,12 +74,6 @@ pub fn emit_uwtable(val: &'ll Value, emit: bool) {
|
||||
Attribute::UWTable.toggle_llfn(Function, val, emit);
|
||||
}
|
||||
|
||||
/// Tell LLVM whether the function can or cannot unwind.
|
||||
#[inline]
|
||||
fn unwind(val: &'ll Value, can_unwind: bool) {
|
||||
Attribute::NoUnwind.toggle_llfn(Function, val, !can_unwind);
|
||||
}
|
||||
|
||||
/// Tell LLVM if this function should be 'naked', i.e., skip the epilogue and prologue.
|
||||
#[inline]
|
||||
fn naked(val: &'ll Value, is_naked: bool) {
|
||||
@ -246,12 +237,7 @@ pub(crate) fn default_optimisation_attrs(sess: &Session, llfn: &'ll Value) {
|
||||
|
||||
/// Composite function which sets LLVM attributes for function depending on its AST (`#[attribute]`)
|
||||
/// attributes.
|
||||
pub fn from_fn_attrs(
|
||||
cx: &CodegenCx<'ll, 'tcx>,
|
||||
llfn: &'ll Value,
|
||||
instance: ty::Instance<'tcx>,
|
||||
fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
|
||||
) {
|
||||
pub fn from_fn_attrs(cx: &CodegenCx<'ll, 'tcx>, llfn: &'ll Value, instance: ty::Instance<'tcx>) {
|
||||
let codegen_fn_attrs = cx.tcx.codegen_fn_attrs(instance.def_id());
|
||||
|
||||
match codegen_fn_attrs.optimize {
|
||||
@ -315,46 +301,6 @@ pub fn from_fn_attrs(
|
||||
}
|
||||
sanitize(cx, codegen_fn_attrs.flags, llfn);
|
||||
|
||||
unwind(
|
||||
llfn,
|
||||
if cx.tcx.sess.panic_strategy() != PanicStrategy::Unwind {
|
||||
// In panic=abort mode we assume nothing can unwind anywhere, so
|
||||
// optimize based on this!
|
||||
false
|
||||
} else if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::UNWIND) {
|
||||
// If a specific #[unwind] attribute is present, use that.
|
||||
true
|
||||
} else if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::RUSTC_ALLOCATOR_NOUNWIND) {
|
||||
// Special attribute for allocator functions, which can't unwind.
|
||||
false
|
||||
} else {
|
||||
if fn_abi.conv == Conv::Rust {
|
||||
// Any Rust method (or `extern "Rust" fn` or `extern
|
||||
// "rust-call" fn`) is explicitly allowed to unwind
|
||||
// (unless it has no-unwind attribute, handled above).
|
||||
true
|
||||
} else {
|
||||
// Anything else is either:
|
||||
//
|
||||
// 1. A foreign item using a non-Rust ABI (like `extern "C" { fn foo(); }`), or
|
||||
//
|
||||
// 2. A Rust item using a non-Rust ABI (like `extern "C" fn foo() { ... }`).
|
||||
//
|
||||
// Foreign items (case 1) are assumed to not unwind; it is
|
||||
// UB otherwise. (At least for now; see also
|
||||
// rust-lang/rust#63909 and Rust RFC 2753.)
|
||||
//
|
||||
// Items defined in Rust with non-Rust ABIs (case 2) are also
|
||||
// not supposed to unwind. Whether this should be enforced
|
||||
// (versus stating it is UB) and *how* it would be enforced
|
||||
// is currently under discussion; see rust-lang/rust#58794.
|
||||
//
|
||||
// In either case, we mark item as explicitly nounwind.
|
||||
false
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
// Always annotate functions with the target-cpu they are compiled for.
|
||||
// Without this, ThinLTO won't inline Rust functions into Clang generated
|
||||
// functions (because Clang annotates functions this way too).
|
||||
|
@ -78,7 +78,7 @@ pub fn get_fn(cx: &CodegenCx<'ll, 'tcx>, instance: Instance<'tcx>) -> &'ll Value
|
||||
let llfn = cx.declare_fn(&sym, &fn_abi);
|
||||
debug!("get_fn: not casting pointer!");
|
||||
|
||||
attributes::from_fn_attrs(cx, llfn, instance, &fn_abi);
|
||||
attributes::from_fn_attrs(cx, llfn, instance);
|
||||
|
||||
let instance_def_id = instance.def_id();
|
||||
|
||||
|
@ -77,7 +77,7 @@ fn predefine_fn(
|
||||
|
||||
debug!("predefine_fn: instance = {:?}", instance);
|
||||
|
||||
attributes::from_fn_attrs(self, lldecl, instance, &fn_abi);
|
||||
attributes::from_fn_attrs(self, lldecl, instance);
|
||||
|
||||
self.instances.borrow_mut().insert(instance, lldecl);
|
||||
}
|
||||
|
@ -299,7 +299,7 @@ fn codegen_drop_terminator(
|
||||
&mut self,
|
||||
helper: TerminatorCodegenHelper<'tcx>,
|
||||
mut bx: Bx,
|
||||
location: &mir::Place<'tcx>,
|
||||
location: mir::Place<'tcx>,
|
||||
target: mir::BasicBlock,
|
||||
unwind: Option<mir::BasicBlock>,
|
||||
) {
|
||||
@ -580,7 +580,7 @@ fn codegen_call_terminator(
|
||||
|
||||
if intrinsic == Some("transmute") {
|
||||
if let Some(destination_ref) = destination.as_ref() {
|
||||
let &(ref dest, target) = destination_ref;
|
||||
let &(dest, target) = destination_ref;
|
||||
self.codegen_transmute(&mut bx, &args[0], dest);
|
||||
helper.maybe_sideeffect(self.mir, &mut bx, &[target]);
|
||||
helper.funclet_br(self, &mut bx, target);
|
||||
@ -619,7 +619,7 @@ fn codegen_call_terminator(
|
||||
let mut llargs = Vec::with_capacity(arg_count);
|
||||
|
||||
// Prepare the return value destination
|
||||
let ret_dest = if let Some((ref dest, _)) = *destination {
|
||||
let ret_dest = if let Some((dest, _)) = *destination {
|
||||
let is_intrinsic = intrinsic.is_some();
|
||||
self.make_return_dest(&mut bx, dest, &fn_abi.ret, &mut llargs, is_intrinsic)
|
||||
} else {
|
||||
@ -873,7 +873,7 @@ fn codegen_terminator(
|
||||
bx.unreachable();
|
||||
}
|
||||
|
||||
mir::TerminatorKind::Drop { ref location, target, unwind } => {
|
||||
mir::TerminatorKind::Drop { location, target, unwind } => {
|
||||
self.codegen_drop_terminator(helper, bx, location, target, unwind);
|
||||
}
|
||||
|
||||
@ -1123,7 +1123,7 @@ pub fn build_block(&self, bb: mir::BasicBlock) -> Bx {
|
||||
fn make_return_dest(
|
||||
&mut self,
|
||||
bx: &mut Bx,
|
||||
dest: &mir::Place<'tcx>,
|
||||
dest: mir::Place<'tcx>,
|
||||
fn_ret: &ArgAbi<'tcx, Ty<'tcx>>,
|
||||
llargs: &mut Vec<Bx::Value>,
|
||||
is_intrinsic: bool,
|
||||
@ -1184,7 +1184,7 @@ fn make_return_dest(
|
||||
}
|
||||
}
|
||||
|
||||
fn codegen_transmute(&mut self, bx: &mut Bx, src: &mir::Operand<'tcx>, dst: &mir::Place<'tcx>) {
|
||||
fn codegen_transmute(&mut self, bx: &mut Bx, src: &mir::Operand<'tcx>, dst: mir::Place<'tcx>) {
|
||||
if let Some(index) = dst.as_local() {
|
||||
match self.locals[index] {
|
||||
LocalRef::Place(place) => self.codegen_transmute_into(bx, src, place),
|
||||
|
@ -383,7 +383,7 @@ pub fn codegen_rvalue_operand(
|
||||
(bx, OperandRef { val, layout: cast })
|
||||
}
|
||||
|
||||
mir::Rvalue::Ref(_, bk, ref place) => {
|
||||
mir::Rvalue::Ref(_, bk, place) => {
|
||||
let mk_ref = move |tcx: TyCtxt<'tcx>, ty: Ty<'tcx>| {
|
||||
tcx.mk_ref(
|
||||
tcx.lifetimes.re_erased,
|
||||
@ -393,14 +393,14 @@ pub fn codegen_rvalue_operand(
|
||||
self.codegen_place_to_pointer(bx, place, mk_ref)
|
||||
}
|
||||
|
||||
mir::Rvalue::AddressOf(mutability, ref place) => {
|
||||
mir::Rvalue::AddressOf(mutability, place) => {
|
||||
let mk_ptr = move |tcx: TyCtxt<'tcx>, ty: Ty<'tcx>| {
|
||||
tcx.mk_ptr(ty::TypeAndMut { ty, mutbl: mutability })
|
||||
};
|
||||
self.codegen_place_to_pointer(bx, place, mk_ptr)
|
||||
}
|
||||
|
||||
mir::Rvalue::Len(ref place) => {
|
||||
mir::Rvalue::Len(place) => {
|
||||
let size = self.evaluate_array_len(&mut bx, place);
|
||||
let operand = OperandRef {
|
||||
val: OperandValue::Immediate(size),
|
||||
@ -537,7 +537,7 @@ pub fn codegen_rvalue_operand(
|
||||
}
|
||||
}
|
||||
|
||||
fn evaluate_array_len(&mut self, bx: &mut Bx, place: &mir::Place<'tcx>) -> Bx::Value {
|
||||
fn evaluate_array_len(&mut self, bx: &mut Bx, place: mir::Place<'tcx>) -> Bx::Value {
|
||||
// ZST are passed as operands and require special handling
|
||||
// because codegen_place() panics if Local is operand.
|
||||
if let Some(index) = place.as_local() {
|
||||
@ -557,7 +557,7 @@ fn evaluate_array_len(&mut self, bx: &mut Bx, place: &mir::Place<'tcx>) -> Bx::V
|
||||
fn codegen_place_to_pointer(
|
||||
&mut self,
|
||||
mut bx: Bx,
|
||||
place: &mir::Place<'tcx>,
|
||||
place: mir::Place<'tcx>,
|
||||
mk_ptr_ty: impl FnOnce(TyCtxt<'tcx>, Ty<'tcx>) -> Ty<'tcx>,
|
||||
) -> (Bx, OperandRef<'tcx, Bx::Value>) {
|
||||
let cg_place = self.codegen_place(&mut bx, place.as_ref());
|
||||
|
@ -562,6 +562,8 @@ fn test_debugging_options_tracking_hash() {
|
||||
assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
|
||||
opts.debugging_opts.dump_mir_graphviz = true;
|
||||
assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
|
||||
opts.debugging_opts.dump_mir_dataflow = true;
|
||||
assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
|
||||
|
||||
// Make sure changing a [TRACKED] option changes the hash
|
||||
opts = reference.clone();
|
||||
|
@ -17,9 +17,13 @@
|
||||
mod cursor;
|
||||
pub mod unescape;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
use self::LiteralKind::*;
|
||||
use self::TokenKind::*;
|
||||
use crate::cursor::{Cursor, EOF_CHAR};
|
||||
use std::convert::TryInto;
|
||||
|
||||
/// Parsed token.
|
||||
/// It doesn't contain information about data that has been parsed,
|
||||
@ -132,9 +136,80 @@ pub enum LiteralKind {
|
||||
/// "b"abc"", "b"abc"
|
||||
ByteStr { terminated: bool },
|
||||
/// "r"abc"", "r#"abc"#", "r####"ab"###"c"####", "r#"a"
|
||||
RawStr { n_hashes: usize, started: bool, terminated: bool },
|
||||
RawStr(UnvalidatedRawStr),
|
||||
/// "br"abc"", "br#"abc"#", "br####"ab"###"c"####", "br#"a"
|
||||
RawByteStr { n_hashes: usize, started: bool, terminated: bool },
|
||||
RawByteStr(UnvalidatedRawStr),
|
||||
}
|
||||
|
||||
/// Represents something that looks like a raw string, but may have some
|
||||
/// problems. Use `.validate()` to convert it into something
|
||||
/// usable.
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub struct UnvalidatedRawStr {
|
||||
/// The prefix (`r###"`) is valid
|
||||
valid_start: bool,
|
||||
/// The number of leading `#`
|
||||
n_start_hashes: usize,
|
||||
/// The number of trailing `#`. `n_end_hashes` <= `n_start_hashes`
|
||||
n_end_hashes: usize,
|
||||
/// The offset starting at `r` or `br` where the user may have intended to end the string.
|
||||
/// Currently, it is the longest sequence of pattern `"#+"`.
|
||||
possible_terminator_offset: Option<usize>,
|
||||
}
|
||||
|
||||
/// Error produced validating a raw string. Represents cases like:
|
||||
/// - `r##~"abcde"##`: `LexRawStrError::InvalidStarter`
|
||||
/// - `r###"abcde"##`: `LexRawStrError::NoTerminator { expected: 3, found: 2, possible_terminator_offset: Some(11)`
|
||||
/// - Too many `#`s (>65536): `TooManyDelimiters`
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub enum LexRawStrError {
|
||||
/// Non `#` characters exist between `r` and `"` eg. `r#~"..`
|
||||
InvalidStarter,
|
||||
/// The string was never terminated. `possible_terminator_offset` is the number of characters after `r` or `br` where they
|
||||
/// may have intended to terminate it.
|
||||
NoTerminator { expected: usize, found: usize, possible_terminator_offset: Option<usize> },
|
||||
/// More than 65536 `#`s exist.
|
||||
TooManyDelimiters,
|
||||
}
|
||||
|
||||
/// Raw String that contains a valid prefix (`#+"`) and postfix (`"#+`) where
|
||||
/// there are a matching number of `#` characters in both. Note that this will
|
||||
/// not consume extra trailing `#` characters: `r###"abcde"####` is lexed as a
|
||||
/// `ValidatedRawString { n_hashes: 3 }` followed by a `#` token.
|
||||
#[derive(Debug, Eq, PartialEq, Copy, Clone)]
|
||||
pub struct ValidatedRawStr {
|
||||
n_hashes: u16,
|
||||
}
|
||||
|
||||
impl ValidatedRawStr {
|
||||
pub fn num_hashes(&self) -> u16 {
|
||||
self.n_hashes
|
||||
}
|
||||
}
|
||||
|
||||
impl UnvalidatedRawStr {
|
||||
pub fn validate(self) -> Result<ValidatedRawStr, LexRawStrError> {
|
||||
if !self.valid_start {
|
||||
return Err(LexRawStrError::InvalidStarter);
|
||||
}
|
||||
|
||||
// Only up to 65535 `#`s are allowed in raw strings
|
||||
let n_start_safe: u16 =
|
||||
self.n_start_hashes.try_into().map_err(|_| LexRawStrError::TooManyDelimiters)?;
|
||||
|
||||
if self.n_start_hashes > self.n_end_hashes {
|
||||
Err(LexRawStrError::NoTerminator {
|
||||
expected: self.n_start_hashes,
|
||||
found: self.n_end_hashes,
|
||||
possible_terminator_offset: self.possible_terminator_offset,
|
||||
})
|
||||
} else {
|
||||
// Since the lexer should never produce a literal with n_end > n_start, if n_start <= n_end,
|
||||
// they must be equal.
|
||||
debug_assert_eq!(self.n_start_hashes, self.n_end_hashes);
|
||||
Ok(ValidatedRawStr { n_hashes: n_start_safe })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Base of numeric literal encoding according to its prefix.
|
||||
@ -209,7 +284,7 @@ pub fn is_whitespace(c: char) -> bool {
|
||||
// Dedicated whitespace characters from Unicode
|
||||
| '\u{2028}' // LINE SEPARATOR
|
||||
| '\u{2029}' // PARAGRAPH SEPARATOR
|
||||
=> true,
|
||||
=> true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
@ -258,12 +333,12 @@ fn advance_token(&mut self) -> Token {
|
||||
'r' => match (self.first(), self.second()) {
|
||||
('#', c1) if is_id_start(c1) => self.raw_ident(),
|
||||
('#', _) | ('"', _) => {
|
||||
let (n_hashes, started, terminated) = self.raw_double_quoted_string();
|
||||
let raw_str_i = self.raw_double_quoted_string(1);
|
||||
let suffix_start = self.len_consumed();
|
||||
if terminated {
|
||||
if raw_str_i.n_end_hashes == raw_str_i.n_start_hashes {
|
||||
self.eat_literal_suffix();
|
||||
}
|
||||
let kind = RawStr { n_hashes, started, terminated };
|
||||
let kind = RawStr(raw_str_i);
|
||||
Literal { kind, suffix_start }
|
||||
}
|
||||
_ => self.ident(),
|
||||
@ -293,12 +368,14 @@ fn advance_token(&mut self) -> Token {
|
||||
}
|
||||
('r', '"') | ('r', '#') => {
|
||||
self.bump();
|
||||
let (n_hashes, started, terminated) = self.raw_double_quoted_string();
|
||||
let raw_str_i = self.raw_double_quoted_string(2);
|
||||
let suffix_start = self.len_consumed();
|
||||
let terminated = raw_str_i.n_start_hashes == raw_str_i.n_end_hashes;
|
||||
if terminated {
|
||||
self.eat_literal_suffix();
|
||||
}
|
||||
let kind = RawByteStr { n_hashes, started, terminated };
|
||||
|
||||
let kind = RawByteStr(raw_str_i);
|
||||
Literal { kind, suffix_start }
|
||||
}
|
||||
_ => self.ident(),
|
||||
@ -594,29 +671,41 @@ fn double_quoted_string(&mut self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
/// Eats the double-quoted string and returns a tuple of
|
||||
/// (amount of the '#' symbols, raw string started, raw string terminated)
|
||||
fn raw_double_quoted_string(&mut self) -> (usize, bool, bool) {
|
||||
/// Eats the double-quoted string and returns an `UnvalidatedRawStr`.
|
||||
fn raw_double_quoted_string(&mut self, prefix_len: usize) -> UnvalidatedRawStr {
|
||||
debug_assert!(self.prev() == 'r');
|
||||
let mut started: bool = false;
|
||||
let mut finished: bool = false;
|
||||
let mut valid_start: bool = false;
|
||||
let start_pos = self.len_consumed();
|
||||
let (mut possible_terminator_offset, mut max_hashes) = (None, 0);
|
||||
|
||||
// Count opening '#' symbols.
|
||||
let n_hashes = self.eat_while(|c| c == '#');
|
||||
let n_start_hashes = self.eat_while(|c| c == '#');
|
||||
|
||||
// Check that string is started.
|
||||
match self.bump() {
|
||||
Some('"') => started = true,
|
||||
_ => return (n_hashes, started, finished),
|
||||
Some('"') => valid_start = true,
|
||||
_ => {
|
||||
return UnvalidatedRawStr {
|
||||
valid_start,
|
||||
n_start_hashes,
|
||||
n_end_hashes: 0,
|
||||
possible_terminator_offset,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// Skip the string contents and on each '#' character met, check if this is
|
||||
// a raw string termination.
|
||||
while !finished {
|
||||
loop {
|
||||
self.eat_while(|c| c != '"');
|
||||
|
||||
if self.is_eof() {
|
||||
return (n_hashes, started, finished);
|
||||
return UnvalidatedRawStr {
|
||||
valid_start,
|
||||
n_start_hashes,
|
||||
n_end_hashes: max_hashes,
|
||||
possible_terminator_offset,
|
||||
};
|
||||
}
|
||||
|
||||
// Eat closing double quote.
|
||||
@ -624,7 +713,7 @@ fn raw_double_quoted_string(&mut self) -> (usize, bool, bool) {
|
||||
|
||||
// Check that amount of closing '#' symbols
|
||||
// is equal to the amount of opening ones.
|
||||
let mut hashes_left = n_hashes;
|
||||
let mut hashes_left = n_start_hashes;
|
||||
let is_closing_hash = |c| {
|
||||
if c == '#' && hashes_left != 0 {
|
||||
hashes_left -= 1;
|
||||
@ -633,10 +722,23 @@ fn raw_double_quoted_string(&mut self) -> (usize, bool, bool) {
|
||||
false
|
||||
}
|
||||
};
|
||||
finished = self.eat_while(is_closing_hash) == n_hashes;
|
||||
}
|
||||
let n_end_hashes = self.eat_while(is_closing_hash);
|
||||
|
||||
(n_hashes, started, finished)
|
||||
if n_end_hashes == n_start_hashes {
|
||||
return UnvalidatedRawStr {
|
||||
valid_start,
|
||||
n_start_hashes,
|
||||
n_end_hashes,
|
||||
possible_terminator_offset: None,
|
||||
};
|
||||
} else if n_end_hashes > max_hashes {
|
||||
// Keep track of possible terminators to give a hint about where there might be
|
||||
// a missing terminator
|
||||
possible_terminator_offset =
|
||||
Some(self.len_consumed() - start_pos - n_end_hashes + prefix_len);
|
||||
max_hashes = n_end_hashes;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn eat_decimal_digits(&mut self) -> bool {
|
||||
|
121
src/librustc_lexer/src/tests.rs
Normal file
121
src/librustc_lexer/src/tests.rs
Normal file
@ -0,0 +1,121 @@
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::*;
|
||||
|
||||
fn check_raw_str(
|
||||
s: &str,
|
||||
expected: UnvalidatedRawStr,
|
||||
validated: Result<ValidatedRawStr, LexRawStrError>,
|
||||
) {
|
||||
let s = &format!("r{}", s);
|
||||
let mut cursor = Cursor::new(s);
|
||||
cursor.bump();
|
||||
let tok = cursor.raw_double_quoted_string(0);
|
||||
assert_eq!(tok, expected);
|
||||
assert_eq!(tok.validate(), validated);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_naked_raw_str() {
|
||||
check_raw_str(
|
||||
r#""abc""#,
|
||||
UnvalidatedRawStr {
|
||||
n_start_hashes: 0,
|
||||
n_end_hashes: 0,
|
||||
valid_start: true,
|
||||
possible_terminator_offset: None,
|
||||
},
|
||||
Ok(ValidatedRawStr { n_hashes: 0 }),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_raw_no_start() {
|
||||
check_raw_str(
|
||||
r##""abc"#"##,
|
||||
UnvalidatedRawStr {
|
||||
n_start_hashes: 0,
|
||||
n_end_hashes: 0,
|
||||
valid_start: true,
|
||||
possible_terminator_offset: None,
|
||||
},
|
||||
Ok(ValidatedRawStr { n_hashes: 0 }),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_too_many_terminators() {
|
||||
// this error is handled in the parser later
|
||||
check_raw_str(
|
||||
r###"#"abc"##"###,
|
||||
UnvalidatedRawStr {
|
||||
n_start_hashes: 1,
|
||||
n_end_hashes: 1,
|
||||
valid_start: true,
|
||||
possible_terminator_offset: None,
|
||||
},
|
||||
Ok(ValidatedRawStr { n_hashes: 1 }),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_unterminated() {
|
||||
check_raw_str(
|
||||
r#"#"abc"#,
|
||||
UnvalidatedRawStr {
|
||||
n_start_hashes: 1,
|
||||
n_end_hashes: 0,
|
||||
valid_start: true,
|
||||
possible_terminator_offset: None,
|
||||
},
|
||||
Err(LexRawStrError::NoTerminator {
|
||||
expected: 1,
|
||||
found: 0,
|
||||
possible_terminator_offset: None,
|
||||
}),
|
||||
);
|
||||
check_raw_str(
|
||||
r###"##"abc"#"###,
|
||||
UnvalidatedRawStr {
|
||||
n_start_hashes: 2,
|
||||
n_end_hashes: 1,
|
||||
valid_start: true,
|
||||
possible_terminator_offset: Some(7),
|
||||
},
|
||||
Err(LexRawStrError::NoTerminator {
|
||||
expected: 2,
|
||||
found: 1,
|
||||
possible_terminator_offset: Some(7),
|
||||
}),
|
||||
);
|
||||
// We're looking for "# not just any #
|
||||
check_raw_str(
|
||||
r###"##"abc#"###,
|
||||
UnvalidatedRawStr {
|
||||
n_start_hashes: 2,
|
||||
n_end_hashes: 0,
|
||||
valid_start: true,
|
||||
possible_terminator_offset: None,
|
||||
},
|
||||
Err(LexRawStrError::NoTerminator {
|
||||
expected: 2,
|
||||
found: 0,
|
||||
possible_terminator_offset: None,
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_invalid_start() {
|
||||
check_raw_str(
|
||||
r##"#~"abc"#"##,
|
||||
UnvalidatedRawStr {
|
||||
n_start_hashes: 1,
|
||||
n_end_hashes: 0,
|
||||
valid_start: false,
|
||||
possible_terminator_offset: None,
|
||||
},
|
||||
Err(LexRawStrError::InvalidStarter),
|
||||
);
|
||||
}
|
||||
}
|
@ -2030,9 +2030,9 @@ pub fn to_copy(&self) -> Self {
|
||||
|
||||
/// Returns the `Place` that is the target of this `Operand`, or `None` if this `Operand` is a
|
||||
/// constant.
|
||||
pub fn place(&self) -> Option<&Place<'tcx>> {
|
||||
pub fn place(&self) -> Option<Place<'tcx>> {
|
||||
match self {
|
||||
Operand::Copy(place) | Operand::Move(place) => Some(place),
|
||||
Operand::Copy(place) | Operand::Move(place) => Some(*place),
|
||||
Operand::Constant(_) => None,
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
use crate::ich::StableHashingContext;
|
||||
use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags;
|
||||
use crate::mir::{GeneratorLayout, GeneratorSavedLocal};
|
||||
use crate::ty::subst::Subst;
|
||||
use crate::ty::{self, subst::SubstsRef, ReprOptions, Ty, TyCtxt, TypeFoldable};
|
||||
@ -15,7 +16,7 @@
|
||||
ArgAbi, ArgAttribute, ArgAttributes, Conv, FnAbi, PassMode, Reg, RegKind,
|
||||
};
|
||||
pub use rustc_target::abi::*;
|
||||
use rustc_target::spec::{abi::Abi as SpecAbi, HasTargetSpec};
|
||||
use rustc_target::spec::{abi::Abi as SpecAbi, HasTargetSpec, PanicStrategy};
|
||||
|
||||
use std::cmp;
|
||||
use std::fmt;
|
||||
@ -2368,11 +2369,55 @@ fn new_internal(
|
||||
sig: ty::PolyFnSig<'tcx>,
|
||||
extra_args: &[Ty<'tcx>],
|
||||
caller_location: Option<Ty<'tcx>>,
|
||||
codegen_fn_attr_flags: CodegenFnAttrFlags,
|
||||
mk_arg_type: impl Fn(Ty<'tcx>, Option<usize>) -> ArgAbi<'tcx, Ty<'tcx>>,
|
||||
) -> Self;
|
||||
fn adjust_for_abi(&mut self, cx: &C, abi: SpecAbi);
|
||||
}
|
||||
|
||||
fn fn_can_unwind(
|
||||
panic_strategy: PanicStrategy,
|
||||
codegen_fn_attr_flags: CodegenFnAttrFlags,
|
||||
call_conv: Conv,
|
||||
) -> bool {
|
||||
if panic_strategy != PanicStrategy::Unwind {
|
||||
// In panic=abort mode we assume nothing can unwind anywhere, so
|
||||
// optimize based on this!
|
||||
false
|
||||
} else if codegen_fn_attr_flags.contains(CodegenFnAttrFlags::UNWIND) {
|
||||
// If a specific #[unwind] attribute is present, use that.
|
||||
true
|
||||
} else if codegen_fn_attr_flags.contains(CodegenFnAttrFlags::RUSTC_ALLOCATOR_NOUNWIND) {
|
||||
// Special attribute for allocator functions, which can't unwind.
|
||||
false
|
||||
} else {
|
||||
if call_conv == Conv::Rust {
|
||||
// Any Rust method (or `extern "Rust" fn` or `extern
|
||||
// "rust-call" fn`) is explicitly allowed to unwind
|
||||
// (unless it has no-unwind attribute, handled above).
|
||||
true
|
||||
} else {
|
||||
// Anything else is either:
|
||||
//
|
||||
// 1. A foreign item using a non-Rust ABI (like `extern "C" { fn foo(); }`), or
|
||||
//
|
||||
// 2. A Rust item using a non-Rust ABI (like `extern "C" fn foo() { ... }`).
|
||||
//
|
||||
// Foreign items (case 1) are assumed to not unwind; it is
|
||||
// UB otherwise. (At least for now; see also
|
||||
// rust-lang/rust#63909 and Rust RFC 2753.)
|
||||
//
|
||||
// Items defined in Rust with non-Rust ABIs (case 2) are also
|
||||
// not supposed to unwind. Whether this should be enforced
|
||||
// (versus stating it is UB) and *how* it would be enforced
|
||||
// is currently under discussion; see rust-lang/rust#58794.
|
||||
//
|
||||
// In either case, we mark item as explicitly nounwind.
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx, C> FnAbiExt<'tcx, C> for call::FnAbi<'tcx, Ty<'tcx>>
|
||||
where
|
||||
C: LayoutOf<Ty = Ty<'tcx>, TyAndLayout = TyAndLayout<'tcx>>
|
||||
@ -2382,7 +2427,12 @@ impl<'tcx, C> FnAbiExt<'tcx, C> for call::FnAbi<'tcx, Ty<'tcx>>
|
||||
+ HasParamEnv<'tcx>,
|
||||
{
|
||||
fn of_fn_ptr(cx: &C, sig: ty::PolyFnSig<'tcx>, extra_args: &[Ty<'tcx>]) -> Self {
|
||||
call::FnAbi::new_internal(cx, sig, extra_args, None, |ty, _| ArgAbi::new(cx.layout_of(ty)))
|
||||
// Assume that fn pointers may always unwind
|
||||
let codegen_fn_attr_flags = CodegenFnAttrFlags::UNWIND;
|
||||
|
||||
call::FnAbi::new_internal(cx, sig, extra_args, None, codegen_fn_attr_flags, |ty, _| {
|
||||
ArgAbi::new(cx.layout_of(ty))
|
||||
})
|
||||
}
|
||||
|
||||
fn of_instance(cx: &C, instance: ty::Instance<'tcx>, extra_args: &[Ty<'tcx>]) -> Self {
|
||||
@ -2394,7 +2444,9 @@ fn of_instance(cx: &C, instance: ty::Instance<'tcx>, extra_args: &[Ty<'tcx>]) ->
|
||||
None
|
||||
};
|
||||
|
||||
call::FnAbi::new_internal(cx, sig, extra_args, caller_location, |ty, arg_idx| {
|
||||
let attrs = cx.tcx().codegen_fn_attrs(instance.def_id()).flags;
|
||||
|
||||
call::FnAbi::new_internal(cx, sig, extra_args, caller_location, attrs, |ty, arg_idx| {
|
||||
let mut layout = cx.layout_of(ty);
|
||||
// Don't pass the vtable, it's not an argument of the virtual fn.
|
||||
// Instead, pass just the data pointer, but give it the type `*const/mut dyn Trait`
|
||||
@ -2450,6 +2502,7 @@ fn new_internal(
|
||||
sig: ty::PolyFnSig<'tcx>,
|
||||
extra_args: &[Ty<'tcx>],
|
||||
caller_location: Option<Ty<'tcx>>,
|
||||
codegen_fn_attr_flags: CodegenFnAttrFlags,
|
||||
mk_arg_type: impl Fn(Ty<'tcx>, Option<usize>) -> ArgAbi<'tcx, Ty<'tcx>>,
|
||||
) -> Self {
|
||||
debug!("FnAbi::new_internal({:?}, {:?})", sig, extra_args);
|
||||
@ -2639,6 +2692,7 @@ fn new_internal(
|
||||
c_variadic: sig.c_variadic,
|
||||
fixed_count: inputs.len(),
|
||||
conv,
|
||||
can_unwind: fn_can_unwind(cx.tcx().sess.panic_strategy(), codegen_fn_attr_flags, conv),
|
||||
};
|
||||
fn_abi.adjust_for_abi(cx, sig.abi);
|
||||
fn_abi
|
||||
|
@ -206,7 +206,7 @@ fn visit_assign(
|
||||
let idx = self.idx_vec.push(borrow);
|
||||
self.location_map.insert(location, idx);
|
||||
|
||||
self.insert_as_pending_if_two_phase(location, &assigned_place, kind, idx);
|
||||
self.insert_as_pending_if_two_phase(location, assigned_place, kind, idx);
|
||||
|
||||
self.local_map.entry(borrowed_place.local).or_default().insert(idx);
|
||||
}
|
||||
|
@ -114,7 +114,7 @@ fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
|
||||
fn visit_assign(&mut self, place: &Place<'tcx>, rvalue: &Rvalue<'tcx>, location: Location) {
|
||||
// When we see `X = ...`, then kill borrows of
|
||||
// `(*X).foo` and so forth.
|
||||
self.record_killed_borrows_for_place(place, location);
|
||||
self.record_killed_borrows_for_place(*place, location);
|
||||
|
||||
self.super_assign(place, rvalue, location);
|
||||
}
|
||||
@ -139,7 +139,7 @@ fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location
|
||||
|
||||
// A `Call` terminator's return value can be a local which has borrows,
|
||||
// so we need to record those as `killed` as well.
|
||||
if let TerminatorKind::Call { ref destination, .. } = terminator.kind {
|
||||
if let TerminatorKind::Call { destination, .. } = terminator.kind {
|
||||
if let Some((place, _)) = destination {
|
||||
self.record_killed_borrows_for_place(place, location);
|
||||
}
|
||||
@ -177,7 +177,7 @@ fn add_regular_live_constraint<T>(&mut self, live_ty: T, location: Location)
|
||||
|
||||
/// When recording facts for Polonius, records the borrows on the specified place
|
||||
/// as `killed`. For example, when assigning to a local, or on a call's return destination.
|
||||
fn record_killed_borrows_for_place(&mut self, place: &Place<'tcx>, location: Location) {
|
||||
fn record_killed_borrows_for_place(&mut self, place: Place<'tcx>, location: Location) {
|
||||
if let Some(all_facts) = self.all_facts {
|
||||
let _prof_timer = self.infcx.tcx.prof.generic_activity("polonius_fact_generation");
|
||||
|
||||
@ -217,7 +217,7 @@ fn record_killed_borrows_for_place(&mut self, place: &Place<'tcx>, location: Loc
|
||||
let places_conflict = places_conflict::places_conflict(
|
||||
self.infcx.tcx,
|
||||
self.body,
|
||||
&self.borrow_set.borrows[borrow_index].borrowed_place,
|
||||
self.borrow_set.borrows[borrow_index].borrowed_place,
|
||||
place,
|
||||
places_conflict::PlaceConflictBias::NoOverlap,
|
||||
);
|
||||
|
@ -247,7 +247,7 @@ pub(in crate::borrow_check) fn report_use_of_moved_or_uninitialized(
|
||||
pub(in crate::borrow_check) fn report_move_out_while_borrowed(
|
||||
&mut self,
|
||||
location: Location,
|
||||
(place, span): (&Place<'tcx>, Span),
|
||||
(place, span): (Place<'tcx>, Span),
|
||||
borrow: &BorrowData<'tcx>,
|
||||
) {
|
||||
debug!(
|
||||
@ -291,7 +291,7 @@ pub(in crate::borrow_check) fn report_move_out_while_borrowed(
|
||||
pub(in crate::borrow_check) fn report_use_while_mutably_borrowed(
|
||||
&mut self,
|
||||
location: Location,
|
||||
(place, _span): (&Place<'tcx>, Span),
|
||||
(place, _span): (Place<'tcx>, Span),
|
||||
borrow: &BorrowData<'tcx>,
|
||||
) -> DiagnosticBuilder<'cx> {
|
||||
let borrow_spans = self.retrieve_borrow_spans(borrow);
|
||||
@ -330,7 +330,7 @@ pub(in crate::borrow_check) fn report_use_while_mutably_borrowed(
|
||||
pub(in crate::borrow_check) fn report_conflicting_borrow(
|
||||
&mut self,
|
||||
location: Location,
|
||||
(place, span): (&Place<'tcx>, Span),
|
||||
(place, span): (Place<'tcx>, Span),
|
||||
gen_borrow_kind: BorrowKind,
|
||||
issued_borrow: &BorrowData<'tcx>,
|
||||
) -> DiagnosticBuilder<'cx> {
|
||||
@ -347,7 +347,7 @@ pub(in crate::borrow_check) fn report_conflicting_borrow(
|
||||
};
|
||||
|
||||
let (desc_place, msg_place, msg_borrow, union_type_name) =
|
||||
self.describe_place_for_conflicting_borrow(place, &issued_borrow.borrowed_place);
|
||||
self.describe_place_for_conflicting_borrow(place, issued_borrow.borrowed_place);
|
||||
|
||||
let explanation = self.explain_why_borrow_contains_point(location, issued_borrow, None);
|
||||
let second_borrow_desc = if explanation.is_explained() { "second " } else { "" };
|
||||
@ -396,8 +396,8 @@ pub(in crate::borrow_check) fn report_conflicting_borrow(
|
||||
);
|
||||
self.suggest_split_at_mut_if_applicable(
|
||||
&mut err,
|
||||
&place,
|
||||
&issued_borrow.borrowed_place,
|
||||
place,
|
||||
issued_borrow.borrowed_place,
|
||||
);
|
||||
err
|
||||
}
|
||||
@ -410,7 +410,7 @@ pub(in crate::borrow_check) fn report_conflicting_borrow(
|
||||
(BorrowKind::Mut { .. }, BorrowKind::Shallow)
|
||||
| (BorrowKind::Unique, BorrowKind::Shallow) => {
|
||||
if let Some(immutable_section_description) =
|
||||
self.classify_immutable_section(&issued_borrow.assigned_place)
|
||||
self.classify_immutable_section(issued_borrow.assigned_place)
|
||||
{
|
||||
let mut err = self.cannot_mutate_in_immutable_section(
|
||||
span,
|
||||
@ -546,8 +546,8 @@ pub(in crate::borrow_check) fn report_conflicting_borrow(
|
||||
fn suggest_split_at_mut_if_applicable(
|
||||
&self,
|
||||
err: &mut DiagnosticBuilder<'_>,
|
||||
place: &Place<'tcx>,
|
||||
borrowed_place: &Place<'tcx>,
|
||||
place: Place<'tcx>,
|
||||
borrowed_place: Place<'tcx>,
|
||||
) {
|
||||
if let ([ProjectionElem::Index(_)], [ProjectionElem::Index(_)]) =
|
||||
(&place.projection[..], &borrowed_place.projection[..])
|
||||
@ -584,8 +584,8 @@ fn suggest_split_at_mut_if_applicable(
|
||||
/// > mutable (via `a.u.s.b`) [E0502]
|
||||
pub(in crate::borrow_check) fn describe_place_for_conflicting_borrow(
|
||||
&self,
|
||||
first_borrowed_place: &Place<'tcx>,
|
||||
second_borrowed_place: &Place<'tcx>,
|
||||
first_borrowed_place: Place<'tcx>,
|
||||
second_borrowed_place: Place<'tcx>,
|
||||
) -> (String, String, String, String) {
|
||||
// Define a small closure that we can use to check if the type of a place
|
||||
// is a union.
|
||||
@ -615,13 +615,8 @@ pub(in crate::borrow_check) fn describe_place_for_conflicting_borrow(
|
||||
cursor = proj_base;
|
||||
|
||||
match elem {
|
||||
ProjectionElem::Field(field, _)
|
||||
if union_ty(*local, proj_base).is_some() =>
|
||||
{
|
||||
return Some((
|
||||
PlaceRef { local: *local, projection: proj_base },
|
||||
field,
|
||||
));
|
||||
ProjectionElem::Field(field, _) if union_ty(local, proj_base).is_some() => {
|
||||
return Some((PlaceRef { local, projection: proj_base }, field));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
@ -631,7 +626,7 @@ pub(in crate::borrow_check) fn describe_place_for_conflicting_borrow(
|
||||
.and_then(|(target_base, target_field)| {
|
||||
// With the place of a union and a field access into it, we traverse the second
|
||||
// borrowed place and look for a access to a different field of the same union.
|
||||
let Place { local, ref projection } = *second_borrowed_place;
|
||||
let Place { local, ref projection } = second_borrowed_place;
|
||||
|
||||
let mut cursor = &projection[..];
|
||||
while let [proj_base @ .., elem] = cursor {
|
||||
@ -682,7 +677,7 @@ pub(in crate::borrow_check) fn report_borrowed_value_does_not_live_long_enough(
|
||||
&mut self,
|
||||
location: Location,
|
||||
borrow: &BorrowData<'tcx>,
|
||||
place_span: (&Place<'tcx>, Span),
|
||||
place_span: (Place<'tcx>, Span),
|
||||
kind: Option<WriteKind>,
|
||||
) {
|
||||
debug!(
|
||||
@ -967,7 +962,7 @@ fn report_borrow_conflicts_with_destructor(
|
||||
&mut self,
|
||||
location: Location,
|
||||
borrow: &BorrowData<'tcx>,
|
||||
(place, drop_span): (&Place<'tcx>, Span),
|
||||
(place, drop_span): (Place<'tcx>, Span),
|
||||
kind: Option<WriteKind>,
|
||||
dropped_ty: Ty<'tcx>,
|
||||
) {
|
||||
@ -1379,7 +1374,7 @@ fn get_moved_indexes(&mut self, location: Location, mpi: MovePathIndex) -> Vec<M
|
||||
pub(in crate::borrow_check) fn report_illegal_mutation_of_borrowed(
|
||||
&mut self,
|
||||
location: Location,
|
||||
(place, span): (&Place<'tcx>, Span),
|
||||
(place, span): (Place<'tcx>, Span),
|
||||
loan: &BorrowData<'tcx>,
|
||||
) {
|
||||
let loan_spans = self.retrieve_borrow_spans(loan);
|
||||
@ -1387,7 +1382,7 @@ pub(in crate::borrow_check) fn report_illegal_mutation_of_borrowed(
|
||||
|
||||
let descr_place = self.describe_any_place(place.as_ref());
|
||||
if loan.kind == BorrowKind::Shallow {
|
||||
if let Some(section) = self.classify_immutable_section(&loan.assigned_place) {
|
||||
if let Some(section) = self.classify_immutable_section(loan.assigned_place) {
|
||||
let mut err = self.cannot_mutate_in_immutable_section(
|
||||
span,
|
||||
loan_span,
|
||||
@ -1432,9 +1427,9 @@ pub(in crate::borrow_check) fn report_illegal_mutation_of_borrowed(
|
||||
pub(in crate::borrow_check) fn report_illegal_reassignment(
|
||||
&mut self,
|
||||
_location: Location,
|
||||
(place, span): (&Place<'tcx>, Span),
|
||||
(place, span): (Place<'tcx>, Span),
|
||||
assigned_span: Span,
|
||||
err_place: &Place<'tcx>,
|
||||
err_place: Place<'tcx>,
|
||||
) {
|
||||
let (from_arg, local_decl, local_name) = match err_place.as_local() {
|
||||
Some(local) => (
|
||||
@ -1539,17 +1534,17 @@ fn classify_drop_access_kind(&self, place: PlaceRef<'tcx>) -> StorageDeadOrDrop<
|
||||
}
|
||||
|
||||
/// Describe the reason for the fake borrow that was assigned to `place`.
|
||||
fn classify_immutable_section(&self, place: &Place<'tcx>) -> Option<&'static str> {
|
||||
fn classify_immutable_section(&self, place: Place<'tcx>) -> Option<&'static str> {
|
||||
use rustc_middle::mir::visit::Visitor;
|
||||
struct FakeReadCauseFinder<'a, 'tcx> {
|
||||
place: &'a Place<'tcx>,
|
||||
struct FakeReadCauseFinder<'tcx> {
|
||||
place: Place<'tcx>,
|
||||
cause: Option<FakeReadCause>,
|
||||
}
|
||||
impl<'tcx> Visitor<'tcx> for FakeReadCauseFinder<'_, 'tcx> {
|
||||
impl<'tcx> Visitor<'tcx> for FakeReadCauseFinder<'tcx> {
|
||||
fn visit_statement(&mut self, statement: &Statement<'tcx>, _: Location) {
|
||||
match statement {
|
||||
Statement { kind: StatementKind::FakeRead(cause, box ref place), .. }
|
||||
if *place == *self.place =>
|
||||
Statement { kind: StatementKind::FakeRead(cause, box place), .. }
|
||||
if *place == self.place =>
|
||||
{
|
||||
self.cause = Some(*cause);
|
||||
}
|
||||
|
@ -286,7 +286,7 @@ pub(in crate::borrow_check) fn explain_why_borrow_contains_point(
|
||||
&self,
|
||||
location: Location,
|
||||
borrow: &BorrowData<'tcx>,
|
||||
kind_place: Option<(WriteKind, &Place<'tcx>)>,
|
||||
kind_place: Option<(WriteKind, Place<'tcx>)>,
|
||||
) -> BorrowExplanation {
|
||||
debug!(
|
||||
"explain_why_borrow_contains_point(location={:?}, borrow={:?}, kind_place={:?})",
|
||||
|
@ -105,7 +105,7 @@ fn append_to_grouped_errors(
|
||||
// whether or not the right-hand side is a place expression
|
||||
if let LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var(
|
||||
VarBindingForm {
|
||||
opt_match_place: Some((ref opt_match_place, match_span)),
|
||||
opt_match_place: Some((opt_match_place, match_span)),
|
||||
binding_mode: _,
|
||||
opt_ty_info: _,
|
||||
pat_span: _,
|
||||
@ -117,7 +117,7 @@ fn append_to_grouped_errors(
|
||||
grouped_errors,
|
||||
kind,
|
||||
original_path,
|
||||
move_from,
|
||||
*move_from,
|
||||
local,
|
||||
opt_match_place,
|
||||
match_span,
|
||||
@ -143,16 +143,16 @@ fn append_binding_error(
|
||||
grouped_errors: &mut Vec<GroupedMoveError<'tcx>>,
|
||||
kind: IllegalMoveOriginKind<'tcx>,
|
||||
original_path: Place<'tcx>,
|
||||
move_from: &Place<'tcx>,
|
||||
move_from: Place<'tcx>,
|
||||
bind_to: Local,
|
||||
match_place: &Option<Place<'tcx>>,
|
||||
match_place: Option<Place<'tcx>>,
|
||||
match_span: Span,
|
||||
statement_span: Span,
|
||||
) {
|
||||
debug!("append_binding_error(match_place={:?}, match_span={:?})", match_place, match_span);
|
||||
|
||||
let from_simple_let = match_place.is_none();
|
||||
let match_place = match_place.as_ref().unwrap_or(move_from);
|
||||
let match_place = match_place.unwrap_or(move_from);
|
||||
|
||||
match self.move_data.rev_lookup.find(match_place.as_ref()) {
|
||||
// Error with the match place
|
||||
@ -178,7 +178,7 @@ fn append_binding_error(
|
||||
};
|
||||
grouped_errors.push(GroupedMoveError::MovesFromPlace {
|
||||
span,
|
||||
move_from: *match_place,
|
||||
move_from,
|
||||
original_path,
|
||||
kind,
|
||||
binds_to,
|
||||
@ -223,14 +223,14 @@ fn report(&mut self, error: GroupedMoveError<'tcx>) {
|
||||
let (span, use_spans, original_path, kind): (
|
||||
Span,
|
||||
Option<UseSpans>,
|
||||
&Place<'tcx>,
|
||||
Place<'tcx>,
|
||||
&IllegalMoveOriginKind<'_>,
|
||||
) = match error {
|
||||
GroupedMoveError::MovesFromPlace { span, ref original_path, ref kind, .. }
|
||||
| GroupedMoveError::MovesFromValue { span, ref original_path, ref kind, .. } => {
|
||||
GroupedMoveError::MovesFromPlace { span, original_path, ref kind, .. }
|
||||
| GroupedMoveError::MovesFromValue { span, original_path, ref kind, .. } => {
|
||||
(span, None, original_path, kind)
|
||||
}
|
||||
GroupedMoveError::OtherIllegalMove { use_spans, ref original_path, ref kind } => {
|
||||
GroupedMoveError::OtherIllegalMove { use_spans, original_path, ref kind } => {
|
||||
(use_spans.args_or_use(), Some(use_spans), original_path, kind)
|
||||
}
|
||||
};
|
||||
@ -247,7 +247,7 @@ fn report(&mut self, error: GroupedMoveError<'tcx>) {
|
||||
IllegalMoveOriginKind::BorrowedContent { target_place } => self
|
||||
.report_cannot_move_from_borrowed_content(
|
||||
original_path,
|
||||
target_place,
|
||||
*target_place,
|
||||
span,
|
||||
use_spans,
|
||||
),
|
||||
@ -268,7 +268,7 @@ fn report(&mut self, error: GroupedMoveError<'tcx>) {
|
||||
|
||||
fn report_cannot_move_from_static(
|
||||
&mut self,
|
||||
place: &Place<'tcx>,
|
||||
place: Place<'tcx>,
|
||||
span: Span,
|
||||
) -> DiagnosticBuilder<'a> {
|
||||
let description = if place.projection.len() == 1 {
|
||||
@ -288,8 +288,8 @@ fn report_cannot_move_from_static(
|
||||
|
||||
fn report_cannot_move_from_borrowed_content(
|
||||
&mut self,
|
||||
move_place: &Place<'tcx>,
|
||||
deref_target_place: &Place<'tcx>,
|
||||
move_place: Place<'tcx>,
|
||||
deref_target_place: Place<'tcx>,
|
||||
span: Span,
|
||||
use_spans: Option<UseSpans>,
|
||||
) -> DiagnosticBuilder<'a> {
|
||||
|
@ -22,7 +22,7 @@ pub(crate) enum AccessKind {
|
||||
impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
pub(crate) fn report_mutability_error(
|
||||
&mut self,
|
||||
access_place: &Place<'tcx>,
|
||||
access_place: Place<'tcx>,
|
||||
span: Span,
|
||||
the_place_err: PlaceRef<'tcx>,
|
||||
error_access: AccessKind,
|
||||
|
@ -56,33 +56,33 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> {
|
||||
fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
|
||||
self.check_activations(location);
|
||||
|
||||
match statement.kind {
|
||||
StatementKind::Assign(box (ref lhs, ref rhs)) => {
|
||||
match &statement.kind {
|
||||
StatementKind::Assign(box (lhs, rhs)) => {
|
||||
self.consume_rvalue(location, rhs);
|
||||
|
||||
self.mutate_place(location, lhs, Shallow(None), JustWrite);
|
||||
self.mutate_place(location, *lhs, Shallow(None), JustWrite);
|
||||
}
|
||||
StatementKind::FakeRead(_, _) => {
|
||||
// Only relevant for initialized/liveness/safety checks.
|
||||
}
|
||||
StatementKind::SetDiscriminant { ref place, variant_index: _ } => {
|
||||
self.mutate_place(location, place, Shallow(None), JustWrite);
|
||||
StatementKind::SetDiscriminant { place, variant_index: _ } => {
|
||||
self.mutate_place(location, **place, Shallow(None), JustWrite);
|
||||
}
|
||||
StatementKind::LlvmInlineAsm(ref asm) => {
|
||||
StatementKind::LlvmInlineAsm(asm) => {
|
||||
for (o, output) in asm.asm.outputs.iter().zip(asm.outputs.iter()) {
|
||||
if o.is_indirect {
|
||||
// FIXME(eddyb) indirect inline asm outputs should
|
||||
// be encoded through MIR place derefs instead.
|
||||
self.access_place(
|
||||
location,
|
||||
output,
|
||||
*output,
|
||||
(Deep, Read(ReadKind::Copy)),
|
||||
LocalMutationIsAllowed::No,
|
||||
);
|
||||
} else {
|
||||
self.mutate_place(
|
||||
location,
|
||||
output,
|
||||
*output,
|
||||
if o.is_rw { Deep } else { Shallow(None) },
|
||||
if o.is_rw { WriteAndRead } else { JustWrite },
|
||||
);
|
||||
@ -102,7 +102,7 @@ fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
|
||||
StatementKind::StorageDead(local) => {
|
||||
self.access_place(
|
||||
location,
|
||||
&Place::from(local),
|
||||
Place::from(*local),
|
||||
(Shallow(None), Write(WriteKind::StorageDeadOrDrop)),
|
||||
LocalMutationIsAllowed::Yes,
|
||||
);
|
||||
@ -119,27 +119,27 @@ fn visit_terminator_kind(&mut self, kind: &TerminatorKind<'tcx>, location: Locat
|
||||
TerminatorKind::SwitchInt { ref discr, switch_ty: _, values: _, targets: _ } => {
|
||||
self.consume_operand(location, discr);
|
||||
}
|
||||
TerminatorKind::Drop { location: ref drop_place, target: _, unwind: _ } => {
|
||||
TerminatorKind::Drop { location: drop_place, target: _, unwind: _ } => {
|
||||
self.access_place(
|
||||
location,
|
||||
drop_place,
|
||||
*drop_place,
|
||||
(AccessDepth::Drop, Write(WriteKind::StorageDeadOrDrop)),
|
||||
LocalMutationIsAllowed::Yes,
|
||||
);
|
||||
}
|
||||
TerminatorKind::DropAndReplace {
|
||||
location: ref drop_place,
|
||||
location: drop_place,
|
||||
value: ref new_value,
|
||||
target: _,
|
||||
unwind: _,
|
||||
} => {
|
||||
self.mutate_place(location, drop_place, Deep, JustWrite);
|
||||
self.mutate_place(location, *drop_place, Deep, JustWrite);
|
||||
self.consume_operand(location, new_value);
|
||||
}
|
||||
TerminatorKind::Call {
|
||||
ref func,
|
||||
ref args,
|
||||
ref destination,
|
||||
destination,
|
||||
cleanup: _,
|
||||
from_hir_call: _,
|
||||
} => {
|
||||
@ -147,8 +147,8 @@ fn visit_terminator_kind(&mut self, kind: &TerminatorKind<'tcx>, location: Locat
|
||||
for arg in args {
|
||||
self.consume_operand(location, arg);
|
||||
}
|
||||
if let Some((ref dest, _ /*bb*/)) = *destination {
|
||||
self.mutate_place(location, dest, Deep, JustWrite);
|
||||
if let Some((dest, _ /*bb*/)) = destination {
|
||||
self.mutate_place(location, *dest, Deep, JustWrite);
|
||||
}
|
||||
}
|
||||
TerminatorKind::Assert { ref cond, expected: _, ref msg, target: _, cleanup: _ } => {
|
||||
@ -166,19 +166,19 @@ fn visit_terminator_kind(&mut self, kind: &TerminatorKind<'tcx>, location: Locat
|
||||
let borrow_set = self.borrow_set.clone();
|
||||
let resume = self.location_table.start_index(resume.start_location());
|
||||
for i in borrow_set.borrows.indices() {
|
||||
if borrow_of_local_data(&borrow_set.borrows[i].borrowed_place) {
|
||||
if borrow_of_local_data(borrow_set.borrows[i].borrowed_place) {
|
||||
self.all_facts.invalidates.push((resume, i));
|
||||
}
|
||||
}
|
||||
|
||||
self.mutate_place(location, resume_arg, Deep, JustWrite);
|
||||
self.mutate_place(location, *resume_arg, Deep, JustWrite);
|
||||
}
|
||||
TerminatorKind::Resume | TerminatorKind::Return | TerminatorKind::GeneratorDrop => {
|
||||
// Invalidate all borrows of local places
|
||||
let borrow_set = self.borrow_set.clone();
|
||||
let start = self.location_table.start_index(location);
|
||||
for i in borrow_set.borrows.indices() {
|
||||
if borrow_of_local_data(&borrow_set.borrows[i].borrowed_place) {
|
||||
if borrow_of_local_data(borrow_set.borrows[i].borrowed_place) {
|
||||
self.all_facts.invalidates.push((start, i));
|
||||
}
|
||||
}
|
||||
@ -201,7 +201,7 @@ impl<'cx, 'tcx> InvalidationGenerator<'cx, 'tcx> {
|
||||
fn mutate_place(
|
||||
&mut self,
|
||||
location: Location,
|
||||
place: &Place<'tcx>,
|
||||
place: Place<'tcx>,
|
||||
kind: AccessDepth,
|
||||
_mode: MutateMode,
|
||||
) {
|
||||
@ -216,7 +216,7 @@ fn mutate_place(
|
||||
/// Simulates consumption of an operand.
|
||||
fn consume_operand(&mut self, location: Location, operand: &Operand<'tcx>) {
|
||||
match *operand {
|
||||
Operand::Copy(ref place) => {
|
||||
Operand::Copy(place) => {
|
||||
self.access_place(
|
||||
location,
|
||||
place,
|
||||
@ -224,7 +224,7 @@ fn consume_operand(&mut self, location: Location, operand: &Operand<'tcx>) {
|
||||
LocalMutationIsAllowed::No,
|
||||
);
|
||||
}
|
||||
Operand::Move(ref place) => {
|
||||
Operand::Move(place) => {
|
||||
self.access_place(
|
||||
location,
|
||||
place,
|
||||
@ -239,7 +239,7 @@ fn consume_operand(&mut self, location: Location, operand: &Operand<'tcx>) {
|
||||
// Simulates consumption of an rvalue
|
||||
fn consume_rvalue(&mut self, location: Location, rvalue: &Rvalue<'tcx>) {
|
||||
match *rvalue {
|
||||
Rvalue::Ref(_ /*rgn*/, bk, ref place) => {
|
||||
Rvalue::Ref(_ /*rgn*/, bk, place) => {
|
||||
let access_kind = match bk {
|
||||
BorrowKind::Shallow => {
|
||||
(Shallow(Some(ArtificialField::ShallowBorrow)), Read(ReadKind::Borrow(bk)))
|
||||
@ -258,7 +258,7 @@ fn consume_rvalue(&mut self, location: Location, rvalue: &Rvalue<'tcx>) {
|
||||
self.access_place(location, place, access_kind, LocalMutationIsAllowed::No);
|
||||
}
|
||||
|
||||
Rvalue::AddressOf(mutability, ref place) => {
|
||||
Rvalue::AddressOf(mutability, place) => {
|
||||
let access_kind = match mutability {
|
||||
Mutability::Mut => (
|
||||
Deep,
|
||||
@ -279,7 +279,7 @@ fn consume_rvalue(&mut self, location: Location, rvalue: &Rvalue<'tcx>) {
|
||||
self.consume_operand(location, operand)
|
||||
}
|
||||
|
||||
Rvalue::Len(ref place) | Rvalue::Discriminant(ref place) => {
|
||||
Rvalue::Len(place) | Rvalue::Discriminant(place) => {
|
||||
let af = match *rvalue {
|
||||
Rvalue::Len(..) => Some(ArtificialField::ArrayLength),
|
||||
Rvalue::Discriminant(..) => None,
|
||||
@ -313,7 +313,7 @@ fn consume_rvalue(&mut self, location: Location, rvalue: &Rvalue<'tcx>) {
|
||||
fn access_place(
|
||||
&mut self,
|
||||
location: Location,
|
||||
place: &Place<'tcx>,
|
||||
place: Place<'tcx>,
|
||||
kind: (AccessDepth, ReadOrWrite),
|
||||
_is_local_mutation_allowed: LocalMutationIsAllowed,
|
||||
) {
|
||||
@ -325,7 +325,7 @@ fn access_place(
|
||||
fn check_access_for_conflict(
|
||||
&mut self,
|
||||
location: Location,
|
||||
place: &Place<'tcx>,
|
||||
place: Place<'tcx>,
|
||||
sd: AccessDepth,
|
||||
rw: ReadOrWrite,
|
||||
) {
|
||||
@ -413,7 +413,7 @@ fn check_activations(&mut self, location: Location) {
|
||||
|
||||
self.access_place(
|
||||
location,
|
||||
&borrow.borrowed_place,
|
||||
borrow.borrowed_place,
|
||||
(Deep, Activation(WriteKind::MutableBorrow(borrow.kind), borrow_index)),
|
||||
LocalMutationIsAllowed::No,
|
||||
);
|
||||
|
@ -308,8 +308,7 @@ fn do_mir_borrowck<'a, 'tcx>(
|
||||
// Convert any reservation warnings into lints.
|
||||
let reservation_warnings = mem::take(&mut mbcx.reservation_warnings);
|
||||
for (_, (place, span, location, bk, borrow)) in reservation_warnings {
|
||||
let mut initial_diag =
|
||||
mbcx.report_conflicting_borrow(location, (&place, span), bk, &borrow);
|
||||
let mut initial_diag = mbcx.report_conflicting_borrow(location, (place, span), bk, &borrow);
|
||||
|
||||
let scope = mbcx.body.source_info(location).scope;
|
||||
let lint_root = match &mbcx.body.source_scopes[scope].local_data {
|
||||
@ -523,11 +522,11 @@ fn visit_statement(
|
||||
|
||||
self.check_activations(location, span, flow_state);
|
||||
|
||||
match stmt.kind {
|
||||
StatementKind::Assign(box (ref lhs, ref rhs)) => {
|
||||
match &stmt.kind {
|
||||
StatementKind::Assign(box (lhs, ref rhs)) => {
|
||||
self.consume_rvalue(location, (rhs, span), flow_state);
|
||||
|
||||
self.mutate_place(location, (lhs, span), Shallow(None), JustWrite, flow_state);
|
||||
self.mutate_place(location, (*lhs, span), Shallow(None), JustWrite, flow_state);
|
||||
}
|
||||
StatementKind::FakeRead(_, box ref place) => {
|
||||
// Read for match doesn't access any memory and is used to
|
||||
@ -547,8 +546,8 @@ fn visit_statement(
|
||||
flow_state,
|
||||
);
|
||||
}
|
||||
StatementKind::SetDiscriminant { ref place, variant_index: _ } => {
|
||||
self.mutate_place(location, (place, span), Shallow(None), JustWrite, flow_state);
|
||||
StatementKind::SetDiscriminant { place, variant_index: _ } => {
|
||||
self.mutate_place(location, (**place, span), Shallow(None), JustWrite, flow_state);
|
||||
}
|
||||
StatementKind::LlvmInlineAsm(ref asm) => {
|
||||
for (o, output) in asm.asm.outputs.iter().zip(asm.outputs.iter()) {
|
||||
@ -557,7 +556,7 @@ fn visit_statement(
|
||||
// be encoded through MIR place derefs instead.
|
||||
self.access_place(
|
||||
location,
|
||||
(output, o.span),
|
||||
(*output, o.span),
|
||||
(Deep, Read(ReadKind::Copy)),
|
||||
LocalMutationIsAllowed::No,
|
||||
flow_state,
|
||||
@ -571,7 +570,7 @@ fn visit_statement(
|
||||
} else {
|
||||
self.mutate_place(
|
||||
location,
|
||||
(output, o.span),
|
||||
(*output, o.span),
|
||||
if o.is_rw { Deep } else { Shallow(None) },
|
||||
if o.is_rw { WriteAndRead } else { JustWrite },
|
||||
flow_state,
|
||||
@ -592,7 +591,7 @@ fn visit_statement(
|
||||
StatementKind::StorageDead(local) => {
|
||||
self.access_place(
|
||||
location,
|
||||
(&Place::from(local), span),
|
||||
(Place::from(*local), span),
|
||||
(Shallow(None), Write(WriteKind::StorageDeadOrDrop)),
|
||||
LocalMutationIsAllowed::Yes,
|
||||
flow_state,
|
||||
@ -638,14 +637,14 @@ fn visit_terminator(
|
||||
|
||||
self.access_place(
|
||||
loc,
|
||||
(drop_place, span),
|
||||
(*drop_place, span),
|
||||
(AccessDepth::Drop, Write(WriteKind::StorageDeadOrDrop)),
|
||||
LocalMutationIsAllowed::Yes,
|
||||
flow_state,
|
||||
);
|
||||
}
|
||||
TerminatorKind::DropAndReplace {
|
||||
location: ref drop_place,
|
||||
location: drop_place,
|
||||
value: ref new_value,
|
||||
target: _,
|
||||
unwind: _,
|
||||
@ -664,7 +663,7 @@ fn visit_terminator(
|
||||
for arg in args {
|
||||
self.consume_operand(loc, (arg, span), flow_state);
|
||||
}
|
||||
if let Some((ref dest, _ /*bb*/)) = *destination {
|
||||
if let Some((dest, _ /*bb*/)) = *destination {
|
||||
self.mutate_place(loc, (dest, span), Deep, JustWrite, flow_state);
|
||||
}
|
||||
}
|
||||
@ -677,7 +676,7 @@ fn visit_terminator(
|
||||
}
|
||||
}
|
||||
|
||||
TerminatorKind::Yield { ref value, resume: _, ref resume_arg, drop: _ } => {
|
||||
TerminatorKind::Yield { ref value, resume: _, resume_arg, drop: _ } => {
|
||||
self.consume_operand(loc, (value, span), flow_state);
|
||||
self.mutate_place(loc, (resume_arg, span), Deep, JustWrite, flow_state);
|
||||
}
|
||||
@ -884,7 +883,7 @@ fn body(&self) -> &'cx Body<'tcx> {
|
||||
fn access_place(
|
||||
&mut self,
|
||||
location: Location,
|
||||
place_span: (&Place<'tcx>, Span),
|
||||
place_span: (Place<'tcx>, Span),
|
||||
kind: (AccessDepth, ReadOrWrite),
|
||||
is_local_mutation_allowed: LocalMutationIsAllowed,
|
||||
flow_state: &Flows<'cx, 'tcx>,
|
||||
@ -905,7 +904,7 @@ fn access_place(
|
||||
// Check is_empty() first because it's the common case, and doing that
|
||||
// way we avoid the clone() call.
|
||||
if !self.access_place_error_reported.is_empty()
|
||||
&& self.access_place_error_reported.contains(&(*place_span.0, place_span.1))
|
||||
&& self.access_place_error_reported.contains(&(place_span.0, place_span.1))
|
||||
{
|
||||
debug!(
|
||||
"access_place: suppressing error place_span=`{:?}` kind=`{:?}`",
|
||||
@ -933,14 +932,14 @@ fn access_place(
|
||||
if conflict_error || mutability_error {
|
||||
debug!("access_place: logging error place_span=`{:?}` kind=`{:?}`", place_span, kind);
|
||||
|
||||
self.access_place_error_reported.insert((*place_span.0, place_span.1));
|
||||
self.access_place_error_reported.insert((place_span.0, place_span.1));
|
||||
}
|
||||
}
|
||||
|
||||
fn check_access_for_conflict(
|
||||
&mut self,
|
||||
location: Location,
|
||||
place_span: (&Place<'tcx>, Span),
|
||||
place_span: (Place<'tcx>, Span),
|
||||
sd: AccessDepth,
|
||||
rw: ReadOrWrite,
|
||||
flow_state: &Flows<'cx, 'tcx>,
|
||||
@ -1043,7 +1042,7 @@ fn check_access_for_conflict(
|
||||
// these sepately so that we only emit a warning if borrow
|
||||
// checking was otherwise successful.
|
||||
this.reservation_warnings
|
||||
.insert(bi, (*place_span.0, place_span.1, location, bk, borrow.clone()));
|
||||
.insert(bi, (place_span.0, place_span.1, location, bk, borrow.clone()));
|
||||
|
||||
// Don't suppress actual errors.
|
||||
Control::Continue
|
||||
@ -1100,7 +1099,7 @@ fn check_access_for_conflict(
|
||||
fn mutate_place(
|
||||
&mut self,
|
||||
location: Location,
|
||||
place_span: (&'cx Place<'tcx>, Span),
|
||||
place_span: (Place<'tcx>, Span),
|
||||
kind: AccessDepth,
|
||||
mode: MutateMode,
|
||||
flow_state: &Flows<'cx, 'tcx>,
|
||||
@ -1150,7 +1149,7 @@ fn consume_rvalue(
|
||||
flow_state: &Flows<'cx, 'tcx>,
|
||||
) {
|
||||
match *rvalue {
|
||||
Rvalue::Ref(_ /*rgn*/, bk, ref place) => {
|
||||
Rvalue::Ref(_ /*rgn*/, bk, place) => {
|
||||
let access_kind = match bk {
|
||||
BorrowKind::Shallow => {
|
||||
(Shallow(Some(ArtificialField::ShallowBorrow)), Read(ReadKind::Borrow(bk)))
|
||||
@ -1188,7 +1187,7 @@ fn consume_rvalue(
|
||||
);
|
||||
}
|
||||
|
||||
Rvalue::AddressOf(mutability, ref place) => {
|
||||
Rvalue::AddressOf(mutability, place) => {
|
||||
let access_kind = match mutability {
|
||||
Mutability::Mut => (
|
||||
Deep,
|
||||
@ -1222,7 +1221,7 @@ fn consume_rvalue(
|
||||
self.consume_operand(location, (operand, span), flow_state)
|
||||
}
|
||||
|
||||
Rvalue::Len(ref place) | Rvalue::Discriminant(ref place) => {
|
||||
Rvalue::Len(place) | Rvalue::Discriminant(place) => {
|
||||
let af = match *rvalue {
|
||||
Rvalue::Len(..) => Some(ArtificialField::ArrayLength),
|
||||
Rvalue::Discriminant(..) => None,
|
||||
@ -1283,7 +1282,7 @@ fn consume_rvalue(
|
||||
}
|
||||
|
||||
fn propagate_closure_used_mut_upvar(&mut self, operand: &Operand<'tcx>) {
|
||||
let propagate_closure_used_mut_place = |this: &mut Self, place: &Place<'tcx>| {
|
||||
let propagate_closure_used_mut_place = |this: &mut Self, place: Place<'tcx>| {
|
||||
if !place.projection.is_empty() {
|
||||
if let Some(field) = this.is_upvar_field_projection(place.as_ref()) {
|
||||
this.used_mut_upvars.push(field);
|
||||
@ -1297,7 +1296,7 @@ fn propagate_closure_used_mut_upvar(&mut self, operand: &Operand<'tcx>) {
|
||||
// captures of a closure are copied/moved directly
|
||||
// when generating MIR.
|
||||
match *operand {
|
||||
Operand::Move(ref place) | Operand::Copy(ref place) => {
|
||||
Operand::Move(place) | Operand::Copy(place) => {
|
||||
match place.as_local() {
|
||||
Some(local) if !self.body.local_decls[local].is_user_variable() => {
|
||||
if self.body.local_decls[local].ty.is_mutable_ptr() {
|
||||
@ -1336,8 +1335,7 @@ fn propagate_closure_used_mut_upvar(&mut self, operand: &Operand<'tcx>) {
|
||||
let stmt = &bbd.statements[loc.statement_index];
|
||||
debug!("temporary assigned in: stmt={:?}", stmt);
|
||||
|
||||
if let StatementKind::Assign(box (_, Rvalue::Ref(_, _, ref source))) =
|
||||
stmt.kind
|
||||
if let StatementKind::Assign(box (_, Rvalue::Ref(_, _, source))) = stmt.kind
|
||||
{
|
||||
propagate_closure_used_mut_place(self, source);
|
||||
} else {
|
||||
@ -1361,7 +1359,7 @@ fn consume_operand(
|
||||
flow_state: &Flows<'cx, 'tcx>,
|
||||
) {
|
||||
match *operand {
|
||||
Operand::Copy(ref place) => {
|
||||
Operand::Copy(place) => {
|
||||
// copy of place: check if this is "copy of frozen path"
|
||||
// (FIXME: see check_loans.rs)
|
||||
self.access_place(
|
||||
@ -1380,7 +1378,7 @@ fn consume_operand(
|
||||
flow_state,
|
||||
);
|
||||
}
|
||||
Operand::Move(ref place) => {
|
||||
Operand::Move(place) => {
|
||||
// move of place: check if this is move of already borrowed path
|
||||
self.access_place(
|
||||
location,
|
||||
@ -1411,7 +1409,7 @@ fn check_for_invalidation_at_exit(
|
||||
span: Span,
|
||||
) {
|
||||
debug!("check_for_invalidation_at_exit({:?})", borrow);
|
||||
let place = &borrow.borrowed_place;
|
||||
let place = borrow.borrowed_place;
|
||||
let mut root_place = PlaceRef { local: place.local, projection: &[] };
|
||||
|
||||
// FIXME(nll-rfc#40): do more precise destructor tracking here. For now
|
||||
@ -1465,7 +1463,7 @@ fn check_for_invalidation_at_exit(
|
||||
fn check_for_local_borrow(&mut self, borrow: &BorrowData<'tcx>, yield_span: Span) {
|
||||
debug!("check_for_local_borrow({:?})", borrow);
|
||||
|
||||
if borrow_of_local_data(&borrow.borrowed_place) {
|
||||
if borrow_of_local_data(borrow.borrowed_place) {
|
||||
let err = self.cannot_borrow_across_generator_yield(
|
||||
self.retrieve_borrow_spans(borrow).var_or_use(),
|
||||
yield_span,
|
||||
@ -1491,7 +1489,7 @@ fn check_activations(&mut self, location: Location, span: Span, flow_state: &Flo
|
||||
|
||||
self.access_place(
|
||||
location,
|
||||
(&borrow.borrowed_place, span),
|
||||
(borrow.borrowed_place, span),
|
||||
(Deep, Activation(WriteKind::MutableBorrow(borrow.kind), borrow_index)),
|
||||
LocalMutationIsAllowed::No,
|
||||
flow_state,
|
||||
@ -1506,7 +1504,7 @@ fn check_if_reassignment_to_immutable_state(
|
||||
&mut self,
|
||||
location: Location,
|
||||
local: Local,
|
||||
place_span: (&Place<'tcx>, Span),
|
||||
place_span: (Place<'tcx>, Span),
|
||||
flow_state: &Flows<'cx, 'tcx>,
|
||||
) {
|
||||
debug!("check_if_reassignment_to_immutable_state({:?})", local);
|
||||
@ -1730,7 +1728,7 @@ fn move_path_for_place(&mut self, place: PlaceRef<'tcx>) -> Option<MovePathIndex
|
||||
fn check_if_assigned_path_is_moved(
|
||||
&mut self,
|
||||
location: Location,
|
||||
(place, span): (&'cx Place<'tcx>, Span),
|
||||
(place, span): (Place<'tcx>, Span),
|
||||
flow_state: &Flows<'cx, 'tcx>,
|
||||
) {
|
||||
debug!("check_if_assigned_path_is_moved place: {:?}", place);
|
||||
@ -1903,7 +1901,7 @@ fn check_parent_of_field<'cx, 'tcx>(
|
||||
/// Returns `true` if an error is reported.
|
||||
fn check_access_permissions(
|
||||
&mut self,
|
||||
(place, span): (&Place<'tcx>, Span),
|
||||
(place, span): (Place<'tcx>, Span),
|
||||
kind: ReadOrWrite,
|
||||
is_local_mutation_allowed: LocalMutationIsAllowed,
|
||||
flow_state: &Flows<'cx, 'tcx>,
|
||||
|
@ -317,7 +317,7 @@ pub(super) fn dump_mir_results<'a, 'tcx>(
|
||||
regioncx: &RegionInferenceContext<'_>,
|
||||
closure_region_requirements: &Option<ClosureRegionRequirements<'_>>,
|
||||
) {
|
||||
if !mir_util::dump_enabled(infcx.tcx, "nll", source) {
|
||||
if !mir_util::dump_enabled(infcx.tcx, "nll", source.def_id()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -27,7 +27,7 @@ pub(super) fn each_borrow_involving_path<'tcx, F, I, S>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
body: &Body<'tcx>,
|
||||
_location: Location,
|
||||
access_place: (AccessDepth, &Place<'tcx>),
|
||||
access_place: (AccessDepth, Place<'tcx>),
|
||||
borrow_set: &BorrowSet<'tcx>,
|
||||
candidates: I,
|
||||
mut op: F,
|
||||
@ -48,7 +48,7 @@ pub(super) fn each_borrow_involving_path<'tcx, F, I, S>(
|
||||
if places_conflict::borrow_conflicts_with_place(
|
||||
tcx,
|
||||
body,
|
||||
&borrowed.borrowed_place,
|
||||
borrowed.borrowed_place,
|
||||
borrowed.kind,
|
||||
place.as_ref(),
|
||||
access,
|
||||
@ -130,7 +130,7 @@ pub(super) fn is_active<'tcx>(
|
||||
|
||||
/// Determines if a given borrow is borrowing local data
|
||||
/// This is called for all Yield expressions on movable generators
|
||||
pub(super) fn borrow_of_local_data(place: &Place<'_>) -> bool {
|
||||
pub(super) fn borrow_of_local_data(place: Place<'_>) -> bool {
|
||||
// Reborrow of already borrowed data is ignored
|
||||
// Any errors will be caught on the initial borrow
|
||||
!place.is_indirect()
|
||||
|
@ -24,8 +24,8 @@
|
||||
crate fn places_conflict<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
body: &Body<'tcx>,
|
||||
borrow_place: &Place<'tcx>,
|
||||
access_place: &Place<'tcx>,
|
||||
borrow_place: Place<'tcx>,
|
||||
access_place: Place<'tcx>,
|
||||
bias: PlaceConflictBias,
|
||||
) -> bool {
|
||||
borrow_conflicts_with_place(
|
||||
@ -46,7 +46,7 @@
|
||||
pub(super) fn borrow_conflicts_with_place<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
body: &Body<'tcx>,
|
||||
borrow_place: &Place<'tcx>,
|
||||
borrow_place: Place<'tcx>,
|
||||
borrow_kind: BorrowKind,
|
||||
access_place: PlaceRef<'tcx>,
|
||||
access: AccessDepth,
|
||||
@ -71,7 +71,7 @@ pub(super) fn borrow_conflicts_with_place<'tcx>(
|
||||
fn place_components_conflict<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
body: &Body<'tcx>,
|
||||
borrow_place: &Place<'tcx>,
|
||||
borrow_place: Place<'tcx>,
|
||||
borrow_kind: BorrowKind,
|
||||
access_place: PlaceRef<'tcx>,
|
||||
access: AccessDepth,
|
||||
|
@ -51,7 +51,7 @@ struct GatherUsedMutsVisitor<'visit, 'cx, 'tcx> {
|
||||
}
|
||||
|
||||
impl GatherUsedMutsVisitor<'_, '_, '_> {
|
||||
fn remove_never_initialized_mut_locals(&mut self, into: &Place<'_>) {
|
||||
fn remove_never_initialized_mut_locals(&mut self, into: Place<'_>) {
|
||||
// Remove any locals that we found were initialized from the
|
||||
// `never_initialized_mut_locals` set. At the end, the only remaining locals will
|
||||
// be those that were never initialized - we will consider those as being used as
|
||||
@ -66,10 +66,10 @@ fn visit_terminator_kind(&mut self, kind: &TerminatorKind<'tcx>, _location: Loca
|
||||
debug!("visit_terminator_kind: kind={:?}", kind);
|
||||
match &kind {
|
||||
TerminatorKind::Call { destination: Some((into, _)), .. } => {
|
||||
self.remove_never_initialized_mut_locals(&into);
|
||||
self.remove_never_initialized_mut_locals(*into);
|
||||
}
|
||||
TerminatorKind::DropAndReplace { location, .. } => {
|
||||
self.remove_never_initialized_mut_locals(&location);
|
||||
self.remove_never_initialized_mut_locals(*location);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
@ -82,7 +82,7 @@ fn visit_statement(&mut self, statement: &Statement<'tcx>, _location: Location)
|
||||
never_initialized_mut_locals={:?}",
|
||||
statement, into.local, self.never_initialized_mut_locals
|
||||
);
|
||||
self.remove_never_initialized_mut_locals(into);
|
||||
self.remove_never_initialized_mut_locals(*into);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -49,7 +49,7 @@ pub fn move_path_children_matching<'tcx, F>(
|
||||
fn place_contents_drop_state_cannot_differ<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
body: &Body<'tcx>,
|
||||
place: &mir::Place<'tcx>,
|
||||
place: mir::Place<'tcx>,
|
||||
) -> bool {
|
||||
let ty = place.ty(body, tcx).ty;
|
||||
match ty.kind {
|
||||
@ -110,7 +110,7 @@ fn is_terminal_path<'tcx>(
|
||||
move_data: &MoveData<'tcx>,
|
||||
path: MovePathIndex,
|
||||
) -> bool {
|
||||
place_contents_drop_state_cannot_differ(tcx, body, &move_data.move_paths[path].place)
|
||||
place_contents_drop_state_cannot_differ(tcx, body, move_data.move_paths[path].place)
|
||||
}
|
||||
|
||||
fn on_all_children_bits<'tcx, F>(
|
||||
|
@ -135,14 +135,14 @@ pub fn seek_after_assume_success(&mut self, target: Location) {
|
||||
target.block,
|
||||
func,
|
||||
args,
|
||||
return_place,
|
||||
*return_place,
|
||||
);
|
||||
}
|
||||
TerminatorKind::Yield { resume, resume_arg, .. } => {
|
||||
self.results.borrow().analysis.apply_yield_resume_effect(
|
||||
&mut self.state,
|
||||
*resume,
|
||||
resume_arg,
|
||||
*resume_arg,
|
||||
);
|
||||
}
|
||||
_ => {}
|
||||
|
@ -15,6 +15,7 @@
|
||||
|
||||
use super::graphviz;
|
||||
use super::{Analysis, GenKillAnalysis, GenKillSet, Results};
|
||||
use crate::util::pretty::dump_enabled;
|
||||
|
||||
/// A solver for dataflow problems.
|
||||
pub struct Engine<'a, 'tcx, A>
|
||||
@ -228,7 +229,7 @@ fn propagate_bits_into_graph_successors_of(
|
||||
self.propagate_bits_into_entry_set_for(in_out, drop, dirty_list);
|
||||
}
|
||||
|
||||
self.analysis.apply_yield_resume_effect(in_out, target, &resume_arg);
|
||||
self.analysis.apply_yield_resume_effect(in_out, target, resume_arg);
|
||||
self.propagate_bits_into_entry_set_for(in_out, target, dirty_list);
|
||||
}
|
||||
|
||||
@ -272,7 +273,7 @@ fn propagate_bits_into_graph_successors_of(
|
||||
}
|
||||
}
|
||||
|
||||
if let Some((ref dest_place, dest_bb)) = *destination {
|
||||
if let Some((dest_place, dest_bb)) = *destination {
|
||||
// N.B.: This must be done *last*, otherwise the unwind path will see the call
|
||||
// return effect.
|
||||
self.analysis.apply_call_return_effect(in_out, bb, func, args, dest_place);
|
||||
@ -314,7 +315,7 @@ fn propagate_bits_into_enum_discriminant_switch_successors(
|
||||
in_out: &mut BitSet<A::Idx>,
|
||||
bb: BasicBlock,
|
||||
enum_def: &'tcx ty::AdtDef,
|
||||
enum_place: &mir::Place<'tcx>,
|
||||
enum_place: mir::Place<'tcx>,
|
||||
dirty_list: &mut WorkQueue<BasicBlock>,
|
||||
values: &[u128],
|
||||
targets: &[BasicBlock],
|
||||
@ -361,14 +362,14 @@ fn switch_on_enum_discriminant(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
body: &'mir mir::Body<'tcx>,
|
||||
block: &'mir mir::BasicBlockData<'tcx>,
|
||||
switch_on: &mir::Place<'tcx>,
|
||||
) -> Option<(&'mir mir::Place<'tcx>, &'tcx ty::AdtDef)> {
|
||||
switch_on: mir::Place<'tcx>,
|
||||
) -> Option<(mir::Place<'tcx>, &'tcx ty::AdtDef)> {
|
||||
match block.statements.last().map(|stmt| &stmt.kind) {
|
||||
Some(mir::StatementKind::Assign(box (lhs, mir::Rvalue::Discriminant(discriminated))))
|
||||
if lhs == switch_on =>
|
||||
if *lhs == switch_on =>
|
||||
{
|
||||
match &discriminated.ty(body, tcx).ty.kind {
|
||||
ty::Adt(def, _) => Some((discriminated, def)),
|
||||
ty::Adt(def, _) => Some((*discriminated, def)),
|
||||
|
||||
// `Rvalue::Discriminant` is also used to get the active yield point for a
|
||||
// generator, but we do not need edge-specific effects in that case. This may
|
||||
@ -400,12 +401,25 @@ fn write_graphviz_results<A>(
|
||||
let attrs = match RustcMirAttrs::parse(tcx, def_id) {
|
||||
Ok(attrs) => attrs,
|
||||
|
||||
// Invalid `rustc_mir` attrs will be reported using `span_err`.
|
||||
// Invalid `rustc_mir` attrs are reported in `RustcMirAttrs::parse`
|
||||
Err(()) => return Ok(()),
|
||||
};
|
||||
|
||||
let path = match attrs.output_path(A::NAME) {
|
||||
Some(path) => path,
|
||||
|
||||
None if tcx.sess.opts.debugging_opts.dump_mir_dataflow
|
||||
&& dump_enabled(tcx, A::NAME, def_id) =>
|
||||
{
|
||||
let mut path = PathBuf::from(&tcx.sess.opts.debugging_opts.dump_mir_dir);
|
||||
|
||||
let item_name = ty::print::with_forced_impl_filename_line(|| {
|
||||
tcx.def_path(def_id).to_filename_friendly_no_crate()
|
||||
});
|
||||
path.push(format!("rustc.{}.{}.dot", item_name, A::NAME));
|
||||
path
|
||||
}
|
||||
|
||||
None => return Ok(()),
|
||||
};
|
||||
|
||||
@ -430,7 +444,12 @@ fn write_graphviz_results<A>(
|
||||
|
||||
let graphviz = graphviz::Formatter::new(body, def_id, results, &mut *formatter);
|
||||
dot::render_opts(&graphviz, &mut buf, &[dot::RenderOption::Monospace])?;
|
||||
|
||||
if let Some(parent) = path.parent() {
|
||||
fs::create_dir_all(parent)?;
|
||||
}
|
||||
fs::write(&path, buf)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -225,7 +225,7 @@ fn apply_call_return_effect(
|
||||
block: BasicBlock,
|
||||
func: &mir::Operand<'tcx>,
|
||||
args: &[mir::Operand<'tcx>],
|
||||
return_place: &mir::Place<'tcx>,
|
||||
return_place: mir::Place<'tcx>,
|
||||
);
|
||||
|
||||
/// Updates the current dataflow state with the effect of resuming from a `Yield` terminator.
|
||||
@ -238,7 +238,7 @@ fn apply_yield_resume_effect(
|
||||
&self,
|
||||
_state: &mut BitSet<Self::Idx>,
|
||||
_resume_block: BasicBlock,
|
||||
_resume_place: &mir::Place<'tcx>,
|
||||
_resume_place: mir::Place<'tcx>,
|
||||
) {
|
||||
}
|
||||
|
||||
@ -251,7 +251,7 @@ fn apply_discriminant_switch_effect(
|
||||
&self,
|
||||
_state: &mut BitSet<Self::Idx>,
|
||||
_block: BasicBlock,
|
||||
_enum_place: &mir::Place<'tcx>,
|
||||
_enum_place: mir::Place<'tcx>,
|
||||
_adt: &ty::AdtDef,
|
||||
_variant: VariantIdx,
|
||||
) {
|
||||
@ -332,7 +332,7 @@ fn call_return_effect(
|
||||
block: BasicBlock,
|
||||
func: &mir::Operand<'tcx>,
|
||||
args: &[mir::Operand<'tcx>],
|
||||
return_place: &mir::Place<'tcx>,
|
||||
return_place: mir::Place<'tcx>,
|
||||
);
|
||||
|
||||
/// See `Analysis::apply_yield_resume_effect`.
|
||||
@ -340,7 +340,7 @@ fn yield_resume_effect(
|
||||
&self,
|
||||
_trans: &mut BitSet<Self::Idx>,
|
||||
_resume_block: BasicBlock,
|
||||
_resume_place: &mir::Place<'tcx>,
|
||||
_resume_place: mir::Place<'tcx>,
|
||||
) {
|
||||
}
|
||||
|
||||
@ -349,7 +349,7 @@ fn discriminant_switch_effect(
|
||||
&self,
|
||||
_state: &mut impl GenKill<Self::Idx>,
|
||||
_block: BasicBlock,
|
||||
_enum_place: &mir::Place<'tcx>,
|
||||
_enum_place: mir::Place<'tcx>,
|
||||
_adt: &ty::AdtDef,
|
||||
_variant: VariantIdx,
|
||||
) {
|
||||
@ -402,7 +402,7 @@ fn apply_call_return_effect(
|
||||
block: BasicBlock,
|
||||
func: &mir::Operand<'tcx>,
|
||||
args: &[mir::Operand<'tcx>],
|
||||
return_place: &mir::Place<'tcx>,
|
||||
return_place: mir::Place<'tcx>,
|
||||
) {
|
||||
self.call_return_effect(state, block, func, args, return_place);
|
||||
}
|
||||
@ -411,7 +411,7 @@ fn apply_yield_resume_effect(
|
||||
&self,
|
||||
state: &mut BitSet<Self::Idx>,
|
||||
resume_block: BasicBlock,
|
||||
resume_place: &mir::Place<'tcx>,
|
||||
resume_place: mir::Place<'tcx>,
|
||||
) {
|
||||
self.yield_resume_effect(state, resume_block, resume_place);
|
||||
}
|
||||
@ -420,7 +420,7 @@ fn apply_discriminant_switch_effect(
|
||||
&self,
|
||||
state: &mut BitSet<Self::Idx>,
|
||||
block: BasicBlock,
|
||||
enum_place: &mir::Place<'tcx>,
|
||||
enum_place: mir::Place<'tcx>,
|
||||
adt: &ty::AdtDef,
|
||||
variant: VariantIdx,
|
||||
) {
|
||||
|
@ -223,7 +223,7 @@ fn apply_call_return_effect(
|
||||
block: BasicBlock,
|
||||
_func: &mir::Operand<'tcx>,
|
||||
_args: &[mir::Operand<'tcx>],
|
||||
_return_place: &mir::Place<'tcx>,
|
||||
_return_place: mir::Place<'tcx>,
|
||||
) {
|
||||
let location = self.body.terminator_loc(block);
|
||||
let idx = self.effect_at_target(SeekTarget::AfterAssumeCallReturns(location)).unwrap();
|
||||
|
@ -123,7 +123,7 @@ fn call_return_effect(
|
||||
_block: mir::BasicBlock,
|
||||
_func: &mir::Operand<'tcx>,
|
||||
_args: &[mir::Operand<'tcx>],
|
||||
_dest_place: &mir::Place<'tcx>,
|
||||
_dest_place: mir::Place<'tcx>,
|
||||
) {
|
||||
}
|
||||
}
|
||||
@ -160,13 +160,13 @@ fn visit_rvalue(&mut self, rvalue: &mir::Rvalue<'tcx>, location: Location) {
|
||||
|
||||
match rvalue {
|
||||
mir::Rvalue::AddressOf(mt, borrowed_place) => {
|
||||
if !borrowed_place.is_indirect() && self.kind.in_address_of(*mt, borrowed_place) {
|
||||
if !borrowed_place.is_indirect() && self.kind.in_address_of(*mt, *borrowed_place) {
|
||||
self.trans.gen(borrowed_place.local);
|
||||
}
|
||||
}
|
||||
|
||||
mir::Rvalue::Ref(_, kind, borrowed_place) => {
|
||||
if !borrowed_place.is_indirect() && self.kind.in_ref(*kind, borrowed_place) {
|
||||
if !borrowed_place.is_indirect() && self.kind.in_ref(*kind, *borrowed_place) {
|
||||
self.trans.gen(borrowed_place.local);
|
||||
}
|
||||
}
|
||||
@ -230,7 +230,7 @@ impl MutBorrow<'mir, 'tcx> {
|
||||
/// below. See [rust-lang/unsafe-code-guidelines#134].
|
||||
///
|
||||
/// [rust-lang/unsafe-code-guidelines#134]: https://github.com/rust-lang/unsafe-code-guidelines/issues/134
|
||||
fn shared_borrow_allows_mutation(&self, place: &Place<'tcx>) -> bool {
|
||||
fn shared_borrow_allows_mutation(&self, place: Place<'tcx>) -> bool {
|
||||
!place.ty(self.body, self.tcx).ty.is_freeze(self.tcx, self.param_env, DUMMY_SP)
|
||||
}
|
||||
}
|
||||
@ -238,17 +238,17 @@ fn shared_borrow_allows_mutation(&self, place: &Place<'tcx>) -> bool {
|
||||
pub trait BorrowAnalysisKind<'tcx> {
|
||||
const ANALYSIS_NAME: &'static str;
|
||||
|
||||
fn in_address_of(&self, mt: Mutability, place: &Place<'tcx>) -> bool;
|
||||
fn in_ref(&self, kind: mir::BorrowKind, place: &Place<'tcx>) -> bool;
|
||||
fn in_address_of(&self, mt: Mutability, place: Place<'tcx>) -> bool;
|
||||
fn in_ref(&self, kind: mir::BorrowKind, place: Place<'tcx>) -> bool;
|
||||
}
|
||||
|
||||
impl BorrowAnalysisKind<'tcx> for AnyBorrow {
|
||||
const ANALYSIS_NAME: &'static str = "maybe_borrowed_locals";
|
||||
|
||||
fn in_ref(&self, _: mir::BorrowKind, _: &Place<'_>) -> bool {
|
||||
fn in_ref(&self, _: mir::BorrowKind, _: Place<'_>) -> bool {
|
||||
true
|
||||
}
|
||||
fn in_address_of(&self, _: Mutability, _: &Place<'_>) -> bool {
|
||||
fn in_address_of(&self, _: Mutability, _: Place<'_>) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
@ -256,7 +256,7 @@ fn in_address_of(&self, _: Mutability, _: &Place<'_>) -> bool {
|
||||
impl BorrowAnalysisKind<'tcx> for MutBorrow<'mir, 'tcx> {
|
||||
const ANALYSIS_NAME: &'static str = "maybe_mut_borrowed_locals";
|
||||
|
||||
fn in_ref(&self, kind: mir::BorrowKind, place: &Place<'tcx>) -> bool {
|
||||
fn in_ref(&self, kind: mir::BorrowKind, place: Place<'tcx>) -> bool {
|
||||
match kind {
|
||||
mir::BorrowKind::Mut { .. } => true,
|
||||
mir::BorrowKind::Shared | mir::BorrowKind::Shallow | mir::BorrowKind::Unique => {
|
||||
@ -265,7 +265,7 @@ fn in_ref(&self, kind: mir::BorrowKind, place: &Place<'tcx>) -> bool {
|
||||
}
|
||||
}
|
||||
|
||||
fn in_address_of(&self, mt: Mutability, place: &Place<'tcx>) -> bool {
|
||||
fn in_address_of(&self, mt: Mutability, place: Place<'tcx>) -> bool {
|
||||
match mt {
|
||||
Mutability::Mut => true,
|
||||
Mutability::Not => self.shared_borrow_allows_mutation(place),
|
||||
|
@ -187,7 +187,7 @@ fn kill_loans_out_of_scope_at_location(
|
||||
}
|
||||
|
||||
/// Kill any borrows that conflict with `place`.
|
||||
fn kill_borrows_on_place(&self, trans: &mut impl GenKill<BorrowIndex>, place: &Place<'tcx>) {
|
||||
fn kill_borrows_on_place(&self, trans: &mut impl GenKill<BorrowIndex>, place: Place<'tcx>) {
|
||||
debug!("kill_borrows_on_place: place={:?}", place);
|
||||
|
||||
let other_borrows_of_local = self
|
||||
@ -216,7 +216,7 @@ fn kill_borrows_on_place(&self, trans: &mut impl GenKill<BorrowIndex>, place: &P
|
||||
places_conflict(
|
||||
self.tcx,
|
||||
self.body,
|
||||
&self.borrow_set.borrows[i].borrowed_place,
|
||||
self.borrow_set.borrows[i].borrowed_place,
|
||||
place,
|
||||
PlaceConflictBias::NoOverlap,
|
||||
)
|
||||
@ -262,8 +262,8 @@ fn statement_effect(
|
||||
location: Location,
|
||||
) {
|
||||
match stmt.kind {
|
||||
mir::StatementKind::Assign(box (ref lhs, ref rhs)) => {
|
||||
if let mir::Rvalue::Ref(_, _, ref place) = *rhs {
|
||||
mir::StatementKind::Assign(box (lhs, ref rhs)) => {
|
||||
if let mir::Rvalue::Ref(_, _, place) = *rhs {
|
||||
if place.ignore_borrow(
|
||||
self.tcx,
|
||||
self.body,
|
||||
@ -286,13 +286,13 @@ fn statement_effect(
|
||||
mir::StatementKind::StorageDead(local) => {
|
||||
// Make sure there are no remaining borrows for locals that
|
||||
// are gone out of scope.
|
||||
self.kill_borrows_on_place(trans, &Place::from(local));
|
||||
self.kill_borrows_on_place(trans, Place::from(local));
|
||||
}
|
||||
|
||||
mir::StatementKind::LlvmInlineAsm(ref asm) => {
|
||||
for (output, kind) in asm.outputs.iter().zip(&asm.asm.outputs) {
|
||||
if !kind.is_indirect && !kind.is_rw {
|
||||
self.kill_borrows_on_place(trans, output);
|
||||
self.kill_borrows_on_place(trans, *output);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -329,7 +329,7 @@ fn call_return_effect(
|
||||
_block: mir::BasicBlock,
|
||||
_func: &mir::Operand<'tcx>,
|
||||
_args: &[mir::Operand<'tcx>],
|
||||
_dest_place: &mir::Place<'tcx>,
|
||||
_dest_place: mir::Place<'tcx>,
|
||||
) {
|
||||
}
|
||||
}
|
||||
|
@ -323,7 +323,7 @@ fn call_return_effect(
|
||||
_block: mir::BasicBlock,
|
||||
_func: &mir::Operand<'tcx>,
|
||||
_args: &[mir::Operand<'tcx>],
|
||||
dest_place: &mir::Place<'tcx>,
|
||||
dest_place: mir::Place<'tcx>,
|
||||
) {
|
||||
// when a call returns successfully, that means we need to set
|
||||
// the bits for that dest_place to 1 (initialized).
|
||||
@ -342,7 +342,7 @@ fn discriminant_switch_effect(
|
||||
&self,
|
||||
trans: &mut impl GenKill<Self::Idx>,
|
||||
_block: mir::BasicBlock,
|
||||
enum_place: &mir::Place<'tcx>,
|
||||
enum_place: mir::Place<'tcx>,
|
||||
_adt: &ty::AdtDef,
|
||||
variant: VariantIdx,
|
||||
) {
|
||||
@ -425,7 +425,7 @@ fn call_return_effect(
|
||||
_block: mir::BasicBlock,
|
||||
_func: &mir::Operand<'tcx>,
|
||||
_args: &[mir::Operand<'tcx>],
|
||||
dest_place: &mir::Place<'tcx>,
|
||||
dest_place: mir::Place<'tcx>,
|
||||
) {
|
||||
// when a call returns successfully, that means we need to set
|
||||
// the bits for that dest_place to 0 (initialized).
|
||||
@ -494,7 +494,7 @@ fn call_return_effect(
|
||||
_block: mir::BasicBlock,
|
||||
_func: &mir::Operand<'tcx>,
|
||||
_args: &[mir::Operand<'tcx>],
|
||||
dest_place: &mir::Place<'tcx>,
|
||||
dest_place: mir::Place<'tcx>,
|
||||
) {
|
||||
// when a call returns successfully, that means we need to set
|
||||
// the bits for that dest_place to 1 (initialized).
|
||||
@ -585,7 +585,7 @@ fn call_return_effect(
|
||||
block: mir::BasicBlock,
|
||||
_func: &mir::Operand<'tcx>,
|
||||
_args: &[mir::Operand<'tcx>],
|
||||
_dest_place: &mir::Place<'tcx>,
|
||||
_dest_place: mir::Place<'tcx>,
|
||||
) {
|
||||
let move_data = self.move_data();
|
||||
let init_loc_map = &move_data.init_loc_map;
|
||||
|
@ -56,7 +56,7 @@ fn call_return_effect(
|
||||
_block: BasicBlock,
|
||||
_func: &mir::Operand<'tcx>,
|
||||
_args: &[mir::Operand<'tcx>],
|
||||
_return_place: &mir::Place<'tcx>,
|
||||
_return_place: mir::Place<'tcx>,
|
||||
) {
|
||||
// Nothing to do when a call returns successfully
|
||||
}
|
||||
@ -231,7 +231,7 @@ fn call_return_effect(
|
||||
_block: BasicBlock,
|
||||
_func: &mir::Operand<'tcx>,
|
||||
_args: &[mir::Operand<'tcx>],
|
||||
return_place: &mir::Place<'tcx>,
|
||||
return_place: mir::Place<'tcx>,
|
||||
) {
|
||||
trans.gen(return_place.local);
|
||||
}
|
||||
@ -240,7 +240,7 @@ fn yield_resume_effect(
|
||||
&self,
|
||||
trans: &mut BitSet<Self::Idx>,
|
||||
_resume_block: BasicBlock,
|
||||
resume_place: &mir::Place<'tcx>,
|
||||
resume_place: mir::Place<'tcx>,
|
||||
) {
|
||||
trans.gen(resume_place.local);
|
||||
}
|
||||
|
@ -94,7 +94,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
|
||||
/// problematic for borrowck.
|
||||
///
|
||||
/// Maybe we should have separate "borrowck" and "moveck" modes.
|
||||
fn move_path_for(&mut self, place: &Place<'tcx>) -> Result<MovePathIndex, MoveError<'tcx>> {
|
||||
fn move_path_for(&mut self, place: Place<'tcx>) -> Result<MovePathIndex, MoveError<'tcx>> {
|
||||
debug!("lookup({:?})", place);
|
||||
let mut base = self.builder.data.rev_lookup.locals[place.local];
|
||||
|
||||
@ -195,7 +195,7 @@ fn add_move_path(
|
||||
})
|
||||
}
|
||||
|
||||
fn create_move_path(&mut self, place: &Place<'tcx>) {
|
||||
fn create_move_path(&mut self, place: Place<'tcx>) {
|
||||
// This is an non-moving access (such as an overwrite or
|
||||
// drop), so this not being a valid move path is OK.
|
||||
let _ = self.move_path_for(place);
|
||||
@ -279,22 +279,22 @@ struct Gatherer<'b, 'a, 'tcx> {
|
||||
|
||||
impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
|
||||
fn gather_statement(&mut self, stmt: &Statement<'tcx>) {
|
||||
match stmt.kind {
|
||||
StatementKind::Assign(box (ref place, ref rval)) => {
|
||||
self.create_move_path(place);
|
||||
match &stmt.kind {
|
||||
StatementKind::Assign(box (place, rval)) => {
|
||||
self.create_move_path(*place);
|
||||
if let RvalueInitializationState::Shallow = rval.initialization_state() {
|
||||
// Box starts out uninitialized - need to create a separate
|
||||
// move-path for the interior so it will be separate from
|
||||
// the exterior.
|
||||
self.create_move_path(&self.builder.tcx.mk_place_deref(place.clone()));
|
||||
self.create_move_path(self.builder.tcx.mk_place_deref(place.clone()));
|
||||
self.gather_init(place.as_ref(), InitKind::Shallow);
|
||||
} else {
|
||||
self.gather_init(place.as_ref(), InitKind::Deep);
|
||||
}
|
||||
self.gather_rvalue(rval);
|
||||
}
|
||||
StatementKind::FakeRead(_, ref place) => {
|
||||
self.create_move_path(place);
|
||||
StatementKind::FakeRead(_, place) => {
|
||||
self.create_move_path(**place);
|
||||
}
|
||||
StatementKind::LlvmInlineAsm(ref asm) => {
|
||||
for (output, kind) in asm.outputs.iter().zip(&asm.asm.outputs) {
|
||||
@ -308,7 +308,7 @@ fn gather_statement(&mut self, stmt: &Statement<'tcx>) {
|
||||
}
|
||||
StatementKind::StorageLive(_) => {}
|
||||
StatementKind::StorageDead(local) => {
|
||||
self.gather_move(&Place::from(local));
|
||||
self.gather_move(Place::from(*local));
|
||||
}
|
||||
StatementKind::SetDiscriminant { .. } => {
|
||||
span_bug!(
|
||||
@ -369,7 +369,7 @@ fn gather_terminator(&mut self, term: &Terminator<'tcx>) {
|
||||
| TerminatorKind::Unreachable => {}
|
||||
|
||||
TerminatorKind::Return => {
|
||||
self.gather_move(&Place::return_place());
|
||||
self.gather_move(Place::return_place());
|
||||
}
|
||||
|
||||
TerminatorKind::Assert { ref cond, .. } => {
|
||||
@ -380,16 +380,16 @@ fn gather_terminator(&mut self, term: &Terminator<'tcx>) {
|
||||
self.gather_operand(discr);
|
||||
}
|
||||
|
||||
TerminatorKind::Yield { ref value, resume_arg: ref place, .. } => {
|
||||
TerminatorKind::Yield { ref value, resume_arg: place, .. } => {
|
||||
self.gather_operand(value);
|
||||
self.create_move_path(place);
|
||||
self.gather_init(place.as_ref(), InitKind::Deep);
|
||||
}
|
||||
|
||||
TerminatorKind::Drop { ref location, target: _, unwind: _ } => {
|
||||
TerminatorKind::Drop { location, target: _, unwind: _ } => {
|
||||
self.gather_move(location);
|
||||
}
|
||||
TerminatorKind::DropAndReplace { ref location, ref value, .. } => {
|
||||
TerminatorKind::DropAndReplace { location, ref value, .. } => {
|
||||
self.create_move_path(location);
|
||||
self.gather_operand(value);
|
||||
self.gather_init(location.as_ref(), InitKind::Deep);
|
||||
@ -405,7 +405,7 @@ fn gather_terminator(&mut self, term: &Terminator<'tcx>) {
|
||||
for arg in args {
|
||||
self.gather_operand(arg);
|
||||
}
|
||||
if let Some((ref destination, _bb)) = *destination {
|
||||
if let Some((destination, _bb)) = *destination {
|
||||
self.create_move_path(destination);
|
||||
self.gather_init(destination.as_ref(), InitKind::NonPanicPathOnly);
|
||||
}
|
||||
@ -416,14 +416,14 @@ fn gather_terminator(&mut self, term: &Terminator<'tcx>) {
|
||||
fn gather_operand(&mut self, operand: &Operand<'tcx>) {
|
||||
match *operand {
|
||||
Operand::Constant(..) | Operand::Copy(..) => {} // not-a-move
|
||||
Operand::Move(ref place) => {
|
||||
Operand::Move(place) => {
|
||||
// a move
|
||||
self.gather_move(place);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn gather_move(&mut self, place: &Place<'tcx>) {
|
||||
fn gather_move(&mut self, place: Place<'tcx>) {
|
||||
debug!("gather_move({:?}, {:?})", self.loc, place);
|
||||
|
||||
if let [ref base @ .., ProjectionElem::Subslice { from, to, from_end: false }] =
|
||||
@ -434,7 +434,7 @@ fn gather_move(&mut self, place: &Place<'tcx>) {
|
||||
// are disjoint, which is expected by drop elaboration.
|
||||
let base_place =
|
||||
Place { local: place.local, projection: self.builder.tcx.intern_place_elems(base) };
|
||||
let base_path = match self.move_path_for(&base_place) {
|
||||
let base_path = match self.move_path_for(base_place) {
|
||||
Ok(path) => path,
|
||||
Err(MoveError::UnionMove { path }) => {
|
||||
self.record_move(place, path);
|
||||
@ -467,13 +467,13 @@ fn gather_move(&mut self, place: &Place<'tcx>) {
|
||||
match self.move_path_for(place) {
|
||||
Ok(path) | Err(MoveError::UnionMove { path }) => self.record_move(place, path),
|
||||
Err(error @ MoveError::IllegalMove { .. }) => {
|
||||
self.builder.errors.push((*place, error));
|
||||
self.builder.errors.push((place, error));
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
fn record_move(&mut self, place: &Place<'tcx>, path: MovePathIndex) {
|
||||
fn record_move(&mut self, place: Place<'tcx>, path: MovePathIndex) {
|
||||
let move_out = self.builder.data.moves.push(MoveOut { path, source: self.loc });
|
||||
debug!(
|
||||
"gather_move({:?}, {:?}): adding move {:?} of {:?}",
|
||||
|
@ -464,7 +464,7 @@ pub fn place_to_op(
|
||||
// avoid allocations.
|
||||
pub fn eval_place_to_op(
|
||||
&self,
|
||||
place: &mir::Place<'tcx>,
|
||||
place: mir::Place<'tcx>,
|
||||
layout: Option<TyAndLayout<'tcx>>,
|
||||
) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> {
|
||||
let base_op = match place.local {
|
||||
@ -498,7 +498,7 @@ pub fn eval_operand(
|
||||
use rustc_middle::mir::Operand::*;
|
||||
let op = match *mir_op {
|
||||
// FIXME: do some more logic on `move` to invalidate the old location
|
||||
Copy(ref place) | Move(ref place) => self.eval_place_to_op(place, layout)?,
|
||||
Copy(place) | Move(place) => self.eval_place_to_op(place, layout)?,
|
||||
|
||||
Constant(ref constant) => {
|
||||
let val =
|
||||
|
@ -635,7 +635,7 @@ pub fn place_projection(
|
||||
/// place; for reading, a more efficient alternative is `eval_place_for_read`.
|
||||
pub fn eval_place(
|
||||
&mut self,
|
||||
place: &mir::Place<'tcx>,
|
||||
place: mir::Place<'tcx>,
|
||||
) -> InterpResult<'tcx, PlaceTy<'tcx, M::PointerTag>> {
|
||||
let mut place_ty = match place.local {
|
||||
mir::RETURN_PLACE => {
|
||||
|
@ -87,23 +87,23 @@ fn statement(&mut self, stmt: &mir::Statement<'tcx>) -> InterpResult<'tcx> {
|
||||
self.tcx.span = stmt.source_info.span;
|
||||
self.memory.tcx.span = stmt.source_info.span;
|
||||
|
||||
match stmt.kind {
|
||||
Assign(box (ref place, ref rvalue)) => self.eval_rvalue_into_place(rvalue, place)?,
|
||||
match &stmt.kind {
|
||||
Assign(box (place, rvalue)) => self.eval_rvalue_into_place(rvalue, *place)?,
|
||||
|
||||
SetDiscriminant { ref place, variant_index } => {
|
||||
let dest = self.eval_place(place)?;
|
||||
self.write_discriminant_index(variant_index, dest)?;
|
||||
SetDiscriminant { place, variant_index } => {
|
||||
let dest = self.eval_place(**place)?;
|
||||
self.write_discriminant_index(*variant_index, dest)?;
|
||||
}
|
||||
|
||||
// Mark locals as alive
|
||||
StorageLive(local) => {
|
||||
let old_val = self.storage_live(local)?;
|
||||
let old_val = self.storage_live(*local)?;
|
||||
self.deallocate_local(old_val)?;
|
||||
}
|
||||
|
||||
// Mark locals as dead
|
||||
StorageDead(local) => {
|
||||
let old_val = self.storage_dead(local);
|
||||
let old_val = self.storage_dead(*local);
|
||||
self.deallocate_local(old_val)?;
|
||||
}
|
||||
|
||||
@ -112,9 +112,9 @@ fn statement(&mut self, stmt: &mir::Statement<'tcx>) -> InterpResult<'tcx> {
|
||||
FakeRead(..) => {}
|
||||
|
||||
// Stacked Borrows.
|
||||
Retag(kind, ref place) => {
|
||||
let dest = self.eval_place(place)?;
|
||||
M::retag(self, kind, dest)?;
|
||||
Retag(kind, place) => {
|
||||
let dest = self.eval_place(**place)?;
|
||||
M::retag(self, *kind, dest)?;
|
||||
}
|
||||
|
||||
// Statements we do not track.
|
||||
@ -138,7 +138,7 @@ fn statement(&mut self, stmt: &mir::Statement<'tcx>) -> InterpResult<'tcx> {
|
||||
pub fn eval_rvalue_into_place(
|
||||
&mut self,
|
||||
rvalue: &mir::Rvalue<'tcx>,
|
||||
place: &mir::Place<'tcx>,
|
||||
place: mir::Place<'tcx>,
|
||||
) -> InterpResult<'tcx> {
|
||||
let dest = self.eval_place(place)?;
|
||||
|
||||
@ -224,7 +224,7 @@ pub fn eval_rvalue_into_place(
|
||||
}
|
||||
}
|
||||
|
||||
Len(ref place) => {
|
||||
Len(place) => {
|
||||
// FIXME(CTFE): don't allow computing the length of arrays in const eval
|
||||
let src = self.eval_place(place)?;
|
||||
let mplace = self.force_allocation(src)?;
|
||||
@ -232,7 +232,7 @@ pub fn eval_rvalue_into_place(
|
||||
self.write_scalar(Scalar::from_machine_usize(len, self), dest)?;
|
||||
}
|
||||
|
||||
AddressOf(_, ref place) | Ref(_, _, ref place) => {
|
||||
AddressOf(_, place) | Ref(_, _, place) => {
|
||||
let src = self.eval_place(place)?;
|
||||
let place = self.force_allocation(src)?;
|
||||
if place.layout.size.bytes() > 0 {
|
||||
@ -261,7 +261,7 @@ pub fn eval_rvalue_into_place(
|
||||
self.cast(src, kind, dest)?;
|
||||
}
|
||||
|
||||
Discriminant(ref place) => {
|
||||
Discriminant(place) => {
|
||||
let op = self.eval_place_to_op(place, None)?;
|
||||
let discr_val = self.read_discriminant(op)?.0;
|
||||
let size = dest.layout.size;
|
||||
|
@ -51,7 +51,7 @@ pub(super) fn eval_terminator(
|
||||
self.go_to_block(target_block);
|
||||
}
|
||||
|
||||
Call { ref func, ref args, ref destination, ref cleanup, .. } => {
|
||||
Call { ref func, ref args, destination, ref cleanup, .. } => {
|
||||
let func = self.eval_operand(func, None)?;
|
||||
let (fn_val, abi) = match func.layout.ty.kind {
|
||||
ty::FnPtr(sig) => {
|
||||
@ -68,7 +68,7 @@ pub(super) fn eval_terminator(
|
||||
};
|
||||
let args = self.eval_operands(args)?;
|
||||
let ret = match destination {
|
||||
Some((dest, ret)) => Some((self.eval_place(dest)?, *ret)),
|
||||
Some((dest, ret)) => Some((self.eval_place(dest)?, ret)),
|
||||
None => None,
|
||||
};
|
||||
self.eval_fn_call(
|
||||
@ -81,7 +81,7 @@ pub(super) fn eval_terminator(
|
||||
)?;
|
||||
}
|
||||
|
||||
Drop { ref location, target, unwind } => {
|
||||
Drop { location, target, unwind } => {
|
||||
// FIXME(CTFE): forbid drop in const eval
|
||||
let place = self.eval_place(location)?;
|
||||
let ty = place.layout.ty;
|
||||
@ -328,7 +328,7 @@ fn eval_fn_call(
|
||||
// `pass_argument` would be the loop body. It takes care to
|
||||
// not advance `caller_iter` for ZSTs.
|
||||
for local in body.args_iter() {
|
||||
let dest = self.eval_place(&mir::Place::from(local))?;
|
||||
let dest = self.eval_place(mir::Place::from(local))?;
|
||||
if Some(local) == body.spread_arg {
|
||||
// Must be a tuple
|
||||
for i in 0..dest.layout.fields.count() {
|
||||
@ -346,7 +346,7 @@ fn eval_fn_call(
|
||||
}
|
||||
// Don't forget to check the return type!
|
||||
if let Some((caller_ret, _)) = ret {
|
||||
let callee_ret = self.eval_place(&mir::Place::return_place())?;
|
||||
let callee_ret = self.eval_place(mir::Place::return_place())?;
|
||||
if !Self::check_argument_compat(
|
||||
rust_abi,
|
||||
caller_ret.layout,
|
||||
|
@ -230,7 +230,7 @@ fn build_drop_shim<'tcx>(
|
||||
elaborate_drops::elaborate_drop(
|
||||
&mut elaborator,
|
||||
source_info,
|
||||
&dropee,
|
||||
dropee,
|
||||
(),
|
||||
return_block,
|
||||
elaborate_drops::Unwind::To(resume_block),
|
||||
|
@ -68,7 +68,7 @@ fn add_moves_for_packed_drops_patch<'tcx>(
|
||||
let terminator = data.terminator();
|
||||
|
||||
match terminator.kind {
|
||||
TerminatorKind::Drop { ref location, .. }
|
||||
TerminatorKind::Drop { location, .. }
|
||||
if util::is_disaligned(tcx, body, param_env, location) =>
|
||||
{
|
||||
add_move_for_packed_drop(tcx, body, &mut patch, terminator, loc, data.is_cleanup);
|
||||
|
@ -68,7 +68,7 @@ fn apply_call_return_effect(
|
||||
_block: BasicBlock,
|
||||
_func: &mir::Operand<'tcx>,
|
||||
_args: &[mir::Operand<'tcx>],
|
||||
return_place: &mir::Place<'tcx>,
|
||||
return_place: mir::Place<'tcx>,
|
||||
) {
|
||||
// We cannot reason about another function's internals, so use conservative type-based
|
||||
// qualification for the result of a function call.
|
||||
@ -76,7 +76,7 @@ fn apply_call_return_effect(
|
||||
let qualif = Q::in_any_value_of_ty(self.item, return_ty);
|
||||
|
||||
if !return_place.is_indirect() {
|
||||
self.assign_qualif_direct(return_place, qualif);
|
||||
self.assign_qualif_direct(&return_place, qualif);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -214,7 +214,7 @@ fn apply_call_return_effect(
|
||||
block: BasicBlock,
|
||||
func: &mir::Operand<'tcx>,
|
||||
args: &[mir::Operand<'tcx>],
|
||||
return_place: &mir::Place<'tcx>,
|
||||
return_place: mir::Place<'tcx>,
|
||||
) {
|
||||
self.transfer_function(state).apply_call_return_effect(block, func, args, return_place)
|
||||
}
|
||||
|
@ -260,7 +260,7 @@ fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
|
||||
|
||||
// Special-case reborrows to be more like a copy of a reference.
|
||||
match *rvalue {
|
||||
Rvalue::Ref(_, kind, ref place) => {
|
||||
Rvalue::Ref(_, kind, place) => {
|
||||
if let Some(reborrowed_proj) = place_as_reborrow(self.tcx, *self.body, place) {
|
||||
let ctx = match kind {
|
||||
BorrowKind::Shared => {
|
||||
@ -281,7 +281,7 @@ fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
Rvalue::AddressOf(mutbl, ref place) => {
|
||||
Rvalue::AddressOf(mutbl, place) => {
|
||||
if let Some(reborrowed_proj) = place_as_reborrow(self.tcx, *self.body, place) {
|
||||
let ctx = match mutbl {
|
||||
Mutability::Not => {
|
||||
@ -645,7 +645,7 @@ fn check_return_ty_is_sync(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, hir_id: HirId)
|
||||
fn place_as_reborrow(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
body: &Body<'tcx>,
|
||||
place: &'a Place<'tcx>,
|
||||
place: Place<'tcx>,
|
||||
) -> Option<&'a [PlaceElem<'tcx>]> {
|
||||
place.projection.split_last().and_then(|(outermost, inner)| {
|
||||
if outermost != &ProjectionElem::Deref {
|
||||
|
@ -184,14 +184,14 @@ fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, _location:
|
||||
// because either of these would allow modifying the layout constrained field and
|
||||
// insert values that violate the layout constraints.
|
||||
if context.is_mutating_use() || context.is_borrow() {
|
||||
self.check_mut_borrowing_layout_constrained_field(place, context.is_mutating_use());
|
||||
self.check_mut_borrowing_layout_constrained_field(*place, context.is_mutating_use());
|
||||
}
|
||||
|
||||
for (i, elem) in place.projection.iter().enumerate() {
|
||||
let proj_base = &place.projection[..i];
|
||||
|
||||
if context.is_borrow() {
|
||||
if util::is_disaligned(self.tcx, self.body, self.param_env, place) {
|
||||
if util::is_disaligned(self.tcx, self.body, self.param_env, *place) {
|
||||
let source_info = self.source_info;
|
||||
let lint_root = self.body.source_scopes[source_info.scope]
|
||||
.local_data
|
||||
@ -382,7 +382,7 @@ fn register_violations(
|
||||
}
|
||||
fn check_mut_borrowing_layout_constrained_field(
|
||||
&mut self,
|
||||
place: &Place<'tcx>,
|
||||
place: Place<'tcx>,
|
||||
is_mut_use: bool,
|
||||
) {
|
||||
let mut cursor = place.projection.as_ref();
|
||||
|
@ -468,7 +468,7 @@ fn eval_constant(&mut self, c: &Constant<'tcx>, source_info: SourceInfo) -> Opti
|
||||
}
|
||||
}
|
||||
|
||||
fn eval_place(&mut self, place: &Place<'tcx>) -> Option<OpTy<'tcx>> {
|
||||
fn eval_place(&mut self, place: Place<'tcx>) -> Option<OpTy<'tcx>> {
|
||||
trace!("eval_place(place={:?})", place);
|
||||
self.use_ecx(|this| this.ecx.eval_place_to_op(place, None))
|
||||
}
|
||||
@ -476,7 +476,7 @@ fn eval_place(&mut self, place: &Place<'tcx>) -> Option<OpTy<'tcx>> {
|
||||
fn eval_operand(&mut self, op: &Operand<'tcx>, source_info: SourceInfo) -> Option<OpTy<'tcx>> {
|
||||
match *op {
|
||||
Operand::Constant(ref c) => self.eval_constant(c, source_info),
|
||||
Operand::Move(ref place) | Operand::Copy(ref place) => self.eval_place(place),
|
||||
Operand::Move(place) | Operand::Copy(place) => self.eval_place(place),
|
||||
}
|
||||
}
|
||||
|
||||
@ -572,7 +572,7 @@ fn const_prop(
|
||||
rvalue: &Rvalue<'tcx>,
|
||||
place_layout: TyAndLayout<'tcx>,
|
||||
source_info: SourceInfo,
|
||||
place: &Place<'tcx>,
|
||||
place: Place<'tcx>,
|
||||
) -> Option<()> {
|
||||
// #66397: Don't try to eval into large places as that can cause an OOM
|
||||
if place_layout.size >= Size::from_bytes(MAX_ALLOC_LIMIT) {
|
||||
@ -825,7 +825,7 @@ fn visit_statement(&mut self, statement: &mut Statement<'tcx>, location: Locatio
|
||||
trace!("visit_statement: {:?}", statement);
|
||||
let source_info = statement.source_info;
|
||||
self.source_info = Some(source_info);
|
||||
if let StatementKind::Assign(box (ref place, ref mut rval)) = statement.kind {
|
||||
if let StatementKind::Assign(box (place, ref mut rval)) = statement.kind {
|
||||
let place_ty: Ty<'tcx> = place.ty(&self.local_decls, self.tcx).ty;
|
||||
if let Ok(place_layout) = self.tcx.layout_of(self.param_env.and(place_ty)) {
|
||||
if let Some(local) = place.as_local() {
|
||||
|
@ -97,9 +97,8 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, _source: MirSource<'tcx>, body: &mut BodyA
|
||||
if let Some(local) = place.as_local() {
|
||||
if local == dest_local {
|
||||
let maybe_action = match operand {
|
||||
Operand::Copy(ref src_place)
|
||||
| Operand::Move(ref src_place) => {
|
||||
Action::local_copy(&body, &def_use_analysis, src_place)
|
||||
Operand::Copy(src_place) | Operand::Move(src_place) => {
|
||||
Action::local_copy(&body, &def_use_analysis, *src_place)
|
||||
}
|
||||
Operand::Constant(ref src_constant) => {
|
||||
Action::constant(src_constant)
|
||||
@ -195,7 +194,7 @@ impl<'tcx> Action<'tcx> {
|
||||
fn local_copy(
|
||||
body: &Body<'tcx>,
|
||||
def_use_analysis: &DefUseAnalysis,
|
||||
src_place: &Place<'tcx>,
|
||||
src_place: Place<'tcx>,
|
||||
) -> Option<Action<'tcx>> {
|
||||
// The source must be a local.
|
||||
let src_local = if let Some(local) = src_place.as_local() {
|
||||
|
@ -46,7 +46,7 @@ pub fn on_mir_pass<'tcx>(
|
||||
body: &Body<'tcx>,
|
||||
is_after: bool,
|
||||
) {
|
||||
if mir_util::dump_enabled(tcx, pass_name, source) {
|
||||
if mir_util::dump_enabled(tcx, pass_name, source.def_id()) {
|
||||
mir_util::dump_mir(
|
||||
tcx,
|
||||
Some(pass_num),
|
||||
|
@ -346,7 +346,7 @@ fn elaborate_drops(&mut self) {
|
||||
|
||||
let resume_block = self.patch.resume_block();
|
||||
match terminator.kind {
|
||||
TerminatorKind::Drop { ref location, target, unwind } => {
|
||||
TerminatorKind::Drop { location, target, unwind } => {
|
||||
self.init_data.seek_before(loc);
|
||||
match self.move_data().rev_lookup.find(location.as_ref()) {
|
||||
LookupResult::Exact(path) => elaborate_drop(
|
||||
@ -371,7 +371,7 @@ fn elaborate_drops(&mut self) {
|
||||
}
|
||||
}
|
||||
}
|
||||
TerminatorKind::DropAndReplace { ref location, ref value, target, unwind } => {
|
||||
TerminatorKind::DropAndReplace { location, ref value, target, unwind } => {
|
||||
assert!(!data.is_cleanup);
|
||||
|
||||
self.elaborate_replace(loc, location, value, target, unwind);
|
||||
@ -396,7 +396,7 @@ fn elaborate_drops(&mut self) {
|
||||
fn elaborate_replace(
|
||||
&mut self,
|
||||
loc: Location,
|
||||
location: &Place<'tcx>,
|
||||
location: Place<'tcx>,
|
||||
value: &Operand<'tcx>,
|
||||
target: BasicBlock,
|
||||
unwind: Option<BasicBlock>,
|
||||
@ -407,7 +407,7 @@ fn elaborate_replace(
|
||||
assert!(!data.is_cleanup, "DropAndReplace in unwind path not supported");
|
||||
|
||||
let assign = Statement {
|
||||
kind: StatementKind::Assign(box (*location, Rvalue::Use(value.clone()))),
|
||||
kind: StatementKind::Assign(box (location, Rvalue::Use(value.clone()))),
|
||||
source_info: terminator.source_info,
|
||||
};
|
||||
|
||||
@ -459,7 +459,7 @@ fn elaborate_replace(
|
||||
debug!("elaborate_drop_and_replace({:?}) - untracked {:?}", terminator, parent);
|
||||
self.patch.patch_terminator(
|
||||
bb,
|
||||
TerminatorKind::Drop { location: *location, target, unwind: Some(unwind) },
|
||||
TerminatorKind::Drop { location, target, unwind: Some(unwind) },
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -853,7 +853,7 @@ fn elaborate_generator_drops<'tcx>(
|
||||
elaborate_drop(
|
||||
&mut elaborator,
|
||||
*source_info,
|
||||
&Place::from(SELF_ARG),
|
||||
Place::from(SELF_ARG),
|
||||
(),
|
||||
*target,
|
||||
unwind,
|
||||
|
@ -450,7 +450,7 @@ fn inline_call(
|
||||
// Place could result in two different locations if `f`
|
||||
// writes to `i`. To prevent this we need to create a temporary
|
||||
// borrow of the place and pass the destination as `*temp` instead.
|
||||
fn dest_needs_borrow(place: &Place<'_>) -> bool {
|
||||
fn dest_needs_borrow(place: Place<'_>) -> bool {
|
||||
for elem in place.projection.iter() {
|
||||
match elem {
|
||||
ProjectionElem::Deref | ProjectionElem::Index(_) => return true,
|
||||
@ -461,7 +461,7 @@ fn dest_needs_borrow(place: &Place<'_>) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
let dest = if dest_needs_borrow(&destination.0) {
|
||||
let dest = if dest_needs_borrow(destination.0) {
|
||||
debug!("creating temp for return destination");
|
||||
let dest = Rvalue::Ref(
|
||||
self.tcx.lifetimes.re_erased,
|
||||
|
@ -150,7 +150,7 @@ fn check_rvalue(
|
||||
Rvalue::Len(place)
|
||||
| Rvalue::Discriminant(place)
|
||||
| Rvalue::Ref(_, _, place)
|
||||
| Rvalue::AddressOf(_, place) => check_place(tcx, place, span, def_id, body),
|
||||
| Rvalue::AddressOf(_, place) => check_place(tcx, *place, span, def_id, body),
|
||||
Rvalue::Cast(CastKind::Misc, operand, cast_ty) => {
|
||||
use rustc_middle::ty::cast::CastTy;
|
||||
let cast_in = CastTy::from_ty(operand.ty(body, tcx)).expect("bad input type for cast");
|
||||
@ -215,7 +215,7 @@ fn check_statement(
|
||||
let span = statement.source_info.span;
|
||||
match &statement.kind {
|
||||
StatementKind::Assign(box (place, rval)) => {
|
||||
check_place(tcx, place, span, def_id, body)?;
|
||||
check_place(tcx, *place, span, def_id, body)?;
|
||||
check_rvalue(tcx, body, def_id, rval, span)
|
||||
}
|
||||
|
||||
@ -225,10 +225,12 @@ fn check_statement(
|
||||
Err((span, "loops and conditional expressions are not stable in const fn".into()))
|
||||
}
|
||||
|
||||
StatementKind::FakeRead(_, place) => check_place(tcx, place, span, def_id, body),
|
||||
StatementKind::FakeRead(_, place) => check_place(tcx, **place, span, def_id, body),
|
||||
|
||||
// just an assignment
|
||||
StatementKind::SetDiscriminant { place, .. } => check_place(tcx, place, span, def_id, body),
|
||||
StatementKind::SetDiscriminant { place, .. } => {
|
||||
check_place(tcx, **place, span, def_id, body)
|
||||
}
|
||||
|
||||
StatementKind::LlvmInlineAsm { .. } => {
|
||||
Err((span, "cannot use inline assembly in const fn".into()))
|
||||
@ -251,7 +253,7 @@ fn check_operand(
|
||||
body: &Body<'tcx>,
|
||||
) -> McfResult {
|
||||
match operand {
|
||||
Operand::Move(place) | Operand::Copy(place) => check_place(tcx, place, span, def_id, body),
|
||||
Operand::Move(place) | Operand::Copy(place) => check_place(tcx, *place, span, def_id, body),
|
||||
Operand::Constant(c) => match c.check_static_ptr(tcx) {
|
||||
Some(_) => Err((span, "cannot access `static` items in const fn".into())),
|
||||
None => Ok(()),
|
||||
@ -261,7 +263,7 @@ fn check_operand(
|
||||
|
||||
fn check_place(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
place: &Place<'tcx>,
|
||||
place: Place<'tcx>,
|
||||
span: Span,
|
||||
def_id: DefId,
|
||||
body: &Body<'tcx>,
|
||||
@ -330,9 +332,9 @@ fn check_terminator(
|
||||
| TerminatorKind::Return
|
||||
| TerminatorKind::Resume => Ok(()),
|
||||
|
||||
TerminatorKind::Drop { location, .. } => check_place(tcx, location, span, def_id, body),
|
||||
TerminatorKind::Drop { location, .. } => check_place(tcx, *location, span, def_id, body),
|
||||
TerminatorKind::DropAndReplace { location, value, .. } => {
|
||||
check_place(tcx, location, span, def_id, body)?;
|
||||
check_place(tcx, *location, span, def_id, body)?;
|
||||
check_operand(tcx, value, span, def_id, body)
|
||||
}
|
||||
|
||||
|
@ -127,7 +127,7 @@ pub fn sanity_check_via_rustc_peek<'tcx, A>(
|
||||
let loc = Location { block: bb, statement_index };
|
||||
cursor.seek_before(loc);
|
||||
let state = cursor.get();
|
||||
results.analysis.peek_at(tcx, place, state, call);
|
||||
results.analysis.peek_at(tcx, *place, state, call);
|
||||
}
|
||||
|
||||
_ => {
|
||||
@ -231,7 +231,7 @@ pub trait RustcPeekAt<'tcx>: Analysis<'tcx> {
|
||||
fn peek_at(
|
||||
&self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
place: &mir::Place<'tcx>,
|
||||
place: mir::Place<'tcx>,
|
||||
flow_state: &BitSet<Self::Idx>,
|
||||
call: PeekCall,
|
||||
);
|
||||
@ -244,7 +244,7 @@ impl<'tcx, A> RustcPeekAt<'tcx> for A
|
||||
fn peek_at(
|
||||
&self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
place: &mir::Place<'tcx>,
|
||||
place: mir::Place<'tcx>,
|
||||
flow_state: &BitSet<Self::Idx>,
|
||||
call: PeekCall,
|
||||
) {
|
||||
@ -268,7 +268,7 @@ impl<'tcx> RustcPeekAt<'tcx> for MaybeMutBorrowedLocals<'_, 'tcx> {
|
||||
fn peek_at(
|
||||
&self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
place: &mir::Place<'tcx>,
|
||||
place: mir::Place<'tcx>,
|
||||
flow_state: &BitSet<Local>,
|
||||
call: PeekCall,
|
||||
) {
|
||||
|
@ -89,7 +89,7 @@ fn match_get_variant_field<'tcx>(stmt: &Statement<'tcx>) -> Option<(Local, Local
|
||||
StatementKind::Assign(box (place_into, rvalue_from)) => match rvalue_from {
|
||||
Rvalue::Use(Operand::Copy(pf)) | Rvalue::Use(Operand::Move(pf)) => {
|
||||
let local_into = place_into.as_local()?;
|
||||
let (local_from, vf) = match_variant_field_place(&pf)?;
|
||||
let (local_from, vf) = match_variant_field_place(*pf)?;
|
||||
Some((local_into, local_from, vf))
|
||||
}
|
||||
_ => None,
|
||||
@ -107,7 +107,7 @@ fn match_set_variant_field<'tcx>(stmt: &Statement<'tcx>) -> Option<(Local, Local
|
||||
StatementKind::Assign(box (place_from, rvalue_into)) => match rvalue_into {
|
||||
Rvalue::Use(Operand::Move(place_into)) => {
|
||||
let local_into = place_into.as_local()?;
|
||||
let (local_from, vf) = match_variant_field_place(&place_from)?;
|
||||
let (local_from, vf) = match_variant_field_place(*place_from)?;
|
||||
Some((local_into, local_from, vf))
|
||||
}
|
||||
_ => None,
|
||||
@ -137,7 +137,7 @@ struct VarField<'tcx> {
|
||||
}
|
||||
|
||||
/// Match on `((_LOCAL as Variant).FIELD: TY)`.
|
||||
fn match_variant_field_place<'tcx>(place: &Place<'tcx>) -> Option<(Local, VarField<'tcx>)> {
|
||||
fn match_variant_field_place<'tcx>(place: Place<'tcx>) -> Option<(Local, VarField<'tcx>)> {
|
||||
match place.as_ref() {
|
||||
PlaceRef {
|
||||
local,
|
||||
|
@ -8,7 +8,7 @@ pub fn is_disaligned<'tcx, L>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
local_decls: &L,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
place: &Place<'tcx>,
|
||||
place: Place<'tcx>,
|
||||
) -> bool
|
||||
where
|
||||
L: HasLocalDecls<'tcx>,
|
||||
@ -34,7 +34,7 @@ pub fn is_disaligned<'tcx, L>(
|
||||
}
|
||||
}
|
||||
|
||||
fn is_within_packed<'tcx, L>(tcx: TyCtxt<'tcx>, local_decls: &L, place: &Place<'tcx>) -> bool
|
||||
fn is_within_packed<'tcx, L>(tcx: TyCtxt<'tcx>, local_decls: &L, place: Place<'tcx>) -> bool
|
||||
where
|
||||
L: HasLocalDecls<'tcx>,
|
||||
{
|
||||
|
@ -100,7 +100,7 @@ struct DropCtxt<'l, 'b, 'tcx, D>
|
||||
|
||||
source_info: SourceInfo,
|
||||
|
||||
place: &'l Place<'tcx>,
|
||||
place: Place<'tcx>,
|
||||
path: D::Path,
|
||||
succ: BasicBlock,
|
||||
unwind: Unwind,
|
||||
@ -109,7 +109,7 @@ struct DropCtxt<'l, 'b, 'tcx, D>
|
||||
pub fn elaborate_drop<'b, 'tcx, D>(
|
||||
elaborator: &mut D,
|
||||
source_info: SourceInfo,
|
||||
place: &Place<'tcx>,
|
||||
place: Place<'tcx>,
|
||||
path: D::Path,
|
||||
succ: BasicBlock,
|
||||
unwind: Unwind,
|
||||
@ -126,7 +126,7 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D>
|
||||
D: DropElaborator<'b, 'tcx>,
|
||||
'tcx: 'b,
|
||||
{
|
||||
fn place_ty(&self, place: &Place<'tcx>) -> Ty<'tcx> {
|
||||
fn place_ty(&self, place: Place<'tcx>) -> Ty<'tcx> {
|
||||
place.ty(self.elaborator.body(), self.tcx()).ty
|
||||
}
|
||||
|
||||
@ -168,7 +168,7 @@ pub fn elaborate_drop(&mut self, bb: BasicBlock) {
|
||||
self.elaborator.patch().patch_terminator(
|
||||
bb,
|
||||
TerminatorKind::Drop {
|
||||
location: *self.place,
|
||||
location: self.place,
|
||||
target: self.succ,
|
||||
unwind: self.unwind.into_option(),
|
||||
},
|
||||
@ -195,7 +195,7 @@ pub fn elaborate_drop(&mut self, bb: BasicBlock) {
|
||||
/// (the move path is `None` if the field is a rest field).
|
||||
fn move_paths_for_fields(
|
||||
&self,
|
||||
base_place: &Place<'tcx>,
|
||||
base_place: Place<'tcx>,
|
||||
variant_path: D::Path,
|
||||
variant: &'tcx ty::VariantDef,
|
||||
substs: SubstsRef<'tcx>,
|
||||
@ -219,7 +219,7 @@ fn move_paths_for_fields(
|
||||
|
||||
fn drop_subpath(
|
||||
&mut self,
|
||||
place: &Place<'tcx>,
|
||||
place: Place<'tcx>,
|
||||
path: Option<D::Path>,
|
||||
succ: BasicBlock,
|
||||
unwind: Unwind,
|
||||
@ -267,12 +267,10 @@ fn drop_halfladder(
|
||||
) -> Vec<BasicBlock> {
|
||||
Some(succ)
|
||||
.into_iter()
|
||||
.chain(fields.iter().rev().zip(unwind_ladder).map(
|
||||
|(&(ref place, path), &unwind_succ)| {
|
||||
succ = self.drop_subpath(place, path, succ, unwind_succ);
|
||||
succ
|
||||
},
|
||||
))
|
||||
.chain(fields.iter().rev().zip(unwind_ladder).map(|(&(place, path), &unwind_succ)| {
|
||||
succ = self.drop_subpath(place, path, succ, unwind_succ);
|
||||
succ
|
||||
}))
|
||||
.collect()
|
||||
}
|
||||
|
||||
@ -315,7 +313,7 @@ fn drop_ladder(
|
||||
debug!("drop_ladder({:?}, {:?})", self, fields);
|
||||
|
||||
let mut fields = fields;
|
||||
fields.retain(|&(ref place, _)| {
|
||||
fields.retain(|&(place, _)| {
|
||||
self.place_ty(place).needs_drop(self.tcx(), self.elaborator.param_env())
|
||||
});
|
||||
|
||||
@ -364,7 +362,7 @@ fn open_drop_for_box(&mut self, adt: &'tcx ty::AdtDef, substs: SubstsRef<'tcx>)
|
||||
let unwind_succ =
|
||||
self.unwind.map(|unwind| self.box_free_block(adt, substs, unwind, Unwind::InCleanup));
|
||||
|
||||
self.drop_subpath(&interior, interior_path, succ, unwind_succ)
|
||||
self.drop_subpath(interior, interior_path, succ, unwind_succ)
|
||||
}
|
||||
|
||||
fn open_drop_for_adt(&mut self, adt: &'tcx ty::AdtDef, substs: SubstsRef<'tcx>) -> BasicBlock {
|
||||
@ -439,8 +437,7 @@ fn open_drop_for_multivariant(
|
||||
self.place.clone(),
|
||||
ProjectionElem::Downcast(Some(variant.ident.name), variant_index),
|
||||
);
|
||||
let fields =
|
||||
self.move_paths_for_fields(&base_place, variant_path, &variant, substs);
|
||||
let fields = self.move_paths_for_fields(base_place, variant_path, &variant, substs);
|
||||
values.push(discr.val);
|
||||
if let Unwind::To(unwind) = unwind {
|
||||
// We can't use the half-ladder from the original
|
||||
@ -527,9 +524,9 @@ fn adt_switch_block(
|
||||
// way lies only trouble.
|
||||
let discr_ty = adt.repr.discr_type().to_ty(self.tcx());
|
||||
let discr = Place::from(self.new_temp(discr_ty));
|
||||
let discr_rv = Rvalue::Discriminant(*self.place);
|
||||
let discr_rv = Rvalue::Discriminant(self.place);
|
||||
let switch_block = BasicBlockData {
|
||||
statements: vec![self.assign(&discr, discr_rv)],
|
||||
statements: vec![self.assign(discr, discr_rv)],
|
||||
terminator: Some(Terminator {
|
||||
source_info: self.source_info,
|
||||
kind: TerminatorKind::SwitchInt {
|
||||
@ -560,11 +557,11 @@ fn destructor_call_block(&mut self, (succ, unwind): (BasicBlock, Unwind)) -> Bas
|
||||
|
||||
let result = BasicBlockData {
|
||||
statements: vec![self.assign(
|
||||
&Place::from(ref_place),
|
||||
Place::from(ref_place),
|
||||
Rvalue::Ref(
|
||||
tcx.lifetimes.re_erased,
|
||||
BorrowKind::Mut { allow_two_phase_borrow: false },
|
||||
*self.place,
|
||||
self.place,
|
||||
),
|
||||
)],
|
||||
terminator: Some(Terminator {
|
||||
@ -607,7 +604,7 @@ fn drop_loop(
|
||||
&mut self,
|
||||
succ: BasicBlock,
|
||||
cur: Local,
|
||||
length_or_end: &Place<'tcx>,
|
||||
length_or_end: Place<'tcx>,
|
||||
ety: Ty<'tcx>,
|
||||
unwind: Unwind,
|
||||
ptr_based: bool,
|
||||
@ -617,7 +614,7 @@ fn drop_loop(
|
||||
let tcx = self.tcx();
|
||||
|
||||
let ptr_ty = tcx.mk_ptr(ty::TypeAndMut { ty: ety, mutbl: hir::Mutability::Mut });
|
||||
let ptr = &Place::from(self.new_temp(ptr_ty));
|
||||
let ptr = Place::from(self.new_temp(ptr_ty));
|
||||
let can_go = Place::from(self.new_temp(tcx.types.bool));
|
||||
|
||||
let one = self.constant_usize(1);
|
||||
@ -631,7 +628,7 @@ fn drop_loop(
|
||||
};
|
||||
|
||||
let drop_block = BasicBlockData {
|
||||
statements: vec![self.assign(ptr, ptr_next), self.assign(&Place::from(cur), cur_next)],
|
||||
statements: vec![self.assign(ptr, ptr_next), self.assign(Place::from(cur), cur_next)],
|
||||
is_cleanup: unwind.is_cleanup(),
|
||||
terminator: Some(Terminator {
|
||||
source_info: self.source_info,
|
||||
@ -643,8 +640,8 @@ fn drop_loop(
|
||||
|
||||
let loop_block = BasicBlockData {
|
||||
statements: vec![self.assign(
|
||||
&can_go,
|
||||
Rvalue::BinaryOp(BinOp::Eq, copy(Place::from(cur)), copy(*length_or_end)),
|
||||
can_go,
|
||||
Rvalue::BinaryOp(BinOp::Eq, copy(Place::from(cur)), copy(length_or_end)),
|
||||
)],
|
||||
is_cleanup: unwind.is_cleanup(),
|
||||
terminator: Some(Terminator {
|
||||
@ -703,16 +700,16 @@ fn open_drop_for_array(&mut self, ety: Ty<'tcx>, opt_size: Option<u64>) -> Basic
|
||||
}
|
||||
}
|
||||
|
||||
let move_ = |place: &Place<'tcx>| Operand::Move(*place);
|
||||
let elem_size = &Place::from(self.new_temp(tcx.types.usize));
|
||||
let len = &Place::from(self.new_temp(tcx.types.usize));
|
||||
let move_ = |place: Place<'tcx>| Operand::Move(place);
|
||||
let elem_size = Place::from(self.new_temp(tcx.types.usize));
|
||||
let len = Place::from(self.new_temp(tcx.types.usize));
|
||||
|
||||
static USIZE_SWITCH_ZERO: &[u128] = &[0];
|
||||
|
||||
let base_block = BasicBlockData {
|
||||
statements: vec![
|
||||
self.assign(elem_size, Rvalue::NullaryOp(NullOp::SizeOf, ety)),
|
||||
self.assign(len, Rvalue::Len(*self.place)),
|
||||
self.assign(len, Rvalue::Len(self.place)),
|
||||
],
|
||||
is_cleanup: self.unwind.is_cleanup(),
|
||||
terminator: Some(Terminator {
|
||||
@ -748,10 +745,10 @@ fn drop_loop_pair(
|
||||
let length_or_end = if ptr_based { Place::from(self.new_temp(iter_ty)) } else { length };
|
||||
|
||||
let unwind = self.unwind.map(|unwind| {
|
||||
self.drop_loop(unwind, cur, &length_or_end, ety, Unwind::InCleanup, ptr_based)
|
||||
self.drop_loop(unwind, cur, length_or_end, ety, Unwind::InCleanup, ptr_based)
|
||||
});
|
||||
|
||||
let loop_block = self.drop_loop(self.succ, cur, &length_or_end, ety, unwind, ptr_based);
|
||||
let loop_block = self.drop_loop(self.succ, cur, length_or_end, ety, unwind, ptr_based);
|
||||
|
||||
let cur = Place::from(cur);
|
||||
let drop_block_stmts = if ptr_based {
|
||||
@ -761,17 +758,17 @@ fn drop_loop_pair(
|
||||
// cur = tmp as *mut T;
|
||||
// end = Offset(cur, len);
|
||||
vec![
|
||||
self.assign(&tmp, Rvalue::AddressOf(Mutability::Mut, *self.place)),
|
||||
self.assign(&cur, Rvalue::Cast(CastKind::Misc, Operand::Move(tmp), iter_ty)),
|
||||
self.assign(tmp, Rvalue::AddressOf(Mutability::Mut, self.place)),
|
||||
self.assign(cur, Rvalue::Cast(CastKind::Misc, Operand::Move(tmp), iter_ty)),
|
||||
self.assign(
|
||||
&length_or_end,
|
||||
length_or_end,
|
||||
Rvalue::BinaryOp(BinOp::Offset, Operand::Copy(cur), Operand::Move(length)),
|
||||
),
|
||||
]
|
||||
} else {
|
||||
// cur = 0 (length already pushed)
|
||||
let zero = self.constant_usize(0);
|
||||
vec![self.assign(&cur, Rvalue::Use(zero))]
|
||||
vec![self.assign(cur, Rvalue::Use(zero))]
|
||||
};
|
||||
let drop_block = self.elaborator.patch().new_block(BasicBlockData {
|
||||
statements: drop_block_stmts,
|
||||
@ -935,7 +932,7 @@ fn unelaborated_free_block(
|
||||
|
||||
fn drop_block(&mut self, target: BasicBlock, unwind: Unwind) -> BasicBlock {
|
||||
let block =
|
||||
TerminatorKind::Drop { location: *self.place, target, unwind: unwind.into_option() };
|
||||
TerminatorKind::Drop { location: self.place, target, unwind: unwind.into_option() };
|
||||
self.new_block(unwind, block)
|
||||
}
|
||||
|
||||
@ -992,7 +989,7 @@ fn constant_usize(&self, val: u16) -> Operand<'tcx> {
|
||||
})
|
||||
}
|
||||
|
||||
fn assign(&self, lhs: &Place<'tcx>, rhs: Rvalue<'tcx>) -> Statement<'tcx> {
|
||||
Statement { source_info: self.source_info, kind: StatementKind::Assign(box (*lhs, rhs)) }
|
||||
fn assign(&self, lhs: Place<'tcx>, rhs: Rvalue<'tcx>) -> Statement<'tcx> {
|
||||
Statement { source_info: self.source_info, kind: StatementKind::Assign(box (lhs, rhs)) }
|
||||
}
|
||||
}
|
||||
|
@ -265,7 +265,7 @@ pub fn dump_mir<'tcx>(
|
||||
body: &Body<'tcx>,
|
||||
result: &LivenessResult,
|
||||
) {
|
||||
if !dump_enabled(tcx, pass_name, source) {
|
||||
if !dump_enabled(tcx, pass_name, source.def_id()) {
|
||||
return;
|
||||
}
|
||||
let node_path = ty::print::with_forced_impl_filename_line(|| {
|
||||
|
@ -78,21 +78,21 @@ pub fn dump_mir<'tcx, F>(
|
||||
) where
|
||||
F: FnMut(PassWhere, &mut dyn Write) -> io::Result<()>,
|
||||
{
|
||||
if !dump_enabled(tcx, pass_name, source) {
|
||||
if !dump_enabled(tcx, pass_name, source.def_id()) {
|
||||
return;
|
||||
}
|
||||
|
||||
dump_matched_mir_node(tcx, pass_num, pass_name, disambiguator, source, body, extra_data);
|
||||
}
|
||||
|
||||
pub fn dump_enabled<'tcx>(tcx: TyCtxt<'tcx>, pass_name: &str, source: MirSource<'tcx>) -> bool {
|
||||
pub fn dump_enabled<'tcx>(tcx: TyCtxt<'tcx>, pass_name: &str, def_id: DefId) -> bool {
|
||||
let filters = match tcx.sess.opts.debugging_opts.dump_mir {
|
||||
None => return false,
|
||||
Some(ref filters) => filters,
|
||||
};
|
||||
let node_path = ty::print::with_forced_impl_filename_line(|| {
|
||||
// see notes on #41697 below
|
||||
tcx.def_path_str(source.def_id())
|
||||
tcx.def_path_str(def_id)
|
||||
});
|
||||
filters.split('|').any(|or_filter| {
|
||||
or_filter.split('&').all(|and_filter| {
|
||||
|
@ -9,7 +9,7 @@
|
||||
impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
crate fn ast_block(
|
||||
&mut self,
|
||||
destination: &Place<'tcx>,
|
||||
destination: Place<'tcx>,
|
||||
block: BasicBlock,
|
||||
ast_block: &'tcx hir::Block<'tcx>,
|
||||
source_info: SourceInfo,
|
||||
@ -43,7 +43,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
|
||||
fn ast_block_stmts(
|
||||
&mut self,
|
||||
destination: &Place<'tcx>,
|
||||
destination: Place<'tcx>,
|
||||
mut block: BasicBlock,
|
||||
span: Span,
|
||||
stmts: Vec<StmtRef<'tcx>>,
|
||||
|
@ -34,12 +34,12 @@ impl<'tcx> CFG<'tcx> {
|
||||
&mut self,
|
||||
block: BasicBlock,
|
||||
source_info: SourceInfo,
|
||||
place: &Place<'tcx>,
|
||||
place: Place<'tcx>,
|
||||
rvalue: Rvalue<'tcx>,
|
||||
) {
|
||||
self.push(
|
||||
block,
|
||||
Statement { source_info, kind: StatementKind::Assign(box (*place, rvalue)) },
|
||||
Statement { source_info, kind: StatementKind::Assign(box (place, rvalue)) },
|
||||
);
|
||||
}
|
||||
|
||||
@ -47,7 +47,7 @@ impl<'tcx> CFG<'tcx> {
|
||||
&mut self,
|
||||
block: BasicBlock,
|
||||
source_info: SourceInfo,
|
||||
temp: &Place<'tcx>,
|
||||
temp: Place<'tcx>,
|
||||
constant: Constant<'tcx>,
|
||||
) {
|
||||
self.push_assign(block, source_info, temp, Rvalue::Use(Operand::Constant(box constant)));
|
||||
@ -57,7 +57,7 @@ impl<'tcx> CFG<'tcx> {
|
||||
&mut self,
|
||||
block: BasicBlock,
|
||||
source_info: SourceInfo,
|
||||
place: &Place<'tcx>,
|
||||
place: Place<'tcx>,
|
||||
) {
|
||||
self.push_assign(
|
||||
block,
|
||||
|
@ -341,12 +341,12 @@ fn bounds_check(
|
||||
let lt = self.temp(bool_ty, expr_span);
|
||||
|
||||
// len = len(slice)
|
||||
self.cfg.push_assign(block, source_info, &len, Rvalue::Len(slice));
|
||||
self.cfg.push_assign(block, source_info, len, Rvalue::Len(slice));
|
||||
// lt = idx < len
|
||||
self.cfg.push_assign(
|
||||
block,
|
||||
source_info,
|
||||
<,
|
||||
lt,
|
||||
Rvalue::BinaryOp(BinOp::Lt, Operand::Copy(Place::from(index)), Operand::Copy(len)),
|
||||
);
|
||||
let msg = BoundsCheck { len: Operand::Move(len), index: Operand::Copy(Place::from(index)) };
|
||||
@ -388,7 +388,7 @@ fn add_fake_borrows_of_base(
|
||||
self.cfg.push_assign(
|
||||
block,
|
||||
source_info,
|
||||
&fake_borrow_temp.into(),
|
||||
fake_borrow_temp.into(),
|
||||
Rvalue::Ref(
|
||||
tcx.lifetimes.re_erased,
|
||||
BorrowKind::Shallow,
|
||||
|
@ -78,7 +78,7 @@ fn expr_as_rvalue(
|
||||
this.cfg.push_assign(
|
||||
block,
|
||||
source_info,
|
||||
&is_min,
|
||||
is_min,
|
||||
Rvalue::BinaryOp(BinOp::Eq, arg.to_copy(), minval),
|
||||
);
|
||||
|
||||
@ -109,15 +109,12 @@ fn expr_as_rvalue(
|
||||
|
||||
// malloc some memory of suitable type (thus far, uninitialized):
|
||||
let box_ = Rvalue::NullaryOp(NullOp::Box, value.ty);
|
||||
this.cfg.push_assign(block, source_info, &Place::from(result), box_);
|
||||
this.cfg.push_assign(block, source_info, Place::from(result), box_);
|
||||
|
||||
// initialize the box contents:
|
||||
unpack!(
|
||||
block = this.into(
|
||||
&this.hir.tcx().mk_place_deref(Place::from(result)),
|
||||
block,
|
||||
value
|
||||
)
|
||||
block =
|
||||
this.into(this.hir.tcx().mk_place_deref(Place::from(result)), block, value)
|
||||
);
|
||||
block.and(Rvalue::Use(Operand::Move(Place::from(result))))
|
||||
}
|
||||
@ -284,7 +281,7 @@ fn expr_as_rvalue(
|
||||
self.cfg.push_assign(
|
||||
block,
|
||||
source_info,
|
||||
&result_value,
|
||||
result_value,
|
||||
Rvalue::CheckedBinaryOp(op, lhs, rhs),
|
||||
);
|
||||
let val_fld = Field::new(0);
|
||||
@ -317,7 +314,7 @@ fn expr_as_rvalue(
|
||||
self.cfg.push_assign(
|
||||
block,
|
||||
source_info,
|
||||
&is_zero,
|
||||
is_zero,
|
||||
Rvalue::BinaryOp(BinOp::Eq, rhs.to_copy(), zero),
|
||||
);
|
||||
|
||||
@ -338,13 +335,13 @@ fn expr_as_rvalue(
|
||||
self.cfg.push_assign(
|
||||
block,
|
||||
source_info,
|
||||
&is_neg_1,
|
||||
is_neg_1,
|
||||
Rvalue::BinaryOp(BinOp::Eq, rhs.to_copy(), neg_1),
|
||||
);
|
||||
self.cfg.push_assign(
|
||||
block,
|
||||
source_info,
|
||||
&is_min,
|
||||
is_min,
|
||||
Rvalue::BinaryOp(BinOp::Eq, lhs.to_copy(), min),
|
||||
);
|
||||
|
||||
@ -353,7 +350,7 @@ fn expr_as_rvalue(
|
||||
self.cfg.push_assign(
|
||||
block,
|
||||
source_info,
|
||||
&of,
|
||||
of,
|
||||
Rvalue::BinaryOp(BinOp::BitAnd, is_neg_1, is_min),
|
||||
);
|
||||
|
||||
@ -428,7 +425,7 @@ fn limit_capture_mutability(
|
||||
this.cfg.push_assign(
|
||||
block,
|
||||
source_info,
|
||||
&Place::from(temp),
|
||||
Place::from(temp),
|
||||
Rvalue::Ref(this.hir.tcx().lifetimes.re_erased, borrow_kind, arg_place),
|
||||
);
|
||||
|
||||
|
@ -66,7 +66,7 @@ fn expr_as_temp(
|
||||
}
|
||||
this.local_decls.push(local_decl)
|
||||
};
|
||||
let temp_place = &Place::from(temp);
|
||||
let temp_place = Place::from(temp);
|
||||
|
||||
match expr.kind {
|
||||
// Don't bother with StorageLive and Dead for these temporaries,
|
||||
|
@ -16,7 +16,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
/// is assumed to be uninitialized.
|
||||
crate fn into_expr(
|
||||
&mut self,
|
||||
destination: &Place<'tcx>,
|
||||
destination: Place<'tcx>,
|
||||
mut block: BasicBlock,
|
||||
expr: Expr<'tcx>,
|
||||
) -> BlockAnd<()> {
|
||||
@ -160,7 +160,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
// introduce a unit temporary as the destination for the loop body.
|
||||
let tmp = this.get_unit_temp();
|
||||
// Execute the body, branching back to the test.
|
||||
let body_block_end = unpack!(this.into(&tmp, body_block, body));
|
||||
let body_block_end = unpack!(this.into(tmp, body_block, body));
|
||||
this.cfg.goto(body_block_end, source_info, loop_block);
|
||||
},
|
||||
);
|
||||
@ -202,8 +202,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
is_block_tail: None,
|
||||
});
|
||||
let ptr_temp = Place::from(ptr_temp);
|
||||
let block = unpack!(this.into(&ptr_temp, block, ptr));
|
||||
this.into(&this.hir.tcx().mk_place_deref(ptr_temp), block, val)
|
||||
let block = unpack!(this.into(ptr_temp, block, ptr));
|
||||
this.into(this.hir.tcx().mk_place_deref(ptr_temp), block, val)
|
||||
} else {
|
||||
let args: Vec<_> = args
|
||||
.into_iter()
|
||||
@ -228,7 +228,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
destination: if expr.ty.is_never() {
|
||||
None
|
||||
} else {
|
||||
Some((*destination, success))
|
||||
Some((destination, success))
|
||||
},
|
||||
from_hir_call,
|
||||
},
|
||||
@ -373,12 +373,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
this.cfg.terminate(
|
||||
block,
|
||||
source_info,
|
||||
TerminatorKind::Yield {
|
||||
value,
|
||||
resume,
|
||||
resume_arg: *destination,
|
||||
drop: cleanup,
|
||||
},
|
||||
TerminatorKind::Yield { value, resume, resume_arg: destination, drop: cleanup },
|
||||
);
|
||||
resume.unit()
|
||||
}
|
||||
|
@ -50,7 +50,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
} else {
|
||||
let rhs = unpack!(block = this.as_local_rvalue(block, rhs));
|
||||
let lhs = unpack!(block = this.as_place(block, lhs));
|
||||
this.cfg.push_assign(block, source_info, &lhs, rhs);
|
||||
this.cfg.push_assign(block, source_info, lhs, rhs);
|
||||
}
|
||||
|
||||
this.block_context.pop();
|
||||
@ -82,7 +82,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
block =
|
||||
this.build_binary_op(block, op, expr_span, lhs_ty, Operand::Copy(lhs), rhs)
|
||||
);
|
||||
this.cfg.push_assign(block, source_info, &lhs, result);
|
||||
this.cfg.push_assign(block, source_info, lhs, result);
|
||||
|
||||
this.block_context.pop();
|
||||
block.unit()
|
||||
|
@ -12,7 +12,7 @@ pub(in crate::build) trait EvalInto<'tcx> {
|
||||
fn eval_into(
|
||||
self,
|
||||
builder: &mut Builder<'_, 'tcx>,
|
||||
destination: &Place<'tcx>,
|
||||
destination: Place<'tcx>,
|
||||
block: BasicBlock,
|
||||
) -> BlockAnd<()>;
|
||||
}
|
||||
@ -20,7 +20,7 @@ fn eval_into(
|
||||
impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
crate fn into<E>(
|
||||
&mut self,
|
||||
destination: &Place<'tcx>,
|
||||
destination: Place<'tcx>,
|
||||
block: BasicBlock,
|
||||
expr: E,
|
||||
) -> BlockAnd<()>
|
||||
@ -35,7 +35,7 @@ impl<'tcx> EvalInto<'tcx> for ExprRef<'tcx> {
|
||||
fn eval_into(
|
||||
self,
|
||||
builder: &mut Builder<'_, 'tcx>,
|
||||
destination: &Place<'tcx>,
|
||||
destination: Place<'tcx>,
|
||||
block: BasicBlock,
|
||||
) -> BlockAnd<()> {
|
||||
let expr = builder.hir.mirror(self);
|
||||
@ -47,7 +47,7 @@ impl<'tcx> EvalInto<'tcx> for Expr<'tcx> {
|
||||
fn eval_into(
|
||||
self,
|
||||
builder: &mut Builder<'_, 'tcx>,
|
||||
destination: &Place<'tcx>,
|
||||
destination: Place<'tcx>,
|
||||
block: BasicBlock,
|
||||
) -> BlockAnd<()> {
|
||||
builder.into_expr(destination, block, self)
|
||||
|
@ -10,16 +10,16 @@
|
||||
use crate::build::{BlockAnd, BlockAndExtension, Builder};
|
||||
use crate::build::{GuardFrame, GuardFrameLocal, LocalsForNode};
|
||||
use crate::hair::{self, *};
|
||||
use rustc_ast::ast::Name;
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
use rustc_hir::HirId;
|
||||
use rustc_index::bit_set::BitSet;
|
||||
use rustc_middle::middle::region;
|
||||
use rustc_middle::mir::*;
|
||||
use rustc_middle::ty::layout::VariantIdx;
|
||||
use rustc_middle::ty::{self, CanonicalUserTypeAnnotation, Ty};
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
use rustc_hir::HirId;
|
||||
use rustc_index::bit_set::BitSet;
|
||||
use rustc_span::Span;
|
||||
use smallvec::{smallvec, SmallVec};
|
||||
use rustc_ast::ast::Name;
|
||||
|
||||
// helper functions, broken out by category:
|
||||
mod simplify;
|
||||
@ -83,7 +83,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
/// * From each otherwise block to the next prebinding block.
|
||||
crate fn match_expr(
|
||||
&mut self,
|
||||
destination: &Place<'tcx>,
|
||||
destination: Place<'tcx>,
|
||||
span: Span,
|
||||
mut block: BasicBlock,
|
||||
scrutinee: ExprRef<'tcx>,
|
||||
@ -218,7 +218,7 @@ fn lower_match_tree<'pat>(
|
||||
/// `outer_source_info` is the SourceInfo for the whole match.
|
||||
fn lower_match_arms(
|
||||
&mut self,
|
||||
destination: &Place<'tcx>,
|
||||
destination: Place<'tcx>,
|
||||
scrutinee_place: Place<'tcx>,
|
||||
scrutinee_span: Span,
|
||||
arm_candidates: Vec<(&'_ Arm<'tcx>, Candidate<'_, 'tcx>)>,
|
||||
@ -364,7 +364,7 @@ pub(super) fn expr_into_pattern(
|
||||
PatKind::Binding { mode: BindingMode::ByValue, var, subpattern: None, .. } => {
|
||||
let place =
|
||||
self.storage_live_binding(block, var, irrefutable_pat.span, OutsideGuard, true);
|
||||
unpack!(block = self.into(&place, block, initializer));
|
||||
unpack!(block = self.into(place, block, initializer));
|
||||
|
||||
// Inject a fake read, see comments on `FakeReadCause::ForLet`.
|
||||
let source_info = self.source_info(irrefutable_pat.span);
|
||||
@ -399,7 +399,7 @@ pub(super) fn expr_into_pattern(
|
||||
} => {
|
||||
let place =
|
||||
self.storage_live_binding(block, var, irrefutable_pat.span, OutsideGuard, true);
|
||||
unpack!(block = self.into(&place, block, initializer));
|
||||
unpack!(block = self.into(place, block, initializer));
|
||||
|
||||
// Inject a fake read, see comments on `FakeReadCause::ForLet`.
|
||||
let pattern_source_info = self.source_info(irrefutable_pat.span);
|
||||
@ -1691,7 +1691,7 @@ fn bind_and_guard_matched_candidate<'pat>(
|
||||
let scrutinee_source_info = self.source_info(scrutinee_span);
|
||||
for &(place, temp) in fake_borrows {
|
||||
let borrow = Rvalue::Ref(re_erased, BorrowKind::Shallow, place);
|
||||
self.cfg.push_assign(block, scrutinee_source_info, &Place::from(temp), borrow);
|
||||
self.cfg.push_assign(block, scrutinee_source_info, Place::from(temp), borrow);
|
||||
}
|
||||
|
||||
// the block to branch to if the guard fails; if there is no
|
||||
@ -1858,7 +1858,7 @@ fn bind_matched_candidate_for_guard<'b>(
|
||||
match binding.binding_mode {
|
||||
BindingMode::ByValue => {
|
||||
let rvalue = Rvalue::Ref(re_erased, BorrowKind::Shared, binding.source);
|
||||
self.cfg.push_assign(block, source_info, &ref_for_guard, rvalue);
|
||||
self.cfg.push_assign(block, source_info, ref_for_guard, rvalue);
|
||||
}
|
||||
BindingMode::ByRef(borrow_kind) => {
|
||||
let value_for_arm = self.storage_live_binding(
|
||||
@ -1870,9 +1870,9 @@ fn bind_matched_candidate_for_guard<'b>(
|
||||
);
|
||||
|
||||
let rvalue = Rvalue::Ref(re_erased, borrow_kind, binding.source);
|
||||
self.cfg.push_assign(block, source_info, &value_for_arm, rvalue);
|
||||
self.cfg.push_assign(block, source_info, value_for_arm, rvalue);
|
||||
let rvalue = Rvalue::Ref(re_erased, BorrowKind::Shared, value_for_arm);
|
||||
self.cfg.push_assign(block, source_info, &ref_for_guard, rvalue);
|
||||
self.cfg.push_assign(block, source_info, ref_for_guard, rvalue);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1910,7 +1910,7 @@ fn bind_matched_candidate_for_arm_body<'b>(
|
||||
Rvalue::Ref(re_erased, borrow_kind, binding.source)
|
||||
}
|
||||
};
|
||||
self.cfg.push_assign(block, source_info, &local, rvalue);
|
||||
self.cfg.push_assign(block, source_info, local, rvalue);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -202,7 +202,7 @@ pub(super) fn perform_test(
|
||||
);
|
||||
let discr_ty = adt_def.repr.discr_type().to_ty(tcx);
|
||||
let discr = self.temp(discr_ty, test.span);
|
||||
self.cfg.push_assign(block, source_info, &discr, Rvalue::Discriminant(place));
|
||||
self.cfg.push_assign(block, source_info, discr, Rvalue::Discriminant(place));
|
||||
assert_eq!(values.len() + 1, targets.len());
|
||||
self.cfg.terminate(
|
||||
block,
|
||||
@ -303,7 +303,7 @@ pub(super) fn perform_test(
|
||||
let actual = self.temp(usize_ty, test.span);
|
||||
|
||||
// actual = len(place)
|
||||
self.cfg.push_assign(block, source_info, &actual, Rvalue::Len(place));
|
||||
self.cfg.push_assign(block, source_info, actual, Rvalue::Len(place));
|
||||
|
||||
// expected = <N>
|
||||
let expected = self.push_usize(block, source_info, len);
|
||||
@ -342,7 +342,7 @@ fn compare(
|
||||
let result = self.temp(bool_ty, source_info.span);
|
||||
|
||||
// result = op(left, right)
|
||||
self.cfg.push_assign(block, source_info, &result, Rvalue::BinaryOp(op, left, right));
|
||||
self.cfg.push_assign(block, source_info, result, Rvalue::BinaryOp(op, left, right));
|
||||
|
||||
// branch based on result
|
||||
self.cfg.terminate(
|
||||
@ -394,7 +394,7 @@ fn non_scalar_compare(
|
||||
self.cfg.push_assign(
|
||||
block,
|
||||
source_info,
|
||||
&temp,
|
||||
temp,
|
||||
Rvalue::Cast(CastKind::Pointer(PointerCast::Unsize), val, ty),
|
||||
);
|
||||
val = Operand::Move(temp);
|
||||
@ -404,7 +404,7 @@ fn non_scalar_compare(
|
||||
self.cfg.push_assign(
|
||||
block,
|
||||
source_info,
|
||||
&slice,
|
||||
slice,
|
||||
Rvalue::Cast(CastKind::Pointer(PointerCast::Unsize), expect, ty),
|
||||
);
|
||||
expect = Operand::Move(slice);
|
||||
|
@ -55,7 +55,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
self.cfg.push_assign_constant(
|
||||
block,
|
||||
source_info,
|
||||
&temp,
|
||||
temp,
|
||||
Constant {
|
||||
span: source_info.span,
|
||||
user_ty: None,
|
||||
|
@ -663,7 +663,7 @@ fn construct_const<'a, 'tcx>(
|
||||
let mut block = START_BLOCK;
|
||||
let ast_expr = &tcx.hir().body(body_id).value;
|
||||
let expr = builder.hir.mirror(ast_expr);
|
||||
unpack!(block = builder.into_expr(&Place::return_place(), block, expr));
|
||||
unpack!(block = builder.into_expr(Place::return_place(), block, expr));
|
||||
|
||||
let source_info = builder.source_info(span);
|
||||
builder.cfg.terminate(block, source_info, TerminatorKind::Return);
|
||||
@ -969,7 +969,7 @@ fn args_and_body(
|
||||
}
|
||||
|
||||
let body = self.hir.mirror(ast_body);
|
||||
self.into(&Place::return_place(), block, body)
|
||||
self.into(Place::return_place(), block, body)
|
||||
}
|
||||
|
||||
fn set_correct_source_scope_for_arg(
|
||||
|
@ -520,10 +520,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
if let Some(value) = value {
|
||||
debug!("stmt_expr Break val block_context.push(SubExpr)");
|
||||
self.block_context.push(BlockFrame::SubExpr);
|
||||
unpack!(block = self.into(&destination, block, value));
|
||||
unpack!(block = self.into(destination, block, value));
|
||||
self.block_context.pop();
|
||||
} else {
|
||||
self.cfg.push_assign_unit(block, source_info, &destination)
|
||||
self.cfg.push_assign_unit(block, source_info, destination)
|
||||
}
|
||||
} else {
|
||||
assert!(value.is_none(), "`return` and `break` should have a destination");
|
||||
|
@ -1,20 +1,20 @@
|
||||
use rustc_ast::token::{self, Token, TokenKind};
|
||||
use rustc_ast::util::comments;
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
use rustc_errors::{error_code, DiagnosticBuilder, FatalError};
|
||||
use rustc_lexer::unescape;
|
||||
use rustc_errors::{error_code, Applicability, DiagnosticBuilder, FatalError};
|
||||
use rustc_lexer::Base;
|
||||
use rustc_lexer::{unescape, LexRawStrError, UnvalidatedRawStr, ValidatedRawStr};
|
||||
use rustc_session::parse::ParseSess;
|
||||
use rustc_span::symbol::{sym, Symbol};
|
||||
use rustc_span::{BytePos, Pos, Span};
|
||||
|
||||
use log::debug;
|
||||
use std::char;
|
||||
use std::convert::TryInto;
|
||||
|
||||
mod tokentrees;
|
||||
mod unescape_error_reporting;
|
||||
mod unicode_chars;
|
||||
|
||||
use unescape_error_reporting::{emit_unescape_error, push_escaped_char};
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
@ -373,30 +373,22 @@ fn cook_lexer_literal(
|
||||
let id = self.symbol_from_to(content_start, content_end);
|
||||
(token::ByteStr, id)
|
||||
}
|
||||
rustc_lexer::LiteralKind::RawStr { n_hashes, started, terminated } => {
|
||||
if !started {
|
||||
self.report_non_started_raw_string(start);
|
||||
}
|
||||
if !terminated {
|
||||
self.report_unterminated_raw_string(start, n_hashes)
|
||||
}
|
||||
let n_hashes: u16 = self.restrict_n_hashes(start, n_hashes);
|
||||
rustc_lexer::LiteralKind::RawStr(unvalidated_raw_str) => {
|
||||
let valid_raw_str = self.validate_and_report_errors(start, unvalidated_raw_str);
|
||||
let n_hashes = valid_raw_str.num_hashes();
|
||||
let n = u32::from(n_hashes);
|
||||
|
||||
let content_start = start + BytePos(2 + n);
|
||||
let content_end = suffix_start - BytePos(1 + n);
|
||||
self.validate_raw_str_escape(content_start, content_end);
|
||||
let id = self.symbol_from_to(content_start, content_end);
|
||||
(token::StrRaw(n_hashes), id)
|
||||
}
|
||||
rustc_lexer::LiteralKind::RawByteStr { n_hashes, started, terminated } => {
|
||||
if !started {
|
||||
self.report_non_started_raw_string(start);
|
||||
}
|
||||
if !terminated {
|
||||
self.report_unterminated_raw_string(start, n_hashes)
|
||||
}
|
||||
let n_hashes: u16 = self.restrict_n_hashes(start, n_hashes);
|
||||
rustc_lexer::LiteralKind::RawByteStr(unvalidated_raw_str) => {
|
||||
let validated_raw_str = self.validate_and_report_errors(start, unvalidated_raw_str);
|
||||
let n_hashes = validated_raw_str.num_hashes();
|
||||
let n = u32::from(n_hashes);
|
||||
|
||||
let content_start = start + BytePos(3 + n);
|
||||
let content_end = suffix_start - BytePos(1 + n);
|
||||
self.validate_raw_byte_str_escape(content_start, content_end);
|
||||
@ -482,6 +474,26 @@ fn forbid_bare_cr(&self, start: BytePos, s: &str, errmsg: &str) {
|
||||
}
|
||||
}
|
||||
|
||||
fn validate_and_report_errors(
|
||||
&self,
|
||||
start: BytePos,
|
||||
unvalidated_raw_str: UnvalidatedRawStr,
|
||||
) -> ValidatedRawStr {
|
||||
match unvalidated_raw_str.validate() {
|
||||
Err(LexRawStrError::InvalidStarter) => self.report_non_started_raw_string(start),
|
||||
Err(LexRawStrError::NoTerminator { expected, found, possible_terminator_offset }) => {
|
||||
self.report_unterminated_raw_string(
|
||||
start,
|
||||
expected,
|
||||
possible_terminator_offset,
|
||||
found,
|
||||
)
|
||||
}
|
||||
Err(LexRawStrError::TooManyDelimiters) => self.report_too_many_hashes(start),
|
||||
Ok(valid) => valid,
|
||||
}
|
||||
}
|
||||
|
||||
fn report_non_started_raw_string(&self, start: BytePos) -> ! {
|
||||
let bad_char = self.str_from(start).chars().last().unwrap();
|
||||
self.struct_fatal_span_char(
|
||||
@ -495,38 +507,51 @@ fn report_non_started_raw_string(&self, start: BytePos) -> ! {
|
||||
FatalError.raise()
|
||||
}
|
||||
|
||||
fn report_unterminated_raw_string(&self, start: BytePos, n_hashes: usize) -> ! {
|
||||
fn report_unterminated_raw_string(
|
||||
&self,
|
||||
start: BytePos,
|
||||
n_hashes: usize,
|
||||
possible_offset: Option<usize>,
|
||||
found_terminators: usize,
|
||||
) -> ! {
|
||||
let mut err = self.sess.span_diagnostic.struct_span_fatal_with_code(
|
||||
self.mk_sp(start, start),
|
||||
"unterminated raw string",
|
||||
error_code!(E0748),
|
||||
);
|
||||
|
||||
err.span_label(self.mk_sp(start, start), "unterminated raw string");
|
||||
|
||||
if n_hashes > 0 {
|
||||
err.note(&format!(
|
||||
"this raw string should be terminated with `\"{}`",
|
||||
"#".repeat(n_hashes as usize)
|
||||
"#".repeat(n_hashes)
|
||||
));
|
||||
}
|
||||
|
||||
if let Some(possible_offset) = possible_offset {
|
||||
let lo = start + BytePos(possible_offset as u32);
|
||||
let hi = lo + BytePos(found_terminators as u32);
|
||||
let span = self.mk_sp(lo, hi);
|
||||
err.span_suggestion(
|
||||
span,
|
||||
"consider terminating the string here",
|
||||
"#".repeat(n_hashes),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
|
||||
err.emit();
|
||||
FatalError.raise()
|
||||
}
|
||||
|
||||
fn restrict_n_hashes(&self, start: BytePos, n_hashes: usize) -> u16 {
|
||||
match n_hashes.try_into() {
|
||||
Ok(n_hashes) => n_hashes,
|
||||
Err(_) => {
|
||||
self.fatal_span_(
|
||||
start,
|
||||
self.pos,
|
||||
"too many `#` symbols: raw strings may be \
|
||||
delimited by up to 65535 `#` symbols",
|
||||
)
|
||||
.raise();
|
||||
}
|
||||
}
|
||||
fn report_too_many_hashes(&self, start: BytePos) -> ! {
|
||||
self.fatal_span_(
|
||||
start,
|
||||
self.pos,
|
||||
"too many `#` symbols: raw strings may be delimited by up to 65535 `#` symbols",
|
||||
)
|
||||
.raise();
|
||||
}
|
||||
|
||||
fn validate_char_escape(&self, content_start: BytePos, content_end: BytePos) {
|
||||
|
@ -4,6 +4,7 @@
|
||||
#![feature(crate_visibility_modifier)]
|
||||
#![feature(bindings_after_at)]
|
||||
#![feature(try_blocks)]
|
||||
#![feature(or_patterns)]
|
||||
|
||||
use rustc_ast::ast;
|
||||
use rustc_ast::token::{self, Nonterminal};
|
||||
|
@ -6,7 +6,7 @@
|
||||
};
|
||||
use rustc_ast::ast::{AttrVec, ItemKind, Mutability, Pat, PatKind, PathSegment, QSelf, Ty, TyKind};
|
||||
use rustc_ast::ptr::P;
|
||||
use rustc_ast::token::{self, TokenKind};
|
||||
use rustc_ast::token::{self, Lit, LitKind, TokenKind};
|
||||
use rustc_ast::util::parser::AssocOp;
|
||||
use rustc_ast_pretty::pprust;
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
@ -255,6 +255,10 @@ fn tokens_to_string(tokens: &[TokenType]) -> String {
|
||||
}
|
||||
}
|
||||
|
||||
if self.check_too_many_raw_str_terminators(&mut err) {
|
||||
return Err(err);
|
||||
}
|
||||
|
||||
let sm = self.sess.source_map();
|
||||
if self.prev_token.span == DUMMY_SP {
|
||||
// Account for macro context where the previous span might not be
|
||||
@ -282,6 +286,29 @@ fn tokens_to_string(tokens: &[TokenType]) -> String {
|
||||
Err(err)
|
||||
}
|
||||
|
||||
fn check_too_many_raw_str_terminators(&mut self, err: &mut DiagnosticBuilder<'_>) -> bool {
|
||||
match (&self.prev_token.kind, &self.token.kind) {
|
||||
(
|
||||
TokenKind::Literal(Lit {
|
||||
kind: LitKind::StrRaw(n_hashes) | LitKind::ByteStrRaw(n_hashes),
|
||||
..
|
||||
}),
|
||||
TokenKind::Pound,
|
||||
) => {
|
||||
err.set_primary_message("too many `#` when terminating raw string");
|
||||
err.span_suggestion(
|
||||
self.token.span,
|
||||
"remove the extra `#`",
|
||||
String::new(),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
err.note(&format!("the raw string started with {} `#`s", n_hashes));
|
||||
true
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn maybe_annotate_with_ascription(
|
||||
&mut self,
|
||||
err: &mut DiagnosticBuilder<'_>,
|
||||
@ -491,7 +518,7 @@ fn attempt_chained_comparison_suggestion(
|
||||
.unwrap_or_else(|_| pprust::expr_to_string(&e))
|
||||
};
|
||||
err.span_suggestion_verbose(
|
||||
inner_op.span.shrink_to_hi(),
|
||||
inner_op.span.shrink_to_hi(),
|
||||
"split the comparison into two",
|
||||
format!(" && {}", expr_to_str(&r1)),
|
||||
Applicability::MaybeIncorrect,
|
||||
@ -1086,7 +1113,7 @@ pub(super) fn could_ascription_be_path(&self, node: &ast::ExprKind) -> bool {
|
||||
self.look_ahead(2, |t| t.is_ident())
|
||||
|| 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>`
|
||||
self.look_ahead(2, |t| t == &token::Lt)) // `foo:bar::<baz>`
|
||||
}
|
||||
|
||||
pub(super) fn recover_seq_parse_error(
|
||||
|
@ -835,6 +835,8 @@ fn parse_symbol_mangling_version(
|
||||
"the directory the MIR is dumped into"),
|
||||
dump_mir_graphviz: bool = (false, parse_bool, [UNTRACKED],
|
||||
"in addition to `.mir` files, create graphviz `.dot` files"),
|
||||
dump_mir_dataflow: bool = (false, parse_bool, [UNTRACKED],
|
||||
"in addition to `.mir` files, create graphviz `.dot` files with dataflow results"),
|
||||
dump_mir_exclude_pass_number: bool = (false, parse_bool, [UNTRACKED],
|
||||
"if set, exclude the pass number when dumping MIR (used in tests)"),
|
||||
mir_emit_retag: bool = (false, parse_bool, [TRACKED],
|
||||
|
@ -546,6 +546,8 @@ pub struct FnAbi<'a, Ty> {
|
||||
pub fixed_count: usize,
|
||||
|
||||
pub conv: Conv,
|
||||
|
||||
pub can_unwind: bool,
|
||||
}
|
||||
|
||||
impl<'a, Ty> FnAbi<'a, Ty> {
|
||||
|
@ -1,4 +0,0 @@
|
||||
static s: &'static str =
|
||||
r#"
|
||||
"## //~ ERROR expected one of `.`, `;`, `?`, or an operator, found `#`
|
||||
;
|
@ -1,8 +0,0 @@
|
||||
error: expected one of `.`, `;`, `?`, or an operator, found `#`
|
||||
--> $DIR/raw-str-unbalanced.rs:3:9
|
||||
|
|
||||
LL | "##
|
||||
| ^ expected one of `.`, `;`, `?`, or an operator
|
||||
|
||||
error: aborting due to previous error
|
||||
|
@ -2,7 +2,9 @@ error[E0748]: unterminated raw string
|
||||
--> $DIR/raw-byte-string-eof.rs:2:5
|
||||
|
|
||||
LL | br##"a"#;
|
||||
| ^ unterminated raw string
|
||||
| ^ - help: consider terminating the string here: `##`
|
||||
| |
|
||||
| unterminated raw string
|
||||
|
|
||||
= note: this raw string should be terminated with `"##`
|
||||
|
14
src/test/ui/parser/raw/raw-str-in-macro-call.rs
Normal file
14
src/test/ui/parser/raw/raw-str-in-macro-call.rs
Normal file
@ -0,0 +1,14 @@
|
||||
// check-pass
|
||||
|
||||
macro_rules! m1 {
|
||||
($tt:tt #) => ()
|
||||
}
|
||||
|
||||
macro_rules! m2 {
|
||||
($tt:tt) => ()
|
||||
}
|
||||
|
||||
fn main() {
|
||||
m1!(r#"abc"##);
|
||||
m2!(r#"abc"#);
|
||||
}
|
4
src/test/ui/parser/raw/raw-str-unbalanced.rs
Normal file
4
src/test/ui/parser/raw/raw-str-unbalanced.rs
Normal file
@ -0,0 +1,4 @@
|
||||
static s: &'static str =
|
||||
r#"
|
||||
"## //~ too many `#` when terminating raw string
|
||||
;
|
10
src/test/ui/parser/raw/raw-str-unbalanced.stderr
Normal file
10
src/test/ui/parser/raw/raw-str-unbalanced.stderr
Normal file
@ -0,0 +1,10 @@
|
||||
error: too many `#` when terminating raw string
|
||||
--> $DIR/raw-str-unbalanced.rs:3:9
|
||||
|
|
||||
LL | "##
|
||||
| ^ help: remove the extra `#`
|
||||
|
|
||||
= note: the raw string started with 1 `#`s
|
||||
|
||||
error: aborting due to previous error
|
||||
|
4
src/test/ui/parser/raw/raw-string-2.rs
Normal file
4
src/test/ui/parser/raw/raw-string-2.rs
Normal file
@ -0,0 +1,4 @@
|
||||
fn main() {
|
||||
let x = r###"here's a long string"# "# "##;
|
||||
//~^ ERROR unterminated raw string
|
||||
}
|
11
src/test/ui/parser/raw/raw-string-2.stderr
Normal file
11
src/test/ui/parser/raw/raw-string-2.stderr
Normal file
@ -0,0 +1,11 @@
|
||||
error[E0748]: unterminated raw string
|
||||
--> $DIR/raw-string-2.rs:2:13
|
||||
|
|
||||
LL | let x = r###"here's a long string"# "# "##;
|
||||
| ^ unterminated raw string -- help: consider terminating the string here: `###`
|
||||
|
|
||||
= note: this raw string should be terminated with `"###`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0748`.
|
@ -1,8 +1,10 @@
|
||||
error[E0748]: unterminated raw string
|
||||
--> $DIR/raw_string.rs:2:13
|
||||
--> $DIR/raw-string.rs:2:13
|
||||
|
|
||||
LL | let x = r##"lol"#;
|
||||
| ^ unterminated raw string
|
||||
| ^ - help: consider terminating the string here: `##`
|
||||
| |
|
||||
| unterminated raw string
|
||||
|
|
||||
= note: this raw string should be terminated with `"##`
|
||||
|
Loading…
Reference in New Issue
Block a user