Skip to content

Commit 6e8ff99

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 54bd9e6 commit 6e8ff99

27 files changed

+210
-118
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 \
@@ -770,9 +774,10 @@ impl LintPass for NonCamelCaseTypes {
770774
}
771775
}
772776

773-
let has_extern_repr = it.attrs.iter().fold(attr::ReprAny, |acc, attr| {
774-
attr::find_repr_attr(cx.tcx.sess.diagnostic(), attr, acc)
775-
}) == attr::ReprExtern;
777+
let has_extern_repr = it.attrs.iter().map(|attr| {
778+
attr::find_repr_attrs(cx.tcx.sess.diagnostic(), attr).iter()
779+
.any(|r| r == &attr::ReprExtern)
780+
}).any(|x| x);
776781
if has_extern_repr { return }
777782

778783
match it.node {
@@ -783,6 +788,7 @@ impl LintPass for NonCamelCaseTypes {
783788
check_case(cx, "trait", it.ident, it.span)
784789
}
785790
ast::ItemEnum(ref enum_definition, _) => {
791+
if has_extern_repr { return }
786792
check_case(cx, "type", it.ident, it.span);
787793
for variant in enum_definition.variants.iter() {
788794
check_case(cx, "variant", variant.node.name, variant.span);

src/librustc/middle/dead.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -195,9 +195,10 @@ impl<'a> MarkSymbolVisitor<'a> {
195195
ast_map::NodeItem(item) => {
196196
match item.node {
197197
ast::ItemStruct(..) => {
198-
let has_extern_repr = item.attrs.iter().fold(attr::ReprAny, |acc, attr| {
199-
attr::find_repr_attr(self.tcx.sess.diagnostic(), attr, acc)
200-
}) == attr::ReprExtern;
198+
let has_extern_repr = item.attrs.iter().fold(false, |acc, attr| {
199+
acc || attr::find_repr_attrs(self.tcx.sess.diagnostic(), attr)
200+
.iter().any(|&x| x == attr::ReprExtern)
201+
});
201202

202203
visit::walk_item(self, &*item, MarkSymbolVisitorContext {
203204
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
@@ -481,7 +481,7 @@ pub struct t { inner: *const t_opaque }
481481

482482
impl fmt::Show for t {
483483
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
484-
"*t_opaque".fmt(f)
484+
write!(f, "{}", get(*self))
485485
}
486486
}
487487

@@ -1962,7 +1962,8 @@ def_type_content_sets!(
19621962
// ReachesManaged /* see [1] below */ = 0b0000_0100__0000_0000__0000,
19631963
ReachesMutable = 0b0000_1000__0000_0000__0000,
19641964
ReachesNoSync = 0b0001_0000__0000_0000__0000,
1965-
ReachesAll = 0b0001_1111__0000_0000__0000,
1965+
ReachesFfiUnsafe = 0b0010_0000__0000_0000__0000,
1966+
ReachesAll = 0b0011_1111__0000_0000__0000,
19661967

19671968
// Things that cause values to *move* rather than *copy*
19681969
Moves = 0b0000_0000__0000_1011__0000,
@@ -2199,38 +2200,44 @@ pub fn type_contents(cx: &ctxt, ty: t) -> TypeContents {
21992200
cache.insert(ty_id, TC::None);
22002201

22012202
let result = match get(ty).sty {
2203+
// uint and int are ffi-unsafe
2204+
ty_uint(ast::TyU) | ty_int(ast::TyI) => {
2205+
TC::ReachesFfiUnsafe
2206+
}
2207+
22022208
// Scalar and unique types are sendable, and durable
22032209
ty_nil | ty_bot | ty_bool | ty_int(_) | ty_uint(_) | ty_float(_) |
22042210
ty_bare_fn(_) | ty::ty_char | ty_str => {
22052211
TC::None
22062212
}
22072213

22082214
ty_closure(ref c) => {
2209-
closure_contents(cx, &**c)
2215+
closure_contents(cx, &**c) | TC::ReachesFfiUnsafe
22102216
}
22112217

22122218
ty_box(typ) => {
2213-
tc_ty(cx, typ, cache).managed_pointer()
2219+
tc_ty(cx, typ, cache).managed_pointer() | TC::ReachesFfiUnsafe
22142220
}
22152221

22162222
ty_uniq(typ) => {
2217-
match get(typ).sty {
2223+
TC::ReachesFfiUnsafe | match get(typ).sty {
22182224
ty_str => TC::OwnsOwned,
22192225
_ => tc_ty(cx, typ, cache).owned_pointer(),
22202226
}
22212227
}
22222228

22232229
ty_trait(box ty::TyTrait { bounds, .. }) => {
2224-
object_contents(cx, bounds)
2230+
object_contents(cx, bounds) | TC::ReachesFfiUnsafe
22252231
}
22262232

22272233
ty_ptr(ref mt) => {
22282234
tc_ty(cx, mt.ty, cache).unsafe_pointer()
22292235
}
22302236

22312237
ty_rptr(r, ref mt) => {
2232-
match get(mt.ty).sty {
2238+
TC::ReachesFfiUnsafe | match get(mt.ty).sty {
22332239
ty_str => borrowed_contents(r, ast::MutImmutable),
2240+
ty_vec(..) => tc_ty(cx, mt.ty, cache).reference(borrowed_contents(r, mt.mutbl)),
22342241
_ => tc_ty(cx, mt.ty, cache).reference(borrowed_contents(r, mt.mutbl)),
22352242
}
22362243
}
@@ -2244,6 +2251,11 @@ pub fn type_contents(cx: &ctxt, ty: t) -> TypeContents {
22442251
let mut res =
22452252
TypeContents::union(flds.as_slice(),
22462253
|f| tc_mt(cx, f.mt, cache));
2254+
2255+
if !lookup_repr_hints(cx, did).contains(&attr::ReprExtern) {
2256+
res = res | TC::ReachesFfiUnsafe;
2257+
}
2258+
22472259
if ty::has_dtor(cx, did) {
22482260
res = res | TC::OwnsDtor;
22492261
}
@@ -2273,9 +2285,49 @@ pub fn type_contents(cx: &ctxt, ty: t) -> TypeContents {
22732285
tc_ty(cx, *arg_ty, cache)
22742286
})
22752287
});
2288+
22762289
if ty::has_dtor(cx, did) {
22772290
res = res | TC::OwnsDtor;
22782291
}
2292+
2293+
if variants.len() != 0 {
2294+
let repr_hints = lookup_repr_hints(cx, did);
2295+
if repr_hints.len() > 1 {
2296+
// this is an error later on, but this type isn't safe
2297+
res = res | TC::ReachesFfiUnsafe;
2298+
}
2299+
2300+
match repr_hints.as_slice().get(0) {
2301+
Some(h) => if !h.is_ffi_safe() {
2302+
res = res | TC::ReachesFfiUnsafe;
2303+
},
2304+
// ReprAny
2305+
None => {
2306+
res = res | TC::ReachesFfiUnsafe;
2307+
2308+
// We allow ReprAny enums if they are eligible for
2309+
// the nullable pointer optimization and the
2310+
// contained type is an `extern fn`
2311+
2312+
if variants.len() == 2 {
2313+
let mut data_idx = 0;
2314+
2315+
if variants.get(0).args.len() == 0 {
2316+
data_idx = 1;
2317+
}
2318+
2319+
if variants.get(data_idx).args.len() == 1 {
2320+
match get(*variants.get(data_idx).args.get(0)).sty {
2321+
ty_bare_fn(..) => { res = res - TC::ReachesFfiUnsafe; }
2322+
_ => { }
2323+
}
2324+
}
2325+
}
2326+
}
2327+
}
2328+
}
2329+
2330+
22792331
apply_lang_items(cx, did, res)
22802332
}
22812333

@@ -2427,6 +2479,10 @@ pub fn type_moves_by_default(cx: &ctxt, ty: t) -> bool {
24272479
type_contents(cx, ty).moves_by_default(cx)
24282480
}
24292481

2482+
pub fn is_ffi_safe(cx: &ctxt, ty: t) -> bool {
2483+
!type_contents(cx, ty).intersects(TC::ReachesFfiUnsafe)
2484+
}
2485+
24302486
// True if instantiating an instance of `r_ty` requires an instance of `r_ty`.
24312487
pub fn is_instantiable(cx: &ctxt, r_ty: t) -> bool {
24322488
fn type_requires(cx: &ctxt, seen: &mut Vec<DefId>,
@@ -3945,7 +4001,7 @@ pub fn substd_enum_variants(cx: &ctxt,
39454001
-> Vec<Rc<VariantInfo>> {
39464002
enum_variants(cx, id).iter().map(|variant_info| {
39474003
let substd_args = variant_info.args.iter()
3948-
.map(|aty| aty.subst(cx, substs)).collect();
4004+
.map(|aty| aty.subst(cx, substs)).collect::<Vec<_>>();
39494005

39504006
let substd_ctor_ty = variant_info.ctor_ty.subst(cx, substs);
39514007

@@ -4168,24 +4224,26 @@ pub fn has_attr(tcx: &ctxt, did: DefId, attr: &str) -> bool {
41684224
found
41694225
}
41704226

4171-
/// Determine whether an item is annotated with `#[packed]`
4227+
/// Determine whether an item is annotated with `#[repr(packed)]`
41724228
pub fn lookup_packed(tcx: &ctxt, did: DefId) -> bool {
4173-
has_attr(tcx, did, "packed")
4229+
lookup_repr_hints(tcx, did).contains(&attr::ReprPacked)
41744230
}
41754231

41764232
/// Determine whether an item is annotated with `#[simd]`
41774233
pub fn lookup_simd(tcx: &ctxt, did: DefId) -> bool {
41784234
has_attr(tcx, did, "simd")
41794235
}
41804236

4181-
// Obtain the representation annotation for a definition.
4182-
pub fn lookup_repr_hint(tcx: &ctxt, did: DefId) -> attr::ReprAttr {
4183-
let mut acc = attr::ReprAny;
4237+
/// Obtain the representation annotation for a struct definition.
4238+
pub fn lookup_repr_hints(tcx: &ctxt, did: DefId) -> Vec<attr::ReprAttr> {
4239+
let mut acc = Vec::new();
4240+
41844241
ty::each_attr(tcx, did, |meta| {
4185-
acc = attr::find_repr_attr(tcx.sess.diagnostic(), meta, acc);
4242+
acc.extend(attr::find_repr_attrs(tcx.sess.diagnostic(), meta).move_iter());
41864243
true
41874244
});
4188-
return acc;
4245+
4246+
acc
41894247
}
41904248

41914249
// 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
@@ -4180,13 +4180,13 @@ pub fn check_enum_variants(ccx: &CrateCtxt,
41804180
let inh = blank_inherited_fields(ccx);
41814181
let fcx = blank_fn_ctxt(ccx, &inh, rty, e.id);
41824182
let declty = match hint {
4183-
attr::ReprAny | attr::ReprExtern => ty::mk_int(),
4183+
attr::ReprAny | attr::ReprPacked | attr::ReprExtern => ty::mk_int(),
41844184
attr::ReprInt(_, attr::SignedInt(ity)) => {
41854185
ty::mk_mach_int(ity)
41864186
}
41874187
attr::ReprInt(_, attr::UnsignedInt(ity)) => {
41884188
ty::mk_mach_uint(ity)
4189-
}
4189+
},
41904190
};
41914191
check_const_with_ty(&fcx, e.span, &*e, declty);
41924192
// check_expr (from check_const pass) doesn't guarantee
@@ -4225,6 +4225,9 @@ pub fn check_enum_variants(ccx: &CrateCtxt,
42254225
"discriminant type specified here");
42264226
}
42274227
}
4228+
attr::ReprPacked => {
4229+
ccx.tcx.sess.bug("range_to_inttype: found ReprPacked on an enum");
4230+
}
42284231
}
42294232
disr_vals.push(current_disr_val);
42304233

@@ -4238,7 +4241,9 @@ pub fn check_enum_variants(ccx: &CrateCtxt,
42384241
return variants;
42394242
}
42404243

4241-
let hint = ty::lookup_repr_hint(ccx.tcx, ast::DefId { krate: ast::LOCAL_CRATE, node: id });
4244+
let hint = *ty::lookup_repr_hints(ccx.tcx, ast::DefId { krate: ast::LOCAL_CRATE, node: id })
4245+
.as_slice().get(0).unwrap_or(&attr::ReprAny);
4246+
42424247
if hint != attr::ReprAny && vs.len() <= 1 {
42434248
if vs.len() == 1 {
42444249
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)