Skip to content

Commit

Permalink
Auto merge of #71853 - Dylan-DPC:rollup-4qi6ry9, r=Dylan-DPC
Browse files Browse the repository at this point in the history
Rollup of 4 pull requests

Successful merges:

 - #71398 (Add `RefCell::take`)
 - #71663 (Fix exceeding bitshifts not emitting for assoc. consts (properly this time, I swear!))
 - #71726 (Suggest deref when coercing `ty::Ref` to `ty::RawPtr` with arbitrary mutability)
 - #71808 (Add long error explanation for E0539)

Failed merges:

r? @ghost
  • Loading branch information
bors committed May 3, 2020
2 parents e5f35df + ce1dba9 commit ea733c3
Show file tree
Hide file tree
Showing 24 changed files with 677 additions and 269 deletions.
25 changes: 25 additions & 0 deletions src/libcore/cell.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1023,6 +1023,31 @@ impl<T: ?Sized> RefCell<T> {
}
}

impl<T: Default> RefCell<T> {
/// Takes the wrapped value, leaving `Default::default()` in its place.
///
/// # Panics
///
/// Panics if the value is currently borrowed.
///
/// # Examples
///
/// ```
/// #![feature(refcell_take)]
/// use std::cell::RefCell;
///
/// let c = RefCell::new(5);
/// let five = c.take();
///
/// assert_eq!(five, 5);
/// assert_eq!(c.into_inner(), 0);
/// ```
#[unstable(feature = "refcell_take", issue = "71395")]
pub fn take(&self) -> T {
self.replace(Default::default())
}
}

#[stable(feature = "rust1", since = "1.0.0")]
unsafe impl<T: ?Sized> Send for RefCell<T> where T: Send {}

Expand Down
2 changes: 1 addition & 1 deletion src/librustc_error_codes/error_codes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,7 @@ E0535: include_str!("./error_codes/E0535.md"),
E0536: include_str!("./error_codes/E0536.md"),
E0537: include_str!("./error_codes/E0537.md"),
E0538: include_str!("./error_codes/E0538.md"),
E0539: include_str!("./error_codes/E0539.md"),
E0541: include_str!("./error_codes/E0541.md"),
E0550: include_str!("./error_codes/E0550.md"),
E0551: include_str!("./error_codes/E0551.md"),
Expand Down Expand Up @@ -570,7 +571,6 @@ E0753: include_str!("./error_codes/E0753.md"),
E0521, // borrowed data escapes outside of closure
E0523,
// E0526, // shuffle indices are not constant
E0539, // incorrect meta item
E0540, // multiple rustc_deprecated attributes
E0542, // missing 'since'
E0543, // missing 'reason'
Expand Down
48 changes: 48 additions & 0 deletions src/librustc_error_codes/error_codes/E0539.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
An invalid meta-item was used inside an attribute.

Erroneous code example:

```compile_fail,E0539
#![feature(staged_api)]
#![stable(since = "1.0.0", feature = "test")]
#[rustc_deprecated(reason)] // error!
#[unstable(feature = "deprecated_fn", issue = "123")]
fn deprecated() {}
#[unstable(feature = "unstable_struct", issue)] // error!
struct Unstable;
#[rustc_const_unstable(feature)] // error!
const fn unstable_fn() {}
#[stable(feature = "stable_struct", since)] // error!
struct Stable;
#[rustc_const_stable(feature)] // error!
const fn stable_fn() {}
```

Meta items are the key-value pairs inside of an attribute.
To fix these issues you need to give required key-value pairs.

```
#![feature(staged_api)]
#![stable(since = "1.0.0", feature = "test")]
#[rustc_deprecated(since = "1.39.0", reason = "reason")] // ok!
#[unstable(feature = "deprecated_fn", issue = "123")]
fn deprecated() {}
#[unstable(feature = "unstable_struct", issue = "123")] // ok!
struct Unstable;
#[rustc_const_unstable(feature = "unstable_fn", issue = "124")] // ok!
const fn unstable_fn() {}
#[stable(feature = "stable_struct", since = "1.39.0")] // ok!
struct Stable;
#[rustc_const_stable(feature = "stable_fn", since = "1.39.0")] // ok!
const fn stable_fn() {}
```
92 changes: 61 additions & 31 deletions src/librustc_mir/interpret/validity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use std::ops::RangeInclusive;

