Skip to content

Rollup of 5 pull requests #97013

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

Merged
merged 11 commits into from
May 13, 2022
4 changes: 3 additions & 1 deletion compiler/rustc_const_eval/src/const_eval/valtrees.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,9 @@ fn slice_branches<'tcx>(
ecx: &CompileTimeEvalContext<'tcx, 'tcx>,
place: &MPlaceTy<'tcx>,
) -> Option<ty::ValTree<'tcx>> {
let n = place.len(&ecx.tcx.tcx).expect(&format!("expected to use len of place {:?}", place));
let n = place
.len(&ecx.tcx.tcx)
.unwrap_or_else(|_| panic!("expected to use len of place {:?}", place));
let branches = (0..n).map(|i| {
let place_elem = ecx.mplace_index(place, i).unwrap();
const_to_valtree_inner(ecx, &place_elem)
Expand Down
1 change: 0 additions & 1 deletion library/alloc/src/raw_vec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,6 @@ impl<T, A: Allocator> RawVec<T, A> {

/// Like `new`, but parameterized over the choice of allocator for
/// the returned `RawVec`.
#[rustc_allow_const_fn_unstable(const_fn)]
pub const fn new_in(alloc: A) -> Self {
// `cap: 0` means "unallocated". zero-sized types are ignored.
Self { ptr: Unique::dangling(), cap: 0, alloc }
Expand Down
81 changes: 66 additions & 15 deletions library/core/src/hint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,27 +5,78 @@

use crate::intrinsics;

/// Informs the compiler that this point in the code is not reachable, enabling
/// further optimizations.
/// Informs the compiler that the site which is calling this function is not
/// reachable, possibly enabling further optimizations.
///
/// # Safety
///
/// Reaching this function is completely *undefined behavior* (UB). In
/// particular, the compiler assumes that all UB must never happen, and
/// therefore will eliminate all branches that reach to a call to
/// `unreachable_unchecked()`.
/// Reaching this function is *Undefined Behavior*.
///
/// Like all instances of UB, if this assumption turns out to be wrong, i.e., the
/// `unreachable_unchecked()` call is actually reachable among all possible
/// control flow, the compiler will apply the wrong optimization strategy, and
/// may sometimes even corrupt seemingly unrelated code, causing
/// difficult-to-debug problems.
/// As the compiler assumes that all forms of Undefined Behavior can never
/// happen, it will eliminate all branches in the surrounding code that it can
/// determine will invariably lead to a call to `unreachable_unchecked()`.
///
/// Use this function only when you can prove that the code will never call it.
/// Otherwise, consider using the [`unreachable!`] macro, which does not allow
/// optimizations but will panic when executed.
/// If the assumptions embedded in using this function turn out to be wrong -
/// that is, if the site which is calling `unreachable_unchecked()` is actually
/// reachable at runtime - the compiler may have generated nonsensical machine
/// instructions for this situation, including in seemingly unrelated code,
/// causing difficult-to-debug problems.
///
/// # Example
/// Use this function sparingly. Consider using the [`unreachable!`] macro,
/// which may prevent some optimizations but will safely panic in case it is
/// actually reached at runtime. Benchmark your code to find out if using
/// `unreachable_unchecked()` comes with a performance benefit.
///
/// # Examples
///
/// `unreachable_unchecked()` can be used in situations where the compiler
/// can't prove invariants that were previously established. Such situations
/// have a higher chance of occuring if those invariants are upheld by
/// external code that the compiler can't analyze.
/// ```
/// fn prepare_inputs(divisors: &mut Vec<u32>) {
/// // Note to future-self when making changes: The invariant established
/// // here is NOT checked in `do_computation()`; if this changes, you HAVE
/// // to change `do_computation()`.
/// divisors.retain(|divisor| *divisor != 0)
/// }
///
/// /// # Safety
/// /// All elements of `divisor` must be non-zero.
/// unsafe fn do_computation(i: u32, divisors: &[u32]) -> u32 {
/// divisors.iter().fold(i, |acc, divisor| {
/// // Convince the compiler that a division by zero can't happen here
/// // and a check is not needed below.
/// if *divisor == 0 {
/// // Safety: `divisor` can't be zero because of `prepare_inputs`,
/// // but the compiler does not know about this. We *promise*
/// // that we always call `prepare_inputs`.
/// std::hint::unreachable_unchecked()
/// }
/// // The compiler would normally introduce a check here that prevents
/// // a division by zero. However, if `divisor` was zero, the branch
/// // above would reach what we explicitly marked as unreachable.
/// // The compiler concludes that `divisor` can't be zero at this point
/// // and removes the - now proven useless - check.
/// acc / divisor
/// })
/// }
///
/// let mut divisors = vec![2, 0, 4];
/// prepare_inputs(&mut divisors);
/// let result = unsafe {
/// // Safety: prepare_inputs() guarantees that divisors is non-zero
/// do_computation(100, &divisors)
/// };
/// assert_eq!(result, 12);
///
/// ```
///
/// While using `unreachable_unchecked()` is perfectly sound in the following
/// example, the compiler is able to prove that a division by zero is not
/// possible. Benchmarking reveals that `unreachable_unchecked()` provides
/// no benefit over using [`unreachable!`], while the latter does not introduce
/// the possibility of Undefined Behavior.
///
/// ```
/// fn div_1(a: u32, b: u32) -> u32 {
Expand Down
1 change: 0 additions & 1 deletion library/core/src/num/nonzero.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@ macro_rules! nonzero_integers {
#[$const_new_unchecked_stability]
#[must_use]
#[inline]
#[rustc_allow_const_fn_unstable(const_fn_fn_ptr_basics)] // required by assert_unsafe_precondition
pub const unsafe fn new_unchecked(n: $Int) -> Self {
// SAFETY: this is guaranteed to be safe by the caller.
unsafe {
Expand Down
1 change: 0 additions & 1 deletion library/core/src/option.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1486,7 +1486,6 @@ impl<T> Option<T> {
where
T: ~const Default,
{
#[rustc_allow_const_fn_unstable(const_fn_trait_bound)]
const fn default<T: ~const Default>() -> T {
T::default()
}
Expand Down
1 change: 0 additions & 1 deletion library/core/src/task/wake.rs
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,6 @@ impl RawWakerVTable {
#[rustc_promotable]
#[stable(feature = "futures_api", since = "1.36.0")]
#[rustc_const_stable(feature = "futures_api", since = "1.36.0")]
#[rustc_allow_const_fn_unstable(const_fn_fn_ptr_basics)]
pub const fn new(
clone: unsafe fn(*const ()) -> RawWaker,
wake: unsafe fn(*const ()),
Expand Down
5 changes: 0 additions & 5 deletions library/proc_macro/src/bridge/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -416,7 +416,6 @@ fn run_client<A: for<'a, 's> DecodeMut<'a, 's, ()>, R: Encode<()>>(
}

impl Client<fn(crate::TokenStream) -> crate::TokenStream> {
#[rustc_allow_const_fn_unstable(const_fn)]
pub const fn expand1(f: fn(crate::TokenStream) -> crate::TokenStream) -> Self {
extern "C" fn run(
bridge: Bridge<'_>,
Expand All @@ -429,7 +428,6 @@ impl Client<fn(crate::TokenStream) -> crate::TokenStream> {
}

impl Client<fn(crate::TokenStream, crate::TokenStream) -> crate::TokenStream> {
#[rustc_allow_const_fn_unstable(const_fn)]
pub const fn expand2(
f: fn(crate::TokenStream, crate::TokenStream) -> crate::TokenStream,
) -> Self {
Expand Down Expand Up @@ -474,7 +472,6 @@ impl ProcMacro {
}
}

#[rustc_allow_const_fn_unstable(const_fn)]
pub const fn custom_derive(
trait_name: &'static str,
attributes: &'static [&'static str],
Expand All @@ -483,15 +480,13 @@ impl ProcMacro {
ProcMacro::CustomDerive { trait_name, attributes, client: Client::expand1(expand) }
}

#[rustc_allow_const_fn_unstable(const_fn)]
pub const fn attr(
name: &'static str,
expand: fn(crate::TokenStream, crate::TokenStream) -> crate::TokenStream,
) -> Self {
ProcMacro::Attr { name, client: Client::expand2(expand) }
}

#[rustc_allow_const_fn_unstable(const_fn)]
pub const fn bang(
name: &'static str,
expand: fn(crate::TokenStream) -> crate::TokenStream,
Expand Down
1 change: 0 additions & 1 deletion library/proc_macro/src/bridge/scoped_cell.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ impl<'a, 'b, T: LambdaL> DerefMut for RefMutL<'a, 'b, T> {
pub struct ScopedCell<T: LambdaL>(Cell<<T as ApplyL<'static>>::Out>);

impl<T: LambdaL> ScopedCell<T> {
#[rustc_allow_const_fn_unstable(const_fn)]
pub const fn new(value: <T as ApplyL<'static>>::Out) -> Self {
ScopedCell(Cell::new(value))
}
Expand Down
9 changes: 9 additions & 0 deletions src/test/ui/inference/issue-28935.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// check-pass

use std::cell::RefCell;

pub fn f(v: Vec<RefCell<u8>>) {
let _t = &mut *v[0].borrow_mut();
}

fn main() {}
51 changes: 51 additions & 0 deletions src/test/ui/nll/issue-54779-anon-static-lifetime.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// Regression test for #54779, checks if the diagnostics are confusing.

#![feature(nll)]

trait DebugWith<Cx: ?Sized> {
fn debug_with<'me>(&'me self, cx: &'me Cx) -> DebugCxPair<'me, Self, Cx> {
DebugCxPair { value: self, cx }
}

fn fmt_with(&self, cx: &Cx, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result;
}

struct DebugCxPair<'me, Value: ?Sized, Cx: ?Sized>
where
Value: DebugWith<Cx>,
{
value: &'me Value,
cx: &'me Cx,
}

trait DebugContext {}

struct Foo {
bar: Bar,
}

impl DebugWith<dyn DebugContext> for Foo {
fn fmt_with(
&self,
cx: &dyn DebugContext,
fmt: &mut std::fmt::Formatter<'_>,
) -> std::fmt::Result {
let Foo { bar } = self;
bar.debug_with(cx); //~ ERROR: lifetime may not live long enough
Ok(())
}
}

struct Bar {}

impl DebugWith<dyn DebugContext> for Bar {
fn fmt_with(
&self,
cx: &dyn DebugContext,
fmt: &mut std::fmt::Formatter<'_>,
) -> std::fmt::Result {
Ok(())
}
}

fn main() {}
11 changes: 11 additions & 0 deletions src/test/ui/nll/issue-54779-anon-static-lifetime.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
error: lifetime may not live long enough
--> $DIR/issue-54779-anon-static-lifetime.rs:34:24
|
LL | cx: &dyn DebugContext,
| - let's call the lifetime of this reference `'1`
...
LL | bar.debug_with(cx);
| ^^ cast requires that `'1` must outlive `'static`

error: aborting due to previous error