Skip to content

Commit ea733c3

Browse files
committed
Auto merge of rust-lang#71853 - Dylan-DPC:rollup-4qi6ry9, r=Dylan-DPC
Rollup of 4 pull requests Successful merges: - rust-lang#71398 (Add `RefCell::take`) - rust-lang#71663 (Fix exceeding bitshifts not emitting for assoc. consts (properly this time, I swear!)) - rust-lang#71726 (Suggest deref when coercing `ty::Ref` to `ty::RawPtr` with arbitrary mutability) - rust-lang#71808 (Add long error explanation for E0539) Failed merges: r? @ghost
2 parents e5f35df + ce1dba9 commit ea733c3

24 files changed

+677
-269
lines changed

src/libcore/cell.rs

+25
Original file line numberDiff line numberDiff line change
@@ -1023,6 +1023,31 @@ impl<T: ?Sized> RefCell<T> {
10231023
}
10241024
}
10251025

1026+
impl<T: Default> RefCell<T> {
1027+
/// Takes the wrapped value, leaving `Default::default()` in its place.
1028+
///
1029+
/// # Panics
1030+
///
1031+
/// Panics if the value is currently borrowed.
1032+
///
1033+
/// # Examples
1034+
///
1035+
/// ```
1036+
/// #![feature(refcell_take)]
1037+
/// use std::cell::RefCell;
1038+
///
1039+
/// let c = RefCell::new(5);
1040+
/// let five = c.take();
1041+
///
1042+
/// assert_eq!(five, 5);
1043+
/// assert_eq!(c.into_inner(), 0);
1044+
/// ```
1045+
#[unstable(feature = "refcell_take", issue = "71395")]
1046+
pub fn take(&self) -> T {
1047+
self.replace(Default::default())
1048+
}
1049+
}
1050+
10261051
#[stable(feature = "rust1", since = "1.0.0")]
10271052
unsafe impl<T: ?Sized> Send for RefCell<T> where T: Send {}
10281053

src/librustc_error_codes/error_codes.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,7 @@ E0535: include_str!("./error_codes/E0535.md"),
281281
E0536: include_str!("./error_codes/E0536.md"),
282282
E0537: include_str!("./error_codes/E0537.md"),
283283
E0538: include_str!("./error_codes/E0538.md"),
284+
E0539: include_str!("./error_codes/E0539.md"),
284285
E0541: include_str!("./error_codes/E0541.md"),
285286
E0550: include_str!("./error_codes/E0550.md"),
286287
E0551: include_str!("./error_codes/E0551.md"),
@@ -570,7 +571,6 @@ E0753: include_str!("./error_codes/E0753.md"),
570571
E0521, // borrowed data escapes outside of closure
571572
E0523,
572573
// E0526, // shuffle indices are not constant
573-
E0539, // incorrect meta item
574574
E0540, // multiple rustc_deprecated attributes
575575
E0542, // missing 'since'
576576
E0543, // missing 'reason'
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
An invalid meta-item was used inside an attribute.
2+
3+
Erroneous code example:
4+
5+
```compile_fail,E0539
6+
#![feature(staged_api)]
7+
#![stable(since = "1.0.0", feature = "test")]
8+
9+
#[rustc_deprecated(reason)] // error!
10+
#[unstable(feature = "deprecated_fn", issue = "123")]
11+
fn deprecated() {}
12+
13+
#[unstable(feature = "unstable_struct", issue)] // error!
14+
struct Unstable;
15+
16+
#[rustc_const_unstable(feature)] // error!
17+
const fn unstable_fn() {}
18+
19+
#[stable(feature = "stable_struct", since)] // error!
20+
struct Stable;
21+
22+
#[rustc_const_stable(feature)] // error!
23+
const fn stable_fn() {}
24+
```
25+
26+
Meta items are the key-value pairs inside of an attribute.
27+
To fix these issues you need to give required key-value pairs.
28+
29+
```
30+
#![feature(staged_api)]
31+
#![stable(since = "1.0.0", feature = "test")]
32+
33+
#[rustc_deprecated(since = "1.39.0", reason = "reason")] // ok!
34+
#[unstable(feature = "deprecated_fn", issue = "123")]
35+
fn deprecated() {}
36+
37+
#[unstable(feature = "unstable_struct", issue = "123")] // ok!
38+
struct Unstable;
39+
40+
#[rustc_const_unstable(feature = "unstable_fn", issue = "124")] // ok!
41+
const fn unstable_fn() {}
42+
43+
#[stable(feature = "stable_struct", since = "1.39.0")] // ok!
44+
struct Stable;
45+
46+
#[rustc_const_stable(feature = "stable_fn", since = "1.39.0")] // ok!
47+
const fn stable_fn() {}
48+
```

