Skip to content

Commit dfe3a71

Browse files
committed
auto merge of #16499 : cmr/rust/struct-undef-repr, r=pcwalton
r? @pcwalton
2 parents 38cb37d + 7e25355 commit dfe3a71

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+504
-221
lines changed

src/doc/guide-ffi.md

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -268,7 +268,7 @@ struct RustObject {
268268
// other members
269269
}
270270
271-
extern fn callback(target: *mut RustObject, a:i32) {
271+
extern "C" fn callback(target: *mut RustObject, a:i32) {
272272
println!("I'm called from C with value {0}", a);
273273
unsafe {
274274
// Update the value in RustObject with the value received from the callback
@@ -506,16 +506,16 @@ to define a block for all windows systems, not just x86 ones.
506506
507507
# Interoperability with foreign code
508508
509-
Rust guarantees that the layout of a `struct` is compatible with the platform's representation in C.
510-
A `#[packed]` attribute is available, which will lay out the struct members without padding.
511-
However, there are currently no guarantees about the layout of an `enum`.
509+
Rust guarantees that the layout of a `struct` is compatible with the platform's representation in C
510+
only if the `#[repr(C)]` attribute is applied to it. `#[repr(C, packed)]` can be used to lay out
511+
struct members without padding. `#[repr(C)]` can also be applied to an enum.
512512
513-
Rust's owned and managed boxes use non-nullable pointers as handles which point to the contained
513+
Rust's owned boxes (`Box<T>`) use non-nullable pointers as handles which point to the contained
514514
object. However, they should not be manually created because they are managed by internal
515-
allocators. References can safely be assumed to be non-nullable pointers directly to the
516-
type. However, breaking the borrow checking or mutability rules is not guaranteed to be safe, so
517-
prefer using raw pointers (`*`) if that's needed because the compiler can't make as many assumptions
518-
about them.
515+
allocators. References can safely be assumed to be non-nullable pointers directly to the type.
516+
However, breaking the borrow checking or mutability rules is not guaranteed to be safe, so prefer
517+
using raw pointers (`*`) if that's needed because the compiler can't make as many assumptions about
518+
them.
519519
520520
Vectors and strings share the same basic memory layout, and utilities are available in the `vec` and
521521
`str` modules for working with C APIs. However, strings are not terminated with `\0`. If you need a

src/doc/rust.md

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1293,6 +1293,9 @@ struct Cookie;
12931293
let c = [Cookie, Cookie, Cookie, Cookie];
12941294
~~~~
12951295

1296+
The precise memory layout of a structure is not specified. One can specify a
1297+
particular layout using the [`repr` attribute](#ffi-attributes).
1298+
12961299
By using the `struct_inherit` feature gate, structures may use single inheritance. A Structure may only
12971300
inherit from a single other structure, called the _super-struct_. The inheriting structure (sub-struct)
12981301
acts as if all fields in the super-struct were present in the sub-struct. Fields declared in a sub-struct
@@ -1926,6 +1929,23 @@ interpreted:
19261929
- `linkage` - on a static, this specifies the [linkage
19271930
type](http://llvm.org/docs/LangRef.html#linkage-types).
19281931

1932+
On `enum`s:
1933+
1934+
- `repr` - on C-like enums, this sets the underlying type used for
1935+
representation. Takes one argument, which is the primitive
1936+
type this enum should be represented for, or `C`, which specifies that it
1937+
should be the default `enum` size of the C ABI for that platform. Note that
1938+
enum representation in C is undefined, and this may be incorrect when the C
1939+
code is compiled with certain flags.
1940+
1941+
On `struct`s:
1942+
1943+
- `repr` - specifies the representation to use for this struct. Takes a list
1944+
of options. The currently accepted ones are `C` and `packed`, which may be
1945+
combined. `C` will use a C ABI comptible struct layout, and `packed` will
1946+
remove any padding between fields (note that this is very fragile and may
1947+
break platforms which require aligned access).
1948+
19291949
### Miscellaneous attributes
19301950

19311951
- `export_name` - on statics and functions, this determines the name of the
@@ -1943,12 +1963,6 @@ interpreted:
19431963
crate at compile-time and use any syntax extensions or lints that the crate
19441964
defines. They can both be specified, `#[phase(link, plugin)]` to use a crate
19451965
both at runtime and compiletime.
1946-
- `repr` - on C-like enums, this sets the underlying type used for
1947-
representation. Useful for FFI. Takes one argument, which is the primitive
1948-
type this enum should be represented for, or `C`, which specifies that it
1949-
should be the default `enum` size of the C ABI for that platform. Note that
1950-
enum representation in C is undefined, and this may be incorrect when the C
1951-
code is compiled with certain flags.
19521966
- `simd` - on certain tuple structs, derive the arithmetic operators, which
19531967
lower to the target's SIMD instructions, if any; the `simd` feature gate
19541968
is necessary to use this attribute.

src/libcore/simd.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
#[experimental]
4141
#[simd]
4242
#[deriving(Show)]
43+
#[repr(C)]
4344
pub struct i8x16(pub i8, pub i8, pub i8, pub i8,
4445
pub i8, pub i8, pub i8, pub i8,
4546
pub i8, pub i8, pub i8, pub i8,
@@ -48,22 +49,26 @@ pub struct i8x16(pub i8, pub i8, pub i8, pub i8,
4849
#[experimental]
4950
#[simd]
5051
#[deriving(Show)]
52+
#[repr(C)]
5153
pub struct i16x8(pub i16, pub i16, pub i16, pub i16,
5254
pub i16, pub i16, pub i16, pub i16);
5355

5456
#[experimental]
5557
#[simd]
5658
#[deriving(Show)]
59+
#[repr(C)]
5760
pub struct i32x4(pub i32, pub i32, pub i32, pub i32);
5861

5962
#[experimental]
6063
#[simd]
6164
#[deriving(Show)]
65+
#[repr(C)]
6266
pub struct i64x2(pub i64, pub i64);
6367

6468
#[experimental]
6569
#[simd]
6670
#[deriving(Show)]
71+
#[repr(C)]
6772
pub struct u8x16(pub u8, pub u8, pub u8, pub u8,
6873
pub u8, pub u8, pub u8, pub u8,
6974
pub u8, pub u8, pub u8, pub u8,
@@ -72,25 +77,30 @@ pub struct u8x16(pub u8, pub u8, pub u8, pub u8,
7277
#[experimental]
7378
#[simd]
7479
#[deriving(Show)]
80+
#[repr(C)]
7581
pub struct u16x8(pub u16, pub u16, pub u16, pub u16,
7682
pub u16, pub u16, pub u16, pub u16);
7783

7884
#[experimental]
7985
#[simd]
8086
#[deriving(Show)]
87+
#[repr(C)]
8188
pub struct u32x4(pub u32, pub u32, pub u32, pub u32);
8289

8390
#[experimental]
8491
#[simd]
8592
#[deriving(Show)]
93+
#[repr(C)]
8694
pub struct u64x2(pub u64, pub u64);
8795

8896
#[experimental]
8997
#[simd]
9098
#[deriving(Show)]
99+
#[repr(C)]
91100
pub struct f32x4(pub f32, pub f32, pub f32, pub f32);
92101

93102
#[experimental]
94103
#[simd]
95104
#[deriving(Show)]
105+
#[repr(C)]
96106
pub struct f64x2(pub f64, pub f64);

src/libgreen/context.rs

Lines changed: 31 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ use std::rt::stack;
1515
use std::raw;
1616
#[cfg(target_arch = "x86_64")]
1717
use std::simd;
18+
use libc;
1819

1920
// FIXME #7761: Registers is boxed so that it is 16-byte aligned, for storing
2021
// SSE regs. It would be marginally better not to do this. In C++ we
@@ -69,7 +70,7 @@ impl Context {
6970
// overflow). Additionally, their coroutine stacks are listed as being
7071
// zero-length, so that's how we detect what's what here.
7172
let stack_base: *const uint = stack.start();
72-
let bounds = if sp as uint == stack_base as uint {
73+
let bounds = if sp as libc::uintptr_t == stack_base as libc::uintptr_t {
7374
None
7475
} else {
7576
Some((stack_base as uint, sp as uint))
@@ -172,9 +173,9 @@ fn initialize_call_frame(regs: &mut Registers, fptr: InitFn, arg: uint,
172173
let sp = align_down(sp);
173174
let sp = mut_offset(sp, -4);
174175

175-
unsafe { *mut_offset(sp, 2) = procedure.env as uint };
176-
unsafe { *mut_offset(sp, 1) = procedure.code as uint };
177-
unsafe { *mut_offset(sp, 0) = arg as uint };
176+
unsafe { *mut_offset(sp, 2) = procedure.env as libc::uintptr_t };
177+
unsafe { *mut_offset(sp, 1) = procedure.code as libc::uintptr_t };
178+
unsafe { *mut_offset(sp, 0) = arg as libc::uintptr_t };
178179
let sp = mut_offset(sp, -1);
179180
unsafe { *sp = 0 }; // The final return address
180181

@@ -188,13 +189,15 @@ fn initialize_call_frame(regs: &mut Registers, fptr: InitFn, arg: uint,
188189
// windows requires saving more registers (both general and XMM), so the windows
189190
// register context must be larger.
190191
#[cfg(windows, target_arch = "x86_64")]
192+
#[repr(C)]
191193
struct Registers {
192-
gpr:[uint, ..14],
194+
gpr:[libc::uintptr_t, ..14],
193195
_xmm:[simd::u32x4, ..10]
194196
}
195197
#[cfg(not(windows), target_arch = "x86_64")]
198+
#[repr(C)]
196199
struct Registers {
197-
gpr:[uint, ..10],
200+
gpr:[libc::uintptr_t, ..10],
198201
_xmm:[simd::u32x4, ..6]
199202
}
200203

@@ -234,30 +237,30 @@ fn initialize_call_frame(regs: &mut Registers, fptr: InitFn, arg: uint,
234237
unsafe { *sp = 0; }
235238

236239
rtdebug!("creating call frame");
237-
rtdebug!("fptr {:#x}", fptr as uint);
240+
rtdebug!("fptr {:#x}", fptr as libc::uintptr_t);
238241
rtdebug!("arg {:#x}", arg);
239242
rtdebug!("sp {}", sp);
240243

241244
// These registers are frobbed by rust_bootstrap_green_task into the right
242245
// location so we can invoke the "real init function", `fptr`.
243-
regs.gpr[RUSTRT_R12] = arg as uint;
244-
regs.gpr[RUSTRT_R13] = procedure.code as uint;
245-
regs.gpr[RUSTRT_R14] = procedure.env as uint;
246-
regs.gpr[RUSTRT_R15] = fptr as uint;
246+
regs.gpr[RUSTRT_R12] = arg as libc::uintptr_t;
247+
regs.gpr[RUSTRT_R13] = procedure.code as libc::uintptr_t;
248+
regs.gpr[RUSTRT_R14] = procedure.env as libc::uintptr_t;
249+
regs.gpr[RUSTRT_R15] = fptr as libc::uintptr_t;
247250

248251
// These registers are picked up by the regular context switch paths. These
249252
// will put us in "mostly the right context" except for frobbing all the
250253
// arguments to the right place. We have the small trampoline code inside of
251254
// rust_bootstrap_green_task to do that.
252-
regs.gpr[RUSTRT_RSP] = sp as uint;
253-
regs.gpr[RUSTRT_IP] = rust_bootstrap_green_task as uint;
255+
regs.gpr[RUSTRT_RSP] = sp as libc::uintptr_t;
256+
regs.gpr[RUSTRT_IP] = rust_bootstrap_green_task as libc::uintptr_t;
254257

255258
// Last base pointer on the stack should be 0
256259
regs.gpr[RUSTRT_RBP] = 0;
257260
}
258261

259262
#[cfg(target_arch = "arm")]
260-
type Registers = [uint, ..32];
263+
type Registers = [libc::uintptr_t, ..32];
261264

262265
#[cfg(target_arch = "arm")]
263266
fn new_regs() -> Box<Registers> { box {[0, .. 32]} }
@@ -277,17 +280,17 @@ fn initialize_call_frame(regs: &mut Registers, fptr: InitFn, arg: uint,
277280
// ARM uses the same technique as x86_64 to have a landing pad for the start
278281
// of all new green tasks. Neither r1/r2 are saved on a context switch, so
279282
// the shim will copy r3/r4 into r1/r2 and then execute the function in r5
280-
regs[0] = arg as uint; // r0
281-
regs[3] = procedure.code as uint; // r3
282-
regs[4] = procedure.env as uint; // r4
283-
regs[5] = fptr as uint; // r5
284-
regs[13] = sp as uint; // #52 sp, r13
285-
regs[14] = rust_bootstrap_green_task as uint; // #56 pc, r14 --> lr
283+
regs[0] = arg as libc::uintptr_t; // r0
284+
regs[3] = procedure.code as libc::uintptr_t; // r3
285+
regs[4] = procedure.env as libc::uintptr_t; // r4
286+
regs[5] = fptr as libc::uintptr_t; // r5
287+
regs[13] = sp as libc::uintptr_t; // #52 sp, r13
288+
regs[14] = rust_bootstrap_green_task as libc::uintptr_t; // #56 pc, r14 --> lr
286289
}
287290

288291
#[cfg(target_arch = "mips")]
289292
#[cfg(target_arch = "mipsel")]
290-
type Registers = [uint, ..32];
293+
type Registers = [libc::uintptr_t, ..32];
291294

292295
#[cfg(target_arch = "mips")]
293296
#[cfg(target_arch = "mipsel")]
@@ -304,16 +307,16 @@ fn initialize_call_frame(regs: &mut Registers, fptr: InitFn, arg: uint,
304307
// The final return address. 0 indicates the bottom of the stack
305308
unsafe { *sp = 0; }
306309

307-
regs[4] = arg as uint;
308-
regs[5] = procedure.code as uint;
309-
regs[6] = procedure.env as uint;
310-
regs[29] = sp as uint;
311-
regs[25] = fptr as uint;
312-
regs[31] = fptr as uint;
310+
regs[4] = arg as libc::uintptr_t;
311+
regs[5] = procedure.code as libc::uintptr_t;
312+
regs[6] = procedure.env as libc::uintptr_t;
313+
regs[29] = sp as libc::uintptr_t;
314+
regs[25] = fptr as libc::uintptr_t;
315+
regs[31] = fptr as libc::uintptr_t;
313316
}
314317

315318
fn align_down(sp: *mut uint) -> *mut uint {
316-
let sp = (sp as uint) & !(16 - 1);
319+
let sp = (sp as libc::uintptr_t) & !(16 - 1);
317320
sp as *mut uint
318321
}
319322

src/libgreen/stack.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ impl Stack {
6868

6969
// FIXME: Using the FFI to call a C macro. Slow
7070
stk.valgrind_id = unsafe {
71-
rust_valgrind_stack_register(stk.start(), stk.end())
71+
rust_valgrind_stack_register(stk.start() as *const libc::uintptr_t, stk.end() as *const libc::uintptr_t)
7272
};
7373
return stk;
7474
}

0 commit comments

Comments
 (0)