Skip to content

Commit 5501f79

Browse files
committed
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. To fix errors caused by this, just add #[repr(C)] to the structs, and change #[packed] to #[repr(packed)] Closes #14309 [breaking-change]
1 parent ba5ed97 commit 5501f79

26 files changed

+209
-117
lines changed

src/liblibc/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -334,6 +334,7 @@ pub mod types {
334334
__variant1,
335335
__variant2,
336336
}
337+
337338
pub enum FILE {}
338339
pub enum fpos_t {}
339340
}

src/librustc/lint/builtin.rs

+12-6
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@
2727
2828
use metadata::csearch;
2929
use middle::def::*;
30-
use middle::trans::adt; // for `adt::is_ffi_safe`
3130
use middle::typeck::astconv::ast_ty_to_ty;
3231
use middle::typeck::infer;
3332
use middle::{typeck, ty, def, pat_util, stability};
@@ -362,8 +361,13 @@ impl LintPass for CTypes {
362361
"found rust type `uint` in foreign module, while \
363362
libc::c_uint or libc::c_ulong should be used");
364363
}
365-
def::DefTy(def_id) => {
366-
if !adt::is_ffi_safe(cx.tcx, def_id) {
364+
def::DefTy(..) => {
365+
let tty = match cx.tcx.ast_ty_to_ty_cache.borrow().find(&ty.id) {
366+
Some(&ty::atttce_resolved(t)) => t,
367+
_ => fail!("ast_ty_to_ty_cache was incomplete after typeck!")
368+
};
369+
370+
if !ty::is_ffi_safe(cx.tcx, tty) {
367371
cx.span_lint(CTYPES, ty.span,
368372
"found enum type without foreign-function-safe
369373
representation annotation in foreign module, consider \
@@ -765,9 +769,10 @@ impl LintPass for NonCamelCaseTypes {
765769
}
766770
}
767771

768-
let has_extern_repr = it.attrs.iter().fold(attr::ReprAny, |acc, attr| {
769-
attr::find_repr_attr(cx.tcx.sess.diagnostic(), attr, acc)
770-
}) == attr::ReprExtern;
772+
let has_extern_repr = it.attrs.iter().map(|attr| {
773+
attr::find_repr_attrs(cx.tcx.sess.diagnostic(), attr).iter()
774+
.any(|r| r == &attr::ReprExtern)
775+
}).any(|x| x);
771776
if has_extern_repr { return }
772777

773778
match it.node {
@@ -778,6 +783,7 @@ impl LintPass for NonCamelCaseTypes {
778783
check_case(cx, "trait", it.ident, it.span)
779784
}
780785
ast::ItemEnum(ref enum_definition, _) => {
786+
if has_extern_repr { return }
781787
check_case(cx, "type", it.ident, it.span);
782788
for variant in enum_definition.variants.iter() {
783789
check_case(cx, "variant", variant.node.name, variant.span);

src/librustc/middle/dead.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -190,9 +190,10 @@ impl<'a> MarkSymbolVisitor<'a> {
190190
ast_map::NodeItem(item) => {
191191
match item.node {
192192
ast::ItemStruct(..) => {
193-
let has_extern_repr = item.attrs.iter().fold(attr::ReprAny, |acc, attr| {
194-
attr::find_repr_attr(self.tcx.sess.diagnostic(), attr, acc)
195-
}) == attr::ReprExtern;
193+
let has_extern_repr = item.attrs.iter().fold(false, |acc, attr| {
194+
acc || attr::find_repr_attrs(self.tcx.sess.diagnostic(), attr)
195+
.iter().any(|&x| x == attr::ReprExtern)
196+
});
196197

197198
visit::walk_item(self, &*item, MarkSymbolVisitorContext {
198199
struct_has_extern_repr: has_extern_repr,

src/librustc/middle/trans/adt.rs

+7-31
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@
4646
#![allow(unsigned_negate)]
4747

4848
use libc::c_ulonglong;
49+
use std::collections::Map;
50+
use std::num::Int;
4951
use std::rc::Rc;
5052

5153
use llvm::{ValueRef, True, IntEQ, IntNE};
@@ -178,7 +180,8 @@ fn represent_type_uncached(cx: &CrateContext, t: ty::t) -> Repr {
178180
}
179181
ty::ty_enum(def_id, ref substs) => {
180182
let cases = get_cases(cx.tcx(), def_id, substs);
181-
let hint = ty::lookup_repr_hint(cx.tcx(), def_id);
183+
let hint = *ty::lookup_repr_hints(cx.tcx(), def_id).as_slice().get(0)
184+
.unwrap_or(&attr::ReprAny);
182185

183186
let dtor = ty::ty_dtor(cx.tcx(), def_id).has_drop_flag();
184187

@@ -266,36 +269,6 @@ fn represent_type_uncached(cx: &CrateContext, t: ty::t) -> Repr {
266269
}
267270
}
268271

269-
/// Determine, without doing translation, whether an ADT must be FFI-safe.
270-
/// For use in lint or similar, where being sound but slightly incomplete is acceptable.
271-
pub fn is_ffi_safe(tcx: &ty::ctxt, def_id: ast::DefId) -> bool {
272-
match ty::get(ty::lookup_item_type(tcx, def_id).ty).sty {
273-
ty::ty_enum(def_id, _) => {
274-
let variants = ty::enum_variants(tcx, def_id);
275-
// Univariant => like struct/tuple.
276-
if variants.len() <= 1 {
277-
return true;
278-
}
279-
let hint = ty::lookup_repr_hint(tcx, def_id);
280-
// Appropriate representation explicitly selected?
281-
if hint.is_ffi_safe() {
282-
return true;
283-
}
284-
// Option<Box<T>> and similar are used in FFI. Rather than try to
285-
// resolve type parameters and recognize this case exactly, this
286-
// overapproximates -- assuming that if a non-C-like enum is being
287-
// used in FFI then the user knows what they're doing.
288-
if variants.iter().any(|vi| !vi.args.is_empty()) {
289-
return true;
290-
}
291-
false
292-
}
293-
// struct, tuple, etc.
294-
// (is this right in the present of typedefs?)
295-
_ => true
296-
}
297-
}
298-
299272
// this should probably all be in ty
300273
struct Case {
301274
discr: Disr,
@@ -427,6 +400,9 @@ fn range_to_inttype(cx: &CrateContext, hint: Hint, bounds: &IntBounds) -> IntTyp
427400
}
428401
attr::ReprAny => {
429402
attempts = choose_shortest;
403+
},
404+
attr::ReprPacked => {
405+
cx.tcx.sess.bug("range_to_inttype: found ReprPacked on an enum");
430406
}
431407
}
432408
for &ity in attempts.iter() {

src/librustc/middle/ty.rs

+73-15
Original file line numberDiff line numberDiff line change
@@ -425,7 +425,7 @@ pub struct t { inner: *const t_opaque }
425425

426426
impl fmt::Show for t {
427427
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
428-
"*t_opaque".fmt(f)
428+
write!(f, "{}", get(*self))
429429
}
430430
}
431431

@@ -1811,7 +1811,8 @@ def_type_content_sets!(
18111811
// ReachesManaged /* see [1] below */ = 0b0000_0100__0000_0000__0000,
18121812
ReachesMutable = 0b0000_1000__0000_0000__0000,
18131813
ReachesNoSync = 0b0001_0000__0000_0000__0000,
1814-
ReachesAll = 0b0001_1111__0000_0000__0000,
1814+
ReachesFfiUnsafe = 0b0010_0000__0000_0000__0000,
1815+
ReachesAll = 0b0011_1111__0000_0000__0000,
18151816

18161817
// Things that cause values to *move* rather than *copy*
18171818
Moves = 0b0000_0000__0000_1011__0000,
@@ -2048,38 +2049,44 @@ pub fn type_contents(cx: &ctxt, ty: t) -> TypeContents {
20482049
cache.insert(ty_id, TC::None);
20492050

20502051
let result = match get(ty).sty {
2052+
// uint and int are ffi-unsafe
2053+
ty_uint(ast::TyU) | ty_int(ast::TyI) => {
2054+
TC::ReachesFfiUnsafe
2055+
}
2056+
20512057
// Scalar and unique types are sendable, and durable
20522058
ty_nil | ty_bot | ty_bool | ty_int(_) | ty_uint(_) | ty_float(_) |
20532059
ty_bare_fn(_) | ty::ty_char | ty_str => {
20542060
TC::None
20552061
}
20562062

20572063
ty_closure(ref c) => {
2058-
closure_contents(cx, &**c)
2064+
closure_contents(cx, &**c) | TC::ReachesFfiUnsafe
20592065
}
20602066

20612067
ty_box(typ) => {
2062-
tc_ty(cx, typ, cache).managed_pointer()
2068+
tc_ty(cx, typ, cache).managed_pointer() | TC::ReachesFfiUnsafe
20632069
}
20642070

20652071
ty_uniq(typ) => {
2066-
match get(typ).sty {
2072+
TC::ReachesFfiUnsafe | match get(typ).sty {
20672073
ty_str => TC::OwnsOwned,
20682074
_ => tc_ty(cx, typ, cache).owned_pointer(),
20692075
}
20702076
}
20712077

20722078
ty_trait(box ty::TyTrait { bounds, .. }) => {
2073-
object_contents(cx, bounds)
2079+
object_contents(cx, bounds) | TC::ReachesFfiUnsafe
20742080
}
20752081

20762082
ty_ptr(ref mt) => {
20772083
tc_ty(cx, mt.ty, cache).unsafe_pointer()
20782084
}
20792085

20802086
ty_rptr(r, ref mt) => {
2081-
match get(mt.ty).sty {
2087+
TC::ReachesFfiUnsafe | match get(mt.ty).sty {
20822088
ty_str => borrowed_contents(r, ast::MutImmutable),
2089+
ty_vec(..) => tc_ty(cx, mt.ty, cache).reference(borrowed_contents(r, mt.mutbl)),
20832090
_ => tc_ty(cx, mt.ty, cache).reference(borrowed_contents(r, mt.mutbl)),
20842091
}
20852092
}
@@ -2093,6 +2100,11 @@ pub fn type_contents(cx: &ctxt, ty: t) -> TypeContents {
20932100
let mut res =
20942101
TypeContents::union(flds.as_slice(),
20952102
|f| tc_mt(cx, f.mt, cache));
2103+
2104+
if !lookup_repr_hints(cx, did).contains(&attr::ReprExtern) {
2105+
res = res | TC::ReachesFfiUnsafe;
2106+
}
2107+
20962108
if ty::has_dtor(cx, did) {
20972109
res = res | TC::OwnsDtor;
20982110
}
@@ -2119,9 +2131,49 @@ pub fn type_contents(cx: &ctxt, ty: t) -> TypeContents {
21192131
tc_ty(cx, *arg_ty, cache)
21202132
})
21212133
});
2134+
21222135
if ty::has_dtor(cx, did) {
21232136
res = res | TC::OwnsDtor;
21242137
}
2138+
2139+
if variants.len() != 0 {
2140+
let repr_hints = lookup_repr_hints(cx, did);
2141+
if repr_hints.len() > 1 {
2142+
// this is an error later on, but this type isn't safe
2143+
res = res | TC::ReachesFfiUnsafe;
2144+
}
2145+
2146+
match repr_hints.as_slice().get(0) {
2147+
Some(h) => if !h.is_ffi_safe() {
2148+
res = res | TC::ReachesFfiUnsafe;
2149+
},
2150+
// ReprAny
2151+
None => {
2152+
res = res | TC::ReachesFfiUnsafe;
2153+
2154+
// We allow ReprAny enums if they are eligible for
2155+
// the nullable pointer optimization and the
2156+
// contained type is an `extern fn`
2157+
2158+
if variants.len() == 2 {
2159+
let mut data_idx = 0;
2160+
2161+
if variants.get(0).args.len() == 0 {
2162+
data_idx = 1;
2163+
}
2164+
2165+
if variants.get(data_idx).args.len() == 1 {
2166+
match get(*variants.get(data_idx).args.get(0)).sty {
2167+
ty_bare_fn(..) => { res = res - TC::ReachesFfiUnsafe; }
2168+
_ => { }
2169+
}
2170+
}
2171+
}
2172+
}
2173+
}
2174+
}
2175+
2176+
21252177
apply_lang_items(cx, did, res)
21262178
}
21272179

@@ -2273,6 +2325,10 @@ pub fn type_moves_by_default(cx: &ctxt, ty: t) -> bool {
22732325
type_contents(cx, ty).moves_by_default(cx)
22742326
}
22752327

2328+
pub fn is_ffi_safe(cx: &ctxt, ty: t) -> bool {
2329+
!type_contents(cx, ty).intersects(TC::ReachesFfiUnsafe)
2330+
}
2331+
22762332
// True if instantiating an instance of `r_ty` requires an instance of `r_ty`.
22772333
pub fn is_instantiable(cx: &ctxt, r_ty: t) -> bool {
22782334
fn type_requires(cx: &ctxt, seen: &mut Vec<DefId>,
@@ -3767,7 +3823,7 @@ pub fn substd_enum_variants(cx: &ctxt,
37673823
-> Vec<Rc<VariantInfo>> {
37683824
enum_variants(cx, id).iter().map(|variant_info| {
37693825
let substd_args = variant_info.args.iter()
3770-
.map(|aty| aty.subst(cx, substs)).collect();
3826+
.map(|aty| aty.subst(cx, substs)).collect::<Vec<_>>();
37713827

37723828
let substd_ctor_ty = variant_info.ctor_ty.subst(cx, substs);
37733829

@@ -3990,24 +4046,26 @@ pub fn has_attr(tcx: &ctxt, did: DefId, attr: &str) -> bool {
39904046
found
39914047
}
39924048

3993-
/// Determine whether an item is annotated with `#[packed]`
4049+
/// Determine whether an item is annotated with `#[repr(packed)]`
39944050
pub fn lookup_packed(tcx: &ctxt, did: DefId) -> bool {
3995-
has_attr(tcx, did, "packed")
4051+
lookup_repr_hints(tcx, did).contains(&attr::ReprPacked)
39964052
}
39974053

39984054
/// Determine whether an item is annotated with `#[simd]`
39994055
pub fn lookup_simd(tcx: &ctxt, did: DefId) -> bool {
40004056
has_attr(tcx, did, "simd")
40014057
}
40024058

4003-
// Obtain the representation annotation for a definition.
4004-
pub fn lookup_repr_hint(tcx: &ctxt, did: DefId) -> attr::ReprAttr {
4005-
let mut acc = attr::ReprAny;
4059+
/// Obtain the representation annotation for a struct definition.
4060+
pub fn lookup_repr_hints(tcx: &ctxt, did: DefId) -> Vec<attr::ReprAttr> {
4061+
let mut acc = Vec::new();
4062+
40064063
ty::each_attr(tcx, did, |meta| {
4007-
acc = attr::find_repr_attr(tcx.sess.diagnostic(), meta, acc);
4064+
acc.extend(attr::find_repr_attrs(tcx.sess.diagnostic(), meta).move_iter());
40084065
true
40094066
});
4010-
return acc;
4067+
4068+
acc
40114069
}
40124070

40134071
// Look up a field ID, whether or not it's local

src/librustc/middle/typeck/check/mod.rs

+8-3
Original file line numberDiff line numberDiff line change
@@ -4121,13 +4121,13 @@ pub fn check_enum_variants(ccx: &CrateCtxt,
41214121
let inh = blank_inherited_fields(ccx);
41224122
let fcx = blank_fn_ctxt(ccx, &inh, rty, e.id);
41234123
let declty = match hint {
4124-
attr::ReprAny | attr::ReprExtern => ty::mk_int(),
4124+
attr::ReprAny | attr::ReprPacked | attr::ReprExtern => ty::mk_int(),
41254125
attr::ReprInt(_, attr::SignedInt(ity)) => {
41264126
ty::mk_mach_int(ity)
41274127
}
41284128
attr::ReprInt(_, attr::UnsignedInt(ity)) => {
41294129
ty::mk_mach_uint(ity)
4130-
}
4130+
},
41314131
};
41324132
check_const_with_ty(&fcx, e.span, &*e, declty);
41334133
// check_expr (from check_const pass) doesn't guarantee
@@ -4166,6 +4166,9 @@ pub fn check_enum_variants(ccx: &CrateCtxt,
41664166
"discriminant type specified here");
41674167
}
41684168
}
4169+
attr::ReprPacked => {
4170+
ccx.tcx.sess.bug("range_to_inttype: found ReprPacked on an enum");
4171+
}
41694172
}
41704173
disr_vals.push(current_disr_val);
41714174

@@ -4179,7 +4182,9 @@ pub fn check_enum_variants(ccx: &CrateCtxt,
41794182
return variants;
41804183
}
41814184

4182-
let hint = ty::lookup_repr_hint(ccx.tcx, ast::DefId { krate: ast::LOCAL_CRATE, node: id });
4185+
let hint = *ty::lookup_repr_hints(ccx.tcx, ast::DefId { krate: ast::LOCAL_CRATE, node: id })
4186+
.as_slice().get(0).unwrap_or(&attr::ReprAny);
4187+
41834188
if hint != attr::ReprAny && vs.len() <= 1 {
41844189
if vs.len() == 1 {
41854190
span_err!(ccx.tcx.sess, sp, E0083,

src/librustrt/libunwind.rs

+1
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ pub static unwinder_private_data_size: uint = 5;
7272
#[cfg(target_arch = "mipsel")]
7373
pub static unwinder_private_data_size: uint = 2;
7474

75+
#[repr(C)]
7576
pub struct _Unwind_Exception {
7677
pub exception_class: _Unwind_Exception_Class,
7778
pub exception_cleanup: _Unwind_Exception_Cleanup_Fn,

src/libstd/rt/backtrace.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -701,7 +701,7 @@ mod imp {
701701
static IMAGE_FILE_MACHINE_IA64: libc::DWORD = 0x0200;
702702
static IMAGE_FILE_MACHINE_AMD64: libc::DWORD = 0x8664;
703703

704-
#[packed]
704+
#[repr(packed)]
705705
struct SYMBOL_INFO {
706706
SizeOfStruct: libc::c_ulong,
707707
TypeIndex: libc::c_ulong,

0 commit comments

Comments
 (0)