src/librustc_mir/interpret/validity.rs

+61-31
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use std::ops::RangeInclusive;
1111

1212
use rustc_data_structures::fx::FxHashSet;
1313
use rustc_hir as hir;
14+
use rustc_middle::mir::interpret::{InterpError, InterpErrorInfo};
1415
use rustc_middle::ty;
1516
use rustc_middle::ty::layout::TyAndLayout;
1617
use rustc_span::symbol::{sym, Symbol};
@@ -24,43 +25,71 @@ use super::{
2425
};
2526

2627
macro_rules! throw_validation_failure {
27-
($what:expr, $where:expr, $details:expr) => {{
28-
let mut msg = format!("encountered {}", $what);
29-
let where_ = &$where;
30-
if !where_.is_empty() {
31-
msg.push_str(" at ");
32-
write_path(&mut msg, where_);
33-
}
34-
write!(&mut msg, ", but expected {}", $details).unwrap();
35-
throw_ub!(ValidationFailure(msg))
36-
}};
37-
($what:expr, $where:expr) => {{
28+
($what:expr, $where:expr $(, $expected:expr )?) => {{
3829
let mut msg = format!("encountered {}", $what);
3930
let where_ = &$where;
4031
if !where_.is_empty() {
4132
msg.push_str(" at ");
4233
write_path(&mut msg, where_);
4334
}
35+
$( write!(&mut msg, ", but expected {}", $expected).unwrap(); )?
4436
throw_ub!(ValidationFailure(msg))
4537
}};
4638
}
4739

40+
/// Returns a validation failure for any Err value of $e.
41+
// FIXME: Replace all usages of try_validation! with try_validation_pat!.
4842
macro_rules! try_validation {
49-
($e:expr, $what:expr, $where:expr, $details:expr) => {{
50-
match $e {
51-
Ok(x) => x,
52-
// We re-throw the error, so we are okay with allocation:
53-
// this can only slow down builds that fail anyway.
54-
Err(_) => throw_validation_failure!($what, $where, $details),
55-
}
43+
($e:expr, $what:expr, $where:expr $(, $expected:expr )?) => {{
44+
try_validation_pat!($e, $where, {
45+
_ => { "{}", $what } $( expected { "{}", $expected } )?,
46+
})
5647
}};
57-
58-
($e:expr, $what:expr, $where:expr) => {{
48+
}
49+
/// Like try_validation, but will throw a validation error if any of the patterns in $p are
50+
/// matched. Other errors are passed back to the caller, unchanged. This lets you use the patterns
51+
/// as a kind of validation blacklist:
52+
///
53+
/// ```
54+
/// let v = try_validation_pat!(some_fn(), some_path, {
55+
/// Foo | Bar | Baz => { "some failure" },
56+
/// });
57+
/// // Failures that match $p are thrown up as validation errors, but other errors are passed back
58+
/// // unchanged.
59+
/// ```
60+
///
61+
/// An additional expected parameter can also be added to the failure message:
62+
///
63+
/// ```
64+
/// let v = try_validation_pat!(some_fn(), some_path, {
65+
/// Foo | Bar | Baz => { "some failure" } expected { "something that wasn't a failure" },
66+
/// });
67+
/// ```
68+
///
69+
/// An additional nicety is that both parameters actually take format args, so you can just write
70+
/// the format string in directly:
71+
///
72+
/// ```
73+
/// let v = try_validation_pat!(some_fn(), some_path, {
74+
/// Foo | Bar | Baz => { "{:?}", some_failure } expected { "{}", expected_value },
75+
/// });
76+
/// ```
77+
///
78+
macro_rules! try_validation_pat {
79+
($e:expr, $where:expr, { $( $p:pat )|+ =>
80+
{ $( $what_fmt:expr ),+ } $( expected { $( $expected_fmt:expr ),+ } )? $( , )?}) => {{
5981
match $e {
6082
Ok(x) => x,
61-
// We re-throw the error, so we are okay with allocation:
62-
// this can only slow down builds that fail anyway.
63-
Err(_) => throw_validation_failure!($what, $where),
83+
// We catch the error and turn it into a validation failure. We are okay with
84+
// allocation here as this can only slow down builds that fail anyway.
85+
$( Err(InterpErrorInfo { kind: $p, .. }) )|+ =>
86+
throw_validation_failure!(
87+
format_args!($( $what_fmt ),+),
88+
$where
89+
$(, format_args!($( $expected_fmt ),+))?
90+
),
91+
#[allow(unreachable_patterns)]
92+
Err(e) => Err::<!, _>(e)?,
6493
}
6594
}};
6695
}
@@ -492,11 +521,9 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
492521
// We are conservative with undef for integers, but try to
493522
// actually enforce the strict rules for raw pointers (mostly because
494523
// that lets us re-use `ref_to_mplace`).
495-
let place = try_validation!(
496-
self.ecx.ref_to_mplace(self.ecx.read_immediate(value)?),
497-
"uninitialized raw pointer",
498-
self.path
499-
);
524+
let place = try_validation_pat!(self.ecx.ref_to_mplace(self.ecx.read_immediate(value)?), self.path, {
525+
err_ub!(InvalidUndefBytes(..)) => { "uninitialized raw pointer" },
526+
});
500527
if place.layout.is_unsized() {
501528
self.check_wide_ptr_meta(place.meta, place.layout)?;
502529
}
@@ -800,7 +827,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
800827

801828
throw_validation_failure!("uninitialized bytes", self.path)
802829
}
803-
// Other errors shouldn't be possible
830+
// Propagate upwards (that will also check for unexpected errors).
804831
_ => return Err(err),
805832
}
806833
}
@@ -843,9 +870,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
843870
// Run it.
844871
match visitor.visit_value(op) {
845872
Ok(()) => Ok(()),
846-
// We should only get validation errors here. Avoid other errors as
847-
// those do not show *where* in the value the issue lies.
873+
// Pass through validation failures.
848874
Err(err) if matches!(err.kind, err_ub!(ValidationFailure { .. })) => Err(err),
875+
// Also pass through InvalidProgram, those just indicate that we could not
876+
// validate and each caller will know best what to do with them.
877+
Err(err) if matches!(err.kind, InterpError::InvalidProgram(_)) => Err(err),
878+
// Avoid other errors as those do not show *where* in the value the issue lies.
849879
Err(err) => bug!("Unexpected error during validation: {}", err),
850880
}
851881
}

src/librustc_mir/transform/const_prop.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -549,11 +549,6 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
549549
return None;
550550
}
551551

552-
// FIXME we need to revisit this for #67176
553-
if rvalue.needs_subst() {
554-
return None;
555-
}
556-
557552
// Perform any special handling for specific Rvalue types.
558553
// Generally, checks here fall into one of two categories:
559554
// 1. Additional checking to provide useful lints to the user
@@ -594,6 +589,11 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
594589
_ => {}
595590
}
596591

