diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index e196304b82ac3..48173cc680428 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -2992,14 +2992,13 @@ pub fn lltype_is_sized(cx: &ctxt, ty: t) -> bool { pub fn unsized_part_of_type(cx: &ctxt, ty: t) -> t { match get(ty).sty { ty_str | ty_trait(..) | ty_vec(..) => ty, - ty_struct(_, ref substs) => { - // Exactly one of the type parameters must be unsized. - for tp in substs.types.get_slice(subst::TypeSpace).iter() { - if !type_is_sized(cx, *tp) { - return unsized_part_of_type(cx, *tp); - } - } - fail!("Unsized struct type with no unsized type params? {}", ty_to_string(cx, ty)); + ty_struct(def_id, ref substs) => { + let unsized_fields: Vec<_> = struct_fields(cx, def_id, substs).iter() + .map(|f| f.mt.ty).filter(|ty| !type_is_sized(cx, *ty)).collect(); + // Exactly one of the fields must be unsized. + assert!(unsized_fields.len() == 1) + + unsized_part_of_type(cx, unsized_fields[0]) } _ => { assert!(type_is_sized(cx, ty), diff --git a/src/test/compile-fail/unsized5.rs b/src/test/compile-fail/unsized5.rs index 7028f7e798b01..6eecc723431ca 100644 --- a/src/test/compile-fail/unsized5.rs +++ b/src/test/compile-fail/unsized5.rs @@ -9,7 +9,7 @@ // except according to those terms. #![feature(struct_variant)] -// Test `Sized?` types not allowed in fields. +// Test `Sized?` types not allowed in fields (except the last one). struct S1 { f1: X, //~ ERROR type `f1` is dynamically sized. dynamically sized types may only appear as the @@ -20,7 +20,14 @@ struct S2 { g: X, //~ ERROR type `g` is dynamically sized. dynamically sized types may only appear as the ty h: int, } - +struct S3 { + f: str, //~ ERROR type `f` is dynamically sized. dynamically sized types may only appear + g: [uint] +} +struct S4 { + f: str, //~ ERROR type `f` is dynamically sized. dynamically sized types may only appear + g: uint +} enum E { V1(X, int), //~ERROR type `X` is dynamically sized. dynamically sized types may only appear as t V2{f1: X, f: int}, //~ERROR type `f1` is dynamically sized. dynamically sized types may only app diff --git a/src/test/run-pass/unsized3.rs b/src/test/run-pass/unsized3.rs new file mode 100644 index 0000000000000..e5e6ce6e76bb6 --- /dev/null +++ b/src/test/run-pass/unsized3.rs @@ -0,0 +1,101 @@ +// 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. + +// Test structs with always-unsized fields. + +use std::mem; +use std::raw; + +struct Foo { + f: [T], +} + +struct Bar { + f1: uint, + f2: [uint], +} + +struct Baz { + f1: uint, + f2: str, +} + +trait Tr { + fn foo(&self) -> uint; +} + +struct St { + f: uint +} + +impl Tr for St { + fn foo(&self) -> uint { + self.f + } +} + +struct Qux<'a> { + f: Tr+'a +} + +pub fn main() { + let _: &Foo; + let _: &Bar; + let _: &Baz; + + let _: Box>; + let _: Box; + let _: Box; + + let _ = mem::size_of::>>(); + let _ = mem::size_of::>(); + let _ = mem::size_of::>(); + + unsafe { + struct Foo_ { + f: [T, ..3] + } + + let data = box Foo_{f: [1i32, 2, 3] }; + let x: &Foo = mem::transmute(raw::Slice { len: 3, data: &*data }); + assert!(x.f.len() == 3); + assert!(x.f[0] == 1); + assert!(x.f[1] == 2); + assert!(x.f[2] == 3); + + struct Baz_ { + f1: uint, + f2: [u8, ..5], + } + + let data = box Baz_{ f1: 42, f2: ['a' as u8, 'b' as u8, 'c' as u8, 'd' as u8, 'e' as u8] }; + let x: &Baz = mem::transmute( raw::Slice { len: 5, data: &*data } ); + assert!(x.f1 == 42); + let chs: Vec = x.f2.chars().collect(); + assert!(chs.len() == 5); + assert!(chs[0] == 'a'); + assert!(chs[1] == 'b'); + assert!(chs[2] == 'c'); + assert!(chs[3] == 'd'); + assert!(chs[4] == 'e'); + + struct Qux_ { + f: St + } + + let obj: Box = box St { f: 42 }; + let obj: &Tr = &*obj; + let obj: raw::TraitObject = mem::transmute(&*obj); + let data = box Qux_{ f: St { f: 234 } }; + let x: &Qux = mem::transmute(raw::TraitObject { vtable: obj.vtable, + data: mem::transmute(&*data) }); + assert!(x.f.foo() == 234); + } +}