Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rollup of 6 pull requests #71467

Merged
merged 27 commits into from
Apr 23, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
4eaf535
Treat RETURN_PLACE as a normal Local
jonas-schievink Apr 15, 2020
a417f96
Remove null places
jonas-schievink Apr 15, 2020
34ed891
Fix pop_stack_frame logic
jonas-schievink Apr 15, 2020
0fda0fd
Dump return_place upon returning
jonas-schievink Apr 15, 2020
c5bfbb6
Update const prop
jonas-schievink Apr 16, 2020
a5c1851
Fix codegen and mir-opt tests
jonas-schievink Apr 16, 2020
f0ab469
Remove unnecessary block
jonas-schievink Apr 16, 2020
1ce6e6a
Bless 32-bit test output
jonas-schievink Apr 16, 2020
9e6f38a
Use copy_op_transmute
jonas-schievink Apr 17, 2020
415fd0c
const prop: don't special case return place
jonas-schievink Apr 19, 2020
57c2712
Improve E0308 error message wording again
DeeDeeG Apr 21, 2020
e97c227
Remove outdated reference to interpreter snapshotting
ecstatic-morse Apr 22, 2020
b3c26de
Inline some function docs re-exported in `std::ptr`
ecstatic-morse Apr 23, 2020
a135ced
Fix ui test blessing when a test has an empty stderr file after havin…
oli-obk Mar 16, 2020
6a3fb26
Rename `Item` to `ConstCx`.
oli-obk Mar 23, 2020
f0f7a59
Use ConstCx in more places
oli-obk Apr 2, 2020
0bc743e
Use ConstCx in the promoted collector
oli-obk Apr 2, 2020
cffd4b6
Improve E0567 explanation
GuillaumeGomez Apr 23, 2020
22a5379
Use `ConstCx` for `validate_candidates`
oli-obk Apr 2, 2020
119c636
Catch and fix explicit promotions that fail to actually promote
oli-obk Apr 6, 2020
4cdc31b
Document our sanity assertion around explicit promotion
oli-obk Apr 16, 2020
61fbc6a
Rollup merge of #71005 - jonas-schievink:no-place-like-return, r=oli-obk
Dylan-DPC Apr 23, 2020
629a613
Rollup merge of #71198 - oli-obk:const_check_cleanup, r=RalfJung
Dylan-DPC Apr 23, 2020
4ae7037
Rollup merge of #71396 - DeeDeeG:improve-e0308-again, r=estebank
Dylan-DPC Apr 23, 2020
414355b
Rollup merge of #71452 - ecstatic-morse:no-more-snapshot, r=RalfJung
Dylan-DPC Apr 23, 2020
98cadb2
Rollup merge of #71454 - ecstatic-morse:inline-core-ptr-docs, r=RalfJung
Dylan-DPC Apr 23, 2020
47e2687
Rollup merge of #71461 - GuillaumeGomez:improve-e0567, r=Dylan-DPC
Dylan-DPC Apr 23, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/libcore/ptr/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,12 +76,15 @@ use crate::intrinsics::{self, is_aligned_and_not_null, is_nonoverlapping};
use crate::mem::{self, MaybeUninit};

#[stable(feature = "rust1", since = "1.0.0")]
#[doc(inline)]
pub use crate::intrinsics::copy_nonoverlapping;

#[stable(feature = "rust1", since = "1.0.0")]
#[doc(inline)]
pub use crate::intrinsics::copy;

#[stable(feature = "rust1", since = "1.0.0")]
#[doc(inline)]
pub use crate::intrinsics::write_bytes;

mod non_null;
Expand Down
9 changes: 4 additions & 5 deletions src/librustc_error_codes/error_codes/E0308.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,7 @@ let x: i32 = "I am not a number!";
// type `i32` assigned to variable `x`
```

This error occurs when the compiler was unable to infer the concrete type of a
variable. It can happen in several cases, the most common being a mismatch
between the type that the compiler inferred for a variable based on its
initializing expression, on the one hand, and the type the author explicitly
assigned to the variable, on the other hand.
This error occurs when the compiler is unable to infer the concrete type of a
variable. It can occur in several cases, the most common being a mismatch
between two types: the type the author explicitly assigned, and the type the
compiler inferred.
6 changes: 2 additions & 4 deletions src/librustc_error_codes/error_codes/E0567.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@ Erroneous code example:
#![feature(optin_builtin_traits)]

auto trait Generic<T> {} // error!

fn main() {}
# fn main() {}
```

