| author | bors <bors@rust-lang.org> 2024-07-23 12:10:45 UTC |
| committer | bors <bors@rust-lang.org> 2024-07-23 12:10:45 UTC |
| log | d53dc752d2bc0a9e7f7e2e5f82aff03a6d222614 |
| tree | 3cb5fe0c2b203a1ee5840d4c4679961ac410dee3 |
| parent | d111ccdb6186b368ead16c01f43c645a6e5f4a67 |
| parent | f8373adcda33b3a8b5e836e28b2162b2bfe31ee8 |
Rollup of 6 pull requests
Successful merges:
- #125834 (treat `&raw (const|mut) UNSAFE_STATIC` implied deref as safe)
- #127962 (Cleanup compiletest dylib name calculation)
- #128049 (Reword E0626 to mention static coroutine, add structured suggestion for adding `static`)
- #128067 (Get rid of `can_eq_shallow`)
- #128076 (Get rid of `InferCtxtExt` from `error_reporting::traits`)
- #128089 (std: Unsafe-wrap actually-universal platform code)
r? `@ghost`
`@rustbot` modify labels: rollup33 files changed, 567 insertions(+), 366 deletions(-)
compiler/rustc_borrowck/src/borrowck_errors.rs+27-3| ... | ... | @@ -1,7 +1,9 @@ |
| 1 | 1 | #![allow(rustc::diagnostic_outside_of_impl)] |
| 2 | 2 | #![allow(rustc::untranslatable_diagnostic)] |
| 3 | 3 | |
| 4 | use rustc_errors::Applicability; | |
| 4 | 5 | use rustc_errors::{codes::*, struct_span_code_err, Diag, DiagCtxtHandle}; |
| 6 | use rustc_hir as hir; | |
| 5 | 7 | use rustc_middle::span_bug; |
| 6 | 8 | use rustc_middle::ty::{self, Ty, TyCtxt}; |
| 7 | 9 | use rustc_span::Span; |
| ... | ... | @@ -382,13 +384,35 @@ impl<'infcx, 'tcx> crate::MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> { |
| 382 | 384 | yield_span: Span, |
| 383 | 385 | ) -> Diag<'infcx> { |
| 384 | 386 | let coroutine_kind = self.body.coroutine.as_ref().unwrap().coroutine_kind; |
| 385 | struct_span_code_err!( | |
| 387 | let mut diag = struct_span_code_err!( | |
| 386 | 388 | self.dcx(), |
| 387 | 389 | span, |
| 388 | 390 | E0626, |
| 389 | 391 | "borrow may still be in use when {coroutine_kind:#} yields", |
| 390 | ) | |
| 391 | .with_span_label(yield_span, "possible yield occurs here") | |
| 392 | ); | |
| 393 | diag.span_label( | |
| 394 | self.infcx.tcx.def_span(self.body.source.def_id()), | |
| 395 | format!("within this {coroutine_kind:#}"), | |
| 396 | ); | |
| 397 | diag.span_label(yield_span, "possible yield occurs here"); | |
| 398 | if matches!(coroutine_kind, hir::CoroutineKind::Coroutine(_)) { | |
| 399 | let hir::Closure { capture_clause, fn_decl_span, .. } = self | |
| 400 | .infcx | |
| 401 | .tcx | |
| 402 | .hir_node_by_def_id(self.body.source.def_id().expect_local()) | |
| 403 | .expect_closure(); | |
| 404 | let span = match capture_clause { | |
| 405 | rustc_hir::CaptureBy::Value { move_kw } => move_kw.shrink_to_lo(), | |
| 406 | rustc_hir::CaptureBy::Ref => fn_decl_span.shrink_to_lo(), | |
| 407 | }; | |
| 408 | diag.span_suggestion_verbose( | |
| 409 | span, | |
| 410 | "add `static` to mark this coroutine as unmovable", | |
| 411 | "static ", | |
| 412 | Applicability::MaybeIncorrect, | |
| 413 | ); | |
| 414 | } | |
| 415 | diag | |
| 392 | 416 | } |
| 393 | 417 | |
| 394 | 418 | pub(crate) fn cannot_borrow_across_destructor(&self, borrow_span: Span) -> Diag<'infcx> { |
compiler/rustc_error_codes/src/error_codes/E0626.md+24-8| ... | ... | @@ -1,4 +1,4 @@ |
| 1 | This error occurs because a borrow in a coroutine persists across a | |
| 1 | This error occurs because a borrow in a movable coroutine persists across a | |
| 2 | 2 | yield point. |
| 3 | 3 | |
| 4 | 4 | Erroneous code example: |
| ... | ... | @@ -15,19 +15,35 @@ let mut b = #[coroutine] || { |
| 15 | 15 | Pin::new(&mut b).resume(()); |
| 16 | 16 | ``` |
| 17 | 17 | |
| 18 | At present, it is not permitted to have a yield that occurs while a | |
| 19 | borrow is still in scope. To resolve this error, the borrow must | |
| 20 | either be "contained" to a smaller scope that does not overlap the | |
| 21 | yield or else eliminated in another way. So, for example, we might | |
| 22 | resolve the previous example by removing the borrow and just storing | |
| 23 | the integer by value: | |
| 18 | Coroutines may be either unmarked, or marked with `static`. If it is unmarked, | |
| 19 | then the coroutine is considered "movable". At present, it is not permitted to | |
| 20 | have a yield in a movable coroutine that occurs while a borrow is still in | |
| 21 | scope. To resolve this error, the coroutine may be marked `static`: | |
| 22 | ||
| 23 | ``` | |
| 24 | # #![feature(coroutines, coroutine_trait, stmt_expr_attributes)] | |
| 25 | # use std::ops::Coroutine; | |
| 26 | # use std::pin::Pin; | |
| 27 | let mut b = #[coroutine] static || { // <-- note the static keyword | |
| 28 | let a = &String::from("hello, world"); | |
| 29 | yield (); | |
| 30 | println!("{}", a); | |
| 31 | }; | |
| 32 | let mut b = std::pin::pin!(b); | |
| 33 | b.as_mut().resume(()); | |
| 34 | ``` | |
| 35 | ||
| 36 | If the coroutine must remain movable, for example to be used as `Unpin` | |
| 37 | without pinning it on the stack or in an allocation, we can alternatively | |
| 38 | resolve the previous example by removing the borrow and just storing the | |
| 39 | type by value: | |
| 24 | 40 | |
| 25 | 41 | ``` |
| 26 | 42 | # #![feature(coroutines, coroutine_trait, stmt_expr_attributes)] |
| 27 | 43 | # use std::ops::Coroutine; |
| 28 | 44 | # use std::pin::Pin; |
| 29 | 45 | let mut b = #[coroutine] || { |
| 30 | let a = 3; | |
| 46 | let a = String::from("hello, world"); | |
| 31 | 47 | yield (); |
| 32 | 48 | println!("{}", a); |
| 33 | 49 | }; |
compiler/rustc_hir_typeck/src/closure.rs+2-2| ... | ... | @@ -18,7 +18,6 @@ use rustc_span::def_id::LocalDefId; |
| 18 | 18 | use rustc_span::Span; |
| 19 | 19 | use rustc_target::spec::abi::Abi; |
| 20 | 20 | use rustc_trait_selection::error_reporting::traits::ArgKind; |
| 21 | use rustc_trait_selection::error_reporting::traits::InferCtxtExt as _; | |
| 22 | 21 | use rustc_trait_selection::traits; |
| 23 | 22 | use rustc_type_ir::ClosureKind; |
| 24 | 23 | use std::iter; |
| ... | ... | @@ -734,13 +733,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { |
| 734 | 733 | .map(|ty| ArgKind::from_expected_ty(*ty, None)) |
| 735 | 734 | .collect(); |
| 736 | 735 | let (closure_span, closure_arg_span, found_args) = |
| 737 | match self.get_fn_like_arguments(expr_map_node) { | |
| 736 | match self.err_ctxt().get_fn_like_arguments(expr_map_node) { | |
| 738 | 737 | Some((sp, arg_sp, args)) => (Some(sp), arg_sp, args), |
| 739 | 738 | None => (None, None, Vec::new()), |
| 740 | 739 | }; |
| 741 | 740 | let expected_span = |
| 742 | 741 | expected_sig.cause_span.unwrap_or_else(|| self.tcx.def_span(expr_def_id)); |
| 743 | 742 | let guar = self |
| 743 | .err_ctxt() | |
| 744 | 744 | .report_arg_count_mismatch( |
| 745 | 745 | expected_span, |
| 746 | 746 | closure_span, |
compiler/rustc_infer/src/infer/mod.rs-12| ... | ... | @@ -755,18 +755,6 @@ impl<'tcx> InferCtxt<'tcx> { |
| 755 | 755 | .collect() |
| 756 | 756 | } |
| 757 | 757 | |
| 758 | // FIXME(-Znext-solver): Get rid of this method, it's never correct. Either that, | |
| 759 | // or we need to process the obligations. | |
| 760 | pub fn can_eq_shallow<T>(&self, param_env: ty::ParamEnv<'tcx>, a: T, b: T) -> bool | |
| 761 | where | |
| 762 | T: at::ToTrace<'tcx>, | |
| 763 | { | |
| 764 | let origin = &ObligationCause::dummy(); | |
| 765 | // We're only answering whether the types could be the same, and with | |
| 766 | // opaque types, "they can be the same", via registering a hidden type. | |
| 767 | self.probe(|_| self.at(origin, param_env).eq(DefineOpaqueTypes::Yes, a, b).is_ok()) | |
| 768 | } | |
| 769 | ||
| 770 | 758 | #[instrument(skip(self), level = "debug")] |
| 771 | 759 | pub fn sub_regions( |
| 772 | 760 | &self, |
compiler/rustc_mir_build/src/check_unsafety.rs+18| ... | ... | @@ -466,6 +466,24 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { |
| 466 | 466 | } |
| 467 | 467 | } |
| 468 | 468 | } |
| 469 | ExprKind::AddressOf { arg, .. } => { | |
| 470 | if let ExprKind::Scope { value: arg, .. } = self.thir[arg].kind | |
| 471 | // THIR desugars UNSAFE_STATIC into *UNSAFE_STATIC_REF, where | |
| 472 | // UNSAFE_STATIC_REF holds the addr of the UNSAFE_STATIC, so: take two steps | |
| 473 | && let ExprKind::Deref { arg } = self.thir[arg].kind | |
| 474 | // FIXME(workingjubiee): we lack a clear reason to reject ThreadLocalRef here, | |
| 475 | // but we also have no conclusive reason to allow it either! | |
| 476 | && let ExprKind::StaticRef { .. } = self.thir[arg].kind | |
| 477 | { | |
| 478 | // A raw ref to a place expr, even an "unsafe static", is okay! | |
| 479 | // We short-circuit to not recursively traverse this expression. | |
| 480 | return; | |
| 481 | // note: const_mut_refs enables this code, and it currently remains unsafe: | |
| 482 | // static mut BYTE: u8 = 0; | |
| 483 | // static mut BYTE_PTR: *mut u8 = unsafe { addr_of_mut!(BYTE) }; | |
| 484 | // static mut DEREF_BYTE_PTR: *mut u8 = unsafe { addr_of_mut!(*BYTE_PTR) }; | |
| 485 | } | |
| 486 | } | |
| 469 | 487 | ExprKind::Deref { arg } => { |
| 470 | 488 | if let ExprKind::StaticRef { def_id, .. } | ExprKind::ThreadLocalRef(def_id) = |
| 471 | 489 | self.thir[arg].kind |
compiler/rustc_mir_build/src/thir/cx/expr.rs+4-2| ... | ... | @@ -939,9 +939,11 @@ impl<'tcx> Cx<'tcx> { |
| 939 | 939 | } |
| 940 | 940 | } |
| 941 | 941 | |
| 942 | // We encode uses of statics as a `*&STATIC` where the `&STATIC` part is | |
| 943 | // a constant reference (or constant raw pointer for `static mut`) in MIR | |
| 942 | // A source Rust `path::to::STATIC` is a place expr like *&ident is. | |
| 943 | // In THIR, we make them exactly equivalent by inserting the implied *& or *&raw, | |
| 944 | // but distinguish between &STATIC and &THREAD_LOCAL as they have different semantics | |
| 944 | 945 | Res::Def(DefKind::Static { .. }, id) => { |
| 946 | // this is &raw for extern static or static mut, and & for other statics | |
| 945 | 947 | let ty = self.tcx.static_ptr_ty(id); |
| 946 | 948 | let temp_lifetime = self |
| 947 | 949 | .rvalue_scopes |
compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs+3-2| ... | ... | @@ -12,6 +12,7 @@ use rustc_middle::{ |
| 12 | 12 | use rustc_span::{def_id::DefId, sym, BytePos, Span, Symbol}; |
| 13 | 13 | |
| 14 | 14 | use crate::error_reporting::TypeErrCtxt; |
| 15 | use crate::infer::InferCtxtExt; | |
| 15 | 16 | |
| 16 | 17 | impl<'tcx> TypeErrCtxt<'_, 'tcx> { |
| 17 | 18 | pub fn note_and_explain_type_err( |
| ... | ... | @@ -821,7 +822,7 @@ fn foo(&self) -> Self::T { String::new() } |
| 821 | 822 | tcx.defaultness(item.id.owner_id) |
| 822 | 823 | { |
| 823 | 824 | let assoc_ty = tcx.type_of(item.id.owner_id).instantiate_identity(); |
| 824 | if self.infcx.can_eq_shallow(param_env, assoc_ty, found) { | |
| 825 | if self.infcx.can_eq(param_env, assoc_ty, found) { | |
| 825 | 826 | diag.span_label( |
| 826 | 827 | item.span, |
| 827 | 828 | "associated type defaults can't be assumed inside the \ |
| ... | ... | @@ -844,7 +845,7 @@ fn foo(&self) -> Self::T { String::new() } |
| 844 | 845 | let assoc_ty = tcx.type_of(item.id.owner_id).instantiate_identity(); |
| 845 | 846 | if let hir::Defaultness::Default { has_value: true } = |
| 846 | 847 | tcx.defaultness(item.id.owner_id) |
| 847 | && self.infcx.can_eq_shallow(param_env, assoc_ty, found) | |
| 848 | && self.infcx.can_eq(param_env, assoc_ty, found) | |
| 848 | 849 | { |
| 849 | 850 | diag.span_label( |
| 850 | 851 | item.span, |
compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs+233-2| ... | ... | @@ -1,7 +1,6 @@ |
| 1 | 1 | use super::on_unimplemented::{AppendConstMessage, OnUnimplementedNote}; |
| 2 | 2 | use super::suggestions::get_explanation_based_on_obligation; |
| 3 | 3 | use crate::error_reporting::infer::TyCategory; |
| 4 | use crate::error_reporting::traits::infer_ctxt_ext::InferCtxtExt; | |
| 5 | 4 | use crate::error_reporting::traits::report_object_safety_error; |
| 6 | 5 | use crate::error_reporting::TypeErrCtxt; |
| 7 | 6 | use crate::errors::{ |
| ... | ... | @@ -2602,7 +2601,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { |
| 2602 | 2601 | }) |
| 2603 | 2602 | .unwrap_or((found_span, None, found)); |
| 2604 | 2603 | |
| 2605 | self.infcx.report_arg_count_mismatch( | |
| 2604 | self.report_arg_count_mismatch( | |
| 2606 | 2605 | span, |
| 2607 | 2606 | closure_span, |
| 2608 | 2607 | expected, |
| ... | ... | @@ -2614,6 +2613,238 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { |
| 2614 | 2613 | ) |
| 2615 | 2614 | } |
| 2616 | 2615 | |
| 2616 | /// Given some node representing a fn-like thing in the HIR map, | |
| 2617 | /// returns a span and `ArgKind` information that describes the | |
| 2618 | /// arguments it expects. This can be supplied to | |
| 2619 | /// `report_arg_count_mismatch`. | |
| 2620 | pub fn get_fn_like_arguments( | |
| 2621 | &self, | |
| 2622 | node: Node<'_>, | |
| 2623 | ) -> Option<(Span, Option<Span>, Vec<ArgKind>)> { | |
| 2624 | let sm = self.tcx.sess.source_map(); | |
| 2625 | let hir = self.tcx.hir(); | |
| 2626 | Some(match node { | |
| 2627 | Node::Expr(&hir::Expr { | |
| 2628 | kind: hir::ExprKind::Closure(&hir::Closure { body, fn_decl_span, fn_arg_span, .. }), | |
| 2629 | .. | |
| 2630 | }) => ( | |
| 2631 | fn_decl_span, | |
| 2632 | fn_arg_span, | |
| 2633 | hir.body(body) | |
| 2634 | .params | |
| 2635 | .iter() | |
| 2636 | .map(|arg| { | |
| 2637 | if let hir::Pat { kind: hir::PatKind::Tuple(args, _), span, .. } = *arg.pat | |
| 2638 | { | |
| 2639 | Some(ArgKind::Tuple( | |
| 2640 | Some(span), | |
| 2641 | args.iter() | |
| 2642 | .map(|pat| { | |
| 2643 | sm.span_to_snippet(pat.span) | |
| 2644 | .ok() | |
| 2645 | .map(|snippet| (snippet, "_".to_owned())) | |
| 2646 | }) | |
| 2647 | .collect::<Option<Vec<_>>>()?, | |
| 2648 | )) | |
| 2649 | } else { | |
| 2650 | let name = sm.span_to_snippet(arg.pat.span).ok()?; | |
| 2651 | Some(ArgKind::Arg(name, "_".to_owned())) | |
| 2652 | } | |
| 2653 | }) | |
| 2654 | .collect::<Option<Vec<ArgKind>>>()?, | |
| 2655 | ), | |
| 2656 | Node::Item(&hir::Item { kind: hir::ItemKind::Fn(ref sig, ..), .. }) | |
| 2657 | | Node::ImplItem(&hir::ImplItem { kind: hir::ImplItemKind::Fn(ref sig, _), .. }) | |
| 2658 | | Node::TraitItem(&hir::TraitItem { | |
| 2659 | kind: hir::TraitItemKind::Fn(ref sig, _), .. | |
| 2660 | }) => ( | |
| 2661 | sig.span, | |
| 2662 | None, | |
| 2663 | sig.decl | |
| 2664 | .inputs | |
| 2665 | .iter() | |
| 2666 | .map(|arg| match arg.kind { | |
| 2667 | hir::TyKind::Tup(tys) => ArgKind::Tuple( | |
| 2668 | Some(arg.span), | |
| 2669 | vec![("_".to_owned(), "_".to_owned()); tys.len()], | |
| 2670 | ), | |
| 2671 | _ => ArgKind::empty(), | |
| 2672 | }) | |
| 2673 | .collect::<Vec<ArgKind>>(), | |
| 2674 | ), | |
| 2675 | Node::Ctor(variant_data) => { | |
| 2676 | let span = variant_data.ctor_hir_id().map_or(DUMMY_SP, |id| hir.span(id)); | |
| 2677 | (span, None, vec![ArgKind::empty(); variant_data.fields().len()]) | |
| 2678 | } | |
| 2679 | _ => panic!("non-FnLike node found: {node:?}"), | |
| 2680 | }) | |
| 2681 | } | |
| 2682 | ||
| 2683 | /// Reports an error when the number of arguments needed by a | |
| 2684 | /// trait match doesn't match the number that the expression | |
| 2685 | /// provides. | |
| 2686 | pub fn report_arg_count_mismatch( | |
| 2687 | &self, | |
| 2688 | span: Span, | |
| 2689 | found_span: Option<Span>, | |
| 2690 | expected_args: Vec<ArgKind>, | |
| 2691 | found_args: Vec<ArgKind>, | |
| 2692 | is_closure: bool, | |
| 2693 | closure_arg_span: Option<Span>, | |
| 2694 | ) -> Diag<'a> { | |
| 2695 | let kind = if is_closure { "closure" } else { "function" }; | |
| 2696 | ||
| 2697 | let args_str = |arguments: &[ArgKind], other: &[ArgKind]| { | |
| 2698 | let arg_length = arguments.len(); | |
| 2699 | let distinct = matches!(other, &[ArgKind::Tuple(..)]); | |
| 2700 | match (arg_length, arguments.get(0)) { | |
| 2701 | (1, Some(ArgKind::Tuple(_, fields))) => { | |
| 2702 | format!("a single {}-tuple as argument", fields.len()) | |
| 2703 | } | |
| 2704 | _ => format!( | |
| 2705 | "{} {}argument{}", | |
| 2706 | arg_length, | |
| 2707 | if distinct && arg_length > 1 { "distinct " } else { "" }, | |
| 2708 | pluralize!(arg_length) | |
| 2709 | ), | |
| 2710 | } | |
| 2711 | }; | |
| 2712 | ||
| 2713 | let expected_str = args_str(&expected_args, &found_args); | |
| 2714 | let found_str = args_str(&found_args, &expected_args); | |
| 2715 | ||
| 2716 | let mut err = struct_span_code_err!( | |
| 2717 | self.dcx(), | |
| 2718 | span, | |
| 2719 | E0593, | |
| 2720 | "{} is expected to take {}, but it takes {}", | |
| 2721 | kind, | |
| 2722 | expected_str, | |
| 2723 | found_str, | |
| 2724 | ); | |
| 2725 | ||
| 2726 | err.span_label(span, format!("expected {kind} that takes {expected_str}")); | |
| 2727 | ||
| 2728 | if let Some(found_span) = found_span { | |
| 2729 | err.span_label(found_span, format!("takes {found_str}")); | |
| 2730 | ||
| 2731 | // Suggest to take and ignore the arguments with expected_args_length `_`s if | |
| 2732 | // found arguments is empty (assume the user just wants to ignore args in this case). | |
| 2733 | // For example, if `expected_args_length` is 2, suggest `|_, _|`. | |
| 2734 | if found_args.is_empty() && is_closure { | |
| 2735 | let underscores = vec!["_"; expected_args.len()].join(", "); | |
| 2736 | err.span_suggestion_verbose( | |
| 2737 | closure_arg_span.unwrap_or(found_span), | |
| 2738 | format!( | |
| 2739 | "consider changing the closure to take and ignore the expected argument{}", | |
| 2740 | pluralize!(expected_args.len()) | |
| 2741 | ), | |
| 2742 | format!("|{underscores}|"), | |
| 2743 | Applicability::MachineApplicable, | |
| 2744 | ); | |
| 2745 | } | |
| 2746 | ||
| 2747 | if let &[ArgKind::Tuple(_, ref fields)] = &found_args[..] { | |
| 2748 | if fields.len() == expected_args.len() { | |
| 2749 | let sugg = fields | |
| 2750 | .iter() | |
| 2751 | .map(|(name, _)| name.to_owned()) | |
| 2752 | .collect::<Vec<String>>() | |
| 2753 | .join(", "); | |
| 2754 | err.span_suggestion_verbose( | |
| 2755 | found_span, | |
| 2756 | "change the closure to take multiple arguments instead of a single tuple", | |
| 2757 | format!("|{sugg}|"), | |
| 2758 | Applicability::MachineApplicable, | |
| 2759 | ); | |
| 2760 | } | |
| 2761 | } | |
| 2762 | if let &[ArgKind::Tuple(_, ref fields)] = &expected_args[..] | |
| 2763 | && fields.len() == found_args.len() | |
| 2764 | && is_closure | |
| 2765 | { | |
| 2766 | let sugg = format!( | |
| 2767 | "|({}){}|", | |
| 2768 | found_args | |
| 2769 | .iter() | |
| 2770 | .map(|arg| match arg { | |
| 2771 | ArgKind::Arg(name, _) => name.to_owned(), | |
| 2772 | _ => "_".to_owned(), | |
| 2773 | }) | |
| 2774 | .collect::<Vec<String>>() | |
| 2775 | .join(", "), | |
| 2776 | // add type annotations if available | |
| 2777 | if found_args.iter().any(|arg| match arg { | |
| 2778 | ArgKind::Arg(_, ty) => ty != "_", | |
| 2779 | _ => false, | |
| 2780 | }) { | |
| 2781 | format!( | |
| 2782 | ": ({})", | |
| 2783 | fields | |
| 2784 | .iter() | |
| 2785 | .map(|(_, ty)| ty.to_owned()) | |
| 2786 | .collect::<Vec<String>>() | |
| 2787 | .join(", ") | |
| 2788 | ) | |
| 2789 | } else { | |
| 2790 | String::new() | |
| 2791 | }, | |
| 2792 | ); | |
| 2793 | err.span_suggestion_verbose( | |
| 2794 | found_span, | |
| 2795 | "change the closure to accept a tuple instead of individual arguments", | |
| 2796 | sugg, | |
| 2797 | Applicability::MachineApplicable, | |
| 2798 | ); | |
| 2799 | } | |
| 2800 | } | |
| 2801 | ||
| 2802 | err | |
| 2803 | } | |
| 2804 | ||
| 2805 | /// Checks if the type implements one of `Fn`, `FnMut`, or `FnOnce` | |
| 2806 | /// in that order, and returns the generic type corresponding to the | |
| 2807 | /// argument of that trait (corresponding to the closure arguments). | |
| 2808 | pub fn type_implements_fn_trait( | |
| 2809 | &self, | |
| 2810 | param_env: ty::ParamEnv<'tcx>, | |
| 2811 | ty: ty::Binder<'tcx, Ty<'tcx>>, | |
| 2812 | polarity: ty::PredicatePolarity, | |
| 2813 | ) -> Result<(ty::ClosureKind, ty::Binder<'tcx, Ty<'tcx>>), ()> { | |
| 2814 | self.commit_if_ok(|_| { | |
| 2815 | for trait_def_id in [ | |
| 2816 | self.tcx.lang_items().fn_trait(), | |
| 2817 | self.tcx.lang_items().fn_mut_trait(), | |
| 2818 | self.tcx.lang_items().fn_once_trait(), | |
| 2819 | ] { | |
| 2820 | let Some(trait_def_id) = trait_def_id else { continue }; | |
| 2821 | // Make a fresh inference variable so we can determine what the generic parameters | |
| 2822 | // of the trait are. | |
| 2823 | let var = self.next_ty_var(DUMMY_SP); | |
| 2824 | // FIXME(effects) | |
| 2825 | let trait_ref = ty::TraitRef::new(self.tcx, trait_def_id, [ty.skip_binder(), var]); | |
| 2826 | let obligation = Obligation::new( | |
| 2827 | self.tcx, | |
| 2828 | ObligationCause::dummy(), | |
| 2829 | param_env, | |
| 2830 | ty.rebind(ty::TraitPredicate { trait_ref, polarity }), | |
| 2831 | ); | |
| 2832 | let ocx = ObligationCtxt::new(self); | |
| 2833 | ocx.register_obligation(obligation); | |
| 2834 | if ocx.select_all_or_error().is_empty() { | |
| 2835 | return Ok(( | |
| 2836 | self.tcx | |
| 2837 | .fn_trait_kind_from_def_id(trait_def_id) | |
| 2838 | .expect("expected to map DefId to ClosureKind"), | |
| 2839 | ty.rebind(self.resolve_vars_if_possible(var)), | |
| 2840 | )); | |
| 2841 | } | |
| 2842 | } | |
| 2843 | ||
| 2844 | Err(()) | |
| 2845 | }) | |
| 2846 | } | |
| 2847 | ||
| 2617 | 2848 | fn report_not_const_evaluatable_error( |
| 2618 | 2849 | &self, |
| 2619 | 2850 | obligation: &PredicateObligation<'tcx>, |
compiler/rustc_trait_selection/src/error_reporting/traits/infer_ctxt_ext.rs deleted-244| ... | ... | @@ -1,244 +0,0 @@ |
| 1 | // FIXME(error_reporting): This should be made into private methods on `TypeErrCtxt`. | |
| 2 | ||
| 3 | use crate::infer::InferCtxt; | |
| 4 | use crate::traits::{Obligation, ObligationCause, ObligationCtxt}; | |
| 5 | use rustc_errors::{codes::*, pluralize, struct_span_code_err, Applicability, Diag}; | |
| 6 | use rustc_hir as hir; | |
| 7 | use rustc_hir::Node; | |
| 8 | use rustc_macros::extension; | |
| 9 | use rustc_middle::ty::{self, Ty}; | |
| 10 | use rustc_span::{Span, DUMMY_SP}; | |
| 11 | ||
| 12 | use super::ArgKind; | |
| 13 | ||
| 14 | #[extension(pub trait InferCtxtExt<'tcx>)] | |
| 15 | impl<'tcx> InferCtxt<'tcx> { | |
| 16 | /// Given some node representing a fn-like thing in the HIR map, | |
| 17 | /// returns a span and `ArgKind` information that describes the | |
| 18 | /// arguments it expects. This can be supplied to | |
| 19 | /// `report_arg_count_mismatch`. | |
| 20 | fn get_fn_like_arguments(&self, node: Node<'_>) -> Option<(Span, Option<Span>, Vec<ArgKind>)> { | |
| 21 | let sm = self.tcx.sess.source_map(); | |
| 22 | let hir = self.tcx.hir(); | |
| 23 | Some(match node { | |
| 24 | Node::Expr(&hir::Expr { | |
| 25 | kind: hir::ExprKind::Closure(&hir::Closure { body, fn_decl_span, fn_arg_span, .. }), | |
| 26 | .. | |
| 27 | }) => ( | |
| 28 | fn_decl_span, | |
| 29 | fn_arg_span, | |
| 30 | hir.body(body) | |
| 31 | .params | |
| 32 | .iter() | |
| 33 | .map(|arg| { | |
| 34 | if let hir::Pat { kind: hir::PatKind::Tuple(args, _), span, .. } = *arg.pat | |
| 35 | { | |
| 36 | Some(ArgKind::Tuple( | |
| 37 | Some(span), | |
| 38 | args.iter() | |
| 39 | .map(|pat| { | |
| 40 | sm.span_to_snippet(pat.span) | |
| 41 | .ok() | |
| 42 | .map(|snippet| (snippet, "_".to_owned())) | |
| 43 | }) | |
| 44 | .collect::<Option<Vec<_>>>()?, | |
| 45 | )) | |
| 46 | } else { | |
| 47 | let name = sm.span_to_snippet(arg.pat.span).ok()?; | |
| 48 | Some(ArgKind::Arg(name, "_".to_owned())) | |
| 49 | } | |
| 50 | }) | |
| 51 | .collect::<Option<Vec<ArgKind>>>()?, | |
| 52 | ), | |
| 53 | Node::Item(&hir::Item { kind: hir::ItemKind::Fn(ref sig, ..), .. }) | |
| 54 | | Node::ImplItem(&hir::ImplItem { kind: hir::ImplItemKind::Fn(ref sig, _), .. }) | |
| 55 | | Node::TraitItem(&hir::TraitItem { | |
| 56 | kind: hir::TraitItemKind::Fn(ref sig, _), .. | |
| 57 | }) => ( | |
| 58 | sig.span, | |
| 59 | None, | |
| 60 | sig.decl | |
| 61 | .inputs | |
| 62 | .iter() | |
| 63 | .map(|arg| match arg.kind { | |
| 64 | hir::TyKind::Tup(tys) => ArgKind::Tuple( | |
| 65 | Some(arg.span), | |
| 66 | vec![("_".to_owned(), "_".to_owned()); tys.len()], | |
| 67 | ), | |
| 68 | _ => ArgKind::empty(), | |
| 69 | }) | |
| 70 | .collect::<Vec<ArgKind>>(), | |
| 71 | ), | |
| 72 | Node::Ctor(variant_data) => { | |
| 73 | let span = variant_data.ctor_hir_id().map_or(DUMMY_SP, |id| hir.span(id)); | |
| 74 | (span, None, vec![ArgKind::empty(); variant_data.fields().len()]) | |
| 75 | } | |
| 76 | _ => panic!("non-FnLike node found: {node:?}"), | |
| 77 | }) | |
| 78 | } | |
| 79 | ||
| 80 | /// Reports an error when the number of arguments needed by a | |
| 81 | /// trait match doesn't match the number that the expression | |
| 82 | /// provides. | |
| 83 | fn report_arg_count_mismatch( | |
| 84 | &self, | |
| 85 | span: Span, | |
| 86 | found_span: Option<Span>, | |
| 87 | expected_args: Vec<ArgKind>, | |
| 88 | found_args: Vec<ArgKind>, | |
| 89 | is_closure: bool, | |
| 90 | closure_arg_span: Option<Span>, | |
| 91 | ) -> Diag<'_> { | |
| 92 | let kind = if is_closure { "closure" } else { "function" }; | |
| 93 | ||
| 94 | let args_str = |arguments: &[ArgKind], other: &[ArgKind]| { | |
| 95 | let arg_length = arguments.len(); | |
| 96 | let distinct = matches!(other, &[ArgKind::Tuple(..)]); | |
| 97 | match (arg_length, arguments.get(0)) { | |
| 98 | (1, Some(ArgKind::Tuple(_, fields))) => { | |
| 99 | format!("a single {}-tuple as argument", fields.len()) | |
| 100 | } | |
| 101 | _ => format!( | |
| 102 | "{} {}argument{}", | |
| 103 | arg_length, | |
| 104 | if distinct && arg_length > 1 { "distinct " } else { "" }, | |
| 105 | pluralize!(arg_length) | |
| 106 | ), | |
| 107 | } | |
| 108 | }; | |
| 109 | ||
| 110 | let expected_str = args_str(&expected_args, &found_args); | |
| 111 | let found_str = args_str(&found_args, &expected_args); | |
| 112 | ||
| 113 | let mut err = struct_span_code_err!( | |
| 114 | self.dcx(), | |
| 115 | span, | |
| 116 | E0593, | |
| 117 | "{} is expected to take {}, but it takes {}", | |
| 118 | kind, | |
| 119 | expected_str, | |
| 120 | found_str, | |
| 121 | ); | |
| 122 | ||
| 123 | err.span_label(span, format!("expected {kind} that takes {expected_str}")); | |
| 124 | ||
| 125 | if let Some(found_span) = found_span { | |
| 126 | err.span_label(found_span, format!("takes {found_str}")); | |
| 127 | ||
| 128 | // Suggest to take and ignore the arguments with expected_args_length `_`s if | |
| 129 | // found arguments is empty (assume the user just wants to ignore args in this case). | |
| 130 | // For example, if `expected_args_length` is 2, suggest `|_, _|`. | |
| 131 | if found_args.is_empty() && is_closure { | |
| 132 | let underscores = vec!["_"; expected_args.len()].join(", "); | |
| 133 | err.span_suggestion_verbose( | |
| 134 | closure_arg_span.unwrap_or(found_span), | |
| 135 | format!( | |
| 136 | "consider changing the closure to take and ignore the expected argument{}", | |
| 137 | pluralize!(expected_args.len()) | |
| 138 | ), | |
| 139 | format!("|{underscores}|"), | |
| 140 | Applicability::MachineApplicable, | |
| 141 | ); | |
| 142 | } | |
| 143 | ||
| 144 | if let &[ArgKind::Tuple(_, ref fields)] = &found_args[..] { | |
| 145 | if fields.len() == expected_args.len() { | |
| 146 | let sugg = fields | |
| 147 | .iter() | |
| 148 | .map(|(name, _)| name.to_owned()) | |
| 149 | .collect::<Vec<String>>() | |
| 150 | .join(", "); | |
| 151 | err.span_suggestion_verbose( | |
| 152 | found_span, | |
| 153 | "change the closure to take multiple arguments instead of a single tuple", | |
| 154 | format!("|{sugg}|"), | |
| 155 | Applicability::MachineApplicable, | |
| 156 | ); | |
| 157 | } | |
| 158 | } | |
| 159 | if let &[ArgKind::Tuple(_, ref fields)] = &expected_args[..] | |
| 160 | && fields.len() == found_args.len() | |
| 161 | && is_closure | |
| 162 | { | |
| 163 | let sugg = format!( | |
| 164 | "|({}){}|", | |
| 165 | found_args | |
| 166 | .iter() | |
| 167 | .map(|arg| match arg { | |
| 168 | ArgKind::Arg(name, _) => name.to_owned(), | |
| 169 | _ => "_".to_owned(), | |
| 170 | }) | |
| 171 | .collect::<Vec<String>>() | |
| 172 | .join(", "), | |
| 173 | // add type annotations if available | |
| 174 | if found_args.iter().any(|arg| match arg { | |
| 175 | ArgKind::Arg(_, ty) => ty != "_", | |
| 176 | _ => false, | |
| 177 | }) { | |
| 178 | format!( | |
| 179 | ": ({})", | |
| 180 | fields | |
| 181 | .iter() | |
| 182 | .map(|(_, ty)| ty.to_owned()) | |
| 183 | .collect::<Vec<String>>() | |
| 184 | .join(", ") | |
| 185 | ) | |
| 186 | } else { | |
| 187 | String::new() | |
| 188 | }, | |
| 189 | ); | |
| 190 | err.span_suggestion_verbose( | |
| 191 | found_span, | |
| 192 | "change the closure to accept a tuple instead of individual arguments", | |
| 193 | sugg, | |
| 194 | Applicability::MachineApplicable, | |
| 195 | ); | |
| 196 | } | |
| 197 | } | |
| 198 | ||
| 199 | err | |
| 200 | } | |
| 201 | ||
| 202 | /// Checks if the type implements one of `Fn`, `FnMut`, or `FnOnce` | |
| 203 | /// in that order, and returns the generic type corresponding to the | |
| 204 | /// argument of that trait (corresponding to the closure arguments). | |
| 205 | fn type_implements_fn_trait( | |
| 206 | &self, | |
| 207 | param_env: ty::ParamEnv<'tcx>, | |
| 208 | ty: ty::Binder<'tcx, Ty<'tcx>>, | |
| 209 | polarity: ty::PredicatePolarity, | |
| 210 | ) -> Result<(ty::ClosureKind, ty::Binder<'tcx, Ty<'tcx>>), ()> { | |
| 211 | self.commit_if_ok(|_| { | |
| 212 | for trait_def_id in [ | |
| 213 | self.tcx.lang_items().fn_trait(), | |
| 214 | self.tcx.lang_items().fn_mut_trait(), | |
| 215 | self.tcx.lang_items().fn_once_trait(), | |
| 216 | ] { | |
| 217 | let Some(trait_def_id) = trait_def_id else { continue }; | |
| 218 | // Make a fresh inference variable so we can determine what the generic parameters | |
| 219 | // of the trait are. | |
| 220 | let var = self.next_ty_var(DUMMY_SP); | |
| 221 | // FIXME(effects) | |
| 222 | let trait_ref = ty::TraitRef::new(self.tcx, trait_def_id, [ty.skip_binder(), var]); | |
| 223 | let obligation = Obligation::new( | |
| 224 | self.tcx, | |
| 225 | ObligationCause::dummy(), | |
| 226 | param_env, | |
| 227 | ty.rebind(ty::TraitPredicate { trait_ref, polarity }), | |
| 228 | ); | |
| 229 | let ocx = ObligationCtxt::new(self); | |
| 230 | ocx.register_obligation(obligation); | |
| 231 | if ocx.select_all_or_error().is_empty() { | |
| 232 | return Ok(( | |
| 233 | self.tcx | |
| 234 | .fn_trait_kind_from_def_id(trait_def_id) | |
| 235 | .expect("expected to map DefId to ClosureKind"), | |
| 236 | ty.rebind(self.resolve_vars_if_possible(var)), | |
| 237 | )); | |
| 238 | } | |
| 239 | } | |
| 240 | ||
| 241 | Err(()) | |
| 242 | }) | |
| 243 | } | |
| 244 | } |
compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs-2| ... | ... | @@ -1,6 +1,5 @@ |
| 1 | 1 | pub mod ambiguity; |
| 2 | 2 | mod fulfillment_errors; |
| 3 | mod infer_ctxt_ext; | |
| 4 | 3 | pub mod on_unimplemented; |
| 5 | 4 | mod overflow; |
| 6 | 5 | pub mod suggestions; |
| ... | ... | @@ -23,7 +22,6 @@ use rustc_span::{ErrorGuaranteed, ExpnKind, Span}; |
| 23 | 22 | use crate::error_reporting::TypeErrCtxt; |
| 24 | 23 | use crate::traits::{FulfillmentError, FulfillmentErrorCode}; |
| 25 | 24 | |
| 26 | pub use self::infer_ctxt_ext::*; | |
| 27 | 25 | pub use self::overflow::*; |
| 28 | 26 | |
| 29 | 27 | // When outputting impl candidates, prefer showing those that are more similar. |
library/panic_unwind/src/seh.rs+6| ... | ... | @@ -157,7 +157,10 @@ mod imp { |
| 157 | 157 | // going to be cross-lang LTOed anyway. However, using expose is shorter and |
| 158 | 158 | // requires less unsafe. |
| 159 | 159 | let addr: usize = ptr.expose_provenance(); |
| 160 | #[cfg(bootstrap)] | |
| 160 | 161 | let image_base = unsafe { addr_of!(__ImageBase) }.addr(); |
| 162 | #[cfg(not(bootstrap))] | |
| 163 | let image_base = addr_of!(__ImageBase).addr(); | |
| 161 | 164 | let offset: usize = addr - image_base; |
| 162 | 165 | Self(offset as u32) |
| 163 | 166 | } |
| ... | ... | @@ -250,7 +253,10 @@ extern "C" { |
| 250 | 253 | // This is fine since the MSVC runtime uses string comparison on the type name |
| 251 | 254 | // to match TypeDescriptors rather than pointer equality. |
| 252 | 255 | static mut TYPE_DESCRIPTOR: _TypeDescriptor = _TypeDescriptor { |
| 256 | #[cfg(bootstrap)] | |
| 253 | 257 | pVFTable: unsafe { addr_of!(TYPE_INFO_VTABLE) } as *const _, |
| 258 | #[cfg(not(bootstrap))] | |
| 259 | pVFTable: addr_of!(TYPE_INFO_VTABLE) as *const _, | |
| 254 | 260 | spare: core::ptr::null_mut(), |
| 255 | 261 | name: TYPE_NAME, |
| 256 | 262 | }; |
library/std/src/sys/backtrace.rs+61-57| ... | ... | @@ -1,4 +1,5 @@ |
| 1 | 1 | //! Common code for printing backtraces. |
| 2 | #![forbid(unsafe_op_in_unsafe_fn)] | |
| 2 | 3 | |
| 3 | 4 | use crate::backtrace_rs::{self, BacktraceFmt, BytesOrWideString, PrintFmt}; |
| 4 | 5 | use crate::borrow::Cow; |
| ... | ... | @@ -62,73 +63,76 @@ unsafe fn _print_fmt(fmt: &mut fmt::Formatter<'_>, print_fmt: PrintFmt) -> fmt:: |
| 62 | 63 | // Start immediately if we're not using a short backtrace. |
| 63 | 64 | let mut start = print_fmt != PrintFmt::Short; |
| 64 | 65 | set_image_base(); |
| 65 | backtrace_rs::trace_unsynchronized(|frame| { | |
| 66 | if print_fmt == PrintFmt::Short && idx > MAX_NB_FRAMES { | |
| 67 | return false; | |
| 68 | } | |
| 66 | // SAFETY: we roll our own locking in this town | |
| 67 | unsafe { | |
| 68 | backtrace_rs::trace_unsynchronized(|frame| { | |
| 69 | if print_fmt == PrintFmt::Short && idx > MAX_NB_FRAMES { | |
| 70 | return false; | |
| 71 | } | |
| 69 | 72 | |
| 70 | let mut hit = false; | |
| 71 | backtrace_rs::resolve_frame_unsynchronized(frame, |symbol| { | |
| 72 | hit = true; | |
| 73 | ||
| 74 | // Any frames between `__rust_begin_short_backtrace` and `__rust_end_short_backtrace` | |
| 75 | // are omitted from the backtrace in short mode, `__rust_end_short_backtrace` will be | |
| 76 | // called before the panic hook, so we won't ignore any frames if there is no | |
| 77 | // invoke of `__rust_begin_short_backtrace`. | |
| 78 | if print_fmt == PrintFmt::Short { | |
| 79 | if let Some(sym) = symbol.name().and_then(|s| s.as_str()) { | |
| 80 | if start && sym.contains("__rust_begin_short_backtrace") { | |
| 81 | start = false; | |
| 82 | return; | |
| 83 | } | |
| 84 | if sym.contains("__rust_end_short_backtrace") { | |
| 85 | start = true; | |
| 86 | return; | |
| 87 | } | |
| 88 | if !start { | |
| 89 | omitted_count += 1; | |
| 73 | let mut hit = false; | |
| 74 | backtrace_rs::resolve_frame_unsynchronized(frame, |symbol| { | |
| 75 | hit = true; | |
| 76 | ||
| 77 | // Any frames between `__rust_begin_short_backtrace` and `__rust_end_short_backtrace` | |
| 78 | // are omitted from the backtrace in short mode, `__rust_end_short_backtrace` will be | |
| 79 | // called before the panic hook, so we won't ignore any frames if there is no | |
| 80 | // invoke of `__rust_begin_short_backtrace`. | |
| 81 | if print_fmt == PrintFmt::Short { | |
| 82 | if let Some(sym) = symbol.name().and_then(|s| s.as_str()) { | |
| 83 | if start && sym.contains("__rust_begin_short_backtrace") { | |
| 84 | start = false; | |
| 85 | return; | |
| 86 | } | |
| 87 | if sym.contains("__rust_end_short_backtrace") { | |
| 88 | start = true; | |
| 89 | return; | |
| 90 | } | |
| 91 | if !start { | |
| 92 | omitted_count += 1; | |
| 93 | } | |
| 90 | 94 | } |
| 91 | 95 | } |
| 92 | } | |
| 93 | 96 | |
| 94 | if start { | |
| 95 | if omitted_count > 0 { | |
| 96 | debug_assert!(print_fmt == PrintFmt::Short); | |
| 97 | // only print the message between the middle of frames | |
| 98 | if !first_omit { | |
| 99 | let _ = writeln!( | |
| 100 | bt_fmt.formatter(), | |
| 101 | " [... omitted {} frame{} ...]", | |
| 102 | omitted_count, | |
| 103 | if omitted_count > 1 { "s" } else { "" } | |
| 104 | ); | |
| 97 | if start { | |
| 98 | if omitted_count > 0 { | |
| 99 | debug_assert!(print_fmt == PrintFmt::Short); | |
| 100 | // only print the message between the middle of frames | |
| 101 | if !first_omit { | |
| 102 | let _ = writeln!( | |
| 103 | bt_fmt.formatter(), | |
| 104 | " [... omitted {} frame{} ...]", | |
| 105 | omitted_count, | |
| 106 | if omitted_count > 1 { "s" } else { "" } | |
| 107 | ); | |
| 108 | } | |
| 109 | first_omit = false; | |
| 110 | omitted_count = 0; | |
| 105 | 111 | } |
| 106 | first_omit = false; | |
| 107 | omitted_count = 0; | |
| 112 | res = bt_fmt.frame().symbol(frame, symbol); | |
| 108 | 113 | } |
| 109 | res = bt_fmt.frame().symbol(frame, symbol); | |
| 114 | }); | |
| 115 | #[cfg(target_os = "nto")] | |
| 116 | if libc::__my_thread_exit as *mut libc::c_void == frame.ip() { | |
| 117 | if !hit && start { | |
| 118 | use crate::backtrace_rs::SymbolName; | |
| 119 | res = bt_fmt.frame().print_raw( | |
| 120 | frame.ip(), | |
| 121 | Some(SymbolName::new("__my_thread_exit".as_bytes())), | |
| 122 | None, | |
| 123 | None, | |
| 124 | ); | |
| 125 | } | |
| 126 | return false; | |
| 110 | 127 | } |
| 111 | }); | |
| 112 | #[cfg(target_os = "nto")] | |
| 113 | if libc::__my_thread_exit as *mut libc::c_void == frame.ip() { | |
| 114 | 128 | if !hit && start { |
| 115 | use crate::backtrace_rs::SymbolName; | |
| 116 | res = bt_fmt.frame().print_raw( | |
| 117 | frame.ip(), | |
| 118 | Some(SymbolName::new("__my_thread_exit".as_bytes())), | |
| 119 | None, | |
| 120 | None, | |
| 121 | ); | |
| 129 | res = bt_fmt.frame().print_raw(frame.ip(), None, None, None); | |
| 122 | 130 | } |
| 123 | return false; | |
| 124 | } | |
| 125 | if !hit && start { | |
| 126 | res = bt_fmt.frame().print_raw(frame.ip(), None, None, None); | |
| 127 | } | |
| 128 | 131 | |
| 129 | idx += 1; | |
| 130 | res.is_ok() | |
| 131 | }); | |
| 132 | idx += 1; | |
| 133 | res.is_ok() | |
| 134 | }) | |
| 135 | }; | |
| 132 | 136 | res?; |
| 133 | 137 | bt_fmt.finish()?; |
| 134 | 138 | if print_fmt == PrintFmt::Short { |
library/std/src/sys/pal/common/alloc.rs+11-8| ... | ... | @@ -1,3 +1,4 @@ |
| 1 | #![forbid(unsafe_op_in_unsafe_fn)] | |
| 1 | 2 | use crate::alloc::{GlobalAlloc, Layout, System}; |
| 2 | 3 | use crate::cmp; |
| 3 | 4 | use crate::ptr; |
| ... | ... | @@ -46,14 +47,16 @@ pub unsafe fn realloc_fallback( |
| 46 | 47 | old_layout: Layout, |
| 47 | 48 | new_size: usize, |
| 48 | 49 | ) -> *mut u8 { |
| 49 | // Docs for GlobalAlloc::realloc require this to be valid: | |
| 50 | let new_layout = Layout::from_size_align_unchecked(new_size, old_layout.align()); | |
| 50 | // SAFETY: Docs for GlobalAlloc::realloc require this to be valid | |
| 51 | unsafe { | |
| 52 | let new_layout = Layout::from_size_align_unchecked(new_size, old_layout.align()); | |
| 51 | 53 | |
| 52 | let new_ptr = GlobalAlloc::alloc(alloc, new_layout); | |
| 53 | if !new_ptr.is_null() { | |
| 54 | let size = cmp::min(old_layout.size(), new_size); | |
| 55 | ptr::copy_nonoverlapping(ptr, new_ptr, size); | |
| 56 | GlobalAlloc::dealloc(alloc, ptr, old_layout); | |
| 54 | let new_ptr = GlobalAlloc::alloc(alloc, new_layout); | |
| 55 | if !new_ptr.is_null() { | |
| 56 | let size = cmp::min(old_layout.size(), new_size); | |
| 57 | ptr::copy_nonoverlapping(ptr, new_ptr, size); | |
| 58 | GlobalAlloc::dealloc(alloc, ptr, old_layout); | |
| 59 | } | |
| 60 | new_ptr | |
| 57 | 61 | } |
| 58 | new_ptr | |
| 59 | 62 | } |
src/tools/clippy/clippy_lints/src/eta_reduction.rs+2-2| ... | ... | @@ -15,7 +15,7 @@ use rustc_middle::ty::{ |
| 15 | 15 | use rustc_session::declare_lint_pass; |
| 16 | 16 | use rustc_span::symbol::sym; |
| 17 | 17 | use rustc_target::spec::abi::Abi; |
| 18 | use rustc_trait_selection::error_reporting::traits::InferCtxtExt as _; | |
| 18 | use rustc_trait_selection::error_reporting::InferCtxtErrorExt as _; | |
| 19 | 19 | |
| 20 | 20 | declare_clippy_lint! { |
| 21 | 21 | /// ### What it does |
| ... | ... | @@ -178,7 +178,7 @@ impl<'tcx> LateLintPass<'tcx> for EtaReduction { |
| 178 | 178 | // 'cuz currently nothing changes after deleting this check. |
| 179 | 179 | local_used_in(cx, l, args) || local_used_after_expr(cx, l, expr) |
| 180 | 180 | }) { |
| 181 | match cx.tcx.infer_ctxt().build().type_implements_fn_trait( | |
| 181 | match cx.tcx.infer_ctxt().build().err_ctxt().type_implements_fn_trait( | |
| 182 | 182 | cx.param_env, |
| 183 | 183 | Binder::bind_with_vars(callee_ty_adjusted, List::empty()), |
| 184 | 184 | ty::PredicatePolarity::Positive, |
src/tools/compiletest/src/runtest.rs+7-11| ... | ... | @@ -82,26 +82,22 @@ fn disable_error_reporting<F: FnOnce() -> R, R>(f: F) -> R { |
| 82 | 82 | } |
| 83 | 83 | |
| 84 | 84 | /// The platform-specific library name |
| 85 | fn get_lib_name(lib: &str, aux_type: AuxType) -> Option<String> { | |
| 85 | fn get_lib_name(name: &str, aux_type: AuxType) -> Option<String> { | |
| 86 | 86 | match aux_type { |
| 87 | 87 | AuxType::Bin => None, |
| 88 | 88 | // In some cases (e.g. MUSL), we build a static |
| 89 | 89 | // library, rather than a dynamic library. |
| 90 | 90 | // In this case, the only path we can pass |
| 91 | 91 | // with '--extern-meta' is the '.rlib' file |
| 92 | AuxType::Lib => Some(format!("lib{}.rlib", lib)), | |
| 93 | AuxType::Dylib => Some(if cfg!(windows) { | |
| 94 | format!("{}.dll", lib) | |
| 95 | } else if cfg!(target_vendor = "apple") { | |
| 96 | format!("lib{}.dylib", lib) | |
| 97 | } else if cfg!(target_os = "aix") { | |
| 98 | format!("lib{}.a", lib) | |
| 99 | } else { | |
| 100 | format!("lib{}.so", lib) | |
| 101 | }), | |
| 92 | AuxType::Lib => Some(format!("lib{name}.rlib")), | |
| 93 | AuxType::Dylib => Some(dylib_name(name)), | |
| 102 | 94 | } |
| 103 | 95 | } |
| 104 | 96 | |
| 97 | fn dylib_name(name: &str) -> String { | |
| 98 | format!("{}{name}.{}", std::env::consts::DLL_PREFIX, std::env::consts::DLL_EXTENSION) | |
| 99 | } | |
| 100 | ||
| 105 | 101 | pub fn run(config: Arc<Config>, testpaths: &TestPaths, revision: Option<&str>) { |
| 106 | 102 | match &*config.target { |
| 107 | 103 | "arm-linux-androideabi" |
src/tools/miri/tests/fail/extern_static.rs+1-1| ... | ... | @@ -5,5 +5,5 @@ extern "C" { |
| 5 | 5 | } |
| 6 | 6 | |
| 7 | 7 | fn main() { |
| 8 | let _val = unsafe { std::ptr::addr_of!(FOO) }; //~ ERROR: is not supported by Miri | |
| 8 | let _val = std::ptr::addr_of!(FOO); //~ ERROR: is not supported by Miri | |
| 9 | 9 | } |
src/tools/miri/tests/fail/extern_static.stderr+2-2| ... | ... | @@ -1,8 +1,8 @@ |
| 1 | 1 | error: unsupported operation: extern static `FOO` is not supported by Miri |
| 2 | 2 | --> $DIR/extern_static.rs:LL:CC |
| 3 | 3 | | |
| 4 | LL | let _val = unsafe { std::ptr::addr_of!(FOO) }; | |
| 5 | | ^^^ extern static `FOO` is not supported by Miri | |
| 4 | LL | let _val = std::ptr::addr_of!(FOO); | |
| 5 | | ^^^ extern static `FOO` is not supported by Miri | |
| 6 | 6 | | |
| 7 | 7 | = help: this is likely not a bug in the program; it indicates that the program performed an operation that Miri does not support |
| 8 | 8 | = note: BACKTRACE: |
src/tools/miri/tests/pass/static_mut.rs+1-1| ... | ... | @@ -2,7 +2,7 @@ use std::ptr::addr_of; |
| 2 | 2 | |
| 3 | 3 | static mut FOO: i32 = 42; |
| 4 | 4 | |
| 5 | static BAR: Foo = Foo(unsafe { addr_of!(FOO) }); | |
| 5 | static BAR: Foo = Foo(addr_of!(FOO)); | |
| 6 | 6 | |
| 7 | 7 | #[allow(dead_code)] |
| 8 | 8 | struct Foo(*const i32); |
tests/ui/consts/const_refs_to_static.rs+1-1| ... | ... | @@ -9,7 +9,7 @@ const C1: &i32 = &S; |
| 9 | 9 | const C1_READ: () = { |
| 10 | 10 | assert!(*C1 == 0); |
| 11 | 11 | }; |
| 12 | const C2: *const i32 = unsafe { std::ptr::addr_of!(S_MUT) }; | |
| 12 | const C2: *const i32 = std::ptr::addr_of!(S_MUT); | |
| 13 | 13 | |
| 14 | 14 | fn main() { |
| 15 | 15 | assert_eq!(*C1, 0); |
tests/ui/consts/mut-ptr-to-static.rs+3-6| ... | ... | @@ -16,12 +16,9 @@ static mut STATIC: u32 = 42; |
| 16 | 16 | static INTERIOR_MUTABLE_STATIC: SyncUnsafeCell<u32> = SyncUnsafeCell::new(42); |
| 17 | 17 | |
| 18 | 18 | // A static that mutably points to STATIC. |
| 19 | static PTR: SyncPtr = SyncPtr { | |
| 20 | foo: unsafe { ptr::addr_of_mut!(STATIC) }, | |
| 21 | }; | |
| 22 | static INTERIOR_MUTABLE_PTR: SyncPtr = SyncPtr { | |
| 23 | foo: ptr::addr_of!(INTERIOR_MUTABLE_STATIC) as *mut u32, | |
| 24 | }; | |
| 19 | static PTR: SyncPtr = SyncPtr { foo: ptr::addr_of_mut!(STATIC) }; | |
| 20 | static INTERIOR_MUTABLE_PTR: SyncPtr = | |
| 21 | SyncPtr { foo: ptr::addr_of!(INTERIOR_MUTABLE_STATIC) as *mut u32 }; | |
| 25 | 22 | |
| 26 | 23 | fn main() { |
| 27 | 24 | let ptr = PTR.foo; |
tests/ui/coroutine/coroutine-with-nll.stderr+8| ... | ... | @@ -1,11 +1,19 @@ |
| 1 | 1 | error[E0626]: borrow may still be in use when coroutine yields |
| 2 | 2 | --> $DIR/coroutine-with-nll.rs:8:17 |
| 3 | 3 | | |
| 4 | LL | || { | |
| 5 | | -- within this coroutine | |
| 6 | ... | |
| 4 | 7 | LL | let b = &mut true; |
| 5 | 8 | | ^^^^^^^^^ |
| 6 | 9 | LL | |
| 7 | 10 | LL | yield (); |
| 8 | 11 | | -------- possible yield occurs here |
| 12 | | | |
| 13 | help: add `static` to mark this coroutine as unmovable | |
| 14 | | | |
| 15 | LL | static || { | |
| 16 | | ++++++ | |
| 9 | 17 | |
| 10 | 18 | error: aborting due to 1 previous error |
| 11 | 19 |
tests/ui/coroutine/issue-48048.stderr+8| ... | ... | @@ -1,10 +1,18 @@ |
| 1 | 1 | error[E0626]: borrow may still be in use when coroutine yields |
| 2 | 2 | --> $DIR/issue-48048.rs:9:9 |
| 3 | 3 | | |
| 4 | LL | #[coroutine] || { | |
| 5 | | -- within this coroutine | |
| 6 | ... | |
| 4 | 7 | LL | x.0({ |
| 5 | 8 | | ^^^ |
| 6 | 9 | LL | yield; |
| 7 | 10 | | ----- possible yield occurs here |
| 11 | | | |
| 12 | help: add `static` to mark this coroutine as unmovable | |
| 13 | | | |
| 14 | LL | #[coroutine] static || { | |
| 15 | | ++++++ | |
| 8 | 16 | |
| 9 | 17 | error: aborting due to 1 previous error |
| 10 | 18 |
tests/ui/coroutine/pattern-borrow.stderr+7| ... | ... | @@ -1,10 +1,17 @@ |
| 1 | 1 | error[E0626]: borrow may still be in use when coroutine yields |
| 2 | 2 | --> $DIR/pattern-borrow.rs:9:24 |
| 3 | 3 | | |
| 4 | LL | #[coroutine] move || { | |
| 5 | | ------- within this coroutine | |
| 4 | 6 | LL | if let Test::A(ref _a) = test { |
| 5 | 7 | | ^^^^^^ |
| 6 | 8 | LL | yield (); |
| 7 | 9 | | -------- possible yield occurs here |
| 10 | | | |
| 11 | help: add `static` to mark this coroutine as unmovable | |
| 12 | | | |
| 13 | LL | #[coroutine] static move || { | |
| 14 | | ++++++ | |
| 8 | 15 | |
| 9 | 16 | error: aborting due to 1 previous error |
| 10 | 17 |
tests/ui/coroutine/self_referential_gen_block.stderr+3| ... | ... | @@ -1,6 +1,9 @@ |
| 1 | 1 | error[E0626]: borrow may still be in use when `gen` block yields |
| 2 | 2 | --> $DIR/self_referential_gen_block.rs:9:21 |
| 3 | 3 | | |
| 4 | LL | let mut x = gen { | |
| 5 | | --- within this `gen` block | |
| 6 | LL | let y = 42; | |
| 4 | 7 | LL | let z = &y; |
| 5 | 8 | | ^^ |
| 6 | 9 | LL | yield 43; |
tests/ui/coroutine/yield-in-args.stderr+8| ... | ... | @@ -1,8 +1,16 @@ |
| 1 | 1 | error[E0626]: borrow may still be in use when coroutine yields |
| 2 | 2 | --> $DIR/yield-in-args.rs:9:13 |
| 3 | 3 | | |
| 4 | LL | || { | |
| 5 | | -- within this coroutine | |
| 6 | LL | let b = true; | |
| 4 | 7 | LL | foo(&b, yield); |
| 5 | 8 | | ^^ ----- possible yield occurs here |
| 9 | | | |
| 10 | help: add `static` to mark this coroutine as unmovable | |
| 11 | | | |
| 12 | LL | static || { | |
| 13 | | ++++++ | |
| 6 | 14 | |
| 7 | 15 | error: aborting due to 1 previous error |
| 8 | 16 |
tests/ui/coroutine/yield-while-iterating.stderr+7| ... | ... | @@ -1,10 +1,17 @@ |
| 1 | 1 | error[E0626]: borrow may still be in use when coroutine yields |
| 2 | 2 | --> $DIR/yield-while-iterating.rs:13:18 |
| 3 | 3 | | |
| 4 | LL | let _b =#[coroutine] move || { | |
| 5 | | ------- within this coroutine | |
| 4 | 6 | LL | for p in &x { |
| 5 | 7 | | ^^ |
| 6 | 8 | LL | yield(); |
| 7 | 9 | | ------- possible yield occurs here |
| 10 | | | |
| 11 | help: add `static` to mark this coroutine as unmovable | |
| 12 | | | |
| 13 | LL | let _b =#[coroutine] static move || { | |
| 14 | | ++++++ | |
| 8 | 15 | |
| 9 | 16 | error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable |
| 10 | 17 | --> $DIR/yield-while-iterating.rs:58:20 |
tests/ui/coroutine/yield-while-local-borrowed.stderr+15| ... | ... | @@ -1,20 +1,35 @@ |
| 1 | 1 | error[E0626]: borrow may still be in use when coroutine yields |
| 2 | 2 | --> $DIR/yield-while-local-borrowed.rs:13:17 |
| 3 | 3 | | |
| 4 | LL | let mut b = #[coroutine] move || { | |
| 5 | | ------- within this coroutine | |
| 4 | 6 | LL | let a = &mut 3; |
| 5 | 7 | | ^^^^^^ |
| 6 | 8 | LL | |
| 7 | 9 | LL | yield (); |
| 8 | 10 | | -------- possible yield occurs here |
| 11 | | | |
| 12 | help: add `static` to mark this coroutine as unmovable | |
| 13 | | | |
| 14 | LL | let mut b = #[coroutine] static move || { | |
| 15 | | ++++++ | |
| 9 | 16 | |
| 10 | 17 | error[E0626]: borrow may still be in use when coroutine yields |
| 11 | 18 | --> $DIR/yield-while-local-borrowed.rs:40:21 |
| 12 | 19 | | |
| 20 | LL | let mut b = #[coroutine] move || { | |
| 21 | | ------- within this coroutine | |
| 22 | ... | |
| 13 | 23 | LL | let b = &a; |
| 14 | 24 | | ^^ |
| 15 | 25 | LL | |
| 16 | 26 | LL | yield (); |
| 17 | 27 | | -------- possible yield occurs here |
| 28 | | | |
| 29 | help: add `static` to mark this coroutine as unmovable | |
| 30 | | | |
| 31 | LL | let mut b = #[coroutine] static move || { | |
| 32 | | ++++++ | |
| 18 | 33 | |
| 19 | 34 | error: aborting due to 2 previous errors |
| 20 | 35 |
tests/ui/nll/issue-55850.stderr+8| ... | ... | @@ -10,8 +10,16 @@ LL | yield &s[..] |
| 10 | 10 | error[E0626]: borrow may still be in use when coroutine yields |
| 11 | 11 | --> $DIR/issue-55850.rs:28:16 |
| 12 | 12 | | |
| 13 | LL | GenIter(#[coroutine] move || { | |
| 14 | | ------- within this coroutine | |
| 15 | LL | let mut s = String::new(); | |
| 13 | 16 | LL | yield &s[..] |
| 14 | 17 | | -------^---- possible yield occurs here |
| 18 | | | |
| 19 | help: add `static` to mark this coroutine as unmovable | |
| 20 | | | |
| 21 | LL | GenIter(#[coroutine] static move || { | |
| 22 | | ++++++ | |
| 15 | 23 | |
| 16 | 24 | error: aborting due to 2 previous errors |
| 17 | 25 |
tests/ui/static/raw-ref-deref-with-unsafe.rs created+16| ... | ... | @@ -0,0 +1,16 @@ |
| 1 | //@ check-pass | |
| 2 | #![feature(const_mut_refs)] | |
| 3 | use std::ptr; | |
| 4 | ||
| 5 | // This code should remain unsafe because of the two unsafe operations here, | |
| 6 | // even if in a hypothetical future we deem all &raw (const|mut) *ptr exprs safe. | |
| 7 | ||
| 8 | static mut BYTE: u8 = 0; | |
| 9 | static mut BYTE_PTR: *mut u8 = ptr::addr_of_mut!(BYTE); | |
| 10 | // An unsafe static's ident is a place expression in its own right, so despite the above being safe | |
| 11 | // (it's fine to create raw refs to places!) the following derefs the ptr before creating its ref | |
| 12 | static mut DEREF_BYTE_PTR: *mut u8 = unsafe { ptr::addr_of_mut!(*BYTE_PTR) }; | |
| 13 | ||
| 14 | fn main() { | |
| 15 | let _ = unsafe { DEREF_BYTE_PTR }; | |
| 16 | } |
tests/ui/static/raw-ref-deref-without-unsafe.rs created+18| ... | ... | @@ -0,0 +1,18 @@ |
| 1 | #![feature(const_mut_refs)] | |
| 2 | ||
| 3 | use std::ptr; | |
| 4 | ||
| 5 | // This code should remain unsafe because of the two unsafe operations here, | |
| 6 | // even if in a hypothetical future we deem all &raw (const|mut) *ptr exprs safe. | |
| 7 | ||
| 8 | static mut BYTE: u8 = 0; | |
| 9 | static mut BYTE_PTR: *mut u8 = ptr::addr_of_mut!(BYTE); | |
| 10 | // An unsafe static's ident is a place expression in its own right, so despite the above being safe | |
| 11 | // (it's fine to create raw refs to places!) the following derefs the ptr before creating its ref! | |
| 12 | static mut DEREF_BYTE_PTR: *mut u8 = ptr::addr_of_mut!(*BYTE_PTR); | |
| 13 | //~^ ERROR: use of mutable static | |
| 14 | //~| ERROR: dereference of raw pointer | |
| 15 | ||
| 16 | fn main() { | |
| 17 | let _ = unsafe { DEREF_BYTE_PTR }; | |
| 18 | } |
tests/ui/static/raw-ref-deref-without-unsafe.stderr created+19| ... | ... | @@ -0,0 +1,19 @@ |
| 1 | error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block | |
| 2 | --> $DIR/raw-ref-deref-without-unsafe.rs:12:56 | |
| 3 | | | |
| 4 | LL | static mut DEREF_BYTE_PTR: *mut u8 = ptr::addr_of_mut!(*BYTE_PTR); | |
| 5 | | ^^^^^^^^^ dereference of raw pointer | |
| 6 | | | |
| 7 | = note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior | |
| 8 | ||
| 9 | error[E0133]: use of mutable static is unsafe and requires unsafe function or block | |
| 10 | --> $DIR/raw-ref-deref-without-unsafe.rs:12:57 | |
| 11 | | | |
| 12 | LL | static mut DEREF_BYTE_PTR: *mut u8 = ptr::addr_of_mut!(*BYTE_PTR); | |
| 13 | | ^^^^^^^^ use of mutable static | |
| 14 | | | |
| 15 | = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior | |
| 16 | ||
| 17 | error: aborting due to 2 previous errors | |
| 18 | ||
| 19 | For more information about this error, try `rustc --explain E0133`. |
tests/ui/static/raw-ref-extern-static.rs created+27| ... | ... | @@ -0,0 +1,27 @@ |
| 1 | //@ check-pass | |
| 2 | #![feature(raw_ref_op)] | |
| 3 | use std::ptr; | |
| 4 | ||
| 5 | // see https://github.com/rust-lang/rust/issues/125833 | |
| 6 | // notionally, taking the address of an extern static is a safe operation, | |
| 7 | // as we only point at it instead of generating a true reference to it | |
| 8 | ||
| 9 | // it may potentially induce linker errors, but the safety of that is not about taking addresses! | |
| 10 | // any safety obligation of the extern static's correctness in declaration is on the extern itself, | |
| 11 | // see RFC 3484 for more on that: https://rust-lang.github.io/rfcs/3484-unsafe-extern-blocks.html | |
| 12 | ||
| 13 | extern "C" { | |
| 14 | static THERE: u8; | |
| 15 | static mut SOMEWHERE: u8; | |
| 16 | } | |
| 17 | ||
| 18 | fn main() { | |
| 19 | let ptr2there = ptr::addr_of!(THERE); | |
| 20 | let ptr2somewhere = ptr::addr_of!(SOMEWHERE); | |
| 21 | let ptr2somewhere = ptr::addr_of_mut!(SOMEWHERE); | |
| 22 | ||
| 23 | // testing both addr_of and the expression it directly expands to | |
| 24 | let raw2there = &raw const THERE; | |
| 25 | let raw2somewhere = &raw const SOMEWHERE; | |
| 26 | let raw2somewhere = &raw mut SOMEWHERE; | |
| 27 | } |
tests/ui/static/raw-ref-static-mut.rs created+17| ... | ... | @@ -0,0 +1,17 @@ |
| 1 | //@ check-pass | |
| 2 | #![feature(raw_ref_op)] | |
| 3 | use std::ptr; | |
| 4 | ||
| 5 | // see https://github.com/rust-lang/rust/issues/125833 | |
| 6 | // notionally, taking the address of a static mut is a safe operation, | |
| 7 | // as we only point at it instead of generating a true reference to it | |
| 8 | static mut NOWHERE: usize = 0; | |
| 9 | ||
| 10 | fn main() { | |
| 11 | let p2nowhere = ptr::addr_of!(NOWHERE); | |
| 12 | let p2nowhere = ptr::addr_of_mut!(NOWHERE); | |
| 13 | ||
| 14 | // testing both addr_of and the expression it directly expands to | |
| 15 | let raw2nowhere = &raw const NOWHERE; | |
| 16 | let raw2nowhere = &raw mut NOWHERE; | |
| 17 | } |