diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs index abd7094440e57..1b8186b5aadba 100644 --- a/compiler/rustc_const_eval/src/interpret/eval_context.rs +++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs @@ -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; @@ -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))) @@ -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))) } diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index 5eff7d693c5a6..c80d7d7178742 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -531,7 +531,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { ) -> InterpResult<'tcx, Pointer>> { // 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. @@ -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 `{}`", @@ -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) diff --git a/compiler/rustc_const_eval/src/interpret/traits.rs b/compiler/rustc_const_eval/src/interpret/traits.rs index 131674decc961..fc60a40e2ada6 100644 --- a/compiler/rustc_const_eval/src/interpret/traits.rs +++ b/compiler/rustc_const_eval/src/interpret/traits.rs @@ -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( diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 9b2fc07e9cbe4..d915f9a5ae83c 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -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 diff --git a/compiler/rustc_middle/src/mir/interpret/pointer.rs b/compiler/rustc_middle/src/mir/interpret/pointer.rs index 7d101046a96b4..813c0912f5396 100644 --- a/compiler/rustc_middle/src/mir/interpret/pointer.rs +++ b/compiler/rustc_middle/src/mir/interpret/pointer.rs @@ -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() diff --git a/compiler/rustc_middle/src/ty/closure.rs b/compiler/rustc_middle/src/ty/closure.rs index 1446f7dac3638..3bddf7fb6ffc4 100644 --- a/compiler/rustc_middle/src/ty/closure.rs +++ b/compiler/rustc_middle/src/ty/closure.rs @@ -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 { + 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 } } } diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index a970d180b1a9b..20d035fba195a 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -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)) diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index d83781170e8c3..727847968e53a 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -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}; @@ -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; @@ -103,6 +105,17 @@ pub trait InferCtxtExt<'tcx> { found_args: Vec, 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> { @@ -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 @@ -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> { diff --git a/compiler/rustc_typeck/src/check/demand.rs b/compiler/rustc_typeck/src/check/demand.rs index d2b462b595960..00bc16452b9b9 100644 --- a/compiler/rustc_typeck/src/check/demand.rs +++ b/compiler/rustc_typeck/src/check/demand.rs @@ -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); diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs index 4d3fdea1fc373..2a1b7a5ab47ba 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs @@ -774,57 +774,68 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let prev_diverges = self.diverges.get(); let ctxt = BreakableCtxt { coerce: Some(coerce), may_break: false }; - let (ctxt, ()) = - self.with_breakable_ctxt(blk.hir_id, ctxt, || { - for (pos, s) in blk.stmts.iter().enumerate() { - self.check_stmt(s, blk.stmts.len() - 1 == pos); - } + let (ctxt, ()) = self.with_breakable_ctxt(blk.hir_id, ctxt, || { + for (pos, s) in blk.stmts.iter().enumerate() { + self.check_stmt(s, blk.stmts.len() - 1 == pos); + } - // check the tail expression **without** holding the - // `enclosing_breakables` lock below. - let tail_expr_ty = tail_expr.map(|t| self.check_expr_with_expectation(t, expected)); - - let mut enclosing_breakables = self.enclosing_breakables.borrow_mut(); - let ctxt = enclosing_breakables.find_breakable(blk.hir_id); - let coerce = ctxt.coerce.as_mut().unwrap(); - if let Some(tail_expr_ty) = tail_expr_ty { - let tail_expr = tail_expr.unwrap(); - let span = self.get_expr_coercion_span(tail_expr); - let cause = - self.cause(span, ObligationCauseCode::BlockTailExpression(blk.hir_id)); - coerce.coerce(self, &cause, tail_expr, tail_expr_ty); - } else { - // Subtle: if there is no explicit tail expression, - // that is typically equivalent to a tail expression - // of `()` -- except if the block diverges. In that - // case, there is no value supplied from the tail - // expression (assuming there are no other breaks, - // this implies that the type of the block will be - // `!`). - // - // #41425 -- label the implicit `()` as being the - // "found type" here, rather than the "expected type". - if !self.diverges.get().is_always() { - // #50009 -- Do not point at the entire fn block span, point at the return type - // span, as it is the cause of the requirement, and - // `consider_hint_about_removing_semicolon` will point at the last expression - // if it were a relevant part of the error. This improves usability in editors - // that highlight errors inline. - let mut sp = blk.span; - let mut fn_span = None; - if let Some((decl, ident)) = self.get_parent_fn_decl(blk.hir_id) { - let ret_sp = decl.output.span(); - if let Some(block_sp) = self.parent_item_span(blk.hir_id) { - // HACK: on some cases (`ui/liveness/liveness-issue-2163.rs`) the - // output would otherwise be incorrect and even misleading. Make sure - // the span we're aiming at correspond to a `fn` body. - if block_sp == blk.span { - sp = ret_sp; - fn_span = Some(ident.span); - } + // check the tail expression **without** holding the + // `enclosing_breakables` lock below. + let tail_expr_ty = tail_expr.map(|t| self.check_expr_with_expectation(t, expected)); + + let mut enclosing_breakables = self.enclosing_breakables.borrow_mut(); + let ctxt = enclosing_breakables.find_breakable(blk.hir_id); + let coerce = ctxt.coerce.as_mut().unwrap(); + if let Some(tail_expr_ty) = tail_expr_ty { + let tail_expr = tail_expr.unwrap(); + let span = self.get_expr_coercion_span(tail_expr); + let cause = self.cause(span, ObligationCauseCode::BlockTailExpression(blk.hir_id)); + let ty_for_diagnostic = coerce.merged_ty(); + // We use coerce_inner here because we want to augment the error + // suggesting to wrap the block in square brackets if it might've + // been mistaken array syntax + coerce.coerce_inner( + self, + &cause, + Some(tail_expr), + tail_expr_ty, + Some(&mut |diag: &mut Diagnostic| { + self.suggest_block_to_brackets(diag, blk, tail_expr_ty, ty_for_diagnostic); + }), + false, + ); + } else { + // Subtle: if there is no explicit tail expression, + // that is typically equivalent to a tail expression + // of `()` -- except if the block diverges. In that + // case, there is no value supplied from the tail + // expression (assuming there are no other breaks, + // this implies that the type of the block will be + // `!`). + // + // #41425 -- label the implicit `()` as being the + // "found type" here, rather than the "expected type". + if !self.diverges.get().is_always() { + // #50009 -- Do not point at the entire fn block span, point at the return type + // span, as it is the cause of the requirement, and + // `consider_hint_about_removing_semicolon` will point at the last expression + // if it were a relevant part of the error. This improves usability in editors + // that highlight errors inline. + let mut sp = blk.span; + let mut fn_span = None; + if let Some((decl, ident)) = self.get_parent_fn_decl(blk.hir_id) { + let ret_sp = decl.output.span(); + if let Some(block_sp) = self.parent_item_span(blk.hir_id) { + // HACK: on some cases (`ui/liveness/liveness-issue-2163.rs`) the + // output would otherwise be incorrect and even misleading. Make sure + // the span we're aiming at correspond to a `fn` body. + if block_sp == blk.span { + sp = ret_sp; + fn_span = Some(ident.span); } } - coerce.coerce_forced_unit( + } + coerce.coerce_forced_unit( self, &self.misc(sp), &mut |err| { @@ -837,21 +848,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Our block must be a `assign desugar local; assignment` if let Some(hir::Node::Block(hir::Block { stmts: - [hir::Stmt { - kind: - hir::StmtKind::Local(hir::Local { - source: hir::LocalSource::AssignDesugar(_), - .. - }), - .. - }, hir::Stmt { - kind: - hir::StmtKind::Expr(hir::Expr { - kind: hir::ExprKind::Assign(..), - .. - }), - .. - }], + [ + hir::Stmt { + kind: + hir::StmtKind::Local(hir::Local { + source: + hir::LocalSource::AssignDesugar(_), + .. + }), + .. + }, + hir::Stmt { + kind: + hir::StmtKind::Expr(hir::Expr { + kind: hir::ExprKind::Assign(..), + .. + }), + .. + }, + ], .. })) = self.tcx.hir().find(blk.hir_id) { @@ -871,9 +886,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }, false, ); - } } - }); + } + }); if ctxt.may_break { // If we can break from the block, then the block's exit is always reachable diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs index e6a98ad6dc051..68d555b3a651d 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs @@ -766,6 +766,77 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } + /// Given an expression type mismatch, peel any `&` expressions until we get to + /// a block expression, and then suggest replacing the braces with square braces + /// if it was possibly mistaken array syntax. + pub(crate) fn suggest_block_to_brackets_peeling_refs( + &self, + diag: &mut Diagnostic, + mut expr: &hir::Expr<'_>, + mut expr_ty: Ty<'tcx>, + mut expected_ty: Ty<'tcx>, + ) { + loop { + match (&expr.kind, expr_ty.kind(), expected_ty.kind()) { + ( + hir::ExprKind::AddrOf(_, _, inner_expr), + ty::Ref(_, inner_expr_ty, _), + ty::Ref(_, inner_expected_ty, _), + ) => { + expr = *inner_expr; + expr_ty = *inner_expr_ty; + expected_ty = *inner_expected_ty; + } + (hir::ExprKind::Block(blk, _), _, _) => { + self.suggest_block_to_brackets(diag, *blk, expr_ty, expected_ty); + break; + } + _ => break, + } + } + } + + /// Suggest wrapping the block in square brackets instead of curly braces + /// in case the block was mistaken array syntax, e.g. `{ 1 }` -> `[ 1 ]`. + pub(crate) fn suggest_block_to_brackets( + &self, + diag: &mut Diagnostic, + blk: &hir::Block<'_>, + blk_ty: Ty<'tcx>, + expected_ty: Ty<'tcx>, + ) { + if let ty::Slice(elem_ty) | ty::Array(elem_ty, _) = expected_ty.kind() { + if self.can_coerce(blk_ty, *elem_ty) + && blk.stmts.is_empty() + && blk.rules == hir::BlockCheckMode::DefaultBlock + { + let source_map = self.tcx.sess.source_map(); + if let Ok(snippet) = source_map.span_to_snippet(blk.span) { + if snippet.starts_with('{') && snippet.ends_with('}') { + diag.multipart_suggestion_verbose( + "to create an array, use square brackets instead of curly braces", + vec![ + ( + blk.span + .shrink_to_lo() + .with_hi(rustc_span::BytePos(blk.span.lo().0 + 1)), + "[".to_string(), + ), + ( + blk.span + .shrink_to_hi() + .with_lo(rustc_span::BytePos(blk.span.hi().0 - 1)), + "]".to_string(), + ), + ], + Applicability::MachineApplicable, + ); + } + } + } + } + } + fn is_loop(&self, id: hir::HirId) -> bool { let node = self.tcx.hir().get(id); matches!(node, Node::Expr(Expr { kind: ExprKind::Loop(..), .. })) diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 133ced5f26cfb..819ec10a4b4b6 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -218,111 +218,122 @@ feature(slice_index_methods, coerce_unsized, sgx_platform) )] #![deny(rustc::existing_doc_keyword)] -// std is implemented with unstable features, many of which are internal -// compiler details that will never be stable -// NB: the following list is sorted to minimize merge conflicts. +// +// Language features: #![feature(alloc_error_handler)] -#![feature(alloc_layout_extra)] -#![feature(allocator_api)] #![feature(allocator_internals)] #![feature(allow_internal_unsafe)] #![feature(allow_internal_unstable)] -#![feature(array_error_internals)] -#![feature(assert_matches)] #![feature(associated_type_bounds)] -#![feature(async_iterator)] -#![feature(atomic_mut_ptr)] -#![feature(bench_black_box)] #![feature(box_syntax)] #![feature(c_unwind)] -#![feature(c_variadic)] -#![feature(cfg_accessible)] -#![feature(cfg_eval)] #![feature(cfg_target_thread_local)] -#![feature(char_error_internals)] -#![feature(char_internals)] -#![feature(concat_bytes)] #![feature(concat_idents)] #![cfg_attr(bootstrap, feature(const_fn_fn_ptr_basics))] #![cfg_attr(bootstrap, feature(const_fn_trait_bound))] -#![feature(const_format_args)] -#![feature(const_io_structs)] -#![feature(const_ip)] -#![feature(const_ipv4)] -#![feature(const_ipv6)] #![feature(const_mut_refs)] -#![feature(const_option)] -#![feature(const_socketaddr)] #![feature(const_trait_impl)] -#![feature(c_size_t)] -#![feature(core_ffi_c)] -#![feature(core_intrinsics)] -#![feature(core_panic)] -#![feature(custom_test_frameworks)] #![feature(decl_macro)] +#![cfg_attr(not(bootstrap), feature(deprecated_suggestion))] #![feature(doc_cfg)] #![feature(doc_cfg_hide)] -#![feature(rustdoc_internals)] -#![cfg_attr(not(bootstrap), feature(deprecated_suggestion))] #![feature(doc_masked)] #![feature(doc_notable_trait)] #![feature(dropck_eyepatch)] -#![feature(duration_checked_float)] -#![feature(duration_constants)] -#![feature(edition_panic)] -#![feature(exact_size_is_empty)] #![feature(exhaustive_patterns)] -#![feature(extend_one)] -#![feature(float_minimum_maximum)] -#![feature(format_args_nl)] -#![feature(strict_provenance)] -#![feature(get_mut_unchecked)] -#![feature(hashmap_internals)] -#![feature(int_error_internals)] #![feature(intra_doc_pointers)] #![feature(lang_items)] #![feature(linkage)] -#![feature(log_syntax)] -#![feature(map_try_insert)] -#![feature(maybe_uninit_slice)] -#![feature(maybe_uninit_write_slice)] #![feature(min_specialization)] -#![feature(mixed_integer_ops)] #![feature(must_not_suspend)] #![feature(needs_panic_runtime)] #![feature(negative_impls)] #![feature(never_type)] -#![feature(new_uninit)] #![feature(nll)] +#![feature(platform_intrinsics)] +#![feature(prelude_import)] +#![feature(rustc_attrs)] +#![feature(rustdoc_internals)] +#![feature(staged_api)] +#![feature(thread_local)] +#![feature(try_blocks)] +// +// Library features (core): +#![feature(array_error_internals)] +#![feature(atomic_mut_ptr)] +#![feature(char_error_internals)] +#![feature(char_internals)] +#![feature(core_intrinsics)] +#![feature(duration_checked_float)] +#![feature(duration_constants)] +#![feature(exact_size_is_empty)] +#![feature(extend_one)] +#![feature(float_minimum_maximum)] +#![feature(hashmap_internals)] +#![feature(int_error_internals)] +#![feature(maybe_uninit_slice)] +#![feature(maybe_uninit_write_slice)] +#![feature(mixed_integer_ops)] #![feature(nonnull_slice_from_raw_parts)] -#![feature(once_cell)] +#![feature(panic_can_unwind)] #![feature(panic_info_message)] #![feature(panic_internals)] -#![feature(panic_can_unwind)] -#![feature(panic_unwind)] -#![feature(platform_intrinsics)] #![feature(portable_simd)] -#![feature(prelude_import)] #![feature(ptr_as_uninit)] #![feature(raw_os_nonzero)] -#![feature(rustc_attrs)] -#![feature(saturating_int_impl)] #![feature(slice_internals)] #![feature(slice_ptr_get)] -#![feature(staged_api)] #![feature(std_internals)] -#![feature(stdsimd)] #![feature(str_internals)] -#![feature(test)] -#![feature(thread_local)] -#![feature(thread_local_internals)] -#![feature(toowned_clone_into)] +#![feature(strict_provenance)] #![feature(total_cmp)] -#![feature(trace_macros)] -#![feature(try_blocks)] +// +// Library features (alloc): +#![feature(alloc_layout_extra)] +#![feature(allocator_api)] +#![feature(get_mut_unchecked)] +#![feature(map_try_insert)] +#![feature(new_uninit)] +#![feature(toowned_clone_into)] #![feature(try_reserve_kind)] #![feature(vec_into_raw_parts)] -// NB: the above list is sorted to minimize merge conflicts. +// +// Library features (unwind): +#![feature(panic_unwind)] +// +// Only for re-exporting: +#![feature(assert_matches)] +#![feature(async_iterator)] +#![feature(c_size_t)] +#![feature(c_variadic)] +#![feature(cfg_accessible)] +#![feature(cfg_eval)] +#![feature(concat_bytes)] +#![feature(const_format_args)] +#![feature(core_ffi_c)] +#![feature(core_panic)] +#![feature(custom_test_frameworks)] +#![feature(edition_panic)] +#![feature(format_args_nl)] +#![feature(log_syntax)] +#![feature(once_cell)] +#![feature(saturating_int_impl)] +#![feature(stdsimd)] +#![feature(test)] +#![feature(trace_macros)] +// +// Only used in tests/benchmarks: +#![feature(bench_black_box)] +// +// Only for const-ness: +#![feature(const_io_structs)] +#![feature(const_ip)] +#![feature(const_ipv4)] +#![feature(const_ipv6)] +#![feature(const_option)] +#![feature(const_socketaddr)] +#![feature(thread_local_internals)] +// #![default_lib_allocator] // Explicitly import the prelude. The compiler uses this same unstable attribute diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 3e60ed2f7c4e5..7698c2de24d5c 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -1,5 +1,6 @@ use std::cell::RefCell; use std::default::Default; +use std::fmt; use std::hash::Hash; use std::iter; use std::lazy::SyncOnceCell as OnceCell; @@ -355,7 +356,7 @@ crate enum ExternalLocation { /// Anything with a source location and set of attributes and, optionally, a /// name. That is, anything that can be documented. This doesn't correspond /// directly to the AST's concept of an item; it's a strict superset. -#[derive(Clone, Debug)] +#[derive(Clone)] crate struct Item { /// The name of this item. /// Optional because not every item has a name, e.g. impls. @@ -370,6 +371,27 @@ crate struct Item { crate cfg: Option>, } +/// NOTE: this does NOT unconditionally print every item, to avoid thousands of lines of logs. +/// If you want to see the debug output for attributes and the `kind` as well, use `{:#?}` instead of `{:?}`. +impl fmt::Debug for Item { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let alternate = f.alternate(); + // hand-picked fields that don't bloat the logs too much + let mut fmt = f.debug_struct("Item"); + fmt.field("name", &self.name) + .field("visibility", &self.visibility) + .field("def_id", &self.def_id); + // allow printing the full item if someone really wants to + if alternate { + fmt.field("attrs", &self.attrs).field("kind", &self.kind).field("cfg", &self.cfg); + } else { + fmt.field("kind", &self.type_()); + fmt.field("docs", &self.doc_value()); + } + fmt.finish() + } +} + // `Item` is used a lot. Make sure it doesn't unintentionally get bigger. #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] rustc_data_structures::static_assert_size!(Item, 56); @@ -471,14 +493,17 @@ impl Item { ) -> Item { trace!("name={:?}, def_id={:?}", name, def_id); - Item { - def_id: def_id.into(), - kind: box kind, - name, - attrs, - visibility: cx.tcx.visibility(def_id).clean(cx), - cfg, - } + // Primitives and Keywords are written in the source code as private modules. + // The modules need to be private so that nobody actually uses them, but the + // keywords and primitives that they are documenting are public. + let visibility = if matches!(&kind, ItemKind::KeywordItem(..) | ItemKind::PrimitiveItem(..)) + { + Visibility::Public + } else { + cx.tcx.visibility(def_id).clean(cx) + }; + + Item { def_id: def_id.into(), kind: box kind, name, attrs, visibility, cfg } } /// Finds all `doc` attributes as NameValues and returns their corresponding values, joined diff --git a/src/test/rustdoc/keyword.rs b/src/test/rustdoc/keyword.rs index 29ceda4f7c1d3..1cebe4c679770 100644 --- a/src/test/rustdoc/keyword.rs +++ b/src/test/rustdoc/keyword.rs @@ -12,6 +12,7 @@ // @has foo/index.html '//a/@href' '../foo/index.html' // @!has foo/foo/index.html // @!has-dir foo/foo +// @!has foo/index.html '//span' 'πŸ”’' #[doc(keyword = "match")] /// this is a test! mod foo{} diff --git a/src/test/rustdoc/primitive.rs b/src/test/rustdoc/primitive.rs new file mode 100644 index 0000000000000..605ca4d170b39 --- /dev/null +++ b/src/test/rustdoc/primitive.rs @@ -0,0 +1,21 @@ +#![crate_name = "foo"] + +#![feature(rustdoc_internals)] + +// @has foo/index.html '//h2[@id="primitives"]' 'Primitive Types' +// @has foo/index.html '//a[@href="primitive.i32.html"]' 'i32' +// @has foo/index.html '//div[@class="sidebar-elems"]//li/a' 'Primitive Types' +// @has foo/index.html '//div[@class="sidebar-elems"]//li/a/@href' '#primitives' +// @has foo/primitive.i32.html '//a[@class="primitive"]' 'i32' +// @has foo/primitive.i32.html '//span[@class="in-band"]' 'Primitive Type i32' +// @has foo/primitive.i32.html '//section[@id="main-content"]//div[@class="docblock"]//p' 'this is a test!' +// @has foo/index.html '//a/@href' '../foo/index.html' +// @!has foo/index.html '//span' 'πŸ”’' +#[doc(primitive = "i32")] +/// this is a test! +mod i32{} + +// @has foo/primitive.bool.html '//section[@id="main-content"]//div[@class="docblock"]//p' 'hello' +#[doc(primitive = "bool")] +/// hello +mod bool {} diff --git a/src/test/ui/consts/const-eval/ub-wide-ptr.32bit.stderr b/src/test/ui/consts/const-eval/ub-wide-ptr.32bit.stderr index f8c9dca566b93..46901bd3b9b34 100644 --- a/src/test/ui/consts/const-eval/ub-wide-ptr.32bit.stderr +++ b/src/test/ui/consts/const-eval/ub-wide-ptr.32bit.stderr @@ -104,6 +104,17 @@ LL | const SLICE_TOO_LONG: &[u8] = unsafe { mem::transmute((&42u8, 999usize)) }; error[E0080]: it is undefined behavior to use this value --> $DIR/ub-wide-ptr.rs:71:1 | +LL | const SLICE_TOO_LONG_OVERFLOW: &[u32] = unsafe { mem::transmute((&42u32, isize::MAX)) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered invalid reference metadata: slice is bigger than largest supported object + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 8, align: 4) { + ╾─allocN─╼ ff ff ff 7f β”‚ ╾──╼.... + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-wide-ptr.rs:74:1 + | LL | const SLICE_LENGTH_PTR: &[u8] = unsafe { mem::transmute((&42u8, &3)) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered non-integer slice length in wide pointer | @@ -113,7 +124,7 @@ LL | const SLICE_LENGTH_PTR: &[u8] = unsafe { mem::transmute((&42u8, &3)) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:74:1 + --> $DIR/ub-wide-ptr.rs:77:1 | LL | const SLICE_TOO_LONG_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, 999usize)) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a dangling box (going beyond the bounds of its allocation) @@ -124,7 +135,7 @@ LL | const SLICE_TOO_LONG_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, 999us } error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:77:1 + --> $DIR/ub-wide-ptr.rs:80:1 | LL | const SLICE_LENGTH_PTR_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, &3)) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered non-integer slice length in wide pointer @@ -135,7 +146,7 @@ LL | const SLICE_LENGTH_PTR_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, &3) } error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:81:1 + --> $DIR/ub-wide-ptr.rs:84:1 | LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .[0]: encountered 0x03, but expected a boolean @@ -146,29 +157,29 @@ LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }]; } error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:87:1 + --> $DIR/ub-wide-ptr.rs:90:1 | LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3u8) }, [false]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at ..0: encountered 0x03, but expected a boolean | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 4, align: 4) { - ╾─allocN─╼ β”‚ ╾──╼ + β•ΎallocN─╼ β”‚ ╾──╼ } error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:90:1 + --> $DIR/ub-wide-ptr.rs:93:1 | LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute(3u8) }]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at ..1[0]: encountered 0x03, but expected a boolean | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 4, align: 4) { - ╾─allocN─╼ β”‚ ╾──╼ + β•ΎallocN─╼ β”‚ ╾──╼ } error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:97:1 + --> $DIR/ub-wide-ptr.rs:100:1 | LL | / const RAW_SLICE_LENGTH_UNINIT: *const [u8] = unsafe { LL | | @@ -183,7 +194,7 @@ LL | | }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:105:1 + --> $DIR/ub-wide-ptr.rs:108:1 | LL | const TRAIT_OBJ_SHORT_VTABLE_1: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u8))) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .0: encountered too small vtable @@ -194,7 +205,7 @@ LL | const TRAIT_OBJ_SHORT_VTABLE_1: W<&dyn Trait> = unsafe { mem::transmute(W(( } error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:108:1 + --> $DIR/ub-wide-ptr.rs:111:1 | LL | const TRAIT_OBJ_SHORT_VTABLE_2: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u64))) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .0: encountered too small vtable @@ -205,7 +216,7 @@ LL | const TRAIT_OBJ_SHORT_VTABLE_2: W<&dyn Trait> = unsafe { mem::transmute(W(( } error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:111:1 + --> $DIR/ub-wide-ptr.rs:114:1 | LL | const TRAIT_OBJ_INT_VTABLE: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, 4usize))) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .0: encountered dangling vtable pointer in wide pointer @@ -216,7 +227,7 @@ LL | const TRAIT_OBJ_INT_VTABLE: W<&dyn Trait> = unsafe { mem::transmute(W((&92u } error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:113:1 + --> $DIR/ub-wide-ptr.rs:116:1 | LL | const TRAIT_OBJ_UNALIGNED_VTABLE: &dyn Trait = unsafe { mem::transmute((&92u8, &[0u8; 128])) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered unaligned vtable pointer in wide pointer @@ -227,7 +238,7 @@ LL | const TRAIT_OBJ_UNALIGNED_VTABLE: &dyn Trait = unsafe { mem::transmute((&92 } error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:115:1 + --> $DIR/ub-wide-ptr.rs:118:1 | LL | const TRAIT_OBJ_BAD_DROP_FN_NULL: &dyn Trait = unsafe { mem::transmute((&92u8, &[0usize; 8])) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered invalid drop function pointer in vtable (not pointing to a function) @@ -238,7 +249,7 @@ LL | const TRAIT_OBJ_BAD_DROP_FN_NULL: &dyn Trait = unsafe { mem::transmute((&92 } error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:117:1 + --> $DIR/ub-wide-ptr.rs:120:1 | LL | const TRAIT_OBJ_BAD_DROP_FN_INT: &dyn Trait = unsafe { mem::transmute((&92u8, &[1usize; 8])) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered invalid drop function pointer in vtable (not pointing to a function) @@ -249,7 +260,7 @@ LL | const TRAIT_OBJ_BAD_DROP_FN_INT: &dyn Trait = unsafe { mem::transmute((&92u } error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:119:1 + --> $DIR/ub-wide-ptr.rs:122:1 | LL | const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &[&42u8; 8]))) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .0: encountered invalid drop function pointer in vtable (not pointing to a function) @@ -260,7 +271,7 @@ LL | const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: W<&dyn Trait> = unsafe { mem::trans } error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:123:1 + --> $DIR/ub-wide-ptr.rs:126:1 | LL | const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_, &bool>(&3u8) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at ..: encountered 0x03, but expected a boolean @@ -271,7 +282,7 @@ LL | const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_, } error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:127:1 + --> $DIR/ub-wide-ptr.rs:130:1 | LL | const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { mem::transmute((&92u8, 0usize)) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered dangling vtable pointer in wide pointer @@ -282,7 +293,7 @@ LL | const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { mem::transmute } error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:129:1 + --> $DIR/ub-wide-ptr.rs:132:1 | LL | const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transmute((&92u8, &3u64)) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered too small vtable @@ -293,17 +304,17 @@ LL | const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transm } error[E0080]: could not evaluate static initializer - --> $DIR/ub-wide-ptr.rs:135:5 + --> $DIR/ub-wide-ptr.rs:138:5 | LL | mem::transmute::<_, &dyn Trait>((&92u8, 0usize)) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: null pointer is not a valid pointer error[E0080]: could not evaluate static initializer - --> $DIR/ub-wide-ptr.rs:139:5 + --> $DIR/ub-wide-ptr.rs:142:5 | LL | mem::transmute::<_, &dyn Trait>((&92u8, &3u64)) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: allocN has size N, so pointer to 12 bytes starting at offset N is out-of-bounds -error: aborting due to 28 previous errors +error: aborting due to 29 previous errors For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/consts/const-eval/ub-wide-ptr.64bit.stderr b/src/test/ui/consts/const-eval/ub-wide-ptr.64bit.stderr index ded007ce28139..b76f88928678a 100644 --- a/src/test/ui/consts/const-eval/ub-wide-ptr.64bit.stderr +++ b/src/test/ui/consts/const-eval/ub-wide-ptr.64bit.stderr @@ -104,6 +104,17 @@ LL | const SLICE_TOO_LONG: &[u8] = unsafe { mem::transmute((&42u8, 999usize)) }; error[E0080]: it is undefined behavior to use this value --> $DIR/ub-wide-ptr.rs:71:1 | +LL | const SLICE_TOO_LONG_OVERFLOW: &[u32] = unsafe { mem::transmute((&42u32, isize::MAX)) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered invalid reference metadata: slice is bigger than largest supported object + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 16, align: 8) { + ╾───────allocN───────╼ ff ff ff ff ff ff ff 7f β”‚ ╾──────╼........ + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-wide-ptr.rs:74:1 + | LL | const SLICE_LENGTH_PTR: &[u8] = unsafe { mem::transmute((&42u8, &3)) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered non-integer slice length in wide pointer | @@ -113,7 +124,7 @@ LL | const SLICE_LENGTH_PTR: &[u8] = unsafe { mem::transmute((&42u8, &3)) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:74:1 + --> $DIR/ub-wide-ptr.rs:77:1 | LL | const SLICE_TOO_LONG_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, 999usize)) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a dangling box (going beyond the bounds of its allocation) @@ -124,7 +135,7 @@ LL | const SLICE_TOO_LONG_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, 999us } error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:77:1 + --> $DIR/ub-wide-ptr.rs:80:1 | LL | const SLICE_LENGTH_PTR_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, &3)) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered non-integer slice length in wide pointer @@ -135,7 +146,7 @@ LL | const SLICE_LENGTH_PTR_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, &3) } error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:81:1 + --> $DIR/ub-wide-ptr.rs:84:1 | LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .[0]: encountered 0x03, but expected a boolean @@ -146,29 +157,29 @@ LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }]; } error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:87:1 + --> $DIR/ub-wide-ptr.rs:90:1 | LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3u8) }, [false]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at ..0: encountered 0x03, but expected a boolean | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 8) { - ╾───────allocN───────╼ β”‚ ╾──────╼ + ╾──────allocN───────╼ β”‚ ╾──────╼ } error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:90:1 + --> $DIR/ub-wide-ptr.rs:93:1 | LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute(3u8) }]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at ..1[0]: encountered 0x03, but expected a boolean | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 8) { - ╾───────allocN───────╼ β”‚ ╾──────╼ + ╾──────allocN───────╼ β”‚ ╾──────╼ } error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:97:1 + --> $DIR/ub-wide-ptr.rs:100:1 | LL | / const RAW_SLICE_LENGTH_UNINIT: *const [u8] = unsafe { LL | | @@ -183,7 +194,7 @@ LL | | }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:105:1 + --> $DIR/ub-wide-ptr.rs:108:1 | LL | const TRAIT_OBJ_SHORT_VTABLE_1: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u8))) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .0: encountered too small vtable @@ -194,7 +205,7 @@ LL | const TRAIT_OBJ_SHORT_VTABLE_1: W<&dyn Trait> = unsafe { mem::transmute(W(( } error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:108:1 + --> $DIR/ub-wide-ptr.rs:111:1 | LL | const TRAIT_OBJ_SHORT_VTABLE_2: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u64))) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .0: encountered too small vtable @@ -205,7 +216,7 @@ LL | const TRAIT_OBJ_SHORT_VTABLE_2: W<&dyn Trait> = unsafe { mem::transmute(W(( } error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:111:1 + --> $DIR/ub-wide-ptr.rs:114:1 | LL | const TRAIT_OBJ_INT_VTABLE: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, 4usize))) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .0: encountered dangling vtable pointer in wide pointer @@ -216,7 +227,7 @@ LL | const TRAIT_OBJ_INT_VTABLE: W<&dyn Trait> = unsafe { mem::transmute(W((&92u } error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:113:1 + --> $DIR/ub-wide-ptr.rs:116:1 | LL | const TRAIT_OBJ_UNALIGNED_VTABLE: &dyn Trait = unsafe { mem::transmute((&92u8, &[0u8; 128])) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered unaligned vtable pointer in wide pointer @@ -227,7 +238,7 @@ LL | const TRAIT_OBJ_UNALIGNED_VTABLE: &dyn Trait = unsafe { mem::transmute((&92 } error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:115:1 + --> $DIR/ub-wide-ptr.rs:118:1 | LL | const TRAIT_OBJ_BAD_DROP_FN_NULL: &dyn Trait = unsafe { mem::transmute((&92u8, &[0usize; 8])) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered invalid drop function pointer in vtable (not pointing to a function) @@ -238,7 +249,7 @@ LL | const TRAIT_OBJ_BAD_DROP_FN_NULL: &dyn Trait = unsafe { mem::transmute((&92 } error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:117:1 + --> $DIR/ub-wide-ptr.rs:120:1 | LL | const TRAIT_OBJ_BAD_DROP_FN_INT: &dyn Trait = unsafe { mem::transmute((&92u8, &[1usize; 8])) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered invalid drop function pointer in vtable (not pointing to a function) @@ -249,7 +260,7 @@ LL | const TRAIT_OBJ_BAD_DROP_FN_INT: &dyn Trait = unsafe { mem::transmute((&92u } error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:119:1 + --> $DIR/ub-wide-ptr.rs:122:1 | LL | const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &[&42u8; 8]))) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .0: encountered invalid drop function pointer in vtable (not pointing to a function) @@ -260,7 +271,7 @@ LL | const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: W<&dyn Trait> = unsafe { mem::trans } error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:123:1 + --> $DIR/ub-wide-ptr.rs:126:1 | LL | const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_, &bool>(&3u8) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at ..: encountered 0x03, but expected a boolean @@ -271,7 +282,7 @@ LL | const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_, } error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:127:1 + --> $DIR/ub-wide-ptr.rs:130:1 | LL | const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { mem::transmute((&92u8, 0usize)) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered dangling vtable pointer in wide pointer @@ -282,7 +293,7 @@ LL | const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { mem::transmute } error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:129:1 + --> $DIR/ub-wide-ptr.rs:132:1 | LL | const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transmute((&92u8, &3u64)) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered too small vtable @@ -293,17 +304,17 @@ LL | const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transm } error[E0080]: could not evaluate static initializer - --> $DIR/ub-wide-ptr.rs:135:5 + --> $DIR/ub-wide-ptr.rs:138:5 | LL | mem::transmute::<_, &dyn Trait>((&92u8, 0usize)) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: null pointer is not a valid pointer error[E0080]: could not evaluate static initializer - --> $DIR/ub-wide-ptr.rs:139:5 + --> $DIR/ub-wide-ptr.rs:142:5 | LL | mem::transmute::<_, &dyn Trait>((&92u8, &3u64)) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: allocN has size N, so pointer to 24 bytes starting at offset N is out-of-bounds -error: aborting due to 28 previous errors +error: aborting due to 29 previous errors For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/consts/const-eval/ub-wide-ptr.rs b/src/test/ui/consts/const-eval/ub-wide-ptr.rs index 0fb9f7960ce1a..ea48a095df95c 100644 --- a/src/test/ui/consts/const-eval/ub-wide-ptr.rs +++ b/src/test/ui/consts/const-eval/ub-wide-ptr.rs @@ -67,6 +67,9 @@ const SLICE_LENGTH_UNINIT: &[u8] = unsafe { // bad slice: length too big const SLICE_TOO_LONG: &[u8] = unsafe { mem::transmute((&42u8, 999usize)) }; //~^ ERROR it is undefined behavior to use this value +// bad slice: length computation overflows +const SLICE_TOO_LONG_OVERFLOW: &[u32] = unsafe { mem::transmute((&42u32, isize::MAX)) }; +//~^ ERROR it is undefined behavior to use this value // bad slice: length not an int const SLICE_LENGTH_PTR: &[u8] = unsafe { mem::transmute((&42u8, &3)) }; //~^ ERROR it is undefined behavior to use this value diff --git a/src/test/ui/consts/const-size_of_val-align_of_val.rs b/src/test/ui/consts/const-size_of_val-align_of_val.rs index 5c0d7d94d64f1..5a78313c48350 100644 --- a/src/test/ui/consts/const-size_of_val-align_of_val.rs +++ b/src/test/ui/consts/const-size_of_val-align_of_val.rs @@ -2,8 +2,9 @@ #![feature(const_size_of_val, const_align_of_val)] #![feature(const_size_of_val_raw, const_align_of_val_raw, layout_for_ptr)] +#![feature(const_slice_from_raw_parts)] -use std::mem; +use std::{mem, ptr}; struct Foo(u32); @@ -34,6 +35,8 @@ const ALIGN_OF_UGH: usize = mem::align_of_val(&UGH); const SIZE_OF_SLICE: usize = mem::size_of_val("foobar".as_bytes()); const SIZE_OF_DANGLING: usize = unsafe { mem::size_of_val_raw(0x100 as *const i32) }; +const SIZE_OF_BIG: usize = + unsafe { mem::size_of_val_raw(ptr::slice_from_raw_parts(0 as *const u8, isize::MAX as usize)) }; const ALIGN_OF_DANGLING: usize = unsafe { mem::align_of_val_raw(0x100 as *const i16) }; fn main() { @@ -46,6 +49,7 @@ fn main() { assert_eq!(ALIGN_OF_UGH, mem::align_of::()); assert_eq!(SIZE_OF_DANGLING, mem::size_of::()); + assert_eq!(SIZE_OF_BIG, isize::MAX as usize); assert_eq!(ALIGN_OF_DANGLING, mem::align_of::()); assert_eq!(SIZE_OF_SLICE, "foobar".len()); diff --git a/src/test/ui/did_you_mean/brackets-to-braces-single-element.rs b/src/test/ui/did_you_mean/brackets-to-braces-single-element.rs new file mode 100644 index 0000000000000..4d0109767fc0f --- /dev/null +++ b/src/test/ui/did_you_mean/brackets-to-braces-single-element.rs @@ -0,0 +1,10 @@ +const A: [&str; 1] = { "hello" }; +//~^ ERROR mismatched types + +const B: &[u32] = &{ 1 }; +//~^ ERROR mismatched types + +const C: &&[u32; 1] = &&{ 1 }; +//~^ ERROR mismatched types + +fn main() {} diff --git a/src/test/ui/did_you_mean/brackets-to-braces-single-element.stderr b/src/test/ui/did_you_mean/brackets-to-braces-single-element.stderr new file mode 100644 index 0000000000000..6ded03e45b55e --- /dev/null +++ b/src/test/ui/did_you_mean/brackets-to-braces-single-element.stderr @@ -0,0 +1,38 @@ +error[E0308]: mismatched types + --> $DIR/brackets-to-braces-single-element.rs:1:24 + | +LL | const A: [&str; 1] = { "hello" }; + | ^^^^^^^ expected array `[&'static str; 1]`, found `&str` + | +help: to create an array, use square brackets instead of curly braces + | +LL | const A: [&str; 1] = [ "hello" ]; + | ~ ~ + +error[E0308]: mismatched types + --> $DIR/brackets-to-braces-single-element.rs:4:19 + | +LL | const B: &[u32] = &{ 1 }; + | ^^^^^^ expected slice `[u32]`, found integer + | + = note: expected reference `&'static [u32]` + found reference `&{integer}` +help: to create an array, use square brackets instead of curly braces + | +LL | const B: &[u32] = &[ 1 ]; + | ~ ~ + +error[E0308]: mismatched types + --> $DIR/brackets-to-braces-single-element.rs:7:27 + | +LL | const C: &&[u32; 1] = &&{ 1 }; + | ^ expected array `[u32; 1]`, found integer + | +help: to create an array, use square brackets instead of curly braces + | +LL | const C: &&[u32; 1] = &&[ 1 ]; + | ~ ~ + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/did_you_mean/issue-87830-try-brackets-for-arrays.rs b/src/test/ui/did_you_mean/issue-87830-try-brackets-for-arrays.rs index 53dad85900a65..070ffaa1eff00 100644 --- a/src/test/ui/did_you_mean/issue-87830-try-brackets-for-arrays.rs +++ b/src/test/ui/did_you_mean/issue-87830-try-brackets-for-arrays.rs @@ -1,15 +1,16 @@ fn main() {} -const FOO: [u8; 3] = { //~ ERROR this code is interpreted as a block expression +const FOO: [u8; 3] = { + //~^ ERROR this is a block expression, not an array 1, 2, 3 }; const BAR: [&str; 3] = {"one", "two", "three"}; -//~^ ERROR this code is interpreted as a block expression +//~^ ERROR this is a block expression, not an array fn foo() { {1, 2, 3}; - //~^ ERROR this code is interpreted as a block expression + //~^ ERROR this is a block expression, not an array } fn bar() { diff --git a/src/test/ui/did_you_mean/issue-87830-try-brackets-for-arrays.stderr b/src/test/ui/did_you_mean/issue-87830-try-brackets-for-arrays.stderr index 9ab491f5c238f..d5ad1a72b8250 100644 --- a/src/test/ui/did_you_mean/issue-87830-try-brackets-for-arrays.stderr +++ b/src/test/ui/did_you_mean/issue-87830-try-brackets-for-arrays.stderr @@ -1,46 +1,45 @@ -error: this code is interpreted as a block expression, not an array +error: this is a block expression, not an array --> $DIR/issue-87830-try-brackets-for-arrays.rs:3:22 | LL | const FOO: [u8; 3] = { | ______________________^ +LL | | LL | | 1, 2, 3 LL | | }; | |_^ | - = note: to define an array, one would use square brackets instead of curly braces -help: try using [] instead of {} +help: to make an array, use square brackets instead of curly braces | LL ~ const FOO: [u8; 3] = [ +LL | LL | 1, 2, 3 LL ~ ]; | -error: this code is interpreted as a block expression, not an array - --> $DIR/issue-87830-try-brackets-for-arrays.rs:7:24 +error: this is a block expression, not an array + --> $DIR/issue-87830-try-brackets-for-arrays.rs:8:24 | LL | const BAR: [&str; 3] = {"one", "two", "three"}; | ^^^^^^^^^^^^^^^^^^^^^^^ | - = note: to define an array, one would use square brackets instead of curly braces -help: try using [] instead of {} +help: to make an array, use square brackets instead of curly braces | LL | const BAR: [&str; 3] = ["one", "two", "three"]; | ~ ~ -error: this code is interpreted as a block expression, not an array - --> $DIR/issue-87830-try-brackets-for-arrays.rs:11:5 +error: this is a block expression, not an array + --> $DIR/issue-87830-try-brackets-for-arrays.rs:12:5 | LL | {1, 2, 3}; | ^^^^^^^^^ | - = note: to define an array, one would use square brackets instead of curly braces -help: try using [] instead of {} +help: to make an array, use square brackets instead of curly braces | LL | [1, 2, 3]; | ~ ~ error: expected one of `.`, `;`, `?`, `}`, or an operator, found `,` - --> $DIR/issue-87830-try-brackets-for-arrays.rs:16:6 + --> $DIR/issue-87830-try-brackets-for-arrays.rs:17:6 | LL | 1, 2, 3 | ^ expected one of `.`, `;`, `?`, `}`, or an operator diff --git a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-62529-3.stderr b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-62529-3.stderr index b110734642177..066bf431a83d7 100644 --- a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-62529-3.stderr +++ b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-62529-3.stderr @@ -4,6 +4,8 @@ error[E0277]: expected a `Fn<(<_ as ATC<'a>>::Type,)>` closure, found `F` LL | call(f, ()); | ^^^^ expected an `Fn<(<_ as ATC<'a>>::Type,)>` closure, found `F` | + = note: expected a closure with arguments `((),)` + found a closure with arguments `(<_ as ATC<'a>>::Type,)` note: required by a bound in `call` --> $DIR/issue-62529-3.rs:9:36 | diff --git a/src/test/ui/issues/issue-59494.stderr b/src/test/ui/issues/issue-59494.stderr index a9284535e4dc4..8b542bb69de2e 100644 --- a/src/test/ui/issues/issue-59494.stderr +++ b/src/test/ui/issues/issue-59494.stderr @@ -7,6 +7,8 @@ LL | let t8 = t8n(t7, t7p(f, g)); | required by a bound introduced by this call | = help: the trait `Fn<(_,)>` is not implemented for `impl Fn(((_, _), _))` + = note: expected a closure with arguments `(((_, _), _),)` + found a closure with arguments `(_,)` note: required by a bound in `t8n` --> $DIR/issue-59494.rs:5:45 | diff --git a/src/test/ui/trait-bounds/mismatch-fn-trait.rs b/src/test/ui/trait-bounds/mismatch-fn-trait.rs new file mode 100644 index 0000000000000..0ed64043a9a56 --- /dev/null +++ b/src/test/ui/trait-bounds/mismatch-fn-trait.rs @@ -0,0 +1,28 @@ +fn take(_f: impl FnMut(i32)) {} + +fn test1(f: impl FnMut(u32)) { + take(f) + //~^ ERROR [E0277] +} + +fn test2(f: impl FnMut(i32, i32)) { + take(f) + //~^ ERROR [E0277] +} + +fn test3(f: impl FnMut()) { + take(f) + //~^ ERROR [E0277] +} + +fn test4(f: impl FnOnce(i32)) { + take(f) + //~^ ERROR [E0277] +} + +fn test5(f: impl FnOnce(u32)) { + take(f) + //~^ ERROR [E0277] +} + +fn main() {} diff --git a/src/test/ui/trait-bounds/mismatch-fn-trait.stderr b/src/test/ui/trait-bounds/mismatch-fn-trait.stderr new file mode 100644 index 0000000000000..961e6d88fbef4 --- /dev/null +++ b/src/test/ui/trait-bounds/mismatch-fn-trait.stderr @@ -0,0 +1,81 @@ +error[E0277]: expected a `FnMut<(i32,)>` closure, found `impl FnMut(u32)` + --> $DIR/mismatch-fn-trait.rs:4:10 + | +LL | take(f) + | ---- ^ expected an `FnMut<(i32,)>` closure, found `impl FnMut(u32)` + | | + | required by a bound introduced by this call + | + = note: expected a closure with arguments `(u32,)` + found a closure with arguments `(i32,)` +note: required by a bound in `take` + --> $DIR/mismatch-fn-trait.rs:1:18 + | +LL | fn take(_f: impl FnMut(i32)) {} + | ^^^^^^^^^^ required by this bound in `take` + +error[E0277]: expected a `FnMut<(i32,)>` closure, found `impl FnMut(i32, i32)` + --> $DIR/mismatch-fn-trait.rs:9:10 + | +LL | take(f) + | ---- ^ expected an `FnMut<(i32,)>` closure, found `impl FnMut(i32, i32)` + | | + | required by a bound introduced by this call + | + = note: expected a closure taking 2 arguments, but one taking 1 argument was given +note: required by a bound in `take` + --> $DIR/mismatch-fn-trait.rs:1:18 + | +LL | fn take(_f: impl FnMut(i32)) {} + | ^^^^^^^^^^ required by this bound in `take` + +error[E0277]: expected a `FnMut<(i32,)>` closure, found `impl FnMut()` + --> $DIR/mismatch-fn-trait.rs:14:10 + | +LL | take(f) + | ---- ^ expected an `FnMut<(i32,)>` closure, found `impl FnMut()` + | | + | required by a bound introduced by this call + | + = note: expected a closure taking 0 arguments, but one taking 1 argument was given +note: required by a bound in `take` + --> $DIR/mismatch-fn-trait.rs:1:18 + | +LL | fn take(_f: impl FnMut(i32)) {} + | ^^^^^^^^^^ required by this bound in `take` + +error[E0277]: expected a `FnMut<(i32,)>` closure, found `impl FnOnce(i32)` + --> $DIR/mismatch-fn-trait.rs:19:10 + | +LL | take(f) + | ---- ^ expected an `FnMut<(i32,)>` closure, found `impl FnOnce(i32)` + | | + | required by a bound introduced by this call + | + = note: `impl FnOnce(i32)` implements `FnOnce`, but it must implement `FnMut`, which is more general +note: required by a bound in `take` + --> $DIR/mismatch-fn-trait.rs:1:18 + | +LL | fn take(_f: impl FnMut(i32)) {} + | ^^^^^^^^^^ required by this bound in `take` + +error[E0277]: expected a `FnMut<(i32,)>` closure, found `impl FnOnce(u32)` + --> $DIR/mismatch-fn-trait.rs:24:10 + | +LL | take(f) + | ---- ^ expected an `FnMut<(i32,)>` closure, found `impl FnOnce(u32)` + | | + | required by a bound introduced by this call + | + = note: `impl FnOnce(u32)` implements `FnOnce`, but it must implement `FnMut`, which is more general + = note: expected a closure with arguments `(u32,)` + found a closure with arguments `(i32,)` +note: required by a bound in `take` + --> $DIR/mismatch-fn-trait.rs:1:18 + | +LL | fn take(_f: impl FnMut(i32)) {} + | ^^^^^^^^^^ required by this bound in `take` + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/unboxed-closures/unboxed-closures-fnmut-as-fn.stderr b/src/test/ui/unboxed-closures/unboxed-closures-fnmut-as-fn.stderr index f379d73eecff7..0ea1c1dcd5bde 100644 --- a/src/test/ui/unboxed-closures/unboxed-closures-fnmut-as-fn.stderr +++ b/src/test/ui/unboxed-closures/unboxed-closures-fnmut-as-fn.stderr @@ -7,6 +7,7 @@ LL | let x = call_it(&S, 22); | required by a bound introduced by this call | = help: the trait `Fn<(isize,)>` is not implemented for `S` + = note: `S` implements `FnMut`, but it must implement `Fn`, which is more general note: required by a bound in `call_it` --> $DIR/unboxed-closures-fnmut-as-fn.rs:22:14 |