Since an auto trait is implemented on all existing types, the
Expand All @@ -20,6 +19,5 @@ To fix this issue, just remove the generics:
#![feature(optin_builtin_traits)]

auto trait Generic {} // ok!

fn main() {}
# fn main() {}
```
2 changes: 0 additions & 2 deletions src/librustc_middle/mir/interpret/allocation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,6 @@ use super::{
read_target_uint, write_target_uint, AllocId, InterpResult, Pointer, Scalar, ScalarMaybeUndef,
};

// NOTE: When adding new fields, make sure to adjust the `Snapshot` impl in
// `src/librustc_mir/interpret/snapshot.rs`.
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)]
#[derive(HashStable)]
pub struct Allocation<Tag = (), Extra = ()> {
Expand Down
3 changes: 0 additions & 3 deletions src/librustc_middle/mir/interpret/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -361,8 +361,6 @@ pub enum UndefinedBehaviorInfo {
InvalidUndefBytes(Option<Pointer>),
/// Working with a local that is not currently live.
DeadLocal,
/// Trying to read from the return place of a function.
ReadFromReturnPlace,
}

impl fmt::Debug for UndefinedBehaviorInfo {
Expand Down Expand Up @@ -424,7 +422,6 @@ impl fmt::Debug for UndefinedBehaviorInfo {
"using uninitialized data, but this operation requires initialized memory"
),
DeadLocal => write!(f, "accessing a dead local variable"),
ReadFromReturnPlace => write!(f, "reading from return place"),
}
}
}
Expand Down
5 changes: 0 additions & 5 deletions src/librustc_middle/mir/interpret/value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -188,11 +188,6 @@ impl<'tcx, Tag> Scalar<Tag> {
}
}

#[inline]
pub fn null_ptr(cx: &impl HasDataLayout) -> Self {
Scalar::Raw { data: 0, size: cx.data_layout().pointer_size.bytes() as u8 }
}

#[inline]
pub fn zst() -> Self {
Scalar::Raw { data: 0, size: 0 }
Expand Down
16 changes: 11 additions & 5 deletions src/librustc_mir/borrow_check/type_check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,10 @@ use rustc_trait_selection::traits::{self, ObligationCause, PredicateObligations}
use crate::dataflow::move_paths::MoveData;
use crate::dataflow::MaybeInitializedPlaces;
use crate::dataflow::ResultsCursor;
use crate::transform::promote_consts::should_suggest_const_in_array_repeat_expressions_attribute;
use crate::transform::{
check_consts::ConstCx,
promote_consts::should_suggest_const_in_array_repeat_expressions_attribute,
};

use crate::borrow_check::{
borrow_set::BorrowSet,
Expand Down Expand Up @@ -1984,14 +1987,17 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
let span = body.source_info(location).span;
let ty = operand.ty(body, tcx);
if !self.infcx.type_is_copy_modulo_regions(self.param_env, ty, span) {
let ccx = ConstCx::new_with_param_env(
tcx,
self.mir_def_id,
body,
self.param_env,
);
// To determine if `const_in_array_repeat_expressions` feature gate should
// be mentioned, need to check if the rvalue is promotable.
let should_suggest =
should_suggest_const_in_array_repeat_expressions_attribute(
tcx,
self.mir_def_id,
body,
operand,
&ccx, operand,
);
debug!("check_rvalue: should_suggest={:?}", should_suggest);

Expand Down
76 changes: 31 additions & 45 deletions src/librustc_mir/interpret/eval_context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -628,35 +628,30 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
let frame = M::init_frame_extra(self, pre_frame)?;
self.stack_mut().push(frame);

// don't allocate at all for trivial constants
if body.local_decls.len() > 1 {
// Locals are initially uninitialized.
let dummy = LocalState { value: LocalValue::Uninitialized, layout: Cell::new(None) };
let mut locals = IndexVec::from_elem(dummy, &body.local_decls);
// Return place is handled specially by the `eval_place` functions, and the
// entry in `locals` should never be used. Make it dead, to be sure.
locals[mir::RETURN_PLACE].value = LocalValue::Dead;
// Now mark those locals as dead that we do not want to initialize
match self.tcx.def_kind(instance.def_id()) {
// statics and constants don't have `Storage*` statements, no need to look for them
//
// FIXME: The above is likely untrue. See
// <https://github.com/rust-lang/rust/pull/70004#issuecomment-602022110>. Is it
// okay to ignore `StorageDead`/`StorageLive` annotations during CTFE?
Some(DefKind::Static | DefKind::Const | DefKind::AssocConst) => {}
_ => {
// Mark locals that use `Storage*` annotations as dead on function entry.
let always_live = AlwaysLiveLocals::new(self.body());
for local in locals.indices() {
if !always_live.contains(local) {
locals[local].value = LocalValue::Dead;
}
// Locals are initially uninitialized.
let dummy = LocalState { value: LocalValue::Uninitialized, layout: Cell::new(None) };
let mut locals = IndexVec::from_elem(dummy, &body.local_decls);

// Now mark those locals as dead that we do not want to initialize
match self.tcx.def_kind(instance.def_id()) {
// statics and constants don't have `Storage*` statements, no need to look for them
//
// FIXME: The above is likely untrue. See
// <https://github.com/rust-lang/rust/pull/70004#issuecomment-602022110>. Is it
// okay to ignore `StorageDead`/`StorageLive` annotations during CTFE?
Some(DefKind::Static | DefKind::Const | DefKind::AssocConst) => {}
_ => {
// Mark locals that use `Storage*` annotations as dead on function entry.
let always_live = AlwaysLiveLocals::new(self.body());
for local in locals.indices() {
if !always_live.contains(local) {
locals[local].value = LocalValue::Dead;
}
}
}
// done
self.frame_mut().locals = locals;
}
// done
self.frame_mut().locals = locals;

M::after_stack_push(self)?;
info!("ENTERING({}) {}", self.frame_idx(), self.frame().instance);
Expand Down Expand Up @@ -734,6 +729,17 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
let frame =
self.stack_mut().pop().expect("tried to pop a stack frame, but there were none");

if !unwinding {
// Copy the return value to the caller's stack frame.
if let Some(return_place) = frame.return_place {
let op = self.access_local(&frame, mir::RETURN_PLACE, None)?;
self.copy_op_transmute(op, return_place)?;
self.dump_place(*return_place);
} else {
throw_ub!(Unreachable);
}
}

// Now where do we jump next?

// Usually we want to clean up (deallocate locals), but in a few rare cases we don't.
Expand All @@ -759,7 +765,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
self.deallocate_local(local.value)?;
}

let return_place = frame.return_place;
if M::after_stack_pop(self, frame, unwinding)? == StackPopJump::NoJump {
// The hook already did everything.
// We want to skip the `info!` below, hence early return.
Expand All @@ -772,25 +777,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
self.unwind_to_block(unwind);
} else {
// Follow the normal return edge.
// Validate the return value. Do this after deallocating so that we catch dangling
// references.
if let Some(return_place) = return_place {
if M::enforce_validity(self) {
// Data got changed, better make sure it matches the type!
// It is still possible that the return place held invalid data while
// the function is running, but that's okay because nobody could have
// accessed that same data from the "outside" to observe any broken
// invariant -- that is, unless a function somehow has a ptr to
// its return place... but the way MIR is currently generated, the
// return place is always a local and then this cannot happen.
self.validate_operand(self.place_to_op(return_place)?)?;
}
} else {
// Uh, that shouldn't happen... the function did not intend to return
throw_ub!(Unreachable);
}

// Jump to new block -- *after* validation so that the spans make more sense.
if let Some(ret) = next_block {
self.return_to_block(ret)?;
}
Expand Down
16 changes: 5 additions & 11 deletions src/librustc_mir/interpret/operand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -419,7 +419,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
local: mir::Local,
layout: Option<TyAndLayout<'tcx>>,
) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> {
assert_ne!(local, mir::RETURN_PLACE);
let layout = self.layout_of_local(frame, local, layout)?;
let op = if layout.is_zst() {
// Do not read from ZST, they might not be initialized
Expand Down Expand Up @@ -454,16 +453,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
place: mir::Place<'tcx>,
layout: Option<TyAndLayout<'tcx>>,
) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> {
let base_op = match place.local {
mir::RETURN_PLACE => throw_ub!(ReadFromReturnPlace),
local => {
// Do not use the layout passed in as argument if the base we are looking at
// here is not the entire place.
let layout = if place.projection.is_empty() { layout } else { None };

self.access_local(self.frame(), local, layout)?
}
};
// Do not use the layout passed in as argument if the base we are looking at
// here is not the entire place.
let layout = if place.projection.is_empty() { layout } else { None };

let base_op = self.access_local(self.frame(), place.local, layout)?;

let op = place
.projection
Expand Down
45 changes: 4 additions & 41 deletions src/librustc_mir/interpret/place.rs
Original file line number Diff line number Diff line change
Expand Up @@ -135,12 +135,6 @@ impl<Tag> MemPlace<Tag> {
MemPlace { ptr, align, meta: MemPlaceMeta::None }
}

/// Produces a Place that will error if attempted to be read from or written to
#[inline(always)]
fn null(cx: &impl HasDataLayout) -> Self {
Self::from_scalar_ptr(Scalar::null_ptr(cx), Align::from_bytes(1).unwrap())
}

#[inline(always)]
pub fn from_ptr(ptr: Pointer<Tag>, align: Align) -> Self {
Self::from_scalar_ptr(ptr.into(), align)
Expand Down Expand Up @@ -260,12 +254,6 @@ impl<'tcx, Tag: ::std::fmt::Debug + Copy> OpTy<'tcx, Tag> {
}

impl<Tag: ::std::fmt::Debug> Place<Tag> {
/// Produces a Place that will error if attempted to be read from or written to
#[inline(always)]
fn null(cx: &impl HasDataLayout) -> Self {
Place::Ptr(MemPlace::null(cx))
}

#[inline]
pub fn assert_mem_place(self) -> MemPlace<Tag> {
match self {
Expand Down Expand Up @@ -641,35 +629,10 @@ where
&mut self,
place: mir::Place<'tcx>,
) -> InterpResult<'tcx, PlaceTy<'tcx, M::PointerTag>> {
let mut place_ty = match place.local {
mir::RETURN_PLACE => {
// `return_place` has the *caller* layout, but we want to use our
// `layout to verify our assumption. The caller will validate
// their layout on return.
PlaceTy {
place: match self.frame().return_place {
Some(p) => *p,
// Even if we don't have a return place, we sometimes need to
// create this place, but any attempt to read from / write to it
// (even a ZST read/write) needs to error, so let us make this
// a NULL place.
//
// FIXME: Ideally we'd make sure that the place projections also
// bail out.
None => Place::null(&*self),
},
layout: self.layout_of(
self.subst_from_current_frame_and_normalize_erasing_regions(
self.frame().body.return_ty(),
),
)?,
}
}
local => PlaceTy {
// This works even for dead/uninitialized locals; we check further when writing
place: Place::Local { frame: self.frame_idx(), local },
layout: self.layout_of_local(self.frame(), local, None)?,
},
let mut place_ty = PlaceTy {
// This works even for dead/uninitialized locals; we check further when writing
place: Place::Local { frame: self.frame_idx(), local: place.local },
layout: self.layout_of_local(self.frame(), place.local, None)?,
};

