From ac50ab58bdbb7814900835d17050b7313b87b133 Mon Sep 17 00:00:00 2001 From: Corey Richardson Date: Sun, 25 May 2014 19:57:17 -0700 Subject: [PATCH 1/5] docs: don't claim struct layout is specified, but mention repr --- src/doc/guide-ffi.md | 18 +++++++++--------- src/doc/rust.md | 26 ++++++++++++++++++++------ 2 files changed, 29 insertions(+), 15 deletions(-) diff --git a/src/doc/guide-ffi.md b/src/doc/guide-ffi.md index 81616c675dee9..4d241b21253df 100644 --- a/src/doc/guide-ffi.md +++ b/src/doc/guide-ffi.md @@ -268,7 +268,7 @@ struct RustObject { // other members } -extern fn callback(target: *mut RustObject, a:i32) { +extern "C" fn callback(target: *mut RustObject, a:i32) { println!("I'm called from C with value {0}", a); unsafe { // Update the value in RustObject with the value received from the callback @@ -505,16 +505,16 @@ to define a block for all windows systems, not just x86 ones. # Interoperability with foreign code -Rust guarantees that the layout of a `struct` is compatible with the platform's representation in C. -A `#[packed]` attribute is available, which will lay out the struct members without padding. -However, there are currently no guarantees about the layout of an `enum`. +Rust guarantees that the layout of a `struct` is compatible with the platform's representation in C +only if the `#[repr(C)]` attribute is applied to it. `#[repr(C, packed)]` can be used to lay out +struct members without padding. `#[repr(C)]` can also be applied to an enum. -Rust's owned and managed boxes use non-nullable pointers as handles which point to the contained +Rust's owned boxes (`Box`) use non-nullable pointers as handles which point to the contained object. However, they should not be manually created because they are managed by internal -allocators. References can safely be assumed to be non-nullable pointers directly to the -type. However, breaking the borrow checking or mutability rules is not guaranteed to be safe, so -prefer using raw pointers (`*`) if that's needed because the compiler can't make as many assumptions -about them. +allocators. References can safely be assumed to be non-nullable pointers directly to the type. +However, breaking the borrow checking or mutability rules is not guaranteed to be safe, so prefer +using raw pointers (`*`) if that's needed because the compiler can't make as many assumptions about +them. Vectors and strings share the same basic memory layout, and utilities are available in the `vec` and `str` modules for working with C APIs. However, strings are not terminated with `\0`. If you need a diff --git a/src/doc/rust.md b/src/doc/rust.md index d860c50f0a215..73ab5fea92ea2 100644 --- a/src/doc/rust.md +++ b/src/doc/rust.md @@ -1221,6 +1221,9 @@ struct Cookie; let c = [Cookie, Cookie, Cookie, Cookie]; ~~~~ +The precise memory layout of a structure is not specified. One can specify a +particular layout using the [`repr` attribute]( + By using the `struct_inherit` feature gate, structures may use single inheritance. A Structure may only inherit from a single other structure, called the _super-struct_. The inheriting structure (sub-struct) acts as if all fields in the super-struct were present in the sub-struct. Fields declared in a sub-struct @@ -1851,6 +1854,23 @@ interpreted: - `linkage` - on a static, this specifies the [linkage type](http://llvm.org/docs/LangRef.html#linkage-types). +On `enum`s: + +- `repr` - on C-like enums, this sets the underlying type used for + representation. Takes one argument, which is the primitive + type this enum should be represented for, or `C`, which specifies that it + should be the default `enum` size of the C ABI for that platform. Note that + enum representation in C is undefined, and this may be incorrect when the C + code is compiled with certain flags. + +On `struct`s: + +- `repr` - specifies the representation to use for this struct. Takes a list + of options. The currently accepted ones are `C` and `packed`, which may be + combined. `C` will use a C ABI comptible struct layout, and `packed` will + remove any padding between fields (note that this is very fragile and may + break platforms which require aligned access). + ### Miscellaneous attributes - `link_section` - on statics and functions, this specifies the section of the @@ -1860,12 +1880,6 @@ interpreted: symbol for this item to its identifier. - `packed` - on structs or enums, eliminate any padding that would be used to align fields. -- `repr` - on C-like enums, this sets the underlying type used for - representation. Useful for FFI. Takes one argument, which is the primitive - type this enum should be represented for, or `C`, which specifies that it - should be the default `enum` size of the C ABI for that platform. Note that - enum representation in C is undefined, and this may be incorrect when the C - code is compiled with certain flags. - `simd` - on certain tuple structs, derive the arithmetic operators, which lower to the target's SIMD instructions, if any. - `static_assert` - on statics whose type is `bool`, terminates compilation From 78893e2899be9ef3124c0faac35e34f0783cbbb9 Mon Sep 17 00:00:00 2001 From: Corey Richardson Date: Mon, 26 May 2014 23:56:52 -0700 Subject: [PATCH 2/5] librustc: handle repr on structs, require it for ffi, unify with packed As of RFC 18, struct layout is undefined. Opting into a C-compatible struct layout is now down with #[repr(C)]. For consistency, specifying a packed layout is now also down with #[repr(packed)]. Both can be specified. [breaking-change] --- src/librustc/middle/lint.rs | 60 +++++++++++++++---- src/librustc/middle/trans/adt.rs | 57 ++++++++++++++---- src/librustc/middle/ty.rs | 22 +++++-- src/librustc/middle/typeck/check/mod.rs | 5 +- src/libstd/rt/backtrace.rs | 2 +- src/libsyntax/attr.rs | 50 ++++++++++++++-- src/test/auxiliary/packed.rs | 2 +- src/test/compile-fail/issue-14309.rs | 49 +++++++++++++++ src/test/compile-fail/lint-ctypes-enum.rs | 4 +- .../packed-struct-generic-transmute.rs | 2 +- .../compile-fail/packed-struct-transmute.rs | 2 +- .../debuginfo/c-style-enum-in-composite.rs | 2 +- .../packed-struct-with-destructor.rs | 10 ++-- src/test/debuginfo/packed-struct.rs | 6 +- .../run-pass/packed-struct-borrow-element.rs | 2 +- .../run-pass/packed-struct-generic-layout.rs | 2 +- .../run-pass/packed-struct-generic-size.rs | 2 +- src/test/run-pass/packed-struct-layout.rs | 4 +- src/test/run-pass/packed-struct-match.rs | 2 +- src/test/run-pass/packed-struct-size.rs | 10 ++-- src/test/run-pass/packed-struct-vec.rs | 2 +- .../run-pass/packed-tuple-struct-layout.rs | 4 +- src/test/run-pass/packed-tuple-struct-size.rs | 10 ++-- 23 files changed, 243 insertions(+), 68 deletions(-) create mode 100644 src/test/compile-fail/issue-14309.rs diff --git a/src/librustc/middle/lint.rs b/src/librustc/middle/lint.rs index eba0bc03bf776..af0e771f41199 100644 --- a/src/librustc/middle/lint.rs +++ b/src/librustc/middle/lint.rs @@ -60,6 +60,7 @@ use std::u16; use std::u32; use std::u64; use std::u8; +use std::cell::RefCell; use collections::SmallIntMap; use syntax::abi; use syntax::ast_map; @@ -482,6 +483,9 @@ struct Context<'a> { /// Level of lints for certain NodeIds, stored here because the body of /// the lint needs to run in trans. node_levels: HashMap<(ast::NodeId, Lint), (Level, LintSource)>, + + /// ids of structs which have had a representation note emitted with ctypes + checked_ffi_structs: RefCell, } pub fn emit_lint(level: Level, src: LintSource, msg: &str, span: Span, @@ -923,26 +927,55 @@ fn check_type_limits(cx: &Context, e: &ast::Expr) { } fn check_item_ctypes(cx: &Context, it: &ast::Item) { - fn check_ty(cx: &Context, ty: &ast::Ty) { - match ty.node { + fn check_ty(cx: &Context, aty: &ast::Ty) { + match aty.node { ast::TyPath(_, _, id) => { match cx.tcx.def_map.borrow().get_copy(&id) { ast::DefPrimTy(ast::TyInt(ast::TyI)) => { - cx.span_lint(CTypes, ty.span, + cx.span_lint(CTypes, aty.span, "found rust type `int` in foreign module, while \ libc::c_int or libc::c_long should be used"); } ast::DefPrimTy(ast::TyUint(ast::TyU)) => { - cx.span_lint(CTypes, ty.span, + cx.span_lint(CTypes, aty.span, "found rust type `uint` in foreign module, while \ libc::c_uint or libc::c_ulong should be used"); } ast::DefTy(def_id) => { - if !adt::is_ffi_safe(cx.tcx, def_id) { - cx.span_lint(CTypes, ty.span, - "found enum type without foreign-function-safe \ - representation annotation in foreign module"); - // hmm... this message could be more helpful + match adt::is_ffi_safe(cx.tcx, def_id) { + Ok(_) => { }, + Err(types) => { + // in the enum case, we don't care about + // "fields". + + let ty = ty::get(ty::lookup_item_type(cx.tcx, def_id).ty); + + match ty.sty { + ty::ty_struct(_, _) => { + cx.span_lint(CTypes, aty.span, "found struct without \ + FFI-safe representation used in FFI"); + + for def_id in types.iter() { + if !cx.checked_ffi_structs.borrow_mut() + .insert(def_id.node) { + return; + } + + match cx.tcx.map.opt_span(def_id.node) { + Some(sp) => cx.tcx.sess.span_note(sp, "consider \ + adding `#[repr(C)]` to this type"), + None => { } + } + } + }, + ty::ty_enum(_, _) => { + cx.span_lint(CTypes, aty.span, + "found enum without FFI-safe representation \ + annotation used in FFI"); + } + _ => { } + } + } } } _ => () @@ -1100,6 +1133,7 @@ static obsolete_attrs: &'static [(&'static str, &'static str)] = &[ ("fast_ffi", "Remove it"), ("fixed_stack_segment", "Remove it"), ("rust_stack", "Remove it"), + ("packed", "Use `#[repr(packed)]` instead") ]; static other_attrs: &'static [&'static str] = &[ @@ -1109,7 +1143,7 @@ static other_attrs: &'static [&'static str] = &[ "allow", "deny", "forbid", "warn", // lint options "deprecated", "experimental", "unstable", "stable", "locked", "frozen", //item stability "cfg", "doc", "export_name", "link_section", - "no_mangle", "static_assert", "unsafe_no_drop_flag", "packed", + "no_mangle", "static_assert", "unsafe_no_drop_flag", "simd", "repr", "deriving", "unsafe_destructor", "link", "phase", "macro_export", "must_use", "automatically_derived", @@ -1178,6 +1212,10 @@ fn check_unused_attribute(cx: &Context, attrs: &[ast::Attribute]) { // FIXME: #14408 whitelist docs since rustdoc looks at them "doc", + // Just because a struct isn't used for FFI in *this* crate, doesn't + // mean it won't ever be. + "repr", + // FIXME: #14406 these are processed in trans, which happens after the // lint pass "address_insignificant", @@ -1189,7 +1227,6 @@ fn check_unused_attribute(cx: &Context, attrs: &[ast::Attribute]) { "no_builtins", "no_mangle", "no_split_stack", - "packed", "static_assert", "thread_local", @@ -1977,6 +2014,7 @@ pub fn check_crate(tcx: &ty::ctxt, negated_expr_id: -1, checked_raw_pointers: NodeSet::new(), node_levels: HashMap::new(), + checked_ffi_structs: RefCell::new(NodeSet::new()), }; // Install default lint levels, followed by the command line levels, and diff --git a/src/librustc/middle/trans/adt.rs b/src/librustc/middle/trans/adt.rs index 45baf07c07c0e..236db9e7c5e18 100644 --- a/src/librustc/middle/trans/adt.rs +++ b/src/librustc/middle/trans/adt.rs @@ -45,10 +45,11 @@ #![allow(unsigned_negate)] -use std::container::Map; use libc::c_ulonglong; -use std::num::{Bitwise}; +use std::container::Map; +use std::num::Bitwise; use std::rc::Rc; +use std; use lib::llvm::{ValueRef, True, IntEQ, IntNE}; use middle::trans::_match; @@ -165,7 +166,7 @@ fn represent_type_uncached(cx: &CrateContext, t: ty::t) -> Repr { } ty::ty_enum(def_id, ref substs) => { let cases = get_cases(cx.tcx(), def_id, substs); - let hint = ty::lookup_repr_hint(cx.tcx(), def_id); + let hint = ty::lookup_enum_repr_hint(cx.tcx(), def_id); if cases.len() == 0 { // Uninhabitable; represent as unit @@ -254,31 +255,60 @@ fn represent_type_uncached(cx: &CrateContext, t: ty::t) -> Repr { /// Determine, without doing translation, whether an ADT must be FFI-safe. /// For use in lint or similar, where being sound but slightly incomplete is acceptable. -pub fn is_ffi_safe(tcx: &ty::ctxt, def_id: ast::DefId) -> bool { +/// Returns Ok(()) if it is, and Err(causes) which is a vector of the DefId's +/// of the types that are unsafe (either the type being checked itself if it +/// lacks a repr attribute, or the fields of a struct). +pub fn is_ffi_safe(tcx: &ty::ctxt, def_id: ast::DefId) -> std::result::Result<(), Vec> { match ty::get(ty::lookup_item_type(tcx, def_id).ty).sty { ty::ty_enum(def_id, _) => { let variants = ty::enum_variants(tcx, def_id); // Univariant => like struct/tuple. if variants.len() <= 1 { - return true; + return Ok(()); } - let hint = ty::lookup_repr_hint(tcx, def_id); + let hint = ty::lookup_enum_repr_hint(tcx, def_id); // Appropriate representation explicitly selected? if hint.is_ffi_safe() { - return true; + return Ok(()); } // Option> and similar are used in FFI. Rather than try to // resolve type parameters and recognize this case exactly, this // overapproximates -- assuming that if a non-C-like enum is being // used in FFI then the user knows what they're doing. if variants.iter().any(|vi| !vi.args.is_empty()) { - return true; + return Ok(()); } - false - } - // struct, tuple, etc. + Err(vec![def_id]) + }, + ty::ty_struct(def_id, _) => { + let struct_is_safe = + ty::lookup_struct_repr_hint(tcx, def_id).contains(&attr::ReprExtern); + let mut fields_are_safe = true; + let mut bad_fields = Vec::new(); + + if !struct_is_safe { + bad_fields.push(def_id); + } + + for field in ty::lookup_struct_fields(tcx, def_id).iter() { + match is_ffi_safe(tcx, field.id) { + Ok(_) => { } + Err(types) => { + fields_are_safe = false; + bad_fields.extend(types.move_iter()) + } + } + } + + if struct_is_safe && fields_are_safe { + Ok(()) + } else { + Err(bad_fields) + } + }, + // tuple, etc. // (is this right in the present of typedefs?) - _ => true + _ => Ok(()) } } @@ -370,6 +400,9 @@ fn range_to_inttype(cx: &CrateContext, hint: Hint, bounds: &IntBounds) -> IntTyp } attr::ReprAny => { attempts = choose_shortest; + }, + attr::ReprPacked => { + cx.tcx.sess.bug("range_to_inttype: found ReprPacked on an enum"); } } for &ity in attempts.iter() { diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index d907b52f0c912..e720650c3971a 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -3928,9 +3928,9 @@ pub fn has_attr(tcx: &ctxt, did: DefId, attr: &str) -> bool { found } -/// Determine whether an item is annotated with `#[packed]` +/// Determine whether an item is annotated with `#[repr(packed)]` pub fn lookup_packed(tcx: &ctxt, did: DefId) -> bool { - has_attr(tcx, did, "packed") + lookup_struct_repr_hint(tcx, did).contains(&attr::ReprPacked) } /// Determine whether an item is annotated with `#[simd]` @@ -3938,16 +3938,28 @@ pub fn lookup_simd(tcx: &ctxt, did: DefId) -> bool { has_attr(tcx, did, "simd") } -// Obtain the representation annotation for a definition. -pub fn lookup_repr_hint(tcx: &ctxt, did: DefId) -> attr::ReprAttr { +/// Obtain the representation annotation for an enum definition. +pub fn lookup_enum_repr_hint(tcx: &ctxt, did: DefId) -> attr::ReprAttr { let mut acc = attr::ReprAny; ty::each_attr(tcx, did, |meta| { - acc = attr::find_repr_attr(tcx.sess.diagnostic(), meta, acc); + acc = attr::find_enum_repr_attr(tcx.sess.diagnostic(), meta, acc); true }); return acc; } +/// Obtain the representation annotation for a struct definition. +pub fn lookup_struct_repr_hint(tcx: &ctxt, did: DefId) -> Vec { + let mut acc = Vec::new(); + + ty::each_attr(tcx, did, |meta| { + acc.extend(attr::find_struct_repr_attrs(tcx.sess.diagnostic(), meta).move_iter()); + true + }); + + acc +} + // Look up a field ID, whether or not it's local // Takes a list of type substs in case the struct is generic pub fn lookup_field_type(tcx: &ctxt, diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs index bb6b0c51a2734..b58c1508946b0 100644 --- a/src/librustc/middle/typeck/check/mod.rs +++ b/src/librustc/middle/typeck/check/mod.rs @@ -3803,6 +3803,9 @@ pub fn check_enum_variants(ccx: &CrateCtxt, ccx.tcx.sess.span_note(sp, "discriminant type specified here"); } } + attr::ReprPacked => { + ccx.tcx.sess.bug("range_to_inttype: found ReprPacked on an enum"); + } } disr_vals.push(current_disr_val); @@ -3816,7 +3819,7 @@ pub fn check_enum_variants(ccx: &CrateCtxt, return variants; } - let hint = ty::lookup_repr_hint(ccx.tcx, ast::DefId { krate: ast::LOCAL_CRATE, node: id }); + let hint = ty::lookup_enum_repr_hint(ccx.tcx, ast::DefId { krate: ast::LOCAL_CRATE, node: id }); if hint != attr::ReprAny && vs.len() <= 1 { let msg = if vs.len() == 1 { "unsupported representation for univariant enum" diff --git a/src/libstd/rt/backtrace.rs b/src/libstd/rt/backtrace.rs index f4cb770544c46..fb4288cecf54a 100644 --- a/src/libstd/rt/backtrace.rs +++ b/src/libstd/rt/backtrace.rs @@ -544,7 +544,7 @@ mod imp { static IMAGE_FILE_MACHINE_IA64: libc::DWORD = 0x0200; static IMAGE_FILE_MACHINE_AMD64: libc::DWORD = 0x8664; - #[packed] + #[repr(packed)] struct SYMBOL_INFO { SizeOfStruct: libc::c_ulong, TypeIndex: libc::c_ulong, diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs index 527e851ae35ac..56f14d01cea4e 100644 --- a/src/libsyntax/attr.rs +++ b/src/libsyntax/attr.rs @@ -464,7 +464,7 @@ pub fn require_unique_names(diagnostic: &SpanHandler, metas: &[@MetaItem]) { * present (before fields, if any) with that type; reprensentation * optimizations which would remove it will not be done. */ -pub fn find_repr_attr(diagnostic: &SpanHandler, attr: &Attribute, acc: ReprAttr) +pub fn find_enum_repr_attr(diagnostic: &SpanHandler, attr: &Attribute, acc: ReprAttr) -> ReprAttr { let mut acc = acc; match attr.node.value.node { @@ -496,7 +496,7 @@ pub fn find_repr_attr(diagnostic: &SpanHandler, attr: &Attribute, acc: ReprAttr) } } // Not a word: - _ => diagnostic.span_err(item.span, "unrecognized representation hint") + _ => diagnostic.span_err(item.span, "unrecognized enum representation hint") } } } @@ -506,6 +506,44 @@ pub fn find_repr_attr(diagnostic: &SpanHandler, attr: &Attribute, acc: ReprAttr) acc } +/// A struct `repr` attribute can only take the values `C` and `packed`, or +/// possibly both. +pub fn find_struct_repr_attrs(diagnostic: &SpanHandler, attr: &Attribute) -> Vec { + let mut attrs = Vec::new(); + match attr.node.value.node { + ast::MetaList(ref s, ref items) if s.equiv(&("repr")) => { + mark_used(attr); + for item in items.iter() { + match item.node { + ast::MetaWord(ref word) => { + let hint = match word.get() { + "C" => Some(ReprExtern), + "packed" => Some(ReprPacked), + _ => { + // Not a word we recognize + diagnostic.span_err(item.span, + "unrecognized struct representation hint"); + None + } + }; + + match hint { + Some(h) => attrs.push(h), + None => { } + } + } + // Not a word: + _ => diagnostic.span_err(item.span, "unrecognized representation hint") + } + } + } + // Not a "repr" hint: ignore. + _ => { } + } + + attrs +} + fn int_type_of_word(s: &str) -> Option { match s { "i8" => Some(SignedInt(ast::TyI8)), @@ -526,7 +564,8 @@ fn int_type_of_word(s: &str) -> Option { pub enum ReprAttr { ReprAny, ReprInt(Span, IntType), - ReprExtern + ReprExtern, + ReprPacked, } impl ReprAttr { @@ -534,7 +573,8 @@ impl ReprAttr { match *self { ReprAny => false, ReprInt(_sp, ity) => ity.is_ffi_safe(), - ReprExtern => true + ReprExtern => true, + ReprPacked => false } } } @@ -559,7 +599,7 @@ impl IntType { SignedInt(ast::TyI16) | UnsignedInt(ast::TyU16) | SignedInt(ast::TyI32) | UnsignedInt(ast::TyU32) | SignedInt(ast::TyI64) | UnsignedInt(ast::TyU64) => true, - _ => false + SignedInt(ast::TyI) | UnsignedInt(ast::TyU) => false } } } diff --git a/src/test/auxiliary/packed.rs b/src/test/auxiliary/packed.rs index 54b2658e380d2..86f5f93e3cf08 100644 --- a/src/test/auxiliary/packed.rs +++ b/src/test/auxiliary/packed.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#[packed] +#[repr(packed)] pub struct S { a: u8, b: u32 diff --git a/src/test/compile-fail/issue-14309.rs b/src/test/compile-fail/issue-14309.rs new file mode 100644 index 0000000000000..416f1e84d6b52 --- /dev/null +++ b/src/test/compile-fail/issue-14309.rs @@ -0,0 +1,49 @@ +// Copyright 2014 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![deny(ctypes)] +#![allow(dead_code)] + +struct A { //~ NOTE #[repr(C)] + x: int +} + +#[repr(C, packed)] +struct B { + x: int, + y: A +} + +#[repr(C)] +struct C { + x: int +} + +type A2 = A; +type B2 = B; +type C2 = C; + +#[repr(C)] +struct D { + x: C, + y: A +} + +extern "C" { + fn foo(x: A); //~ ERROR FFI-safe + fn bar(x: B); //~ ERROR FFI-safe + fn baz(x: C); + fn qux(x: A2); //~ ERROR FFI-safe + fn quux(x: B2); //~ ERROR FFI-safe + fn corge(x: C2); + fn fred(x: D); //~ ERROR FFI-safe +} + +fn main() { } diff --git a/src/test/compile-fail/lint-ctypes-enum.rs b/src/test/compile-fail/lint-ctypes-enum.rs index e968bd601c572..d597006e29dd5 100644 --- a/src/test/compile-fail/lint-ctypes-enum.rs +++ b/src/test/compile-fail/lint-ctypes-enum.rs @@ -19,8 +19,8 @@ enum T { E, F, G } extern { fn zf(x: Z); fn uf(x: U); - fn bf(x: B); //~ ERROR found enum type without foreign-function-safe - fn tf(x: T); //~ ERROR found enum type without foreign-function-safe + fn bf(x: B); //~ ERROR found enum without FFI-safe + fn tf(x: T); //~ ERROR found enum without FFI-safe } pub fn main() { } diff --git a/src/test/compile-fail/packed-struct-generic-transmute.rs b/src/test/compile-fail/packed-struct-generic-transmute.rs index 45e6b76e20038..835c3c4b2806d 100644 --- a/src/test/compile-fail/packed-struct-generic-transmute.rs +++ b/src/test/compile-fail/packed-struct-generic-transmute.rs @@ -17,7 +17,7 @@ use std::mem; -#[packed] +#[repr(packed)] struct Foo { bar: T, baz: S diff --git a/src/test/compile-fail/packed-struct-transmute.rs b/src/test/compile-fail/packed-struct-transmute.rs index 24be7d3a2972f..f27261352f3c2 100644 --- a/src/test/compile-fail/packed-struct-transmute.rs +++ b/src/test/compile-fail/packed-struct-transmute.rs @@ -17,7 +17,7 @@ use std::mem; -#[packed] +#[repr(packed)] struct Foo { bar: u8, baz: uint diff --git a/src/test/debuginfo/c-style-enum-in-composite.rs b/src/test/debuginfo/c-style-enum-in-composite.rs index 3e76bf1987b98..93039c49b582e 100644 --- a/src/test/debuginfo/c-style-enum-in-composite.rs +++ b/src/test/debuginfo/c-style-enum-in-composite.rs @@ -58,7 +58,7 @@ struct PaddedStruct { e: i16 } -#[packed] +#[repr(packed)] struct PackedStruct { a: i16, b: AnEnum, diff --git a/src/test/debuginfo/packed-struct-with-destructor.rs b/src/test/debuginfo/packed-struct-with-destructor.rs index 29087b18d5a96..0f417ce606b89 100644 --- a/src/test/debuginfo/packed-struct-with-destructor.rs +++ b/src/test/debuginfo/packed-struct-with-destructor.rs @@ -44,7 +44,7 @@ #![allow(unused_variable)] -#[packed] +#[repr(packed)] struct Packed { x: i16, y: i32, @@ -55,7 +55,7 @@ impl Drop for Packed { fn drop(&mut self) {} } -#[packed] +#[repr(packed)] struct PackedInPacked { a: i32, b: Packed, @@ -80,7 +80,7 @@ impl Drop for Unpacked { fn drop(&mut self) {} } -#[packed] +#[repr(packed)] struct UnpackedInPacked { a: i16, b: Unpacked, @@ -88,7 +88,7 @@ struct UnpackedInPacked { d: i64 } -#[packed] +#[repr(packed)] struct PackedInPackedWithDrop { a: i32, b: Packed, @@ -111,7 +111,7 @@ impl Drop for PackedInUnpackedWithDrop { fn drop(&mut self) {} } -#[packed] +#[repr(packed)] struct UnpackedInPackedWithDrop { a: i16, b: Unpacked, diff --git a/src/test/debuginfo/packed-struct.rs b/src/test/debuginfo/packed-struct.rs index bc8156c73853c..b7b048c0768cd 100644 --- a/src/test/debuginfo/packed-struct.rs +++ b/src/test/debuginfo/packed-struct.rs @@ -37,14 +37,14 @@ #![allow(unused_variable)] -#[packed] +#[repr(packed)] struct Packed { x: i16, y: i32, z: i64 } -#[packed] +#[repr(packed)] struct PackedInPacked { a: i32, b: Packed, @@ -69,7 +69,7 @@ struct Unpacked { } // layout (64 bit): aabb bbbb bbbb bbbb bbbb bbbb bbcc cccc cccc cccc cccc cccc ccdd dddd dd -#[packed] +#[repr(packed)] struct UnpackedInPacked { a: i16, b: Unpacked, diff --git a/src/test/run-pass/packed-struct-borrow-element.rs b/src/test/run-pass/packed-struct-borrow-element.rs index 1434e1da4c758..c6c74fe3fda1d 100644 --- a/src/test/run-pass/packed-struct-borrow-element.rs +++ b/src/test/run-pass/packed-struct-borrow-element.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#[packed] +#[repr(packed)] struct Foo { bar: u8, baz: uint diff --git a/src/test/run-pass/packed-struct-generic-layout.rs b/src/test/run-pass/packed-struct-generic-layout.rs index 202697661582f..999e4aeeb5977 100644 --- a/src/test/run-pass/packed-struct-generic-layout.rs +++ b/src/test/run-pass/packed-struct-generic-layout.rs @@ -10,7 +10,7 @@ use std::mem; -#[packed] +#[repr(packed)] struct S { a: T, b: u8, diff --git a/src/test/run-pass/packed-struct-generic-size.rs b/src/test/run-pass/packed-struct-generic-size.rs index 80f37a0fa3d0c..45791332bbedf 100644 --- a/src/test/run-pass/packed-struct-generic-size.rs +++ b/src/test/run-pass/packed-struct-generic-size.rs @@ -10,7 +10,7 @@ use std::mem; -#[packed] +#[repr(packed)] struct S { a: T, b: u8, diff --git a/src/test/run-pass/packed-struct-layout.rs b/src/test/run-pass/packed-struct-layout.rs index 7f9bf8e7d57fe..b4fbf0820cd46 100644 --- a/src/test/run-pass/packed-struct-layout.rs +++ b/src/test/run-pass/packed-struct-layout.rs @@ -10,13 +10,13 @@ use std::mem; -#[packed] +#[repr(packed)] struct S4 { a: u8, b: [u8, .. 3], } -#[packed] +#[repr(packed)] struct S5 { a: u8, b: u32 diff --git a/src/test/run-pass/packed-struct-match.rs b/src/test/run-pass/packed-struct-match.rs index 27ab2c83e5566..46ffed0cba968 100644 --- a/src/test/run-pass/packed-struct-match.rs +++ b/src/test/run-pass/packed-struct-match.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#[packed] +#[repr(packed)] struct Foo { bar: u8, baz: uint diff --git a/src/test/run-pass/packed-struct-size.rs b/src/test/run-pass/packed-struct-size.rs index 1781f162bc498..8129583885783 100644 --- a/src/test/run-pass/packed-struct-size.rs +++ b/src/test/run-pass/packed-struct-size.rs @@ -12,19 +12,19 @@ use std::mem; -#[packed] +#[repr(packed)] struct S4 { a: u8, b: [u8, .. 3], } -#[packed] +#[repr(packed)] struct S5 { a: u8, b: u32 } -#[packed] +#[repr(packed)] struct S13 { a: i64, b: f32, @@ -36,14 +36,14 @@ enum Foo { Baz = 2 } -#[packed] +#[repr(packed)] struct S3_Foo { a: u8, b: u16, c: Foo } -#[packed] +#[repr(packed)] struct S7_Option { a: f32, b: u8, diff --git a/src/test/run-pass/packed-struct-vec.rs b/src/test/run-pass/packed-struct-vec.rs index 94e4e3c6bef29..03750757cbadf 100644 --- a/src/test/run-pass/packed-struct-vec.rs +++ b/src/test/run-pass/packed-struct-vec.rs @@ -12,7 +12,7 @@ use std::mem; -#[packed] +#[repr(packed)] #[deriving(Eq, Show)] struct Foo { bar: u8, diff --git a/src/test/run-pass/packed-tuple-struct-layout.rs b/src/test/run-pass/packed-tuple-struct-layout.rs index 3ec6182beb261..5fb43503ccb26 100644 --- a/src/test/run-pass/packed-tuple-struct-layout.rs +++ b/src/test/run-pass/packed-tuple-struct-layout.rs @@ -10,10 +10,10 @@ use std::mem; -#[packed] +#[repr(packed)] struct S4(u8,[u8, .. 3]); -#[packed] +#[repr(packed)] struct S5(u8,u32); pub fn main() { diff --git a/src/test/run-pass/packed-tuple-struct-size.rs b/src/test/run-pass/packed-tuple-struct-size.rs index 9036df0bbd1e9..1d5b4308f76b8 100644 --- a/src/test/run-pass/packed-tuple-struct-size.rs +++ b/src/test/run-pass/packed-tuple-struct-size.rs @@ -12,13 +12,13 @@ use std::mem; -#[packed] +#[repr(packed)] struct S4(u8,[u8, .. 3]); -#[packed] +#[repr(packed)] struct S5(u8, u32); -#[packed] +#[repr(packed)] struct S13(i64, f32, u8); enum Foo { @@ -26,10 +26,10 @@ enum Foo { Baz = 2 } -#[packed] +#[repr(packed)] struct S3_Foo(u8, u16, Foo); -#[packed] +#[repr(packed)] struct S7_Option(f32, u8, u16, Option<@f64>); pub fn main() { From fc4483492f26caf3b60f337eda52e736f697afd7 Mon Sep 17 00:00:00 2001 From: Corey Richardson Date: Tue, 27 May 2014 18:37:49 -0700 Subject: [PATCH 3/5] Add #[repr(C)] to all the things! --- src/liblibc/lib.rs | 84 +++++++++++++++++++++++++++++++++ src/libnative/io/c_unix.rs | 10 ++++ src/librustdoc/html/markdown.rs | 4 ++ src/librustuv/uvll.rs | 5 ++ src/libstd/rt/libunwind.rs | 1 + src/libstd/unstable/mutex.rs | 6 +++ 6 files changed, 110 insertions(+) diff --git a/src/liblibc/lib.rs b/src/liblibc/lib.rs index 1edd99c1d7dcc..68629461b7f98 100644 --- a/src/liblibc/lib.rs +++ b/src/liblibc/lib.rs @@ -355,6 +355,7 @@ pub mod types { pub type pthread_t = c_ulong; + #[repr(C)] pub struct glob_t { pub gl_pathc: size_t, pub gl_pathv: **c_char, @@ -367,11 +368,13 @@ pub mod types { pub __unused5: *c_void, } + #[repr(C)] pub struct timeval { pub tv_sec: time_t, pub tv_usec: suseconds_t, } + #[repr(C)] pub struct timespec { pub tv_sec: time_t, pub tv_nsec: c_long, @@ -388,24 +391,29 @@ pub mod types { pub type sa_family_t = u16; pub type in_port_t = u16; pub type in_addr_t = u32; + #[repr(C)] pub struct sockaddr { pub sa_family: sa_family_t, pub sa_data: [u8, ..14], } + #[repr(C)] pub struct sockaddr_storage { pub ss_family: sa_family_t, pub __ss_align: i64, pub __ss_pad2: [u8, ..112], } + #[repr(C)] pub struct sockaddr_in { pub sin_family: sa_family_t, pub sin_port: in_port_t, pub sin_addr: in_addr, pub sin_zero: [u8, ..8], } + #[repr(C)] pub struct in_addr { pub s_addr: in_addr_t, } + #[repr(C)] pub struct sockaddr_in6 { pub sin6_family: sa_family_t, pub sin6_port: in_port_t, @@ -413,17 +421,21 @@ pub mod types { pub sin6_addr: in6_addr, pub sin6_scope_id: u32, } + #[repr(C)] pub struct in6_addr { pub s6_addr: [u16, ..8] } + #[repr(C)] pub struct ip_mreq { pub imr_multiaddr: in_addr, pub imr_interface: in_addr, } + #[repr(C)] pub struct ip6_mreq { pub ipv6mr_multiaddr: in6_addr, pub ipv6mr_interface: c_uint, } + #[repr(C)] pub struct addrinfo { pub ai_flags: c_int, pub ai_family: c_int, @@ -445,6 +457,7 @@ pub mod types { pub ai_next: *addrinfo, } + #[repr(C)] pub struct sockaddr_un { pub sun_family: sa_family_t, pub sun_path: [c_char, ..108] @@ -517,6 +530,7 @@ pub mod types { pub type blksize_t = i32; pub type blkcnt_t = i32; + #[repr(C)] pub struct stat { pub st_dev: dev_t, pub __pad1: c_short, @@ -540,11 +554,13 @@ pub mod types { pub __unused5: c_long, } + #[repr(C)] pub struct utimbuf { pub actime: time_t, pub modtime: time_t, } + #[repr(C)] pub struct pthread_attr_t { pub __size: [u32, ..9] } @@ -559,6 +575,7 @@ pub mod types { pub type blksize_t = u32; pub type blkcnt_t = u32; + #[repr(C)] pub struct stat { pub st_dev: c_ulonglong, pub __pad0: [c_uchar, ..4], @@ -581,11 +598,13 @@ pub mod types { pub st_ino: c_ulonglong, } + #[repr(C)] pub struct utimbuf { pub actime: time_t, pub modtime: time_t, } + #[repr(C)] pub struct pthread_attr_t { pub __size: [u32, ..9] } @@ -601,6 +620,7 @@ pub mod types { pub type blksize_t = i32; pub type blkcnt_t = i32; + #[repr(C)] pub struct stat { pub st_dev: c_ulong, pub st_pad1: [c_long, ..3], @@ -624,11 +644,13 @@ pub mod types { pub st_pad5: [c_long, ..14], } + #[repr(C)] pub struct utimbuf { pub actime: time_t, pub modtime: time_t, } + #[repr(C)] pub struct pthread_attr_t { pub __size: [u32, ..9] } @@ -685,6 +707,7 @@ pub mod types { pub type nlink_t = u64; pub type blksize_t = i64; pub type blkcnt_t = i64; + #[repr(C)] pub struct stat { pub st_dev: dev_t, pub st_ino: ino_t, @@ -706,11 +729,13 @@ pub mod types { pub __unused: [c_long, ..3], } + #[repr(C)] pub struct utimbuf { pub actime: time_t, pub modtime: time_t, } + #[repr(C)] pub struct pthread_attr_t { pub __size: [u64, ..7] } @@ -735,6 +760,7 @@ pub mod types { pub type pthread_t = uintptr_t; + #[repr(C)] pub struct glob_t { pub gl_pathc: size_t, pub __unused1: size_t, @@ -751,11 +777,13 @@ pub mod types { pub __unused8: *c_void, } + #[repr(C)] pub struct timeval { pub tv_sec: time_t, pub tv_usec: suseconds_t, } + #[repr(C)] pub struct timespec { pub tv_sec: time_t, pub tv_nsec: c_long, @@ -772,11 +800,13 @@ pub mod types { pub type sa_family_t = u8; pub type in_port_t = u16; pub type in_addr_t = u32; + #[repr(C)] pub struct sockaddr { pub sa_len: u8, pub sa_family: sa_family_t, pub sa_data: [u8, ..14], } + #[repr(C)] pub struct sockaddr_storage { pub ss_len: u8, pub ss_family: sa_family_t, @@ -784,6 +814,7 @@ pub mod types { pub __ss_align: i64, pub __ss_pad2: [u8, ..112], } + #[repr(C)] pub struct sockaddr_in { pub sin_len: u8, pub sin_family: sa_family_t, @@ -791,9 +822,11 @@ pub mod types { pub sin_addr: in_addr, pub sin_zero: [u8, ..8], } + #[repr(C)] pub struct in_addr { pub s_addr: in_addr_t, } + #[repr(C)] pub struct sockaddr_in6 { pub sin6_len: u8, pub sin6_family: sa_family_t, @@ -802,17 +835,21 @@ pub mod types { pub sin6_addr: in6_addr, pub sin6_scope_id: u32, } + #[repr(C)] pub struct in6_addr { pub s6_addr: [u16, ..8] } + #[repr(C)] pub struct ip_mreq { pub imr_multiaddr: in_addr, pub imr_interface: in_addr, } + #[repr(C)] pub struct ip6_mreq { pub ipv6mr_multiaddr: in6_addr, pub ipv6mr_interface: c_uint, } + #[repr(C)] pub struct addrinfo { pub ai_flags: c_int, pub ai_family: c_int, @@ -823,6 +860,7 @@ pub mod types { pub ai_addr: *sockaddr, pub ai_next: *addrinfo, } + #[repr(C)] pub struct sockaddr_un { pub sun_len: u8, pub sun_family: sa_family_t, @@ -881,6 +919,7 @@ pub mod types { pub type blksize_t = i64; pub type blkcnt_t = i64; pub type fflags_t = u32; + #[repr(C)] pub struct stat { pub st_dev: dev_t, pub st_ino: ino_t, @@ -906,6 +945,7 @@ pub mod types { pub __unused: [uint8_t, ..2], } + #[repr(C)] pub struct utimbuf { pub actime: time_t, pub modtime: time_t, @@ -934,6 +974,7 @@ pub mod types { // pub Note: this is the struct called stat64 in win32. Not stat, // nor stati64. + #[repr(C)] pub struct stat { pub st_dev: dev_t, pub st_ino: ino_t, @@ -949,16 +990,19 @@ pub mod types { } // note that this is called utimbuf64 in win32 + #[repr(C)] pub struct utimbuf { pub actime: time64_t, pub modtime: time64_t, } + #[repr(C)] pub struct timeval { pub tv_sec: time_t, pub tv_usec: suseconds_t, } + #[repr(C)] pub struct timespec { pub tv_sec: time_t, pub tv_nsec: c_long, @@ -975,24 +1019,29 @@ pub mod types { pub type sa_family_t = u16; pub type in_port_t = u16; pub type in_addr_t = u32; + #[repr(C)] pub struct sockaddr { pub sa_family: sa_family_t, pub sa_data: [u8, ..14], } + #[repr(C)] pub struct sockaddr_storage { pub ss_family: sa_family_t, pub __ss_align: i64, pub __ss_pad2: [u8, ..112], } + #[repr(C)] pub struct sockaddr_in { pub sin_family: sa_family_t, pub sin_port: in_port_t, pub sin_addr: in_addr, pub sin_zero: [u8, ..8], } + #[repr(C)] pub struct in_addr { pub s_addr: in_addr_t, } + #[repr(C)] pub struct sockaddr_in6 { pub sin6_family: sa_family_t, pub sin6_port: in_port_t, @@ -1000,17 +1049,21 @@ pub mod types { pub sin6_addr: in6_addr, pub sin6_scope_id: u32, } + #[repr(C)] pub struct in6_addr { pub s6_addr: [u16, ..8] } + #[repr(C)] pub struct ip_mreq { pub imr_multiaddr: in_addr, pub imr_interface: in_addr, } + #[repr(C)] pub struct ip6_mreq { pub ipv6mr_multiaddr: in6_addr, pub ipv6mr_interface: c_uint, } + #[repr(C)] pub struct addrinfo { pub ai_flags: c_int, pub ai_family: c_int, @@ -1021,6 +1074,7 @@ pub mod types { pub ai_addr: *sockaddr, pub ai_next: *addrinfo, } + #[repr(C)] pub struct sockaddr_un { pub sun_family: sa_family_t, pub sun_path: [c_char, ..108] @@ -1159,6 +1213,7 @@ pub mod types { pub type time64_t = i64; pub type int64 = i64; + #[repr(C)] pub struct STARTUPINFO { pub cb: DWORD, pub lpReserved: LPWSTR, @@ -1181,6 +1236,7 @@ pub mod types { } pub type LPSTARTUPINFO = *mut STARTUPINFO; + #[repr(C)] pub struct PROCESS_INFORMATION { pub hProcess: HANDLE, pub hThread: HANDLE, @@ -1189,6 +1245,7 @@ pub mod types { } pub type LPPROCESS_INFORMATION = *mut PROCESS_INFORMATION; + #[repr(C)] pub struct SYSTEM_INFO { pub wProcessorArchitecture: WORD, pub wReserved: WORD, @@ -1204,6 +1261,7 @@ pub mod types { } pub type LPSYSTEM_INFO = *mut SYSTEM_INFO; + #[repr(C)] pub struct MEMORY_BASIC_INFORMATION { pub BaseAddress: LPVOID, pub AllocationBase: LPVOID, @@ -1215,6 +1273,7 @@ pub mod types { } pub type LPMEMORY_BASIC_INFORMATION = *mut MEMORY_BASIC_INFORMATION; + #[repr(C)] pub struct OVERLAPPED { pub Internal: *c_ulong, pub InternalHigh: *c_ulong, @@ -1225,6 +1284,7 @@ pub mod types { pub type LPOVERLAPPED = *mut OVERLAPPED; + #[repr(C)] pub struct FILETIME { pub dwLowDateTime: DWORD, pub dwHighDateTime: DWORD, @@ -1232,6 +1292,7 @@ pub mod types { pub type LPFILETIME = *mut FILETIME; + #[repr(C)] pub struct GUID { pub Data1: DWORD, pub Data2: WORD, @@ -1239,6 +1300,7 @@ pub mod types { pub Data4: [BYTE, ..8], } + #[repr(C)] pub struct WSAPROTOCOLCHAIN { pub ChainLen: c_int, pub ChainEntries: [DWORD, ..MAX_PROTOCOL_CHAIN], @@ -1246,6 +1308,7 @@ pub mod types { pub type LPWSAPROTOCOLCHAIN = *mut WSAPROTOCOLCHAIN; + #[repr(C)] pub struct WSAPROTOCOL_INFO { pub dwServiceFlags1: DWORD, pub dwServiceFlags2: DWORD, @@ -1287,6 +1350,7 @@ pub mod types { pub type pthread_t = uintptr_t; + #[repr(C)] pub struct glob_t { pub gl_pathc: size_t, pub __unused1: c_int, @@ -1303,11 +1367,13 @@ pub mod types { pub __unused8: *c_void, } + #[repr(C)] pub struct timeval { pub tv_sec: time_t, pub tv_usec: suseconds_t, } + #[repr(C)] pub struct timespec { pub tv_sec: time_t, pub tv_nsec: c_long, @@ -1325,11 +1391,13 @@ pub mod types { pub type sa_family_t = u8; pub type in_port_t = u16; pub type in_addr_t = u32; + #[repr(C)] pub struct sockaddr { pub sa_len: u8, pub sa_family: sa_family_t, pub sa_data: [u8, ..14], } + #[repr(C)] pub struct sockaddr_storage { pub ss_len: u8, pub ss_family: sa_family_t, @@ -1337,6 +1405,7 @@ pub mod types { pub __ss_align: i64, pub __ss_pad2: [u8, ..112], } + #[repr(C)] pub struct sockaddr_in { pub sin_len: u8, pub sin_family: sa_family_t, @@ -1344,9 +1413,11 @@ pub mod types { pub sin_addr: in_addr, pub sin_zero: [u8, ..8], } + #[repr(C)] pub struct in_addr { pub s_addr: in_addr_t, } + #[repr(C)] pub struct sockaddr_in6 { pub sin6_len: u8, pub sin6_family: sa_family_t, @@ -1355,17 +1426,21 @@ pub mod types { pub sin6_addr: in6_addr, pub sin6_scope_id: u32, } + #[repr(C)] pub struct in6_addr { pub s6_addr: [u16, ..8] } + #[repr(C)] pub struct ip_mreq { pub imr_multiaddr: in_addr, pub imr_interface: in_addr, } + #[repr(C)] pub struct ip6_mreq { pub ipv6mr_multiaddr: in6_addr, pub ipv6mr_interface: c_uint, } + #[repr(C)] pub struct addrinfo { pub ai_flags: c_int, pub ai_family: c_int, @@ -1376,6 +1451,7 @@ pub mod types { pub ai_addr: *sockaddr, pub ai_next: *addrinfo, } + #[repr(C)] pub struct sockaddr_un { pub sun_len: u8, pub sun_family: sa_family_t, @@ -1433,6 +1509,7 @@ pub mod types { pub type blksize_t = i64; pub type blkcnt_t = i32; + #[repr(C)] pub struct stat { pub st_dev: dev_t, pub st_mode: mode_t, @@ -1458,11 +1535,13 @@ pub mod types { pub st_qspare: [int64_t, ..2], } + #[repr(C)] pub struct utimbuf { pub actime: time_t, pub modtime: time_t, } + #[repr(C)] pub struct pthread_attr_t { pub __sig: c_long, pub __opaque: [c_char, ..36] @@ -1473,6 +1552,7 @@ pub mod types { pub mod bsd44 { } pub mod extra { + #[repr(C)] pub struct mach_timebase_info { pub numer: u32, pub denom: u32, @@ -1531,6 +1611,7 @@ pub mod types { pub type blksize_t = i64; pub type blkcnt_t = i32; + #[repr(C)] pub struct stat { pub st_dev: dev_t, pub st_mode: mode_t, @@ -1556,11 +1637,13 @@ pub mod types { pub st_qspare: [int64_t, ..2], } + #[repr(C)] pub struct utimbuf { pub actime: time_t, pub modtime: time_t, } + #[repr(C)] pub struct pthread_attr_t { pub __sig: c_long, pub __opaque: [c_char, ..56] @@ -1571,6 +1654,7 @@ pub mod types { pub mod bsd44 { } pub mod extra { + #[repr(C)] pub struct mach_timebase_info { pub numer: u32, pub denom: u32, diff --git a/src/libnative/io/c_unix.rs b/src/libnative/io/c_unix.rs index 767090a10cda2..1888976527f51 100644 --- a/src/libnative/io/c_unix.rs +++ b/src/libnative/io/c_unix.rs @@ -73,6 +73,7 @@ extern { mod select { pub static FD_SETSIZE: uint = 1024; + #[repr(C)] pub struct fd_set { fds_bits: [i32, ..(FD_SETSIZE / 32)] } @@ -90,6 +91,7 @@ mod select { pub static FD_SETSIZE: uint = 1024; + #[repr(C)] pub struct fd_set { fds_bits: [uint, ..(FD_SETSIZE / uint::BITS)] } @@ -117,6 +119,7 @@ mod signal { // This definition is not as accurate as it could be, {pid, uid, status} is // actually a giant union. Currently we're only interested in these fields, // however. + #[repr(C)] pub struct siginfo { si_signo: libc::c_int, si_errno: libc::c_int, @@ -126,6 +129,7 @@ mod signal { pub status: libc::c_int, } + #[repr(C)] pub struct sigaction { pub sa_handler: extern fn(libc::c_int), pub sa_mask: sigset_t, @@ -133,10 +137,13 @@ mod signal { sa_restorer: *mut libc::c_void, } + #[repr(C)] #[cfg(target_word_size = "32")] pub struct sigset_t { __val: [libc::c_ulong, ..32], } + + #[repr(C)] #[cfg(target_word_size = "64")] pub struct sigset_t { __val: [libc::c_ulong, ..16], @@ -166,6 +173,7 @@ mod signal { // This structure has more fields, but we're not all that interested in // them. + #[repr(C)] pub struct siginfo { pub si_signo: libc::c_int, pub si_errno: libc::c_int, @@ -176,6 +184,7 @@ mod signal { } #[cfg(target_os = "macos")] + #[repr(C)] pub struct sigaction { pub sa_handler: extern fn(libc::c_int), sa_tramp: *mut libc::c_void, @@ -184,6 +193,7 @@ mod signal { } #[cfg(target_os = "freebsd")] + #[repr(C)] pub struct sigaction { pub sa_handler: extern fn(libc::c_int), pub sa_flags: libc::c_int, diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index f49b7f3e98903..8dab83b94deeb 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -61,6 +61,7 @@ static HOEDOWN_EXTENSIONS: libc::c_uint = type hoedown_document = libc::c_void; // this is opaque to us +#[repr(C)] struct hoedown_renderer { opaque: *mut hoedown_html_renderer_state, blockcode: Option, } +#[repr(C)] struct html_toc_data { header_count: libc::c_int, current_level: libc::c_int, @@ -95,6 +98,7 @@ struct MyOpaque { toc_builder: Option, } +#[repr(C)] struct hoedown_buffer { data: *u8, size: libc::size_t, diff --git a/src/librustuv/uvll.rs b/src/librustuv/uvll.rs index 6236fd0e0e563..a41cb797d8ff3 100644 --- a/src/librustuv/uvll.rs +++ b/src/librustuv/uvll.rs @@ -98,6 +98,7 @@ pub type uv_buf_len_t = libc::size_t; pub type uv_buf_len_t = libc::c_ulong; // see libuv/include/uv-unix.h +#[repr(C)] #[cfg(unix)] pub struct uv_buf_t { pub base: *u8, @@ -118,6 +119,7 @@ pub enum uv_run_mode { RUN_NOWAIT, } +#[repr(C)] pub struct uv_process_options_t { pub exit_cb: uv_exit_cb, pub file: *libc::c_char, @@ -133,6 +135,7 @@ pub struct uv_process_options_t { // These fields are private because they must be interfaced with through the // functions below. +#[repr(C)] pub struct uv_stdio_container_t { flags: libc::c_int, stream: *uv_stream_t, @@ -159,11 +162,13 @@ pub type uv_tty_t = c_void; pub type uv_signal_t = c_void; pub type uv_shutdown_t = c_void; +#[repr(C)] pub struct uv_timespec_t { pub tv_sec: libc::c_long, pub tv_nsec: libc::c_long } +#[repr(C)] pub struct uv_stat_t { pub st_dev: libc::uint64_t, pub st_mode: libc::uint64_t, diff --git a/src/libstd/rt/libunwind.rs b/src/libstd/rt/libunwind.rs index 4fd610d742360..ab60051ae113e 100644 --- a/src/libstd/rt/libunwind.rs +++ b/src/libstd/rt/libunwind.rs @@ -66,6 +66,7 @@ pub static unwinder_private_data_size: int = 20; #[cfg(target_arch = "mips")] pub static unwinder_private_data_size: int = 2; +#[repr(C)] pub struct _Unwind_Exception { pub exception_class: _Unwind_Exception_Class, pub exception_cleanup: _Unwind_Exception_Cleanup_Fn, diff --git a/src/libstd/unstable/mutex.rs b/src/libstd/unstable/mutex.rs index 04da7dab6c658..743e36944a16b 100644 --- a/src/libstd/unstable/mutex.rs +++ b/src/libstd/unstable/mutex.rs @@ -299,10 +299,12 @@ mod imp { static _PTHREAD_MUTEX_SIG_init: libc::c_long = 0x32AAABA7; static _PTHREAD_COND_SIG_init: libc::c_long = 0x3CB0B1BB; + #[repr(C)] pub struct pthread_mutex_t { __sig: libc::c_long, __opaque: [u8, ..__PTHREAD_MUTEX_SIZE__], } + #[repr(C)] pub struct pthread_cond_t { __sig: libc::c_long, __opaque: [u8, ..__PTHREAD_COND_SIZE__], @@ -340,10 +342,12 @@ mod imp { #[cfg(target_arch = "mips")] static __SIZEOF_PTHREAD_COND_T: uint = 48 - 8; + #[repr(C)] pub struct pthread_mutex_t { __align: libc::c_longlong, size: [u8, ..__SIZEOF_PTHREAD_MUTEX_T], } + #[repr(C)] pub struct pthread_cond_t { __align: libc::c_longlong, size: [u8, ..__SIZEOF_PTHREAD_COND_T], @@ -362,7 +366,9 @@ mod imp { mod os { use libc; + #[repr(C)] pub struct pthread_mutex_t { value: libc::c_int } + #[repr(C)] pub struct pthread_cond_t { value: libc::c_int } pub static PTHREAD_MUTEX_INITIALIZER: pthread_mutex_t = pthread_mutex_t { From 4b2a8d248add084daf18904ea3e76d367b4a94cf Mon Sep 17 00:00:00 2001 From: Corey Richardson Date: Thu, 29 May 2014 12:41:58 -0700 Subject: [PATCH 4/5] manual: fix link --- src/doc/rust.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rust.md b/src/doc/rust.md index 73ab5fea92ea2..1577dff7320de 100644 --- a/src/doc/rust.md +++ b/src/doc/rust.md @@ -1222,7 +1222,7 @@ let c = [Cookie, Cookie, Cookie, Cookie]; ~~~~ The precise memory layout of a structure is not specified. One can specify a -particular layout using the [`repr` attribute]( +particular layout using the [`repr` attribute](#ffi-attributes). By using the `struct_inherit` feature gate, structures may use single inheritance. A Structure may only inherit from a single other structure, called the _super-struct_. The inheriting structure (sub-struct) From 5b72258579167acbd993abf4b572b5b9dc0a8229 Mon Sep 17 00:00:00 2001 From: Corey Richardson Date: Fri, 30 May 2014 15:27:17 -0700 Subject: [PATCH 5/5] WIP! --- src/liblibc/lib.rs | 1 + src/librustc/middle/lint.rs | 38 +---------- src/librustc/middle/trans/adt.rs | 62 +----------------- src/librustc/middle/ty.rs | 87 ++++++++++++++++++++----- src/librustc/middle/typeck/check/mod.rs | 4 +- src/libsyntax/attr.rs | 71 ++++---------------- src/test/compile-fail/issue-14309.rs | 4 +- 7 files changed, 93 insertions(+), 174 deletions(-) diff --git a/src/liblibc/lib.rs b/src/liblibc/lib.rs index 68629461b7f98..1283a3f066a5c 100644 --- a/src/liblibc/lib.rs +++ b/src/liblibc/lib.rs @@ -320,6 +320,7 @@ pub mod types { __variant1, __variant2, } + pub enum FILE {} pub enum fpos_t {} } diff --git a/src/librustc/middle/lint.rs b/src/librustc/middle/lint.rs index af0e771f41199..74f61ebefb3fd 100644 --- a/src/librustc/middle/lint.rs +++ b/src/librustc/middle/lint.rs @@ -40,7 +40,6 @@ use metadata::csearch; use middle::dead::DEAD_CODE_LINT_STR; use middle::pat_util; use middle::privacy; -use middle::trans::adt; // for `adt::is_ffi_safe` use middle::ty; use middle::typeck::astconv::{ast_ty_to_ty, AstConv}; use middle::typeck::infer; @@ -942,40 +941,9 @@ fn check_item_ctypes(cx: &Context, it: &ast::Item) { libc::c_uint or libc::c_ulong should be used"); } ast::DefTy(def_id) => { - match adt::is_ffi_safe(cx.tcx, def_id) { - Ok(_) => { }, - Err(types) => { - // in the enum case, we don't care about - // "fields". - - let ty = ty::get(ty::lookup_item_type(cx.tcx, def_id).ty); - - match ty.sty { - ty::ty_struct(_, _) => { - cx.span_lint(CTypes, aty.span, "found struct without \ - FFI-safe representation used in FFI"); - - for def_id in types.iter() { - if !cx.checked_ffi_structs.borrow_mut() - .insert(def_id.node) { - return; - } - - match cx.tcx.map.opt_span(def_id.node) { - Some(sp) => cx.tcx.sess.span_note(sp, "consider \ - adding `#[repr(C)]` to this type"), - None => { } - } - } - }, - ty::ty_enum(_, _) => { - cx.span_lint(CTypes, aty.span, - "found enum without FFI-safe representation \ - annotation used in FFI"); - } - _ => { } - } - } + if !ty::is_ffi_safe(cx.tcx, def_id) { + cx.span_lint(CTypes, aty.span, "type without FFI-safe \ + representation used in FFI"); } } _ => () diff --git a/src/librustc/middle/trans/adt.rs b/src/librustc/middle/trans/adt.rs index 236db9e7c5e18..75ac26d0e4e1c 100644 --- a/src/librustc/middle/trans/adt.rs +++ b/src/librustc/middle/trans/adt.rs @@ -49,7 +49,6 @@ use libc::c_ulonglong; use std::container::Map; use std::num::Bitwise; use std::rc::Rc; -use std; use lib::llvm::{ValueRef, True, IntEQ, IntNE}; use middle::trans::_match; @@ -166,7 +165,7 @@ fn represent_type_uncached(cx: &CrateContext, t: ty::t) -> Repr { } ty::ty_enum(def_id, ref substs) => { let cases = get_cases(cx.tcx(), def_id, substs); - let hint = ty::lookup_enum_repr_hint(cx.tcx(), def_id); + let hint = *ty::lookup_repr_hints(cx.tcx(), def_id).as_slice().get(0).unwrap_or(&attr::ReprAny); if cases.len() == 0 { // Uninhabitable; represent as unit @@ -253,65 +252,6 @@ fn represent_type_uncached(cx: &CrateContext, t: ty::t) -> Repr { } } -/// Determine, without doing translation, whether an ADT must be FFI-safe. -/// For use in lint or similar, where being sound but slightly incomplete is acceptable. -/// Returns Ok(()) if it is, and Err(causes) which is a vector of the DefId's -/// of the types that are unsafe (either the type being checked itself if it -/// lacks a repr attribute, or the fields of a struct). -pub fn is_ffi_safe(tcx: &ty::ctxt, def_id: ast::DefId) -> std::result::Result<(), Vec> { - match ty::get(ty::lookup_item_type(tcx, def_id).ty).sty { - ty::ty_enum(def_id, _) => { - let variants = ty::enum_variants(tcx, def_id); - // Univariant => like struct/tuple. - if variants.len() <= 1 { - return Ok(()); - } - let hint = ty::lookup_enum_repr_hint(tcx, def_id); - // Appropriate representation explicitly selected? - if hint.is_ffi_safe() { - return Ok(()); - } - // Option> and similar are used in FFI. Rather than try to - // resolve type parameters and recognize this case exactly, this - // overapproximates -- assuming that if a non-C-like enum is being - // used in FFI then the user knows what they're doing. - if variants.iter().any(|vi| !vi.args.is_empty()) { - return Ok(()); - } - Err(vec![def_id]) - }, - ty::ty_struct(def_id, _) => { - let struct_is_safe = - ty::lookup_struct_repr_hint(tcx, def_id).contains(&attr::ReprExtern); - let mut fields_are_safe = true; - let mut bad_fields = Vec::new(); - - if !struct_is_safe { - bad_fields.push(def_id); - } - - for field in ty::lookup_struct_fields(tcx, def_id).iter() { - match is_ffi_safe(tcx, field.id) { - Ok(_) => { } - Err(types) => { - fields_are_safe = false; - bad_fields.extend(types.move_iter()) - } - } - } - - if struct_is_safe && fields_are_safe { - Ok(()) - } else { - Err(bad_fields) - } - }, - // tuple, etc. - // (is this right in the present of typedefs?) - _ => Ok(()) - } -} - // this should probably all be in ty struct Case { discr: Disr, tys: Vec } impl Case { diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index e720650c3971a..b5d9549dd0692 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -1822,7 +1822,8 @@ def_type_content_sets!( // ReachesManaged /* see [1] below */ = 0b0000_0100__0000_0000__0000, ReachesMutable = 0b0000_1000__0000_0000__0000, ReachesNoShare = 0b0001_0000__0000_0000__0000, - ReachesAll = 0b0001_1111__0000_0000__0000, + ReachesFfiUnsafe = 0b0010_0000__0000_0000__0000, + ReachesAll = 0b0011_1111__0000_0000__0000, // Things that cause values to *move* rather than *copy* Moves = 0b0000_0000__0000_1011__0000, @@ -2059,6 +2060,11 @@ pub fn type_contents(cx: &ctxt, ty: t) -> TypeContents { cache.insert(ty_id, TC::None); let result = match get(ty).sty { + // uint and int are ffi-unsafe + ty_uint(ast::TyU) | ty_int(ast::TyI) => { + TC::ReachesFfiUnsafe + } + // Scalar and unique types are sendable, and durable ty_nil | ty_bot | ty_bool | ty_int(_) | ty_uint(_) | ty_float(_) | ty_bare_fn(_) | ty::ty_char | ty_str => { @@ -2096,7 +2102,7 @@ pub fn type_contents(cx: &ctxt, ty: t) -> TypeContents { } ty_vec(mt, _) => { - tc_mt(cx, mt, cache) + tc_mt(cx, mt, cache) & TC::ReachesFfiUnsafe // don't use slices in FFI } ty_struct(did, ref substs) => { @@ -2104,6 +2110,11 @@ pub fn type_contents(cx: &ctxt, ty: t) -> TypeContents { let mut res = TypeContents::union(flds.as_slice(), |f| tc_mt(cx, f.mt, cache)); + + if !lookup_repr_hints(cx, did).contains(&attr::ReprExtern) { + res = res | TC::ReachesFfiUnsafe; + } + if ty::has_dtor(cx, did) { res = res | TC::OwnsDtor; } @@ -2117,13 +2128,54 @@ pub fn type_contents(cx: &ctxt, ty: t) -> TypeContents { ty_enum(did, ref substs) => { let variants = substd_enum_variants(cx, did, substs); - let res = + let mut res = TypeContents::union(variants.as_slice(), |variant| { TypeContents::union(variant.args.as_slice(), |arg_ty| { tc_ty(cx, *arg_ty, cache) }) }); + + if variants.len() != 0 { + let repr_hints = lookup_repr_hints(cx, did); + if repr_hints.len() > 1 { + // this is an error later on, but this type isn't safe + res = res | TC::ReachesFfiUnsafe; + } + + match repr_hints.as_slice().get(0) { + Some(h) => if !h.is_ffi_safe() { + res = res | TC::ReachesFfiUnsafe; + }, + // ReprAny + None => { + res = res | TC::ReachesFfiUnsafe; + + // We allow ReprAny enums if they are eligible for + // the nullable pointer optimization and the + // contained type is an `extern fn` + + if variants.len() == 2 { + let mut data_idx = 0; + + if variants.get(0).args.len() == 0 { + data_idx = 1; + } + + if variants.get(data_idx).args.len() == 1 { + match get(*variants.get(data_idx).args.get(0)).sty { + ty_bare_fn(..) => { error!("yay it's good!"); res = res - TC::ReachesFfiUnsafe; } + ref ct => { + error!("it had wrong sty {:?} :(", ct); + } + } + } + } + } + } + } + + apply_lang_items(cx, did, res) } @@ -2286,6 +2338,10 @@ pub fn type_moves_by_default(cx: &ctxt, ty: t) -> bool { type_contents(cx, ty).moves_by_default(cx) } +pub fn is_ffi_safe(cx: &ctxt, did: ast::DefId) -> bool { + !type_contents(cx, ty::lookup_item_type(cx, did).ty).intersects(TC::ReachesFfiUnsafe) +} + // True if instantiating an instance of `r_ty` requires an instance of `r_ty`. pub fn is_instantiable(cx: &ctxt, r_ty: t) -> bool { fn type_requires(cx: &ctxt, seen: &mut Vec, @@ -3700,11 +3756,18 @@ pub fn substd_enum_variants(cx: &ctxt, substs: &substs) -> Vec> { enum_variants(cx, id).iter().map(|variant_info| { - let substd_args = variant_info.args.iter() + let substd_args: Vec = variant_info.args.iter() .map(|aty| subst(cx, substs, *aty)).collect(); let substd_ctor_ty = subst(cx, substs, variant_info.ctor_ty); + if !substd_args.iter().all(|t| match get(*t).sty { + ty_param(..) => false, + _ => true + }) { + error!("WOW what the heck is going on???? substd has type parameters still!"); + } + Rc::new(VariantInfo { args: substd_args, ctor_ty: substd_ctor_ty, @@ -3930,7 +3993,7 @@ pub fn has_attr(tcx: &ctxt, did: DefId, attr: &str) -> bool { /// Determine whether an item is annotated with `#[repr(packed)]` pub fn lookup_packed(tcx: &ctxt, did: DefId) -> bool { - lookup_struct_repr_hint(tcx, did).contains(&attr::ReprPacked) + lookup_repr_hints(tcx, did).contains(&attr::ReprPacked) } /// Determine whether an item is annotated with `#[simd]` @@ -3938,22 +4001,12 @@ pub fn lookup_simd(tcx: &ctxt, did: DefId) -> bool { has_attr(tcx, did, "simd") } -/// Obtain the representation annotation for an enum definition. -pub fn lookup_enum_repr_hint(tcx: &ctxt, did: DefId) -> attr::ReprAttr { - let mut acc = attr::ReprAny; - ty::each_attr(tcx, did, |meta| { - acc = attr::find_enum_repr_attr(tcx.sess.diagnostic(), meta, acc); - true - }); - return acc; -} - /// Obtain the representation annotation for a struct definition. -pub fn lookup_struct_repr_hint(tcx: &ctxt, did: DefId) -> Vec { +pub fn lookup_repr_hints(tcx: &ctxt, did: DefId) -> Vec { let mut acc = Vec::new(); ty::each_attr(tcx, did, |meta| { - acc.extend(attr::find_struct_repr_attrs(tcx.sess.diagnostic(), meta).move_iter()); + acc.extend(attr::find_repr_attrs(tcx.sess.diagnostic(), meta).move_iter()); true }); diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs index b58c1508946b0..3d3df557f8d0d 100644 --- a/src/librustc/middle/typeck/check/mod.rs +++ b/src/librustc/middle/typeck/check/mod.rs @@ -3819,7 +3819,9 @@ pub fn check_enum_variants(ccx: &CrateCtxt, return variants; } - let hint = ty::lookup_enum_repr_hint(ccx.tcx, ast::DefId { krate: ast::LOCAL_CRATE, node: id }); + let hint = *ty::lookup_repr_hints(ccx.tcx, ast::DefId { krate: ast::LOCAL_CRATE, node: id }) + .as_slice().get(0).unwrap_or(&attr::ReprAny); + if hint != attr::ReprAny && vs.len() <= 1 { let msg = if vs.len() == 1 { "unsupported representation for univariant enum" diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs index 56f14d01cea4e..9fd735abdb347 100644 --- a/src/libsyntax/attr.rs +++ b/src/libsyntax/attr.rs @@ -453,20 +453,15 @@ pub fn require_unique_names(diagnostic: &SpanHandler, metas: &[@MetaItem]) { /** - * Fold this over attributes to parse #[repr(...)] forms. + * Parse #[repr(...)] forms. * * Valid repr contents: any of the primitive integral type names (see - * `int_type_of_word`, below) to specify the discriminant type; and `C`, to use - * the same discriminant size that the corresponding C enum would. These are - * not allowed on univariant or zero-variant enums, which have no discriminant. - * - * If a discriminant type is so specified, then the discriminant will be - * present (before fields, if any) with that type; reprensentation - * optimizations which would remove it will not be done. + * `int_type_of_word`, below) to specify enum discriminant type; `C`, to use + * the same discriminant size that the corresponding C enum would or C + * structure layout, and `packed` to remove padding. */ -pub fn find_enum_repr_attr(diagnostic: &SpanHandler, attr: &Attribute, acc: ReprAttr) - -> ReprAttr { - let mut acc = acc; +pub fn find_repr_attrs(diagnostic: &SpanHandler, attr: &Attribute) -> Vec { + let mut acc = Vec::new(); match attr.node.value.node { ast::MetaList(ref s, ref items) if s.equiv(&("repr")) => { mark_used(attr); @@ -475,73 +470,33 @@ pub fn find_enum_repr_attr(diagnostic: &SpanHandler, attr: &Attribute, acc: Repr ast::MetaWord(ref word) => { let hint = match word.get() { // Can't use "extern" because it's not a lexical identifier. - "C" => ReprExtern, + "C" => Some(ReprExtern), + "packed" => Some(ReprPacked), _ => match int_type_of_word(word.get()) { - Some(ity) => ReprInt(item.span, ity), + Some(ity) => Some(ReprInt(item.span, ity)), None => { // Not a word we recognize diagnostic.span_err(item.span, "unrecognized representation hint"); - ReprAny + None } } }; - if hint != ReprAny { - if acc == ReprAny { - acc = hint; - } else if acc != hint { - diagnostic.span_warn(item.span, - "conflicting representation hint ignored") - } - } - } - // Not a word: - _ => diagnostic.span_err(item.span, "unrecognized enum representation hint") - } - } - } - // Not a "repr" hint: ignore. - _ => { } - } - acc -} - -/// A struct `repr` attribute can only take the values `C` and `packed`, or -/// possibly both. -pub fn find_struct_repr_attrs(diagnostic: &SpanHandler, attr: &Attribute) -> Vec { - let mut attrs = Vec::new(); - match attr.node.value.node { - ast::MetaList(ref s, ref items) if s.equiv(&("repr")) => { - mark_used(attr); - for item in items.iter() { - match item.node { - ast::MetaWord(ref word) => { - let hint = match word.get() { - "C" => Some(ReprExtern), - "packed" => Some(ReprPacked), - _ => { - // Not a word we recognize - diagnostic.span_err(item.span, - "unrecognized struct representation hint"); - None - } - }; match hint { - Some(h) => attrs.push(h), + Some(h) => acc.push(h), None => { } } } // Not a word: - _ => diagnostic.span_err(item.span, "unrecognized representation hint") + _ => diagnostic.span_err(item.span, "unrecognized enum representation hint") } } } // Not a "repr" hint: ignore. _ => { } } - - attrs + acc } fn int_type_of_word(s: &str) -> Option { diff --git a/src/test/compile-fail/issue-14309.rs b/src/test/compile-fail/issue-14309.rs index 416f1e84d6b52..eb8e75eae785d 100644 --- a/src/test/compile-fail/issue-14309.rs +++ b/src/test/compile-fail/issue-14309.rs @@ -11,7 +11,7 @@ #![deny(ctypes)] #![allow(dead_code)] -struct A { //~ NOTE #[repr(C)] +struct A { //~ NOTE consider adding `#[repr(C)]` to this type x: int } @@ -37,7 +37,7 @@ struct D { } extern "C" { - fn foo(x: A); //~ ERROR FFI-safe + fn foo(x: A); //~ ERROR found struct without FFI-safe representation used in FFI fn bar(x: B); //~ ERROR FFI-safe fn baz(x: C); fn qux(x: A2); //~ ERROR FFI-safe