authorbors <bors@rust-lang.org> 2024-07-23 12:10:45 UTC
committerbors <bors@rust-lang.org> 2024-07-23 12:10:45 UTC
logd53dc752d2bc0a9e7f7e2e5f82aff03a6d222614
tree3cb5fe0c2b203a1ee5840d4c4679961ac410dee3
parentd111ccdb6186b368ead16c01f43c645a6e5f4a67
parentf8373adcda33b3a8b5e836e28b2162b2bfe31ee8

Auto merge of #128093 - matthiaskrgr:rollup-1snye4b, r=matthiaskrgr

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: rollup

33 files changed, 567 insertions(+), 366 deletions(-)

compiler/rustc_borrowck/src/borrowck_errors.rs+27-3
......@@ -1,7 +1,9 @@
11#![allow(rustc::diagnostic_outside_of_impl)]
22#![allow(rustc::untranslatable_diagnostic)]
33
4use rustc_errors::Applicability;
45use rustc_errors::{codes::*, struct_span_code_err, Diag, DiagCtxtHandle};
6use rustc_hir as hir;
57use rustc_middle::span_bug;
68use rustc_middle::ty::{self, Ty, TyCtxt};
79use rustc_span::Span;
......@@ -382,13 +384,35 @@ impl<'infcx, 'tcx> crate::MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
382384 yield_span: Span,
383385 ) -> Diag<'infcx> {
384386 let coroutine_kind = self.body.coroutine.as_ref().unwrap().coroutine_kind;
385 struct_span_code_err!(
387 let mut diag = struct_span_code_err!(
386388 self.dcx(),
387389 span,
388390 E0626,
389391 "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
392416 }
393417
394418 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 @@
1This error occurs because a borrow in a coroutine persists across a
1This error occurs because a borrow in a movable coroutine persists across a
22yield point.
33
44Erroneous code example:
......@@ -15,19 +15,35 @@ let mut b = #[coroutine] || {
1515Pin::new(&mut b).resume(());
1616```
1717
18At present, it is not permitted to have a yield that occurs while a
19borrow is still in scope. To resolve this error, the borrow must
20either be "contained" to a smaller scope that does not overlap the
21yield or else eliminated in another way. So, for example, we might
22resolve the previous example by removing the borrow and just storing
23the integer by value:
18Coroutines may be either unmarked, or marked with `static`. If it is unmarked,
19then the coroutine is considered "movable". At present, it is not permitted to
20have a yield in a movable coroutine that occurs while a borrow is still in
21scope. 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;
27let mut b = #[coroutine] static || { // <-- note the static keyword
28 let a = &String::from("hello, world");
29 yield ();
30 println!("{}", a);
31};
32let mut b = std::pin::pin!(b);
33b.as_mut().resume(());
34```
35
36If the coroutine must remain movable, for example to be used as `Unpin`
37without pinning it on the stack or in an allocation, we can alternatively
38resolve the previous example by removing the borrow and just storing the
39type by value:
2440
2541```
2642# #![feature(coroutines, coroutine_trait, stmt_expr_attributes)]
2743# use std::ops::Coroutine;
2844# use std::pin::Pin;
2945let mut b = #[coroutine] || {
30 let a = 3;
46 let a = String::from("hello, world");
3147 yield ();
3248 println!("{}", a);
3349};
compiler/rustc_hir_typeck/src/closure.rs+2-2
......@@ -18,7 +18,6 @@ use rustc_span::def_id::LocalDefId;
1818use rustc_span::Span;
1919use rustc_target::spec::abi::Abi;
2020use rustc_trait_selection::error_reporting::traits::ArgKind;
21use rustc_trait_selection::error_reporting::traits::InferCtxtExt as _;
2221use rustc_trait_selection::traits;
2322use rustc_type_ir::ClosureKind;
2423use std::iter;
......@@ -734,13 +733,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
734733 .map(|ty| ArgKind::from_expected_ty(*ty, None))
735734 .collect();
736735 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) {
738737 Some((sp, arg_sp, args)) => (Some(sp), arg_sp, args),
739738 None => (None, None, Vec::new()),
740739 };
741740 let expected_span =
742741 expected_sig.cause_span.unwrap_or_else(|| self.tcx.def_span(expr_def_id));
743742 let guar = self
743 .err_ctxt()
744744 .report_arg_count_mismatch(
745745 expected_span,
746746 closure_span,
compiler/rustc_infer/src/infer/mod.rs-12
......@@ -755,18 +755,6 @@ impl<'tcx> InferCtxt<'tcx> {
755755 .collect()
756756 }
757757
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
770758 #[instrument(skip(self), level = "debug")]
771759 pub fn sub_regions(
772760 &self,
compiler/rustc_mir_build/src/check_unsafety.rs+18
......@@ -466,6 +466,24 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
466466 }
467467 }
468468 }
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 }
469487 ExprKind::Deref { arg } => {
470488 if let ExprKind::StaticRef { def_id, .. } | ExprKind::ThreadLocalRef(def_id) =
471489 self.thir[arg].kind
compiler/rustc_mir_build/src/thir/cx/expr.rs+4-2
......@@ -939,9 +939,11 @@ impl<'tcx> Cx<'tcx> {
939939 }
940940 }
941941
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
944945 Res::Def(DefKind::Static { .. }, id) => {
946 // this is &raw for extern static or static mut, and & for other statics
945947 let ty = self.tcx.static_ptr_ty(id);
946948 let temp_lifetime = self
947949 .rvalue_scopes
compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs+3-2
......@@ -12,6 +12,7 @@ use rustc_middle::{
1212use rustc_span::{def_id::DefId, sym, BytePos, Span, Symbol};
1313
1414use crate::error_reporting::TypeErrCtxt;
15use crate::infer::InferCtxtExt;
1516
1617impl<'tcx> TypeErrCtxt<'_, 'tcx> {
1718 pub fn note_and_explain_type_err(
......@@ -821,7 +822,7 @@ fn foo(&self) -> Self::T { String::new() }
821822 tcx.defaultness(item.id.owner_id)
822823 {
823824 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) {
825826 diag.span_label(
826827 item.span,
827828 "associated type defaults can't be assumed inside the \
......@@ -844,7 +845,7 @@ fn foo(&self) -> Self::T { String::new() }
844845 let assoc_ty = tcx.type_of(item.id.owner_id).instantiate_identity();
845846 if let hir::Defaultness::Default { has_value: true } =
846847 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)
848849 {
849850 diag.span_label(
850851 item.span,
compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs+233-2
......@@ -1,7 +1,6 @@
11use super::on_unimplemented::{AppendConstMessage, OnUnimplementedNote};
22use super::suggestions::get_explanation_based_on_obligation;
33use crate::error_reporting::infer::TyCategory;
4use crate::error_reporting::traits::infer_ctxt_ext::InferCtxtExt;
54use crate::error_reporting::traits::report_object_safety_error;
65use crate::error_reporting::TypeErrCtxt;
76use crate::errors::{
......@@ -2602,7 +2601,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
26022601 })
26032602 .unwrap_or((found_span, None, found));
26042603
2605 self.infcx.report_arg_count_mismatch(
2604 self.report_arg_count_mismatch(
26062605 span,
26072606 closure_span,
26082607 expected,
......@@ -2614,6 +2613,238 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
26142613 )
26152614 }
26162615
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
26172848 fn report_not_const_evaluatable_error(
26182849 &self,
26192850 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
3use crate::infer::InferCtxt;
4use crate::traits::{Obligation, ObligationCause, ObligationCtxt};
5use rustc_errors::{codes::*, pluralize, struct_span_code_err, Applicability, Diag};
6use rustc_hir as hir;
7use rustc_hir::Node;
8use rustc_macros::extension;
9use rustc_middle::ty::{self, Ty};
10use rustc_span::{Span, DUMMY_SP};
11
12use super::ArgKind;
13
14#[extension(pub trait InferCtxtExt<'tcx>)]
15impl<'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 @@
11pub mod ambiguity;
22mod fulfillment_errors;
3mod infer_ctxt_ext;
43pub mod on_unimplemented;
54mod overflow;
65pub mod suggestions;
......@@ -23,7 +22,6 @@ use rustc_span::{ErrorGuaranteed, ExpnKind, Span};
2322use crate::error_reporting::TypeErrCtxt;
2423use crate::traits::{FulfillmentError, FulfillmentErrorCode};
2524
26pub use self::infer_ctxt_ext::*;
2725pub use self::overflow::*;
2826
2927// When outputting impl candidates, prefer showing those that are more similar.
library/panic_unwind/src/seh.rs+6
......@@ -157,7 +157,10 @@ mod imp {
157157 // going to be cross-lang LTOed anyway. However, using expose is shorter and
158158 // requires less unsafe.
159159 let addr: usize = ptr.expose_provenance();
160 #[cfg(bootstrap)]
160161 let image_base = unsafe { addr_of!(__ImageBase) }.addr();
162 #[cfg(not(bootstrap))]
163 let image_base = addr_of!(__ImageBase).addr();
161164 let offset: usize = addr - image_base;
162165 Self(offset as u32)
163166 }
......@@ -250,7 +253,10 @@ extern "C" {
250253// This is fine since the MSVC runtime uses string comparison on the type name
251254// to match TypeDescriptors rather than pointer equality.
252255static mut TYPE_DESCRIPTOR: _TypeDescriptor = _TypeDescriptor {
256 #[cfg(bootstrap)]
253257 pVFTable: unsafe { addr_of!(TYPE_INFO_VTABLE) } as *const _,
258 #[cfg(not(bootstrap))]
259 pVFTable: addr_of!(TYPE_INFO_VTABLE) as *const _,
254260 spare: core::ptr::null_mut(),
255261 name: TYPE_NAME,
256262};
library/std/src/sys/backtrace.rs+61-57
......@@ -1,4 +1,5 @@
11//! Common code for printing backtraces.
2#![forbid(unsafe_op_in_unsafe_fn)]
23
34use crate::backtrace_rs::{self, BacktraceFmt, BytesOrWideString, PrintFmt};
45use crate::borrow::Cow;
......@@ -62,73 +63,76 @@ unsafe fn _print_fmt(fmt: &mut fmt::Formatter<'_>, print_fmt: PrintFmt) -> fmt::
6263 // Start immediately if we're not using a short backtrace.
6364 let mut start = print_fmt != PrintFmt::Short;
6465 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 }
6972
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 }
9094 }
9195 }
92 }
9396
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;
105111 }
106 first_omit = false;
107 omitted_count = 0;
112 res = bt_fmt.frame().symbol(frame, symbol);
108113 }
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;
110127 }
111 });
112 #[cfg(target_os = "nto")]
113 if libc::__my_thread_exit as *mut libc::c_void == frame.ip() {
114128 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);
122130 }
123 return false;
124 }
125 if !hit && start {
126 res = bt_fmt.frame().print_raw(frame.ip(), None, None, None);
127 }
128131
129 idx += 1;
130 res.is_ok()
131 });
132 idx += 1;
133 res.is_ok()
134 })
135 };
132136 res?;
133137 bt_fmt.finish()?;
134138 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)]
12use crate::alloc::{GlobalAlloc, Layout, System};
23use crate::cmp;
34use crate::ptr;
......@@ -46,14 +47,16 @@ pub unsafe fn realloc_fallback(
4647 old_layout: Layout,
4748 new_size: usize,
4849) -> *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());
5153
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
5761 }
58 new_ptr
5962}
src/tools/clippy/clippy_lints/src/eta_reduction.rs+2-2
......@@ -15,7 +15,7 @@ use rustc_middle::ty::{
1515use rustc_session::declare_lint_pass;
1616use rustc_span::symbol::sym;
1717use rustc_target::spec::abi::Abi;
18use rustc_trait_selection::error_reporting::traits::InferCtxtExt as _;
18use rustc_trait_selection::error_reporting::InferCtxtErrorExt as _;
1919
2020declare_clippy_lint! {
2121 /// ### What it does
......@@ -178,7 +178,7 @@ impl<'tcx> LateLintPass<'tcx> for EtaReduction {
178178 // 'cuz currently nothing changes after deleting this check.
179179 local_used_in(cx, l, args) || local_used_after_expr(cx, l, expr)
180180 }) {
181 match cx.tcx.infer_ctxt().build().type_implements_fn_trait(
181 match cx.tcx.infer_ctxt().build().err_ctxt().type_implements_fn_trait(
182182 cx.param_env,
183183 Binder::bind_with_vars(callee_ty_adjusted, List::empty()),
184184 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 {
8282}
8383
8484/// The platform-specific library name
85fn get_lib_name(lib: &str, aux_type: AuxType) -> Option<String> {
85fn get_lib_name(name: &str, aux_type: AuxType) -> Option<String> {
8686 match aux_type {
8787 AuxType::Bin => None,
8888 // In some cases (e.g. MUSL), we build a static
8989 // library, rather than a dynamic library.
9090 // In this case, the only path we can pass
9191 // 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)),
10294 }
10395}
10496
97fn dylib_name(name: &str) -> String {
98 format!("{}{name}.{}", std::env::consts::DLL_PREFIX, std::env::consts::DLL_EXTENSION)
99}
100
105101pub fn run(config: Arc<Config>, testpaths: &TestPaths, revision: Option<&str>) {
106102 match &*config.target {
107103 "arm-linux-androideabi"
src/tools/miri/tests/fail/extern_static.rs+1-1
......@@ -5,5 +5,5 @@ extern "C" {
55}
66
77fn 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
99}
src/tools/miri/tests/fail/extern_static.stderr+2-2
......@@ -1,8 +1,8 @@
11error: unsupported operation: extern static `FOO` is not supported by Miri
22 --> $DIR/extern_static.rs:LL:CC
33 |
4LL | let _val = unsafe { std::ptr::addr_of!(FOO) };
5 | ^^^ extern static `FOO` is not supported by Miri
4LL | let _val = std::ptr::addr_of!(FOO);
5 | ^^^ extern static `FOO` is not supported by Miri
66 |
77 = help: this is likely not a bug in the program; it indicates that the program performed an operation that Miri does not support
88 = note: BACKTRACE:
src/tools/miri/tests/pass/static_mut.rs+1-1
......@@ -2,7 +2,7 @@ use std::ptr::addr_of;
22
33static mut FOO: i32 = 42;
44
5static BAR: Foo = Foo(unsafe { addr_of!(FOO) });
5static BAR: Foo = Foo(addr_of!(FOO));
66
77#[allow(dead_code)]
88struct Foo(*const i32);
tests/ui/consts/const_refs_to_static.rs+1-1
......@@ -9,7 +9,7 @@ const C1: &i32 = &S;
99const C1_READ: () = {
1010 assert!(*C1 == 0);
1111};
12const C2: *const i32 = unsafe { std::ptr::addr_of!(S_MUT) };
12const C2: *const i32 = std::ptr::addr_of!(S_MUT);
1313
1414fn main() {
1515 assert_eq!(*C1, 0);
tests/ui/consts/mut-ptr-to-static.rs+3-6
......@@ -16,12 +16,9 @@ static mut STATIC: u32 = 42;
1616static INTERIOR_MUTABLE_STATIC: SyncUnsafeCell<u32> = SyncUnsafeCell::new(42);
1717
1818// A static that mutably points to STATIC.
19static PTR: SyncPtr = SyncPtr {
20 foo: unsafe { ptr::addr_of_mut!(STATIC) },
21};
22static INTERIOR_MUTABLE_PTR: SyncPtr = SyncPtr {
23 foo: ptr::addr_of!(INTERIOR_MUTABLE_STATIC) as *mut u32,
24};
19static PTR: SyncPtr = SyncPtr { foo: ptr::addr_of_mut!(STATIC) };
20static INTERIOR_MUTABLE_PTR: SyncPtr =
21 SyncPtr { foo: ptr::addr_of!(INTERIOR_MUTABLE_STATIC) as *mut u32 };
2522
2623fn main() {
2724 let ptr = PTR.foo;
tests/ui/coroutine/coroutine-with-nll.stderr+8
......@@ -1,11 +1,19 @@
11error[E0626]: borrow may still be in use when coroutine yields
22 --> $DIR/coroutine-with-nll.rs:8:17
33 |
4LL | || {
5 | -- within this coroutine
6...
47LL | let b = &mut true;
58 | ^^^^^^^^^
69LL |
710LL | yield ();
811 | -------- possible yield occurs here
12 |
13help: add `static` to mark this coroutine as unmovable
14 |
15LL | static || {
16 | ++++++
917
1018error: aborting due to 1 previous error
1119
tests/ui/coroutine/issue-48048.stderr+8
......@@ -1,10 +1,18 @@
11error[E0626]: borrow may still be in use when coroutine yields
22 --> $DIR/issue-48048.rs:9:9
33 |
4LL | #[coroutine] || {
5 | -- within this coroutine
6...
47LL | x.0({
58 | ^^^
69LL | yield;
710 | ----- possible yield occurs here
11 |
12help: add `static` to mark this coroutine as unmovable
13 |
14LL | #[coroutine] static || {
15 | ++++++
816
917error: aborting due to 1 previous error
1018
tests/ui/coroutine/pattern-borrow.stderr+7
......@@ -1,10 +1,17 @@
11error[E0626]: borrow may still be in use when coroutine yields
22 --> $DIR/pattern-borrow.rs:9:24
33 |
4LL | #[coroutine] move || {
5 | ------- within this coroutine
46LL | if let Test::A(ref _a) = test {
57 | ^^^^^^
68LL | yield ();
79 | -------- possible yield occurs here
10 |
11help: add `static` to mark this coroutine as unmovable
12 |
13LL | #[coroutine] static move || {
14 | ++++++
815
916error: aborting due to 1 previous error
1017
tests/ui/coroutine/self_referential_gen_block.stderr+3
......@@ -1,6 +1,9 @@
11error[E0626]: borrow may still be in use when `gen` block yields
22 --> $DIR/self_referential_gen_block.rs:9:21
33 |
4LL | let mut x = gen {
5 | --- within this `gen` block
6LL | let y = 42;
47LL | let z = &y;
58 | ^^
69LL | yield 43;
tests/ui/coroutine/yield-in-args.stderr+8
......@@ -1,8 +1,16 @@
11error[E0626]: borrow may still be in use when coroutine yields
22 --> $DIR/yield-in-args.rs:9:13
33 |
4LL | || {
5 | -- within this coroutine
6LL | let b = true;
47LL | foo(&b, yield);
58 | ^^ ----- possible yield occurs here
9 |
10help: add `static` to mark this coroutine as unmovable
11 |
12LL | static || {
13 | ++++++
614
715error: aborting due to 1 previous error
816
tests/ui/coroutine/yield-while-iterating.stderr+7
......@@ -1,10 +1,17 @@
11error[E0626]: borrow may still be in use when coroutine yields
22 --> $DIR/yield-while-iterating.rs:13:18
33 |
4LL | let _b =#[coroutine] move || {
5 | ------- within this coroutine
46LL | for p in &x {
57 | ^^
68LL | yield();
79 | ------- possible yield occurs here
10 |
11help: add `static` to mark this coroutine as unmovable
12 |
13LL | let _b =#[coroutine] static move || {
14 | ++++++
815
916error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable
1017 --> $DIR/yield-while-iterating.rs:58:20
tests/ui/coroutine/yield-while-local-borrowed.stderr+15
......@@ -1,20 +1,35 @@
11error[E0626]: borrow may still be in use when coroutine yields
22 --> $DIR/yield-while-local-borrowed.rs:13:17
33 |
4LL | let mut b = #[coroutine] move || {
5 | ------- within this coroutine
46LL | let a = &mut 3;
57 | ^^^^^^
68LL |
79LL | yield ();
810 | -------- possible yield occurs here
11 |
12help: add `static` to mark this coroutine as unmovable
13 |
14LL | let mut b = #[coroutine] static move || {
15 | ++++++
916
1017error[E0626]: borrow may still be in use when coroutine yields
1118 --> $DIR/yield-while-local-borrowed.rs:40:21
1219 |
20LL | let mut b = #[coroutine] move || {
21 | ------- within this coroutine
22...
1323LL | let b = &a;
1424 | ^^
1525LL |
1626LL | yield ();
1727 | -------- possible yield occurs here
28 |
29help: add `static` to mark this coroutine as unmovable
30 |
31LL | let mut b = #[coroutine] static move || {
32 | ++++++
1833
1934error: aborting due to 2 previous errors
2035
tests/ui/nll/issue-55850.stderr+8
......@@ -10,8 +10,16 @@ LL | yield &s[..]
1010error[E0626]: borrow may still be in use when coroutine yields
1111 --> $DIR/issue-55850.rs:28:16
1212 |
13LL | GenIter(#[coroutine] move || {
14 | ------- within this coroutine
15LL | let mut s = String::new();
1316LL | yield &s[..]
1417 | -------^---- possible yield occurs here
18 |
19help: add `static` to mark this coroutine as unmovable
20 |
21LL | GenIter(#[coroutine] static move || {
22 | ++++++
1523
1624error: aborting due to 2 previous errors
1725
tests/ui/static/raw-ref-deref-with-unsafe.rs created+16
......@@ -0,0 +1,16 @@
1//@ check-pass
2#![feature(const_mut_refs)]
3use 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
8static mut BYTE: u8 = 0;
9static 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
12static mut DEREF_BYTE_PTR: *mut u8 = unsafe { ptr::addr_of_mut!(*BYTE_PTR) };
13
14fn 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
3use 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
8static mut BYTE: u8 = 0;
9static 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!
12static 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
16fn main() {
17 let _ = unsafe { DEREF_BYTE_PTR };
18}
tests/ui/static/raw-ref-deref-without-unsafe.stderr created+19
......@@ -0,0 +1,19 @@
1error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block
2 --> $DIR/raw-ref-deref-without-unsafe.rs:12:56
3 |
4LL | 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
9error[E0133]: use of mutable static is unsafe and requires unsafe function or block
10 --> $DIR/raw-ref-deref-without-unsafe.rs:12:57
11 |
12LL | 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
17error: aborting due to 2 previous errors
18
19For 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)]
3use 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
13extern "C" {
14 static THERE: u8;
15 static mut SOMEWHERE: u8;
16}
17
18fn 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)]
3use 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
8static mut NOWHERE: usize = 0;
9
10fn 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}