for elem in place.projection.iter() {
Expand Down
1 change: 0 additions & 1 deletion src/librustc_mir/interpret/terminator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
use rustc_middle::mir::TerminatorKind::*;
match terminator.kind {
Return => {
self.frame().return_place.map(|r| self.dump_place(*r));
self.pop_stack_frame(/* unwinding */ false)?
}

Expand Down
15 changes: 12 additions & 3 deletions src/librustc_mir/transform/check_consts/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,20 +20,29 @@ pub mod validation;

/// Information about the item currently being const-checked, as well as a reference to the global
/// context.
pub struct Item<'mir, 'tcx> {
pub struct ConstCx<'mir, 'tcx> {
pub body: &'mir mir::Body<'tcx>,
pub tcx: TyCtxt<'tcx>,
pub def_id: DefId,
pub param_env: ty::ParamEnv<'tcx>,
pub const_kind: Option<ConstKind>,
}

impl Item<'mir, 'tcx> {
impl ConstCx<'mir, 'tcx> {
pub fn new(tcx: TyCtxt<'tcx>, def_id: DefId, body: &'mir mir::Body<'tcx>) -> Self {
let param_env = tcx.param_env(def_id);
Self::new_with_param_env(tcx, def_id, body, param_env)
}

pub fn new_with_param_env(
tcx: TyCtxt<'tcx>,
def_id: DefId,
body: &'mir mir::Body<'tcx>,
param_env: ty::ParamEnv<'tcx>,
) -> Self {
let const_kind = ConstKind::for_item(tcx, def_id);

Item { body, tcx, def_id, param_env, const_kind }
ConstCx { body, tcx, def_id, param_env, const_kind }
}

/// Returns the kind of const context this `Item` represents (`const`, `static`, etc.).
Expand Down
Loading