auto merge of #5227 : jdm/rust/newconst, r=pcwalton
All comments from previous pull requests addressed.
This commit is contained in:
commit
7140d7c52b
14 changed files with 293 additions and 29 deletions
|
|
@ -616,7 +616,7 @@ fn encode_info_for_item(ecx: @EncodeContext, ebml_w: writer::Encoder,
|
|||
let must_write =
|
||||
match item.node {
|
||||
item_enum(_, _) | item_impl(*) | item_trait(*) | item_struct(*) |
|
||||
item_mod(*) | item_foreign_mod(*) => true,
|
||||
item_mod(*) | item_foreign_mod(*) | item_const(*) => true,
|
||||
_ => false
|
||||
};
|
||||
if !must_write && !reachable(ecx, item.id) { return; }
|
||||
|
|
@ -639,6 +639,7 @@ fn encode_info_for_item(ecx: @EncodeContext, ebml_w: writer::Encoder,
|
|||
encode_type(ecx, ebml_w, node_id_to_type(tcx, item.id));
|
||||
encode_symbol(ecx, ebml_w, item.id);
|
||||
encode_path(ecx, ebml_w, path, ast_map::path_name(item.ident));
|
||||
(ecx.encode_inlined_item)(ecx, ebml_w, path, ii_item(item));
|
||||
ebml_w.end_tag();
|
||||
}
|
||||
item_fn(_, purity, ref generics, _) => {
|
||||
|
|
|
|||
|
|
@ -107,7 +107,7 @@ pub fn check_expr(sess: Session,
|
|||
expr_lit(_) => (),
|
||||
expr_cast(_, _) => {
|
||||
let ety = ty::expr_ty(tcx, e);
|
||||
if !ty::type_is_numeric(ety) {
|
||||
if !ty::type_is_numeric(ety) && !ty::type_is_unsafe_ptr(ety) {
|
||||
sess.span_err(e.span, ~"can not cast to `" +
|
||||
ppaux::ty_to_str(tcx, ety) +
|
||||
~"` in a constant expression");
|
||||
|
|
@ -124,17 +124,11 @@ pub fn check_expr(sess: Session,
|
|||
items without type parameters");
|
||||
}
|
||||
match def_map.find(&e.id) {
|
||||
Some(def_variant(_, _)) |
|
||||
Some(def_struct(_)) => { }
|
||||
Some(def_const(_)) |
|
||||
Some(def_fn(_, _)) |
|
||||
Some(def_variant(_, _)) |
|
||||
Some(def_struct(_)) => { }
|
||||
|
||||
Some(def_const(def_id)) |
|
||||
Some(def_fn(def_id, _)) => {
|
||||
if !ast_util::is_local(def_id) {
|
||||
sess.span_err(
|
||||
e.span, ~"paths in constants may only refer to \
|
||||
crate-local constants or functions");
|
||||
}
|
||||
}
|
||||
Some(def) => {
|
||||
debug!("(checking const) found bad def: %?", def);
|
||||
sess.span_err(
|
||||
|
|
@ -246,11 +240,13 @@ pub fn check_item_recursion(sess: Session,
|
|||
expr_path(*) => {
|
||||
match env.def_map.find(&e.id) {
|
||||
Some(def_const(def_id)) => {
|
||||
match env.ast_map.get(&def_id.node) {
|
||||
ast_map::node_item(it, _) => {
|
||||
(v.visit_item)(it, env, v);
|
||||
if ast_util::is_local(def_id) {
|
||||
match env.ast_map.get(&def_id.node) {
|
||||
ast_map::node_item(it, _) => {
|
||||
(v.visit_item)(it, env, v);
|
||||
}
|
||||
_ => fail!(~"const not bound to an item")
|
||||
}
|
||||
_ => fail!(~"const not bound to an item")
|
||||
}
|
||||
}
|
||||
_ => ()
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
use core::prelude::*;
|
||||
|
||||
use lib::llvm::{llvm, ValueRef, TypeRef, Bool, True, False};
|
||||
use metadata::csearch;
|
||||
use middle::const_eval;
|
||||
use middle::trans::adt;
|
||||
use middle::trans::base;
|
||||
|
|
@ -18,6 +19,7 @@ use middle::trans::base::get_insn_ctxt;
|
|||
use middle::trans::common::*;
|
||||
use middle::trans::consts;
|
||||
use middle::trans::expr;
|
||||
use middle::trans::inline;
|
||||
use middle::trans::machine;
|
||||
use middle::trans::type_of;
|
||||
use middle::ty;
|
||||
|
|
@ -110,7 +112,7 @@ pub fn const_autoderef(cx: @CrateContext, ty: ty::t, v: ValueRef)
|
|||
let mut v1 = v;
|
||||
loop {
|
||||
// Only rptrs can be autoderef'ed in a const context.
|
||||
match ty::get(ty).sty {
|
||||
match ty::get(t1).sty {
|
||||
ty::ty_rptr(_, mt) => {
|
||||
t1 = mt.ty;
|
||||
v1 = const_deref(cx, v1);
|
||||
|
|
@ -121,10 +123,12 @@ pub fn const_autoderef(cx: @CrateContext, ty: ty::t, v: ValueRef)
|
|||
}
|
||||
|
||||
pub fn get_const_val(cx: @CrateContext, def_id: ast::def_id) -> ValueRef {
|
||||
if !ast_util::is_local(def_id) {
|
||||
cx.tcx.sess.bug(~"cross-crate constants");
|
||||
}
|
||||
if !cx.const_values.contains_key(&def_id.node) {
|
||||
let mut def_id = def_id;
|
||||
if !ast_util::is_local(def_id) ||
|
||||
!cx.const_values.contains_key(&def_id.node) {
|
||||
if !ast_util::is_local(def_id) {
|
||||
def_id = inline::maybe_instantiate_inline(cx, def_id, true);
|
||||
}
|
||||
match cx.tcx.items.get(&def_id.node) {
|
||||
ast_map::node_item(@ast::item {
|
||||
node: ast::item_const(_, subexpr), _
|
||||
|
|
@ -338,6 +342,12 @@ fn const_expr_unchecked(cx: @CrateContext, e: @ast::expr) -> ValueRef {
|
|||
integral or float")
|
||||
}
|
||||
}
|
||||
(expr::cast_pointer, expr::cast_pointer) => {
|
||||
llvm::LLVMConstPointerCast(v, llty)
|
||||
}
|
||||
(expr::cast_integral, expr::cast_pointer) => {
|
||||
llvm::LLVMConstIntToPtr(v, llty)
|
||||
}
|
||||
_ => {
|
||||
cx.sess.impossible_case(e.span,
|
||||
~"bad combination of types for cast")
|
||||
|
|
@ -416,8 +426,13 @@ fn const_expr_unchecked(cx: @CrateContext, e: @ast::expr) -> ValueRef {
|
|||
assert pth.types.len() == 0;
|
||||
match cx.tcx.def_map.find(&e.id) {
|
||||
Some(ast::def_fn(def_id, _purity)) => {
|
||||
assert ast_util::is_local(def_id);
|
||||
let f = base::get_item_val(cx, def_id.node);
|
||||
let f = if !ast_util::is_local(def_id) {
|
||||
let ty = csearch::get_type(cx.tcx, def_id).ty;
|
||||
base::trans_external_path(cx, def_id, ty)
|
||||
} else {
|
||||
assert ast_util::is_local(def_id);
|
||||
base::get_item_val(cx, def_id.node)
|
||||
};
|
||||
let ety = ty::expr_ty_adjusted(cx.tcx, e);
|
||||
match ty::get(ety).sty {
|
||||
ty::ty_bare_fn(*) | ty::ty_ptr(*) => {
|
||||
|
|
|
|||
|
|
@ -138,6 +138,7 @@ use middle::trans::consts;
|
|||
use middle::trans::controlflow;
|
||||
use middle::trans::datum::*;
|
||||
use middle::trans::debuginfo;
|
||||
use middle::trans::inline;
|
||||
use middle::trans::machine;
|
||||
use middle::trans::meth;
|
||||
use middle::trans::tvec;
|
||||
|
|
@ -984,15 +985,54 @@ fn trans_lvalue_unadjusted(bcx: block, expr: @ast::expr) -> DatumBlock {
|
|||
match def {
|
||||
ast::def_const(did) => {
|
||||
let const_ty = expr_ty(bcx, ref_expr);
|
||||
let val = if did.crate == ast::local_crate {
|
||||
|
||||
#[cfg(stage0)]
|
||||
fn get_did(_ccx: @CrateContext, did: ast::def_id)
|
||||
-> ast::def_id {
|
||||
did
|
||||
}
|
||||
|
||||
#[cfg(stage1)]
|
||||
#[cfg(stage2)]
|
||||
#[cfg(stage3)]
|
||||
fn get_did(ccx: @CrateContext, did: ast::def_id)
|
||||
-> ast::def_id {
|
||||
if did.crate != ast::local_crate {
|
||||
inline::maybe_instantiate_inline(ccx, did, true)
|
||||
} else {
|
||||
did
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(stage0)]
|
||||
fn get_val(bcx: block, did: ast::def_id, const_ty: ty::t)
|
||||
-> ValueRef {
|
||||
let ccx = bcx.ccx();
|
||||
if did.crate == ast::local_crate {
|
||||
// The LLVM global has the type of its initializer,
|
||||
// which may not be equal to the enum's type for
|
||||
// non-C-like enums.
|
||||
PointerCast(bcx, base::get_item_val(ccx, did.node),
|
||||
T_ptr(type_of(bcx.ccx(), const_ty)))
|
||||
} else {
|
||||
base::trans_external_path(ccx, did, const_ty)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(stage1)]
|
||||
#[cfg(stage2)]
|
||||
#[cfg(stage3)]
|
||||
fn get_val(bcx: block, did: ast::def_id, const_ty: ty::t)
|
||||
-> ValueRef {
|
||||
// The LLVM global has the type of its initializer,
|
||||
// which may not be equal to the enum's type for
|
||||
// non-C-like enums.
|
||||
PointerCast(bcx, base::get_item_val(ccx, did.node),
|
||||
PointerCast(bcx, base::get_item_val(bcx.ccx(), did.node),
|
||||
T_ptr(type_of(bcx.ccx(), const_ty)))
|
||||
} else {
|
||||
base::trans_external_path(ccx, did, const_ty)
|
||||
};
|
||||
}
|
||||
|
||||
let did = get_did(ccx, did);
|
||||
let val = get_val(bcx, did, const_ty);
|
||||
DatumBlock {
|
||||
bcx: bcx,
|
||||
datum: Datum {val: val,
|
||||
|
|
|
|||
|
|
@ -93,7 +93,7 @@ use middle::typeck::check::method::TransformTypeNormally;
|
|||
use middle::typeck::check::regionmanip::replace_bound_regions_in_fn_sig;
|
||||
use middle::typeck::check::vtable::{LocationInfo, VtableContext};
|
||||
use middle::typeck::CrateCtxt;
|
||||
use middle::typeck::infer::{resolve_type, force_tvar};
|
||||
use middle::typeck::infer::{resolve_type, force_tvar, mk_eqty};
|
||||
use middle::typeck::infer;
|
||||
use middle::typeck::rscope::{binding_rscope, bound_self_region};
|
||||
use middle::typeck::rscope::{RegionError};
|
||||
|
|
@ -2452,6 +2452,44 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt,
|
|||
let t_1_is_scalar = type_is_scalar(fcx, expr.span, t_1);
|
||||
if type_is_c_like_enum(fcx,expr.span,t_e) && t_1_is_scalar {
|
||||
/* this case is allowed */
|
||||
} else if type_is_region_ptr(fcx, expr.span, t_e) &&
|
||||
type_is_unsafe_ptr(fcx, expr.span, t_1) {
|
||||
|
||||
fn is_vec(t: ty::t) -> bool {
|
||||
match ty::get(t).sty {
|
||||
ty::ty_evec(_,_) => true,
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
fn types_compatible(fcx: @mut FnCtxt, sp: span, t1: ty::t,
|
||||
t2: ty::t) -> bool {
|
||||
if !is_vec(t1) {
|
||||
false
|
||||
} else {
|
||||
let el = ty::sequence_element_type(fcx.tcx(), t1);
|
||||
infer::mk_eqty(fcx.infcx(), false, sp, el, t2).is_ok()
|
||||
}
|
||||
}
|
||||
|
||||
// Due to the limitations of LLVM global constants,
|
||||
// region pointers end up pointing at copies of
|
||||
// vector elements instead of the original values.
|
||||
// To allow unsafe pointers to work correctly, we
|
||||
// need to special-case obtaining an unsafe pointer
|
||||
// from a region pointer to a vector.
|
||||
|
||||
/* this cast is only allowed from &[T] to *T or
|
||||
&T to *T. */
|
||||
let te = structurally_resolved_type(fcx, e.span, t_e);
|
||||
match (&ty::get(te).sty, &ty::get(t_1).sty) {
|
||||
(&ty::ty_rptr(_, mt1), &ty::ty_ptr(mt2))
|
||||
if types_compatible(fcx, e.span, mt1.ty, mt2.ty) => {
|
||||
/* this case is allowed */
|
||||
}
|
||||
_ => {
|
||||
demand::coerce(fcx, e.span, t_1, e);
|
||||
}
|
||||
}
|
||||
} else if !(type_is_scalar(fcx,expr.span,t_e) && t_1_is_scalar) {
|
||||
/*
|
||||
If more type combinations should be supported than are
|
||||
|
|
@ -3081,6 +3119,16 @@ pub fn type_is_scalar(fcx: @mut FnCtxt, sp: span, typ: ty::t) -> bool {
|
|||
return ty::type_is_scalar(typ_s);
|
||||
}
|
||||
|
||||
pub fn type_is_unsafe_ptr(fcx: @mut FnCtxt, sp: span, typ: ty::t) -> bool {
|
||||
let typ_s = structurally_resolved_type(fcx, sp, typ);
|
||||
return ty::type_is_unsafe_ptr(typ_s);
|
||||
}
|
||||
|
||||
pub fn type_is_region_ptr(fcx: @mut FnCtxt, sp: span, typ: ty::t) -> bool {
|
||||
let typ_s = structurally_resolved_type(fcx, sp, typ);
|
||||
return ty::type_is_region_ptr(typ_s);
|
||||
}
|
||||
|
||||
pub fn type_is_c_like_enum(fcx: @mut FnCtxt, sp: span, typ: ty::t) -> bool {
|
||||
let typ_s = structurally_resolved_type(fcx, sp, typ);
|
||||
return ty::type_is_c_like_enum(fcx.ccx.tcx, typ_s);
|
||||
|
|
|
|||
16
src/test/auxiliary/cci_const.rs
Normal file
16
src/test/auxiliary/cci_const.rs
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
pub extern fn bar() {
|
||||
}
|
||||
|
||||
pub const foopy: &static/str = "hi there";
|
||||
pub const uint_val: uint = 12;
|
||||
pub const uint_expr: uint = (1 << uint_val) - 1;
|
||||
14
src/test/compile-fail/cast-vector-to-unsafe-nonstatic.rs
Normal file
14
src/test/compile-fail/cast-vector-to-unsafe-nonstatic.rs
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
fn main() {
|
||||
let foo = ['h' as u8, 'i' as u8, 0 as u8];
|
||||
let bar = &foo as *u8; //~ ERROR mismatched types
|
||||
}
|
||||
16
src/test/compile-fail/const-cast-different-types.rs
Normal file
16
src/test/compile-fail/const-cast-different-types.rs
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
const a: &static/str = &"foo";
|
||||
const b: *u8 = a as *u8; //~ ERROR non-scalar cast
|
||||
const c: *u8 = &a as *u8; //~ ERROR mismatched types
|
||||
|
||||
fn main() {
|
||||
}
|
||||
15
src/test/compile-fail/const-cast-wrong-type.rs
Normal file
15
src/test/compile-fail/const-cast-wrong-type.rs
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
const a: [u8 * 3] = ['h' as u8, 'i' as u8, 0 as u8];
|
||||
const b: *i8 = &a as *i8; //~ ERROR mismatched types
|
||||
|
||||
fn main() {
|
||||
}
|
||||
15
src/test/run-pass/const-cast-ptr-int.rs
Normal file
15
src/test/run-pass/const-cast-ptr-int.rs
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
const a: *u8 = 0 as *u8;
|
||||
|
||||
fn main() {
|
||||
assert a == ptr::null();
|
||||
}
|
||||
21
src/test/run-pass/const-cast.rs
Normal file
21
src/test/run-pass/const-cast.rs
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
extern fn foo() {}
|
||||
|
||||
const x: *u8 = foo;
|
||||
const y: *libc::c_void = x as *libc::c_void;
|
||||
const a: &static/int = &10;
|
||||
const b: *int = a as *int;
|
||||
|
||||
fn main() {
|
||||
assert x as *libc::c_void == y;
|
||||
assert a as *int == b;
|
||||
}
|
||||
25
src/test/run-pass/const-cross-crate-const.rs
Normal file
25
src/test/run-pass/const-cross-crate-const.rs
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// xfail-fast
|
||||
// aux-build:cci_const.rs
|
||||
|
||||
extern mod cci_const;
|
||||
const foo: &static/str = cci_const::foopy;
|
||||
const a: uint = cci_const::uint_val;
|
||||
const b: uint = cci_const::uint_expr + 5;
|
||||
|
||||
fn main() {
|
||||
assert a == 12;
|
||||
let foo2 = a;
|
||||
assert foo2 == cci_const::uint_val;
|
||||
assert b == cci_const::uint_expr + 5;
|
||||
assert foo == cci_const::foopy;
|
||||
}
|
||||
20
src/test/run-pass/const-cross-crate-extern.rs
Normal file
20
src/test/run-pass/const-cross-crate-extern.rs
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// xfail-fast
|
||||
// aux-build:cci_const.rs
|
||||
|
||||
extern mod cci_const;
|
||||
use cci_const::bar;
|
||||
const foo: *u8 = bar;
|
||||
|
||||
fn main() {
|
||||
assert foo == cci_const::bar;
|
||||
}
|
||||
22
src/test/run-pass/const-str-ptr.rs
Normal file
22
src/test/run-pass/const-str-ptr.rs
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
const a: [u8 * 3] = ['h' as u8, 'i' as u8, 0 as u8];
|
||||
const c: &static/[u8 * 3] = &a;
|
||||
const b: *u8 = c as *u8;
|
||||
|
||||
fn main() {
|
||||
let foo = &a as *u8;
|
||||
assert unsafe { str::raw::from_bytes(a) } == ~"hi\x00";
|
||||
assert unsafe { str::raw::from_buf(foo) } == ~"hi";
|
||||
assert unsafe { str::raw::from_buf(b) } == ~"hi";
|
||||
assert unsafe { *b == a[0] };
|
||||
assert unsafe { *(&c[0] as *u8) == a[0] };
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue