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 8 pull requests #81385

Closed
wants to merge 21 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
679f6f3
Add `unwrap_unchecked()` methods for `Option` and `Result`
ojeda Jan 10, 2021
76299b3
Add `SAFETY` annotations
ojeda Jan 10, 2021
def0e9b
Fix ICE with `ReadPointerAsBytes` validation error
camelid Jan 11, 2021
a7b7a43
Move test to `src/test/ui/consts/`
camelid Jan 11, 2021
e25959b
Make more traits of the From/Into family diagnostic items
flip1995 Jan 22, 2021
6d4e03a
codegen: assume constants cannot fail to evaluate
RalfJung Jan 24, 2021
57c72ab
libtest: Wait for test threads to exit after they report completion
andersk Jan 25, 2021
2be1993
Ignore test on 32-bit architectures
camelid Jan 25, 2021
26b4baf
Point to span of upvar making closure FnMut
sledgehammervampire Jan 18, 2021
088c89d
Account for generics when suggesting bound
estebank Jan 19, 2021
042facb
Fix some bugs reported by eslint
GuillaumeGomez Jan 23, 2021
0140dac
Link the reference about undefined behavior
ojeda Jan 25, 2021
01250fc
Add tracking issue
ojeda Jan 25, 2021
8bf2392
Rollup merge of #80876 - ojeda:option-result-unwrap_unchecked, r=m-ou-se
jonas-schievink Jan 25, 2021
3ca45fd
Rollup merge of #80900 - camelid:readpointerasbytes-ice, r=oli-obk
jonas-schievink Jan 25, 2021
0f3c5e8
Rollup merge of #81158 - 1000teslas:issue-80313-fix, r=Aaron1011
jonas-schievink Jan 25, 2021
f4fd715
Rollup merge of #81195 - estebank:suggest-bound-on-trait-with-params,…
jonas-schievink Jan 25, 2021
0248edb
Rollup merge of #81277 - flip1995:from_diag_items, r=matthewjasper
jonas-schievink Jan 25, 2021
21bdfcb
Rollup merge of #81299 - GuillaumeGomez:fix-eslint-detected-bugs, r=N…
jonas-schievink Jan 25, 2021
75563f1
Rollup merge of #81327 - RalfJung:codegen-no-const-fail, r=oli-obk
jonas-schievink Jan 25, 2021
e0414d5
Rollup merge of #81367 - andersk:join-test-threads, r=dtolnay
jonas-schievink Jan 25, 2021
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
21 changes: 21 additions & 0 deletions compiler/rustc_codegen_ssa/src/mir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -188,8 +188,10 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(

fx.per_local_var_debug_info = fx.compute_per_local_var_debug_info(&mut bx);

let mut all_consts_ok = true;
for const_ in &mir.required_consts {
if let Err(err) = fx.eval_mir_constant(const_) {
all_consts_ok = false;
match err {
// errored or at least linted
ErrorHandled::Reported(ErrorReported) | ErrorHandled::Linted => {}
Expand All @@ -199,6 +201,25 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
}
}
}
if !all_consts_ok {
// There is no delay_span_bug here, we just have to rely on a hard error actually having
// been raised.
bx.abort();
// `abort` does not terminate the block, so we still need to generate
// an `unreachable` terminator after it.
bx.unreachable();
// We also have to delete all the other basic blocks again...
for bb in mir.basic_blocks().indices() {
if bb != mir::START_BLOCK {
unsafe {
bx.delete_basic_block(fx.blocks[bb]);
}
}
}
// FIXME: Can we somehow avoid all this by evaluating the consts before creating the basic
// blocks? The tricky part is doing that without duplicating `fx.eval_mir_constant`.
return;
}

let memory_locals = analyze::non_ssa_locals(&fx);

Expand Down
25 changes: 4 additions & 21 deletions compiler/rustc_codegen_ssa/src/mir/operand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,8 @@ use crate::glue;
use crate::traits::*;
use crate::MemFlags;

use rustc_errors::ErrorReported;
use rustc_middle::mir;
use rustc_middle::mir::interpret::{ConstValue, ErrorHandled, Pointer, Scalar};
use rustc_middle::mir::interpret::{ConstValue, Pointer, Scalar};
use rustc_middle::ty::layout::TyAndLayout;
use rustc_middle::ty::Ty;
use rustc_target::abi::{Abi, Align, LayoutOf, Size};
Expand Down Expand Up @@ -439,25 +438,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
}

