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 9 pull requests #70174

Merged
merged 23 commits into from
Mar 20, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
cdc7304
Compute the correct layout for variants of uninhabited enums and read…
oli-obk Mar 6, 2020
ec88ffa
Comment nits
oli-obk Mar 11, 2020
74608c7
Rustfmt and adjust capitalization
oli-obk Mar 11, 2020
bee1513
codegen/mir: support polymorphic `InstanceDef`s
davidtwco Mar 11, 2020
fda913b
Add regression test for TAIT lifetime inference (issue #55099)
Aaron1011 Mar 19, 2020
410cd7a
remove unused imports
stlankes Mar 19, 2020
2c38ecf
doc: Add quote to .init_array
tesuji Mar 19, 2020
be06f67
Clean up E0437 explanation
GuillaumeGomez Mar 18, 2020
6f16118
Clean up e0438 explanation
GuillaumeGomez Mar 19, 2020
8e0398c
Clarify the relationship between `forget()` and `ManuallyDrop`.
hniksic Mar 1, 2020
2a08b0e
Restore (and reword) the warning against passing invalid values to me…
hniksic Mar 4, 2020
7554341
Minor re-wordings and typo fixes.
hniksic Mar 18, 2020
2bebe8d
Don't hard-code the vector length in the examples.
hniksic Mar 19, 2020
89ef59a
triagebot.toml: accept typo due to pnkfelix
Centril Mar 19, 2020
5d39517
Rollup merge of #69618 - hniksic:mem-forget-doc-fix, r=RalfJung
JohnTitor Mar 20, 2020
3554f2d
Rollup merge of #69768 - oli-obk:union_field_ice, r=eddyb,RalfJung
JohnTitor Mar 20, 2020
9dc6994
Rollup merge of #69935 - davidtwco:issue-69925, r=eddyb
JohnTitor Mar 20, 2020
532133b
Rollup merge of #70103 - GuillaumeGomez:cleanup-e0437, r=Dylan-DPC
JohnTitor Mar 20, 2020
2f77d5f
Rollup merge of #70131 - Aaron1011:fix/issue-55099-test, r=nikomatsakis
JohnTitor Mar 20, 2020
8615a36
Rollup merge of #70133 - hermitcore:libpanic_unwind, r=nikomatsakis
JohnTitor Mar 20, 2020
d6ebf21
Rollup merge of #70145 - lzutao:patch-1, r=Dylan-DPC
JohnTitor Mar 20, 2020
8965f63
Rollup merge of #70146 - GuillaumeGomez:cleanup-e0438, r=Dylan-DPC
JohnTitor Mar 20, 2020
43c7a50
Rollup merge of #70150 - rust-lang:accept-felixes-typo, r=Mark-Simula…
JohnTitor Mar 20, 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
65 changes: 49 additions & 16 deletions src/libcore/mem/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,9 @@ pub use crate::intrinsics::transmute;
///
/// # Examples
///
/// Leak an I/O object, never closing the file:
/// The canonical safe use of `mem::forget` is to circumvent a value's destructor
/// implemented by the `Drop` trait. For example, this will leak a `File`, i.e. reclaim
/// the space taken by the variable but never close the underlying system resource:
///
/// ```no_run
/// use std::mem;
Expand All @@ -68,9 +70,40 @@ pub use crate::intrinsics::transmute;
/// mem::forget(file);
/// ```
///
/// The practical use cases for `forget` are rather specialized and mainly come
/// up in unsafe or FFI code. However, [`ManuallyDrop`] is usually preferred
/// for such cases, e.g.:
/// This is useful when the ownership of the underlying resource was previously
/// transferred to code outside of Rust, for example by transmitting the raw
/// file descriptor to C code.
///
/// # Relationship with `ManuallyDrop`
///
/// While `mem::forget` can also be used to transfer *memory* ownership, doing so is error-prone.
/// [`ManuallyDrop`] should be used instead. Consider, for example, this code:
///
/// ```
/// use std::mem;
///
/// let mut v = vec![65, 122];
/// // Build a `String` using the contents of `v`
/// let s = unsafe { String::from_raw_parts(v.as_mut_ptr(), v.len(), v.capacity()) };
/// // leak `v` because its memory is now managed by `s`
/// mem::forget(v); // ERROR - v is invalid and must not be passed to a function
/// assert_eq!(s, "Az");
/// // `s` is implicitly dropped and its memory deallocated.
/// ```
///
/// There are two issues with the above example:
///
/// * If more code were added between the construction of `String` and the invocation of
/// `mem::forget()`, a panic within it would cause a double free because the same memory
/// is handled by both `v` and `s`.
/// * After calling `v.as_mut_ptr()` and transmitting the ownership of the data to `s`,
/// the `v` value is invalid. Even when a value is just moved to `mem::forget` (which won't
/// inspect it), some types have strict requirements on their values that
/// make them invalid when dangling or no longer owned. Using invalid values in any
/// way, including passing them to or returning them from functions, constitutes
/// undefined behavior and may break the assumptions made by the compiler.
///
/// Switching to `ManuallyDrop` avoids both issues:
///
/// ```
/// use std::mem::ManuallyDrop;
Expand All @@ -80,24 +113,24 @@ pub use crate::intrinsics::transmute;
/// // does not get dropped!
/// let mut v = ManuallyDrop::new(v);
/// // Now disassemble `v`. These operations cannot panic, so there cannot be a leak.
/// let ptr = v.as_mut_ptr();
/// let cap = v.capacity();
/// let (ptr, len, cap) = (v.as_mut_ptr(), v.len(), v.capacity());
/// // Finally, build a `String`.
/// let s = unsafe { String::from_raw_parts(ptr, 2, cap) };
/// let s = unsafe { String::from_raw_parts(ptr, len, cap) };
/// assert_eq!(s, "Az");
/// // `s` is implicitly dropped and its memory deallocated.
/// ```
///
/// Using `ManuallyDrop` here has two advantages:
/// `ManuallyDrop` robustly prevents double-free because we disable `v`'s destructor
/// before doing anything else. `mem::forget()` doesn't allow this because it consumes its
/// argument, forcing us to call it only after extracting anything we need from `v`. Even
/// if a panic were introduced between construction of `ManuallyDrop` and building the
/// string (which cannot happen in the code as shown), it would result in a leak and not a
/// double free. In other words, `ManuallyDrop` errs on the side of leaking instead of
/// erring on the side of (double-)dropping.
///
/// * We do not "touch" `v` after disassembling it. For some types, operations
/// such as passing ownership (to a function like `mem::forget`) requires them to actually
/// be fully owned right now; that is a promise we do not want to make here as we are
/// in the process of transferring ownership to the new `String` we are building.
/// * In case of an unexpected panic, `ManuallyDrop` is not dropped, but if the panic
/// occurs before `mem::forget` was called we might end up dropping invalid data,
/// or double-dropping. In other words, `ManuallyDrop` errs on the side of leaking
/// instead of erring on the side of dropping.
/// Also, `ManuallyDrop` prevents us from having to "touch" `v` after transferring the
/// ownership to `s` - the final step of interacting with `v` to dispoe of it without
/// running its destructor is entirely avoided.
///
/// [drop]: fn.drop.html
/// [uninit]: fn.uninitialized.html
Expand Down
1 change: 0 additions & 1 deletion src/libpanic_unwind/hermit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

use alloc::boxed::Box;
use core::any::Any;
use core::ptr;

pub unsafe fn cleanup(_ptr: *mut u8) -> Box<dyn Any + Send> {
extern "C" {
Expand Down
26 changes: 26 additions & 0 deletions src/librustc/ty/instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -381,6 +381,32 @@ impl<'tcx> Instance<'tcx> {
Instance { def, substs }
}

/// FIXME(#69925) Depending on the kind of `InstanceDef`, the MIR body associated with an
/// instance is expressed in terms of the generic parameters of `self.def_id()`, and in other
/// cases the MIR body is expressed in terms of the types found in the substitution array.
/// In the former case, we want to substitute those generic types and replace them with the
/// values from the substs when monomorphizing the function body. But in the latter case, we
/// don't want to do that substitution, since it has already been done effectively.
///
/// This function returns `Some(substs)` in the former case and None otherwise -- i.e., if
/// this function returns `None`, then the MIR body does not require substitution during
/// monomorphization.
pub fn substs_for_mir_body(&self) -> Option<SubstsRef<'tcx>> {
match self.def {
InstanceDef::CloneShim(..)
| InstanceDef::DropGlue(_, Some(_)) => None,
InstanceDef::ClosureOnceShim { .. }
| InstanceDef::DropGlue(..)
// FIXME(#69925): `FnPtrShim` should be in the other branch.
| InstanceDef::FnPtrShim(..)
| InstanceDef::Item(_)
| InstanceDef::Intrinsic(..)
| InstanceDef::ReifyShim(..)
| InstanceDef::Virtual(..)
| InstanceDef::VtableShim(..) => Some(self.substs),
}
}

pub fn is_vtable_shim(&self) -> bool {
if let InstanceDef::VtableShim(..) = self.def { true } else { false }
}
Expand Down
14 changes: 11 additions & 3 deletions src/librustc/ty/layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -780,8 +780,8 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
present_first @ Some(_) => present_first,
// Uninhabited because it has no variants, or only absent ones.
None if def.is_enum() => return tcx.layout_raw(param_env.and(tcx.types.never)),
// if it's a struct, still compute a layout so that we can still compute the
// field offsets
// If it's a struct, still compute a layout so that we can still compute the
// field offsets.
None => Some(VariantIdx::new(0)),
};

Expand Down Expand Up @@ -1987,7 +1987,15 @@ where
{
fn for_variant(this: TyLayout<'tcx>, cx: &C, variant_index: VariantIdx) -> TyLayout<'tcx> {
let details = match this.variants {
Variants::Single { index } if index == variant_index => this.details,
Variants::Single { index }
// If all variants but one are uninhabited, the variant layout is the enum layout.
if index == variant_index &&
// Don't confuse variants of uninhabited enums with the enum itself.
// For more details see https://github.com/rust-lang/rust/issues/69763.
this.fields != FieldPlacement::Union(0) =>
{
this.details
}

Variants::Single { index } => {
// Deny calling for_variant more than once for non-Single enums.
Expand Down
17 changes: 11 additions & 6 deletions src/librustc_codegen_ssa/mir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,13 +86,18 @@ pub struct FunctionCx<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> {
impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
pub fn monomorphize<T>(&self, value: &T) -> T
where
T: TypeFoldable<'tcx>,
T: Copy + TypeFoldable<'tcx>,
{
self.cx.tcx().subst_and_normalize_erasing_regions(
self.instance.substs,
ty::ParamEnv::reveal_all(),
value,
)
debug!("monomorphize: self.instance={:?}", self.instance);
if let Some(substs) = self.instance.substs_for_mir_body() {
self.cx.tcx().subst_and_normalize_erasing_regions(
substs,
ty::ParamEnv::reveal_all(),
&value,
)
} else {
self.cx.tcx().normalize_erasing_regions(ty::ParamEnv::reveal_all(), *value)
}
}
}

Expand Down
9 changes: 5 additions & 4 deletions src/librustc_error_codes/error_codes/E0437.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
Trait implementations can only implement associated types that are members of
the trait in question. This error indicates that you attempted to implement
an associated type whose name does not match the name of any associated type
in the trait.
An associated type whose name does not match any of the associated types
in the trait was used when implementing the trait.

Erroneous code example:

Expand All @@ -13,6 +11,9 @@ impl Foo for i32 {
}
```

Trait implementations can only implement associated types that are members of
the trait in question.

The solution to this problem is to remove the extraneous associated type:

```
Expand Down
9 changes: 5 additions & 4 deletions src/librustc_error_codes/error_codes/E0438.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
Trait implementations can only implement associated constants that are
members of the trait in question. This error indicates that you
attempted to implement an associated constant whose name does not
match the name of any associated constant in the trait.
An associated constant whose name does not match any of the associated constants
in the trait was used when implementing the trait.

Erroneous code example:

Expand All @@ -13,6 +11,9 @@ impl Foo for i32 {
}
```

Trait implementations can only implement associated constants that are
members of the trait in question.

The solution to this problem is to remove the extraneous associated constant:

```
Expand Down
27 changes: 17 additions & 10 deletions src/librustc_mir/interpret/eval_context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -335,15 +335,25 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {

/// Call this on things you got out of the MIR (so it is as generic as the current
/// stack frame), to bring it into the proper environment for this interpreter.
pub(super) fn subst_from_current_frame_and_normalize_erasing_regions<T: TypeFoldable<'tcx>>(
&self,
value: T,
) -> T {
self.subst_from_frame_and_normalize_erasing_regions(self.frame(), value)
}

/// Call this on things you got out of the MIR (so it is as generic as the provided
/// stack frame), to bring it into the proper environment for this interpreter.
pub(super) fn subst_from_frame_and_normalize_erasing_regions<T: TypeFoldable<'tcx>>(
&self,
frame: &Frame<'mir, 'tcx, M::PointerTag, M::FrameExtra>,
value: T,
) -> T {
self.tcx.subst_and_normalize_erasing_regions(
self.frame().instance.substs,
self.param_env,
&value,
)
if let Some(substs) = frame.instance.substs_for_mir_body() {
self.tcx.subst_and_normalize_erasing_regions(substs, self.param_env, &value)
} else {
self.tcx.normalize_erasing_regions(self.param_env, value)
}
}

/// The `substs` are assumed to already be in our interpreter "universe" (param_env).
Expand Down Expand Up @@ -371,11 +381,8 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
None => {
let layout = crate::interpret::operand::from_known_layout(layout, || {
let local_ty = frame.body.local_decls[local].ty;
let local_ty = self.tcx.subst_and_normalize_erasing_regions(
frame.instance.substs,
self.param_env,
&local_ty,
);
let local_ty =
self.subst_from_frame_and_normalize_erasing_regions(frame, local_ty);
self.layout_of(local_ty)
})?;
if let Some(state) = frame.locals.get(local) {
Expand Down
5 changes: 3 additions & 2 deletions src/librustc_mir/interpret/operand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -355,7 +355,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> {
let base = match op.try_as_mplace(self) {
Ok(mplace) => {
// The easy case
// We can reuse the mplace field computation logic for indirect operands.
let field = self.mplace_field(mplace, field)?;
return Ok(field.into());
}
Expand Down Expand Up @@ -490,7 +490,8 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
Copy(ref place) | Move(ref place) => self.eval_place_to_op(place, layout)?,

Constant(ref constant) => {
let val = self.subst_from_frame_and_normalize_erasing_regions(constant.literal);
let val =
self.subst_from_current_frame_and_normalize_erasing_regions(constant.literal);
self.eval_const_to_op(val, layout)?
}
};
Expand Down
16 changes: 5 additions & 11 deletions src/librustc_mir/interpret/place.rs
Original file line number Diff line number Diff line change
Expand Up @@ -410,14 +410,6 @@ where
stride * field
}
layout::FieldPlacement::Union(count) => {
// This is a narrow bug-fix for rust-lang/rust#69191: if we are
// trying to access absent field of uninhabited variant, then
// signal UB (but don't ICE the compiler).
// FIXME temporary hack to work around incoherence between
// layout computation and MIR building
if field >= count as u64 && base.layout.abi == layout::Abi::Uninhabited {
throw_ub!(Unreachable);
}
assert!(
field < count as u64,
"Tried to access field {} of union {:#?} with {} fields",
Expand Down Expand Up @@ -648,9 +640,11 @@ where
// bail out.
None => Place::null(&*self),
},
layout: self.layout_of(self.subst_from_frame_and_normalize_erasing_regions(
self.frame().body.return_ty(),
))?,
layout: self.layout_of(
self.subst_from_current_frame_and_normalize_erasing_regions(
self.frame().body.return_ty(),
),
)?,
}
}
local => PlaceTy {
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_mir/interpret/step.rs
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
}

NullaryOp(mir::NullOp::SizeOf, ty) => {
let ty = self.subst_from_frame_and_normalize_erasing_regions(ty);
let ty = self.subst_from_current_frame_and_normalize_erasing_regions(ty);
let layout = self.layout_of(ty)?;
assert!(
!layout.is_unsized(),
Expand Down
Loading