592+
// FIXME we need to revisit this for #67176
593+
if rvalue.needs_subst() {
594+
return None;
595+
}
596+
597597
self.use_ecx(|this| {
598598
trace!("calling eval_rvalue_into_place(rvalue = {:?}, place = {:?})", rvalue, place);
599599
this.ecx.eval_rvalue_into_place(rvalue, place)?;

src/librustc_typeck/check/coercion.rs

+15-3
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode};
7474
use smallvec::{smallvec, SmallVec};
7575
use std::ops::Deref;
7676

77-
pub struct Coerce<'a, 'tcx> {
77+
struct Coerce<'a, 'tcx> {
7878
fcx: &'a FnCtxt<'a, 'tcx>,
7979
cause: ObligationCause<'tcx>,
8080
use_lub: bool,
@@ -126,15 +126,15 @@ fn success<'tcx>(
126126
}
127127

128128
impl<'f, 'tcx> Coerce<'f, 'tcx> {
129-
pub fn new(
129+
fn new(
130130
fcx: &'f FnCtxt<'f, 'tcx>,
131131
cause: ObligationCause<'tcx>,
132132
allow_two_phase: AllowTwoPhase,
133133
) -> Self {
134134
Coerce { fcx, cause, allow_two_phase, use_lub: false }
135135
}
136136

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

844+
/// Given a type and a target type, this function will calculate and return
845+
/// how many dereference steps needed to achieve `expr_ty <: target`. If
846+
/// it's not possible, return `None`.
847+
pub fn deref_steps(&self, expr_ty: Ty<'tcx>, target: Ty<'tcx>) -> Option<usize> {
848+
let cause = self.cause(rustc_span::DUMMY_SP, ObligationCauseCode::ExprAssignable);
849+
// We don't ever need two-phase here since we throw out the result of the coercion
850+
let coerce = Coerce::new(self, cause, AllowTwoPhase::No);
851+
coerce
852+
.autoderef(rustc_span::DUMMY_SP, expr_ty)
853+
.find_map(|(ty, steps)| coerce.unify(ty, target).ok().map(|_| steps))
854+
}
855+
844856
/// Given some expressions, their known unified type and another expression,
845857
/// tries to unify the types, potentially inserting coercions on any of the
846858
/// provided expressions and returns their LUB (aka "common supertype").

0 commit comments

Comments
 (0)