mir::Operand::Constant(ref constant) => {
self.eval_mir_constant_to_operand(bx, constant).unwrap_or_else(|err| {
match err {
// errored or at least linted
ErrorHandled::Reported(ErrorReported) | ErrorHandled::Linted => {}
ErrorHandled::TooGeneric => {
bug!("codegen encountered polymorphic constant")
}
}
// Allow RalfJ to sleep soundly knowing that even refactorings that remove
// the above error (or silence it under some conditions) will not cause UB.
bx.abort();
// We still have to return an operand but it doesn't matter,
// this code is unreachable.
let ty = self.monomorphize(constant.literal.ty);
let layout = bx.cx().layout_of(ty);
bx.load_operand(PlaceRef::new_sized(
bx.cx().const_undef(bx.cx().type_ptr_to(bx.cx().backend_type(layout))),
layout,
))
// This cannot fail because we checked all required_consts in advance.
self.eval_mir_constant_to_operand(bx, constant).unwrap_or_else(|_err| {
span_bug!(constant.span, "erroneous constant not captured by required_consts")
})
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
use rustc_hir as hir;
use rustc_hir::Node;
use rustc_index::vec::Idx;
use rustc_middle::mir::{self, ClearCrossCrate, Local, LocalDecl, LocalInfo, Location};
use rustc_middle::mir::{Mutability, Place, PlaceRef, ProjectionElem};
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_middle::{
hir::place::PlaceBase,
mir::{self, ClearCrossCrate, Local, LocalDecl, LocalInfo, Location},
};
use rustc_span::source_map::DesugaringKind;
use rustc_span::symbol::{kw, Symbol};
use rustc_span::Span;
Expand Down Expand Up @@ -241,6 +244,10 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
format!("mut {}", self.local_names[local].unwrap()),
Applicability::MachineApplicable,
);
let tcx = self.infcx.tcx;
if let ty::Closure(id, _) = the_place_err.ty(self.body, tcx).ty.kind() {
self.show_mutating_upvar(tcx, id, the_place_err, &mut err);
}
}

// Also suggest adding mut for upvars
Expand Down Expand Up @@ -271,6 +278,14 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
);
}
}

let tcx = self.infcx.tcx;
if let ty::Ref(_, ty, Mutability::Mut) = the_place_err.ty(self.body, tcx).ty.kind()
{
if let ty::Closure(id, _) = ty.kind() {
self.show_mutating_upvar(tcx, id, the_place_err, &mut err);
}
}
}

// complete hack to approximate old AST-borrowck
Expand Down Expand Up @@ -463,6 +478,45 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
err.buffer(&mut self.errors_buffer);
}

// point to span of upvar making closure call require mutable borrow
fn show_mutating_upvar(
&self,
tcx: TyCtxt<'_>,
id: &hir::def_id::DefId,
the_place_err: PlaceRef<'tcx>,
err: &mut DiagnosticBuilder<'_>,
) {
let id = id.expect_local();
let tables = tcx.typeck(id);
let hir_id = tcx.hir().local_def_id_to_hir_id(id);
let (span, place) = &tables.closure_kind_origins()[hir_id];
let reason = if let PlaceBase::Upvar(upvar_id) = place.base {
let upvar = ty::place_to_string_for_capture(tcx, place);
match tables.upvar_capture(upvar_id) {
ty::UpvarCapture::ByRef(ty::UpvarBorrow {
kind: ty::BorrowKind::MutBorrow,
..
}) => {
format!("mutable borrow of `{}`", upvar)
}
ty::UpvarCapture::ByValue(_) => {
format!("possible mutation of `{}`", upvar)
}
_ => bug!("upvar `{}` borrowed, but not mutably", upvar),
}
} else {
bug!("not an upvar")
};
err.span_label(
*span,
format!(
"calling `{}` requires mutable binding due to {}",
self.describe_place(the_place_err).unwrap(),
reason
),
);
}

