Skip to content

Commit 297a801

Browse files
committed
Auto merge of #95552 - matthiaskrgr:rollup-bxminn9, r=matthiaskrgr
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
2 parents 99da9ae + c6750e4 commit 297a801

File tree

28 files changed

+702
-224
lines changed

28 files changed

+702
-224
lines changed

compiler/rustc_const_eval/src/interpret/eval_context.rs

+8-6
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@ use rustc_target::abi::{call::FnAbi, Align, HasDataLayout, Size, TargetDataLayou
2323

2424
use super::{
2525
AllocCheck, AllocId, GlobalId, Immediate, InterpErrorInfo, InterpResult, MPlaceTy, Machine,
26-
MemPlace, MemPlaceMeta, Memory, MemoryKind, Operand, Place, PlaceTy, Pointer, Provenance,
27-
Scalar, ScalarMaybeUninit, StackPopJump,
26+
MemPlace, MemPlaceMeta, Memory, MemoryKind, Operand, Place, PlaceTy, Pointer,
27+
PointerArithmetic, Provenance, Scalar, ScalarMaybeUninit, StackPopJump,
2828
};
2929
use crate::transform::validate::equal_up_to_regions;
3030

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

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

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

compiler/rustc_const_eval/src/interpret/intrinsics.rs

+7-1
Original file line numberDiff line numberDiff line change
@@ -531,7 +531,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
531531
) -> InterpResult<'tcx, Pointer<Option<M::PointerTag>>> {
532532
// We cannot overflow i64 as a type's size must be <= isize::MAX.
533533
let pointee_size = i64::try_from(self.layout_of(pointee_ty)?.size.bytes()).unwrap();
534-
// The computed offset, in bytes, cannot overflow an isize.
534+
// The computed offset, in bytes, must not overflow an isize.
535+
// `checked_mul` enforces a too small bound, but no actual allocation can be big enough for
536+
// the difference to be noticeable.
535537
let offset_bytes =
536538
offset_count.checked_mul(pointee_size).ok_or(err_ub!(PointerArithOverflow))?;
537539
// The offset being in bounds cannot rely on "wrapping around" the address space.
@@ -563,6 +565,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
563565
let count = self.read_scalar(&count)?.to_machine_usize(self)?;
564566
let layout = self.layout_of(src.layout.ty.builtin_deref(true).unwrap().ty)?;
565567
let (size, align) = (layout.size, layout.align.abi);
568+
// `checked_mul` enforces a too small bound (the correct one would probably be machine_isize_max),
569+
// but no actual allocation can be big enough for the difference to be noticeable.
566570
let size = size.checked_mul(count, self).ok_or_else(|| {
567571
err_ub_format!(
568572
"overflow computing total size of `{}`",
@@ -588,6 +592,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
588592
let byte = self.read_scalar(&byte)?.to_u8()?;
589593
let count = self.read_scalar(&count)?.to_machine_usize(self)?;
590594

595+
// `checked_mul` enforces a too small bound (the correct one would probably be machine_isize_max),
596+
// but no actual allocation can be big enough for the difference to be noticeable.
591597
let len = layout
592598
.size
593599
.checked_mul(count, self)

compiler/rustc_const_eval/src/interpret/traits.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -110,16 +110,17 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
110110
.read_ptr_sized(pointer_size * u64::try_from(COMMON_VTABLE_ENTRIES_SIZE).unwrap())?
111111
.check_init()?;
112112
let size = size.to_machine_usize(self)?;
113+
let size = Size::from_bytes(size);
113114
let align = vtable
114115
.read_ptr_sized(pointer_size * u64::try_from(COMMON_VTABLE_ENTRIES_ALIGN).unwrap())?
115116
.check_init()?;
116117
let align = align.to_machine_usize(self)?;
117118
let align = Align::from_bytes(align).map_err(|e| err_ub!(InvalidVtableAlignment(e)))?;
118119

119-
if size >= self.tcx.data_layout.obj_size_bound() {
120+
if size > self.max_size_of_val() {
120121
throw_ub!(InvalidVtableSize);
121122
}
122-
Ok((Size::from_bytes(size), align))
123+
Ok((size, align))
123124
}
124125

125126
pub fn read_new_vtable_after_trait_upcasting_from_vtable(

compiler/rustc_infer/src/infer/error_reporting/mod.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -1091,7 +1091,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
10911091

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

10971101
// helper functions

compiler/rustc_middle/src/mir/interpret/pointer.rs

+5
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,11 @@ pub trait PointerArithmetic: HasDataLayout {
1818
self.data_layout().pointer_size
1919
}
2020

21+
#[inline(always)]
22+
fn max_size_of_val(&self) -> Size {
23+
Size::from_bytes(self.machine_isize_max())
24+
}
25+
2126
#[inline]
2227
fn machine_usize_max(&self) -> u64 {
2328
self.pointer_size().unsigned_int_max().try_into().unwrap()

compiler/rustc_middle/src/ty/closure.rs

+15-3
Original file line numberDiff line numberDiff line change
@@ -119,9 +119,21 @@ impl<'tcx> ClosureKind {
119119
/// See `Ty::to_opt_closure_kind` for more details.
120120
pub fn to_ty(self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
121121
match self {
122-
ty::ClosureKind::Fn => tcx.types.i8,
123-
ty::ClosureKind::FnMut => tcx.types.i16,
124-
ty::ClosureKind::FnOnce => tcx.types.i32,
122+
ClosureKind::Fn => tcx.types.i8,
123+
ClosureKind::FnMut => tcx.types.i16,
124+
ClosureKind::FnOnce => tcx.types.i32,
125+
}
126+
}
127+
128+
pub fn from_def_id(tcx: TyCtxt<'_>, def_id: DefId) -> Option<ClosureKind> {
129+
if Some(def_id) == tcx.lang_items().fn_once_trait() {
130+
Some(ClosureKind::FnOnce)
131+
} else if Some(def_id) == tcx.lang_items().fn_mut_trait() {
132+
Some(ClosureKind::FnMut)
133+
} else if Some(def_id) == tcx.lang_items().fn_trait() {
134+
Some(ClosureKind::Fn)
135+
} else {
136+
None
125137
}
126138
}
127139
}

compiler/rustc_parse/src/parser/expr.rs

+7-11
Original file line numberDiff line numberDiff line change
@@ -1919,17 +1919,13 @@ impl<'a> Parser<'a> {
19191919
match snapshot.parse_array_or_repeat_expr(attrs, token::Brace) {
19201920
Ok(arr) => {
19211921
let hi = snapshot.prev_token.span;
1922-
self.struct_span_err(
1923-
arr.span,
1924-
"this code is interpreted as a block expression, not an array",
1925-
)
1926-
.multipart_suggestion(
1927-
"try using [] instead of {}",
1928-
vec![(lo, "[".to_owned()), (hi, "]".to_owned())],
1929-
Applicability::MaybeIncorrect,
1930-
)
1931-
.note("to define an array, one would use square brackets instead of curly braces")
1932-
.emit();
1922+
self.struct_span_err(arr.span, "this is a block expression, not an array")
1923+
.multipart_suggestion(
1924+
"to make an array, use square brackets instead of curly braces",
1925+
vec![(lo, "[".to_owned()), (hi, "]".to_owned())],
1926+
Applicability::MaybeIncorrect,
1927+
)
1928+
.emit();
19331929

19341930
self.restore_snapshot(snapshot);
19351931
Some(self.mk_expr_err(arr.span))

compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs

+121-5
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@ pub mod on_unimplemented;
22
pub mod suggestions;
33

44
use super::{
5-
EvaluationResult, FulfillmentError, FulfillmentErrorCode, MismatchedProjectionTypes,
6-
Obligation, ObligationCause, ObligationCauseCode, OnUnimplementedDirective,
7-
OnUnimplementedNote, OutputTypeParameterMismatch, Overflow, PredicateObligation,
8-
SelectionContext, SelectionError, TraitNotObjectSafe,
5+
EvaluationResult, FulfillmentContext, FulfillmentError, FulfillmentErrorCode,
6+
MismatchedProjectionTypes, Obligation, ObligationCause, ObligationCauseCode,
7+
OnUnimplementedDirective, OnUnimplementedNote, OutputTypeParameterMismatch, Overflow,
8+
PredicateObligation, SelectionContext, SelectionError, TraitNotObjectSafe,
99
};
1010

1111
use crate::infer::error_reporting::{TyCategory, TypeAnnotationNeeded as ErrorCode};
@@ -21,6 +21,8 @@ use rustc_hir::intravisit::Visitor;
2121
use rustc_hir::GenericParam;
2222
use rustc_hir::Item;
2323
use rustc_hir::Node;
24+
use rustc_infer::infer::error_reporting::same_type_modulo_infer;
25+
use rustc_infer::traits::TraitEngine;
2426
use rustc_middle::thir::abstract_const::NotConstEvaluatable;
2527
use rustc_middle::traits::select::OverflowError;
2628
use rustc_middle::ty::error::ExpectedFound;
@@ -103,6 +105,17 @@ pub trait InferCtxtExt<'tcx> {
103105
found_args: Vec<ArgKind>,
104106
is_closure: bool,
105107
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>;
108+
109+
/// Checks if the type implements one of `Fn`, `FnMut`, or `FnOnce`
110+
/// in that order, and returns the generic type corresponding to the
111+
/// argument of that trait (corresponding to the closure arguments).
112+
fn type_implements_fn_trait(
113+
&self,
114+
param_env: ty::ParamEnv<'tcx>,
115+
ty: ty::Binder<'tcx, Ty<'tcx>>,
116+
constness: ty::BoundConstness,
117+
polarity: ty::ImplPolarity,
118+
) -> Result<(ty::ClosureKind, ty::Binder<'tcx, Ty<'tcx>>), ()>;
106119
}
107120

108121
impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
@@ -563,7 +576,64 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
563576
}
564577

565578
// Try to report a help message
566-
if !trait_ref.has_infer_types_or_consts()
579+
if is_fn_trait
580+
&& let Ok((implemented_kind, params)) = self.type_implements_fn_trait(
581+
obligation.param_env,
582+
trait_ref.self_ty(),
583+
trait_predicate.skip_binder().constness,
584+
trait_predicate.skip_binder().polarity,
585+
)
586+
{
587+
// If the type implements `Fn`, `FnMut`, or `FnOnce`, suppress the following
588+
// suggestion to add trait bounds for the type, since we only typically implement
589+
// these traits once.
590+
591+
// Note if the `FnMut` or `FnOnce` is less general than the trait we're trying
592+
// to implement.
593+
let selected_kind =
594+
ty::ClosureKind::from_def_id(self.tcx, trait_ref.def_id())
595+
.expect("expected to map DefId to ClosureKind");
596+
if !implemented_kind.extends(selected_kind) {
597+
err.note(
598+
&format!(
599+
"`{}` implements `{}`, but it must implement `{}`, which is more general",
600+
trait_ref.skip_binder().self_ty(),
601+
implemented_kind,
602+
selected_kind
603+
)
604+
);
605+
}
606+
607+
// Note any argument mismatches
608+
let given_ty = params.skip_binder();
609+
let expected_ty = trait_ref.skip_binder().substs.type_at(1);
610+
if let ty::Tuple(given) = given_ty.kind()
611+
&& let ty::Tuple(expected) = expected_ty.kind()
612+
{
613+
if expected.len() != given.len() {
614+
// Note number of types that were expected and given
615+
err.note(
616+
&format!(
617+
"expected a closure taking {} argument{}, but one taking {} argument{} was given",
618+
given.len(),
619+
if given.len() == 1 { "" } else { "s" },
620+
expected.len(),
621+
if expected.len() == 1 { "" } else { "s" },
622+
)
623+
);
624+
} else if !same_type_modulo_infer(given_ty, expected_ty) {
625+
// Print type mismatch
626+
let (expected_args, given_args) =
627+
self.cmp(given_ty, expected_ty);
628+
err.note_expected_found(
629+
&"a closure with arguments",
630+
expected_args,
631+
&"a closure with arguments",
632+
given_args,
633+
);
634+
}
635+
}
636+
} else if !trait_ref.has_infer_types_or_consts()
567637
&& self.predicate_can_apply(obligation.param_env, trait_ref)
568638
{
569639
// If a where-clause may be useful, remind the
@@ -1148,6 +1218,52 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
11481218

11491219
err
11501220
}
1221+
1222+
fn type_implements_fn_trait(
1223+
&self,
1224+
param_env: ty::ParamEnv<'tcx>,
1225+
ty: ty::Binder<'tcx, Ty<'tcx>>,
1226+
constness: ty::BoundConstness,
1227+
polarity: ty::ImplPolarity,
1228+
) -> Result<(ty::ClosureKind, ty::Binder<'tcx, Ty<'tcx>>), ()> {
1229+
self.commit_if_ok(|_| {
1230+
for trait_def_id in [
1231+
self.tcx.lang_items().fn_trait(),
1232+
self.tcx.lang_items().fn_mut_trait(),
1233+
self.tcx.lang_items().fn_once_trait(),
1234+
] {
1235+
let Some(trait_def_id) = trait_def_id else { continue };
1236+
// Make a fresh inference variable so we can determine what the substitutions
1237+
// of the trait are.
1238+
let var = self.next_ty_var(TypeVariableOrigin {
1239+
span: DUMMY_SP,
1240+
kind: TypeVariableOriginKind::MiscVariable,
1241+
});
1242+
let substs = self.tcx.mk_substs_trait(ty.skip_binder(), &[var.into()]);
1243+
let obligation = Obligation::new(
1244+
ObligationCause::dummy(),
1245+
param_env,
1246+
ty.rebind(ty::TraitPredicate {
1247+
trait_ref: ty::TraitRef::new(trait_def_id, substs),
1248+
constness,
1249+
polarity,
1250+
})
1251+
.to_predicate(self.tcx),
1252+
);
1253+
let mut fulfill_cx = FulfillmentContext::new_in_snapshot();
1254+
fulfill_cx.register_predicate_obligation(self, obligation);
1255+
if fulfill_cx.select_all_or_error(self).is_empty() {
1256+
return Ok((
1257+
ty::ClosureKind::from_def_id(self.tcx, trait_def_id)
1258+
.expect("expected to map DefId to ClosureKind"),
1259+
ty.rebind(self.resolve_vars_if_possible(var)),
1260+
));
1261+
}
1262+
}
1263+
1264+
Err(())
1265+
})
1266+
}
11511267
}
11521268

11531269
trait InferCtxtPrivExt<'hir, 'tcx> {

compiler/rustc_typeck/src/check/demand.rs

+1
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
3939
self.suggest_no_capture_closure(err, expected, expr_ty);
4040
self.suggest_boxing_when_appropriate(err, expr, expected, expr_ty);
4141
self.suggest_missing_parentheses(err, expr);
42+
self.suggest_block_to_brackets_peeling_refs(err, expr, expr_ty, expected);
4243
self.note_need_for_fn_pointer(err, expected, expr_ty);
4344
self.note_internal_mutation_in_method(err, expr, expected, expr_ty);
4445
self.report_closure_inferred_return_type(err, expected);

0 commit comments

Comments
 (0)