Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit d53dc75

Browse files
committedJul 23, 2024
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
2 parents d111ccd + f8373ad commit d53dc75

File tree

33 files changed

+567
-366
lines changed

33 files changed

+567
-366
lines changed
 

‎compiler/rustc_borrowck/src/borrowck_errors.rs

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
#![allow(rustc::diagnostic_outside_of_impl)]
22
#![allow(rustc::untranslatable_diagnostic)]
33

4+
use rustc_errors::Applicability;
45
use rustc_errors::{codes::*, struct_span_code_err, Diag, DiagCtxtHandle};
6+
use rustc_hir as hir;
57
use rustc_middle::span_bug;
68
use rustc_middle::ty::{self, Ty, TyCtxt};
79
use 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

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -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
22
yield point.
33

44
Erroneous code example:
@@ -15,19 +15,35 @@ let mut b = #[coroutine] || {
1515
Pin::new(&mut b).resume(());
1616
```
1717

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

2541
```
2642
# #![feature(coroutines, coroutine_trait, stmt_expr_attributes)]
2743
# use std::ops::Coroutine;
2844
# use std::pin::Pin;
2945
let 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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ use rustc_span::def_id::LocalDefId;
1818
use rustc_span::Span;
1919
use rustc_target::spec::abi::Abi;
2020
use rustc_trait_selection::error_reporting::traits::ArgKind;
21-
use rustc_trait_selection::error_reporting::traits::InferCtxtExt as _;
2221
use rustc_trait_selection::traits;
2322
use rustc_type_ir::ClosureKind;
2423
use 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

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ use rustc_middle::{
1212
use rustc_span::{def_id::DefId, sym, BytePos, Span, Symbol};
1313

1414
use crate::error_reporting::TypeErrCtxt;
15+
use crate::infer::InferCtxtExt;
1516

1617
impl<'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

Lines changed: 233 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
use super::on_unimplemented::{AppendConstMessage, OnUnimplementedNote};
22
use super::suggestions::get_explanation_based_on_obligation;
33
use crate::error_reporting::infer::TyCategory;
4-
use crate::error_reporting::traits::infer_ctxt_ext::InferCtxtExt;
54
use crate::error_reporting::traits::report_object_safety_error;
65
use crate::error_reporting::TypeErrCtxt;
76
use 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

Lines changed: 0 additions & 244 deletions
This file was deleted.

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

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
pub mod ambiguity;
22
mod fulfillment_errors;
3-
mod infer_ctxt_ext;
43
pub mod on_unimplemented;
54
mod overflow;
65
pub mod suggestions;
@@ -23,7 +22,6 @@ use rustc_span::{ErrorGuaranteed, ExpnKind, Span};
2322
use crate::error_reporting::TypeErrCtxt;
2423
use crate::traits::{FulfillmentError, FulfillmentErrorCode};
2524

26-
pub use self::infer_ctxt_ext::*;
2725
pub use self::overflow::*;
2826

2927
// When outputting impl candidates, prefer showing those that are more similar.

‎library/panic_unwind/src/seh.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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.
252255
static 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

Lines changed: 61 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
//! Common code for printing backtraces.
2+
#![forbid(unsafe_op_in_unsafe_fn)]
23

34
use crate::backtrace_rs::{self, BacktraceFmt, BytesOrWideString, PrintFmt};
45
use 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

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
#![forbid(unsafe_op_in_unsafe_fn)]
12
use crate::alloc::{GlobalAlloc, Layout, System};
23
use crate::cmp;
34
use 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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use rustc_middle::ty::{
1515
use rustc_session::declare_lint_pass;
1616
use rustc_span::symbol::sym;
1717
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 _;
1919

2020
declare_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

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -82,26 +82,22 @@ fn disable_error_reporting<F: FnOnce() -> R, R>(f: F) -> R {
8282
}
8383

8484
/// 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> {
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

97+
fn dylib_name(name: &str) -> String {
98+
format!("{}{name}.{}", std::env::consts::DLL_PREFIX, std::env::consts::DLL_EXTENSION)
99+
}
100+
105101
pub 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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,5 @@ extern "C" {
55
}
66

77
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
99
}

‎src/tools/miri/tests/fail/extern_static.stderr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
error: unsupported operation: extern static `FOO` is not supported by Miri
22
--> $DIR/extern_static.rs:LL:CC
33
|
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
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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use std::ptr::addr_of;
22

33
static mut FOO: i32 = 42;
44

5-
static BAR: Foo = Foo(unsafe { addr_of!(FOO) });
5+
static BAR: Foo = Foo(addr_of!(FOO));
66

77
#[allow(dead_code)]
88
struct Foo(*const i32);

‎tests/ui/consts/const_refs_to_static.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ const C1: &i32 = &S;
99
const C1_READ: () = {
1010
assert!(*C1 == 0);
1111
};
12-
const C2: *const i32 = unsafe { std::ptr::addr_of!(S_MUT) };
12+
const C2: *const i32 = std::ptr::addr_of!(S_MUT);
1313

1414
fn main() {
1515
assert_eq!(*C1, 0);

‎tests/ui/consts/mut-ptr-to-static.rs

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,9 @@ static mut STATIC: u32 = 42;
1616
static INTERIOR_MUTABLE_STATIC: SyncUnsafeCell<u32> = SyncUnsafeCell::new(42);
1717

1818
// 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 };
2522

2623
fn main() {
2724
let ptr = PTR.foo;

‎tests/ui/coroutine/coroutine-with-nll.stderr

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,19 @@
11
error[E0626]: borrow may still be in use when coroutine yields
22
--> $DIR/coroutine-with-nll.rs:8:17
33
|
4+
LL | || {
5+
| -- within this coroutine
6+
...
47
LL | let b = &mut true;
58
| ^^^^^^^^^
69
LL |
710
LL | yield ();
811
| -------- possible yield occurs here
12+
|
13+
help: add `static` to mark this coroutine as unmovable
14+
|
15+
LL | static || {
16+
| ++++++
917

1018
error: aborting due to 1 previous error
1119

‎tests/ui/coroutine/issue-48048.stderr

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,18 @@
11
error[E0626]: borrow may still be in use when coroutine yields
22
--> $DIR/issue-48048.rs:9:9
33
|
4+
LL | #[coroutine] || {
5+
| -- within this coroutine
6+
...
47
LL | x.0({
58
| ^^^
69
LL | yield;
710
| ----- possible yield occurs here
11+
|
12+
help: add `static` to mark this coroutine as unmovable
13+
|
14+
LL | #[coroutine] static || {
15+
| ++++++
816

917
error: aborting due to 1 previous error
1018

‎tests/ui/coroutine/pattern-borrow.stderr

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,17 @@
11
error[E0626]: borrow may still be in use when coroutine yields
22
--> $DIR/pattern-borrow.rs:9:24
33
|
4+
LL | #[coroutine] move || {
5+
| ------- within this coroutine
46
LL | if let Test::A(ref _a) = test {
57
| ^^^^^^
68
LL | yield ();
79
| -------- possible yield occurs here
10+
|
11+
help: add `static` to mark this coroutine as unmovable
12+
|
13+
LL | #[coroutine] static move || {
14+
| ++++++
815

916
error: aborting due to 1 previous error
1017

‎tests/ui/coroutine/self_referential_gen_block.stderr

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
error[E0626]: borrow may still be in use when `gen` block yields
22
--> $DIR/self_referential_gen_block.rs:9:21
33
|
4+
LL | let mut x = gen {
5+
| --- within this `gen` block
6+
LL | let y = 42;
47
LL | let z = &y;
58
| ^^
69
LL | yield 43;

‎tests/ui/coroutine/yield-in-args.stderr

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,16 @@
11
error[E0626]: borrow may still be in use when coroutine yields
22
--> $DIR/yield-in-args.rs:9:13
33
|
4+
LL | || {
5+
| -- within this coroutine
6+
LL | let b = true;
47
LL | foo(&b, yield);
58
| ^^ ----- possible yield occurs here
9+
|
10+
help: add `static` to mark this coroutine as unmovable
11+
|
12+
LL | static || {
13+
| ++++++
614

715
error: aborting due to 1 previous error
816

‎tests/ui/coroutine/yield-while-iterating.stderr

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,17 @@
11
error[E0626]: borrow may still be in use when coroutine yields
22
--> $DIR/yield-while-iterating.rs:13:18
33
|
4+
LL | let _b =#[coroutine] move || {
5+
| ------- within this coroutine
46
LL | for p in &x {
57
| ^^
68
LL | yield();
79
| ------- possible yield occurs here
10+
|
11+
help: add `static` to mark this coroutine as unmovable
12+
|
13+
LL | let _b =#[coroutine] static move || {
14+
| ++++++
815

916
error[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

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,35 @@
11
error[E0626]: borrow may still be in use when coroutine yields
22
--> $DIR/yield-while-local-borrowed.rs:13:17
33
|
4+
LL | let mut b = #[coroutine] move || {
5+
| ------- within this coroutine
46
LL | let a = &mut 3;
57
| ^^^^^^
68
LL |
79
LL | yield ();
810
| -------- 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+
| ++++++
916

1017
error[E0626]: borrow may still be in use when coroutine yields
1118
--> $DIR/yield-while-local-borrowed.rs:40:21
1219
|
20+
LL | let mut b = #[coroutine] move || {
21+
| ------- within this coroutine
22+
...
1323
LL | let b = &a;
1424
| ^^
1525
LL |
1626
LL | yield ();
1727
| -------- 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+
| ++++++
1833

1934
error: aborting due to 2 previous errors
2035

‎tests/ui/nll/issue-55850.stderr

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,16 @@ LL | yield &s[..]
1010
error[E0626]: borrow may still be in use when coroutine yields
1111
--> $DIR/issue-55850.rs:28:16
1212
|
13+
LL | GenIter(#[coroutine] move || {
14+
| ------- within this coroutine
15+
LL | let mut s = String::new();
1316
LL | yield &s[..]
1417
| -------^---- possible yield occurs here
18+
|
19+
help: add `static` to mark this coroutine as unmovable
20+
|
21+
LL | GenIter(#[coroutine] static move || {
22+
| ++++++
1523

1624
error: aborting due to 2 previous errors
1725

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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`.
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
}

0 commit comments

Comments
 (0)
Please sign in to comment.