/// Targeted error when encountering an `FnMut` closure where an `Fn` closure was expected.
fn expected_fn_found_fn_mut_call(&self, err: &mut DiagnosticBuilder<'_>, sp: Span, act: &str) {
err.span_label(sp, format!("cannot {}", act));
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_mir/src/interpret/operand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -511,6 +511,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
Constant(ref constant) => {
let val =
self.subst_from_current_frame_and_normalize_erasing_regions(constant.literal);
// This can still fail:
// * During ConstProp, with `TooGeneric` or since the `requried_consts` were not all
// checked yet.
// * During CTFE, since promoteds in `const`/`static` initializer bodies can fail.
self.const_to_op(val, layout)?
}
};
Expand Down
6 changes: 5 additions & 1 deletion compiler/rustc_mir/src/interpret/validity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -515,7 +515,11 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
Ok(true)
}
ty::Float(_) | ty::Int(_) | ty::Uint(_) => {
let value = self.ecx.read_scalar(value)?;
let value = try_validation!(
self.ecx.read_scalar(value),
self.path,
err_unsup!(ReadPointerAsBytes) => { "read of part of a pointer" },
);
// NOTE: Keep this in sync with the array optimization for int/float
// types below!
if self.ctfe_mode.is_some() {
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_span/src/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -622,6 +622,7 @@ symbols! {
intel,
into_iter,
into_result,
into_trait,
intra_doc_pointers,
intrinsics,
irrefutable_let_patterns,
Expand Down Expand Up @@ -1159,6 +1160,8 @@ symbols! {
truncf32,
truncf64,
try_blocks,
try_from_trait,
try_into_trait,
try_trait,
tt,
tuple,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -286,21 +286,32 @@ fn suggest_restriction(
);
} else {
// Trivial case: `T` needs an extra bound: `T: Bound`.
let (sp, suggestion) = match super_traits {
None => predicate_constraint(
let (sp, suggestion) = match (
generics
.params
.iter()
.filter(
|p| !matches!(p.kind, hir::GenericParamKind::Type { synthetic: Some(_), ..}),
)
.next(),
super_traits,
) {
(_, None) => predicate_constraint(
generics,
trait_ref.without_const().to_predicate(tcx).to_string(),
),
Some((ident, bounds)) => match bounds {
[.., bound] => (
bound.span().shrink_to_hi(),
format!(" + {}", trait_ref.print_only_trait_path().to_string()),
),
[] => (
ident.span.shrink_to_hi(),
format!(": {}", trait_ref.print_only_trait_path().to_string()),
),
},
(None, Some((ident, []))) => (
ident.span.shrink_to_hi(),
format!(": {}", trait_ref.print_only_trait_path().to_string()),
),
(_, Some((_, [.., bounds]))) => (
bounds.span().shrink_to_hi(),
format!(" + {}", trait_ref.print_only_trait_path().to_string()),
),
(Some(_), Some((_, []))) => (
generics.span.shrink_to_hi(),
format!(": {}", trait_ref.print_only_trait_path().to_string()),
),
};

err.span_suggestion_verbose(
Expand Down
3 changes: 3 additions & 0 deletions library/core/src/convert/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,7 @@ pub trait AsMut<T: ?Sized> {
///
/// [`String`]: ../../std/string/struct.String.html
/// [`Vec`]: ../../std/vec/struct.Vec.html
#[rustc_diagnostic_item = "into_trait"]
#[stable(feature = "rust1", since = "1.0.0")]
pub trait Into<T>: Sized {
/// Performs the conversion.
Expand Down Expand Up @@ -382,6 +383,7 @@ pub trait From<T>: Sized {
///
/// This suffers the same restrictions and reasoning as implementing
/// [`Into`], see there for details.
#[rustc_diagnostic_item = "try_into_trait"]
#[stable(feature = "try_from", since = "1.34.0")]
pub trait TryInto<T>: Sized {
/// The type returned in the event of a conversion error.
Expand Down Expand Up @@ -462,6 +464,7 @@ pub trait TryInto<T>: Sized {
///
/// [`try_from`]: TryFrom::try_from
/// [`!`]: ../../std/primitive.never.html
#[rustc_diagnostic_item = "try_from_trait"]
#[stable(feature = "try_from", since = "1.34.0")]
pub trait TryFrom<T>: Sized {
/// The type returned in the event of a conversion error.
Expand Down
34 changes: 34 additions & 0 deletions library/core/src/option.rs
Original file line number Diff line number Diff line change
Expand Up @@ -428,6 +428,40 @@ impl<T> Option<T> {
}
}

/// Returns the contained [`Some`] value, consuming the `self` value,
/// without checking that the value is not [`None`].
///
/// # Safety
///
/// Calling this method on [`None`] is *[undefined behavior]*.
///
/// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
///
/// # Examples
///
/// ```
/// #![feature(option_result_unwrap_unchecked)]
/// let x = Some("air");
/// assert_eq!(unsafe { x.unwrap_unchecked() }, "air");
/// ```
///
/// ```no_run
/// #![feature(option_result_unwrap_unchecked)]
/// let x: Option<&str> = None;
/// assert_eq!(unsafe { x.unwrap_unchecked() }, "air"); // Undefined behavior!
/// ```
#[inline]
#[track_caller]
#[unstable(feature = "option_result_unwrap_unchecked", reason = "newly added", issue = "81383")]
pub unsafe fn unwrap_unchecked(self) -> T {
debug_assert!(self.is_some());
match self {
Some(val) => val,
// SAFETY: the safety contract must be upheld by the caller.
None => unsafe { hint::unreachable_unchecked() },
}
}

/////////////////////////////////////////////////////////////////////////
// Transforming contained values
/////////////////////////////////////////////////////////////////////////
Expand Down
70 changes: 69 additions & 1 deletion library/core/src/result.rs
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@

use crate::iter::{self, FromIterator, FusedIterator, TrustedLen};
use crate::ops::{self, Deref, DerefMut};
use crate::{convert, fmt};
use crate::{convert, fmt, hint};

/// `Result` is a type that represents either success ([`Ok`]) or failure ([`Err`]).
///
Expand Down Expand Up @@ -821,6 +821,74 @@ impl<T, E> Result<T, E> {
Err(e) => op(e),
}
}

/// Returns the contained [`Ok`] value, consuming the `self` value,
/// without checking that the value is not an [`Err`].
///
/// # Safety
///
/// Calling this method on an [`Err`] is *[undefined behavior]*.
///
/// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
///
/// # Examples
///
/// ```
/// #![feature(option_result_unwrap_unchecked)]
/// let x: Result<u32, &str> = Ok(2);
/// assert_eq!(unsafe { x.unwrap_unchecked() }, 2);
/// ```
///
/// ```no_run
/// #![feature(option_result_unwrap_unchecked)]
/// let x: Result<u32, &str> = Err("emergency failure");
/// unsafe { x.unwrap_unchecked(); } // Undefined behavior!
/// ```
#[inline]
#[track_caller]
#[unstable(feature = "option_result_unwrap_unchecked", reason = "newly added", issue = "81383")]
pub unsafe fn unwrap_unchecked(self) -> T {
debug_assert!(self.is_ok());
match self {
Ok(t) => t,
// SAFETY: the safety contract must be upheld by the caller.
Err(_) => unsafe { hint::unreachable_unchecked() },
}
}

/// Returns the contained [`Err`] value, consuming the `self` value,
/// without checking that the value is not an [`Ok`].
///
/// # Safety
///
/// Calling this method on an [`Ok`] is *[undefined behavior]*.
///
/// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
///
/// # Examples
///
/// ```no_run
/// #![feature(option_result_unwrap_unchecked)]
/// let x: Result<u32, &str> = Ok(2);
/// unsafe { x.unwrap_err_unchecked() }; // Undefined behavior!
/// ```
///
/// ```
/// #![feature(option_result_unwrap_unchecked)]
/// let x: Result<u32, &str> = Err("emergency failure");
/// assert_eq!(unsafe { x.unwrap_err_unchecked() }, "emergency failure");
/// ```
#[inline]
#[track_caller]
#[unstable(feature = "option_result_unwrap_unchecked", reason = "newly added", issue = "81383")]
pub unsafe fn unwrap_err_unchecked(self) -> E {
debug_assert!(self.is_err());
match self {
// SAFETY: the safety contract must be upheld by the caller.
Ok(_) => unsafe { hint::unreachable_unchecked() },
Err(e) => e,
}
}
}

impl<T: Copy, E> Result<&T, E> {
Expand Down
Loading