This looks unintentional, and has been broken in all cases, until a few releases ago, AFAICT.
Should this be covered by WF rules? cc @rust-lang/lang @ubsan @solson
Unsized constants cause an ICE, in both old trans and MIR trans:
// rustc_trans/consts.rs:445: const expr(35: &S) of type &str has size 8 instead of 16
// rustc_trans/mir/constant.rs:175: loading from `str`
// ((i8*:i8* getelementptr inbounds ([3 x i8], [3 x i8]* @str7144, i32 0, i32 0)))
// in constant
const S: str = *"foo";
fn main() { println!("{}", &S); }
Unsized statics appear to work, but only in old trans:
use std::fmt::Debug;
static FOO: Debug+Sync = *(&1 as &(Debug+Sync));
static S: str = *"foo";
fn main() { println!("{:?} {}", &FOO, &S); }
I believe this is possible because a constant DST lvalue in old trans is merely the fat pointer.
It seems useful to allow an unsized static, but IMO it should require a sized RHS instead, i.e.:
static A: [i32] = [1, 2, 3];
fn main() { let x = A[0]; ... }
// as sugar for:
static A_SIZED: [i32; 3] = [1, 2, 3];
static A: &'static [i32] = &A_SIZED;
fn main() { let x = (*A)[0]; ... }
And, of course, this should all go through the RFC process, to figure out all the finer details.
Should it be
// as sugar for:
const A: &'static [i32] = &[1, 2, 3];
fn main() { let x = (*A)[0]; ... }
? I don't think A needs to be an lvalue.
It makes more sense for constants, but I gave the example with static because that's the only one that works today (although by accident).
Hmm? I mean the static is desugared into a const. const A: &'static [i32] = &[1, 2, 3]; works today.
The idea being that a static and a const reference both give access to one lvalue.
@Ericson2314 No, static has different semantics: it allows an UnsafeCell somewhere within and is guaranteed not to be duplicated.
Hmm?
#![feature(const_fn)]
use std::fmt::Debug;
use std::cell::UnsafeCell;
#[derive(Debug)]
struct Doop(UnsafeCell<u32>);
unsafe impl Send for Doop {}
unsafe impl Sync for Doop {}
//const ASDF: &'static (Debug + Sync) = &Doop(UnsafeCell::new(1));
static ASDF: &'static (Debug + Sync) = &Doop(UnsafeCell::new(1));
fn main() {
println!("{:#?}", ASDF);
}
Both of these gives me a "error: cannot borrow a constant which contains interior mutability, create a static instead". This is what I'd suspect as the lvalue from the promoted Doop(..) has nothing to do with ASDF being a static or a const.
@Ericson2314 Let me rewrite my desugaring to account for that, oops.
#![feature(const_fn)]
use std::fmt::Debug;
use std::cell::UnsafeCell;
#[derive(Debug)]
struct Doop(UnsafeCell<u32>);
unsafe impl Send for Doop {}
unsafe impl Sync for Doop {}
static ASDF_INNER: Doop = Doop(UnsafeCell::new(1));
//static ASDF: &'static (Debug + Sync) = &ASDF_INNER;
const ASDF: &'static (Debug + Sync) = &ASDF_INNER;
fn main() {
println!("{:#?}", ASDF);
}
Oh and my confusion really just stemmed from forgetting about the constants referring to statics rule. [Kind of a funny rule when const S: &'static T = &... works, but this is an orthogonal issue.]
I think in the meantime unsized statics should probably error, perhaps dependent on a crater run, though I doubt there's many people relying on said bug. It's much easier to relax restrictions than tighten them.
Will prepare a patch to turn this into an error, hopefully nobody has been abusing it.
Most helpful comment
I think in the meantime unsized statics should probably error, perhaps dependent on a crater run, though I doubt there's many people relying on said bug. It's much easier to relax restrictions than tighten them.