提交 d4ecf31e 编写于 作者: B bors

Auto merge of #73367 - RalfJung:rollup-4ewvk9b, r=RalfJung

Rollup of 10 pull requests

Successful merges:

 - #71824 (Check for live drops in constants after drop elaboration)
 - #72389 (Explain move errors that occur due to method calls involving `self`)
 - #72556 (Fix trait alias inherent impl resolution)
 - #72584 (Stabilize vec::Drain::as_slice)
 - #72598 (Display information about captured variable in `FnMut` error)
 - #73336 (Group `Pattern::strip_*` method together)
 - #73341 (_match.rs: fix module doc comment)
 - #73342 (Fix iterator copied() documentation example code)
 - #73351 (Update E0446.md)
 - #73353 (structural_match: non-structural-match ty closures)

Failed merges:

r? @ghost
......@@ -2779,19 +2779,25 @@ impl<'a, T> Drain<'a, T> {
/// # Examples
///
/// ```
/// # #![feature(vec_drain_as_slice)]
/// let mut vec = vec!['a', 'b', 'c'];
/// let mut drain = vec.drain(..);
/// assert_eq!(drain.as_slice(), &['a', 'b', 'c']);
/// let _ = drain.next().unwrap();
/// assert_eq!(drain.as_slice(), &['b', 'c']);
/// ```
#[unstable(feature = "vec_drain_as_slice", reason = "recently added", issue = "58957")]
#[stable(feature = "vec_drain_as_slice", since = "1.46.0")]
pub fn as_slice(&self) -> &[T] {
self.iter.as_slice()
}
}
#[stable(feature = "vec_drain_as_slice", since = "1.46.0")]
impl<'a, T> AsRef<[T]> for Drain<'a, T> {
fn as_ref(&self) -> &[T] {
self.as_slice()
}
}
#[stable(feature = "drain", since = "1.6.0")]
unsafe impl<T: Sync> Sync for Drain<'_, T> {}
#[stable(feature = "drain", since = "1.6.0")]
......
......@@ -56,6 +56,7 @@ pub const fn from_generator<T>(gen: T) -> impl Future<Output = T::Return>
where
T: Generator<ResumeTy, Yield = ()>,
{
#[rustc_diagnostic_item = "gen_future"]
struct GenFuture<T: Generator<ResumeTy, Yield = ()>>(T);
// We rely on the fact that async/await futures are immovable in order to create
......
......@@ -2717,12 +2717,12 @@ fn extend<'a, A, B>(
/// ```
/// let a = [1, 2, 3];
///
/// let v_cloned: Vec<_> = a.iter().copied().collect();
/// let v_copied: Vec<_> = a.iter().copied().collect();
///
/// // copied is the same as .map(|&x| x)
/// let v_map: Vec<_> = a.iter().map(|&x| x).collect();
///
/// assert_eq!(v_cloned, vec![1, 2, 3]);
/// assert_eq!(v_copied, vec![1, 2, 3]);
/// assert_eq!(v_map, vec![1, 2, 3]);
/// ```
#[stable(feature = "iter_copied", since = "1.36.0")]
......
......@@ -69,7 +69,7 @@
/// |--------------------------|-------------------------------------------|
/// | `&str` | is substring |
/// | `char` | is contained in string |
/// | `&[char] | any char in slice is contained in string |
/// | `&[char]` | any char in slice is contained in string |
/// | `F: FnMut(char) -> bool` | `F` returns `true` for a char in string |
/// | `&&str` | is substring |
/// | `&String` | is substring |
......@@ -117,6 +117,15 @@ fn is_prefix_of(self, haystack: &'a str) -> bool {
matches!(self.into_searcher(haystack).next(), SearchStep::Match(0, _))
}
/// Checks whether the pattern matches at the back of the haystack
#[inline]
fn is_suffix_of(self, haystack: &'a str) -> bool
where
Self::Searcher: ReverseSearcher<'a>,
{
matches!(self.into_searcher(haystack).next_back(), SearchStep::Match(_, j) if haystack.len() == j)
}
/// Removes the pattern from the front of haystack, if it matches.
#[inline]
fn strip_prefix_of(self, haystack: &'a str) -> Option<&'a str> {
......@@ -133,15 +142,6 @@ fn strip_prefix_of(self, haystack: &'a str) -> Option<&'a str> {
}
}
/// Checks whether the pattern matches at the back of the haystack
#[inline]
fn is_suffix_of(self, haystack: &'a str) -> bool
where
Self::Searcher: ReverseSearcher<'a>,
{
matches!(self.into_searcher(haystack).next_back(), SearchStep::Match(_, j) if haystack.len() == j)
}
/// Removes the pattern from the back of haystack, if it matches.
#[inline]
fn strip_suffix_of(self, haystack: &'a str) -> Option<&'a str>
......
......@@ -9,7 +9,7 @@
use rustc_errors::struct_span_err;
use rustc_hir as hir;
use rustc_hir::def::Res;
use rustc_span::source_map::{respan, DesugaringKind, Span, Spanned};
use rustc_span::source_map::{respan, DesugaringKind, ForLoopLoc, Span, Spanned};
use rustc_span::symbol::{sym, Ident, Symbol};
use rustc_target::asm;
use std::collections::hash_map::Entry;
......@@ -25,6 +25,7 @@ pub(super) fn lower_expr(&mut self, e: &Expr) -> &'hir hir::Expr<'hir> {
}
pub(super) fn lower_expr_mut(&mut self, e: &Expr) -> hir::Expr<'hir> {
let mut span = e.span;
ensure_sufficient_stack(|| {
let kind = match e.kind {
ExprKind::Box(ref inner) => hir::ExprKind::Box(self.lower_expr(inner)),
......@@ -53,6 +54,7 @@ pub(super) fn lower_expr_mut(&mut self, e: &Expr) -> hir::Expr<'hir> {
hir::ExprKind::MethodCall(hir_seg, seg.ident.span, args, span)
}
ExprKind::Binary(binop, ref lhs, ref rhs) => {
span = self.mark_span_with_reason(DesugaringKind::Operator, e.span, None);
let binop = self.lower_binop(binop);
let lhs = self.lower_expr(lhs);
let rhs = self.lower_expr(rhs);
......@@ -222,7 +224,7 @@ pub(super) fn lower_expr_mut(&mut self, e: &Expr) -> hir::Expr<'hir> {
hir::Expr {
hir_id: self.lower_node_id(e.id),
kind,
span: e.span,
span,
attrs: e.attrs.iter().map(|a| self.lower_attr(a)).collect::<Vec<_>>().into(),
}
})
......@@ -237,6 +239,7 @@ fn lower_unop(&mut self, u: UnOp) -> hir::UnOp {
}
fn lower_binop(&mut self, b: BinOp) -> hir::BinOp {
let span = self.mark_span_with_reason(DesugaringKind::Operator, b.span, None);
Spanned {
node: match b.node {
BinOpKind::Add => hir::BinOpKind::Add,
......@@ -258,7 +261,7 @@ fn lower_binop(&mut self, b: BinOp) -> hir::BinOp {
BinOpKind::Ge => hir::BinOpKind::Ge,
BinOpKind::Gt => hir::BinOpKind::Gt,
},
span: b.span,
span,
}
}
......@@ -1360,9 +1363,14 @@ fn lower_expr_for(
body: &Block,
opt_label: Option<Label>,
) -> hir::Expr<'hir> {
let orig_head_span = head.span;
// expand <head>
let mut head = self.lower_expr_mut(head);
let desugared_span = self.mark_span_with_reason(DesugaringKind::ForLoop, head.span, None);
let desugared_span = self.mark_span_with_reason(
DesugaringKind::ForLoop(ForLoopLoc::Head),
orig_head_span,
None,
);
head.span = desugared_span;
let iter = Ident::with_dummy_span(sym::iter);
......@@ -1457,10 +1465,16 @@ fn lower_expr_for(
// `mut iter => { ... }`
let iter_arm = self.arm(iter_pat, loop_expr);
let into_iter_span = self.mark_span_with_reason(
DesugaringKind::ForLoop(ForLoopLoc::IntoIter),
orig_head_span,
None,
);
// `match ::std::iter::IntoIterator::into_iter(<head>) { ... }`
let into_iter_expr = {
let into_iter_path = &[sym::iter, sym::IntoIterator, sym::into_iter];
self.expr_call_std_path(desugared_span, into_iter_path, arena_vec![self; head])
self.expr_call_std_path(into_iter_span, into_iter_path, arena_vec![self; head])
};
let match_expr = self.arena.alloc(self.expr_match(
......
......@@ -4,10 +4,10 @@ Erroneous code example:
```compile_fail,E0446
#![deny(private_in_public)]
struct Bar(u32);
mod Foo {
struct Bar(u32);
mod foo {
use crate::Bar;
pub fn bar() -> Bar { // error: private type in public interface
Bar(0)
}
......@@ -16,15 +16,31 @@ mod Foo {
fn main() {}
```
To solve this error, please ensure that the type is also public. The type
can be made inaccessible if necessary by placing it into a private inner
module, but it still has to be marked with `pub`.
There are two ways to solve this error. The first is to make the public type
signature only public to a module that also has access to the private type.
This is done by using pub(crate) or pub(in crate::my_mod::etc)
Example:
```
mod Foo {
pub struct Bar(u32); // we set the Bar type public
struct Bar(u32);
mod foo {
use crate::Bar;
pub(crate) fn bar() -> Bar { // only public to crate root
Bar(0)
}
}
fn main() {}
```
The other way to solve this error is to make the private type public.
Example:
```
pub struct Bar(u32); // we set the Bar type public
mod foo {
use crate::Bar;
pub fn bar() -> Bar { // ok!
Bar(0)
}
......
A type with a `Drop` implementation was destructured when trying to initialize
a static item.
A value with a custom `Drop` implementation may be dropped during const-eval.
Erroneous code example:
......@@ -16,13 +15,14 @@ struct Foo {
field1: DropType,
}
static FOO: Foo = Foo { ..Foo { field1: DropType::A } }; // error!
static FOO: Foo = Foo { field1: (DropType::A, DropType::A).1 }; // error!
```
The problem here is that if the given type or one of its fields implements the
`Drop` trait, this `Drop` implementation cannot be called during the static
type initialization which might cause a memory leak. To prevent this issue,
you need to instantiate all the static type's fields by hand.
`Drop` trait, this `Drop` implementation cannot be called within a const
context since it may run arbitrary, non-const-checked code. To prevent this
issue, ensure all values with custom a custom `Drop` implementation escape the
initializer.
```
enum DropType {
......
......@@ -577,6 +577,9 @@ pub fn set(&self, features: &mut Features, span: Span) {
/// Allows `extern "avr-interrupt" fn()` and `extern "avr-non-blocking-interrupt" fn()`.
(active, abi_avr_interrupt, "1.45.0", Some(69664), None),
/// Be more precise when looking for live drops in a const context.
(active, const_precise_live_drops, "1.46.0", Some(73255), None),
// -------------------------------------------------------------------------
// feature-group-end: actual feature gates
// -------------------------------------------------------------------------
......
......@@ -455,7 +455,7 @@ pub fn need_type_info_err(
let msg = if let Some(simple_ident) = pattern.simple_ident() {
match pattern.span.desugaring_kind() {
None => format!("consider giving `{}` {}", simple_ident, suffix),
Some(DesugaringKind::ForLoop) => {
Some(DesugaringKind::ForLoop(_)) => {
"the element type for this iterator is not specified".to_string()
}
_ => format!("this needs {}", suffix),
......
......@@ -847,7 +847,11 @@ fn analysis(tcx: TyCtxt<'_>, cnum: CrateNum) -> Result<()> {
sess.time("MIR_effect_checking", || {
for def_id in tcx.body_owners() {
mir::transform::check_unsafety::check_unsafety(tcx, def_id)
mir::transform::check_unsafety::check_unsafety(tcx, def_id);
if tcx.hir().body_const_context(def_id).is_some() {
tcx.ensure().mir_drops_elaborated_and_const_checked(def_id);
}
}
});
......
......@@ -1315,13 +1315,13 @@ fn get_missing_lang_items(&self, tcx: TyCtxt<'tcx>) -> &'tcx [lang_items::LangIt
}
}
fn get_fn_param_names(&self, tcx: TyCtxt<'tcx>, id: DefIndex) -> &'tcx [Symbol] {
fn get_fn_param_names(&self, tcx: TyCtxt<'tcx>, id: DefIndex) -> &'tcx [Ident] {
let param_names = match self.kind(id) {
EntryKind::Fn(data) | EntryKind::ForeignFn(data) => data.decode(self).param_names,
EntryKind::AssocFn(data) => data.decode(self).fn_data.param_names,
_ => Lazy::empty(),
};
tcx.arena.alloc_from_iter(param_names.decode(self))
tcx.arena.alloc_from_iter(param_names.decode((self, tcx)))
}
fn exported_symbols(
......
......@@ -30,7 +30,7 @@
use rustc_serialize::{opaque, Encodable, Encoder, SpecializedEncoder};
use rustc_session::config::CrateType;
use rustc_span::source_map::Spanned;
use rustc_span::symbol::{kw, sym, Ident, Symbol};
use rustc_span::symbol::{sym, Ident, Symbol};
use rustc_span::{self, ExternalSource, FileName, SourceFile, Span};
use rustc_target::abi::VariantIdx;
use std::hash::Hash;
......@@ -994,18 +994,12 @@ fn encode_info_for_impl_item(&mut self, def_id: DefId) {
}
}
fn encode_fn_param_names_for_body(&mut self, body_id: hir::BodyId) -> Lazy<[Symbol]> {
self.tcx.dep_graph.with_ignore(|| {
let body = self.tcx.hir().body(body_id);
self.lazy(body.params.iter().map(|arg| match arg.pat.kind {
hir::PatKind::Binding(_, _, ident, _) => ident.name,
_ => kw::Invalid,
}))
})
fn encode_fn_param_names_for_body(&mut self, body_id: hir::BodyId) -> Lazy<[Ident]> {
self.tcx.dep_graph.with_ignore(|| self.lazy(self.tcx.hir().body_param_names(body_id)))
}
fn encode_fn_param_names(&mut self, param_names: &[Ident]) -> Lazy<[Symbol]> {
self.lazy(param_names.iter().map(|ident| ident.name))
fn encode_fn_param_names(&mut self, param_names: &[Ident]) -> Lazy<[Ident]> {
self.lazy(param_names.iter())
}
fn encode_optimized_mir(&mut self, def_id: LocalDefId) {
......
......@@ -19,7 +19,7 @@
use rustc_session::config::SymbolManglingVersion;
use rustc_session::CrateDisambiguator;
use rustc_span::edition::Edition;
use rustc_span::symbol::Symbol;
use rustc_span::symbol::{Ident, Symbol};
use rustc_span::{self, Span};
use rustc_target::spec::{PanicStrategy, TargetTriple};
......@@ -326,7 +326,7 @@ struct ModData {
struct FnData {
asyncness: hir::IsAsync,
constness: hir::Constness,
param_names: Lazy<[Symbol]>,
param_names: Lazy<[Ident]>,
}
#[derive(RustcEncodable, RustcDecodable)]
......
......@@ -14,7 +14,7 @@
use rustc_index::vec::IndexVec;
use rustc_span::hygiene::MacroKind;
use rustc_span::source_map::Spanned;
use rustc_span::symbol::{kw, Symbol};
use rustc_span::symbol::{kw, Ident, Symbol};
use rustc_span::Span;
use rustc_target::spec::abi::Abi;
......@@ -374,6 +374,13 @@ pub fn body_owned_by(&self, id: HirId) -> BodyId {
})
}
pub fn body_param_names(&self, id: BodyId) -> impl Iterator<Item = Ident> + 'hir {
self.body(id).params.iter().map(|arg| match arg.pat.kind {
PatKind::Binding(_, _, ident, _) => ident,
_ => Ident::new(kw::Invalid, rustc_span::DUMMY_SP),
})
}
/// Returns the `BodyOwnerKind` of this `LocalDefId`.
///
/// Panics if `LocalDefId` does not have an associated body.
......
......@@ -12,10 +12,7 @@
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_hir::def_id::{LocalDefId, LOCAL_CRATE};
use rustc_hir::Body;
use rustc_hir::HirId;
use rustc_hir::ItemLocalId;
use rustc_hir::Node;
use rustc_hir::*;
use rustc_index::vec::IndexVec;
pub struct Owner<'tcx> {
......@@ -79,5 +76,20 @@ pub fn provide(providers: &mut Providers<'_>) {
};
providers.hir_owner = |tcx, id| tcx.index_hir(LOCAL_CRATE).map[id].signature;
providers.hir_owner_nodes = |tcx, id| tcx.index_hir(LOCAL_CRATE).map[id].with_bodies.as_deref();
providers.fn_arg_names = |tcx, id| {
let hir = tcx.hir();
let hir_id = hir.as_local_hir_id(id.expect_local());
if let Some(body_id) = hir.maybe_body_owned_by(hir_id) {
tcx.arena.alloc_from_iter(hir.body_param_names(body_id))
} else if let Node::TraitItem(&TraitItem {
kind: TraitItemKind::Fn(_, TraitFn::Required(idents)),
..
}) = hir.get(hir_id)
{
tcx.arena.alloc_slice(idents)
} else {
span_bug!(hir.span(hir_id), "fn_arg_names: unexpected item {:?}", id);
}
};
map::provide(providers);
}
......@@ -339,7 +339,9 @@ fn struct_lint_level_impl(
pub fn in_external_macro(sess: &Session, span: Span) -> bool {
let expn_data = span.ctxt().outer_expn_data();
match expn_data.kind {
ExpnKind::Root | ExpnKind::Desugaring(DesugaringKind::ForLoop) => false,
ExpnKind::Root
| ExpnKind::Desugaring(DesugaringKind::ForLoop(_))
| ExpnKind::Desugaring(DesugaringKind::Operator) => false,
ExpnKind::AstPass(_) | ExpnKind::Desugaring(_) => true, // well, it's "external"
ExpnKind::Macro(MacroKind::Bang, _) => {
// Dummy span for the `def_site` means it's an external macro.
......
......@@ -76,7 +76,8 @@ pub enum MirPhase {
Build = 0,
Const = 1,
Validated = 2,
Optimized = 3,
DropElab = 3,
Optimized = 4,
}
impl MirPhase {
......
......@@ -183,7 +183,7 @@ pub struct ClosureOutlivesRequirement<'tcx> {
#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash)]
#[derive(RustcEncodable, RustcDecodable, HashStable)]
pub enum ConstraintCategory {
Return,
Return(ReturnConstraint),
Yield,
UseAsConst,
UseAsStatic,
......@@ -199,6 +199,7 @@ pub enum ConstraintCategory {
SizedBound,
Assignment,
OpaqueType,
ClosureUpvar(hir::HirId),
/// A "boring" constraint (caused by the given location) is one that
/// the user probably doesn't want to see described in diagnostics,
......@@ -216,6 +217,13 @@ pub enum ConstraintCategory {
Internal,
}
#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash)]
#[derive(RustcEncodable, RustcDecodable, HashStable)]
pub enum ReturnConstraint {
Normal,
ClosureUpvar(hir::HirId),
}
/// The subject of a `ClosureOutlivesRequirement` -- that is, the thing
/// that must outlive some region.
#[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable, HashStable)]
......
......@@ -190,6 +190,12 @@ fn describe_as_module(def_id: DefId, tcx: TyCtxt<'_>) -> String {
no_hash
}
query mir_drops_elaborated_and_const_checked(key: LocalDefId) -> Steal<mir::Body<'tcx>> {
storage(ArenaCacheSelector<'tcx>)
no_hash
desc { |tcx| "elaborating drops for `{}`", tcx.def_path_str(key.to_def_id()) }
}
query mir_validated(key: LocalDefId) ->
(
Steal<mir::Body<'tcx>>,
......@@ -700,7 +706,7 @@ fn describe_as_module(def_id: DefId, tcx: TyCtxt<'_>) -> String {
}
Other {
query fn_arg_names(def_id: DefId) -> &'tcx [Symbol] {
query fn_arg_names(def_id: DefId) -> &'tcx [rustc_span::symbol::Ident] {
desc { |tcx| "looking up function parameter names for `{}`", tcx.def_path_str(def_id) }
}
/// Gets the rendered value of the specified constant or associated constant.
......
......@@ -24,7 +24,8 @@
};
use super::{
explain_borrow::BorrowExplanation, IncludingDowncast, RegionName, RegionNameSource, UseSpans,
explain_borrow::BorrowExplanation, FnSelfUseKind, IncludingDowncast, RegionName,
RegionNameSource, UseSpans,
};
#[derive(Debug)]
......@@ -150,13 +151,70 @@ pub(in crate::borrow_check) fn report_use_of_moved_or_uninitialized(
format!("value moved{} here, in previous iteration of loop", move_msg),
);
} else {
err.span_label(move_span, format!("value moved{} here", move_msg));
move_spans.var_span_label(
&mut err,
format!("variable moved due to use{}", move_spans.describe()),
);
if let UseSpans::FnSelfUse { var_span, fn_call_span, fn_span, kind } =
move_spans
{
let place_name = self
.describe_place(moved_place.as_ref())
.map(|n| format!("`{}`", n))
.unwrap_or_else(|| "value".to_owned());
match kind {
FnSelfUseKind::FnOnceCall => {
err.span_label(
fn_call_span,
&format!("{} moved due to this call", place_name),
);
err.span_note(
var_span,
"this value implements `FnOnce`, which causes it to be moved when called",
);
}
FnSelfUseKind::Operator { self_arg } => {
err.span_label(
fn_call_span,
&format!("{} moved due to usage in operator", place_name),
);
if self.fn_self_span_reported.insert(fn_span) {
err.span_note(
self_arg.span,
"calling this operator moves the left-hand side",
);
}
}
FnSelfUseKind::Normal { self_arg, implicit_into_iter } => {
if implicit_into_iter {
err.span_label(
fn_call_span,
&format!(
"{} moved due to this implicit call to `.into_iter()`",
place_name
),
);
} else {
err.span_label(
fn_call_span,
&format!("{} moved due to this method call", place_name),
);
}
// Avoid pointing to the same function in multiple different
// error messages
if self.fn_self_span_reported.insert(self_arg.span) {
err.span_note(
self_arg.span,
&format!("this function consumes the receiver `self` by taking ownership of it, which moves {}", place_name)
);
}
}
}
} else {
err.span_label(move_span, format!("value moved{} here", move_msg));
move_spans.var_span_label(
&mut err,
format!("variable moved due to use{}", move_spans.describe()),
);
}
}
if Some(DesugaringKind::ForLoop) == move_span.desugaring_kind() {
if let Some(DesugaringKind::ForLoop(_)) = move_span.desugaring_kind() {
let sess = self.infcx.tcx.sess;
if let Ok(snippet) = sess.source_map().span_to_snippet(move_span) {
err.span_suggestion(
......@@ -766,7 +824,7 @@ pub(in crate::borrow_check) fn report_borrowed_value_does_not_live_long_enough(
category:
category
@
(ConstraintCategory::Return
(ConstraintCategory::Return(_)
| ConstraintCategory::CallArgument
| ConstraintCategory::OpaqueType),
from_closure: false,
......@@ -1089,7 +1147,7 @@ fn try_report_cannot_return_reference_to_local(
opt_place_desc: Option<&String>,
) -> Option<DiagnosticBuilder<'cx>> {
let return_kind = match category {
ConstraintCategory::Return => "return",
ConstraintCategory::Return(_) => "return",
ConstraintCategory::Yield => "yield",
_ => return None,
};
......@@ -1203,7 +1261,7 @@ fn report_escaping_closure_capture(
);
let msg = match category {
ConstraintCategory::Return | ConstraintCategory::OpaqueType => {
ConstraintCategory::Return(_) | ConstraintCategory::OpaqueType => {
format!("{} is returned here", kind)
}
ConstraintCategory::CallArgument => {
......
......@@ -509,7 +509,7 @@ fn later_use_kind(
// Used in a closure.
(LaterUseKind::ClosureCapture, var_span)
}
UseSpans::OtherUse(span) => {
UseSpans::OtherUse(span) | UseSpans::FnSelfUse { var_span: span, .. } => {
let block = &self.body.basic_blocks()[location.block];
let kind = if let Some(&Statement {
......
......@@ -11,7 +11,11 @@
};
use rustc_middle::ty::print::Print;
use rustc_middle::ty::{self, DefIdTree, Ty, TyCtxt};
use rustc_span::{symbol::sym, Span};
use rustc_span::{
hygiene::{DesugaringKind, ForLoopLoc},
symbol::sym,
Span,
};
use rustc_target::abi::VariantIdx;
use super::borrow_set::BorrowData;
......@@ -33,6 +37,7 @@
crate use outlives_suggestion::OutlivesSuggestionBuilder;
crate use region_errors::{ErrorConstraintInfo, RegionErrorKind, RegionErrors};
crate use region_name::{RegionName, RegionNameSource};
use rustc_span::symbol::Ident;
pub(super) struct IncludingDowncast(pub(super) bool);
......@@ -529,33 +534,58 @@ pub(super) fn get_region_name_for_ty(&self, ty: Ty<'tcx>, counter: usize) -> Str
}
}
// The span(s) associated to a use of a place.
/// The span(s) associated to a use of a place.
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub(super) enum UseSpans {
// The access is caused by capturing a variable for a closure.
/// The access is caused by capturing a variable for a closure.
ClosureUse {
// This is true if the captured variable was from a generator.
/// This is true if the captured variable was from a generator.
generator_kind: Option<GeneratorKind>,
// The span of the args of the closure, including the `move` keyword if
// it's present.
/// The span of the args of the closure, including the `move` keyword if
/// it's present.
args_span: Span,
// The span of the first use of the captured variable inside the closure.
/// The span of the first use of the captured variable inside the closure.
var_span: Span,
},
/// The access is caused by using a variable as the receiver of a method
/// that takes 'self'
FnSelfUse {
/// The span of the variable being moved
var_span: Span,
/// The span of the method call on the variable
fn_call_span: Span,
/// The definition span of the method being called
fn_span: Span,
kind: FnSelfUseKind,
},
// This access has a single span associated to it: common case.
OtherUse(Span),
}
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub(super) enum FnSelfUseKind {
/// A normal method call of the form `receiver.foo(a, b, c)`
Normal { self_arg: Ident, implicit_into_iter: bool },
/// A call to `FnOnce::call_once`, desugared from `my_closure(a, b, c)`
FnOnceCall,
/// A call to an operator trait, desuraged from operator syntax (e.g. `a << b`)
Operator { self_arg: Ident },
}
impl UseSpans {
pub(super) fn args_or_use(self) -> Span {
match self {
UseSpans::ClosureUse { args_span: span, .. } | UseSpans::OtherUse(span) => span,
UseSpans::ClosureUse { args_span: span, .. }
| UseSpans::FnSelfUse { var_span: span, .. }
| UseSpans::OtherUse(span) => span,
}
}
pub(super) fn var_or_use(self) -> Span {
match self {
UseSpans::ClosureUse { var_span: span, .. } | UseSpans::OtherUse(span) => span,
UseSpans::ClosureUse { var_span: span, .. }
| UseSpans::FnSelfUse { var_span: span, .. }
| UseSpans::OtherUse(span) => span,
}
}
......@@ -624,6 +654,7 @@ pub(super) fn or_else<F>(self, if_other: F) -> Self
{
match self {
closure @ UseSpans::ClosureUse { .. } => closure,
fn_self @ UseSpans::FnSelfUse { .. } => fn_self,
UseSpans::OtherUse(_) => if_other(),
}
}
......@@ -727,21 +758,100 @@ pub(super) fn move_spans(
debug!("move_spans: moved_place={:?} location={:?} stmt={:?}", moved_place, location, stmt);
if let StatementKind::Assign(box (_, Rvalue::Aggregate(ref kind, ref places))) = stmt.kind {
let def_id = match kind {
match kind {
box AggregateKind::Closure(def_id, _)
| box AggregateKind::Generator(def_id, _, _) => def_id,
_ => return OtherUse(stmt.source_info.span),
};
debug!("move_spans: def_id={:?} places={:?}", def_id, places);
if let Some((args_span, generator_kind, var_span)) =
self.closure_span(*def_id, moved_place, places)
{
return ClosureUse { generator_kind, args_span, var_span };
| box AggregateKind::Generator(def_id, _, _) => {
debug!("move_spans: def_id={:?} places={:?}", def_id, places);
if let Some((args_span, generator_kind, var_span)) =
self.closure_span(*def_id, moved_place, places)
{
return ClosureUse { generator_kind, args_span, var_span };
}
}
_ => {}
}
}
OtherUse(stmt.source_info.span)
let normal_ret = OtherUse(stmt.source_info.span);
// We are trying to find MIR of the form:
// ```
// _temp = _moved_val;
// ...
// FnSelfCall(_temp, ...)
// ```
//
// where `_moved_val` is the place we generated the move error for,
// `_temp` is some other local, and `FnSelfCall` is a function
// that has a `self` parameter.
let target_temp = match stmt.kind {
StatementKind::Assign(box (temp, _)) if temp.as_local().is_some() => {
temp.as_local().unwrap()
}
_ => return normal_ret,
};
debug!("move_spans: target_temp = {:?}", target_temp);
if let Some(Terminator { kind: TerminatorKind::Call { func, args, fn_span, .. }, .. }) =
&self.body[location.block].terminator
{
let mut method_did = None;
if let Operand::Constant(box Constant { literal: ty::Const { ty, .. }, .. }) = func {
if let ty::FnDef(def_id, _) = ty.kind {
debug!("move_spans: fn = {:?}", def_id);
if let Some(ty::AssocItem { fn_has_self_parameter, .. }) =
self.infcx.tcx.opt_associated_item(def_id)
{
if *fn_has_self_parameter {
method_did = Some(def_id);
}
}
}
}
let tcx = self.infcx.tcx;
let method_did = if let Some(did) = method_did { did } else { return normal_ret };
if let [Operand::Move(self_place), ..] = **args {
if self_place.as_local() == Some(target_temp) {
let is_fn_once = tcx.parent(method_did) == tcx.lang_items().fn_once_trait();
let fn_call_span = *fn_span;
let self_arg = tcx.fn_arg_names(method_did)[0];
let kind = if is_fn_once {
FnSelfUseKind::FnOnceCall
} else if fn_call_span.is_desugaring(DesugaringKind::Operator) {
FnSelfUseKind::Operator { self_arg }
} else {
debug!(
"move_spans: method_did={:?}, fn_call_span={:?}",
method_did, fn_call_span
);
let implicit_into_iter = matches!(
fn_call_span.desugaring_kind(),
Some(DesugaringKind::ForLoop(ForLoopLoc::IntoIter))
);
FnSelfUseKind::Normal { self_arg, implicit_into_iter }
};
return FnSelfUse {
var_span: stmt.source_info.span,
fn_call_span,
fn_span: self
.infcx
.tcx
.sess
.source_map()
.guess_head_span(self.infcx.tcx.def_span(method_did)),
kind,
};
}
}
}
return normal_ret;
}
/// Finds the span of arguments of a closure (within `maybe_closure_span`)
......
......@@ -408,7 +408,7 @@ fn report_cannot_move_from_borrowed_content(
format!("{}.as_ref()", snippet),
Applicability::MaybeIncorrect,
);
} else if span.is_desugaring(DesugaringKind::ForLoop)
} else if matches!(span.desugaring_kind(), Some(DesugaringKind::ForLoop(_)))
&& self.infcx.tcx.is_diagnostic_item(Symbol::intern("vec_type"), def_id)
{
// FIXME: suggest for anything that implements `IntoIterator`.
......
......@@ -365,7 +365,7 @@ pub(crate) fn report_mutability_error(
opt_assignment_rhs_span.and_then(|span| span.desugaring_kind());
match opt_desugaring_kind {
// on for loops, RHS points to the iterator part
Some(DesugaringKind::ForLoop) => Some((
Some(DesugaringKind::ForLoop(_)) => Some((
false,
opt_assignment_rhs_span.unwrap(),
format!(
......
......@@ -5,9 +5,9 @@
error_reporting::nice_region_error::NiceRegionError,
error_reporting::unexpected_hidden_region_diagnostic, NLLRegionVariableOrigin,
};
use rustc_middle::mir::ConstraintCategory;
use rustc_middle::mir::{ConstraintCategory, ReturnConstraint};
use rustc_middle::ty::{self, RegionVid, Ty};
use rustc_span::symbol::kw;
use rustc_span::symbol::{kw, sym};
use rustc_span::Span;
use crate::util::borrowck_errors;
......@@ -26,7 +26,7 @@ fn description(&self) -> &'static str {
// Must end with a space. Allows for empty names to be provided.
match self {
ConstraintCategory::Assignment => "assignment ",
ConstraintCategory::Return => "returning this value ",
ConstraintCategory::Return(_) => "returning this value ",
ConstraintCategory::Yield => "yielding this value ",
ConstraintCategory::UseAsConst => "using this value as a constant ",
ConstraintCategory::UseAsStatic => "using this value as a static ",
......@@ -37,6 +37,7 @@ fn description(&self) -> &'static str {
ConstraintCategory::SizedBound => "proving this value is `Sized` ",
ConstraintCategory::CopyBound => "copying this value ",
ConstraintCategory::OpaqueType => "opaque type ",
ConstraintCategory::ClosureUpvar(_) => "closure capture ",
ConstraintCategory::Boring
| ConstraintCategory::BoringNoLocation
| ConstraintCategory::Internal => "",
......@@ -306,8 +307,8 @@ pub(in crate::borrow_check) fn report_region_error(
};
let diag = match (category, fr_is_local, outlived_fr_is_local) {
(ConstraintCategory::Return, true, false) if self.is_closure_fn_mut(fr) => {
self.report_fnmut_error(&errci)
(ConstraintCategory::Return(kind), true, false) if self.is_closure_fn_mut(fr) => {
self.report_fnmut_error(&errci, kind)
}
(ConstraintCategory::Assignment, true, false)
| (ConstraintCategory::CallArgument, true, false) => {
......@@ -347,7 +348,11 @@ pub(in crate::borrow_check) fn report_region_error(
/// executing...
/// = note: ...therefore, returned references to captured variables will escape the closure
/// ```
fn report_fnmut_error(&self, errci: &ErrorConstraintInfo) -> DiagnosticBuilder<'tcx> {
fn report_fnmut_error(
&self,
errci: &ErrorConstraintInfo,
kind: ReturnConstraint,
) -> DiagnosticBuilder<'tcx> {
let ErrorConstraintInfo { outlived_fr, span, .. } = errci;
let mut diag = self
......@@ -356,19 +361,39 @@ fn report_fnmut_error(&self, errci: &ErrorConstraintInfo) -> DiagnosticBuilder<'
.sess
.struct_span_err(*span, "captured variable cannot escape `FnMut` closure body");
// We should check if the return type of this closure is in fact a closure - in that
// case, we can special case the error further.
let return_type_is_closure =
self.regioncx.universal_regions().unnormalized_output_ty.is_closure();
let message = if return_type_is_closure {
"returns a closure that contains a reference to a captured variable, which then \
escapes the closure body"
} else {
"returns a reference to a captured variable which escapes the closure body"
let mut output_ty = self.regioncx.universal_regions().unnormalized_output_ty;
if let ty::Opaque(def_id, _) = output_ty.kind {
output_ty = self.infcx.tcx.type_of(def_id)
};
debug!("report_fnmut_error: output_ty={:?}", output_ty);
let message = match output_ty.kind {
ty::Closure(_, _) => {
"returns a closure that contains a reference to a captured variable, which then \
escapes the closure body"
}
ty::Adt(def, _) if self.infcx.tcx.is_diagnostic_item(sym::gen_future, def.did) => {
"returns an `async` block that contains a reference to a captured variable, which then \
escapes the closure body"
}
_ => "returns a reference to a captured variable which escapes the closure body",
};
diag.span_label(*span, message);
if let ReturnConstraint::ClosureUpvar(upvar) = kind {
let def_id = match self.regioncx.universal_regions().defining_ty {
DefiningTy::Closure(def_id, _) => def_id,
ty @ _ => bug!("unexpected DefiningTy {:?}", ty),
};
let upvar_def_span = self.infcx.tcx.hir().span(upvar);
let upvar_span = self.infcx.tcx.upvars_mentioned(def_id).unwrap()[&upvar].span;
diag.span_label(upvar_def_span, "variable defined here");
diag.span_label(upvar_span, "variable captured here");
}
match self.give_region_a_name(*outlived_fr).unwrap().source {
RegionNameSource::NamedEarlyBoundRegion(fr_span)
| RegionNameSource::NamedFreeRegion(fr_span)
......@@ -506,7 +531,7 @@ fn report_general_error(&self, errci: &ErrorConstraintInfo) -> DiagnosticBuilder
outlived_fr_name.highlight_region_name(&mut diag);
match (category, outlived_fr_is_local, fr_is_local) {
(ConstraintCategory::Return, true, _) => {
(ConstraintCategory::Return(_), true, _) => {
diag.span_label(
*span,
format!(
......
......@@ -216,6 +216,7 @@ fn do_mir_borrowck<'a, 'tcx>(
&mut flow_inits,
&mdpe.move_data,
&borrow_set,
&upvars,
);
// Dump MIR results into a file, if that is enabled. This let us
......@@ -277,6 +278,7 @@ fn do_mir_borrowck<'a, 'tcx>(
move_data: &move_data,
location_table: &LocationTable::new(promoted_body),
movable_generator,
fn_self_span_reported: Default::default(),
locals_are_invalidated_at_exit,
access_place_error_reported: Default::default(),
reservation_error_reported: Default::default(),
......@@ -310,6 +312,7 @@ fn do_mir_borrowck<'a, 'tcx>(
location_table,
movable_generator,
locals_are_invalidated_at_exit,
fn_self_span_reported: Default::default(),
access_place_error_reported: Default::default(),
reservation_error_reported: Default::default(),
reservation_warnings: Default::default(),
......@@ -486,6 +489,10 @@ fn do_mir_borrowck<'a, 'tcx>(
// but it is currently inconvenient to track down the `BorrowIndex`
// at the time we detect and report a reservation error.
reservation_error_reported: FxHashSet<Place<'tcx>>,
/// This fields keeps track of the `Span`s that we have
/// used to report extra information for `FnSelfUse`, to avoid
/// unnecessarily verbose errors.
fn_self_span_reported: FxHashSet<Span>,
/// Migration warnings to be reported for #56254. We delay reporting these
/// so that we can suppress the warning if there's a corresponding error
/// for the activation of the borrow.
......@@ -2308,30 +2315,7 @@ fn is_mutable(
/// be `self` in the current MIR, because that is the only time we directly access the fields
/// of a closure type.
pub fn is_upvar_field_projection(&self, place_ref: PlaceRef<'tcx>) -> Option<Field> {
let mut place_projection = place_ref.projection;
let mut by_ref = false;
if let [proj_base @ .., ProjectionElem::Deref] = place_projection {
place_projection = proj_base;
by_ref = true;
}
match place_projection {
[base @ .., ProjectionElem::Field(field, _ty)] => {
let tcx = self.infcx.tcx;
let base_ty = Place::ty_from(place_ref.local, base, self.body(), tcx).ty;
if (base_ty.is_closure() || base_ty.is_generator())
&& (!by_ref || self.upvars[field.index()].by_ref)
{
Some(*field)
} else {
None
}
}
_ => None,
}
path_utils::is_upvar_field_projection(self.infcx.tcx, &self.upvars, place_ref, self.body())
}
}
......
......@@ -39,6 +39,7 @@
renumber,
type_check::{self, MirTypeckRegionConstraints, MirTypeckResults},
universal_regions::UniversalRegions,
Upvar,
};
crate type PoloniusOutput = Output<RustcFacts>;
......@@ -166,6 +167,7 @@ pub(in crate::borrow_check) fn compute_regions<'cx, 'tcx>(
flow_inits: &mut ResultsCursor<'cx, 'tcx, MaybeInitializedPlaces<'cx, 'tcx>>,
move_data: &MoveData<'tcx>,
borrow_set: &BorrowSet<'tcx>,
upvars: &[Upvar],
) -> NllOutput<'tcx> {
let mut all_facts = AllFacts::enabled(infcx.tcx).then_some(AllFacts::default());
......@@ -188,6 +190,7 @@ pub(in crate::borrow_check) fn compute_regions<'cx, 'tcx>(
flow_inits,
move_data,
elements,
upvars,
);
if let Some(all_facts) = &mut all_facts {
......
use crate::borrow_check::borrow_set::{BorrowData, BorrowSet, TwoPhaseActivation};
use crate::borrow_check::places_conflict;
use crate::borrow_check::AccessDepth;
use crate::borrow_check::Upvar;
use crate::dataflow::indexes::BorrowIndex;
use rustc_data_structures::graph::dominators::Dominators;
use rustc_middle::mir::BorrowKind;
use rustc_middle::mir::{BasicBlock, Body, Location, Place};
use rustc_middle::mir::{BasicBlock, Body, Field, Location, Place, PlaceRef, ProjectionElem};
use rustc_middle::ty::TyCtxt;
/// Returns `true` if the borrow represented by `kind` is
......@@ -135,3 +136,38 @@ pub(super) fn borrow_of_local_data(place: Place<'_>) -> bool {
// Any errors will be caught on the initial borrow
!place.is_indirect()
}
/// If `place` is a field projection, and the field is being projected from a closure type,
/// then returns the index of the field being projected. Note that this closure will always
/// be `self` in the current MIR, because that is the only time we directly access the fields
/// of a closure type.
pub(crate) fn is_upvar_field_projection(
tcx: TyCtxt<'tcx>,
upvars: &[Upvar],
place_ref: PlaceRef<'tcx>,
body: &Body<'tcx>,
) -> Option<Field> {
let mut place_projection = place_ref.projection;
let mut by_ref = false;
if let [proj_base @ .., ProjectionElem::Deref] = place_projection {
place_projection = proj_base;
by_ref = true;
}
match place_projection {
[base @ .., ProjectionElem::Field(field, _ty)] => {
let base_ty = Place::ty_from(place_ref.local, base, body, tcx).ty;
if (base_ty.is_closure() || base_ty.is_generator())
&& (!by_ref || upvars[field.index()].by_ref)
{
Some(*field)
} else {
None
}
}
_ => None,
}
}
......@@ -12,7 +12,7 @@
use rustc_infer::infer::{InferCtxt, NLLRegionVariableOrigin, RegionVariableOrigin};
use rustc_middle::mir::{
Body, ClosureOutlivesRequirement, ClosureOutlivesSubject, ClosureRegionRequirements,
ConstraintCategory, Local, Location,
ConstraintCategory, Local, Location, ReturnConstraint,
};
use rustc_middle::ty::{self, subst::SubstsRef, RegionVid, Ty, TyCtxt, TypeFoldable};
use rustc_span::Span;
......@@ -2017,7 +2017,7 @@ fn check_member_constraints(
| ConstraintCategory::BoringNoLocation
| ConstraintCategory::Internal => false,
ConstraintCategory::TypeAnnotation
| ConstraintCategory::Return
| ConstraintCategory::Return(_)
| ConstraintCategory::Yield => true,
_ => constraint_sup_scc != target_scc,
}
......@@ -2042,7 +2042,7 @@ fn check_member_constraints(
if let Some(i) = best_choice {
if let Some(next) = categorized_path.get(i + 1) {
if categorized_path[i].0 == ConstraintCategory::Return
if matches!(categorized_path[i].0, ConstraintCategory::Return(_))
&& next.0 == ConstraintCategory::OpaqueType
{
// The return expression is being influenced by the return type being
......@@ -2050,6 +2050,18 @@ fn check_member_constraints(
return *next;
}
}
if categorized_path[i].0 == ConstraintCategory::Return(ReturnConstraint::Normal) {
let field = categorized_path.iter().find_map(|p| {
if let ConstraintCategory::ClosureUpvar(f) = p.0 { Some(f) } else { None }
});
if let Some(field) = field {
categorized_path[i].0 =
ConstraintCategory::Return(ReturnConstraint::ClosureUpvar(field));
}
}
return categorized_path[i];
}
......
......@@ -55,6 +55,7 @@
location::LocationTable,
member_constraints::MemberConstraintSet,
nll::ToRegionVid,
path_utils,
region_infer::values::{
LivenessValues, PlaceholderIndex, PlaceholderIndices, RegionValueElements,
},
......@@ -62,6 +63,7 @@
renumber,
type_check::free_region_relations::{CreateResult, UniversalRegionRelations},
universal_regions::{DefiningTy, UniversalRegions},
Upvar,
};
macro_rules! span_mirbug {
......@@ -132,6 +134,7 @@ pub(crate) fn type_check<'mir, 'tcx>(
flow_inits: &mut ResultsCursor<'mir, 'tcx, MaybeInitializedPlaces<'mir, 'tcx>>,
move_data: &MoveData<'tcx>,
elements: &Rc<RegionValueElements>,
upvars: &[Upvar],
) -> MirTypeckResults<'tcx> {
let implicit_region_bound = infcx.tcx.mk_region(ty::ReVar(universal_regions.fr_fn_body));
let mut constraints = MirTypeckRegionConstraints {
......@@ -162,6 +165,7 @@ pub(crate) fn type_check<'mir, 'tcx>(
borrow_set,
all_facts,
constraints: &mut constraints,
upvars,
};
let opaque_type_values = type_check_internal(
......@@ -577,7 +581,7 @@ fn sanitize_promoted(&mut self, promoted_body: &'b Body<'tcx>, location: Locatio
for constraint in constraints.outlives().iter() {
let mut constraint = *constraint;
constraint.locations = locations;
if let ConstraintCategory::Return
if let ConstraintCategory::Return(_)
| ConstraintCategory::UseAsConst
| ConstraintCategory::UseAsStatic = constraint.category
{
......@@ -827,6 +831,7 @@ struct BorrowCheckContext<'a, 'tcx> {
all_facts: &'a mut Option<AllFacts>,
borrow_set: &'a BorrowSet<'tcx>,
constraints: &'a mut MirTypeckRegionConstraints<'tcx>,
upvars: &'a [Upvar],
}
crate struct MirTypeckResults<'tcx> {
......@@ -1420,7 +1425,7 @@ fn check_stmt(&mut self, body: &Body<'tcx>, stmt: &Statement<'tcx>, location: Lo
ConstraintCategory::UseAsConst
}
} else {
ConstraintCategory::Return
ConstraintCategory::Return(ReturnConstraint::Normal)
}
}
Some(l) if !body.local_decls[l].is_user_variable() => {
......@@ -1703,7 +1708,7 @@ fn check_call_dest(
ConstraintCategory::UseAsConst
}
} else {
ConstraintCategory::Return
ConstraintCategory::Return(ReturnConstraint::Normal)
}
}
Some(l) if !body.local_decls[l].is_user_variable() => {
......@@ -2489,6 +2494,19 @@ fn add_reborrow_constraint(
);
let mut cursor = borrowed_place.projection.as_ref();
let tcx = self.infcx.tcx;
let field = path_utils::is_upvar_field_projection(
tcx,
&self.borrowck_context.upvars,
borrowed_place.as_ref(),
body,
);
let category = if let Some(field) = field {
ConstraintCategory::ClosureUpvar(self.borrowck_context.upvars[field.index()].var_hir_id)
} else {
ConstraintCategory::Boring
};
while let [proj_base @ .., elem] = cursor {
cursor = proj_base;
......@@ -2496,7 +2514,6 @@ fn add_reborrow_constraint(
match elem {
ProjectionElem::Deref => {
let tcx = self.infcx.tcx;
let base_ty = Place::ty_from(borrowed_place.local, proj_base, body, tcx).ty;
debug!("add_reborrow_constraint - base_ty = {:?}", base_ty);
......@@ -2506,7 +2523,7 @@ fn add_reborrow_constraint(
sup: ref_region.to_region_vid(),
sub: borrow_region.to_region_vid(),
locations: location.to_locations(),
category: ConstraintCategory::Boring,
category,
});
match mutbl {
......
......@@ -12,6 +12,7 @@
pub use self::qualifs::Qualif;
mod ops;
pub mod post_drop_elaboration;
pub mod qualifs;
mod resolver;
pub mod validation;
......
......@@ -10,6 +10,22 @@
use super::ConstCx;
/// Emits an error if `op` is not allowed in the given const context.
pub fn non_const<O: NonConstOp>(ccx: &ConstCx<'_, '_>, op: O, span: Span) {
debug!("illegal_op: op={:?}", op);
if op.is_allowed_in_item(ccx) {
return;
}
if ccx.tcx.sess.opts.debugging_opts.unleash_the_miri_inside_of_you {
ccx.tcx.sess.miri_unleashed_feature(span, O::feature_gate());
return;
}
op.emit_error(ccx, span);
}
/// An operation that is not *always* allowed in a const context.
pub trait NonConstOp: std::fmt::Debug {
/// Returns the `Symbol` corresponding to the feature gate that would enable this operation,
......
use rustc_hir::def_id::LocalDefId;
use rustc_middle::mir::visit::Visitor;
use rustc_middle::mir::{self, BasicBlock, Location};
use rustc_middle::ty::TyCtxt;
use rustc_span::Span;
use super::ops;
use super::qualifs::{NeedsDrop, Qualif};
use super::validation::Qualifs;
use super::ConstCx;
/// Returns `true` if we should use the more precise live drop checker that runs after drop
/// elaboration.
pub fn checking_enabled(tcx: TyCtxt<'tcx>) -> bool {
tcx.features().const_precise_live_drops
}
/// Look for live drops in a const context.
///
/// This is separate from the rest of the const checking logic because it must run after drop
/// elaboration.
pub fn check_live_drops(tcx: TyCtxt<'tcx>, def_id: LocalDefId, body: &mir::Body<'tcx>) {
let const_kind = tcx.hir().body_const_context(def_id);
if const_kind.is_none() {
return;
}
if !checking_enabled(tcx) {
return;
}
let ccx = ConstCx {
body,
tcx,
def_id: def_id.to_def_id(),
const_kind,
param_env: tcx.param_env(def_id),
};
let mut visitor = CheckLiveDrops { ccx: &ccx, qualifs: Qualifs::default() };
visitor.visit_body(body);
}
struct CheckLiveDrops<'mir, 'tcx> {
ccx: &'mir ConstCx<'mir, 'tcx>,
qualifs: Qualifs<'mir, 'tcx>,
}
// So we can access `body` and `tcx`.
impl std::ops::Deref for CheckLiveDrops<'mir, 'tcx> {
type Target = ConstCx<'mir, 'tcx>;
fn deref(&self) -> &Self::Target {
&self.ccx
}
}
impl CheckLiveDrops<'mir, 'tcx> {
fn check_live_drop(&self, span: Span) {
ops::non_const(self.ccx, ops::LiveDrop, span);
}
}
impl Visitor<'tcx> for CheckLiveDrops<'mir, 'tcx> {
fn visit_basic_block_data(&mut self, bb: BasicBlock, block: &mir::BasicBlockData<'tcx>) {
trace!("visit_basic_block_data: bb={:?} is_cleanup={:?}", bb, block.is_cleanup);
// Ignore drop terminators in cleanup blocks.
if block.is_cleanup {
return;
}
self.super_basic_block_data(bb, block);
}
fn visit_terminator(&mut self, terminator: &mir::Terminator<'tcx>, location: Location) {
trace!("visit_terminator: terminator={:?} location={:?}", terminator, location);
match &terminator.kind {
mir::TerminatorKind::Drop { location: dropped_place, .. } => {
let dropped_ty = dropped_place.ty(self.body, self.tcx).ty;
if !NeedsDrop::in_any_value_of_ty(self.ccx, dropped_ty) {
return;
}
if dropped_place.is_indirect() {
self.check_live_drop(terminator.source_info.span);
return;
}
if self.qualifs.needs_drop(self.ccx, dropped_place.local, location) {
// Use the span where the dropped local was declared for the error.
let span = self.body.local_decls[dropped_place.local].source_info.span;
self.check_live_drop(span);
}
}
mir::TerminatorKind::DropAndReplace { .. } => span_bug!(
terminator.source_info.span,
"`DropAndReplace` should be removed by drop elaboration",
),
mir::TerminatorKind::Abort
| mir::TerminatorKind::Call { .. }
| mir::TerminatorKind::Assert { .. }
| mir::TerminatorKind::FalseEdge { .. }
| mir::TerminatorKind::FalseUnwind { .. }
| mir::TerminatorKind::GeneratorDrop
| mir::TerminatorKind::Goto { .. }
| mir::TerminatorKind::InlineAsm { .. }
| mir::TerminatorKind::Resume
| mir::TerminatorKind::Return
| mir::TerminatorKind::SwitchInt { .. }
| mir::TerminatorKind::Unreachable
| mir::TerminatorKind::Yield { .. } => {}
}
}
}
......@@ -40,7 +40,7 @@ pub struct Qualifs<'mir, 'tcx> {
}
impl Qualifs<'mir, 'tcx> {
fn indirectly_mutable(
pub fn indirectly_mutable(
&mut self,
ccx: &'mir ConstCx<'mir, 'tcx>,
local: Local,
......@@ -68,7 +68,7 @@ fn indirectly_mutable(
/// Returns `true` if `local` is `NeedsDrop` at the given `Location`.
///
/// Only updates the cursor if absolutely necessary
fn needs_drop(
pub fn needs_drop(
&mut self,
ccx: &'mir ConstCx<'mir, 'tcx>,
local: Local,
......@@ -95,7 +95,7 @@ fn needs_drop(
/// Returns `true` if `local` is `HasMutInterior` at the given `Location`.
///
/// Only updates the cursor if absolutely necessary.
fn has_mut_interior(
pub fn has_mut_interior(
&mut self,
ccx: &'mir ConstCx<'mir, 'tcx>,
local: Local,
......@@ -232,30 +232,15 @@ pub fn qualifs_in_return_place(&mut self) -> ConstQualifs {
self.qualifs.in_return_place(self.ccx)
}
/// Emits an error at the given `span` if an expression cannot be evaluated in the current
/// context.
pub fn check_op_spanned<O>(&mut self, op: O, span: Span)
where
O: NonConstOp,
{
debug!("check_op: op={:?}", op);
if op.is_allowed_in_item(self) {
return;
}
if self.tcx.sess.opts.debugging_opts.unleash_the_miri_inside_of_you {
self.tcx.sess.miri_unleashed_feature(span, O::feature_gate());
return;
}
op.emit_error(self, span);
}
/// Emits an error if an expression cannot be evaluated in the current context.
pub fn check_op(&mut self, op: impl NonConstOp) {
let span = self.span;
self.check_op_spanned(op, span)
ops::non_const(self.ccx, op, self.span);
}
/// Emits an error at the given `span` if an expression cannot be evaluated in the current
/// context.
pub fn check_op_spanned(&mut self, op: impl NonConstOp, span: Span) {
ops::non_const(self.ccx, op, span);
}
fn check_static(&mut self, def_id: DefId, span: Span) {
......@@ -577,6 +562,12 @@ fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location
// projections that cannot be `NeedsDrop`.
TerminatorKind::Drop { location: dropped_place, .. }
| TerminatorKind::DropAndReplace { location: dropped_place, .. } => {
// If we are checking live drops after drop-elaboration, don't emit duplicate
// errors here.
if super::post_drop_elaboration::checking_enabled(self.tcx) {
return;
}
let mut err_span = self.span;
// Check to see if the type of this place can ever have a drop impl. If not, this
......
......@@ -511,6 +511,7 @@ fn check_binary_op(
// This is basically `force_bits`.
let r_bits = r_bits.and_then(|r| r.to_bits_or_ptr(right_size, &self.tcx).ok());
if r_bits.map_or(false, |b| b >= left_size_bits as u128) {
debug!("check_binary_op: reporting assert for {:?}", source_info);
self.report_assert_as_lint(
lint::builtin::ARITHMETIC_OVERFLOW,
source_info,
......
......@@ -49,6 +49,7 @@ pub(crate) fn provide(providers: &mut Providers<'_>) {
mir_const,
mir_const_qualif,
mir_validated,
mir_drops_elaborated_and_const_checked,
optimized_mir,
is_mir_available,
promoted_mir,
......@@ -294,12 +295,31 @@ fn mir_validated(
(tcx.alloc_steal_mir(body), tcx.alloc_steal_promoted(promoted))
}
fn run_optimization_passes<'tcx>(
fn mir_drops_elaborated_and_const_checked<'tcx>(
tcx: TyCtxt<'tcx>,
def_id: LocalDefId,
) -> Steal<Body<'tcx>> {
// (Mir-)Borrowck uses `mir_validated`, so we have to force it to
// execute before we can steal.
tcx.ensure().mir_borrowck(def_id);
let (body, _) = tcx.mir_validated(def_id);
let mut body = body.steal();
run_post_borrowck_cleanup_passes(tcx, &mut body, def_id, None);
check_consts::post_drop_elaboration::check_live_drops(tcx, def_id, &body);
tcx.alloc_steal_mir(body)
}
/// After this series of passes, no lifetime analysis based on borrowing can be done.
fn run_post_borrowck_cleanup_passes<'tcx>(
tcx: TyCtxt<'tcx>,
body: &mut Body<'tcx>,
def_id: LocalDefId,
promoted: Option<Promoted>,
) {
debug!("post_borrowck_cleanup({:?})", def_id);
let post_borrowck_cleanup: &[&dyn MirPass<'tcx>] = &[
// Remove all things only needed by analysis
&no_landing_pads::NoLandingPads::new(tcx),
......@@ -318,9 +338,24 @@ fn run_optimization_passes<'tcx>(
// but before optimizations begin.
&add_retag::AddRetag,
&simplify::SimplifyCfg::new("elaborate-drops"),
// No lifetime analysis based on borrowing can be done from here on out.
];
run_passes(
tcx,
body,
InstanceDef::Item(def_id.to_def_id()),
promoted,
MirPhase::DropElab,
&[post_borrowck_cleanup],
);
}
fn run_optimization_passes<'tcx>(
tcx: TyCtxt<'tcx>,
body: &mut Body<'tcx>,
def_id: LocalDefId,
promoted: Option<Promoted>,
) {
let optimizations: &[&dyn MirPass<'tcx>] = &[
&unreachable_prop::UnreachablePropagation,
&uninhabited_enum_branching::UninhabitedEnumBranching,
......@@ -368,6 +403,7 @@ fn run_optimization_passes<'tcx>(
let mir_opt_level = tcx.sess.opts.debugging_opts.mir_opt_level;
#[rustfmt::skip]
run_passes(
tcx,
body,
......@@ -375,7 +411,6 @@ fn run_optimization_passes<'tcx>(
promoted,
MirPhase::Optimized,
&[
post_borrowck_cleanup,
if mir_opt_level > 0 { optimizations } else { no_optimizations },
pre_codegen_cleanup,
],
......@@ -393,12 +428,7 @@ fn optimized_mir(tcx: TyCtxt<'_>, def_id: DefId) -> Body<'_> {
let def_id = def_id.expect_local();
// (Mir-)Borrowck uses `mir_validated`, so we have to force it to
// execute before we can steal.
tcx.ensure().mir_borrowck(def_id);
let (body, _) = tcx.mir_validated(def_id);
let mut body = body.steal();
let mut body = tcx.mir_drops_elaborated_and_const_checked(def_id).steal();
run_optimization_passes(tcx, &mut body, def_id, None);
debug_assert!(!body.has_free_regions(), "Free regions in optimized MIR");
......@@ -418,6 +448,7 @@ fn promoted_mir(tcx: TyCtxt<'_>, def_id: DefId) -> IndexVec<Promoted, Body<'_>>
let mut promoted = promoted.steal();
for (p, mut body) in promoted.iter_enumerated_mut() {
run_post_borrowck_cleanup_passes(tcx, &mut body, def_id, Some(p));
run_optimization_passes(tcx, &mut body, def_id, Some(p));
}
......
......@@ -130,6 +130,9 @@ fn to_pat(
traits::NonStructuralMatchTy::Generator => {
"generators cannot be used in patterns".to_string()
}
traits::NonStructuralMatchTy::Closure => {
"closures cannot be used in patterns".to_string()
}
traits::NonStructuralMatchTy::Param => {
bug!("use of a constant whose type is a parameter inside a pattern")
}
......
......@@ -822,7 +822,15 @@ pub enum DesugaringKind {
OpaqueTy,
Async,
Await,
ForLoop,
ForLoop(ForLoopLoc),
Operator,
}
/// A location in the desugaring of a `for` loop
#[derive(Clone, Copy, PartialEq, Debug, RustcEncodable, RustcDecodable, HashStable_Generic)]
pub enum ForLoopLoc {
Head,
IntoIter,
}
impl DesugaringKind {
......@@ -835,7 +843,8 @@ fn descr(self) -> &'static str {
DesugaringKind::QuestionMark => "operator `?`",
DesugaringKind::TryBlock => "`try` block",
DesugaringKind::OpaqueTy => "`impl Trait`",
DesugaringKind::ForLoop => "`for` loop",
DesugaringKind::ForLoop(_) => "`for` loop",
DesugaringKind::Operator => "operator",
}
}
}
......
......@@ -31,7 +31,9 @@
use edition::Edition;
pub mod hygiene;
use hygiene::Transparency;
pub use hygiene::{DesugaringKind, ExpnData, ExpnId, ExpnKind, MacroKind, SyntaxContext};
pub use hygiene::{
DesugaringKind, ExpnData, ExpnId, ExpnKind, ForLoopLoc, MacroKind, SyntaxContext,
};
pub mod def_id;
use def_id::{CrateNum, DefId, LOCAL_CRATE};
mod span_encoding;
......
......@@ -227,6 +227,7 @@
const_loop,
const_mut_refs,
const_panic,
const_precise_live_drops,
const_raw_ptr_deref,
const_raw_ptr_to_usize_cast,
const_transmute,
......
......@@ -18,6 +18,7 @@ pub enum NonStructuralMatchTy<'tcx> {
Opaque,
Generator,
Projection,
Closure,
}
/// This method traverses the structure of `ty`, trying to find an
......@@ -162,6 +163,10 @@ fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool {
self.found = Some(NonStructuralMatchTy::Generator);
return true; // Stop visiting.
}
ty::Closure(..) => {
self.found = Some(NonStructuralMatchTy::Closure);
return true; // Stop visiting.
}
ty::RawPtr(..) => {
// structural-match ignores substructure of
// `*const _`/`*mut _`, so skip `super_visit_with`.
......@@ -211,7 +216,7 @@ fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool {
ty.super_visit_with(self);
return false;
}
ty::Closure(..) | ty::Infer(_) | ty::Placeholder(_) | ty::Bound(..) => {
ty::Infer(_) | ty::Placeholder(_) | ty::Bound(..) => {
bug!("unexpected type during structural-match checking: {:?}", ty);
}
ty::Error => {
......
......@@ -795,6 +795,7 @@ fn assemble_inherent_candidates_from_object(&mut self, self_ty: Ty<'tcx>) {
fn assemble_inherent_candidates_from_param(&mut self, param_ty: ty::ParamTy) {
// FIXME: do we want to commit to this behavior for param bounds?
debug!("assemble_inherent_candidates_from_param(param_ty={:?})", param_ty);
let bounds =
self.param_env.caller_bounds.iter().filter_map(|predicate| match predicate.kind() {
......@@ -952,7 +953,7 @@ fn assemble_extension_candidates_for_trait(
import_ids: import_ids.clone(),
kind: TraitCandidate(new_trait_ref),
},
true,
false,
);
});
} else {
......
// Regression test for issue #69446 - we should display
// which variable is captured
// edition:2018
use core::future::Future;
struct Foo;
impl Foo {
fn foo(&mut self) {}
}
async fn bar<T>(_: impl FnMut() -> T)
where
T: Future<Output = ()>,
{}
fn main() {
let mut x = Foo;
bar(move || async { //~ ERROR captured
x.foo();
});
}
error: captured variable cannot escape `FnMut` closure body
--> $DIR/issue-69446-fnmut-capture.rs:19:17
|
LL | let mut x = Foo;
| ----- variable defined here
LL | bar(move || async {
| _______________-_^
| | |
| | inferred to be a `FnMut` closure
LL | | x.foo();
| | - variable captured here
LL | | });
| |_____^ returns an `async` block that contains a reference to a captured variable, which then escapes the closure body
|
= note: `FnMut` closures only have access to their captured variables while they are executing...
= note: ...therefore, they cannot allow references to captured variables to escape
error: aborting due to previous error
......@@ -4,10 +4,15 @@ error[E0382]: use of moved value: `lhs`
LL | fn add<A: Add<B, Output=()>, B>(lhs: A, rhs: B) {
| --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait
LL | lhs + rhs;
| --- value moved here
| --------- `lhs` moved due to usage in operator
LL | drop(lhs);
| ^^^ value used here after move
|
note: calling this operator moves the left-hand side
--> $SRC_DIR/libcore/ops/arith.rs:LL:COL
|
LL | fn add(self, rhs: Rhs) -> Self::Output;
| ^^^^
help: consider further restricting this bound
|
LL | fn add<A: Add<B, Output=()> + Copy, B>(lhs: A, rhs: B) {
......@@ -35,10 +40,15 @@ error[E0382]: use of moved value: `lhs`
LL | fn sub<A: Sub<B, Output=()>, B>(lhs: A, rhs: B) {
| --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait
LL | lhs - rhs;
| --- value moved here
| --------- `lhs` moved due to usage in operator
LL | drop(lhs);
| ^^^ value used here after move
|
note: calling this operator moves the left-hand side
--> $SRC_DIR/libcore/ops/arith.rs:LL:COL
|
LL | fn sub(self, rhs: Rhs) -> Self::Output;
| ^^^^
help: consider further restricting this bound
|
LL | fn sub<A: Sub<B, Output=()> + Copy, B>(lhs: A, rhs: B) {
......@@ -66,10 +76,15 @@ error[E0382]: use of moved value: `lhs`
LL | fn mul<A: Mul<B, Output=()>, B>(lhs: A, rhs: B) {
| --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait
LL | lhs * rhs;
| --- value moved here
| --------- `lhs` moved due to usage in operator
LL | drop(lhs);
| ^^^ value used here after move
|
note: calling this operator moves the left-hand side
--> $SRC_DIR/libcore/ops/arith.rs:LL:COL
|
LL | fn mul(self, rhs: Rhs) -> Self::Output;
| ^^^^
help: consider further restricting this bound
|
LL | fn mul<A: Mul<B, Output=()> + Copy, B>(lhs: A, rhs: B) {
......@@ -97,10 +112,15 @@ error[E0382]: use of moved value: `lhs`
LL | fn div<A: Div<B, Output=()>, B>(lhs: A, rhs: B) {
| --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait
LL | lhs / rhs;
| --- value moved here
| --------- `lhs` moved due to usage in operator
LL | drop(lhs);
| ^^^ value used here after move
|
note: calling this operator moves the left-hand side
--> $SRC_DIR/libcore/ops/arith.rs:LL:COL
|
LL | fn div(self, rhs: Rhs) -> Self::Output;
| ^^^^
help: consider further restricting this bound
|
LL | fn div<A: Div<B, Output=()> + Copy, B>(lhs: A, rhs: B) {
......@@ -128,10 +148,15 @@ error[E0382]: use of moved value: `lhs`
LL | fn rem<A: Rem<B, Output=()>, B>(lhs: A, rhs: B) {
| --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait
LL | lhs % rhs;
| --- value moved here
| --------- `lhs` moved due to usage in operator
LL | drop(lhs);
| ^^^ value used here after move
|
note: calling this operator moves the left-hand side
--> $SRC_DIR/libcore/ops/arith.rs:LL:COL
|
LL | fn rem(self, rhs: Rhs) -> Self::Output;
| ^^^^
help: consider further restricting this bound
|
LL | fn rem<A: Rem<B, Output=()> + Copy, B>(lhs: A, rhs: B) {
......@@ -159,10 +184,15 @@ error[E0382]: use of moved value: `lhs`
LL | fn bitand<A: BitAnd<B, Output=()>, B>(lhs: A, rhs: B) {
| --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait
LL | lhs & rhs;
| --- value moved here
| --------- `lhs` moved due to usage in operator
LL | drop(lhs);
| ^^^ value used here after move
|
note: calling this operator moves the left-hand side
--> $SRC_DIR/libcore/ops/bit.rs:LL:COL
|
LL | fn bitand(self, rhs: Rhs) -> Self::Output;
| ^^^^
help: consider further restricting this bound
|
LL | fn bitand<A: BitAnd<B, Output=()> + Copy, B>(lhs: A, rhs: B) {
......@@ -190,10 +220,15 @@ error[E0382]: use of moved value: `lhs`
LL | fn bitor<A: BitOr<B, Output=()>, B>(lhs: A, rhs: B) {
| --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait
LL | lhs | rhs;
| --- value moved here
| --------- `lhs` moved due to usage in operator
LL | drop(lhs);
| ^^^ value used here after move
|
note: calling this operator moves the left-hand side
--> $SRC_DIR/libcore/ops/bit.rs:LL:COL
|
LL | fn bitor(self, rhs: Rhs) -> Self::Output;
| ^^^^
help: consider further restricting this bound
|
LL | fn bitor<A: BitOr<B, Output=()> + Copy, B>(lhs: A, rhs: B) {
......@@ -221,10 +256,15 @@ error[E0382]: use of moved value: `lhs`
LL | fn bitxor<A: BitXor<B, Output=()>, B>(lhs: A, rhs: B) {
| --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait
LL | lhs ^ rhs;
| --- value moved here
| --------- `lhs` moved due to usage in operator
LL | drop(lhs);
| ^^^ value used here after move
|
note: calling this operator moves the left-hand side
--> $SRC_DIR/libcore/ops/bit.rs:LL:COL
|
LL | fn bitxor(self, rhs: Rhs) -> Self::Output;
| ^^^^
help: consider further restricting this bound
|
LL | fn bitxor<A: BitXor<B, Output=()> + Copy, B>(lhs: A, rhs: B) {
......@@ -252,10 +292,15 @@ error[E0382]: use of moved value: `lhs`
LL | fn shl<A: Shl<B, Output=()>, B>(lhs: A, rhs: B) {
| --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait
LL | lhs << rhs;
| --- value moved here
| ---------- `lhs` moved due to usage in operator
LL | drop(lhs);
| ^^^ value used here after move
|
note: calling this operator moves the left-hand side
--> $SRC_DIR/libcore/ops/bit.rs:LL:COL
|
LL | fn shl(self, rhs: Rhs) -> Self::Output;
| ^^^^
help: consider further restricting this bound
|
LL | fn shl<A: Shl<B, Output=()> + Copy, B>(lhs: A, rhs: B) {
......@@ -283,10 +328,15 @@ error[E0382]: use of moved value: `lhs`
LL | fn shr<A: Shr<B, Output=()>, B>(lhs: A, rhs: B) {
| --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait
LL | lhs >> rhs;
| --- value moved here
| ---------- `lhs` moved due to usage in operator
LL | drop(lhs);
| ^^^ value used here after move
|
note: calling this operator moves the left-hand side
--> $SRC_DIR/libcore/ops/bit.rs:LL:COL
|
LL | fn shr(self, rhs: Rhs) -> Self::Output;
| ^^^^
help: consider further restricting this bound
|
LL | fn shr<A: Shr<B, Output=()> + Copy, B>(lhs: A, rhs: B) {
......
error[E0382]: use of moved value: `x`
--> $DIR/binop-move-semantics.rs:8:5
|
LL | fn double_move<T: Add<Output=()>>(x: T) {
| - move occurs because `x` has type `T`, which does not implement the `Copy` trait
LL | x
| - value moved here
LL | +
LL | x;
| ^ value used here after move
LL | fn double_move<T: Add<Output=()>>(x: T) {
| - move occurs because `x` has type `T`, which does not implement the `Copy` trait
LL | / x
LL | | +
LL | | x;
| | ^
| | |
| |_____value used here after move
| `x` moved due to usage in operator
|
note: calling this operator moves the left-hand side
--> $SRC_DIR/libcore/ops/arith.rs:LL:COL
|
LL | fn add(self, rhs: Rhs) -> Self::Output;
| ^^^^
help: consider further restricting this bound
|
LL | fn double_move<T: Add<Output=()> + Copy>(x: T) {
......
......@@ -21,10 +21,13 @@ LL | *y = 1;
error: captured variable cannot escape `FnMut` closure body
--> $DIR/borrowck-describe-lvalue.rs:264:16
|
LL | let mut x = 0;
| ----- variable defined here
LL | || {
| - inferred to be a `FnMut` closure
LL | / || {
LL | | let y = &mut x;
| | - variable captured here
LL | | &mut x;
LL | | *y = 1;
LL | | drop(y);
......
......@@ -22,10 +22,15 @@ error[E0382]: use of moved value: `f`
LL | fn c<F:FnOnce(isize, isize) -> isize>(f: F) {
| - move occurs because `f` has type `F`, which does not implement the `Copy` trait
LL | f(1, 2);
| - value moved here
| ------- `f` moved due to this call
LL | f(1, 2);
| ^ value used here after move
|
note: this value implements `FnOnce`, which causes it to be moved when called
--> $DIR/borrowck-unboxed-closures.rs:11:5
|
LL | f(1, 2);
| ^
help: consider further restricting this bound
|
LL | fn c<F:FnOnce(isize, isize) -> isize + Copy>(f: F) {
......
......@@ -2,7 +2,7 @@ error[E0382]: use of moved value: `debug_dump_dict`
--> $DIR/issue-42065.rs:11:5
|
LL | debug_dump_dict();
| --------------- value moved here
| ----------------- `debug_dump_dict` moved due to this call
LL | debug_dump_dict();
| ^^^^^^^^^^^^^^^ value used here after move
|
......@@ -11,6 +11,11 @@ note: closure cannot be invoked more than once because it moves the variable `di
|
LL | for (key, value) in dict {
| ^^^^
note: this value implements `FnOnce`, which causes it to be moved when called
--> $DIR/issue-42065.rs:10:5
|
LL | debug_dump_dict();
| ^^^^^^^^^^^^^^^
error: aborting due to previous error
......
......@@ -4,10 +4,16 @@ error[E0382]: borrow of moved value: `some_vec`
LL | let some_vec = vec!["hi"];
| -------- move occurs because `some_vec` has type `std::vec::Vec<&str>`, which does not implement the `Copy` trait
LL | some_vec.into_iter();
| -------- value moved here
| ----------- `some_vec` moved due to this method call
LL | {
LL | println!("{:?}", some_vec);
| ^^^^^^^^ value borrowed here after move
|
note: this function consumes the receiver `self` by taking ownership of it, which moves `some_vec`
--> $SRC_DIR/libcore/iter/traits/collect.rs:LL:COL
|
LL | fn into_iter(self) -> Self::IntoIter;
| ^^^^
error: aborting due to previous error
......
error[E0493]: destructors cannot be evaluated at compile-time
--> $DIR/drop-fail.rs:10:9
|
LL | let x = Some(Vec::new());
| ^ constants cannot evaluate destructors
error[E0493]: destructors cannot be evaluated at compile-time
--> $DIR/drop-fail.rs:41:9
|
LL | let mut tmp = None;
| ^^^^^^^ constants cannot evaluate destructors
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0493`.
// revisions: stock precise
#![feature(const_if_match)]
#![feature(const_loop)]
#![cfg_attr(precise, feature(const_precise_live_drops))]
// `x` is *not* always moved into the final value may be dropped inside the initializer.
// `x` is *not* always moved into the final value and may be dropped inside the initializer.
const _: Option<Vec<i32>> = {
let y: Option<Vec<i32>> = None;
let x = Some(Vec::new());
//~^ ERROR destructors cannot be evaluated at compile-time
//[stock,precise]~^ ERROR destructors cannot be evaluated at compile-time
if true {
x
......@@ -18,7 +21,7 @@
// existing analysis.
const _: Vec<i32> = {
let vec_tuple = (Vec::new(),);
//~^ ERROR destructors cannot be evaluated at compile-time
//[stock]~^ ERROR destructors cannot be evaluated at compile-time
vec_tuple.0
};
......@@ -26,7 +29,7 @@
// This applies to single-field enum variants as well.
const _: Vec<i32> = {
let x: Result<_, Vec<i32>> = Ok(Vec::new());
//~^ ERROR destructors cannot be evaluated at compile-time
//[stock]~^ ERROR destructors cannot be evaluated at compile-time
match x {
Ok(x) | Err(x) => x,
......@@ -36,7 +39,7 @@
const _: Option<Vec<i32>> = {
let mut some = Some(Vec::new());
let mut tmp = None;
//~^ ERROR destructors cannot be evaluated at compile-time
//[stock,precise]~^ ERROR destructors cannot be evaluated at compile-time
let mut i = 0;
while i < 10 {
......
error[E0493]: destructors cannot be evaluated at compile-time
--> $DIR/drop-failure.rs:7:9
--> $DIR/drop-fail.rs:10:9
|
LL | let x = Some(Vec::new());
| ^ constants cannot evaluate destructors
error[E0493]: destructors cannot be evaluated at compile-time
--> $DIR/drop-failure.rs:20:9
--> $DIR/drop-fail.rs:23:9
|
LL | let vec_tuple = (Vec::new(),);
| ^^^^^^^^^ constants cannot evaluate destructors
error[E0493]: destructors cannot be evaluated at compile-time
--> $DIR/drop-failure.rs:28:9
--> $DIR/drop-fail.rs:31:9
|
LL | let x: Result<_, Vec<i32>> = Ok(Vec::new());
| ^ constants cannot evaluate destructors
error[E0493]: destructors cannot be evaluated at compile-time
--> $DIR/drop-failure.rs:38:9
--> $DIR/drop-fail.rs:41:9
|
LL | let mut tmp = None;
| ^^^^^^^ constants cannot evaluate destructors
......
// run-pass
// revisions: stock precise
#![feature(const_if_match)]
#![feature(const_loop)]
#![cfg_attr(precise, feature(const_precise_live_drops))]
// `x` is always moved into the final value and is not dropped inside the initializer.
const _: Option<Vec<i32>> = {
......
// run-pass
// gate-test-const_precise_live_drops
#![feature(const_if_match)]
#![feature(const_loop)]
#![feature(const_precise_live_drops)]
const _: Vec<i32> = {
let vec_tuple = (Vec::new(),);
vec_tuple.0
};
const _: Vec<i32> = {
let x: Result<_, Vec<i32>> = Ok(Vec::new());
match x {
Ok(x) | Err(x) => x,
}
};
fn main() {}
......@@ -6,14 +6,15 @@
static CMP: () = {
let x = &0 as *const _;
let _v = x == x;
let _v = x == x; //~ NOTE in this
//~^ ERROR could not evaluate static initializer
//~| NOTE pointer arithmetic or comparison
//~| NOTE in this
};
static INT_PTR_ARITH: () = unsafe {
let x: usize = std::mem::transmute(&0);
let _v = x + 0;
let _v = x + 0; //~ NOTE in this
//~^ ERROR could not evaluate static initializer
//~| NOTE pointer-to-integer cast
};
......
......@@ -5,7 +5,7 @@ LL | let _v = x == x;
| ^^^^^^ "pointer arithmetic or comparison" needs an rfc before being allowed inside constants
error[E0080]: could not evaluate static initializer
--> $DIR/ptr_arith.rs:16:14
--> $DIR/ptr_arith.rs:17:14
|
LL | let _v = x + 0;
| ^^^^^ "pointer-to-integer cast" needs an rfc before being allowed inside constants
......@@ -18,7 +18,7 @@ help: skipping check for `const_compare_raw_pointers` feature
LL | let _v = x == x;
| ^^^^^^
help: skipping check that does not even have a feature gate
--> $DIR/ptr_arith.rs:15:20
--> $DIR/ptr_arith.rs:16:20
|
LL | let x: usize = std::mem::transmute(&0);
| ^^^^^^^^^^^^^^^^^^^^^^^
......
......@@ -18,8 +18,12 @@ fn y /* 0#0 */() { }
Expansions:
0: parent: ExpnId(0), call_site_ctxt: #0, kind: Root
1: parent: ExpnId(0), call_site_ctxt: #0, kind: Macro(Bang, "foo")
2: parent: ExpnId(0), call_site_ctxt: #1, kind: Desugaring(Operator)
3: parent: ExpnId(0), call_site_ctxt: #1, kind: Desugaring(Operator)
SyntaxContexts:
#0: parent: #0, outer_mark: (ExpnId(0), Opaque)
#1: parent: #0, outer_mark: (ExpnId(1), SemiTransparent)
#2: parent: #1, outer_mark: (ExpnId(2), Transparent)
#3: parent: #1, outer_mark: (ExpnId(3), Transparent)
*/
// check-pass
#![feature(impl_trait_in_bindings)]
//~^ WARN the feature `impl_trait_in_bindings` is incomplete
const _: impl Fn() = ||();
fn main() {}
warning: the feature `impl_trait_in_bindings` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/impl-trait-in-bindings-issue-73003.rs:3:12
|
LL | #![feature(impl_trait_in_bindings)]
| ^^^^^^^^^^^^^^^^^^^^^^
|
= note: `#[warn(incomplete_features)]` on by default
= note: see issue #63065 <https://github.com/rust-lang/rust/issues/63065> for more information
warning: 1 warning emitted
......@@ -2,10 +2,15 @@ error[E0382]: use of moved value: `f`
--> $DIR/issue-12127.rs:11:9
|
LL | f();
| - value moved here
| --- `f` moved due to this call
LL | f();
| ^ value used here after move
|
note: this value implements `FnOnce`, which causes it to be moved when called
--> $DIR/issue-12127.rs:10:9
|
LL | f();
| ^
= note: move occurs because `f` has type `[closure@$DIR/issue-12127.rs:8:24: 8:41 x:std::boxed::Box<isize>]`, which does not implement the `Copy` trait
error: aborting due to previous error
......
......@@ -3,4 +3,5 @@
fn main() {
for _ in HashMap::new().iter().cloned() {} //~ ERROR type mismatch
//~^ ERROR type mismatch
//~| ERROR type mismatch
}
......@@ -17,6 +17,16 @@ LL | for _ in HashMap::new().iter().cloned() {}
found reference `&_`
= note: required because of the requirements on the impl of `std::iter::Iterator` for `std::iter::Cloned<std::collections::hash_map::Iter<'_, _, _>>`
error: aborting due to 2 previous errors
error[E0271]: type mismatch resolving `<std::collections::hash_map::Iter<'_, _, _> as std::iter::Iterator>::Item == &_`
--> $DIR/issue-33941.rs:4:14
|
LL | for _ in HashMap::new().iter().cloned() {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected tuple, found reference
|
= note: expected tuple `(&_, &_)`
found reference `&_`
= note: required because of the requirements on the impl of `std::iter::Iterator` for `std::iter::Cloned<std::collections::hash_map::Iter<'_, _, _>>`
error: aborting due to 3 previous errors
For more information about this error, try `rustc --explain E0271`.
......@@ -5,14 +5,19 @@ LL | pub fn baz<T: Foo>(x: T) -> T {
| - move occurs because `x` has type `T`, which does not implement the `Copy` trait
LL | if 0 == 1 {
LL | bar::bar(x.zero())
| - value moved here
| ------ `x` moved due to this method call
LL | } else {
LL | x.zero()
| - value moved here
| ------ `x` moved due to this method call
LL | };
LL | x.zero()
| ^ value used here after move
|
note: this function consumes the receiver `self` by taking ownership of it, which moves `x`
--> $DIR/issue-34721.rs:4:13
|
LL | fn zero(self) -> Self;
| ^^^^
help: consider further restricting this bound
|
LL | pub fn baz<T: Foo + Copy>(x: T) -> T {
......
error: captured variable cannot escape `FnMut` closure body
--> $DIR/issue-40510-1.rs:7:9
|
LL | let mut x: Box<()> = Box::new(());
| ----- variable defined here
LL |
LL | || {
| - inferred to be a `FnMut` closure
LL | &mut x
| ^^^^^^ returns a reference to a captured variable which escapes the closure body
| ^^^^^-
| | |
| | variable captured here
| returns a reference to a captured variable which escapes the closure body
|
= note: `FnMut` closures only have access to their captured variables while they are executing...
= note: ...therefore, they cannot allow references to captured variables to escape
......
error: captured variable cannot escape `FnMut` closure body
--> $DIR/issue-40510-3.rs:7:9
|
LL | let mut x: Vec<()> = Vec::new();
| ----- variable defined here
LL |
LL | || {
| - inferred to be a `FnMut` closure
LL | / || {
LL | | x.push(())
| | - variable captured here
LL | | }
| |_________^ returns a closure that contains a reference to a captured variable, which then escapes the closure body
|
......
error: captured variable cannot escape `FnMut` closure body
--> $DIR/issue-49824.rs:4:9
|
LL | let mut x = 0;
| ----- variable defined here
LL | || {
| - inferred to be a `FnMut` closure
LL | / || {
LL | |
LL | | let _y = &mut x;
| | - variable captured here
LL | | }
| |_________^ returns a closure that contains a reference to a captured variable, which then escapes the closure body
|
......
......@@ -6,11 +6,17 @@ LL | let mut bad_letters = vec!['e', 't', 'o', 'i'];
LL | for l in bad_letters {
| -----------
| |
| value moved here
| `bad_letters` moved due to this implicit call to `.into_iter()`
| help: consider borrowing to avoid moving into the for loop: `&bad_letters`
...
LL | bad_letters.push('s');
| ^^^^^^^^^^^ value borrowed here after move
|
note: this function consumes the receiver `self` by taking ownership of it, which moves `bad_letters`
--> $SRC_DIR/libcore/iter/traits/collect.rs:LL:COL
|
LL | fn into_iter(self) -> Self::IntoIter;
| ^^^^
error: aborting due to previous error
......
......@@ -6,12 +6,18 @@ LL | let orig = vec![true];
LL | for _val in orig {}
| ----
| |
| value moved here
| `orig` moved due to this implicit call to `.into_iter()`
| help: consider borrowing to avoid moving into the for loop: `&orig`
LL | let _closure = || orig;
| ^^ ---- use occurs due to use in closure
| |
| value used here after move
|
note: this function consumes the receiver `self` by taking ownership of it, which moves `orig`
--> $SRC_DIR/libcore/iter/traits/collect.rs:LL:COL
|
LL | fn into_iter(self) -> Self::IntoIter;
| ^^^^
error: aborting due to previous error
......
use std::pin::Pin;
use std::rc::Rc;
use std::ops::Add;
struct Foo;
impl Add for Foo {
type Output = ();
fn add(self, _rhs: Self) -> () {}
}
impl Foo {
fn use_self(self) {}
fn use_box_self(self: Box<Self>) {}
fn use_pin_box_self(self: Pin<Box<Self>>) {}
fn use_rc_self(self: Rc<Self>) {}
fn use_mut_self(&mut self) -> &mut Self { self }
}
struct Container(Vec<bool>);
impl Container {
fn custom_into_iter(self) -> impl Iterator<Item = bool> {
self.0.into_iter()
}
}
fn move_out(val: Container) {
val.0.into_iter().next();
val.0; //~ ERROR use of moved
let foo = Foo;
foo.use_self();
foo; //~ ERROR use of moved
let second_foo = Foo;
second_foo.use_self();
second_foo; //~ ERROR use of moved
let boxed_foo = Box::new(Foo);
boxed_foo.use_box_self();
boxed_foo; //~ ERROR use of moved
let pin_box_foo = Box::pin(Foo);
pin_box_foo.use_pin_box_self();
pin_box_foo; //~ ERROR use of moved
let mut mut_foo = Foo;
let ret = mut_foo.use_mut_self();
mut_foo; //~ ERROR cannot move out
ret;
let rc_foo = Rc::new(Foo);
rc_foo.use_rc_self();
rc_foo; //~ ERROR use of moved
let foo_add = Foo;
foo_add + Foo;
foo_add; //~ ERROR use of moved
let implicit_into_iter = vec![true];
for _val in implicit_into_iter {}
implicit_into_iter; //~ ERROR use of moved
let explicit_into_iter = vec![true];
for _val in explicit_into_iter.into_iter() {}
explicit_into_iter; //~ ERROR use of moved
let container = Container(vec![]);
for _val in container.custom_into_iter() {}
container; //~ ERROR use of moved
}
fn main() {}
error[E0382]: use of moved value: `val.0`
--> $DIR/move-fn-self-receiver.rs:30:5
|
LL | val.0.into_iter().next();
| ----------- `val.0` moved due to this method call
LL | val.0;
| ^^^^^ value used here after move
|
note: this function consumes the receiver `self` by taking ownership of it, which moves `val.0`
--> $SRC_DIR/libcore/iter/traits/collect.rs:LL:COL
|
LL | fn into_iter(self) -> Self::IntoIter;
| ^^^^
= note: move occurs because `val.0` has type `std::vec::Vec<bool>`, which does not implement the `Copy` trait
error[E0382]: use of moved value: `foo`
--> $DIR/move-fn-self-receiver.rs:34:5
|
LL | let foo = Foo;
| --- move occurs because `foo` has type `Foo`, which does not implement the `Copy` trait
LL | foo.use_self();
| ---------- `foo` moved due to this method call
LL | foo;
| ^^^ value used here after move
|
note: this function consumes the receiver `self` by taking ownership of it, which moves `foo`
--> $DIR/move-fn-self-receiver.rs:13:17
|
LL | fn use_self(self) {}
| ^^^^
error[E0382]: use of moved value: `second_foo`
--> $DIR/move-fn-self-receiver.rs:38:5
|
LL | let second_foo = Foo;
| ---------- move occurs because `second_foo` has type `Foo`, which does not implement the `Copy` trait
LL | second_foo.use_self();
| ---------- `second_foo` moved due to this method call
LL | second_foo;
| ^^^^^^^^^^ value used here after move
error[E0382]: use of moved value: `boxed_foo`
--> $DIR/move-fn-self-receiver.rs:42:5
|
LL | let boxed_foo = Box::new(Foo);
| --------- move occurs because `boxed_foo` has type `std::boxed::Box<Foo>`, which does not implement the `Copy` trait
LL | boxed_foo.use_box_self();
| -------------- `boxed_foo` moved due to this method call
LL | boxed_foo;
| ^^^^^^^^^ value used here after move
|
note: this function consumes the receiver `self` by taking ownership of it, which moves `boxed_foo`
--> $DIR/move-fn-self-receiver.rs:14:21
|
LL | fn use_box_self(self: Box<Self>) {}
| ^^^^
error[E0382]: use of moved value: `pin_box_foo`
--> $DIR/move-fn-self-receiver.rs:46:5
|
LL | let pin_box_foo = Box::pin(Foo);
| ----------- move occurs because `pin_box_foo` has type `std::pin::Pin<std::boxed::Box<Foo>>`, which does not implement the `Copy` trait
LL | pin_box_foo.use_pin_box_self();
| ------------------ `pin_box_foo` moved due to this method call
LL | pin_box_foo;
| ^^^^^^^^^^^ value used here after move
|
note: this function consumes the receiver `self` by taking ownership of it, which moves `pin_box_foo`
--> $DIR/move-fn-self-receiver.rs:15:25
|
LL | fn use_pin_box_self(self: Pin<Box<Self>>) {}
| ^^^^
error[E0505]: cannot move out of `mut_foo` because it is borrowed
--> $DIR/move-fn-self-receiver.rs:50:5
|
LL | let ret = mut_foo.use_mut_self();
| ------- borrow of `mut_foo` occurs here
LL | mut_foo;
| ^^^^^^^ move out of `mut_foo` occurs here
LL | ret;
| --- borrow later used here
error[E0382]: use of moved value: `rc_foo`
--> $DIR/move-fn-self-receiver.rs:55:5
|
LL | let rc_foo = Rc::new(Foo);
| ------ move occurs because `rc_foo` has type `std::rc::Rc<Foo>`, which does not implement the `Copy` trait
LL | rc_foo.use_rc_self();
| ------------- `rc_foo` moved due to this method call
LL | rc_foo;
| ^^^^^^ value used here after move
|
note: this function consumes the receiver `self` by taking ownership of it, which moves `rc_foo`
--> $DIR/move-fn-self-receiver.rs:16:20
|
LL | fn use_rc_self(self: Rc<Self>) {}
| ^^^^
error[E0382]: use of moved value: `foo_add`
--> $DIR/move-fn-self-receiver.rs:59:5
|
LL | let foo_add = Foo;
| ------- move occurs because `foo_add` has type `Foo`, which does not implement the `Copy` trait
LL | foo_add + Foo;
| ------------- `foo_add` moved due to usage in operator
LL | foo_add;
| ^^^^^^^ value used here after move
|
note: calling this operator moves the left-hand side
--> $SRC_DIR/libcore/ops/arith.rs:LL:COL
|
LL | fn add(self, rhs: Rhs) -> Self::Output;
| ^^^^
error[E0382]: use of moved value: `implicit_into_iter`
--> $DIR/move-fn-self-receiver.rs:63:5
|
LL | let implicit_into_iter = vec![true];
| ------------------ move occurs because `implicit_into_iter` has type `std::vec::Vec<bool>`, which does not implement the `Copy` trait
LL | for _val in implicit_into_iter {}
| ------------------
| |
| `implicit_into_iter` moved due to this implicit call to `.into_iter()`
| help: consider borrowing to avoid moving into the for loop: `&implicit_into_iter`
LL | implicit_into_iter;
| ^^^^^^^^^^^^^^^^^^ value used here after move
error[E0382]: use of moved value: `explicit_into_iter`
--> $DIR/move-fn-self-receiver.rs:67:5
|
LL | let explicit_into_iter = vec![true];
| ------------------ move occurs because `explicit_into_iter` has type `std::vec::Vec<bool>`, which does not implement the `Copy` trait
LL | for _val in explicit_into_iter.into_iter() {}
| ----------- `explicit_into_iter` moved due to this method call
LL | explicit_into_iter;
| ^^^^^^^^^^^^^^^^^^ value used here after move
error[E0382]: use of moved value: `container`
--> $DIR/move-fn-self-receiver.rs:71:5
|
LL | let container = Container(vec![]);
| --------- move occurs because `container` has type `Container`, which does not implement the `Copy` trait
LL | for _val in container.custom_into_iter() {}
| ------------------ `container` moved due to this method call
LL | container;
| ^^^^^^^^^ value used here after move
|
note: this function consumes the receiver `self` by taking ownership of it, which moves `container`
--> $DIR/move-fn-self-receiver.rs:23:25
|
LL | fn custom_into_iter(self) -> impl Iterator<Item = bool> {
| ^^^^
error: aborting due to 11 previous errors
Some errors have detailed explanations: E0382, E0505.
For more information about an error, try `rustc --explain E0382`.
......@@ -4,9 +4,15 @@ error[E0382]: borrow of moved value: `x`
LL | let x = vec!["hi".to_string()];
| - move occurs because `x` has type `std::vec::Vec<std::string::String>`, which does not implement the `Copy` trait
LL | consume(x.into_iter().next().unwrap());
| - value moved here
| ----------- `x` moved due to this method call
LL | touch(&x[0]);
| ^ value borrowed here after move
|
note: this function consumes the receiver `self` by taking ownership of it, which moves `x`
--> $SRC_DIR/libcore/iter/traits/collect.rs:LL:COL
|
LL | fn into_iter(self) -> Self::IntoIter;
| ^^^^
error: aborting due to previous error
......
......@@ -104,9 +104,15 @@ error[E0382]: borrow of moved value: `x`
LL | let x = vec!["hi".to_string()];
| - move occurs because `x` has type `std::vec::Vec<std::string::String>`, which does not implement the `Copy` trait
LL | let _y = x.into_iter().next().unwrap();
| - value moved here
| ----------- `x` moved due to this method call
LL | touch(&x);
| ^^ value borrowed here after move
|
note: this function consumes the receiver `self` by taking ownership of it, which moves `x`
--> $SRC_DIR/libcore/iter/traits/collect.rs:LL:COL
|
LL | fn into_iter(self) -> Self::IntoIter;
| ^^^^
error[E0382]: borrow of moved value: `x`
--> $DIR/moves-based-on-type-exprs.rs:83:11
......@@ -114,9 +120,15 @@ error[E0382]: borrow of moved value: `x`
LL | let x = vec!["hi".to_string()];
| - move occurs because `x` has type `std::vec::Vec<std::string::String>`, which does not implement the `Copy` trait
LL | let _y = [x.into_iter().next().unwrap(); 1];
| - value moved here
| ----------- `x` moved due to this method call
LL | touch(&x);
| ^^ value borrowed here after move
|
note: this function consumes the receiver `self` by taking ownership of it, which moves `x`
--> $SRC_DIR/libcore/iter/traits/collect.rs:LL:COL
|
LL | fn into_iter(self) -> Self::IntoIter;
| ^^^^
error: aborting due to 11 previous errors
......
error: captured variable cannot escape `FnMut` closure body
--> $DIR/issue-53040.rs:3:8
|
LL | let mut v: Vec<()> = Vec::new();
| ----- variable defined here
LL | || &mut v;
| - ^^^^^^ returns a reference to a captured variable which escapes the closure body
| |
| - ^^^^^-
| | | |
| | | variable captured here
| | returns a reference to a captured variable which escapes the closure body
| inferred to be a `FnMut` closure
|
= note: `FnMut` closures only have access to their captured variables while they are executing...
......
......@@ -4,10 +4,15 @@ error[E0382]: use of moved value: `blk`
LL | fn foo<F:FnOnce()>(blk: F) {
| --- move occurs because `blk` has type `F`, which does not implement the `Copy` trait
LL | blk();
| --- value moved here
| ----- `blk` moved due to this call
LL | blk();
| ^^^ value used here after move
|
note: this value implements `FnOnce`, which causes it to be moved when called
--> $DIR/once-cant-call-twice-on-heap.rs:8:5
|
LL | blk();
| ^^^
help: consider further restricting this bound
|
LL | fn foo<F:FnOnce() + Copy>(blk: F) {
......
error: captured variable cannot escape `FnMut` closure body
--> $DIR/regions-return-ref-to-upvar-issue-17403.rs:7:24
|
LL | let mut x = 0;
| ----- variable defined here
LL | let mut f = || &mut x;
| - ^^^^^^ returns a reference to a captured variable which escapes the closure body
| |
| - ^^^^^-
| | | |
| | | variable captured here
| | returns a reference to a captured variable which escapes the closure body
| inferred to be a `FnMut` closure
|
= note: `FnMut` closures only have access to their captured variables while they are executing...
......
// check-pass
#![feature(trait_alias)]
trait SomeTrait {
fn map(&self) {}
}
impl<T> SomeTrait for Option<T> {}
trait SomeAlias = SomeTrait;
fn main() {
let x = Some(123);
// This should resolve to the trait impl for Option
Option::map(x, |z| z);
// This should resolve to the trait impl for SomeTrait
SomeTrait::map(&x);
}
// check-pass
#![feature(trait_alias)]
trait Bounded { const MAX: Self; }
impl Bounded for u32 {
// This should correctly resolve to the associated const in the inherent impl of u32.
const MAX: Self = u32::MAX;
}
trait Num = Bounded + Copy;
fn main() {}
......@@ -2,7 +2,7 @@ error[E0382]: use of moved value: `tick`
--> $DIR/unboxed-closures-infer-fnonce-call-twice.rs:10:5
|
LL | tick();
| ---- value moved here
| ------ `tick` moved due to this call
LL | tick();
| ^^^^ value used here after move
|
......@@ -11,6 +11,11 @@ note: closure cannot be invoked more than once because it moves the variable `co
|
LL | let tick = || mem::drop(counter);
| ^^^^^^^
note: this value implements `FnOnce`, which causes it to be moved when called
--> $DIR/unboxed-closures-infer-fnonce-call-twice.rs:9:5
|
LL | tick();
| ^^^^
error: aborting due to previous error
......
......@@ -2,7 +2,7 @@ error[E0382]: use of moved value: `tick`
--> $DIR/unboxed-closures-infer-fnonce-move-call-twice.rs:10:5
|
LL | tick();
| ---- value moved here
| ------ `tick` moved due to this call
LL | tick();
| ^^^^ value used here after move
|
......@@ -11,6 +11,11 @@ note: closure cannot be invoked more than once because it moves the variable `co
|
LL | let tick = move || mem::drop(counter);
| ^^^^^^^
note: this value implements `FnOnce`, which causes it to be moved when called
--> $DIR/unboxed-closures-infer-fnonce-move-call-twice.rs:9:5
|
LL | tick();
| ^^^^
error: aborting due to previous error
......
......@@ -4,11 +4,16 @@ error[E0382]: borrow of moved value: `x`
LL | fn move_then_borrow<T: Not<Output=T> + Clone>(x: T) {
| - move occurs because `x` has type `T`, which does not implement the `Copy` trait
LL | !x;
| - value moved here
| -- `x` moved due to this method call
LL |
LL | x.clone();
| ^ value borrowed here after move
|
note: this function consumes the receiver `self` by taking ownership of it, which moves `x`
--> $SRC_DIR/libcore/ops/bit.rs:LL:COL
|
LL | fn not(self) -> Self::Output;
| ^^^^
help: consider further restricting this bound
|
LL | fn move_then_borrow<T: Not<Output=T> + Clone + Copy>(x: T) {
......
......@@ -37,10 +37,16 @@ error[E0382]: borrow of moved value: `y`
LL | let y = *x;
| - move occurs because `y` has type `str`, which does not implement the `Copy` trait
LL | y.foo();
| - value moved here
| ----- `y` moved due to this method call
...
LL | println!("{}", &y);
| ^^ value borrowed here after move
|
note: this function consumes the receiver `self` by taking ownership of it, which moves `y`
--> $DIR/borrow-after-move.rs:4:12
|
LL | fn foo(self) -> String;
| ^^^^
error[E0382]: borrow of moved value: `x`
--> $DIR/borrow-after-move.rs:39:24
......
......@@ -34,9 +34,15 @@ error[E0382]: use of moved value: `y`
LL | let y = *x;
| - move occurs because `y` has type `str`, which does not implement the `Copy` trait
LL | y.foo();
| - value moved here
| ----- `y` moved due to this method call
LL | y.foo();
| ^ value used here after move
|
note: this function consumes the receiver `self` by taking ownership of it, which moves `y`
--> $DIR/double-move.rs:4:12
|
LL | fn foo(self) -> String;
| ^^^^
error[E0382]: use of moved value: `x`
--> $DIR/double-move.rs:45:9
......
......@@ -4,9 +4,15 @@ error[E0382]: use of moved value: `self`
LL | pub fn foo(self) -> isize {
| ---- move occurs because `self` has type `S`, which does not implement the `Copy` trait
LL | self.bar();
| ---- value moved here
| ----- `self` moved due to this method call
LL | return self.x;
| ^^^^^^ value used here after move
|
note: this function consumes the receiver `self` by taking ownership of it, which moves `self`
--> $DIR/use-after-move-self-based-on-type.rs:15:16
|
LL | pub fn bar(self) {}
| ^^^^
error: aborting due to previous error
......
......@@ -4,9 +4,15 @@ error[E0382]: use of moved value: `self`
LL | pub fn foo(self) -> isize {
| ---- move occurs because `self` has type `S`, which does not implement the `Copy` trait
LL | self.bar();
| ---- value moved here
| ----- `self` moved due to this method call
LL | return *self.x;
| ^^^^^^^ value used here after move
|
note: this function consumes the receiver `self` by taking ownership of it, which moves `self`
--> $DIR/use-after-move-self.rs:13:16
|
LL | pub fn bar(self) {}
| ^^^^
error: aborting due to previous error
......
......@@ -4,9 +4,15 @@ error[E0382]: borrow of moved value: `start`
LL | let start = Mine{test:"Foo".to_string(), other_val:0};
| ----- move occurs because `start` has type `Mine`, which does not implement the `Copy` trait
LL | let end = Mine{other_val:1, ..start.make_string_bar()};
| ----- value moved here
| ----------------- `start` moved due to this method call
LL | println!("{}", start.test);
| ^^^^^^^^^^ value borrowed here after move
|
note: this function consumes the receiver `self` by taking ownership of it, which moves `start`
--> $DIR/walk-struct-literal-with.rs:7:28
|
LL | fn make_string_bar(mut self) -> Mine{
| ^^^^
error: aborting due to previous error
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册