use rustc_data_structures::fx::FxHashSet;
use rustc_hir as hir;
use rustc_middle::mir::interpret::{InterpError, InterpErrorInfo};
use rustc_middle::ty;
use rustc_middle::ty::layout::TyAndLayout;
use rustc_span::symbol::{sym, Symbol};
Expand All @@ -24,43 +25,71 @@ use super::{
};

macro_rules! throw_validation_failure {
($what:expr, $where:expr, $details:expr) => {{
let mut msg = format!("encountered {}", $what);
let where_ = &$where;
if !where_.is_empty() {
msg.push_str(" at ");
write_path(&mut msg, where_);
}
write!(&mut msg, ", but expected {}", $details).unwrap();
throw_ub!(ValidationFailure(msg))
}};
($what:expr, $where:expr) => {{
($what:expr, $where:expr $(, $expected:expr )?) => {{
let mut msg = format!("encountered {}", $what);
let where_ = &$where;
if !where_.is_empty() {
msg.push_str(" at ");
write_path(&mut msg, where_);
}
$( write!(&mut msg, ", but expected {}", $expected).unwrap(); )?
throw_ub!(ValidationFailure(msg))
}};
}

/// Returns a validation failure for any Err value of $e.
// FIXME: Replace all usages of try_validation! with try_validation_pat!.
macro_rules! try_validation {
($e:expr, $what:expr, $where:expr, $details:expr) => {{
match $e {
Ok(x) => x,
// We re-throw the error, so we are okay with allocation:
// this can only slow down builds that fail anyway.
Err(_) => throw_validation_failure!($what, $where, $details),
}
($e:expr, $what:expr, $where:expr $(, $expected:expr )?) => {{
try_validation_pat!($e, $where, {
_ => { "{}", $what } $( expected { "{}", $expected } )?,
})
}};

($e:expr, $what:expr, $where:expr) => {{
}
/// Like try_validation, but will throw a validation error if any of the patterns in $p are
/// matched. Other errors are passed back to the caller, unchanged. This lets you use the patterns
/// as a kind of validation blacklist:
///
/// ```
/// let v = try_validation_pat!(some_fn(), some_path, {
/// Foo | Bar | Baz => { "some failure" },
/// });
/// // Failures that match $p are thrown up as validation errors, but other errors are passed back
/// // unchanged.
/// ```
///
/// An additional expected parameter can also be added to the failure message:
///
/// ```
/// let v = try_validation_pat!(some_fn(), some_path, {
/// Foo | Bar | Baz => { "some failure" } expected { "something that wasn't a failure" },
/// });
/// ```
///
/// An additional nicety is that both parameters actually take format args, so you can just write
/// the format string in directly:
///
/// ```
/// let v = try_validation_pat!(some_fn(), some_path, {
/// Foo | Bar | Baz => { "{:?}", some_failure } expected { "{}", expected_value },
/// });
/// ```
///
macro_rules! try_validation_pat {
($e:expr, $where:expr, { $( $p:pat )|+ =>
{ $( $what_fmt:expr ),+ } $( expected { $( $expected_fmt:expr ),+ } )? $( , )?}) => {{
match $e {
Ok(x) => x,
// We re-throw the error, so we are okay with allocation:
// this can only slow down builds that fail anyway.
Err(_) => throw_validation_failure!($what, $where),
// We catch the error and turn it into a validation failure. We are okay with
// allocation here as this can only slow down builds that fail anyway.
$( Err(InterpErrorInfo { kind: $p, .. }) )|+ =>
throw_validation_failure!(
format_args!($( $what_fmt ),+),
$where
$(, format_args!($( $expected_fmt ),+))?
),
#[allow(unreachable_patterns)]
Err(e) => Err::<!, _>(e)?,
}
}};
}
Expand Down Expand Up @@ -492,11 +521,9 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
// We are conservative with undef for integers, but try to
// actually enforce the strict rules for raw pointers (mostly because
// that lets us re-use `ref_to_mplace`).
let place = try_validation!(
self.ecx.ref_to_mplace(self.ecx.read_immediate(value)?),
"uninitialized raw pointer",
self.path
);
let place = try_validation_pat!(self.ecx.ref_to_mplace(self.ecx.read_immediate(value)?), self.path, {
err_ub!(InvalidUndefBytes(..)) => { "uninitialized raw pointer" },
});
if place.layout.is_unsized() {
self.check_wide_ptr_meta(place.meta, place.layout)?;
}
Expand Down Expand Up @@ -800,7 +827,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>

throw_validation_failure!("uninitialized bytes", self.path)
}
// Other errors shouldn't be possible
// Propagate upwards (that will also check for unexpected errors).
_ => return Err(err),
}
}
Expand Down Expand Up @@ -843,9 +870,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
// Run it.
match visitor.visit_value(op) {
Ok(()) => Ok(()),
// We should only get validation errors here. Avoid other errors as
// those do not show *where* in the value the issue lies.
// Pass through validation failures.
Err(err) if matches!(err.kind, err_ub!(ValidationFailure { .. })) => Err(err),
// Also pass through InvalidProgram, those just indicate that we could not
// validate and each caller will know best what to do with them.
Err(err) if matches!(err.kind, InterpError::InvalidProgram(_)) => Err(err),
// Avoid other errors as those do not show *where* in the value the issue lies.
Err(err) => bug!("Unexpected error during validation: {}", err),
}
}
Expand Down
10 changes: 5 additions & 5 deletions src/librustc_mir/transform/const_prop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -549,11 +549,6 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
return None;
}

// FIXME we need to revisit this for #67176
if rvalue.needs_subst() {
return None;
}

// Perform any special handling for specific Rvalue types.
// Generally, checks here fall into one of two categories:
// 1. Additional checking to provide useful lints to the user
Expand Down Expand Up @@ -594,6 +589,11 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
_ => {}
}

