Skip to content

Commit

Permalink
Auto merge of #95552 - matthiaskrgr:rollup-bxminn9, r=matthiaskrgr
Browse files Browse the repository at this point in the history
Rollup of 6 pull requests

Successful merges:

 - #95032 (Clean up, categorize and sort unstable features in std.)
 - #95260 (Better suggestions for `Fn`-family trait selection errors)
 - #95293 (suggest wrapping single-expr blocks in square brackets)
 - #95344 (Make `impl Debug for rustdoc::clean::Item` easier to read)
 - #95388 (interpret: make isize::MAX the limit for dynamic value sizes)
 - #95530 (rustdoc: do not show primitives and keywords as private)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
  • Loading branch information
bors committed Apr 1, 2022
2 parents 99da9ae + c6750e4 commit 297a801
Show file tree
Hide file tree
Showing 28 changed files with 702 additions and 224 deletions.
14 changes: 8 additions & 6 deletions compiler/rustc_const_eval/src/interpret/eval_context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ use rustc_target::abi::{call::FnAbi, Align, HasDataLayout, Size, TargetDataLayou

use super::{
AllocCheck, AllocId, GlobalId, Immediate, InterpErrorInfo, InterpResult, MPlaceTy, Machine,
MemPlace, MemPlaceMeta, Memory, MemoryKind, Operand, Place, PlaceTy, Pointer, Provenance,
Scalar, ScalarMaybeUninit, StackPopJump,
MemPlace, MemPlaceMeta, Memory, MemoryKind, Operand, Place, PlaceTy, Pointer,
PointerArithmetic, Provenance, Scalar, ScalarMaybeUninit, StackPopJump,
};
use crate::transform::validate::equal_up_to_regions;

Expand Down Expand Up @@ -678,7 +678,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
let size = size.align_to(align);

// Check if this brought us over the size limit.
if size.bytes() >= self.tcx.data_layout.obj_size_bound() {
if size > self.max_size_of_val() {
throw_ub!(InvalidMeta("total size is bigger than largest supported object"));
}
Ok(Some((size, align)))
Expand All @@ -694,9 +694,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
let elem = layout.field(self, 0);

// Make sure the slice is not too big.
let size = elem.size.checked_mul(len, self).ok_or_else(|| {
err_ub!(InvalidMeta("slice is bigger than largest supported object"))
})?;
let size = elem.size.bytes().saturating_mul(len); // we rely on `max_size_of_val` being smaller than `u64::MAX`.
let size = Size::from_bytes(size);
if size > self.max_size_of_val() {
throw_ub!(InvalidMeta("slice is bigger than largest supported object"));
}
Ok(Some((size, elem.align.abi)))
}

Expand Down
8 changes: 7 additions & 1 deletion compiler/rustc_const_eval/src/interpret/intrinsics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -531,7 +531,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
) -> InterpResult<'tcx, Pointer<Option<M::PointerTag>>> {
// We cannot overflow i64 as a type's size must be <= isize::MAX.
let pointee_size = i64::try_from(self.layout_of(pointee_ty)?.size.bytes()).unwrap();
// The computed offset, in bytes, cannot overflow an isize.
// The computed offset, in bytes, must not overflow an isize.
// `checked_mul` enforces a too small bound, but no actual allocation can be big enough for
// the difference to be noticeable.
let offset_bytes =
offset_count.checked_mul(pointee_size).ok_or(err_ub!(PointerArithOverflow))?;
// The offset being in bounds cannot rely on "wrapping around" the address space.
Expand Down Expand Up @@ -563,6 +565,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
let count = self.read_scalar(&count)?.to_machine_usize(self)?;
let layout = self.layout_of(src.layout.ty.builtin_deref(true).unwrap().ty)?;
let (size, align) = (layout.size, layout.align.abi);
// `checked_mul` enforces a too small bound (the correct one would probably be machine_isize_max),
// but no actual allocation can be big enough for the difference to be noticeable.
let size = size.checked_mul(count, self).ok_or_else(|| {
err_ub_format!(
"overflow computing total size of `{}`",
Expand All @@ -588,6 +592,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
let byte = self.read_scalar(&byte)?.to_u8()?;
let count = self.read_scalar(&count)?.to_machine_usize(self)?;

// `checked_mul` enforces a too small bound (the correct one would probably be machine_isize_max),
// but no actual allocation can be big enough for the difference to be noticeable.
let len = layout
.size
.checked_mul(count, self)
Expand Down
5 changes: 3 additions & 2 deletions compiler/rustc_const_eval/src/interpret/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,16 +110,17 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
.read_ptr_sized(pointer_size * u64::try_from(COMMON_VTABLE_ENTRIES_SIZE).unwrap())?
.check_init()?;
let size = size.to_machine_usize(self)?;
let size = Size::from_bytes(size);
let align = vtable
.read_ptr_sized(pointer_size * u64::try_from(COMMON_VTABLE_ENTRIES_ALIGN).unwrap())?
.check_init()?;
let align = align.to_machine_usize(self)?;
let align = Align::from_bytes(align).map_err(|e| err_ub!(InvalidVtableAlignment(e)))?;

if size >= self.tcx.data_layout.obj_size_bound() {
if size > self.max_size_of_val() {
throw_ub!(InvalidVtableSize);
}
Ok((Size::from_bytes(size), align))
Ok((size, align))
}

pub fn read_new_vtable_after_trait_upcasting_from_vtable(
Expand Down
6 changes: 5 additions & 1 deletion compiler/rustc_infer/src/infer/error_reporting/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1091,7 +1091,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {

/// Compares two given types, eliding parts that are the same between them and highlighting
/// relevant differences, and return two representation of those types for highlighted printing.
fn cmp(&self, t1: Ty<'tcx>, t2: Ty<'tcx>) -> (DiagnosticStyledString, DiagnosticStyledString) {
pub fn cmp(
&self,
t1: Ty<'tcx>,
t2: Ty<'tcx>,
) -> (DiagnosticStyledString, DiagnosticStyledString) {
debug!("cmp(t1={}, t1.kind={:?}, t2={}, t2.kind={:?})", t1, t1.kind(), t2, t2.kind());

// helper functions
Expand Down
5 changes: 5 additions & 0 deletions compiler/rustc_middle/src/mir/interpret/pointer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@ pub trait PointerArithmetic: HasDataLayout {
self.data_layout().pointer_size
}

#[inline(always)]
fn max_size_of_val(&self) -> Size {
Size::from_bytes(self.machine_isize_max())
}

#[inline]
fn machine_usize_max(&self) -> u64 {
self.pointer_size().unsigned_int_max().try_into().unwrap()
Expand Down
18 changes: 15 additions & 3 deletions compiler/rustc_middle/src/ty/closure.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,9 +119,21 @@ impl<'tcx> ClosureKind {
/// See `Ty::to_opt_closure_kind` for more details.
pub fn to_ty(self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
match self {
ty::ClosureKind::Fn => tcx.types.i8,
ty::ClosureKind::FnMut => tcx.types.i16,
ty::ClosureKind::FnOnce => tcx.types.i32,
ClosureKind::Fn => tcx.types.i8,
ClosureKind::FnMut => tcx.types.i16,
ClosureKind::FnOnce => tcx.types.i32,
}
}

pub fn from_def_id(tcx: TyCtxt<'_>, def_id: DefId) -> Option<ClosureKind> {
if Some(def_id) == tcx.lang_items().fn_once_trait() {
Some(ClosureKind::FnOnce)
} else if Some(def_id) == tcx.lang_items().fn_mut_trait() {
Some(ClosureKind::FnMut)
} else if Some(def_id) == tcx.lang_items().fn_trait() {
Some(ClosureKind::Fn)
} else {
None
}
}
}
Expand Down
18 changes: 7 additions & 11 deletions compiler/rustc_parse/src/parser/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1919,17 +1919,13 @@ impl<'a> Parser<'a> {
match snapshot.parse_array_or_repeat_expr(attrs, token::Brace) {
Ok(arr) => {
let hi = snapshot.prev_token.span;
self.struct_span_err(
arr.span,
"this code is interpreted as a block expression, not an array",
)
.multipart_suggestion(
"try using [] instead of {}",
vec![(lo, "[".to_owned()), (hi, "]".to_owned())],
Applicability::MaybeIncorrect,
)
.note("to define an array, one would use square brackets instead of curly braces")
.emit();
self.struct_span_err(arr.span, "this is a block expression, not an array")
.multipart_suggestion(
"to make an array, use square brackets instead of curly braces",
vec![(lo, "[".to_owned()), (hi, "]".to_owned())],
Applicability::MaybeIncorrect,
)
.emit();

self.restore_snapshot(snapshot);
Some(self.mk_expr_err(arr.span))
Expand Down
126 changes: 121 additions & 5 deletions compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ pub mod on_unimplemented;
pub mod suggestions;

use super::{
EvaluationResult, FulfillmentError, FulfillmentErrorCode, MismatchedProjectionTypes,
Obligation, ObligationCause, ObligationCauseCode, OnUnimplementedDirective,
OnUnimplementedNote, OutputTypeParameterMismatch, Overflow, PredicateObligation,
SelectionContext, SelectionError, TraitNotObjectSafe,
EvaluationResult, FulfillmentContext, FulfillmentError, FulfillmentErrorCode,
MismatchedProjectionTypes, Obligation, ObligationCause, ObligationCauseCode,
OnUnimplementedDirective, OnUnimplementedNote, OutputTypeParameterMismatch, Overflow,
PredicateObligation, SelectionContext, SelectionError, TraitNotObjectSafe,
};

use crate::infer::error_reporting::{TyCategory, TypeAnnotationNeeded as ErrorCode};
Expand All @@ -21,6 +21,8 @@ use rustc_hir::intravisit::Visitor;
use rustc_hir::GenericParam;
use rustc_hir::Item;
use rustc_hir::Node;
use rustc_infer::infer::error_reporting::same_type_modulo_infer;
use rustc_infer::traits::TraitEngine;
use rustc_middle::thir::abstract_const::NotConstEvaluatable;
use rustc_middle::traits::select::OverflowError;
use rustc_middle::ty::error::ExpectedFound;
Expand Down Expand Up @@ -103,6 +105,17 @@ pub trait InferCtxtExt<'tcx> {
found_args: Vec<ArgKind>,
is_closure: bool,
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>;

/// Checks if the type implements one of `Fn`, `FnMut`, or `FnOnce`
/// in that order, and returns the generic type corresponding to the
/// argument of that trait (corresponding to the closure arguments).
fn type_implements_fn_trait(
&self,
param_env: ty::ParamEnv<'tcx>,
ty: ty::Binder<'tcx, Ty<'tcx>>,
constness: ty::BoundConstness,
polarity: ty::ImplPolarity,
) -> Result<(ty::ClosureKind, ty::Binder<'tcx, Ty<'tcx>>), ()>;
}

impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
Expand Down Expand Up @@ -563,7 +576,64 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
}

// Try to report a help message
if !trait_ref.has_infer_types_or_consts()
if is_fn_trait
&& let Ok((implemented_kind, params)) = self.type_implements_fn_trait(
obligation.param_env,
trait_ref.self_ty(),
trait_predicate.skip_binder().constness,
trait_predicate.skip_binder().polarity,
)
{
// If the type implements `Fn`, `FnMut`, or `FnOnce`, suppress the following
// suggestion to add trait bounds for the type, since we only typically implement
// these traits once.

// Note if the `FnMut` or `FnOnce` is less general than the trait we're trying
// to implement.
let selected_kind =
ty::ClosureKind::from_def_id(self.tcx, trait_ref.def_id())
.expect("expected to map DefId to ClosureKind");
if !implemented_kind.extends(selected_kind) {
err.note(
&format!(
"`{}` implements `{}`, but it must implement `{}`, which is more general",
trait_ref.skip_binder().self_ty(),
implemented_kind,
selected_kind
)
);
}

// Note any argument mismatches
let given_ty = params.skip_binder();
let expected_ty = trait_ref.skip_binder().substs.type_at(1);
if let ty::Tuple(given) = given_ty.kind()
&& let ty::Tuple(expected) = expected_ty.kind()
{
if expected.len() != given.len() {
// Note number of types that were expected and given
err.note(
&format!(
"expected a closure taking {} argument{}, but one taking {} argument{} was given",
given.len(),
if given.len() == 1 { "" } else { "s" },
expected.len(),
if expected.len() == 1 { "" } else { "s" },
)
);
} else if !same_type_modulo_infer(given_ty, expected_ty) {
// Print type mismatch
let (expected_args, given_args) =
self.cmp(given_ty, expected_ty);
err.note_expected_found(
&"a closure with arguments",
expected_args,
&"a closure with arguments",
given_args,
);
}
}
} else if !trait_ref.has_infer_types_or_consts()
&& self.predicate_can_apply(obligation.param_env, trait_ref)
{
// If a where-clause may be useful, remind the
Expand Down Expand Up @@ -1148,6 +1218,52 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {

err
}

fn type_implements_fn_trait(
&self,
param_env: ty::ParamEnv<'tcx>,
ty: ty::Binder<'tcx, Ty<'tcx>>,
constness: ty::BoundConstness,
polarity: ty::ImplPolarity,
) -> Result<(ty::ClosureKind, ty::Binder<'tcx, Ty<'tcx>>), ()> {
self.commit_if_ok(|_| {
for trait_def_id in [
self.tcx.lang_items().fn_trait(),
self.tcx.lang_items().fn_mut_trait(),
self.tcx.lang_items().fn_once_trait(),
] {
let Some(trait_def_id) = trait_def_id else { continue };
// Make a fresh inference variable so we can determine what the substitutions
// of the trait are.
let var = self.next_ty_var(TypeVariableOrigin {
span: DUMMY_SP,
kind: TypeVariableOriginKind::MiscVariable,
});
let substs = self.tcx.mk_substs_trait(ty.skip_binder(), &[var.into()]);
let obligation = Obligation::new(
ObligationCause::dummy(),
param_env,
ty.rebind(ty::TraitPredicate {
trait_ref: ty::TraitRef::new(trait_def_id, substs),
constness,
polarity,
})
.to_predicate(self.tcx),
);
let mut fulfill_cx = FulfillmentContext::new_in_snapshot();
fulfill_cx.register_predicate_obligation(self, obligation);
if fulfill_cx.select_all_or_error(self).is_empty() {
return Ok((
ty::ClosureKind::from_def_id(self.tcx, trait_def_id)
.expect("expected to map DefId to ClosureKind"),
ty.rebind(self.resolve_vars_if_possible(var)),
));
}
}

Err(())
})
}
}

trait InferCtxtPrivExt<'hir, 'tcx> {
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_typeck/src/check/demand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.suggest_no_capture_closure(err, expected, expr_ty);
self.suggest_boxing_when_appropriate(err, expr, expected, expr_ty);
self.suggest_missing_parentheses(err, expr);
self.suggest_block_to_brackets_peeling_refs(err, expr, expr_ty, expected);
self.note_need_for_fn_pointer(err, expected, expr_ty);
self.note_internal_mutation_in_method(err, expr, expected, expr_ty);
self.report_closure_inferred_return_type(err, expected);
Expand Down
Loading

0 comments on commit 297a801

Please sign in to comment.