mirror of
https://github.com/rust-lang/rust.git
synced 2025-04-15 05:26:47 +00:00
Auto merge of #78458 - Dylan-DPC:rollup-tan044s, r=Dylan-DPC
Rollup of 10 pull requests Successful merges: - #78152 (Separate unsized locals) - #78297 (Suggest calling await on method call and field access) - #78351 (Move "mutable thing in const" check from interning to validity) - #78365 (check object safety of generic constants) - #78379 (Tweak invalid `fn` header and body parsing) - #78391 (Add const_fn in generics test) - #78401 (resolve: private fields in tuple struct ctor diag) - #78408 (Remove tokens from foreign items in `TokenStripper`) - #78447 (Fix typo in comment) - #78453 (Fix typo in comments) Failed merges: r? `@ghost`
This commit is contained in:
commit
db241bb0c8
@ -533,7 +533,7 @@ impl DropArena {
|
||||
ptr::write(mem, object);
|
||||
let result = &mut *mem;
|
||||
// Record the destructor after doing the allocation as that may panic
|
||||
// and would cause `object`'s destuctor to run twice if it was recorded before
|
||||
// and would cause `object`'s destructor to run twice if it was recorded before
|
||||
self.destructors
|
||||
.borrow_mut()
|
||||
.push(DropType { drop_fn: drop_for_type::<T>, obj: result as *mut T as *mut u8 });
|
||||
@ -560,7 +560,7 @@ impl DropArena {
|
||||
mem::forget(vec.drain(..));
|
||||
|
||||
// Record the destructors after doing the allocation as that may panic
|
||||
// and would cause `object`'s destuctor to run twice if it was recorded before
|
||||
// and would cause `object`'s destructor to run twice if it was recorded before
|
||||
for i in 0..len {
|
||||
destructors.push(DropType {
|
||||
drop_fn: drop_for_type::<T>,
|
||||
|
@ -29,7 +29,7 @@ impl<N: Idx> VecGraph<N> {
|
||||
|
||||
// Create the *edge starts* array. We are iterating over over
|
||||
// the (sorted) edge pairs. We maintain the invariant that the
|
||||
// length of the `node_starts` arary is enough to store the
|
||||
// length of the `node_starts` array is enough to store the
|
||||
// current source node -- so when we see that the source node
|
||||
// for an edge is greater than the current length, we grow the
|
||||
// edge-starts array by just enough.
|
||||
|
@ -607,6 +607,9 @@ declare_features! (
|
||||
/// Allow anonymous constants from an inline `const` block
|
||||
(active, inline_const, "1.49.0", Some(76001), None),
|
||||
|
||||
/// Allows unsized fn parameters.
|
||||
(active, unsized_fn_params, "1.49.0", Some(48055), None),
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// feature-group-end: actual feature gates
|
||||
// -------------------------------------------------------------------------
|
||||
@ -629,6 +632,7 @@ pub const INCOMPLETE_FEATURES: &[Symbol] = &[
|
||||
sym::specialization,
|
||||
sym::inline_const,
|
||||
sym::repr128,
|
||||
sym::unsized_locals,
|
||||
];
|
||||
|
||||
/// Some features are not allowed to be used together at the same time, if
|
||||
|
@ -1669,7 +1669,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||
self.note_error_origin(diag, cause, exp_found);
|
||||
}
|
||||
|
||||
fn get_impl_future_output_ty(&self, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
|
||||
pub fn get_impl_future_output_ty(&self, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
|
||||
if let ty::Opaque(def_id, substs) = ty.kind() {
|
||||
let future_trait = self.tcx.require_lang_item(LangItem::Future, None);
|
||||
// Future::Output
|
||||
|
@ -63,6 +63,13 @@ impl mut_visit::MutVisitor for TokenStripper {
|
||||
i.tokens = None;
|
||||
mut_visit::noop_flat_map_item(i, self)
|
||||
}
|
||||
fn flat_map_foreign_item(
|
||||
&mut self,
|
||||
mut i: P<ast::ForeignItem>,
|
||||
) -> SmallVec<[P<ast::ForeignItem>; 1]> {
|
||||
i.tokens = None;
|
||||
mut_visit::noop_flat_map_foreign_item(i, self)
|
||||
}
|
||||
fn visit_block(&mut self, b: &mut P<ast::Block>) {
|
||||
b.tokens = None;
|
||||
mut_visit::noop_visit_block(b, self);
|
||||
|
@ -210,16 +210,6 @@ pub struct Body<'tcx> {
|
||||
/// We hold in this field all the constants we are not able to evaluate yet.
|
||||
pub required_consts: Vec<Constant<'tcx>>,
|
||||
|
||||
/// The user may be writing e.g. `&[(SOME_CELL, 42)][i].1` and this would get promoted, because
|
||||
/// we'd statically know that no thing with interior mutability will ever be available to the
|
||||
/// user without some serious unsafe code. Now this means that our promoted is actually
|
||||
/// `&[(SOME_CELL, 42)]` and the MIR using it will do the `&promoted[i].1` projection because
|
||||
/// the index may be a runtime value. Such a promoted value is illegal because it has reachable
|
||||
/// interior mutability. This flag just makes this situation very obvious where the previous
|
||||
/// implementation without the flag hid this situation silently.
|
||||
/// FIXME(oli-obk): rewrite the promoted during promotion to eliminate the cell components.
|
||||
pub ignore_interior_mut_in_const_validation: bool,
|
||||
|
||||
/// Does this body use generic parameters. This is used for the `ConstEvaluatable` check.
|
||||
///
|
||||
/// Note that this does not actually mean that this body is not computable right now.
|
||||
@ -276,7 +266,6 @@ impl<'tcx> Body<'tcx> {
|
||||
var_debug_info,
|
||||
span,
|
||||
required_consts: Vec::new(),
|
||||
ignore_interior_mut_in_const_validation: false,
|
||||
is_polymorphic: false,
|
||||
predecessor_cache: PredecessorCache::new(),
|
||||
};
|
||||
@ -306,7 +295,6 @@ impl<'tcx> Body<'tcx> {
|
||||
required_consts: Vec::new(),
|
||||
generator_kind: None,
|
||||
var_debug_info: Vec::new(),
|
||||
ignore_interior_mut_in_const_validation: false,
|
||||
is_polymorphic: false,
|
||||
predecessor_cache: PredecessorCache::new(),
|
||||
};
|
||||
|
@ -974,6 +974,11 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
checker
|
||||
}
|
||||
|
||||
fn unsized_feature_enabled(&self) -> bool {
|
||||
let features = self.tcx().features();
|
||||
features.unsized_locals || features.unsized_fn_params
|
||||
}
|
||||
|
||||
/// Equate the inferred type and the annotated type for user type annotations
|
||||
fn check_user_type_annotations(&mut self) {
|
||||
debug!(
|
||||
@ -1456,7 +1461,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
}
|
||||
|
||||
self.check_rvalue(body, rv, location);
|
||||
if !self.tcx().features().unsized_locals {
|
||||
if !self.unsized_feature_enabled() {
|
||||
let trait_ref = ty::TraitRef {
|
||||
def_id: tcx.require_lang_item(LangItem::Sized, Some(self.last_span)),
|
||||
substs: tcx.mk_substs_trait(place_ty, &[]),
|
||||
@ -1717,9 +1722,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
);
|
||||
}
|
||||
|
||||
// When `#![feature(unsized_locals)]` is not enabled,
|
||||
// When `unsized_fn_params` and `unsized_locals` are both not enabled,
|
||||
// this check is done at `check_local`.
|
||||
if self.tcx().features().unsized_locals {
|
||||
if self.unsized_feature_enabled() {
|
||||
let span = term.source_info.span;
|
||||
self.ensure_place_sized(dest_ty, span);
|
||||
}
|
||||
@ -1880,9 +1885,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
LocalKind::Var | LocalKind::Temp => {}
|
||||
}
|
||||
|
||||
// When `#![feature(unsized_locals)]` is enabled, only function calls
|
||||
// When `unsized_fn_params` or `unsized_locals` is enabled, only function calls
|
||||
// and nullary ops are checked in `check_call_dest`.
|
||||
if !self.tcx().features().unsized_locals {
|
||||
if !self.unsized_feature_enabled() {
|
||||
let span = local_decl.source_info.span;
|
||||
let ty = local_decl.ty;
|
||||
self.ensure_place_sized(ty, span);
|
||||
@ -2024,7 +2029,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
|
||||
Rvalue::NullaryOp(_, ty) => {
|
||||
// Even with unsized locals cannot box an unsized value.
|
||||
if self.tcx().features().unsized_locals {
|
||||
if self.unsized_feature_enabled() {
|
||||
let span = body.source_info(location).span;
|
||||
self.ensure_place_sized(ty, span);
|
||||
}
|
||||
|
@ -1,8 +1,8 @@
|
||||
use super::{CompileTimeEvalContext, CompileTimeInterpreter, ConstEvalErr, MemoryExtra};
|
||||
use crate::interpret::eval_nullary_intrinsic;
|
||||
use crate::interpret::{
|
||||
intern_const_alloc_recursive, Allocation, ConstAlloc, ConstValue, GlobalId, Immediate,
|
||||
InternKind, InterpCx, InterpResult, MPlaceTy, MemoryKind, OpTy, RefTracking, Scalar,
|
||||
intern_const_alloc_recursive, Allocation, ConstAlloc, ConstValue, CtfeValidationMode, GlobalId,
|
||||
Immediate, InternKind, InterpCx, InterpResult, MPlaceTy, MemoryKind, OpTy, RefTracking, Scalar,
|
||||
ScalarMaybeUninit, StackPopCleanup,
|
||||
};
|
||||
|
||||
@ -59,23 +59,15 @@ fn eval_body_using_ecx<'mir, 'tcx>(
|
||||
ecx.run()?;
|
||||
|
||||
// Intern the result
|
||||
// FIXME: since the DefId of a promoted is the DefId of its owner, this
|
||||
// means that promoteds in statics are actually interned like statics!
|
||||
// However, this is also currently crucial because we promote mutable
|
||||
// non-empty slices in statics to extend their lifetime, and this
|
||||
// ensures that they are put into a mutable allocation.
|
||||
// For other kinds of promoteds in statics (like array initializers), this is rather silly.
|
||||
let intern_kind = match tcx.static_mutability(cid.instance.def_id()) {
|
||||
Some(m) => InternKind::Static(m),
|
||||
None if cid.promoted.is_some() => InternKind::Promoted,
|
||||
_ => InternKind::Constant,
|
||||
let intern_kind = if cid.promoted.is_some() {
|
||||
InternKind::Promoted
|
||||
} else {
|
||||
match tcx.static_mutability(cid.instance.def_id()) {
|
||||
Some(m) => InternKind::Static(m),
|
||||
None => InternKind::Constant,
|
||||
}
|
||||
};
|
||||
intern_const_alloc_recursive(
|
||||
ecx,
|
||||
intern_kind,
|
||||
ret,
|
||||
body.ignore_interior_mut_in_const_validation,
|
||||
);
|
||||
intern_const_alloc_recursive(ecx, intern_kind, ret);
|
||||
|
||||
debug!("eval_body_using_ecx done: {:?}", *ret);
|
||||
Ok(ret)
|
||||
@ -376,16 +368,23 @@ pub fn eval_to_allocation_raw_provider<'tcx>(
|
||||
// Since evaluation had no errors, valiate the resulting constant:
|
||||
let validation = try {
|
||||
// FIXME do not validate promoteds until a decision on
|
||||
// https://github.com/rust-lang/rust/issues/67465 is made
|
||||
// https://github.com/rust-lang/rust/issues/67465 and
|
||||
// https://github.com/rust-lang/rust/issues/67534 is made.
|
||||
// Promoteds can contain unexpected `UnsafeCell` and reference `static`s, but their
|
||||
// otherwise restricted form ensures that this is still sound. We just lose the
|
||||
// extra safety net of some of the dynamic checks. They can also contain invalid
|
||||
// values, but since we do not usually check intermediate results of a computation
|
||||
// for validity, it might be surprising to do that here.
|
||||
if cid.promoted.is_none() {
|
||||
let mut ref_tracking = RefTracking::new(mplace);
|
||||
let mut inner = false;
|
||||
while let Some((mplace, path)) = ref_tracking.todo.pop() {
|
||||
ecx.const_validate_operand(
|
||||
mplace.into(),
|
||||
path,
|
||||
&mut ref_tracking,
|
||||
/*may_ref_to_static*/ ecx.memory.extra.can_access_statics,
|
||||
)?;
|
||||
let mode = match tcx.static_mutability(cid.instance.def_id()) {
|
||||
Some(_) => CtfeValidationMode::Regular, // a `static`
|
||||
None => CtfeValidationMode::Const { inner },
|
||||
};
|
||||
ecx.const_validate_operand(mplace.into(), path, &mut ref_tracking, mode)?;
|
||||
inner = true;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -29,7 +29,7 @@ pub(crate) fn const_caller_location(
|
||||
let mut ecx = mk_eval_cx(tcx, DUMMY_SP, ty::ParamEnv::reveal_all(), false);
|
||||
|
||||
let loc_place = ecx.alloc_caller_location(file, line, col);
|
||||
intern_const_alloc_recursive(&mut ecx, InternKind::Constant, loc_place, false);
|
||||
intern_const_alloc_recursive(&mut ecx, InternKind::Constant, loc_place);
|
||||
ConstValue::Scalar(loc_place.ptr)
|
||||
}
|
||||
|
||||
|
@ -2,12 +2,23 @@
|
||||
//!
|
||||
//! After a const evaluation has computed a value, before we destroy the const evaluator's session
|
||||
//! memory, we need to extract all memory allocations to the global memory pool so they stay around.
|
||||
//!
|
||||
//! In principle, this is not very complicated: we recursively walk the final value, follow all the
|
||||
//! pointers, and move all reachable allocations to the global `tcx` memory. The only complication
|
||||
//! is picking the right mutability for the allocations in a `static` initializer: we want to make
|
||||
//! as many allocations as possible immutable so LLVM can put them into read-only memory. At the
|
||||
//! same time, we need to make memory that could be mutated by the program mutable to avoid
|
||||
//! incorrect compilations. To achieve this, we do a type-based traversal of the final value,
|
||||
//! tracking mutable and shared references and `UnsafeCell` to determine the current mutability.
|
||||
//! (In principle, we could skip this type-based part for `const` and promoteds, as they need to be
|
||||
//! always immutable. At least for `const` however we use this opportunity to reject any `const`
|
||||
//! that contains allocations whose mutability we cannot identify.)
|
||||
|
||||
use super::validity::RefTracking;
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
use rustc_hir as hir;
|
||||
use rustc_middle::mir::interpret::InterpResult;
|
||||
use rustc_middle::ty::{self, layout::TyAndLayout, query::TyCtxtAt, Ty};
|
||||
use rustc_middle::ty::{self, layout::TyAndLayout, Ty};
|
||||
use rustc_target::abi::Size;
|
||||
|
||||
use rustc_ast::Mutability;
|
||||
@ -40,11 +51,6 @@ struct InternVisitor<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx>> {
|
||||
/// This field stores whether we are *currently* inside an `UnsafeCell`. This can affect
|
||||
/// the intern mode of references we encounter.
|
||||
inside_unsafe_cell: bool,
|
||||
|
||||
/// This flag is to avoid triggering UnsafeCells are not allowed behind references in constants
|
||||
/// for promoteds.
|
||||
/// It's a copy of `mir::Body`'s ignore_interior_mut_in_const_validation field
|
||||
ignore_interior_mut_in_const: bool,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Hash, Eq)]
|
||||
@ -53,22 +59,14 @@ enum InternMode {
|
||||
/// this is *immutable*, and below mutable references inside an `UnsafeCell`, this
|
||||
/// is *mutable*.
|
||||
Static(hir::Mutability),
|
||||
/// The "base value" of a const, which can have `UnsafeCell` (as in `const FOO: Cell<i32>`),
|
||||
/// but that interior mutability is simply ignored.
|
||||
ConstBase,
|
||||
/// The "inner values" of a const with references, where `UnsafeCell` is an error.
|
||||
ConstInner,
|
||||
/// A `const`.
|
||||
Const,
|
||||
}
|
||||
|
||||
/// Signalling data structure to ensure we don't recurse
|
||||
/// into the memory of other constants or statics
|
||||
struct IsStaticOrFn;
|
||||
|
||||
fn mutable_memory_in_const(tcx: TyCtxtAt<'_>, kind: &str) {
|
||||
// FIXME: show this in validation instead so we can point at where in the value the error is?
|
||||
tcx.sess.span_err(tcx.span, &format!("mutable memory ({}) is not allowed in constant", kind));
|
||||
}
|
||||
|
||||
/// Intern an allocation without looking at its children.
|
||||
/// `mode` is the mode of the environment where we found this pointer.
|
||||
/// `mutablity` is the mutability of the place to be interned; even if that says
|
||||
@ -129,9 +127,7 @@ fn intern_shallow<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx>>(
|
||||
// See const_eval::machine::MemoryExtra::can_access_statics for why
|
||||
// immutability is so important.
|
||||
|
||||
// There are no sensible checks we can do here; grep for `mutable_memory_in_const` to
|
||||
// find the checks we are doing elsewhere to avoid even getting here for memory
|
||||
// that "wants" to be mutable.
|
||||
// Validation will ensure that there is no `UnsafeCell` on an immutable allocation.
|
||||
alloc.mutability = Mutability::Not;
|
||||
};
|
||||
// link the alloc id to the actual allocation
|
||||
@ -167,17 +163,13 @@ impl<'rt, 'mir, 'tcx: 'mir, M: CompileTimeMachine<'mir, 'tcx>> ValueVisitor<'mir
|
||||
mplace: MPlaceTy<'tcx>,
|
||||
fields: impl Iterator<Item = InterpResult<'tcx, Self::V>>,
|
||||
) -> InterpResult<'tcx> {
|
||||
// ZSTs cannot contain pointers, so we can skip them.
|
||||
if mplace.layout.is_zst() {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
if let Some(def) = mplace.layout.ty.ty_adt_def() {
|
||||
if Some(def.did) == self.ecx.tcx.lang_items().unsafe_cell_type() {
|
||||
if self.mode == InternMode::ConstInner && !self.ignore_interior_mut_in_const {
|
||||
// We do not actually make this memory mutable. But in case the user
|
||||
// *expected* it to be mutable, make sure we error. This is just a
|
||||
// sanity check to prevent users from accidentally exploiting the UB
|
||||
// they caused. It also helps us to find cases where const-checking
|
||||
// failed to prevent an `UnsafeCell` (but as `ignore_interior_mut_in_const`
|
||||
// shows that part is not airtight).
|
||||
mutable_memory_in_const(self.ecx.tcx, "`UnsafeCell`");
|
||||
}
|
||||
// We are crossing over an `UnsafeCell`, we can mutate again. This means that
|
||||
// References we encounter inside here are interned as pointing to mutable
|
||||
// allocations.
|
||||
@ -189,11 +181,6 @@ impl<'rt, 'mir, 'tcx: 'mir, M: CompileTimeMachine<'mir, 'tcx>> ValueVisitor<'mir
|
||||
}
|
||||
}
|
||||
|
||||
// ZSTs cannot contain pointers, so we can skip them.
|
||||
if mplace.layout.is_zst() {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
self.walk_aggregate(mplace, fields)
|
||||
}
|
||||
|
||||
@ -213,7 +200,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: CompileTimeMachine<'mir, 'tcx>> ValueVisitor<'mir
|
||||
if let Scalar::Ptr(vtable) = mplace.meta.unwrap_meta() {
|
||||
// Explicitly choose const mode here, since vtables are immutable, even
|
||||
// if the reference of the fat pointer is mutable.
|
||||
self.intern_shallow(vtable.alloc_id, InternMode::ConstInner, None);
|
||||
self.intern_shallow(vtable.alloc_id, InternMode::Const, None);
|
||||
} else {
|
||||
// Validation will error (with a better message) on an invalid vtable pointer.
|
||||
// Let validation show the error message, but make sure it *does* error.
|
||||
@ -225,7 +212,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: CompileTimeMachine<'mir, 'tcx>> ValueVisitor<'mir
|
||||
// Only recurse for allocation-backed pointers.
|
||||
if let Scalar::Ptr(ptr) = mplace.ptr {
|
||||
// Compute the mode with which we intern this. Our goal here is to make as many
|
||||
// statics as we can immutable so they can be placed in const memory by LLVM.
|
||||
// statics as we can immutable so they can be placed in read-only memory by LLVM.
|
||||
let ref_mode = match self.mode {
|
||||
InternMode::Static(mutbl) => {
|
||||
// In statics, merge outer mutability with reference mutability and
|
||||
@ -259,27 +246,11 @@ impl<'rt, 'mir, 'tcx: 'mir, M: CompileTimeMachine<'mir, 'tcx>> ValueVisitor<'mir
|
||||
}
|
||||
}
|
||||
}
|
||||
InternMode::ConstBase | InternMode::ConstInner => {
|
||||
// Ignore `UnsafeCell`, everything is immutable. Do some sanity checking
|
||||
// for mutable references that we encounter -- they must all be ZST.
|
||||
// This helps to prevent users from accidentally exploiting UB that they
|
||||
// caused (by somehow getting a mutable reference in a `const`).
|
||||
if ref_mutability == Mutability::Mut {
|
||||
match referenced_ty.kind() {
|
||||
ty::Array(_, n) if n.eval_usize(*tcx, self.ecx.param_env) == 0 => {}
|
||||
ty::Slice(_)
|
||||
if mplace.meta.unwrap_meta().to_machine_usize(self.ecx)?
|
||||
== 0 => {}
|
||||
_ => mutable_memory_in_const(tcx, "`&mut`"),
|
||||
}
|
||||
} else {
|
||||
// A shared reference. We cannot check `freeze` here due to references
|
||||
// like `&dyn Trait` that are actually immutable. We do check for
|
||||
// concrete `UnsafeCell` when traversing the pointee though (if it is
|
||||
// a new allocation, not yet interned).
|
||||
}
|
||||
// Go on with the "inner" rules.
|
||||
InternMode::ConstInner
|
||||
InternMode::Const => {
|
||||
// Ignore `UnsafeCell`, everything is immutable. Validity does some sanity
|
||||
// checking for mutable references that we encounter -- they must all be
|
||||
// ZST.
|
||||
InternMode::Const
|
||||
}
|
||||
};
|
||||
match self.intern_shallow(ptr.alloc_id, ref_mode, Some(referenced_ty)) {
|
||||
@ -318,7 +289,6 @@ pub fn intern_const_alloc_recursive<M: CompileTimeMachine<'mir, 'tcx>>(
|
||||
ecx: &mut InterpCx<'mir, 'tcx, M>,
|
||||
intern_kind: InternKind,
|
||||
ret: MPlaceTy<'tcx>,
|
||||
ignore_interior_mut_in_const: bool,
|
||||
) where
|
||||
'tcx: 'mir,
|
||||
{
|
||||
@ -327,7 +297,7 @@ pub fn intern_const_alloc_recursive<M: CompileTimeMachine<'mir, 'tcx>>(
|
||||
InternKind::Static(mutbl) => InternMode::Static(mutbl),
|
||||
// `Constant` includes array lengths.
|
||||
// `Promoted` includes non-`Copy` array initializers and `rustc_args_required_const` arguments.
|
||||
InternKind::Constant | InternKind::Promoted => InternMode::ConstBase,
|
||||
InternKind::Constant | InternKind::Promoted => InternMode::Const,
|
||||
};
|
||||
|
||||
// Type based interning.
|
||||
@ -357,7 +327,6 @@ pub fn intern_const_alloc_recursive<M: CompileTimeMachine<'mir, 'tcx>>(
|
||||
ecx,
|
||||
mode,
|
||||
leftover_allocations,
|
||||
ignore_interior_mut_in_const,
|
||||
inside_unsafe_cell: false,
|
||||
}
|
||||
.visit_value(mplace);
|
||||
|
@ -24,7 +24,7 @@ pub use self::machine::{compile_time_machine, AllocMap, Machine, MayLeak, StackP
|
||||
pub use self::memory::{AllocCheck, FnVal, Memory, MemoryKind};
|
||||
pub use self::operand::{ImmTy, Immediate, OpTy, Operand};
|
||||
pub use self::place::{MPlaceTy, MemPlace, MemPlaceMeta, Place, PlaceTy};
|
||||
pub use self::validity::RefTracking;
|
||||
pub use self::validity::{CtfeValidationMode, RefTracking};
|
||||
pub use self::visitor::{MutValueVisitor, ValueVisitor};
|
||||
|
||||
crate use self::intrinsics::eval_nullary_intrinsic;
|
||||
|
@ -113,6 +113,17 @@ pub enum PathElem {
|
||||
DynDowncast,
|
||||
}
|
||||
|
||||
/// Extra things to check for during validation of CTFE results.
|
||||
pub enum CtfeValidationMode {
|
||||
/// Regular validation, nothing special happening.
|
||||
Regular,
|
||||
/// Validation of a `const`. `inner` says if this is an inner, indirect allocation (as opposed
|
||||
/// to the top-level const allocation).
|
||||
/// Being an inner allocation makes a difference because the top-level allocation of a `const`
|
||||
/// is copied for each use, but the inner allocations are implicitly shared.
|
||||
Const { inner: bool },
|
||||
}
|
||||
|
||||
/// State for tracking recursive validation of references
|
||||
pub struct RefTracking<T, PATH = ()> {
|
||||
pub seen: FxHashSet<T>,
|
||||
@ -202,9 +213,9 @@ struct ValidityVisitor<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> {
|
||||
/// starts must not be changed! `visit_fields` and `visit_array` rely on
|
||||
/// this stack discipline.
|
||||
path: Vec<PathElem>,
|
||||
ref_tracking_for_consts:
|
||||
Option<&'rt mut RefTracking<MPlaceTy<'tcx, M::PointerTag>, Vec<PathElem>>>,
|
||||
may_ref_to_static: bool,
|
||||
ref_tracking: Option<&'rt mut RefTracking<MPlaceTy<'tcx, M::PointerTag>, Vec<PathElem>>>,
|
||||
/// `None` indicates this is not validating for CTFE (but for runtime).
|
||||
ctfe_mode: Option<CtfeValidationMode>,
|
||||
ecx: &'rt InterpCx<'mir, 'tcx, M>,
|
||||
}
|
||||
|
||||
@ -418,7 +429,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
|
||||
{ "a dangling {} (use-after-free)", kind },
|
||||
);
|
||||
// Recursive checking
|
||||
if let Some(ref mut ref_tracking) = self.ref_tracking_for_consts {
|
||||
if let Some(ref mut ref_tracking) = self.ref_tracking {
|
||||
if let Some(ptr) = ptr {
|
||||
// not a ZST
|
||||
// Skip validation entirely for some external statics
|
||||
@ -426,19 +437,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
|
||||
if let Some(GlobalAlloc::Static(did)) = alloc_kind {
|
||||
assert!(!self.ecx.tcx.is_thread_local_static(did));
|
||||
assert!(self.ecx.tcx.is_static(did));
|
||||
if self.may_ref_to_static {
|
||||
// We skip checking other statics. These statics must be sound by
|
||||
// themselves, and the only way to get broken statics here is by using
|
||||
// unsafe code.
|
||||
// The reasons we don't check other statics is twofold. For one, in all
|
||||
// sound cases, the static was already validated on its own, and second, we
|
||||
// trigger cycle errors if we try to compute the value of the other static
|
||||
// and that static refers back to us.
|
||||
// We might miss const-invalid data,
|
||||
// but things are still sound otherwise (in particular re: consts
|
||||
// referring to statics).
|
||||
return Ok(());
|
||||
} else {
|
||||
if matches!(self.ctfe_mode, Some(CtfeValidationMode::Const { .. })) {
|
||||
// See const_eval::machine::MemoryExtra::can_access_statics for why
|
||||
// this check is so important.
|
||||
// This check is reachable when the const just referenced the static,
|
||||
@ -447,6 +446,17 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
|
||||
{ "a {} pointing to a static variable", kind }
|
||||
);
|
||||
}
|
||||
// We skip checking other statics. These statics must be sound by
|
||||
// themselves, and the only way to get broken statics here is by using
|
||||
// unsafe code.
|
||||
// The reasons we don't check other statics is twofold. For one, in all
|
||||
// sound cases, the static was already validated on its own, and second, we
|
||||
// trigger cycle errors if we try to compute the value of the other static
|
||||
// and that static refers back to us.
|
||||
// We might miss const-invalid data,
|
||||
// but things are still sound otherwise (in particular re: consts
|
||||
// referring to statics).
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
// Proceed recursively even for ZST, no reason to skip them!
|
||||
@ -504,7 +514,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
|
||||
let value = self.ecx.read_scalar(value)?;
|
||||
// NOTE: Keep this in sync with the array optimization for int/float
|
||||
// types below!
|
||||
if self.ref_tracking_for_consts.is_some() {
|
||||
if self.ctfe_mode.is_some() {
|
||||
// Integers/floats in CTFE: Must be scalar bits, pointers are dangerous
|
||||
let is_bits = value.check_init().map_or(false, |v| v.is_bits());
|
||||
if !is_bits {
|
||||
@ -532,7 +542,17 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
|
||||
}
|
||||
Ok(true)
|
||||
}
|
||||
ty::Ref(..) => {
|
||||
ty::Ref(_, ty, mutbl) => {
|
||||
if matches!(self.ctfe_mode, Some(CtfeValidationMode::Const { .. }))
|
||||
&& *mutbl == hir::Mutability::Mut
|
||||
{
|
||||
// A mutable reference inside a const? That does not seem right (except if it is
|
||||
// a ZST).
|
||||
let layout = self.ecx.layout_of(ty)?;
|
||||
if !layout.is_zst() {
|
||||
throw_validation_failure!(self.path, { "mutable reference in a `const`" });
|
||||
}
|
||||
}
|
||||
self.check_safe_pointer(value, "reference")?;
|
||||
Ok(true)
|
||||
}
|
||||
@ -723,6 +743,15 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
|
||||
// Sanity check: `builtin_deref` does not know any pointers that are not primitive.
|
||||
assert!(op.layout.ty.builtin_deref(true).is_none());
|
||||
|
||||
// Special check preventing `UnsafeCell` in constants
|
||||
if let Some(def) = op.layout.ty.ty_adt_def() {
|
||||
if matches!(self.ctfe_mode, Some(CtfeValidationMode::Const { inner: true }))
|
||||
&& Some(def.did) == self.ecx.tcx.lang_items().unsafe_cell_type()
|
||||
{
|
||||
throw_validation_failure!(self.path, { "`UnsafeCell` in a `const`" });
|
||||
}
|
||||
}
|
||||
|
||||
// Recursively walk the value at its type.
|
||||
self.walk_value(op)?;
|
||||
|
||||
@ -814,7 +843,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
|
||||
self.ecx,
|
||||
ptr,
|
||||
size,
|
||||
/*allow_uninit_and_ptr*/ self.ref_tracking_for_consts.is_none(),
|
||||
/*allow_uninit_and_ptr*/ self.ctfe_mode.is_none(),
|
||||
) {
|
||||
// In the happy case, we needn't check anything else.
|
||||
Ok(()) => {}
|
||||
@ -865,16 +894,13 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
&self,
|
||||
op: OpTy<'tcx, M::PointerTag>,
|
||||
path: Vec<PathElem>,
|
||||
ref_tracking_for_consts: Option<
|
||||
&mut RefTracking<MPlaceTy<'tcx, M::PointerTag>, Vec<PathElem>>,
|
||||
>,
|
||||
may_ref_to_static: bool,
|
||||
ref_tracking: Option<&mut RefTracking<MPlaceTy<'tcx, M::PointerTag>, Vec<PathElem>>>,
|
||||
ctfe_mode: Option<CtfeValidationMode>,
|
||||
) -> InterpResult<'tcx> {
|
||||
trace!("validate_operand_internal: {:?}, {:?}", *op, op.layout.ty);
|
||||
|
||||
// Construct a visitor
|
||||
let mut visitor =
|
||||
ValidityVisitor { path, ref_tracking_for_consts, may_ref_to_static, ecx: self };
|
||||
let mut visitor = ValidityVisitor { path, ref_tracking, ctfe_mode, ecx: self };
|
||||
|
||||
// Try to cast to ptr *once* instead of all the time.
|
||||
let op = self.force_op_ptr(op).unwrap_or(op);
|
||||
@ -902,16 +928,18 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
/// `ref_tracking` is used to record references that we encounter so that they
|
||||
/// can be checked recursively by an outside driving loop.
|
||||
///
|
||||
/// `may_ref_to_static` controls whether references are allowed to point to statics.
|
||||
/// `constant` controls whether this must satisfy the rules for constants:
|
||||
/// - no pointers to statics.
|
||||
/// - no `UnsafeCell` or non-ZST `&mut`.
|
||||
#[inline(always)]
|
||||
pub fn const_validate_operand(
|
||||
&self,
|
||||
op: OpTy<'tcx, M::PointerTag>,
|
||||
path: Vec<PathElem>,
|
||||
ref_tracking: &mut RefTracking<MPlaceTy<'tcx, M::PointerTag>, Vec<PathElem>>,
|
||||
may_ref_to_static: bool,
|
||||
ctfe_mode: CtfeValidationMode,
|
||||
) -> InterpResult<'tcx> {
|
||||
self.validate_operand_internal(op, path, Some(ref_tracking), may_ref_to_static)
|
||||
self.validate_operand_internal(op, path, Some(ref_tracking), Some(ctfe_mode))
|
||||
}
|
||||
|
||||
/// This function checks the data at `op` to be runtime-valid.
|
||||
@ -919,6 +947,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
/// It will error if the bits at the destination do not match the ones described by the layout.
|
||||
#[inline(always)]
|
||||
pub fn validate_operand(&self, op: OpTy<'tcx, M::PointerTag>) -> InterpResult<'tcx> {
|
||||
self.validate_operand_internal(op, vec![], None, false)
|
||||
self.validate_operand_internal(op, vec![], None, None)
|
||||
}
|
||||
}
|
||||
|
@ -9,7 +9,6 @@ use rustc_hir::def::DefKind;
|
||||
use rustc_hir::HirId;
|
||||
use rustc_index::bit_set::BitSet;
|
||||
use rustc_index::vec::IndexVec;
|
||||
use rustc_middle::mir::interpret::{InterpResult, Scalar};
|
||||
use rustc_middle::mir::visit::{
|
||||
MutVisitor, MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor,
|
||||
};
|
||||
@ -28,9 +27,10 @@ use rustc_trait_selection::traits;
|
||||
|
||||
use crate::const_eval::ConstEvalErr;
|
||||
use crate::interpret::{
|
||||
self, compile_time_machine, truncate, AllocId, Allocation, ConstValue, Frame, ImmTy, Immediate,
|
||||
InterpCx, LocalState, LocalValue, MemPlace, Memory, MemoryKind, OpTy, Operand as InterpOperand,
|
||||
PlaceTy, Pointer, ScalarMaybeUninit, StackPopCleanup,
|
||||
self, compile_time_machine, truncate, AllocId, Allocation, ConstValue, CtfeValidationMode,
|
||||
Frame, ImmTy, Immediate, InterpCx, InterpResult, LocalState, LocalValue, MemPlace, Memory,
|
||||
MemoryKind, OpTy, Operand as InterpOperand, PlaceTy, Pointer, Scalar, ScalarMaybeUninit,
|
||||
StackPopCleanup,
|
||||
};
|
||||
use crate::transform::MirPass;
|
||||
|
||||
@ -805,8 +805,9 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
|
||||
value,
|
||||
vec![],
|
||||
// FIXME: is ref tracking too expensive?
|
||||
// FIXME: what is the point of ref tracking if we do not even check the tracked refs?
|
||||
&mut interpret::RefTracking::empty(),
|
||||
/*may_ref_to_static*/ true,
|
||||
CtfeValidationMode::Regular,
|
||||
) {
|
||||
trace!("validation error, attempt failed: {:?}", e);
|
||||
return;
|
||||
|
@ -1170,7 +1170,7 @@ pub fn promote_candidates<'tcx>(
|
||||
let mut scope = body.source_scopes[candidate.source_info(body).scope].clone();
|
||||
scope.parent_scope = None;
|
||||
|
||||
let mut promoted = Body::new(
|
||||
let promoted = Body::new(
|
||||
body.source, // `promoted` gets filled in below
|
||||
IndexVec::new(),
|
||||
IndexVec::from_elem_n(scope, 1),
|
||||
@ -1181,7 +1181,6 @@ pub fn promote_candidates<'tcx>(
|
||||
body.span,
|
||||
body.generator_kind,
|
||||
);
|
||||
promoted.ignore_interior_mut_in_const_validation = true;
|
||||
|
||||
let promoter = Promoter {
|
||||
promoted,
|
||||
|
@ -165,7 +165,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
|
||||
let tcx = this.hir.tcx();
|
||||
|
||||
if tcx.features().unsized_locals {
|
||||
if tcx.features().unsized_fn_params {
|
||||
let ty = expr.ty;
|
||||
let span = expr.span;
|
||||
let param_env = this.hir.param_env;
|
||||
|
@ -1557,14 +1557,6 @@ impl<'a> Parser<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn expected_semi_or_open_brace<T>(&mut self) -> PResult<'a, T> {
|
||||
let token_str = super::token_descr(&self.token);
|
||||
let msg = &format!("expected `;` or `{{`, found {}", token_str);
|
||||
let mut err = self.struct_span_err(self.token.span, msg);
|
||||
err.span_label(self.token.span, "expected `;` or `{`");
|
||||
Err(err)
|
||||
}
|
||||
|
||||
pub(super) fn eat_incorrect_doc_comment_for_param_type(&mut self) {
|
||||
if let token::DocComment(..) = self.token.kind {
|
||||
self.struct_span_err(
|
||||
|
@ -831,7 +831,7 @@ impl<'a> Parser<'a> {
|
||||
self.struct_span_err(self.token.span, &format!("unexpected token: `{}`", actual)).emit();
|
||||
}
|
||||
|
||||
// We need and identifier or integer, but the next token is a float.
|
||||
// We need an identifier or integer, but the next token is a float.
|
||||
// Break the float into components to extract the identifier or integer.
|
||||
// FIXME: With current `TokenCursor` it's hard to break tokens into more than 2
|
||||
// parts unless those parts are processed immediately. `TokenCursor` should either
|
||||
|
@ -1538,7 +1538,7 @@ impl<'a> Parser<'a> {
|
||||
generics.where_clause = self.parse_where_clause()?; // `where T: Ord`
|
||||
|
||||
let mut sig_hi = self.prev_token.span;
|
||||
let body = self.parse_fn_body(attrs, &mut sig_hi)?; // `;` or `{ ... }`.
|
||||
let body = self.parse_fn_body(attrs, &ident, &mut sig_hi)?; // `;` or `{ ... }`.
|
||||
let fn_sig_span = sig_lo.to(sig_hi);
|
||||
Ok((ident, FnSig { header, decl, span: fn_sig_span }, generics, body))
|
||||
}
|
||||
@ -1549,12 +1549,12 @@ impl<'a> Parser<'a> {
|
||||
fn parse_fn_body(
|
||||
&mut self,
|
||||
attrs: &mut Vec<Attribute>,
|
||||
ident: &Ident,
|
||||
sig_hi: &mut Span,
|
||||
) -> PResult<'a, Option<P<Block>>> {
|
||||
let (inner_attrs, body) = if self.check(&token::Semi) {
|
||||
let (inner_attrs, body) = if self.eat(&token::Semi) {
|
||||
// Include the trailing semicolon in the span of the signature
|
||||
*sig_hi = self.token.span;
|
||||
self.bump(); // `;`
|
||||
*sig_hi = self.prev_token.span;
|
||||
(Vec::new(), None)
|
||||
} else if self.check(&token::OpenDelim(token::Brace)) || self.token.is_whole_block() {
|
||||
self.parse_inner_attrs_and_block().map(|(attrs, body)| (attrs, Some(body)))?
|
||||
@ -1574,7 +1574,21 @@ impl<'a> Parser<'a> {
|
||||
.emit();
|
||||
(Vec::new(), Some(self.mk_block_err(span)))
|
||||
} else {
|
||||
return self.expected_semi_or_open_brace();
|
||||
if let Err(mut err) =
|
||||
self.expected_one_of_not_found(&[], &[token::Semi, token::OpenDelim(token::Brace)])
|
||||
{
|
||||
if self.token.kind == token::CloseDelim(token::Brace) {
|
||||
// The enclosing `mod`, `trait` or `impl` is being closed, so keep the `fn` in
|
||||
// the AST for typechecking.
|
||||
err.span_label(ident.span, "while parsing this `fn`");
|
||||
err.emit();
|
||||
(Vec::new(), None)
|
||||
} else {
|
||||
return Err(err);
|
||||
}
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
};
|
||||
attrs.extend(inner_attrs);
|
||||
Ok(body)
|
||||
@ -1652,10 +1666,19 @@ impl<'a> Parser<'a> {
|
||||
req_name: ReqName,
|
||||
ret_allow_plus: AllowPlus,
|
||||
) -> PResult<'a, P<FnDecl>> {
|
||||
Ok(P(FnDecl {
|
||||
inputs: self.parse_fn_params(req_name)?,
|
||||
output: self.parse_ret_ty(ret_allow_plus, RecoverQPath::Yes)?,
|
||||
}))
|
||||
let inputs = self.parse_fn_params(req_name)?;
|
||||
let output = self.parse_ret_ty(ret_allow_plus, RecoverQPath::Yes)?;
|
||||
|
||||
if let ast::FnRetTy::Ty(ty) = &output {
|
||||
if let TyKind::Path(_, Path { segments, .. }) = &ty.kind {
|
||||
if let [.., last] = &segments[..] {
|
||||
// Detect and recover `fn foo() -> Vec<i32>> {}`
|
||||
self.check_trailing_angle_brackets(last, &[&token::OpenDelim(token::Brace)]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(P(FnDecl { inputs, output }))
|
||||
}
|
||||
|
||||
/// Parses the parameter list of a function, including the `(` and `)` delimiters.
|
||||
|
@ -265,7 +265,19 @@ impl<'a> Parser<'a> {
|
||||
/// Parses an array (`[TYPE; EXPR]`) or slice (`[TYPE]`) type.
|
||||
/// The opening `[` bracket is already eaten.
|
||||
fn parse_array_or_slice_ty(&mut self) -> PResult<'a, TyKind> {
|
||||
let elt_ty = self.parse_ty()?;
|
||||
let elt_ty = match self.parse_ty() {
|
||||
Ok(ty) => ty,
|
||||
Err(mut err)
|
||||
if self.look_ahead(1, |t| t.kind == token::CloseDelim(token::Bracket))
|
||||
| self.look_ahead(1, |t| t.kind == token::Semi) =>
|
||||
{
|
||||
// Recover from `[LIT; EXPR]` and `[LIT]`
|
||||
self.bump();
|
||||
err.emit();
|
||||
self.mk_ty(self.prev_token.span, TyKind::Err)
|
||||
}
|
||||
Err(err) => return Err(err),
|
||||
};
|
||||
let ty = if self.eat(&token::Semi) {
|
||||
TyKind::Array(elt_ty, self.parse_anon_const_expr()?)
|
||||
} else {
|
||||
|
@ -917,54 +917,71 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
|
||||
self.suggest_using_enum_variant(err, source, def_id, span);
|
||||
}
|
||||
(Res::Def(DefKind::Struct, def_id), _) if ns == ValueNS => {
|
||||
if let Some((ctor_def, ctor_vis, fields)) =
|
||||
self.r.struct_constructors.get(&def_id).cloned()
|
||||
{
|
||||
let accessible_ctor =
|
||||
self.r.is_accessible_from(ctor_vis, self.parent_scope.module);
|
||||
if is_expected(ctor_def) && !accessible_ctor {
|
||||
let mut better_diag = false;
|
||||
if let PathSource::TupleStruct(_, pattern_spans) = source {
|
||||
if pattern_spans.len() > 0 && fields.len() == pattern_spans.len() {
|
||||
let non_visible_spans: Vec<Span> = fields
|
||||
.iter()
|
||||
.zip(pattern_spans.iter())
|
||||
.filter_map(|(vis, span)| {
|
||||
match self
|
||||
.r
|
||||
.is_accessible_from(*vis, self.parent_scope.module)
|
||||
{
|
||||
true => None,
|
||||
false => Some(*span),
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
// Extra check to be sure
|
||||
if non_visible_spans.len() > 0 {
|
||||
let mut m: rustc_span::MultiSpan =
|
||||
non_visible_spans.clone().into();
|
||||
non_visible_spans.into_iter().for_each(|s| {
|
||||
m.push_span_label(s, "private field".to_string())
|
||||
});
|
||||
err.span_note(
|
||||
m,
|
||||
"constructor is not visible here due to private fields",
|
||||
);
|
||||
better_diag = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
let (ctor_def, ctor_vis, fields) =
|
||||
if let Some(struct_ctor) = self.r.struct_constructors.get(&def_id).cloned() {
|
||||
struct_ctor
|
||||
} else {
|
||||
bad_struct_syntax_suggestion(def_id);
|
||||
return true;
|
||||
};
|
||||
|
||||
if !better_diag {
|
||||
err.span_label(
|
||||
span,
|
||||
"constructor is not visible here due to private fields".to_string(),
|
||||
);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
bad_struct_syntax_suggestion(def_id);
|
||||
let is_accessible = self.r.is_accessible_from(ctor_vis, self.parent_scope.module);
|
||||
if !is_expected(ctor_def) || is_accessible {
|
||||
return true;
|
||||
}
|
||||
|
||||
let field_spans = match source {
|
||||
// e.g. `if let Enum::TupleVariant(field1, field2) = _`
|
||||
PathSource::TupleStruct(_, pattern_spans) => {
|
||||
err.set_primary_message(
|
||||
"cannot match against a tuple struct which contains private fields",
|
||||
);
|
||||
|
||||
// Use spans of the tuple struct pattern.
|
||||
Some(Vec::from(pattern_spans))
|
||||
}
|
||||
// e.g. `let _ = Enum::TupleVariant(field1, field2);`
|
||||
_ if source.is_call() => {
|
||||
err.set_primary_message(
|
||||
"cannot initialize a tuple struct which contains private fields",
|
||||
);
|
||||
|
||||
// Use spans of the tuple struct definition.
|
||||
self.r
|
||||
.field_names
|
||||
.get(&def_id)
|
||||
.map(|fields| fields.iter().map(|f| f.span).collect::<Vec<_>>())
|
||||
}
|
||||
_ => None,
|
||||
};
|
||||
|
||||
if let Some(spans) =
|
||||
field_spans.filter(|spans| spans.len() > 0 && fields.len() == spans.len())
|
||||
{
|
||||
let non_visible_spans: Vec<Span> = fields
|
||||
.iter()
|
||||
.zip(spans.iter())
|
||||
.filter(|(vis, _)| {
|
||||
!self.r.is_accessible_from(**vis, self.parent_scope.module)
|
||||
})
|
||||
.map(|(_, span)| *span)
|
||||
.collect();
|
||||
|
||||
if non_visible_spans.len() > 0 {
|
||||
let mut m: rustc_span::MultiSpan = non_visible_spans.clone().into();
|
||||
non_visible_spans
|
||||
.into_iter()
|
||||
.for_each(|s| m.push_span_label(s, "private field".to_string()));
|
||||
err.span_note(m, "constructor is not visible here due to private fields");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
err.span_label(
|
||||
span,
|
||||
"constructor is not visible here due to private fields".to_string(),
|
||||
);
|
||||
}
|
||||
(
|
||||
Res::Def(
|
||||
|
@ -738,14 +738,14 @@ impl<D: Decoder> Decodable<D> for Span {
|
||||
}
|
||||
|
||||
/// Calls the provided closure, using the provided `SourceMap` to format
|
||||
/// any spans that are debug-printed during the closure'e exectuino.
|
||||
/// any spans that are debug-printed during the closure's execution.
|
||||
///
|
||||
/// Normally, the global `TyCtxt` is used to retrieve the `SourceMap`
|
||||
/// (see `rustc_interface::callbacks::span_debug1). However, some parts
|
||||
/// of the compiler (e.g. `rustc_parse`) may debug-print `Span`s before
|
||||
/// a `TyCtxt` is available. In this case, we fall back to
|
||||
/// the `SourceMap` provided to this function. If that is not available,
|
||||
/// we fall back to printing the raw `Span` field values
|
||||
/// we fall back to printing the raw `Span` field values.
|
||||
pub fn with_source_map<T, F: FnOnce() -> T>(source_map: Lrc<SourceMap>, f: F) -> T {
|
||||
SESSION_GLOBALS.with(|session_globals| {
|
||||
*session_globals.source_map.borrow_mut() = Some(source_map);
|
||||
|
@ -1169,6 +1169,7 @@ symbols! {
|
||||
unsafe_cell,
|
||||
unsafe_no_drop_flag,
|
||||
unsize,
|
||||
unsized_fn_params,
|
||||
unsized_locals,
|
||||
unsized_tuple_coercion,
|
||||
unstable,
|
||||
|
@ -85,8 +85,10 @@ pub fn is_const_evaluatable<'cx, 'tcx>(
|
||||
} else if leaf.has_param_types_or_consts() {
|
||||
failure_kind = cmp::min(failure_kind, FailureKind::MentionsParam);
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
Node::Binop(_, _, _) | Node::UnaryOp(_, _) | Node::FunctionCall(_, _) => (),
|
||||
Node::Binop(_, _, _) | Node::UnaryOp(_, _) | Node::FunctionCall(_, _) => false,
|
||||
});
|
||||
|
||||
match failure_kind {
|
||||
@ -194,12 +196,12 @@ pub fn is_const_evaluatable<'cx, 'tcx>(
|
||||
///
|
||||
/// This is only able to represent a subset of `MIR`,
|
||||
/// and should not leak any information about desugarings.
|
||||
#[derive(Clone, Copy)]
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct AbstractConst<'tcx> {
|
||||
// FIXME: Consider adding something like `IndexSlice`
|
||||
// and use this here.
|
||||
inner: &'tcx [Node<'tcx>],
|
||||
substs: SubstsRef<'tcx>,
|
||||
pub inner: &'tcx [Node<'tcx>],
|
||||
pub substs: SubstsRef<'tcx>,
|
||||
}
|
||||
|
||||
impl AbstractConst<'tcx> {
|
||||
@ -209,9 +211,21 @@ impl AbstractConst<'tcx> {
|
||||
substs: SubstsRef<'tcx>,
|
||||
) -> Result<Option<AbstractConst<'tcx>>, ErrorReported> {
|
||||
let inner = tcx.mir_abstract_const_opt_const_arg(def)?;
|
||||
debug!("AbstractConst::new({:?}) = {:?}", def, inner);
|
||||
Ok(inner.map(|inner| AbstractConst { inner, substs }))
|
||||
}
|
||||
|
||||
pub fn from_const(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
ct: &ty::Const<'tcx>,
|
||||
) -> Result<Option<AbstractConst<'tcx>>, ErrorReported> {
|
||||
match ct.val {
|
||||
ty::ConstKind::Unevaluated(def, substs, None) => AbstractConst::new(tcx, def, substs),
|
||||
ty::ConstKind::Error(_) => Err(ErrorReported),
|
||||
_ => Ok(None),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn subtree(self, node: NodeId) -> AbstractConst<'tcx> {
|
||||
AbstractConst { inner: &self.inner[..=node.index()], substs: self.substs }
|
||||
@ -550,31 +564,32 @@ pub(super) fn try_unify_abstract_consts<'tcx>(
|
||||
// on `ErrorReported`.
|
||||
}
|
||||
|
||||
fn walk_abstract_const<'tcx, F>(tcx: TyCtxt<'tcx>, ct: AbstractConst<'tcx>, mut f: F)
|
||||
// FIXME: Use `std::ops::ControlFlow` instead of `bool` here.
|
||||
pub fn walk_abstract_const<'tcx, F>(tcx: TyCtxt<'tcx>, ct: AbstractConst<'tcx>, mut f: F) -> bool
|
||||
where
|
||||
F: FnMut(Node<'tcx>),
|
||||
F: FnMut(Node<'tcx>) -> bool,
|
||||
{
|
||||
recurse(tcx, ct, &mut f);
|
||||
fn recurse<'tcx>(tcx: TyCtxt<'tcx>, ct: AbstractConst<'tcx>, f: &mut dyn FnMut(Node<'tcx>)) {
|
||||
fn recurse<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
ct: AbstractConst<'tcx>,
|
||||
f: &mut dyn FnMut(Node<'tcx>) -> bool,
|
||||
) -> bool {
|
||||
let root = ct.root();
|
||||
f(root);
|
||||
match root {
|
||||
Node::Leaf(_) => (),
|
||||
Node::Binop(_, l, r) => {
|
||||
recurse(tcx, ct.subtree(l), f);
|
||||
recurse(tcx, ct.subtree(r), f);
|
||||
}
|
||||
Node::UnaryOp(_, v) => {
|
||||
recurse(tcx, ct.subtree(v), f);
|
||||
}
|
||||
Node::FunctionCall(func, args) => {
|
||||
recurse(tcx, ct.subtree(func), f);
|
||||
for &arg in args {
|
||||
recurse(tcx, ct.subtree(arg), f);
|
||||
f(root)
|
||||
|| match root {
|
||||
Node::Leaf(_) => false,
|
||||
Node::Binop(_, l, r) => {
|
||||
recurse(tcx, ct.subtree(l), f) || recurse(tcx, ct.subtree(r), f)
|
||||
}
|
||||
Node::UnaryOp(_, v) => recurse(tcx, ct.subtree(v), f),
|
||||
Node::FunctionCall(func, args) => {
|
||||
recurse(tcx, ct.subtree(func), f)
|
||||
|| args.iter().any(|&arg| recurse(tcx, ct.subtree(arg), f))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
recurse(tcx, ct, &mut f)
|
||||
}
|
||||
|
||||
/// Tries to unify two abstract constants using structural equality.
|
||||
|
@ -1845,9 +1845,9 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
|
||||
err.note("all function arguments must have a statically known size");
|
||||
}
|
||||
if tcx.sess.opts.unstable_features.is_nightly_build()
|
||||
&& !self.tcx.features().unsized_locals
|
||||
&& !self.tcx.features().unsized_fn_params
|
||||
{
|
||||
err.help("unsized locals are gated as an unstable feature");
|
||||
err.help("unsized fn params are gated as an unstable feature");
|
||||
}
|
||||
}
|
||||
ObligationCauseCode::SizedReturnType => {
|
||||
|
@ -11,6 +11,7 @@
|
||||
use super::elaborate_predicates;
|
||||
|
||||
use crate::infer::TyCtxtInferExt;
|
||||
use crate::traits::const_evaluatable::{self, AbstractConst};
|
||||
use crate::traits::query::evaluate_obligation::InferCtxtExt;
|
||||
use crate::traits::{self, Obligation, ObligationCause};
|
||||
use rustc_errors::FatalError;
|
||||
@ -249,7 +250,7 @@ fn predicates_reference_self(
|
||||
predicates
|
||||
.predicates
|
||||
.iter()
|
||||
.map(|(predicate, sp)| (predicate.subst_supertrait(tcx, &trait_ref), *sp))
|
||||
.map(|&(predicate, sp)| (predicate.subst_supertrait(tcx, &trait_ref), sp))
|
||||
.filter_map(|predicate| predicate_references_self(tcx, predicate))
|
||||
.collect()
|
||||
}
|
||||
@ -260,7 +261,7 @@ fn bounds_reference_self(tcx: TyCtxt<'_>, trait_def_id: DefId) -> SmallVec<[Span
|
||||
.in_definition_order()
|
||||
.filter(|item| item.kind == ty::AssocKind::Type)
|
||||
.flat_map(|item| tcx.explicit_item_bounds(item.def_id))
|
||||
.map(|(predicate, sp)| (predicate.subst_supertrait(tcx, &trait_ref), *sp))
|
||||
.map(|&(predicate, sp)| (predicate.subst_supertrait(tcx, &trait_ref), sp))
|
||||
.filter_map(|predicate| predicate_references_self(tcx, predicate))
|
||||
.collect()
|
||||
}
|
||||
@ -415,7 +416,7 @@ fn virtual_call_violation_for_method<'tcx>(
|
||||
));
|
||||
}
|
||||
|
||||
for (i, input_ty) in sig.skip_binder().inputs()[1..].iter().enumerate() {
|
||||
for (i, &input_ty) in sig.skip_binder().inputs()[1..].iter().enumerate() {
|
||||
if contains_illegal_self_type_reference(tcx, trait_def_id, input_ty) {
|
||||
return Some(MethodViolationCode::ReferencesSelfInput(i));
|
||||
}
|
||||
@ -438,10 +439,7 @@ fn virtual_call_violation_for_method<'tcx>(
|
||||
// so outlives predicates will always hold.
|
||||
.cloned()
|
||||
.filter(|(p, _)| p.to_opt_type_outlives().is_none())
|
||||
.collect::<Vec<_>>()
|
||||
// Do a shallow visit so that `contains_illegal_self_type_reference`
|
||||
// may apply it's custom visiting.
|
||||
.visit_tys_shallow(|t| contains_illegal_self_type_reference(tcx, trait_def_id, t))
|
||||
.any(|pred| contains_illegal_self_type_reference(tcx, trait_def_id, pred))
|
||||
{
|
||||
return Some(MethodViolationCode::WhereClauseReferencesSelf);
|
||||
}
|
||||
@ -715,10 +713,10 @@ fn receiver_is_dispatchable<'tcx>(
|
||||
})
|
||||
}
|
||||
|
||||
fn contains_illegal_self_type_reference<'tcx>(
|
||||
fn contains_illegal_self_type_reference<'tcx, T: TypeFoldable<'tcx>>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
trait_def_id: DefId,
|
||||
ty: Ty<'tcx>,
|
||||
value: T,
|
||||
) -> bool {
|
||||
// This is somewhat subtle. In general, we want to forbid
|
||||
// references to `Self` in the argument and return types,
|
||||
@ -761,7 +759,6 @@ fn contains_illegal_self_type_reference<'tcx>(
|
||||
|
||||
struct IllegalSelfTypeVisitor<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
self_ty: Ty<'tcx>,
|
||||
trait_def_id: DefId,
|
||||
supertraits: Option<Vec<ty::PolyTraitRef<'tcx>>>,
|
||||
}
|
||||
@ -769,7 +766,7 @@ fn contains_illegal_self_type_reference<'tcx>(
|
||||
impl<'tcx> TypeVisitor<'tcx> for IllegalSelfTypeVisitor<'tcx> {
|
||||
fn visit_ty(&mut self, t: Ty<'tcx>) -> bool {
|
||||
match t.kind() {
|
||||
ty::Param(_) => t == self.self_ty,
|
||||
ty::Param(_) => t == self.tcx.types.self_param,
|
||||
ty::Projection(ref data) => {
|
||||
// This is a projected type `<Foo as SomeTrait>::X`.
|
||||
|
||||
@ -802,22 +799,62 @@ fn contains_illegal_self_type_reference<'tcx>(
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_const(&mut self, _c: &ty::Const<'tcx>) -> bool {
|
||||
// FIXME(#72219) Look into the unevaluated constants for object safety violations.
|
||||
// Do not walk substitutions of unevaluated consts, as they contain `Self`, even
|
||||
// though the const expression doesn't necessary use it. Currently type variables
|
||||
// inside array length expressions are forbidden, so they can't break the above
|
||||
// rules.
|
||||
false
|
||||
fn visit_const(&mut self, ct: &ty::Const<'tcx>) -> bool {
|
||||
// First check if the type of this constant references `Self`.
|
||||
if self.visit_ty(ct.ty) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Constants can only influence object safety if they reference `Self`.
|
||||
// This is only possible for unevaluated constants, so we walk these here.
|
||||
//
|
||||
// If `AbstractConst::new` returned an error we already failed compilation
|
||||
// so we don't have to emit an additional error here.
|
||||
//
|
||||
// We currently recurse into abstract consts here but do not recurse in
|
||||
// `is_const_evaluatable`. This means that the object safety check is more
|
||||
// liberal than the const eval check.
|
||||
//
|
||||
// This shouldn't really matter though as we can't really use any
|
||||
// constants which are not considered const evaluatable.
|
||||
use rustc_middle::mir::abstract_const::Node;
|
||||
if let Ok(Some(ct)) = AbstractConst::from_const(self.tcx, ct) {
|
||||
const_evaluatable::walk_abstract_const(self.tcx, ct, |node| match node {
|
||||
Node::Leaf(leaf) => {
|
||||
let leaf = leaf.subst(self.tcx, ct.substs);
|
||||
self.visit_const(leaf)
|
||||
}
|
||||
Node::Binop(..) | Node::UnaryOp(..) | Node::FunctionCall(_, _) => false,
|
||||
})
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_predicate(&mut self, pred: ty::Predicate<'tcx>) -> bool {
|
||||
if let ty::PredicateAtom::ConstEvaluatable(def, substs) = pred.skip_binders() {
|
||||
// FIXME(const_evaluatable_checked): We should probably deduplicate the logic for
|
||||
// `AbstractConst`s here, it might make sense to change `ConstEvaluatable` to
|
||||
// take a `ty::Const` instead.
|
||||
use rustc_middle::mir::abstract_const::Node;
|
||||
if let Ok(Some(ct)) = AbstractConst::new(self.tcx, def, substs) {
|
||||
const_evaluatable::walk_abstract_const(self.tcx, ct, |node| match node {
|
||||
Node::Leaf(leaf) => {
|
||||
let leaf = leaf.subst(self.tcx, ct.substs);
|
||||
self.visit_const(leaf)
|
||||
}
|
||||
Node::Binop(..) | Node::UnaryOp(..) | Node::FunctionCall(_, _) => false,
|
||||
})
|
||||
} else {
|
||||
false
|
||||
}
|
||||
} else {
|
||||
pred.super_visit_with(self)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ty.visit_with(&mut IllegalSelfTypeVisitor {
|
||||
tcx,
|
||||
self_ty: tcx.types.self_param,
|
||||
trait_def_id,
|
||||
supertraits: None,
|
||||
})
|
||||
value.visit_with(&mut IllegalSelfTypeVisitor { tcx, trait_def_id, supertraits: None })
|
||||
}
|
||||
|
||||
pub fn provide(providers: &mut ty::query::Providers) {
|
||||
|
@ -131,7 +131,7 @@ pub(super) fn check_fn<'a, 'tcx>(
|
||||
// The check for a non-trivial pattern is a hack to avoid duplicate warnings
|
||||
// for simple cases like `fn foo(x: Trait)`,
|
||||
// where we would error once on the parameter as a whole, and once on the binding `x`.
|
||||
if param.pat.simple_ident().is_none() && !tcx.features().unsized_locals {
|
||||
if param.pat.simple_ident().is_none() && !tcx.features().unsized_fn_params {
|
||||
fcx.require_type_is_sized(param_ty, param.pat.span, traits::SizedArgumentType(ty_span));
|
||||
}
|
||||
|
||||
|
@ -42,7 +42,7 @@ use rustc_middle::ty::{AdtKind, Visibility};
|
||||
use rustc_span::hygiene::DesugaringKind;
|
||||
use rustc_span::source_map::Span;
|
||||
use rustc_span::symbol::{kw, sym, Ident, Symbol};
|
||||
use rustc_trait_selection::traits::{self, ObligationCauseCode, SelectionContext};
|
||||
use rustc_trait_selection::traits::{self, ObligationCauseCode};
|
||||
|
||||
use std::fmt::Display;
|
||||
|
||||
@ -476,7 +476,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
|
||||
if let ty::FnDef(..) = ty.kind() {
|
||||
let fn_sig = ty.fn_sig(tcx);
|
||||
if !tcx.features().unsized_locals {
|
||||
if !tcx.features().unsized_fn_params {
|
||||
// We want to remove some Sized bounds from std functions,
|
||||
// but don't want to expose the removal to stable Rust.
|
||||
// i.e., we don't want to allow
|
||||
@ -1583,51 +1583,34 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
err: &mut DiagnosticBuilder<'_>,
|
||||
field_ident: Ident,
|
||||
base: &'tcx hir::Expr<'tcx>,
|
||||
expr: &'tcx hir::Expr<'tcx>,
|
||||
def_id: DefId,
|
||||
ty: Ty<'tcx>,
|
||||
) {
|
||||
let param_env = self.tcx().param_env(def_id);
|
||||
let future_trait = self.tcx.require_lang_item(LangItem::Future, None);
|
||||
// Future::Output
|
||||
let item_def_id =
|
||||
self.tcx.associated_items(future_trait).in_definition_order().next().unwrap().def_id;
|
||||
|
||||
let projection_ty = self.tcx.projection_ty_from_predicates((def_id, item_def_id));
|
||||
debug!("suggest_await_on_field_access: projection_ty={:?}", projection_ty);
|
||||
|
||||
let cause = self.misc(expr.span);
|
||||
let mut selcx = SelectionContext::new(&self.infcx);
|
||||
|
||||
let mut obligations = vec![];
|
||||
if let Some(projection_ty) = projection_ty {
|
||||
let normalized_ty = rustc_trait_selection::traits::normalize_projection_type(
|
||||
&mut selcx,
|
||||
param_env,
|
||||
projection_ty,
|
||||
cause,
|
||||
0,
|
||||
&mut obligations,
|
||||
);
|
||||
debug!(
|
||||
"suggest_await_on_field_access: normalized_ty={:?}, ty_kind={:?}",
|
||||
self.resolve_vars_if_possible(&normalized_ty),
|
||||
normalized_ty.kind(),
|
||||
);
|
||||
if let ty::Adt(def, _) = normalized_ty.kind() {
|
||||
// no field access on enum type
|
||||
if !def.is_enum() {
|
||||
if def.non_enum_variant().fields.iter().any(|field| field.ident == field_ident)
|
||||
{
|
||||
err.span_suggestion_verbose(
|
||||
base.span.shrink_to_hi(),
|
||||
"consider awaiting before field access",
|
||||
".await".to_string(),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
let output_ty = match self.infcx.get_impl_future_output_ty(ty) {
|
||||
Some(output_ty) => self.resolve_vars_if_possible(&output_ty),
|
||||
_ => return,
|
||||
};
|
||||
let mut add_label = true;
|
||||
if let ty::Adt(def, _) = output_ty.kind() {
|
||||
// no field access on enum type
|
||||
if !def.is_enum() {
|
||||
if def.non_enum_variant().fields.iter().any(|field| field.ident == field_ident) {
|
||||
add_label = false;
|
||||
err.span_label(
|
||||
field_ident.span,
|
||||
"field not available in `impl Future`, but it is available in its `Output`",
|
||||
);
|
||||
err.span_suggestion_verbose(
|
||||
base.span.shrink_to_hi(),
|
||||
"consider `await`ing on the `Future` and access the field of its `Output`",
|
||||
".await".to_string(),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
if add_label {
|
||||
err.span_label(field_ident.span, &format!("field not found in `{}`", ty));
|
||||
}
|
||||
}
|
||||
|
||||
fn ban_nonexisting_field(
|
||||
@ -1656,8 +1639,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
ty::Param(param_ty) => {
|
||||
self.point_at_param_definition(&mut err, param_ty);
|
||||
}
|
||||
ty::Opaque(def_id, _) => {
|
||||
self.suggest_await_on_field_access(&mut err, field, base, expr, def_id);
|
||||
ty::Opaque(_, _) => {
|
||||
self.suggest_await_on_field_access(&mut err, field, base, expr_t.peel_refs());
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
@ -6,15 +6,20 @@ use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKi
|
||||
use rustc_middle::ty::Ty;
|
||||
use rustc_span::Span;
|
||||
use rustc_trait_selection::traits;
|
||||
use std::mem;
|
||||
|
||||
pub(super) struct GatherLocalsVisitor<'a, 'tcx> {
|
||||
fcx: &'a FnCtxt<'a, 'tcx>,
|
||||
parent_id: hir::HirId,
|
||||
// parameters are special cases of patterns, but we want to handle them as
|
||||
// *distinct* cases. so track when we are hitting a pattern *within* an fn
|
||||
// parameter.
|
||||
outermost_fn_param_pat: bool,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> GatherLocalsVisitor<'a, 'tcx> {
|
||||
pub(super) fn new(fcx: &'a FnCtxt<'a, 'tcx>, parent_id: hir::HirId) -> Self {
|
||||
Self { fcx, parent_id }
|
||||
Self { fcx, parent_id, outermost_fn_param_pat: false }
|
||||
}
|
||||
|
||||
fn assign(&mut self, span: Span, nid: hir::HirId, ty_opt: Option<LocalTy<'tcx>>) -> Ty<'tcx> {
|
||||
@ -88,13 +93,29 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> {
|
||||
intravisit::walk_local(self, local);
|
||||
}
|
||||
|
||||
fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) {
|
||||
let old_outermost_fn_param_pat = mem::replace(&mut self.outermost_fn_param_pat, true);
|
||||
intravisit::walk_param(self, param);
|
||||
self.outermost_fn_param_pat = old_outermost_fn_param_pat;
|
||||
}
|
||||
|
||||
// Add pattern bindings.
|
||||
fn visit_pat(&mut self, p: &'tcx hir::Pat<'tcx>) {
|
||||
if let PatKind::Binding(_, _, ident, _) = p.kind {
|
||||
let var_ty = self.assign(p.span, p.hir_id, None);
|
||||
|
||||
if !self.fcx.tcx.features().unsized_locals {
|
||||
self.fcx.require_type_is_sized(var_ty, p.span, traits::VariableType(p.hir_id));
|
||||
if self.outermost_fn_param_pat {
|
||||
if !self.fcx.tcx.features().unsized_fn_params {
|
||||
self.fcx.require_type_is_sized(
|
||||
var_ty,
|
||||
p.span,
|
||||
traits::SizedArgumentType(Some(p.span)),
|
||||
);
|
||||
}
|
||||
} else {
|
||||
if !self.fcx.tcx.features().unsized_locals {
|
||||
self.fcx.require_type_is_sized(var_ty, p.span, traits::VariableType(p.hir_id));
|
||||
}
|
||||
}
|
||||
|
||||
debug!(
|
||||
@ -104,7 +125,9 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> {
|
||||
var_ty
|
||||
);
|
||||
}
|
||||
let old_outermost_fn_param_pat = mem::replace(&mut self.outermost_fn_param_pat, false);
|
||||
intravisit::walk_pat(self, p);
|
||||
self.outermost_fn_param_pat = old_outermost_fn_param_pat;
|
||||
}
|
||||
|
||||
// Don't descend into the bodies of nested closures.
|
||||
|
@ -21,7 +21,6 @@ use rustc_span::symbol::{kw, sym, Ident};
|
||||
use rustc_span::{source_map, FileName, Span};
|
||||
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
|
||||
use rustc_trait_selection::traits::Obligation;
|
||||
use rustc_trait_selection::traits::SelectionContext;
|
||||
|
||||
use std::cmp::Ordering;
|
||||
|
||||
@ -870,46 +869,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
call: &hir::Expr<'_>,
|
||||
span: Span,
|
||||
) {
|
||||
if let ty::Opaque(def_id, _) = *ty.kind() {
|
||||
let future_trait = self.tcx.require_lang_item(LangItem::Future, None);
|
||||
// Future::Output
|
||||
let item_def_id = self
|
||||
.tcx
|
||||
.associated_items(future_trait)
|
||||
.in_definition_order()
|
||||
.next()
|
||||
.unwrap()
|
||||
.def_id;
|
||||
|
||||
let projection_ty = self.tcx.projection_ty_from_predicates((def_id, item_def_id));
|
||||
let cause = self.misc(span);
|
||||
let mut selcx = SelectionContext::new(&self.infcx);
|
||||
let mut obligations = vec![];
|
||||
if let Some(projection_ty) = projection_ty {
|
||||
let normalized_ty = rustc_trait_selection::traits::normalize_projection_type(
|
||||
&mut selcx,
|
||||
self.param_env,
|
||||
projection_ty,
|
||||
cause,
|
||||
0,
|
||||
&mut obligations,
|
||||
);
|
||||
debug!(
|
||||
"suggest_await_before_method: normalized_ty={:?}, ty_kind={:?}",
|
||||
self.resolve_vars_if_possible(&normalized_ty),
|
||||
normalized_ty.kind(),
|
||||
);
|
||||
let method_exists = self.method_exists(item_name, normalized_ty, call.hir_id, true);
|
||||
debug!("suggest_await_before_method: is_method_exist={}", method_exists);
|
||||
if method_exists {
|
||||
err.span_suggestion_verbose(
|
||||
span.shrink_to_lo(),
|
||||
"consider awaiting before this method call",
|
||||
"await.".to_string(),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
}
|
||||
let output_ty = match self.infcx.get_impl_future_output_ty(ty) {
|
||||
Some(output_ty) => self.resolve_vars_if_possible(&output_ty),
|
||||
_ => return,
|
||||
};
|
||||
let method_exists = self.method_exists(item_name, output_ty, call.hir_id, true);
|
||||
debug!("suggest_await_before_method: is_method_exist={}", method_exists);
|
||||
if method_exists {
|
||||
err.span_suggestion_verbose(
|
||||
span.shrink_to_lo(),
|
||||
"consider `await`ing on the `Future` and calling the method on its `Output`",
|
||||
"await.".to_string(),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2090,25 +2090,25 @@ fn const_evaluatable_predicates_of<'tcx>(
|
||||
if let hir::Node::Item(item) = node {
|
||||
if let hir::ItemKind::Impl { ref of_trait, ref self_ty, .. } = item.kind {
|
||||
if let Some(of_trait) = of_trait {
|
||||
warn!("const_evaluatable_predicates_of({:?}): visit impl trait_ref", def_id);
|
||||
debug!("const_evaluatable_predicates_of({:?}): visit impl trait_ref", def_id);
|
||||
collector.visit_trait_ref(of_trait);
|
||||
}
|
||||
|
||||
warn!("const_evaluatable_predicates_of({:?}): visit_self_ty", def_id);
|
||||
debug!("const_evaluatable_predicates_of({:?}): visit_self_ty", def_id);
|
||||
collector.visit_ty(self_ty);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(generics) = node.generics() {
|
||||
warn!("const_evaluatable_predicates_of({:?}): visit_generics", def_id);
|
||||
debug!("const_evaluatable_predicates_of({:?}): visit_generics", def_id);
|
||||
collector.visit_generics(generics);
|
||||
}
|
||||
|
||||
if let Some(fn_sig) = tcx.hir().fn_sig_by_hir_id(hir_id) {
|
||||
warn!("const_evaluatable_predicates_of({:?}): visit_fn_decl", def_id);
|
||||
debug!("const_evaluatable_predicates_of({:?}): visit_fn_decl", def_id);
|
||||
collector.visit_fn_decl(fn_sig.decl);
|
||||
}
|
||||
warn!("const_evaluatable_predicates_of({:?}) = {:?}", def_id, collector.preds);
|
||||
debug!("const_evaluatable_predicates_of({:?}) = {:?}", def_id, collector.preds);
|
||||
|
||||
collector.preds
|
||||
}
|
||||
|
@ -130,7 +130,8 @@
|
||||
#![feature(unicode_internals)]
|
||||
#![feature(unsafe_block_in_unsafe_fn)]
|
||||
#![feature(unsize)]
|
||||
#![feature(unsized_locals)]
|
||||
#![cfg_attr(not(bootstrap), feature(unsized_fn_params))]
|
||||
#![cfg_attr(bootstrap, feature(unsized_locals))]
|
||||
#![feature(allocator_internals)]
|
||||
#![feature(slice_partition_dedup)]
|
||||
#![feature(maybe_uninit_extra, maybe_uninit_slice, maybe_uninit_uninit_array)]
|
||||
|
@ -132,7 +132,8 @@
|
||||
#![feature(transparent_unions)]
|
||||
#![feature(try_blocks)]
|
||||
#![feature(unboxed_closures)]
|
||||
#![feature(unsized_locals)]
|
||||
#![cfg_attr(not(bootstrap), feature(unsized_fn_params))]
|
||||
#![cfg_attr(bootstrap, feature(unsized_locals))]
|
||||
#![cfg_attr(bootstrap, feature(untagged_unions))]
|
||||
#![feature(unwind_attributes)]
|
||||
#![feature(variant_count)]
|
||||
|
@ -11,7 +11,8 @@ This implements [RFC1909]. When turned on, you can have unsized arguments and lo
|
||||
[RFC1909]: https://github.com/rust-lang/rfcs/blob/master/text/1909-unsized-rvalues.md
|
||||
|
||||
```rust
|
||||
#![feature(unsized_locals)]
|
||||
#![allow(incomplete_features)]
|
||||
#![feature(unsized_locals, unsized_fn_params)]
|
||||
|
||||
use std::any::Any;
|
||||
|
||||
@ -85,7 +86,7 @@ fn main() {
|
||||
With this feature, you can have by-value `self` arguments without `Self: Sized` bounds.
|
||||
|
||||
```rust
|
||||
#![feature(unsized_locals)]
|
||||
#![feature(unsized_fn_params)]
|
||||
|
||||
trait Foo {
|
||||
fn foo(self) {}
|
||||
@ -102,7 +103,7 @@ fn main() {
|
||||
And `Foo` will also be object-safe.
|
||||
|
||||
```rust
|
||||
#![feature(unsized_locals)]
|
||||
#![feature(unsized_fn_params)]
|
||||
|
||||
trait Foo {
|
||||
fn foo(self) {}
|
||||
|
@ -1,4 +1,5 @@
|
||||
#![feature(unsized_locals)]
|
||||
#![allow(incomplete_features)]
|
||||
#![feature(unsized_locals, unsized_fn_params)]
|
||||
|
||||
use std::fmt;
|
||||
|
||||
@ -45,11 +46,7 @@ fn main() {
|
||||
|
||||
{
|
||||
let x: fmt::Display = *gen_foo();
|
||||
let x = if true {
|
||||
x
|
||||
} else {
|
||||
*gen_foo()
|
||||
};
|
||||
let x = if true { x } else { *gen_foo() };
|
||||
foo(x);
|
||||
}
|
||||
}
|
||||
|
18
src/test/ui/ast-json/issue-78398-foreign-ice.rs
Normal file
18
src/test/ui/ast-json/issue-78398-foreign-ice.rs
Normal file
@ -0,0 +1,18 @@
|
||||
// Regression test for issue #78398
|
||||
// Tests that we don't ICE when trying to print the AST json
|
||||
// when we have capturd tokens for a foreign item
|
||||
|
||||
// check-pass
|
||||
// compile-flags: -Zast-json
|
||||
|
||||
fn main() {}
|
||||
|
||||
macro_rules! mac_extern {
|
||||
($i:item) => {
|
||||
extern "C" { $i }
|
||||
}
|
||||
}
|
||||
|
||||
mac_extern! {
|
||||
fn foo();
|
||||
}
|
1
src/test/ui/ast-json/issue-78398-foreign-ice.stdout
Normal file
1
src/test/ui/ast-json/issue-78398-foreign-ice.stdout
Normal file
@ -0,0 +1 @@
|
||||
{"module":{"inner":{"lo":192,"hi":315},"unsafety":"No","items":[{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"prelude_import","span":{"lo":0,"hi":0}},"id":3,"args":null}],"tokens":null},"args":"Empty","tokens":null}]},"id":null,"style":"Outer","span":{"lo":0,"hi":0},"tokens":null}],"id":4,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"","span":{"lo":0,"hi":0}},"kind":{"variant":"Use","fields":[{"prefix":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"{{root}}","span":{"lo":0,"hi":0}},"id":5,"args":null},{"ident":{"name":"std","span":{"lo":0,"hi":0}},"id":6,"args":null},{"ident":{"name":"prelude","span":{"lo":0,"hi":0}},"id":7,"args":null},{"ident":{"name":"v1","span":{"lo":0,"hi":0}},"id":8,"args":null}],"tokens":null},"kind":"Glob","span":{"lo":0,"hi":0}}]},"tokens":null},{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"macro_use","span":{"lo":0,"hi":0}},"id":9,"args":null}],"tokens":null},"args":"Empty","tokens":null}]},"id":null,"style":"Outer","span":{"lo":0,"hi":0},"tokens":null}],"id":10,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"std","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null},{"attrs":[],"id":11,"span":{"lo":192,"hi":204},"vis":{"kind":"Inherited","span":{"lo":192,"hi":192},"tokens":null},"ident":{"name":"main","span":{"lo":195,"hi":199}},"kind":{"variant":"Fn","fields":["Final",{"header":{"unsafety":"No","asyncness":"No","constness":"No","ext":"None"},"decl":{"inputs":[],"output":{"variant":"Default","fields":[{"lo":202,"hi":202}]}},"span":{"lo":192,"hi":201}},{"params":[],"where_clause":{"has_where_token":false,"predicates":[],"span":{"lo":201,"hi":201}},"span":{"lo":199,"hi":199}},{"stmts":[],"id":12,"rules":"Default","span":{"lo":202,"hi":204},"tokens":null}]},"tokens":null},{"attrs":[],"id":13,"span":{"lo":206,"hi":284},"vis":{"kind":"Inherited","span":{"lo":206,"hi":206},"tokens":null},"ident":{"name":"mac_extern","span":{"lo":219,"hi":229}},"kind":{"variant":"MacroDef","fields":[{"body":{"variant":"Delimited","fields":[{"open":{"lo":230,"hi":231},"close":{"lo":283,"hi":284}},"Brace",{"0":[[{"variant":"Delimited","fields":[{"open":{"lo":236,"hi":237},"close":{"lo":244,"hi":245}},"Paren",{"0":[[{"variant":"Token","fields":[{"kind":"Dollar","span":{"lo":237,"hi":238}}]},"Alone"],[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["i",false]},"span":{"lo":238,"hi":239}}]},"Joint"],[{"variant":"Token","fields":[{"kind":"Colon","span":{"lo":239,"hi":240}}]},"Alone"],[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["item",false]},"span":{"lo":240,"hi":244}}]},"Alone"]]}]},"Alone"],[{"variant":"Token","fields":[{"kind":"FatArrow","span":{"lo":246,"hi":248}}]},"Alone"],[{"variant":"Delimited","fields":[{"open":{"lo":249,"hi":250},"close":{"lo":281,"hi":282}},"Brace",{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["extern",false]},"span":{"lo":259,"hi":265}}]},"Alone"],[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"C","suffix":null}]},"span":{"lo":266,"hi":269}}]},"Alone"],[{"variant":"Delimited","fields":[{"open":{"lo":270,"hi":271},"close":{"lo":275,"hi":276}},"Brace",{"0":[[{"variant":"Token","fields":[{"kind":"Dollar","span":{"lo":272,"hi":273}}]},"Alone"],[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["i",false]},"span":{"lo":273,"hi":274}}]},"Alone"]]}]},"Alone"]]}]},"Alone"]]}]},"macro_rules":true}]},"tokens":null},{"attrs":[],"id":14,"span":{"lo":259,"hi":276},"vis":{"kind":"Inherited","span":{"lo":259,"hi":259},"tokens":null},"ident":{"name":"","span":{"lo":0,"hi":0}},"kind":{"variant":"ForeignMod","fields":[{"unsafety":"No","abi":{"style":"Cooked","symbol":"C","suffix":null,"span":{"lo":266,"hi":269},"symbol_unescaped":"C"},"items":[{"attrs":[],"id":15,"span":{"lo":304,"hi":313},"vis":{"kind":"Inherited","span":{"lo":304,"hi":304},"tokens":null},"ident":{"name":"foo","span":{"lo":307,"hi":310}},"kind":{"variant":"Fn","fields":["Final",{"header":{"unsafety":"No","asyncness":"No","constness":"No","ext":"None"},"decl":{"inputs":[],"output":{"variant":"Default","fields":[{"lo":312,"hi":312}]}},"span":{"lo":304,"hi":313}},{"params":[],"where_clause":{"has_where_token":false,"predicates":[],"span":{"lo":312,"hi":312}},"span":{"lo":310,"hi":310}},null]},"tokens":null}]}]},"tokens":null}],"inline":true},"attrs":[],"span":{"lo":192,"hi":315},"proc_macros":[]}
|
@ -40,6 +40,14 @@ async fn foo() -> Result<(), ()> {
|
||||
|
||||
async fn bar() -> Result<(), ()> {
|
||||
foo()?; //~ ERROR the `?` operator can only be applied to values that implement `Try`
|
||||
//~^ NOTE the `?` operator cannot be applied to type `impl Future`
|
||||
//~| HELP the trait `Try` is not implemented for `impl Future`
|
||||
//~| NOTE required by `into_result`
|
||||
//~| HELP consider `await`ing on the `Future`
|
||||
//~| NOTE in this expansion of desugaring of operator `?`
|
||||
//~| NOTE in this expansion of desugaring of operator `?`
|
||||
//~| NOTE in this expansion of desugaring of operator `?`
|
||||
//~| NOTE in this expansion of desugaring of operator `?`
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -48,25 +56,42 @@ async fn struct_() -> Struct {
|
||||
}
|
||||
|
||||
async fn tuple() -> Tuple {
|
||||
//~^ NOTE the `Output` of this `async fn`'s expected opaque type
|
||||
Tuple(1i32)
|
||||
}
|
||||
|
||||
async fn baz() -> Result<(), ()> {
|
||||
let t = T;
|
||||
t?; //~ ERROR the `?` operator can only be applied to values that implement `Try`
|
||||
//~^ NOTE the `?` operator cannot be applied to type `T`
|
||||
//~| HELP the trait `Try` is not implemented for `T`
|
||||
//~| NOTE required by `into_result`
|
||||
//~| HELP consider `await`ing on the `Future`
|
||||
//~| NOTE in this expansion of desugaring of operator `?`
|
||||
//~| NOTE in this expansion of desugaring of operator `?`
|
||||
//~| NOTE in this expansion of desugaring of operator `?`
|
||||
//~| NOTE in this expansion of desugaring of operator `?`
|
||||
|
||||
|
||||
let _: i32 = tuple().0; //~ ERROR no field `0`
|
||||
//~^ HELP consider `await`ing on the `Future`
|
||||
//~| NOTE field not available in `impl Future`
|
||||
|
||||
let _: i32 = struct_().a; //~ ERROR no field `a`
|
||||
//~^ HELP consider `await`ing on the `Future`
|
||||
//~| NOTE field not available in `impl Future`
|
||||
|
||||
struct_().method(); //~ ERROR no method named
|
||||
|
||||
//~^ NOTE method not found in `impl Future`
|
||||
//~| HELP consider `await`ing on the `Future`
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn match_() {
|
||||
match tuple() {
|
||||
match tuple() { //~ HELP consider `await`ing on the `Future`
|
||||
Tuple(_) => {} //~ ERROR mismatched types
|
||||
//~^ NOTE expected opaque type, found struct `Tuple`
|
||||
//~| NOTE expected opaque type `impl Future`
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -12,7 +12,7 @@ LL | foo().await?;
|
||||
| ^^^^^^
|
||||
|
||||
error[E0277]: the `?` operator can only be applied to values that implement `Try`
|
||||
--> $DIR/issue-61076.rs:56:5
|
||||
--> $DIR/issue-61076.rs:65:5
|
||||
|
|
||||
LL | t?;
|
||||
| ^^ the `?` operator cannot be applied to type `T`
|
||||
@ -25,25 +25,40 @@ LL | t.await?;
|
||||
| ^^^^^^
|
||||
|
||||
error[E0609]: no field `0` on type `impl Future`
|
||||
--> $DIR/issue-61076.rs:58:26
|
||||
--> $DIR/issue-61076.rs:76:26
|
||||
|
|
||||
LL | let _: i32 = tuple().0;
|
||||
| ^
|
||||
| ^ field not available in `impl Future`, but it is available in its `Output`
|
||||
|
|
||||
help: consider `await`ing on the `Future` and access the field of its `Output`
|
||||
|
|
||||
LL | let _: i32 = tuple().await.0;
|
||||
| ^^^^^^
|
||||
|
||||
error[E0609]: no field `a` on type `impl Future`
|
||||
--> $DIR/issue-61076.rs:60:28
|
||||
--> $DIR/issue-61076.rs:80:28
|
||||
|
|
||||
LL | let _: i32 = struct_().a;
|
||||
| ^
|
||||
| ^ field not available in `impl Future`, but it is available in its `Output`
|
||||
|
|
||||
help: consider `await`ing on the `Future` and access the field of its `Output`
|
||||
|
|
||||
LL | let _: i32 = struct_().await.a;
|
||||
| ^^^^^^
|
||||
|
||||
error[E0599]: no method named `method` found for opaque type `impl Future` in the current scope
|
||||
--> $DIR/issue-61076.rs:62:15
|
||||
--> $DIR/issue-61076.rs:84:15
|
||||
|
|
||||
LL | struct_().method();
|
||||
| ^^^^^^ method not found in `impl Future`
|
||||
|
|
||||
help: consider `await`ing on the `Future` and calling the method on its `Output`
|
||||
|
|
||||
LL | struct_().await.method();
|
||||
| ^^^^^^
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/issue-61076.rs:69:9
|
||||
--> $DIR/issue-61076.rs:92:9
|
||||
|
|
||||
LL | async fn tuple() -> Tuple {
|
||||
| ----- the `Output` of this `async fn`'s expected opaque type
|
||||
|
@ -18,7 +18,7 @@ LL | async fn frob(self) {}
|
||||
|
|
||||
= help: within `Foo`, the trait `Sized` is not implemented for `str`
|
||||
= note: required because it appears within the type `Foo`
|
||||
= help: unsized locals are gated as an unstable feature
|
||||
= help: unsized fn params are gated as an unstable feature
|
||||
help: function arguments must have a statically known size, borrowed types always have a known size
|
||||
|
|
||||
LL | async fn frob(&self) {}
|
||||
|
@ -16,7 +16,7 @@ LL | (&|_| ()) as &dyn for<'x> Fn(<u32 as T<'x>>::V);
|
||||
| ^ doesn't have a size known at compile-time
|
||||
|
|
||||
= help: the trait `Sized` is not implemented for `<u32 as T<'_>>::V`
|
||||
= help: unsized locals are gated as an unstable feature
|
||||
= help: unsized fn params are gated as an unstable feature
|
||||
help: consider further restricting the associated type
|
||||
|
|
||||
LL | fn main() where <u32 as T<'_>>::V: Sized {
|
||||
|
@ -0,0 +1,21 @@
|
||||
#![feature(const_generics, const_evaluatable_checked)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
|
||||
const fn bar<T: ?Sized>() -> usize { 7 }
|
||||
|
||||
trait Foo {
|
||||
fn test(&self) -> [u8; bar::<Self>()];
|
||||
}
|
||||
|
||||
impl Foo for () {
|
||||
fn test(&self) -> [u8; bar::<Self>()] {
|
||||
[0; bar::<Self>()]
|
||||
}
|
||||
}
|
||||
|
||||
fn use_dyn(v: &dyn Foo) { //~ERROR the trait `Foo` cannot be made into an object
|
||||
v.test();
|
||||
}
|
||||
|
||||
fn main() {}
|
@ -0,0 +1,18 @@
|
||||
error[E0038]: the trait `Foo` cannot be made into an object
|
||||
--> $DIR/object-safety-err-ret.rs:17:15
|
||||
|
|
||||
LL | fn use_dyn(v: &dyn Foo) {
|
||||
| ^^^^^^^^ `Foo` cannot be made into an object
|
||||
|
|
||||
= help: consider moving `test` to another trait
|
||||
note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
|
||||
--> $DIR/object-safety-err-ret.rs:8:23
|
||||
|
|
||||
LL | trait Foo {
|
||||
| --- this trait cannot be made into an object...
|
||||
LL | fn test(&self) -> [u8; bar::<Self>()];
|
||||
| ^^^^^^^^^^^^^^^^^^^ ...because method `test` references the `Self` type in its return type
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0038`.
|
@ -0,0 +1,22 @@
|
||||
#![feature(const_generics, const_evaluatable_checked)]
|
||||
#![allow(incomplete_features)]
|
||||
#![deny(where_clauses_object_safety)]
|
||||
|
||||
|
||||
const fn bar<T: ?Sized>() -> usize { 7 }
|
||||
|
||||
trait Foo {
|
||||
fn test(&self) where [u8; bar::<Self>()]: Sized;
|
||||
//~^ ERROR the trait `Foo` cannot be made into an object
|
||||
//~| WARN this was previously accepted by the compiler but is being phased out
|
||||
}
|
||||
|
||||
impl Foo for () {
|
||||
fn test(&self) where [u8; bar::<Self>()]: Sized {}
|
||||
}
|
||||
|
||||
fn use_dyn(v: &dyn Foo) {
|
||||
v.test();
|
||||
}
|
||||
|
||||
fn main() {}
|
@ -0,0 +1,24 @@
|
||||
error: the trait `Foo` cannot be made into an object
|
||||
--> $DIR/object-safety-err-where-bounds.rs:9:8
|
||||
|
|
||||
LL | fn test(&self) where [u8; bar::<Self>()]: Sized;
|
||||
| ^^^^
|
||||
|
|
||||
note: the lint level is defined here
|
||||
--> $DIR/object-safety-err-where-bounds.rs:3:9
|
||||
|
|
||||
LL | #![deny(where_clauses_object_safety)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
= note: for more information, see issue #51443 <https://github.com/rust-lang/rust/issues/51443>
|
||||
note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
|
||||
--> $DIR/object-safety-err-where-bounds.rs:9:8
|
||||
|
|
||||
LL | trait Foo {
|
||||
| --- this trait cannot be made into an object...
|
||||
LL | fn test(&self) where [u8; bar::<Self>()]: Sized;
|
||||
| ^^^^ ...because method `test` references the `Self` type in its `where` clause
|
||||
= help: consider moving `test` to another trait
|
||||
|
||||
error: aborting due to previous error
|
||||
|
@ -0,0 +1,22 @@
|
||||
#![feature(const_generics, const_evaluatable_checked)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
trait Foo<const N: usize> {
|
||||
fn test(&self) -> [u8; N + 1];
|
||||
}
|
||||
|
||||
impl<const N: usize> Foo<N> for () {
|
||||
fn test(&self) -> [u8; N + 1] {
|
||||
[0; N + 1]
|
||||
}
|
||||
}
|
||||
|
||||
fn use_dyn<const N: usize>(v: &dyn Foo<N>) where [u8; N + 1]: Sized {
|
||||
assert_eq!(v.test(), [0; N + 1]);
|
||||
}
|
||||
|
||||
fn main() {
|
||||
// FIXME(const_evaluatable_checked): Improve the error message here.
|
||||
use_dyn(&());
|
||||
//~^ ERROR type annotations needed
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
error[E0284]: type annotations needed: cannot satisfy `the constant `use_dyn::<{_: usize}>::{constant#0}` can be evaluated`
|
||||
--> $DIR/object-safety-ok-infer-err.rs:20:5
|
||||
|
|
||||
LL | fn use_dyn<const N: usize>(v: &dyn Foo<N>) where [u8; N + 1]: Sized {
|
||||
| ----- required by this bound in `use_dyn`
|
||||
...
|
||||
LL | use_dyn(&());
|
||||
| ^^^^^^^ cannot satisfy `the constant `use_dyn::<{_: usize}>::{constant#0}` can be evaluated`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0284`.
|
@ -0,0 +1,21 @@
|
||||
// run-pass
|
||||
#![feature(const_generics, const_evaluatable_checked)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
trait Foo<const N: usize> {
|
||||
fn test(&self) -> [u8; N + 1];
|
||||
}
|
||||
|
||||
impl<const N: usize> Foo<N> for () {
|
||||
fn test(&self) -> [u8; N + 1] {
|
||||
[0; N + 1]
|
||||
}
|
||||
}
|
||||
|
||||
fn use_dyn<const N: usize>(v: &dyn Foo<N>) where [u8; N + 1]: Sized {
|
||||
assert_eq!(v.test(), [0; N + 1]);
|
||||
}
|
||||
|
||||
fn main() {
|
||||
use_dyn::<3>(&());
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
// run-pass
|
||||
|
||||
#![feature(min_const_generics)]
|
||||
|
||||
const fn identity<const T: u32>() -> u32 { T }
|
||||
|
||||
#[derive(Eq, PartialEq, Debug)]
|
||||
pub struct ConstU32<const U: u32>;
|
||||
|
||||
pub fn new() -> ConstU32<{ identity::<3>() }> {
|
||||
ConstU32::<{ identity::<3>() }>
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let v = new();
|
||||
assert_eq!(v, ConstU32::<3>);
|
||||
}
|
@ -13,7 +13,7 @@ unsafe impl Sync for Meh {}
|
||||
|
||||
// the following will never be ok! no interior mut behind consts, because
|
||||
// all allocs interned here will be marked immutable.
|
||||
const MUH: Meh = Meh { //~ ERROR: mutable memory (`UnsafeCell`) is not allowed in constant
|
||||
const MUH: Meh = Meh { //~ ERROR: it is undefined behavior to use this value
|
||||
x: &UnsafeCell::new(42),
|
||||
};
|
||||
|
||||
@ -24,11 +24,11 @@ unsafe impl Sync for Synced {}
|
||||
|
||||
// Make sure we also catch this behind a type-erased `dyn Trait` reference.
|
||||
const SNEAKY: &dyn Sync = &Synced { x: UnsafeCell::new(42) };
|
||||
//~^ ERROR: mutable memory (`UnsafeCell`) is not allowed in constant
|
||||
//~^ ERROR: it is undefined behavior to use this value
|
||||
|
||||
// Make sure we also catch mutable references.
|
||||
const BLUNT: &mut i32 = &mut 42;
|
||||
//~^ ERROR: mutable memory (`&mut`) is not allowed in constant
|
||||
//~^ ERROR: it is undefined behavior to use this value
|
||||
|
||||
fn main() {
|
||||
unsafe {
|
||||
|
@ -1,22 +1,28 @@
|
||||
error: mutable memory (`UnsafeCell`) is not allowed in constant
|
||||
error[E0080]: it is undefined behavior to use this value
|
||||
--> $DIR/mutable_references_err.rs:16:1
|
||||
|
|
||||
LL | / const MUH: Meh = Meh {
|
||||
LL | | x: &UnsafeCell::new(42),
|
||||
LL | | };
|
||||
| |__^
|
||||
| |__^ type validation failed: encountered `UnsafeCell` in a `const` at .x.<deref>
|
||||
|
|
||||
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
|
||||
|
||||
error: mutable memory (`UnsafeCell`) is not allowed in constant
|
||||
error[E0080]: it is undefined behavior to use this value
|
||||
--> $DIR/mutable_references_err.rs:26:1
|
||||
|
|
||||
LL | const SNEAKY: &dyn Sync = &Synced { x: UnsafeCell::new(42) };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered `UnsafeCell` in a `const` at .<deref>.<dyn-downcast>.x
|
||||
|
|
||||
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
|
||||
|
||||
error: mutable memory (`&mut`) is not allowed in constant
|
||||
error[E0080]: it is undefined behavior to use this value
|
||||
--> $DIR/mutable_references_err.rs:30:1
|
||||
|
|
||||
LL | const BLUNT: &mut i32 = &mut 42;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered mutable reference in a `const`
|
||||
|
|
||||
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
|
||||
|
||||
warning: skipping const checks
|
||||
|
|
||||
@ -38,3 +44,4 @@ LL | const BLUNT: &mut i32 = &mut 42;
|
||||
|
||||
error: aborting due to 3 previous errors; 1 warning emitted
|
||||
|
||||
For more information about this error, try `rustc --explain E0080`.
|
||||
|
@ -9,13 +9,13 @@
|
||||
//[zflagsul]compile-flags: -Z borrowck=migrate
|
||||
//[editionul]edition:2018
|
||||
|
||||
#![allow(incomplete_features)]
|
||||
#![cfg_attr(nll, feature(nll))]
|
||||
#![cfg_attr(nllul, feature(nll))]
|
||||
#![cfg_attr(migrateul, feature(unsized_locals))]
|
||||
#![cfg_attr(zflagsul, feature(unsized_locals))]
|
||||
#![cfg_attr(nllul, feature(unsized_locals))]
|
||||
#![cfg_attr(editionul, feature(unsized_locals))]
|
||||
|
||||
#![feature(box_syntax)]
|
||||
|
||||
fn foo(x: Box<[i32]>) {
|
||||
|
@ -6,11 +6,11 @@ LL | fn f(p: Path) { }
|
||||
|
|
||||
= help: within `Path`, the trait `Sized` is not implemented for `[u8]`
|
||||
= note: required because it appears within the type `Path`
|
||||
= help: unsized locals are gated as an unstable feature
|
||||
= help: unsized fn params are gated as an unstable feature
|
||||
help: function arguments must have a statically known size, borrowed types always have a known size
|
||||
|
|
||||
LL | fn f(p: &Path) { }
|
||||
| ^
|
||||
LL | fn f(&p: Path) { }
|
||||
| ^
|
||||
|
||||
error[E0277]: the trait bound `i32: Foo` is not satisfied
|
||||
--> $DIR/E0277.rs:17:15
|
||||
|
26
src/test/ui/feature-gates/feature-gate-unsized_fn_params.rs
Normal file
26
src/test/ui/feature-gates/feature-gate-unsized_fn_params.rs
Normal file
@ -0,0 +1,26 @@
|
||||
#[repr(align(256))]
|
||||
#[allow(dead_code)]
|
||||
struct A {
|
||||
v: u8,
|
||||
}
|
||||
|
||||
trait Foo {
|
||||
fn foo(&self);
|
||||
}
|
||||
|
||||
impl Foo for A {
|
||||
fn foo(&self) {
|
||||
assert_eq!(self as *const A as usize % 256, 0);
|
||||
}
|
||||
}
|
||||
|
||||
fn foo(x: dyn Foo) {
|
||||
//~^ ERROR [E0277]
|
||||
x.foo()
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let x: Box<dyn Foo> = Box::new(A { v: 22 });
|
||||
foo(*x);
|
||||
//~^ ERROR [E0277]
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
error[E0277]: the size for values of type `(dyn Foo + 'static)` cannot be known at compilation time
|
||||
--> $DIR/feature-gate-unsized_fn_params.rs:17:8
|
||||
|
|
||||
LL | fn foo(x: dyn Foo) {
|
||||
| ^ doesn't have a size known at compile-time
|
||||
|
|
||||
= help: the trait `Sized` is not implemented for `(dyn Foo + 'static)`
|
||||
= help: unsized fn params are gated as an unstable feature
|
||||
help: function arguments must have a statically known size, borrowed types always have a known size
|
||||
|
|
||||
LL | fn foo(&x: dyn Foo) {
|
||||
| ^
|
||||
|
||||
error[E0277]: the size for values of type `(dyn Foo + 'static)` cannot be known at compilation time
|
||||
--> $DIR/feature-gate-unsized_fn_params.rs:24:5
|
||||
|
|
||||
LL | foo(*x);
|
||||
| ^^^ doesn't have a size known at compile-time
|
||||
|
|
||||
= help: the trait `Sized` is not implemented for `(dyn Foo + 'static)`
|
||||
= note: all function arguments must have a statically known size
|
||||
= help: unsized fn params are gated as an unstable feature
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
@ -5,11 +5,11 @@ LL | fn f(f: dyn FnOnce()) {}
|
||||
| ^ doesn't have a size known at compile-time
|
||||
|
|
||||
= help: the trait `Sized` is not implemented for `(dyn FnOnce() + 'static)`
|
||||
= help: unsized locals are gated as an unstable feature
|
||||
= help: unsized fn params are gated as an unstable feature
|
||||
help: function arguments must have a statically known size, borrowed types always have a known size
|
||||
|
|
||||
LL | fn f(f: &dyn FnOnce()) {}
|
||||
| ^
|
||||
LL | fn f(&f: dyn FnOnce()) {}
|
||||
| ^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
@ -1,6 +1,5 @@
|
||||
// run-pass
|
||||
|
||||
#![feature(unsized_locals)]
|
||||
#![allow(dead_code)]
|
||||
#[repr(align(256))]
|
||||
struct A {
|
||||
|
@ -15,7 +15,7 @@ LL | (|| Box::new(*(&[0][..])))();
|
||||
|
|
||||
= help: the trait `Sized` is not implemented for `[{integer}]`
|
||||
= note: all function arguments must have a statically known size
|
||||
= help: unsized locals are gated as an unstable feature
|
||||
= help: unsized fn params are gated as an unstable feature
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
@ -4,7 +4,7 @@ error[E0277]: the size for values of type `Self` cannot be known at compilation
|
||||
LL | fn foo(self) -> &'static i32 {
|
||||
| ^^^^ doesn't have a size known at compile-time
|
||||
|
|
||||
= help: unsized locals are gated as an unstable feature
|
||||
= help: unsized fn params are gated as an unstable feature
|
||||
help: consider further restricting `Self`
|
||||
|
|
||||
LL | fn foo(self) -> &'static i32 where Self: Sized {
|
||||
|
@ -6,7 +6,7 @@ LL | &X(*Y)
|
||||
|
|
||||
= help: the trait `Sized` is not implemented for `[u8]`
|
||||
= note: all function arguments must have a statically known size
|
||||
= help: unsized locals are gated as an unstable feature
|
||||
= help: unsized fn params are gated as an unstable feature
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
fn main() {
|
||||
let Box(a) = loop { };
|
||||
//~^ ERROR expected tuple struct or tuple variant, found struct `Box`
|
||||
//~^ ERROR cannot match against a tuple struct which contains private fields
|
||||
|
||||
// (The below is a trick to allow compiler to infer a type for
|
||||
// variable `a` without attempting to ascribe a type to the
|
||||
|
@ -1,4 +1,4 @@
|
||||
error[E0532]: expected tuple struct or tuple variant, found struct `Box`
|
||||
error[E0532]: cannot match against a tuple struct which contains private fields
|
||||
--> $DIR/issue-38412.rs:2:9
|
||||
|
|
||||
LL | let Box(a) = loop { };
|
||||
|
@ -5,7 +5,7 @@ LL | fn _test(ref _p: str) {}
|
||||
| ^^^^^^ doesn't have a size known at compile-time
|
||||
|
|
||||
= help: the trait `Sized` is not implemented for `str`
|
||||
= help: unsized locals are gated as an unstable feature
|
||||
= help: unsized fn params are gated as an unstable feature
|
||||
help: function arguments must have a statically known size, borrowed types always have a known size
|
||||
|
|
||||
LL | fn _test(ref _p: &str) {}
|
||||
|
@ -1,4 +1,3 @@
|
||||
fn foo(a: [0; 1]) {} //~ ERROR expected type, found `0`
|
||||
//~| ERROR expected `;` or `{`, found `]`
|
||||
|
||||
fn main() {}
|
||||
|
@ -4,11 +4,5 @@ error: expected type, found `0`
|
||||
LL | fn foo(a: [0; 1]) {}
|
||||
| ^ expected type
|
||||
|
||||
error: expected `;` or `{`, found `]`
|
||||
--> $DIR/issue-39616.rs:1:16
|
||||
|
|
||||
LL | fn foo(a: [0; 1]) {}
|
||||
| ^ expected `;` or `{`
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
error: aborting due to previous error
|
||||
|
||||
|
@ -5,7 +5,7 @@ LL | pub fn example(ref s: str) {}
|
||||
| ^^^^^ doesn't have a size known at compile-time
|
||||
|
|
||||
= help: the trait `Sized` is not implemented for `str`
|
||||
= help: unsized locals are gated as an unstable feature
|
||||
= help: unsized fn params are gated as an unstable feature
|
||||
help: function arguments must have a statically known size, borrowed types always have a known size
|
||||
|
|
||||
LL | pub fn example(ref s: &str) {}
|
||||
|
@ -5,7 +5,7 @@ LL | fn baz(_: Self::Target) where Self: Deref {}
|
||||
| ^ doesn't have a size known at compile-time
|
||||
|
|
||||
= help: the trait `Sized` is not implemented for `<Self as Deref>::Target`
|
||||
= help: unsized locals are gated as an unstable feature
|
||||
= help: unsized fn params are gated as an unstable feature
|
||||
help: consider further restricting the associated type
|
||||
|
|
||||
LL | fn baz(_: Self::Target) where Self: Deref, <Self as Deref>::Target: Sized {}
|
||||
@ -22,7 +22,7 @@ LL | pub fn f(_: dyn ToString) {}
|
||||
| ^ doesn't have a size known at compile-time
|
||||
|
|
||||
= help: the trait `Sized` is not implemented for `(dyn ToString + 'static)`
|
||||
= help: unsized locals are gated as an unstable feature
|
||||
= help: unsized fn params are gated as an unstable feature
|
||||
help: function arguments must have a statically known size, borrowed types always have a known size
|
||||
|
|
||||
LL | pub fn f(_: &dyn ToString) {}
|
||||
|
@ -7,7 +7,7 @@ mod bar {
|
||||
|
||||
fn foo() {
|
||||
Bx(());
|
||||
//~^ ERROR expected function, tuple struct or tuple variant, found struct `Bx` [E0423]
|
||||
//~^ ERROR cannot initialize a tuple struct which contains private fields [E0423]
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,8 +1,14 @@
|
||||
error[E0423]: expected function, tuple struct or tuple variant, found struct `Bx`
|
||||
error[E0423]: cannot initialize a tuple struct which contains private fields
|
||||
--> $DIR/issue-42944.rs:9:9
|
||||
|
|
||||
LL | Bx(());
|
||||
| ^^ constructor is not visible here due to private fields
|
||||
| ^^
|
||||
|
|
||||
note: constructor is not visible here due to private fields
|
||||
--> $DIR/issue-42944.rs:2:19
|
||||
|
|
||||
LL | pub struct Bx(());
|
||||
| ^^ private field
|
||||
|
||||
error[E0425]: cannot find function, tuple struct or tuple variant `Bx` in this scope
|
||||
--> $DIR/issue-42944.rs:16:9
|
||||
|
@ -5,11 +5,11 @@ LL | fn new_struct(r: dyn A + 'static)
|
||||
| ^ doesn't have a size known at compile-time
|
||||
|
|
||||
= help: the trait `Sized` is not implemented for `(dyn A + 'static)`
|
||||
= help: unsized locals are gated as an unstable feature
|
||||
= help: unsized fn params are gated as an unstable feature
|
||||
help: function arguments must have a statically known size, borrowed types always have a known size
|
||||
|
|
||||
LL | fn new_struct(r: &dyn A + 'static)
|
||||
| ^
|
||||
LL | fn new_struct(&r: dyn A + 'static)
|
||||
| ^
|
||||
|
||||
error[E0277]: the size for values of type `(dyn A + 'static)` cannot be known at compilation time
|
||||
--> $DIR/issue-5883.rs:8:8
|
||||
|
@ -2,7 +2,7 @@ impl A {
|
||||
//~^ ERROR cannot find type `A` in this scope
|
||||
fn b(self>
|
||||
//~^ ERROR expected one of `)`, `,`, or `:`, found `>`
|
||||
//~| ERROR expected `;` or `{`, found `>`
|
||||
//~| ERROR expected one of `->`, `;`, `where`, or `{`, found `>`
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
@ -6,14 +6,14 @@ LL | fn b(self>
|
||||
| |
|
||||
| unclosed delimiter
|
||||
|
||||
error: expected `;` or `{`, found `>`
|
||||
error: expected one of `->`, `;`, `where`, or `{`, found `>`
|
||||
--> $DIR/issue-58856-1.rs:3:14
|
||||
|
|
||||
LL | impl A {
|
||||
| - while parsing this item list starting here
|
||||
LL |
|
||||
LL | fn b(self>
|
||||
| ^ expected `;` or `{`
|
||||
| ^ expected one of `->`, `;`, `where`, or `{`
|
||||
...
|
||||
LL | }
|
||||
| - the item list ends here
|
||||
|
13
src/test/ui/issues/issue-75906.rs
Normal file
13
src/test/ui/issues/issue-75906.rs
Normal file
@ -0,0 +1,13 @@
|
||||
mod m {
|
||||
pub struct Foo { x: u8 }
|
||||
|
||||
pub struct Bar(u8);
|
||||
}
|
||||
|
||||
use m::{Foo, Bar};
|
||||
|
||||
fn main() {
|
||||
let x = Foo { x: 12 };
|
||||
let y = Bar(12);
|
||||
//~^ ERROR cannot initialize a tuple struct which contains private fields [E0423]
|
||||
}
|
15
src/test/ui/issues/issue-75906.stderr
Normal file
15
src/test/ui/issues/issue-75906.stderr
Normal file
@ -0,0 +1,15 @@
|
||||
error[E0423]: cannot initialize a tuple struct which contains private fields
|
||||
--> $DIR/issue-75906.rs:11:13
|
||||
|
|
||||
LL | let y = Bar(12);
|
||||
| ^^^
|
||||
|
|
||||
note: constructor is not visible here due to private fields
|
||||
--> $DIR/issue-75906.rs:4:20
|
||||
|
|
||||
LL | pub struct Bar(u8);
|
||||
| ^^ private field
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0423`.
|
@ -13,6 +13,6 @@ use foo::{make_bar, Bar, Foo};
|
||||
|
||||
fn main() {
|
||||
let Bar(x, y, Foo(z)) = make_bar();
|
||||
//~^ ERROR expected tuple struct
|
||||
//~| ERROR expected tuple struct
|
||||
//~^ ERROR cannot match against a tuple struct which contains private fields
|
||||
//~| ERROR cannot match against a tuple struct which contains private fields
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
error[E0532]: expected tuple struct or tuple variant, found struct `Bar`
|
||||
error[E0532]: cannot match against a tuple struct which contains private fields
|
||||
--> $DIR/issue-75907.rs:15:9
|
||||
|
|
||||
LL | let Bar(x, y, Foo(z)) = make_bar();
|
||||
@ -12,7 +12,7 @@ LL | let Bar(x, y, Foo(z)) = make_bar();
|
||||
| |
|
||||
| private field
|
||||
|
||||
error[E0532]: expected tuple struct or tuple variant, found struct `Foo`
|
||||
error[E0532]: cannot match against a tuple struct which contains private fields
|
||||
--> $DIR/issue-75907.rs:15:19
|
||||
|
|
||||
LL | let Bar(x, y, Foo(z)) = make_bar();
|
||||
|
@ -7,5 +7,5 @@ use a::{make_bar, Bar};
|
||||
|
||||
fn main() {
|
||||
let Bar(x, y, z) = make_bar();
|
||||
//~^ ERROR expected tuple struct
|
||||
//~^ ERROR cannot match against a tuple struct which contains private fields
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
error[E0532]: expected tuple struct or tuple variant, found struct `Bar`
|
||||
error[E0532]: cannot match against a tuple struct which contains private fields
|
||||
--> $DIR/issue-75907_b.rs:9:9
|
||||
|
|
||||
LL | let Bar(x, y, z) = make_bar();
|
||||
|
@ -1,4 +1,6 @@
|
||||
#![feature(arbitrary_self_types, coerce_unsized, dispatch_from_dyn, unsize, unsized_locals)]
|
||||
#![feature(arbitrary_self_types, coerce_unsized, dispatch_from_dyn, unsize)]
|
||||
#![feature(unsized_locals, unsized_fn_params)]
|
||||
//~^ WARN the feature `unsized_locals` is incomplete
|
||||
|
||||
// This tests a few edge-cases around `arbitrary_self_types`. Most specifically,
|
||||
// it checks that the `ObjectCandidate` you get from method matching can't
|
||||
|
@ -1,5 +1,14 @@
|
||||
warning: the feature `unsized_locals` is incomplete and may not be safe to use and/or cause compiler crashes
|
||||
--> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:2:12
|
||||
|
|
||||
LL | #![feature(unsized_locals, unsized_fn_params)]
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: `#[warn(incomplete_features)]` on by default
|
||||
= note: see issue #48055 <https://github.com/rust-lang/rust/issues/48055> for more information
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:85:24
|
||||
--> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:87:24
|
||||
|
|
||||
LL | let _seetype: () = z;
|
||||
| -- ^ expected `()`, found `u32`
|
||||
@ -7,7 +16,7 @@ LL | let _seetype: () = z;
|
||||
| expected due to this
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:102:24
|
||||
--> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:104:24
|
||||
|
|
||||
LL | let _seetype: () = z;
|
||||
| -- ^ expected `()`, found `u64`
|
||||
@ -15,23 +24,23 @@ LL | let _seetype: () = z;
|
||||
| expected due to this
|
||||
|
||||
error[E0034]: multiple applicable items in scope
|
||||
--> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:120:15
|
||||
--> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:122:15
|
||||
|
|
||||
LL | let z = x.foo();
|
||||
| ^^^ multiple `foo` found
|
||||
|
|
||||
note: candidate #1 is defined in an impl of the trait `X` for the type `T`
|
||||
--> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:43:9
|
||||
--> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:45:9
|
||||
|
|
||||
LL | fn foo(self: Smaht<Self, u64>) -> u64 {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
note: candidate #2 is defined in an impl of the trait `NuisanceFoo` for the type `T`
|
||||
--> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:70:9
|
||||
--> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:72:9
|
||||
|
|
||||
LL | fn foo(self) {}
|
||||
| ^^^^^^^^^^^^
|
||||
note: candidate #3 is defined in the trait `FinalFoo`
|
||||
--> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:57:5
|
||||
--> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:59:5
|
||||
|
|
||||
LL | fn foo(&self) -> u8;
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
@ -49,7 +58,7 @@ LL | let z = FinalFoo::foo(x);
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:137:24
|
||||
--> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:139:24
|
||||
|
|
||||
LL | let _seetype: () = z;
|
||||
| -- ^ expected `()`, found `u8`
|
||||
@ -57,7 +66,7 @@ LL | let _seetype: () = z;
|
||||
| expected due to this
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:155:24
|
||||
--> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:157:24
|
||||
|
|
||||
LL | let _seetype: () = z;
|
||||
| -- ^ expected `()`, found `u32`
|
||||
@ -65,14 +74,14 @@ LL | let _seetype: () = z;
|
||||
| expected due to this
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:172:24
|
||||
--> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:174:24
|
||||
|
|
||||
LL | let _seetype: () = z;
|
||||
| -- ^ expected `()`, found `u32`
|
||||
| |
|
||||
| expected due to this
|
||||
|
||||
error: aborting due to 6 previous errors
|
||||
error: aborting due to 6 previous errors; 1 warning emitted
|
||||
|
||||
Some errors have detailed explanations: E0034, E0308.
|
||||
For more information about an error, try `rustc --explain E0034`.
|
||||
|
@ -1,4 +1,5 @@
|
||||
#![feature(unsized_locals)]
|
||||
//~^ WARN the feature `unsized_locals` is incomplete
|
||||
|
||||
struct A;
|
||||
#[derive(Clone, Copy)]
|
||||
@ -8,13 +9,13 @@ fn main() {
|
||||
let a: Box<[A]> = Box::new([A]);
|
||||
match *a {
|
||||
//~^ ERROR cannot move out of type `[A]`, a non-copy slice
|
||||
[a @ ..] => {},
|
||||
[a @ ..] => {}
|
||||
_ => {}
|
||||
}
|
||||
let b: Box<[A]> = Box::new([A, A, A]);
|
||||
match *b {
|
||||
//~^ ERROR cannot move out of type `[A]`, a non-copy slice
|
||||
[_, _, b @ .., _] => {},
|
||||
[_, _, b @ .., _] => {}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
@ -22,13 +23,13 @@ fn main() {
|
||||
let c: Box<[C]> = Box::new([C]);
|
||||
match *c {
|
||||
//~^ ERROR cannot move out of type `[C]`, a non-copy slice
|
||||
[c @ ..] => {},
|
||||
[c @ ..] => {}
|
||||
_ => {}
|
||||
}
|
||||
let d: Box<[C]> = Box::new([C, C, C]);
|
||||
match *d {
|
||||
//~^ ERROR cannot move out of type `[C]`, a non-copy slice
|
||||
[_, _, d @ .., _] => {},
|
||||
[_, _, d @ .., _] => {}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
@ -1,51 +1,60 @@
|
||||
warning: the feature `unsized_locals` is incomplete and may not be safe to use and/or cause compiler crashes
|
||||
--> $DIR/move-out-of-slice-2.rs:1:12
|
||||
|
|
||||
LL | #![feature(unsized_locals)]
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: `#[warn(incomplete_features)]` on by default
|
||||
= note: see issue #48055 <https://github.com/rust-lang/rust/issues/48055> for more information
|
||||
|
||||
error[E0508]: cannot move out of type `[A]`, a non-copy slice
|
||||
--> $DIR/move-out-of-slice-2.rs:9:11
|
||||
--> $DIR/move-out-of-slice-2.rs:10:11
|
||||
|
|
||||
LL | match *a {
|
||||
| ^^ cannot move out of here
|
||||
LL |
|
||||
LL | [a @ ..] => {},
|
||||
LL | [a @ ..] => {}
|
||||
| ------
|
||||
| |
|
||||
| data moved here
|
||||
| move occurs because `a` has type `[A]`, which does not implement the `Copy` trait
|
||||
|
||||
error[E0508]: cannot move out of type `[A]`, a non-copy slice
|
||||
--> $DIR/move-out-of-slice-2.rs:15:11
|
||||
--> $DIR/move-out-of-slice-2.rs:16:11
|
||||
|
|
||||
LL | match *b {
|
||||
| ^^ cannot move out of here
|
||||
LL |
|
||||
LL | [_, _, b @ .., _] => {},
|
||||
LL | [_, _, b @ .., _] => {}
|
||||
| ------
|
||||
| |
|
||||
| data moved here
|
||||
| move occurs because `b` has type `[A]`, which does not implement the `Copy` trait
|
||||
|
||||
error[E0508]: cannot move out of type `[C]`, a non-copy slice
|
||||
--> $DIR/move-out-of-slice-2.rs:23:11
|
||||
--> $DIR/move-out-of-slice-2.rs:24:11
|
||||
|
|
||||
LL | match *c {
|
||||
| ^^ cannot move out of here
|
||||
LL |
|
||||
LL | [c @ ..] => {},
|
||||
LL | [c @ ..] => {}
|
||||
| ------
|
||||
| |
|
||||
| data moved here
|
||||
| move occurs because `c` has type `[C]`, which does not implement the `Copy` trait
|
||||
|
||||
error[E0508]: cannot move out of type `[C]`, a non-copy slice
|
||||
--> $DIR/move-out-of-slice-2.rs:29:11
|
||||
--> $DIR/move-out-of-slice-2.rs:30:11
|
||||
|
|
||||
LL | match *d {
|
||||
| ^^ cannot move out of here
|
||||
LL |
|
||||
LL | [_, _, d @ .., _] => {},
|
||||
LL | [_, _, d @ .., _] => {}
|
||||
| ------
|
||||
| |
|
||||
| data moved here
|
||||
| move occurs because `d` has type `[C]`, which does not implement the `Copy` trait
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
error: aborting due to 4 previous errors; 1 warning emitted
|
||||
|
||||
For more information about this error, try `rustc --explain E0508`.
|
||||
|
5
src/test/ui/parser/fn-colon-return-type.rs
Normal file
5
src/test/ui/parser/fn-colon-return-type.rs
Normal file
@ -0,0 +1,5 @@
|
||||
fn foo(x: i32): i32 { //~ ERROR expected one of `->`, `;`, `where`, or `{`, found `:`
|
||||
x
|
||||
}
|
||||
|
||||
fn main() {}
|
8
src/test/ui/parser/fn-colon-return-type.stderr
Normal file
8
src/test/ui/parser/fn-colon-return-type.stderr
Normal file
@ -0,0 +1,8 @@
|
||||
error: expected one of `->`, `;`, `where`, or `{`, found `:`
|
||||
--> $DIR/fn-colon-return-type.rs:1:15
|
||||
|
|
||||
LL | fn foo(x: i32): i32 {
|
||||
| ^ expected one of `->`, `;`, `where`, or `{`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
@ -1,8 +1,9 @@
|
||||
// Verify that '>' is not both expected and found at the same time, as it used
|
||||
// to happen in #24780. For example, following should be an error:
|
||||
// expected one of ..., `>`, ... found `>`
|
||||
// expected one of ..., `>`, ... found `>`. No longer exactly this, but keeping for posterity.
|
||||
|
||||
fn foo() -> Vec<usize>> {
|
||||
//~^ ERROR expected `;` or `{`, found `>`
|
||||
fn foo() -> Vec<usize>> { //~ ERROR unmatched angle bracket
|
||||
Vec::new()
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
@ -1,8 +1,8 @@
|
||||
error: expected `;` or `{`, found `>`
|
||||
error: unmatched angle bracket
|
||||
--> $DIR/issue-24780.rs:5:23
|
||||
|
|
||||
LL | fn foo() -> Vec<usize>> {
|
||||
| ^ expected `;` or `{`
|
||||
| ^^ help: remove extra angle bracket
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
@ -1,3 +1,3 @@
|
||||
trait Foo { fn a() } //~ ERROR expected `;` or `{`, found `}`
|
||||
trait Foo { fn a() } //~ ERROR expected one of `->`, `;`, `where`, or `{`, found `}`
|
||||
|
||||
fn main() {}
|
||||
|
@ -1,12 +1,10 @@
|
||||
error: expected `;` or `{`, found `}`
|
||||
error: expected one of `->`, `;`, `where`, or `{`, found `}`
|
||||
--> $DIR/issue-6610.rs:1:20
|
||||
|
|
||||
LL | trait Foo { fn a() }
|
||||
| - ^
|
||||
| | |
|
||||
| | expected `;` or `{`
|
||||
| | the item list ends here
|
||||
| while parsing this item list starting here
|
||||
| - ^ expected one of `->`, `;`, `where`, or `{`
|
||||
| |
|
||||
| while parsing this `fn`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
@ -22,11 +22,11 @@ error: expected one of `:` or `|`, found `)`
|
||||
LL | fn main((ؼ
|
||||
| ^ expected one of `:` or `|`
|
||||
|
||||
error: expected `;` or `{`, found `<eof>`
|
||||
error: expected one of `->`, `;`, `where`, or `{`, found `<eof>`
|
||||
--> $DIR/missing_right_paren.rs:3:11
|
||||
|
|
||||
LL | fn main((ؼ
|
||||
| ^ expected `;` or `{`
|
||||
| ^ expected one of `->`, `;`, `where`, or `{`
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
|
@ -1,6 +1,5 @@
|
||||
// error-pattern: lt
|
||||
|
||||
fn f(a: isize, b: isize) : lt(a, b) { }
|
||||
//~^ ERROR expected one of `->`, `;`, `where`, or `{`, found `:`
|
||||
|
||||
fn lt(a: isize, b: isize) { }
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
error: expected `;` or `{`, found `:`
|
||||
--> $DIR/not-a-pred.rs:3:26
|
||||
error: expected one of `->`, `;`, `where`, or `{`, found `:`
|
||||
--> $DIR/not-a-pred.rs:1:26
|
||||
|
|
||||
LL | fn f(a: isize, b: isize) : lt(a, b) { }
|
||||
| ^ expected `;` or `{`
|
||||
| ^ expected one of `->`, `;`, `where`, or `{`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
@ -5,11 +5,11 @@ LL | fn foo(_x: K) {}
|
||||
| ^^ doesn't have a size known at compile-time
|
||||
|
|
||||
= help: the trait `Sized` is not implemented for `(dyn I + 'static)`
|
||||
= help: unsized locals are gated as an unstable feature
|
||||
= help: unsized fn params are gated as an unstable feature
|
||||
help: function arguments must have a statically known size, borrowed types always have a known size
|
||||
|
|
||||
LL | fn foo(_x: &K) {}
|
||||
| ^
|
||||
LL | fn foo(&_x: K) {}
|
||||
| ^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
@ -18,7 +18,7 @@ fn main() {
|
||||
//~^ ERROR `..` required with struct marked as non-exhaustive
|
||||
|
||||
let ts = TupleStruct(640, 480);
|
||||
//~^ ERROR expected function, tuple struct or tuple variant, found struct `TupleStruct` [E0423]
|
||||
//~^ ERROR cannot initialize a tuple struct which contains private fields [E0423]
|
||||
|
||||
let ts_explicit = structs::TupleStruct(640, 480);
|
||||
//~^ ERROR tuple struct constructor `TupleStruct` is private [E0603]
|
||||
|
@ -1,4 +1,4 @@
|
||||
error[E0423]: expected function, tuple struct or tuple variant, found struct `TupleStruct`
|
||||
error[E0423]: cannot initialize a tuple struct which contains private fields
|
||||
--> $DIR/struct.rs:20:14
|
||||
|
|
||||
LL | let ts = TupleStruct(640, 480);
|
||||
|
@ -6,11 +6,11 @@ LL | fn f(p: Path) { }
|
||||
|
|
||||
= help: within `Path`, the trait `Sized` is not implemented for `[u8]`
|
||||
= note: required because it appears within the type `Path`
|
||||
= help: unsized locals are gated as an unstable feature
|
||||
= help: unsized fn params are gated as an unstable feature
|
||||
help: function arguments must have a statically known size, borrowed types always have a known size
|
||||
|
|
||||
LL | fn f(p: &Path) { }
|
||||
| ^
|
||||
LL | fn f(&p: Path) { }
|
||||
| ^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
@ -13,11 +13,11 @@ LL | fn foo(_x: Foo + Send) {
|
||||
| ^^ doesn't have a size known at compile-time
|
||||
|
|
||||
= help: the trait `Sized` is not implemented for `(dyn Foo + Send + 'static)`
|
||||
= help: unsized locals are gated as an unstable feature
|
||||
= help: unsized fn params are gated as an unstable feature
|
||||
help: function arguments must have a statically known size, borrowed types always have a known size
|
||||
|
|
||||
LL | fn foo(_x: &Foo + Send) {
|
||||
| ^
|
||||
LL | fn foo(&_x: Foo + Send) {
|
||||
| ^
|
||||
|
||||
error: aborting due to previous error; 1 warning emitted
|
||||
|
||||
|
@ -5,7 +5,7 @@ LL | let f: &mut dyn FnMut<(_,), Output = ()> = &mut |_: <() as Lt<'_>>::T|
|
||||
| ^ doesn't have a size known at compile-time
|
||||
|
|
||||
= help: the trait `Sized` is not implemented for `<() as Lt<'_>>::T`
|
||||
= help: unsized locals are gated as an unstable feature
|
||||
= help: unsized fn params are gated as an unstable feature
|
||||
help: consider further restricting the associated type
|
||||
|
|
||||
LL | fn main() where <() as Lt<'_>>::T: Sized {
|
||||
|
@ -1,6 +1,7 @@
|
||||
// run-pass
|
||||
|
||||
#![feature(unsized_locals)]
|
||||
#![allow(incomplete_features)]
|
||||
#![feature(unsized_locals, unsized_fn_params)]
|
||||
|
||||
pub trait Foo {
|
||||
fn foo(self) -> String;
|
||||
@ -24,7 +25,6 @@ impl Foo for dyn FnMut() -> String {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn main() {
|
||||
let x = *(Box::new(['h', 'e', 'l', 'l', 'o']) as Box<[char]>);
|
||||
assert_eq!(&x.foo() as &str, "hello");
|
||||
|
@ -1,3 +1,3 @@
|
||||
#![feature(unsized_locals)]
|
||||
#![feature(unsized_locals, unsized_fn_params)]
|
||||
|
||||
pub fn udrop<T: ?Sized>(_x: T) {}
|
||||
|
@ -1,4 +1,5 @@
|
||||
#![feature(unsized_locals)]
|
||||
#![feature(unsized_locals, unsized_fn_params)]
|
||||
//~^ WARN the feature `unsized_locals` is incomplete
|
||||
|
||||
pub trait Foo {
|
||||
fn foo(self) -> String;
|
||||
|
@ -1,5 +1,14 @@
|
||||
warning: the feature `unsized_locals` is incomplete and may not be safe to use and/or cause compiler crashes
|
||||
--> $DIR/borrow-after-move.rs:1:12
|
||||
|
|
||||
LL | #![feature(unsized_locals, unsized_fn_params)]
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: `#[warn(incomplete_features)]` on by default
|
||||
= note: see issue #48055 <https://github.com/rust-lang/rust/issues/48055> for more information
|
||||
|
||||
error[E0382]: borrow of moved value: `x`
|
||||
--> $DIR/borrow-after-move.rs:20:24
|
||||
--> $DIR/borrow-after-move.rs:21:24
|
||||
|
|
||||
LL | let y = *x;
|
||||
| -- value moved here
|
||||
@ -10,7 +19,7 @@ LL | println!("{}", &x);
|
||||
= note: move occurs because `*x` has type `str`, which does not implement the `Copy` trait
|
||||
|
||||
error[E0382]: borrow of moved value: `y`
|
||||
--> $DIR/borrow-after-move.rs:22:24
|
||||
--> $DIR/borrow-after-move.rs:23:24
|
||||
|
|
||||
LL | let y = *x;
|
||||
| - move occurs because `y` has type `str`, which does not implement the `Copy` trait
|
||||
@ -21,7 +30,7 @@ LL | println!("{}", &y);
|
||||
| ^^ value borrowed here after move
|
||||
|
||||
error[E0382]: borrow of moved value: `x`
|
||||
--> $DIR/borrow-after-move.rs:30:24
|
||||
--> $DIR/borrow-after-move.rs:31:24
|
||||
|
|
||||
LL | let y = *x;
|
||||
| -- value moved here
|
||||
@ -32,7 +41,7 @@ LL | println!("{}", &x);
|
||||
= note: move occurs because `*x` has type `str`, which does not implement the `Copy` trait
|
||||
|
||||
error[E0382]: borrow of moved value: `y`
|
||||
--> $DIR/borrow-after-move.rs:32:24
|
||||
--> $DIR/borrow-after-move.rs:33:24
|
||||
|
|
||||
LL | let y = *x;
|
||||
| - move occurs because `y` has type `str`, which does not implement the `Copy` trait
|
||||
@ -43,13 +52,13 @@ 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
|
||||
--> $DIR/borrow-after-move.rs:5:12
|
||||
|
|
||||
LL | fn foo(self) -> String;
|
||||
| ^^^^
|
||||
|
||||
error[E0382]: borrow of moved value: `x`
|
||||
--> $DIR/borrow-after-move.rs:39:24
|
||||
--> $DIR/borrow-after-move.rs:40:24
|
||||
|
|
||||
LL | let x = "hello".to_owned().into_boxed_str();
|
||||
| - move occurs because `x` has type `Box<str>`, which does not implement the `Copy` trait
|
||||
@ -58,6 +67,6 @@ LL | x.foo();
|
||||
LL | println!("{}", &x);
|
||||
| ^^ value borrowed here after move
|
||||
|
||||
error: aborting due to 5 previous errors
|
||||
error: aborting due to 5 previous errors; 1 warning emitted
|
||||
|
||||
For more information about this error, try `rustc --explain E0382`.
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user