// FIXME we need to revisit this for #67176
if rvalue.needs_subst() {
return None;
}

self.use_ecx(|this| {
trace!("calling eval_rvalue_into_place(rvalue = {:?}, place = {:?})", rvalue, place);
this.ecx.eval_rvalue_into_place(rvalue, place)?;
Expand Down
18 changes: 15 additions & 3 deletions src/librustc_typeck/check/coercion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode};
use smallvec::{smallvec, SmallVec};
use std::ops::Deref;

pub struct Coerce<'a, 'tcx> {
struct Coerce<'a, 'tcx> {
fcx: &'a FnCtxt<'a, 'tcx>,
cause: ObligationCause<'tcx>,
use_lub: bool,
Expand Down Expand Up @@ -126,15 +126,15 @@ fn success<'tcx>(
}

impl<'f, 'tcx> Coerce<'f, 'tcx> {
pub fn new(
fn new(
fcx: &'f FnCtxt<'f, 'tcx>,
cause: ObligationCause<'tcx>,
allow_two_phase: AllowTwoPhase,
) -> Self {
Coerce { fcx, cause, allow_two_phase, use_lub: false }
}

pub fn unify(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> InferResult<'tcx, Ty<'tcx>> {
fn unify(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> InferResult<'tcx, Ty<'tcx>> {
debug!("unify(a: {:?}, b: {:?}, use_lub: {})", a, b, self.use_lub);
self.commit_if_ok(|_| {
if self.use_lub {
Expand Down Expand Up @@ -841,6 +841,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.probe(|_| coerce.coerce(source, target)).is_ok()
}

/// Given a type and a target type, this function will calculate and return
/// how many dereference steps needed to achieve `expr_ty <: target`. If
/// it's not possible, return `None`.
pub fn deref_steps(&self, expr_ty: Ty<'tcx>, target: Ty<'tcx>) -> Option<usize> {
let cause = self.cause(rustc_span::DUMMY_SP, ObligationCauseCode::ExprAssignable);
// We don't ever need two-phase here since we throw out the result of the coercion
let coerce = Coerce::new(self, cause, AllowTwoPhase::No);
coerce
.autoderef(rustc_span::DUMMY_SP, expr_ty)
.find_map(|(ty, steps)| coerce.unify(ty, target).ok().map(|_| steps))
}

/// Given some expressions, their known unified type and another expression,
/// tries to unify the types, potentially inserting coercions on any of the
/// provided expressions and returns their LUB (aka "common supertype").
Expand Down
Loading

0 comments on commit ea733c3

Please sign in to comment.