Rollup merge of #143084 - RalfJung:const-eval-recursive-static-write, r=oli-obk
const-eval: error when initializing a static writes to that static Fixes https://github.com/rust-lang/rust/issues/142404 by also calling the relevant hook for writes, not just reads. To avoid erroring during the actual write of the initial value, we neuter the hook when popping the final stack frame. Calling the hook during writes requires changing its signature since we cannot pass in the entire interpreter any more. While doing this I also realized a gap in https://github.com/rust-lang/rust/pull/142575 for zero-sized copies on the read side, so I fixed that and added a test. r? `@oli-obk`
This commit is contained in:
@@ -352,7 +352,7 @@ const_eval_realloc_or_alloc_with_offset =
|
|||||||
*[other] {""}
|
*[other] {""}
|
||||||
} {$ptr} which does not point to the beginning of an object
|
} {$ptr} which does not point to the beginning of an object
|
||||||
|
|
||||||
const_eval_recursive_static = encountered static that tried to initialize itself with itself
|
const_eval_recursive_static = encountered static that tried to access itself during initialization
|
||||||
|
|
||||||
const_eval_remainder_by_zero =
|
const_eval_remainder_by_zero =
|
||||||
calculating the remainder with a divisor of zero
|
calculating the remainder with a divisor of zero
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ pub struct CompileTimeMachine<'tcx> {
|
|||||||
|
|
||||||
/// If `Some`, we are evaluating the initializer of the static with the given `LocalDefId`,
|
/// If `Some`, we are evaluating the initializer of the static with the given `LocalDefId`,
|
||||||
/// storing the result in the given `AllocId`.
|
/// storing the result in the given `AllocId`.
|
||||||
/// Used to prevent reads from a static's base allocation, as that may allow for self-initialization loops.
|
/// Used to prevent accesses to a static's base allocation, as that may allow for self-initialization loops.
|
||||||
pub(crate) static_root_ids: Option<(AllocId, LocalDefId)>,
|
pub(crate) static_root_ids: Option<(AllocId, LocalDefId)>,
|
||||||
|
|
||||||
/// A cache of "data range" computations for unions (i.e., the offsets of non-padding bytes).
|
/// A cache of "data range" computations for unions (i.e., the offsets of non-padding bytes).
|
||||||
@@ -705,19 +705,27 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> {
|
|||||||
interp_ok(())
|
interp_ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn before_alloc_read(ecx: &InterpCx<'tcx, Self>, alloc_id: AllocId) -> InterpResult<'tcx> {
|
fn before_alloc_access(
|
||||||
|
tcx: TyCtxtAt<'tcx>,
|
||||||
|
machine: &Self,
|
||||||
|
alloc_id: AllocId,
|
||||||
|
) -> InterpResult<'tcx> {
|
||||||
|
if machine.stack.is_empty() {
|
||||||
|
// Get out of the way for the final copy.
|
||||||
|
return interp_ok(());
|
||||||
|
}
|
||||||
// Check if this is the currently evaluated static.
|
// Check if this is the currently evaluated static.
|
||||||
if Some(alloc_id) == ecx.machine.static_root_ids.map(|(id, _)| id) {
|
if Some(alloc_id) == machine.static_root_ids.map(|(id, _)| id) {
|
||||||
return Err(ConstEvalErrKind::RecursiveStatic).into();
|
return Err(ConstEvalErrKind::RecursiveStatic).into();
|
||||||
}
|
}
|
||||||
// If this is another static, make sure we fire off the query to detect cycles.
|
// If this is another static, make sure we fire off the query to detect cycles.
|
||||||
// But only do that when checks for static recursion are enabled.
|
// But only do that when checks for static recursion are enabled.
|
||||||
if ecx.machine.static_root_ids.is_some() {
|
if machine.static_root_ids.is_some() {
|
||||||
if let Some(GlobalAlloc::Static(def_id)) = ecx.tcx.try_get_global_alloc(alloc_id) {
|
if let Some(GlobalAlloc::Static(def_id)) = tcx.try_get_global_alloc(alloc_id) {
|
||||||
if ecx.tcx.is_foreign_item(def_id) {
|
if tcx.is_foreign_item(def_id) {
|
||||||
throw_unsup!(ExternStatic(def_id));
|
throw_unsup!(ExternStatic(def_id));
|
||||||
}
|
}
|
||||||
ecx.ctfe_query(|tcx| tcx.eval_static_initializer(def_id))?;
|
tcx.eval_static_initializer(def_id)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
interp_ok(())
|
interp_ok(())
|
||||||
|
|||||||
@@ -443,7 +443,11 @@ pub trait Machine<'tcx>: Sized {
|
|||||||
///
|
///
|
||||||
/// Used to prevent statics from self-initializing by reading from their own memory
|
/// Used to prevent statics from self-initializing by reading from their own memory
|
||||||
/// as it is being initialized.
|
/// as it is being initialized.
|
||||||
fn before_alloc_read(_ecx: &InterpCx<'tcx, Self>, _alloc_id: AllocId) -> InterpResult<'tcx> {
|
fn before_alloc_access(
|
||||||
|
_tcx: TyCtxtAt<'tcx>,
|
||||||
|
_machine: &Self,
|
||||||
|
_alloc_id: AllocId,
|
||||||
|
) -> InterpResult<'tcx> {
|
||||||
interp_ok(())
|
interp_ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -720,7 +720,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||||||
// do this after `check_and_deref_ptr` to ensure some basic sanity has already been checked.
|
// do this after `check_and_deref_ptr` to ensure some basic sanity has already been checked.
|
||||||
if !self.memory.validation_in_progress.get() {
|
if !self.memory.validation_in_progress.get() {
|
||||||
if let Ok((alloc_id, ..)) = self.ptr_try_get_alloc_id(ptr, size_i64) {
|
if let Ok((alloc_id, ..)) = self.ptr_try_get_alloc_id(ptr, size_i64) {
|
||||||
M::before_alloc_read(self, alloc_id)?;
|
M::before_alloc_access(self.tcx, &self.machine, alloc_id)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -821,6 +821,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||||||
if let Some((alloc_id, offset, prov, alloc, machine)) = ptr_and_alloc {
|
if let Some((alloc_id, offset, prov, alloc, machine)) = ptr_and_alloc {
|
||||||
let range = alloc_range(offset, size);
|
let range = alloc_range(offset, size);
|
||||||
if !validation_in_progress {
|
if !validation_in_progress {
|
||||||
|
// For writes, it's okay to only call those when there actually is a non-zero
|
||||||
|
// amount of bytes to be written: a zero-sized write doesn't manifest anything.
|
||||||
|
M::before_alloc_access(tcx, machine, alloc_id)?;
|
||||||
M::before_memory_write(
|
M::before_memory_write(
|
||||||
tcx,
|
tcx,
|
||||||
machine,
|
machine,
|
||||||
@@ -1396,6 +1399,14 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||||||
let src_parts = self.get_ptr_access(src, size)?;
|
let src_parts = self.get_ptr_access(src, size)?;
|
||||||
let dest_parts = self.get_ptr_access(dest, size * num_copies)?; // `Size` multiplication
|
let dest_parts = self.get_ptr_access(dest, size * num_copies)?; // `Size` multiplication
|
||||||
|
|
||||||
|
// Similar to `get_ptr_alloc`, we need to call `before_alloc_access` even for zero-sized
|
||||||
|
// reads. However, just like in `get_ptr_alloc_mut`, the write part is okay to skip for
|
||||||
|
// zero-sized writes.
|
||||||
|
if let Ok((alloc_id, ..)) = self.ptr_try_get_alloc_id(src, size.bytes().try_into().unwrap())
|
||||||
|
{
|
||||||
|
M::before_alloc_access(tcx, &self.machine, alloc_id)?;
|
||||||
|
}
|
||||||
|
|
||||||
// FIXME: we look up both allocations twice here, once before for the `check_ptr_access`
|
// FIXME: we look up both allocations twice here, once before for the `check_ptr_access`
|
||||||
// and once below to get the underlying `&[mut] Allocation`.
|
// and once below to get the underlying `&[mut] Allocation`.
|
||||||
|
|
||||||
@@ -1408,12 +1419,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||||||
let src_range = alloc_range(src_offset, size);
|
let src_range = alloc_range(src_offset, size);
|
||||||
assert!(!self.memory.validation_in_progress.get(), "we can't be copying during validation");
|
assert!(!self.memory.validation_in_progress.get(), "we can't be copying during validation");
|
||||||
|
|
||||||
// Trigger read hooks.
|
// Trigger read hook.
|
||||||
// For the overlapping case, it is crucial that we trigger the read hooks
|
// For the overlapping case, it is crucial that we trigger the read hook
|
||||||
// before the write hook -- the aliasing model cares about the order.
|
// before the write hook -- the aliasing model cares about the order.
|
||||||
if let Ok((alloc_id, ..)) = self.ptr_try_get_alloc_id(src, size.bytes() as i64) {
|
|
||||||
M::before_alloc_read(self, alloc_id)?;
|
|
||||||
}
|
|
||||||
M::before_memory_read(
|
M::before_memory_read(
|
||||||
tcx,
|
tcx,
|
||||||
&self.machine,
|
&self.machine,
|
||||||
@@ -1438,16 +1446,18 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||||||
let provenance = src_alloc
|
let provenance = src_alloc
|
||||||
.provenance()
|
.provenance()
|
||||||
.prepare_copy(src_range, dest_offset, num_copies, self)
|
.prepare_copy(src_range, dest_offset, num_copies, self)
|
||||||
.map_err(|e| e.to_interp_error(dest_alloc_id))?;
|
.map_err(|e| e.to_interp_error(src_alloc_id))?;
|
||||||
// Prepare a copy of the initialization mask.
|
// Prepare a copy of the initialization mask.
|
||||||
let init = src_alloc.init_mask().prepare_copy(src_range);
|
let init = src_alloc.init_mask().prepare_copy(src_range);
|
||||||
|
|
||||||
// Destination alloc preparations and access hooks.
|
// Destination alloc preparations...
|
||||||
let (dest_alloc, extra) = self.get_alloc_raw_mut(dest_alloc_id)?;
|
let (dest_alloc, machine) = self.get_alloc_raw_mut(dest_alloc_id)?;
|
||||||
let dest_range = alloc_range(dest_offset, size * num_copies);
|
let dest_range = alloc_range(dest_offset, size * num_copies);
|
||||||
|
// ...and access hooks.
|
||||||
|
M::before_alloc_access(tcx, machine, dest_alloc_id)?;
|
||||||
M::before_memory_write(
|
M::before_memory_write(
|
||||||
tcx,
|
tcx,
|
||||||
extra,
|
machine,
|
||||||
&mut dest_alloc.extra,
|
&mut dest_alloc.extra,
|
||||||
dest,
|
dest,
|
||||||
(dest_alloc_id, dest_prov),
|
(dest_alloc_id, dest_prov),
|
||||||
|
|||||||
24
tests/ui/consts/recursive-static-write.rs
Normal file
24
tests/ui/consts/recursive-static-write.rs
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
//! Ensure that writing to `S` while initializing `S` errors.
|
||||||
|
//! Regression test for <https://github.com/rust-lang/rust/issues/142404>.
|
||||||
|
#![allow(dead_code)]
|
||||||
|
|
||||||
|
struct Foo {
|
||||||
|
x: i32,
|
||||||
|
y: (),
|
||||||
|
}
|
||||||
|
|
||||||
|
static S: Foo = Foo {
|
||||||
|
x: 0,
|
||||||
|
y: unsafe {
|
||||||
|
(&raw const S.x).cast_mut().write(1); //~ERROR access itself during initialization
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static mut S2: Foo = Foo {
|
||||||
|
x: 0,
|
||||||
|
y: unsafe {
|
||||||
|
S2.x = 1; //~ERROR access itself during initialization
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
fn main() {}
|
||||||
15
tests/ui/consts/recursive-static-write.stderr
Normal file
15
tests/ui/consts/recursive-static-write.stderr
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
error[E0080]: encountered static that tried to access itself during initialization
|
||||||
|
--> $DIR/recursive-static-write.rs:13:9
|
||||||
|
|
|
||||||
|
LL | (&raw const S.x).cast_mut().write(1);
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `S` failed here
|
||||||
|
|
||||||
|
error[E0080]: encountered static that tried to access itself during initialization
|
||||||
|
--> $DIR/recursive-static-write.rs:20:9
|
||||||
|
|
|
||||||
|
LL | S2.x = 1;
|
||||||
|
| ^^^^^^^^ evaluation of `S2` failed here
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0080`.
|
||||||
@@ -1,20 +1,20 @@
|
|||||||
error[E0080]: encountered static that tried to initialize itself with itself
|
error[E0080]: encountered static that tried to access itself during initialization
|
||||||
--> $DIR/recursive-zst-static.rs:10:18
|
--> $DIR/recursive-zst-static.rs:10:18
|
||||||
|
|
|
|
||||||
LL | static FOO: () = FOO;
|
LL | static FOO: () = FOO;
|
||||||
| ^^^ evaluation of `FOO` failed here
|
| ^^^ evaluation of `FOO` failed here
|
||||||
|
|
||||||
error[E0391]: cycle detected when evaluating initializer of static `A`
|
error[E0391]: cycle detected when evaluating initializer of static `A`
|
||||||
--> $DIR/recursive-zst-static.rs:13:16
|
--> $DIR/recursive-zst-static.rs:13:1
|
||||||
|
|
|
|
||||||
LL | static A: () = B;
|
LL | static A: () = B;
|
||||||
| ^
|
| ^^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
note: ...which requires evaluating initializer of static `B`...
|
note: ...which requires evaluating initializer of static `B`...
|
||||||
--> $DIR/recursive-zst-static.rs:14:16
|
--> $DIR/recursive-zst-static.rs:14:1
|
||||||
|
|
|
|
||||||
LL | static B: () = A;
|
LL | static B: () = A;
|
||||||
| ^
|
| ^^^^^^^^^^^^
|
||||||
= note: ...which again requires evaluating initializer of static `A`, completing the cycle
|
= note: ...which again requires evaluating initializer of static `A`, completing the cycle
|
||||||
= note: cycle used when running analysis passes on this crate
|
= note: cycle used when running analysis passes on this crate
|
||||||
= note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
|
= note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
// See https://github.com/rust-lang/rust/issues/71078 for more details.
|
// See https://github.com/rust-lang/rust/issues/71078 for more details.
|
||||||
|
|
||||||
static FOO: () = FOO;
|
static FOO: () = FOO;
|
||||||
//~^ ERROR encountered static that tried to initialize itself with itself
|
//~^ ERROR encountered static that tried to access itself during initialization
|
||||||
|
|
||||||
static A: () = B; //~ ERROR cycle detected when evaluating initializer of static `A`
|
static A: () = B; //~ ERROR cycle detected when evaluating initializer of static `A`
|
||||||
static B: () = A;
|
static B: () = A;
|
||||||
|
|||||||
@@ -1,20 +1,20 @@
|
|||||||
error[E0080]: encountered static that tried to initialize itself with itself
|
error[E0080]: encountered static that tried to access itself during initialization
|
||||||
--> $DIR/recursive-zst-static.rs:10:18
|
--> $DIR/recursive-zst-static.rs:10:18
|
||||||
|
|
|
|
||||||
LL | static FOO: () = FOO;
|
LL | static FOO: () = FOO;
|
||||||
| ^^^ evaluation of `FOO` failed here
|
| ^^^ evaluation of `FOO` failed here
|
||||||
|
|
||||||
error[E0391]: cycle detected when evaluating initializer of static `A`
|
error[E0391]: cycle detected when evaluating initializer of static `A`
|
||||||
--> $DIR/recursive-zst-static.rs:13:16
|
--> $DIR/recursive-zst-static.rs:13:1
|
||||||
|
|
|
|
||||||
LL | static A: () = B;
|
LL | static A: () = B;
|
||||||
| ^
|
| ^^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
note: ...which requires evaluating initializer of static `B`...
|
note: ...which requires evaluating initializer of static `B`...
|
||||||
--> $DIR/recursive-zst-static.rs:14:16
|
--> $DIR/recursive-zst-static.rs:14:1
|
||||||
|
|
|
|
||||||
LL | static B: () = A;
|
LL | static B: () = A;
|
||||||
| ^
|
| ^^^^^^^^^^^^
|
||||||
= note: ...which again requires evaluating initializer of static `A`, completing the cycle
|
= note: ...which again requires evaluating initializer of static `A`, completing the cycle
|
||||||
= note: cycle used when running analysis passes on this crate
|
= note: cycle used when running analysis passes on this crate
|
||||||
= note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
|
= note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
|
||||||
|
|||||||
@@ -3,8 +3,9 @@ pub static mut B: () = unsafe { A = 1; };
|
|||||||
//~^ ERROR modifying a static's initial value
|
//~^ ERROR modifying a static's initial value
|
||||||
|
|
||||||
pub static mut C: u32 = unsafe { C = 1; 0 };
|
pub static mut C: u32 = unsafe { C = 1; 0 };
|
||||||
|
//~^ ERROR static that tried to access itself during initialization
|
||||||
|
|
||||||
pub static D: u32 = D;
|
pub static D: u32 = D;
|
||||||
//~^ ERROR static that tried to initialize itself with itself
|
//~^ ERROR static that tried to access itself during initialization
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
|||||||
@@ -4,12 +4,18 @@ error[E0080]: modifying a static's initial value from another static's initializ
|
|||||||
LL | pub static mut B: () = unsafe { A = 1; };
|
LL | pub static mut B: () = unsafe { A = 1; };
|
||||||
| ^^^^^ evaluation of `B` failed here
|
| ^^^^^ evaluation of `B` failed here
|
||||||
|
|
||||||
error[E0080]: encountered static that tried to initialize itself with itself
|
error[E0080]: encountered static that tried to access itself during initialization
|
||||||
--> $DIR/write-to-static-mut-in-static.rs:7:21
|
--> $DIR/write-to-static-mut-in-static.rs:5:34
|
||||||
|
|
|
||||||
|
LL | pub static mut C: u32 = unsafe { C = 1; 0 };
|
||||||
|
| ^^^^^ evaluation of `C` failed here
|
||||||
|
|
||||||
|
error[E0080]: encountered static that tried to access itself during initialization
|
||||||
|
--> $DIR/write-to-static-mut-in-static.rs:8:21
|
||||||
|
|
|
|
||||||
LL | pub static D: u32 = D;
|
LL | pub static D: u32 = D;
|
||||||
| ^ evaluation of `D` failed here
|
| ^ evaluation of `D` failed here
|
||||||
|
|
||||||
error: aborting due to 2 previous errors
|
error: aborting due to 3 previous errors
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0080`.
|
For more information about this error, try `rustc --explain E0080`.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
pub static FOO: u32 = FOO;
|
pub static FOO: u32 = FOO;
|
||||||
//~^ ERROR encountered static that tried to initialize itself with itself
|
//~^ ERROR encountered static that tried to access itself during initialization
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
pub union Foo {
|
pub union Foo {
|
||||||
@@ -7,6 +7,6 @@ pub union Foo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub static BAR: Foo = BAR;
|
pub static BAR: Foo = BAR;
|
||||||
//~^ ERROR encountered static that tried to initialize itself with itself
|
//~^ ERROR encountered static that tried to access itself during initialization
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
error[E0080]: encountered static that tried to initialize itself with itself
|
error[E0080]: encountered static that tried to access itself during initialization
|
||||||
--> $DIR/recursive-static-definition.rs:1:23
|
--> $DIR/recursive-static-definition.rs:1:23
|
||||||
|
|
|
|
||||||
LL | pub static FOO: u32 = FOO;
|
LL | pub static FOO: u32 = FOO;
|
||||||
| ^^^ evaluation of `FOO` failed here
|
| ^^^ evaluation of `FOO` failed here
|
||||||
|
|
||||||
error[E0080]: encountered static that tried to initialize itself with itself
|
error[E0080]: encountered static that tried to access itself during initialization
|
||||||
--> $DIR/recursive-static-definition.rs:9:23
|
--> $DIR/recursive-static-definition.rs:9:23
|
||||||
|
|
|
|
||||||
LL | pub static BAR: Foo = BAR;
|
LL | pub static BAR: Foo = BAR;
|
||||||
|
|||||||
@@ -8,13 +8,15 @@
|
|||||||
|
|
||||||
use std::mem::MaybeUninit;
|
use std::mem::MaybeUninit;
|
||||||
|
|
||||||
pub static X: (i32, MaybeUninit<i32>) = (1, foo(&X.0));
|
pub static X: (i32, MaybeUninit<i32>) = (1, foo(&X.0, 1));
|
||||||
//~^ ERROR: encountered static that tried to initialize itself with itself
|
//~^ ERROR: encountered static that tried to access itself during initialization
|
||||||
|
pub static Y: (i32, MaybeUninit<i32>) = (1, foo(&Y.0, 0));
|
||||||
|
//~^ ERROR: encountered static that tried to access itself during initialization
|
||||||
|
|
||||||
const fn foo(x: &i32) -> MaybeUninit<i32> {
|
const fn foo(x: &i32, num: usize) -> MaybeUninit<i32> {
|
||||||
let mut temp = MaybeUninit::<i32>::uninit();
|
let mut temp = MaybeUninit::<i32>::uninit();
|
||||||
unsafe {
|
unsafe {
|
||||||
std::ptr::copy(x, temp.as_mut_ptr(), 1);
|
std::ptr::copy(x, temp.as_mut_ptr(), num);
|
||||||
}
|
}
|
||||||
temp
|
temp
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,17 +1,31 @@
|
|||||||
error[E0080]: encountered static that tried to initialize itself with itself
|
error[E0080]: encountered static that tried to access itself during initialization
|
||||||
--> $DIR/read_before_init.rs:11:45
|
--> $DIR/read_before_init.rs:11:45
|
||||||
|
|
|
|
||||||
LL | pub static X: (i32, MaybeUninit<i32>) = (1, foo(&X.0));
|
LL | pub static X: (i32, MaybeUninit<i32>) = (1, foo(&X.0, 1));
|
||||||
| ^^^^^^^^^ evaluation of `X` failed inside this call
|
| ^^^^^^^^^^^^ evaluation of `X` failed inside this call
|
||||||
|
|
|
|
||||||
note: inside `foo`
|
note: inside `foo`
|
||||||
--> $DIR/read_before_init.rs:17:9
|
--> $DIR/read_before_init.rs:19:9
|
||||||
|
|
|
|
||||||
LL | std::ptr::copy(x, temp.as_mut_ptr(), 1);
|
LL | std::ptr::copy(x, temp.as_mut_ptr(), num);
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
note: inside `std::ptr::copy::<i32>`
|
note: inside `std::ptr::copy::<i32>`
|
||||||
--> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
|
--> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
|
||||||
|
|
||||||
error: aborting due to 1 previous error
|
error[E0080]: encountered static that tried to access itself during initialization
|
||||||
|
--> $DIR/read_before_init.rs:13:45
|
||||||
|
|
|
||||||
|
LL | pub static Y: (i32, MaybeUninit<i32>) = (1, foo(&Y.0, 0));
|
||||||
|
| ^^^^^^^^^^^^ evaluation of `Y` failed inside this call
|
||||||
|
|
|
||||||
|
note: inside `foo`
|
||||||
|
--> $DIR/read_before_init.rs:19:9
|
||||||
|
|
|
||||||
|
LL | std::ptr::copy(x, temp.as_mut_ptr(), num);
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
note: inside `std::ptr::copy::<i32>`
|
||||||
|
--> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0080`.
|
For more information about this error, try `rustc --explain E0080`.
|
||||||
|
|||||||
Reference in New Issue
Block a user