Auto merge of #44295 - plietar:extern-types, r=arielb1

Implement RFC 1861: Extern types

A few notes :

- Type parameters are not supported. This was an unresolved question from the RFC. It is not clear how useful this feature is, and how variance should be treated. This can be added in a future PR.

- `size_of_val` / `align_of_val` can be called with extern types, and respectively return 0 and 1. This differs from the RFC, which specified that they should panic, but after discussion with @eddyb on IRC this seems like a better solution.
If/when a `DynSized` trait is added, this will be disallowed statically.

- Auto traits are not implemented by default, since the contents of extern types is unknown. This means extern types are `!Sync`, `!Send` and `!Freeze`. This seems like the correct behaviour to me.
Manual `unsafe impl Sync for Foo` is still possible.

- This PR allows extern type to be used as the tail of a struct, as described by the RFC :
```rust
extern {
    type OpaqueTail;
}

#[repr(C)]
struct FfiStruct {
    data: u8,
    more_data: u32,
    tail: OpaqueTail,
}
```

However this is undesirable, as the alignment of `tail` is unknown (the current PR assumes an alignment of 1). Unfortunately we can't prevent it in the general case as the tail could be a type parameter :
```rust
#[repr(C)]
struct FfiStruct<T: ?Sized> {
    data: u8,
    more_data: u32,
    tail: T,
}
```

Adding a `DynSized` trait would solve this as well, by requiring tail fields to be bound by it.

- Despite being unsized, pointers to extern types are thin and can be casted from/to integers. However it is not possible to write a `null<T>() -> *const T` function which works with extern types, as I've explained here : https://github.com/rust-lang/rust/issues/43467#issuecomment-321678621

- Trait objects cannot be built from extern types. I intend to support it eventually, although how this interacts with `DynSized`/`size_of_val` is still unclear.

- The definition of `c_void` is unmodified
This commit is contained in:
bors 2017-10-28 13:34:12 +00:00
commit dce604a8fe
82 changed files with 732 additions and 114 deletions

View File

@ -35,6 +35,7 @@ pub enum Def {
Variant(DefId),
Trait(DefId),
TyAlias(DefId),
TyForeign(DefId),
AssociatedTy(DefId),
PrimTy(hir::PrimTy),
TyParam(DefId),
@ -152,7 +153,7 @@ impl Def {
Def::AssociatedTy(id) | Def::TyParam(id) | Def::Struct(id) | Def::StructCtor(id, ..) |
Def::Union(id) | Def::Trait(id) | Def::Method(id) | Def::Const(id) |
Def::AssociatedConst(id) | Def::Macro(id, ..) |
Def::GlobalAsm(id) => {
Def::GlobalAsm(id) | Def::TyForeign(id) => {
id
}
@ -186,6 +187,7 @@ impl Def {
Def::StructCtor(.., CtorKind::Fictive) => bug!("impossible struct constructor"),
Def::Union(..) => "union",
Def::Trait(..) => "trait",
Def::TyForeign(..) => "foreign type",
Def::Method(..) => "method",
Def::Const(..) => "constant",
Def::AssociatedConst(..) => "associated constant",

View File

@ -704,6 +704,7 @@ pub fn walk_foreign_item<'v, V: Visitor<'v>>(visitor: &mut V, foreign_item: &'v
}
}
ForeignItemStatic(ref typ, _) => visitor.visit_ty(typ),
ForeignItemType => (),
}
walk_list!(visitor, visit_attribute, &foreign_item.attrs);

View File

@ -1722,6 +1722,9 @@ impl<'a> LoweringContext<'a> {
ForeignItemKind::Static(ref t, m) => {
hir::ForeignItemStatic(this.lower_ty(t), m)
}
ForeignItemKind::Ty => {
hir::ForeignItemType
}
},
vis: this.lower_visibility(&i.vis, None),
span: i.span,

View File

@ -1912,6 +1912,8 @@ pub enum ForeignItem_ {
/// A foreign static item (`static ext: u8`), with optional mutability
/// (the boolean is true when mutable)
ForeignItemStatic(P<Ty>, bool),
/// A foreign type
ForeignItemType,
}
impl ForeignItem_ {
@ -1919,6 +1921,7 @@ impl ForeignItem_ {
match *self {
ForeignItemFn(..) => "foreign function",
ForeignItemStatic(..) => "foreign static item",
ForeignItemType => "foreign type",
}
}
}

View File

@ -478,6 +478,13 @@ impl<'a> State<'a> {
self.end()?; // end the head-ibox
self.end() // end the outer cbox
}
hir::ForeignItemType => {
self.head(&visibility_qualified(&item.vis, "type"))?;
self.print_name(item.name)?;
self.s.word(";")?;
self.end()?; // end the head-ibox
self.end() // end the outer cbox
}
}
}

View File

@ -977,7 +977,8 @@ impl_stable_hash_for!(struct hir::ForeignItem {
impl_stable_hash_for!(enum hir::ForeignItem_ {
ForeignItemFn(fn_decl, arg_names, generics),
ForeignItemStatic(ty, is_mutbl)
ForeignItemStatic(ty, is_mutbl),
ForeignItemType
});
impl_stable_hash_for!(enum hir::Stmt_ {
@ -1086,6 +1087,7 @@ impl_stable_hash_for!(enum hir::def::Def {
PrimTy(prim_ty),
TyParam(def_id),
SelfTy(trait_def_id, impl_def_id),
TyForeign(def_id),
Fn(def_id),
Const(def_id),
Static(def_id, is_mutbl),

View File

@ -610,8 +610,7 @@ for ty::TypeVariants<'gcx>
def_id.hash_stable(hcx, hasher);
closure_substs.hash_stable(hcx, hasher);
}
TyGenerator(def_id, closure_substs, interior)
=> {
TyGenerator(def_id, closure_substs, interior) => {
def_id.hash_stable(hcx, hasher);
closure_substs.hash_stable(hcx, hasher);
interior.hash_stable(hcx, hasher);
@ -630,6 +629,9 @@ for ty::TypeVariants<'gcx>
TyParam(param_ty) => {
param_ty.hash_stable(hcx, hasher);
}
TyForeign(def_id) => {
def_id.hash_stable(hcx, hasher);
}
TyInfer(..) => {
bug!("ty::TypeVariants::hash_stable() - Unexpected variant {:?}.", *self)
}

View File

@ -312,6 +312,7 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for TypeFreshener<'a, 'gcx, 'tcx> {
ty::TyNever |
ty::TyTuple(..) |
ty::TyProjection(..) |
ty::TyForeign(..) |
ty::TyParam(..) |
ty::TyAnon(..) => {
t.super_fold_with(self)

View File

@ -365,6 +365,9 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
hir::ForeignItemStatic(..) => {
intravisit::walk_foreign_item(self, item);
}
hir::ForeignItemType => {
intravisit::walk_foreign_item(self, item);
}
}
}

View File

@ -304,6 +304,10 @@ fn ty_is_local_constructor(ty: Ty, infer_is_local: InferIsLocal)-> bool {
def.did.is_local()
}
ty::TyForeign(did) => {
did.is_local()
}
ty::TyDynamic(ref tt, ..) => {
tt.principal().map_or(false, |p| p.def_id().is_local())
}

View File

@ -255,6 +255,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
AdtKind::Enum => Some(17),
},
ty::TyGenerator(..) => Some(18),
ty::TyForeign(..) => Some(19),
ty::TyInfer(..) | ty::TyError => None
}
}

View File

@ -1705,6 +1705,12 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
// say nothing; a candidate may be added by
// `assemble_candidates_from_object_ty`.
}
ty::TyForeign(..) => {
// Since the contents of foreign types is unknown,
// we don't add any `..` impl. Default traits could
// still be provided by a manual implementation for
// this trait and type.
}
ty::TyParam(..) |
ty::TyProjection(..) => {
// In these cases, we don't know what the actual
@ -2022,7 +2028,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
Where(ty::Binder(Vec::new()))
}
ty::TyStr | ty::TySlice(_) | ty::TyDynamic(..) => Never,
ty::TyStr | ty::TySlice(_) | ty::TyDynamic(..) | ty::TyForeign(..) => Never,
ty::TyTuple(tys, _) => {
Where(ty::Binder(tys.last().into_iter().cloned().collect()))
@ -2066,7 +2072,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
Where(ty::Binder(Vec::new()))
}
ty::TyDynamic(..) | ty::TyStr | ty::TySlice(..) | ty::TyGenerator(..) |
ty::TyDynamic(..) | ty::TyStr | ty::TySlice(..) |
ty::TyGenerator(..) | ty::TyForeign(..) |
ty::TyRef(_, ty::TypeAndMut { ty: _, mutbl: hir::MutMutable }) => {
Never
}
@ -2148,6 +2155,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
ty::TyDynamic(..) |
ty::TyParam(..) |
ty::TyForeign(..) |
ty::TyProjection(..) |
ty::TyInfer(ty::TyVar(_)) |
ty::TyInfer(ty::FreshTy(_)) |

View File

@ -1610,7 +1610,7 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {
pub fn print_debug_stats(self) {
sty_debug_print!(
self,
TyAdt, TyArray, TySlice, TyRawPtr, TyRef, TyFnDef, TyFnPtr, TyGenerator,
TyAdt, TyArray, TySlice, TyRawPtr, TyRef, TyFnDef, TyFnPtr, TyGenerator, TyForeign,
TyDynamic, TyClosure, TyTuple, TyParam, TyInfer, TyProjection, TyAnon);
println!("Substs interner: #{}", self.interners.substs.borrow().len());
@ -1861,6 +1861,10 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
self.mk_ty(TyAdt(def, substs))
}
pub fn mk_foreign(self, def_id: DefId) -> Ty<'tcx> {
self.mk_ty(TyForeign(def_id))
}
pub fn mk_box(self, ty: Ty<'tcx>) -> Ty<'tcx> {
let def_id = self.require_lang_item(lang_items::OwnedBoxLangItem);
let adt_def = self.adt_def(def_id);

View File

@ -182,6 +182,7 @@ impl<'a, 'gcx, 'lcx, 'tcx> ty::TyS<'tcx> {
ty::TyTuple(ref tys, _) if tys.is_empty() => self.to_string(),
ty::TyAdt(def, _) => format!("{} `{}`", def.descr(), tcx.item_path_str(def.did)),
ty::TyForeign(def_id) => format!("extern type `{}`", tcx.item_path_str(def_id)),
ty::TyArray(_, n) => {
if let ConstVal::Integral(ConstInt::Usize(n)) = n.val {
format!("array of {} elements", n)

View File

@ -49,6 +49,7 @@ pub enum SimplifiedTypeGen<D>
AnonSimplifiedType(D),
FunctionSimplifiedType(usize),
ParameterSimplifiedType,
ForeignSimplifiedType(DefId),
}
/// Tries to simplify a type by dropping type parameters, deref'ing away any reference types, etc.
@ -113,6 +114,9 @@ pub fn simplify_type<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
ty::TyAnon(def_id, _) => {
Some(AnonSimplifiedType(def_id))
}
ty::TyForeign(def_id) => {
Some(ForeignSimplifiedType(def_id))
}
ty::TyInfer(_) | ty::TyError => None,
}
}
@ -140,6 +144,7 @@ impl<D: Copy + Debug + Ord + Eq + Hash> SimplifiedTypeGen<D> {
AnonSimplifiedType(d) => AnonSimplifiedType(map(d)),
FunctionSimplifiedType(n) => FunctionSimplifiedType(n),
ParameterSimplifiedType => ParameterSimplifiedType,
ForeignSimplifiedType(d) => ForeignSimplifiedType(d),
}
}
}
@ -172,6 +177,7 @@ impl<'gcx, D> HashStable<StableHashingContext<'gcx>> for SimplifiedTypeGen<D>
GeneratorSimplifiedType(d) => d.hash_stable(hcx, hasher),
AnonSimplifiedType(d) => d.hash_stable(hcx, hasher),
FunctionSimplifiedType(n) => n.hash_stable(hcx, hasher),
ForeignSimplifiedType(d) => d.hash_stable(hcx, hasher),
}
}
}

View File

@ -63,7 +63,8 @@ impl FlagComputation {
&ty::TyFloat(_) |
&ty::TyUint(_) |
&ty::TyNever |
&ty::TyStr => {
&ty::TyStr |
&ty::TyForeign(..) => {
}
// You might think that we could just return TyError for

View File

@ -281,6 +281,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
}
}
ty::TyForeign(did) => self.push_item_path(buffer, did),
ty::TyBool |
ty::TyChar |
ty::TyInt(_) |
@ -344,8 +346,9 @@ pub fn characteristic_def_id_of_type(ty: Ty) -> Option<DefId> {
.next(),
ty::TyFnDef(def_id, _) |
ty::TyClosure(def_id, _) => Some(def_id),
ty::TyGenerator(def_id, _, _) => Some(def_id),
ty::TyClosure(def_id, _) |
ty::TyGenerator(def_id, _, _) |
ty::TyForeign(def_id) => Some(def_id),
ty::TyBool |
ty::TyChar |

View File

@ -1141,14 +1141,15 @@ impl<'a, 'tcx> Layout {
Ok(Scalar { value: Pointer, non_zero: non_zero })
} else {
let unsized_part = tcx.struct_tail(pointee);
let meta = match unsized_part.sty {
ty::TySlice(_) | ty::TyStr => {
Int(dl.ptr_sized_integer())
}
ty::TyDynamic(..) => Pointer,
_ => return Err(LayoutError::Unknown(unsized_part))
};
Ok(FatPointer { metadata: meta, non_zero: non_zero })
match unsized_part.sty {
ty::TySlice(_) | ty::TyStr => Ok(FatPointer {
metadata: Int(dl.ptr_sized_integer()),
non_zero: non_zero
}),
ty::TyDynamic(..) => Ok(FatPointer { metadata: Pointer, non_zero: non_zero }),
ty::TyForeign(..) => Ok(Scalar { value: Pointer, non_zero: non_zero }),
_ => Err(LayoutError::Unknown(unsized_part)),
}
}
};
@ -1239,7 +1240,7 @@ impl<'a, 'tcx> Layout {
non_zero: false
}
}
ty::TyDynamic(..) => {
ty::TyDynamic(..) | ty::TyForeign(..) => {
let mut unit = Struct::new(dl, &vec![], &ReprOptions::default(),
StructKind::AlwaysSizedUnivariant, ty)?;
unit.sized = false;
@ -2252,7 +2253,8 @@ impl<'a, 'tcx> TyLayout<'tcx> {
ty::TyFnPtr(_) |
ty::TyNever |
ty::TyFnDef(..) |
ty::TyDynamic(..) => {
ty::TyDynamic(..) |
ty::TyForeign(..) => {
bug!("TyLayout::field_type({:?}): not applicable", self)
}

View File

@ -1784,7 +1784,7 @@ impl<'a, 'gcx, 'tcx> AdtDef {
vec![]
}
TyStr | TyDynamic(..) | TySlice(_) | TyError => {
TyStr | TyDynamic(..) | TySlice(_) | TyForeign(..) | TyError => {
// these are never sized - return the target type
vec![ty]
}

View File

@ -142,6 +142,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
ty::TyNever | // ...
ty::TyAdt(..) | // OutlivesNominalType
ty::TyAnon(..) | // OutlivesNominalType (ish)
ty::TyForeign(..) | // OutlivesNominalType
ty::TyStr | // OutlivesScalar (ish)
ty::TyArray(..) | // ...
ty::TySlice(..) | // ...

View File

@ -381,6 +381,12 @@ pub fn super_relate_tys<'a, 'gcx, 'tcx, R>(relation: &mut R,
Ok(tcx.mk_adt(a_def, substs))
}
(&ty::TyForeign(a_id), &ty::TyForeign(b_id))
if a_id == b_id =>
{
Ok(tcx.mk_foreign(a_id))
}
(&ty::TyDynamic(ref a_obj, ref a_region), &ty::TyDynamic(ref b_obj, ref b_region)) => {
let region_bound = relation.with_cause(Cause::ExistentialRegionBound,
|relation| {

View File

@ -676,7 +676,7 @@ impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> {
ty::TyAnon(did, substs) => ty::TyAnon(did, substs.fold_with(folder)),
ty::TyBool | ty::TyChar | ty::TyStr | ty::TyInt(_) |
ty::TyUint(_) | ty::TyFloat(_) | ty::TyError | ty::TyInfer(_) |
ty::TyParam(..) | ty::TyNever => return self
ty::TyParam(..) | ty::TyNever | ty::TyForeign(..) => return self
};
if self.sty == sty {
@ -710,7 +710,7 @@ impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> {
ty::TyAnon(_, ref substs) => substs.visit_with(visitor),
ty::TyBool | ty::TyChar | ty::TyStr | ty::TyInt(_) |
ty::TyUint(_) | ty::TyFloat(_) | ty::TyError | ty::TyInfer(_) |
ty::TyParam(..) | ty::TyNever => false,
ty::TyParam(..) | ty::TyNever | ty::TyForeign(..) => false,
}
}

View File

@ -104,6 +104,8 @@ pub enum TypeVariants<'tcx> {
/// definition and not a concrete use of it.
TyAdt(&'tcx AdtDef, &'tcx Substs<'tcx>),
TyForeign(DefId),
/// The pointee of a string slice. Written as `str`.
TyStr,
@ -1117,13 +1119,6 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
}
}
pub fn is_structural(&self) -> bool {
match self.sty {
TyAdt(..) | TyTuple(..) | TyArray(..) | TyClosure(..) => true,
_ => self.is_slice() | self.is_trait(),
}
}
#[inline]
pub fn is_simd(&self) -> bool {
match self.sty {
@ -1347,6 +1342,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
match self.sty {
TyDynamic(ref tt, ..) => tt.principal().map(|p| p.def_id()),
TyAdt(def, _) => Some(def.did),
TyForeign(did) => Some(did),
TyClosure(id, _) => Some(id),
_ => None,
}
@ -1396,6 +1392,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
TyRawPtr(_) |
TyNever |
TyTuple(..) |
TyForeign(..) |
TyParam(_) |
TyInfer(_) |
TyError => {

View File

@ -553,7 +553,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
let result = match ty.sty {
ty::TyBool | ty::TyChar | ty::TyInt(_) | ty::TyUint(_) |
ty::TyFloat(_) | ty::TyStr | ty::TyNever |
ty::TyFloat(_) | ty::TyStr | ty::TyNever | ty::TyForeign(..) |
ty::TyRawPtr(..) | ty::TyRef(..) | ty::TyFnDef(..) | ty::TyFnPtr(_) => {
// these types never have a destructor
Ok(ty::DtorckConstraint::empty())
@ -714,6 +714,7 @@ impl<'a, 'gcx, 'tcx, W> TypeVisitor<'tcx> for TypeIdHasher<'a, 'gcx, 'tcx, W>
TyAnon(def_id, _) |
TyFnDef(def_id, _) => self.def_id(def_id),
TyAdt(d, _) => self.def_id(d.did),
TyForeign(def_id) => self.def_id(def_id),
TyFnPtr(f) => {
self.hash(f.unsafety());
self.hash(f.abi());
@ -1109,6 +1110,9 @@ fn needs_drop_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
ty::TyFnDef(..) | ty::TyFnPtr(_) | ty::TyChar |
ty::TyRawPtr(_) | ty::TyRef(..) | ty::TyStr => false,
// Foreign types can never have destructors
ty::TyForeign(..) => false,
// Issue #22536: We first query type_moves_by_default. It sees a
// normalized version of the type, and therefore will definitely
// know whether the type implements Copy (and thus needs no

View File

@ -82,7 +82,8 @@ pub fn walk_shallow<'tcx>(ty: Ty<'tcx>) -> AccIntoIter<TypeWalkerArray<'tcx>> {
fn push_subtypes<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent_ty: Ty<'tcx>) {
match parent_ty.sty {
ty::TyBool | ty::TyChar | ty::TyInt(_) | ty::TyUint(_) | ty::TyFloat(_) |
ty::TyStr | ty::TyInfer(_) | ty::TyParam(_) | ty::TyNever | ty::TyError => {
ty::TyStr | ty::TyInfer(_) | ty::TyParam(_) | ty::TyNever | ty::TyError |
ty::TyForeign(..) => {
}
ty::TyArray(ty, len) => {
push_const(stack, len);

View File

@ -284,7 +284,8 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> {
ty::TyError |
ty::TyStr |
ty::TyNever |
ty::TyParam(_) => {
ty::TyParam(_) |
ty::TyForeign(..) => {
// WfScalar, WfParameter, etc
}

View File

@ -17,7 +17,7 @@ use ty::{BrAnon, BrEnv, BrFresh, BrNamed};
use ty::{TyBool, TyChar, TyAdt};
use ty::{TyError, TyStr, TyArray, TySlice, TyFloat, TyFnDef, TyFnPtr};
use ty::{TyParam, TyRawPtr, TyRef, TyNever, TyTuple};
use ty::{TyClosure, TyGenerator, TyProjection, TyAnon};
use ty::{TyClosure, TyGenerator, TyForeign, TyProjection, TyAnon};
use ty::{TyDynamic, TyInt, TyUint, TyInfer};
use ty::{self, Ty, TyCtxt, TypeFoldable};
use util::nodemap::FxHashSet;
@ -1012,6 +1012,7 @@ define_print! {
Ok(())
}
}
TyForeign(def_id) => parameterized(f, subst::Substs::empty(), def_id, &[]),
TyProjection(ref data) => data.print(f, cx),
TyAnon(def_id, substs) => {
ty::tls::with(|tcx| {

View File

@ -621,6 +621,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
FfiSafe
}
ty::TyForeign(..) => FfiSafe,
ty::TyParam(..) |
ty::TyInfer(..) |
ty::TyError |
@ -723,6 +725,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ImproperCTypes {
hir::ForeignItemStatic(ref ty, _) => {
vis.check_foreign_static(ni.id, ty.span);
}
hir::ForeignItemType => ()
}
}
}

View File

@ -449,6 +449,7 @@ impl<'tcx> EntryKind<'tcx> {
EntryKind::Enum(..) => Def::Enum(did),
EntryKind::MacroDef(_) => Def::Macro(did, MacroKind::Bang),
EntryKind::GlobalAsm => Def::GlobalAsm(did),
EntryKind::ForeignType => Def::TyForeign(did),
EntryKind::ForeignMod |
EntryKind::Impl(_) |

View File

@ -1419,6 +1419,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> {
}
hir::ForeignItemStatic(_, true) => EntryKind::ForeignMutStatic,
hir::ForeignItemStatic(_, false) => EntryKind::ForeignImmStatic,
hir::ForeignItemType => EntryKind::ForeignType,
};
Entry {

View File

@ -292,6 +292,7 @@ pub enum EntryKind<'tcx> {
ForeignImmStatic,
ForeignMutStatic,
ForeignMod,
ForeignType,
GlobalAsm,
Type,
Enum(ReprOptions),
@ -325,6 +326,7 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for EntryKind<'gcx> {
EntryKind::ForeignMutStatic |
EntryKind::ForeignMod |
EntryKind::GlobalAsm |
EntryKind::ForeignType |
EntryKind::Field |
EntryKind::Type => {
// Nothing else to hash here.

View File

@ -288,7 +288,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
err.emit();
});
}
ForeignItemKind::Static(..) => {}
ForeignItemKind::Static(..) | ForeignItemKind::Ty => {}
}
visit::walk_foreign_item(self, fi)

View File

@ -85,6 +85,7 @@ impl<'a, 'tcx> EmbargoVisitor<'a, 'tcx> {
fn item_ty_level(&self, item_def_id: DefId) -> Option<AccessLevel> {
let ty_def_id = match self.tcx.type_of(item_def_id).sty {
ty::TyAdt(adt, _) => adt.did,
ty::TyForeign(did) => did,
ty::TyDynamic(ref obj, ..) if obj.principal().is_some() =>
obj.principal().unwrap().def_id(),
ty::TyProjection(ref proj) => proj.trait_ref(self.tcx).def_id,
@ -444,6 +445,7 @@ impl<'b, 'a, 'tcx> TypeVisitor<'tcx> for ReachEverythingInTheInterfaceVisitor<'b
fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool {
let ty_def_id = match ty.sty {
ty::TyAdt(adt, _) => Some(adt.did),
ty::TyForeign(did) => Some(did),
ty::TyDynamic(ref obj, ..) => obj.principal().map(|p| p.def_id()),
ty::TyProjection(ref proj) => Some(proj.item_def_id),
ty::TyFnDef(def_id, ..) |
@ -800,7 +802,9 @@ impl<'a, 'tcx> Visitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> {
impl<'a, 'tcx> TypeVisitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> {
fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool {
match ty.sty {
ty::TyAdt(&ty::AdtDef { did: def_id, .. }, ..) | ty::TyFnDef(def_id, ..) => {
ty::TyAdt(&ty::AdtDef { did: def_id, .. }, ..) |
ty::TyFnDef(def_id, ..) |
ty::TyForeign(def_id) => {
if !self.item_is_accessible(def_id) {
let msg = format!("type `{}` is private", ty);
self.tcx.sess.span_err(self.span, &msg);
@ -1329,6 +1333,7 @@ impl<'a, 'tcx: 'a> TypeVisitor<'tcx> for SearchInterfaceForPrivateItemsVisitor<'
fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool {
let ty_def_id = match ty.sty {
ty::TyAdt(adt, _) => Some(adt.did),
ty::TyForeign(did) => Some(did),
ty::TyDynamic(ref obj, ..) => obj.principal().map(|p| p.def_id()),
ty::TyProjection(ref proj) => {
if self.required_visibility == ty::Visibility::Invisible {
@ -1349,8 +1354,13 @@ impl<'a, 'tcx: 'a> TypeVisitor<'tcx> for SearchInterfaceForPrivateItemsVisitor<'
if let Some(def_id) = ty_def_id {
// Non-local means public (private items can't leave their crate, modulo bugs)
if let Some(node_id) = self.tcx.hir.as_local_node_id(def_id) {
let item = self.tcx.hir.expect_item(node_id);
let vis = ty::Visibility::from_hir(&item.vis, node_id, self.tcx);
let vis = match self.tcx.hir.find(node_id) {
Some(hir::map::NodeItem(item)) => &item.vis,
Some(hir::map::NodeForeignItem(item)) => &item.vis,
_ => bug!("expected item of foreign item"),
};
let vis = ty::Visibility::from_hir(vis, node_id, self.tcx);
if !vis.is_at_least(self.min_visibility, self.tcx) {
self.min_visibility = vis;

View File

@ -419,17 +419,20 @@ impl<'a> Resolver<'a> {
/// Constructs the reduced graph for one foreign item.
fn build_reduced_graph_for_foreign_item(&mut self, item: &ForeignItem, expansion: Mark) {
let def = match item.node {
let (def, ns) = match item.node {
ForeignItemKind::Fn(..) => {
Def::Fn(self.definitions.local_def_id(item.id))
(Def::Fn(self.definitions.local_def_id(item.id)), ValueNS)
}
ForeignItemKind::Static(_, m) => {
Def::Static(self.definitions.local_def_id(item.id), m)
(Def::Static(self.definitions.local_def_id(item.id), m), ValueNS)
}
ForeignItemKind::Ty => {
(Def::TyForeign(self.definitions.local_def_id(item.id)), TypeNS)
}
};
let parent = self.current_module;
let vis = self.resolve_visibility(&item.vis);
self.define(parent, item.ident, ValueNS, (def, vis, item.span, expansion));
self.define(parent, item.ident, ns, (def, vis, item.span, expansion));
}
fn build_reduced_graph_for_block(&mut self, block: &Block, expansion: Mark) {
@ -462,7 +465,7 @@ impl<'a> Resolver<'a> {
span);
self.define(parent, ident, TypeNS, (module, vis, DUMMY_SP, expansion));
}
Def::Variant(..) | Def::TyAlias(..) => {
Def::Variant(..) | Def::TyAlias(..) | Def::TyForeign(..) => {
self.define(parent, ident, TypeNS, (def, vis, DUMMY_SP, expansion));
}
Def::Fn(..) | Def::Static(..) | Def::Const(..) | Def::VariantCtor(..) => {

View File

@ -468,7 +468,8 @@ impl<'a> PathSource<'a> {
PathSource::Type => match def {
Def::Struct(..) | Def::Union(..) | Def::Enum(..) |
Def::Trait(..) | Def::TyAlias(..) | Def::AssociatedTy(..) |
Def::PrimTy(..) | Def::TyParam(..) | Def::SelfTy(..) => true,
Def::PrimTy(..) | Def::TyParam(..) | Def::SelfTy(..) |
Def::TyForeign(..) => true,
_ => false,
},
PathSource::Trait => match def {
@ -707,6 +708,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Resolver<'a> {
HasTypeParameters(generics, ItemRibKind)
}
ForeignItemKind::Static(..) => NoTypeParameters,
ForeignItemKind::Ty => NoTypeParameters,
};
self.with_type_parameter_rib(type_parameters, |this| {
visit::walk_foreign_item(this, foreign_item);

View File

@ -263,6 +263,7 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
HirDef::Union(..) |
HirDef::Enum(..) |
HirDef::TyAlias(..) |
HirDef::TyForeign(..) |
HirDef::Trait(_) => {
let span = self.span_from_span(sub_span.expect("No span found for type ref"));
self.dumper.dump_ref(Ref {
@ -1539,6 +1540,12 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> Visitor<'l> for DumpVisitor<'l, 'tc
self.visit_ty(ty);
}
ast::ForeignItemKind::Ty => {
if let Some(var_data) = self.save_ctxt.get_extern_item_data(item) {
down_cast_data!(var_data, DefData, item.span);
self.dumper.dump_def(item.vis == ast::Visibility::Public, var_data);
}
}
}
}
}

View File

@ -173,6 +173,8 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
attributes: lower_attributes(item.attrs.clone(), self),
}))
}
// FIXME(plietar): needs a new DefKind in rls-data
ast::ForeignItemKind::Ty => None,
}
}
@ -642,6 +644,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
HirDef::Union(def_id) |
HirDef::Enum(def_id) |
HirDef::TyAlias(def_id) |
HirDef::TyForeign(def_id) |
HirDef::AssociatedTy(def_id) |
HirDef::Trait(def_id) |
HirDef::TyParam(def_id) => {

View File

@ -808,6 +808,23 @@ impl Sig for ast::ForeignItem {
Ok(extend_sig(ty_sig, text, defs, vec![]))
}
ast::ForeignItemKind::Ty => {
let mut text = "type ".to_owned();
let name = self.ident.to_string();
let defs = vec![SigElement {
id: id_from_node_id(self.id, scx),
start: offset + text.len(),
end: offset + text.len() + name.len(),
}];
text.push_str(&name);
text.push(';');
Ok(Signature {
text: text,
defs: defs,
refs: vec![],
})
}
}
}
}

View File

@ -32,6 +32,7 @@ use rustc::session::Session;
use rustc::ty::layout::{LayoutCx, LayoutError, LayoutTyper, TyLayout};
use rustc::ty::{self, Ty, TyCtxt};
use rustc::util::nodemap::FxHashMap;
use rustc_trans_utils;
use std::ffi::{CStr, CString};
use std::cell::{Cell, RefCell};
@ -301,6 +302,10 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> {
common::type_is_freeze(self.tcx, ty)
}
pub fn type_has_metadata(&self, ty: Ty<'tcx>) -> bool {
rustc_trans_utils::common::type_has_metadata(self.tcx, ty)
}
pub fn tcx(&self) -> TyCtxt<'b, 'tcx, 'tcx> {
self.tcx
}

View File

@ -543,6 +543,11 @@ pub fn type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
trait_pointer_metadata(cx, t, None, unique_type_id),
false)
}
ty::TyForeign(..) => {
MetadataCreationResult::new(
foreign_type_metadata(cx, t, unique_type_id),
false)
}
ty::TyRawPtr(ty::TypeAndMut{ty, ..}) |
ty::TyRef(_, ty::TypeAndMut{ty, ..}) => {
match ptr_metadata(ty) {
@ -752,6 +757,17 @@ fn basic_type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
return ty_metadata;
}
fn foreign_type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
t: Ty<'tcx>,
unique_type_id: UniqueTypeId) -> DIType {
debug!("foreign_type_metadata: {:?}", t);
let llvm_type = type_of::type_of(cx, t);
let name = compute_debuginfo_type_name(cx, t, false);
create_struct_stub(cx, llvm_type, &name, unique_type_id, NO_SCOPE_METADATA)
}
fn pointer_type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
pointer_type: Ty<'tcx>,
pointee_type_metadata: DIType)

View File

@ -48,6 +48,7 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
ty::TyInt(int_ty) => output.push_str(int_ty.ty_to_string()),
ty::TyUint(uint_ty) => output.push_str(uint_ty.ty_to_string()),
ty::TyFloat(float_ty) => output.push_str(float_ty.ty_to_string()),
ty::TyForeign(def_id) => push_item_name(cx, def_id, qualified, output),
ty::TyAdt(def, substs) => {
push_item_name(cx, def.did, qualified, output);
push_type_params(cx, substs, output);

View File

@ -139,13 +139,15 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bcx: &Builder<'a, 'tcx>,
}
"size_of_val" => {
let tp_ty = substs.type_at(0);
if !bcx.ccx.shared().type_is_sized(tp_ty) {
if bcx.ccx.shared().type_is_sized(tp_ty) {
let lltp_ty = type_of::type_of(ccx, tp_ty);
C_usize(ccx, machine::llsize_of_alloc(ccx, lltp_ty))
} else if bcx.ccx.shared().type_has_metadata(tp_ty) {
let (llsize, _) =
glue::size_and_align_of_dst(bcx, tp_ty, llargs[1]);
llsize
} else {
let lltp_ty = type_of::type_of(ccx, tp_ty);
C_usize(ccx, machine::llsize_of_alloc(ccx, lltp_ty))
C_usize(ccx, 0u64)
}
}
"min_align_of" => {
@ -154,12 +156,14 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bcx: &Builder<'a, 'tcx>,
}
"min_align_of_val" => {
let tp_ty = substs.type_at(0);
if !bcx.ccx.shared().type_is_sized(tp_ty) {
if bcx.ccx.shared().type_is_sized(tp_ty) {
C_usize(ccx, ccx.align_of(tp_ty) as u64)
} else if bcx.ccx.shared().type_has_metadata(tp_ty) {
let (_, llalign) =
glue::size_and_align_of_dst(bcx, tp_ty, llargs[1]);
llalign
} else {
C_usize(ccx, ccx.align_of(tp_ty) as u64)
C_usize(ccx, 1u64)
}
}
"pref_align_of" => {

View File

@ -428,11 +428,11 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
.projection_ty(tcx, &projection.elem);
let base = tr_base.to_const(span);
let projected_ty = self.monomorphize(&projected_ty).to_ty(tcx);
let is_sized = self.ccx.shared().type_is_sized(projected_ty);
let has_metadata = self.ccx.shared().type_has_metadata(projected_ty);
let (projected, llextra) = match projection.elem {
mir::ProjectionElem::Deref => {
let (base, extra) = if is_sized {
let (base, extra) = if !has_metadata {
(base.llval, ptr::null_mut())
} else {
base.get_fat_ptr()
@ -463,7 +463,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
mir::ProjectionElem::Field(ref field, _) => {
let llprojected = adt::const_get_field(self.ccx, tr_base.ty, base.llval,
field.index());
let llextra = if is_sized {
let llextra = if !has_metadata {
ptr::null_mut()
} else {
tr_base.llextra

View File

@ -147,15 +147,16 @@ impl<'a, 'tcx> LvalueRef<'tcx> {
// * Packed struct - There is no alignment padding
// * Field is sized - pointer is properly aligned already
if st.offsets[ix] == layout::Size::from_bytes(0) || st.packed ||
bcx.ccx.shared().type_is_sized(fty) {
return (bcx.struct_gep(
ptr_val, adt::struct_llfields_index(st, ix)), alignment);
}
bcx.ccx.shared().type_is_sized(fty)
{
return (bcx.struct_gep(
ptr_val, adt::struct_llfields_index(st, ix)), alignment);
}
// If the type of the last field is [T] or str, then we don't need to do
// If the type of the last field is [T], str or a foreign type, then we don't need to do
// any adjusments
match fty.sty {
ty::TySlice(..) | ty::TyStr => {
ty::TySlice(..) | ty::TyStr | ty::TyForeign(..) => {
return (bcx.struct_gep(
ptr_val, adt::struct_llfields_index(st, ix)), alignment);
}
@ -328,7 +329,9 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
let ((llprojected, align), llextra) = match projection.elem {
mir::ProjectionElem::Deref => bug!(),
mir::ProjectionElem::Field(ref field, _) => {
let llextra = if self.ccx.shared().type_is_sized(projected_ty.to_ty(tcx)) {
let has_metadata = self.ccx.shared()
.type_has_metadata(projected_ty.to_ty(tcx));
let llextra = if !has_metadata {
ptr::null_mut()
} else {
tr_base.llextra
@ -415,3 +418,4 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
self.monomorphize(&lvalue_ty.to_ty(tcx))
}
}

View File

@ -364,7 +364,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
// Note: lvalues are indirect, so storing the `llval` into the
// destination effectively creates a reference.
let operand = if bcx.ccx.shared().type_is_sized(ty) {
let operand = if !bcx.ccx.shared().type_has_metadata(ty) {
OperandRef {
val: OperandValue::Immediate(tr_lvalue.llval),
ty: ref_ty,

View File

@ -230,4 +230,3 @@ fn predefine_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
ccx.instances().borrow_mut().insert(instance, lldecl);
}

View File

@ -22,7 +22,7 @@ use syntax::ast;
pub fn fat_ptr_base_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -> Type {
match ty.sty {
ty::TyRef(_, ty::TypeAndMut { ty: t, .. }) |
ty::TyRawPtr(ty::TypeAndMut { ty: t, .. }) if !ccx.shared().type_is_sized(t) => {
ty::TyRawPtr(ty::TypeAndMut { ty: t, .. }) if ccx.shared().type_has_metadata(t) => {
in_memory_type_of(ccx, t).ptr_to()
}
ty::TyAdt(def, _) if def.is_box() => {
@ -62,7 +62,7 @@ pub fn immediate_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) ->
/// is too large for it to be placed in SSA value (by our rules).
/// For the raw type without far pointer indirection, see `in_memory_type_of`.
pub fn type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -> Type {
let ty = if !cx.shared().type_is_sized(ty) {
let ty = if cx.shared().type_has_metadata(ty) {
cx.tcx().mk_imm_ptr(ty)
} else {
ty
@ -106,7 +106,7 @@ pub fn in_memory_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) ->
}
let ptr_ty = |ty: Ty<'tcx>| {
if !cx.shared().type_is_sized(ty) {
if cx.shared().type_has_metadata(ty) {
if let ty::TyStr = ty.sty {
// This means we get a nicer name in the output (str is always
// unsized).
@ -158,7 +158,7 @@ pub fn in_memory_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) ->
// fat pointers is of the right type (e.g. for array accesses), even
// when taking the address of an unsized field in a struct.
ty::TySlice(ty) => in_memory_type_of(cx, ty),
ty::TyStr | ty::TyDynamic(..) => Type::i8(cx),
ty::TyStr | ty::TyDynamic(..) | ty::TyForeign(..) => Type::i8(cx),
ty::TyFnDef(..) => Type::nil(cx),
ty::TyFnPtr(sig) => {

View File

@ -203,7 +203,7 @@ use rustc::ty::adjustment::CustomCoerceUnsized;
use rustc::mir::{self, Location};
use rustc::mir::visit::Visitor as MirVisitor;
use common::{def_ty, instance_ty, type_is_sized};
use common::{def_ty, instance_ty, type_has_metadata};
use monomorphize::{self, Instance};
use rustc::util::nodemap::{FxHashSet, FxHashMap, DefIdMap};
@ -782,7 +782,7 @@ fn find_vtable_types_for_unsizing<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
target_ty: Ty<'tcx>)
-> (Ty<'tcx>, Ty<'tcx>) {
let ptr_vtable = |inner_source: Ty<'tcx>, inner_target: Ty<'tcx>| {
if !type_is_sized(tcx, inner_source) {
if type_has_metadata(tcx, inner_source) {
(inner_source, inner_target)
} else {
tcx.struct_lockstep_tails(inner_source, inner_target)

View File

@ -25,6 +25,19 @@ pub fn type_is_sized<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty: Ty<'tcx>) -> boo
ty.is_sized(tcx, ty::ParamEnv::empty(traits::Reveal::All), DUMMY_SP)
}
pub fn type_has_metadata<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty: Ty<'tcx>) -> bool {
if type_is_sized(tcx, ty) {
return false;
}
let tail = tcx.struct_tail(ty);
match tail.sty {
ty::TyForeign(..) => false,
ty::TyStr | ty::TySlice(..) | ty::TyDynamic(..) => true,
_ => bug!("unexpected unsized tail: {:?}", tail.sty),
}
}
pub fn requests_inline<'a, 'tcx>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
instance: &ty::Instance<'tcx>

View File

@ -48,7 +48,7 @@ use rustc::util::nodemap::NodeSet;
use syntax::attr;
mod common;
pub mod common;
pub mod link;
pub mod collector;
pub mod trans_item;

View File

@ -335,6 +335,7 @@ impl<'a, 'tcx> DefPathBasedNames<'a, 'tcx> {
output);
}
},
ty::TyForeign(did) => self.push_def_path(did, output),
ty::TyFnDef(..) |
ty::TyFnPtr(_) => {
let sig = t.fn_sig(self.tcx);

View File

@ -928,7 +928,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
let span = path.span;
match path.def {
Def::Enum(did) | Def::TyAlias(did) | Def::Struct(did) | Def::Union(did) => {
Def::Enum(did) | Def::TyAlias(did) | Def::Struct(did) |
Def::Union(did) | Def::TyForeign(did) => {
assert_eq!(opt_self_ty, None);
self.prohibit_type_params(path.segments.split_last().unwrap().1);
self.ast_path_to_ty(span, did, path.segments.last().unwrap())

View File

@ -13,7 +13,7 @@
//! A cast `e as U` is valid if one of the following holds:
//! * `e` has type `T` and `T` coerces to `U`; *coercion-cast*
//! * `e` has type `*T`, `U` is `*U_0`, and either `U_0: Sized` or
//! unsize_kind(`T`) = unsize_kind(`U_0`); *ptr-ptr-cast*
//! pointer_kind(`T`) = pointer_kind(`U_0`); *ptr-ptr-cast*
//! * `e` has type `*T` and `U` is a numeric type, while `T: Sized`; *ptr-addr-cast*
//! * `e` is an integer and `U` is `*U_0`, while `U_0: Sized`; *addr-ptr-cast*
//! * `e` has type `T` and `T` and `U` are any numeric types; *numeric-cast*
@ -26,7 +26,7 @@
//! * `e` is a function pointer type and `U` is an integer; *fptr-addr-cast*
//!
//! where `&.T` and `*T` are references of either mutability,
//! and where unsize_kind(`T`) is the kind of the unsize info
//! and where pointer_kind(`T`) is the kind of the unsize info
//! in `T` - the vtable for a trait definition (e.g. `fmt::Display` or
//! `Iterator`, not `Iterator<Item=u8>`) or a length (or `()` if `T: Sized`).
//!
@ -64,11 +64,16 @@ pub struct CastCheck<'tcx> {
span: Span,
}
/// The kind of the unsize info (length or vtable) - we only allow casts between
/// fat pointers if their unsize-infos have the same kind.
/// The kind of pointer and associated metadata (thin, length or vtable) - we
/// only allow casts between fat pointers if their metadata have the same
/// kind.
#[derive(Copy, Clone, PartialEq, Eq)]
enum UnsizeKind<'tcx> {
enum PointerKind<'tcx> {
/// No metadata attached, ie pointer to sized type or foreign type
Thin,
/// A trait object
Vtable(Option<DefId>),
/// Slice
Length,
/// The unsize info of this projection
OfProjection(&'tcx ty::ProjectionTy<'tcx>),
@ -79,22 +84,28 @@ enum UnsizeKind<'tcx> {
impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
/// Returns the kind of unsize information of t, or None
/// if t is sized or it is unknown.
fn unsize_kind(&self, t: Ty<'tcx>) -> Option<UnsizeKind<'tcx>> {
fn pointer_kind(&self, t: Ty<'tcx>, span: Span) -> PointerKind<'tcx> {
if self.type_is_known_to_be_sized(t, span) {
return PointerKind::Thin;
}
match t.sty {
ty::TySlice(_) | ty::TyStr => Some(UnsizeKind::Length),
ty::TySlice(_) | ty::TyStr => PointerKind::Length,
ty::TyDynamic(ref tty, ..) =>
Some(UnsizeKind::Vtable(tty.principal().map(|p| p.def_id()))),
PointerKind::Vtable(tty.principal().map(|p| p.def_id())),
ty::TyAdt(def, substs) if def.is_struct() => {
// FIXME(arielb1): do some kind of normalization
match def.struct_variant().fields.last() {
None => None,
Some(f) => self.unsize_kind(f.ty(self.tcx, substs)),
None => PointerKind::Thin,
Some(f) => self.pointer_kind(f.ty(self.tcx, substs), span),
}
}
// Pointers to foreign types are thin, despite being unsized
ty::TyForeign(..) => PointerKind::Thin,
// We should really try to normalize here.
ty::TyProjection(ref pi) => Some(UnsizeKind::OfProjection(pi)),
ty::TyParam(ref p) => Some(UnsizeKind::OfParam(p)),
_ => None,
ty::TyProjection(ref pi) => PointerKind::OfProjection(pi),
ty::TyParam(ref p) => PointerKind::OfParam(p),
_ => panic!(),
}
}
}
@ -446,20 +457,23 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> {
debug!("check_ptr_ptr_cast m_expr={:?} m_cast={:?}", m_expr, m_cast);
// ptr-ptr cast. vtables must match.
// Cast to sized is OK
if fcx.type_is_known_to_be_sized(m_cast.ty, self.span) {
// Cast to thin pointer is OK
let cast_kind = fcx.pointer_kind(m_cast.ty, self.span);
if cast_kind == PointerKind::Thin {
return Ok(CastKind::PtrPtrCast);
}
// sized -> unsized? report invalid cast (don't complain about vtable kinds)
if fcx.type_is_known_to_be_sized(m_expr.ty, self.span) {
// thin -> fat? report invalid cast (don't complain about vtable kinds)
let expr_kind = fcx.pointer_kind(m_expr.ty, self.span);
if expr_kind == PointerKind::Thin {
return Err(CastError::SizedUnsizedCast);
}
// vtable kinds must match
match (fcx.unsize_kind(m_cast.ty), fcx.unsize_kind(m_expr.ty)) {
(Some(a), Some(b)) if a == b => Ok(CastKind::PtrPtrCast),
_ => Err(CastError::DifferingKinds),
if cast_kind == expr_kind {
Ok(CastKind::PtrPtrCast)
} else {
Err(CastError::DifferingKinds)
}
}
@ -467,9 +481,9 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> {
fcx: &FnCtxt<'a, 'gcx, 'tcx>,
m_cast: &'tcx ty::TypeAndMut<'tcx>)
-> Result<CastKind, CastError> {
// fptr-ptr cast. must be to sized ptr
// fptr-ptr cast. must be to thin ptr
if fcx.type_is_known_to_be_sized(m_cast.ty, self.span) {
if fcx.pointer_kind(m_cast.ty, self.span) == PointerKind::Thin {
Ok(CastKind::FnPtrPtrCast)
} else {
Err(CastError::IllegalCast)
@ -480,9 +494,9 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> {
fcx: &FnCtxt<'a, 'gcx, 'tcx>,
m_expr: &'tcx ty::TypeAndMut<'tcx>)
-> Result<CastKind, CastError> {
// ptr-addr cast. must be from sized ptr
// ptr-addr cast. must be from thin ptr
if fcx.type_is_known_to_be_sized(m_expr.ty, self.span) {
if fcx.pointer_kind(m_expr.ty, self.span) == PointerKind::Thin {
Ok(CastKind::PtrAddrCast)
} else {
Err(CastError::NeedViaThinPtr)
@ -519,7 +533,7 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> {
m_cast: &'tcx ty::TypeAndMut<'tcx>)
-> Result<CastKind, CastError> {
// ptr-addr cast. pointer must be thin.
if fcx.type_is_known_to_be_sized(m_cast.ty, self.span) {
if fcx.pointer_kind(m_cast.ty, self.span) == PointerKind::Thin {
Ok(CastKind::AddrPtrCast)
} else {
Err(CastError::IllegalCast)

View File

@ -414,6 +414,9 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
ty::TyAdt(def, _) => {
self.assemble_inherent_impl_candidates_for_type(def.did);
}
ty::TyForeign(did) => {
self.assemble_inherent_impl_candidates_for_type(did);
}
ty::TyParam(p) => {
self.assemble_inherent_candidates_from_param(self_ty, p);
}

View File

@ -451,6 +451,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
fn is_local(ty: Ty) -> bool {
match ty.sty {
ty::TyAdt(def, _) => def.did.is_local(),
ty::TyForeign(did) => did.is_local(),
ty::TyDynamic(ref tr, ..) => tr.principal()
.map_or(false, |p| p.def_id().is_local()),

View File

@ -117,6 +117,9 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for InherentCollect<'a, 'tcx> {
ty::TyAdt(def, _) => {
self.check_def_id(item, def.did);
}
ty::TyForeign(did) => {
self.check_def_id(item, did);
}
ty::TyDynamic(ref data, ..) if data.principal().is_some() => {
self.check_def_id(item, data.principal().unwrap().def_id());
}

View File

@ -68,10 +68,10 @@ impl<'cx, 'tcx, 'v> ItemLikeVisitor<'v> for OrphanChecker<'cx, 'tcx> {
}
// In addition to the above rules, we restrict impls of defaulted traits
// so that they can only be implemented on structs/enums. To see why this
// restriction exists, consider the following example (#22978). Imagine
// that crate A defines a defaulted trait `Foo` and a fn that operates
// on pairs of types:
// so that they can only be implemented on nominal types, such as structs,
// enums or foreign types. To see why this restriction exists, consider the
// following example (#22978). Imagine that crate A defines a defaulted trait
// `Foo` and a fn that operates on pairs of types:
//
// ```
// // Crate A
@ -109,11 +109,12 @@ impl<'cx, 'tcx, 'v> ItemLikeVisitor<'v> for OrphanChecker<'cx, 'tcx> {
let self_ty = trait_ref.self_ty();
let opt_self_def_id = match self_ty.sty {
ty::TyAdt(self_def, _) => Some(self_def.did),
ty::TyForeign(did) => Some(did),
_ => None,
};
let msg = match opt_self_def_id {
// We only want to permit structs/enums, but not *all* structs/enums.
// We only want to permit nominal types, but not *all* nominal types.
// They must be local to the current crate, so that people
// can't do `unsafe impl Send for Rc<SomethingLocal>` or
// `impl !Send for Box<SomethingLocalAndSend>`.

View File

@ -916,7 +916,8 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
NodeForeignItem(item) => {
match item.node {
ForeignItemStatic(..) => &no_generics,
ForeignItemFn(_, _, ref generics) => generics
ForeignItemFn(_, _, ref generics) => generics,
ForeignItemType => &no_generics,
}
}
@ -1094,7 +1095,8 @@ fn type_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
let substs = Substs::identity_for_item(tcx, def_id);
tcx.mk_fn_def(def_id, substs)
}
ForeignItemStatic(ref t, _) => icx.to_ty(t)
ForeignItemStatic(ref t, _) => icx.to_ty(t),
ForeignItemType => tcx.mk_foreign(def_id),
}
}
@ -1363,7 +1365,8 @@ fn explicit_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
NodeForeignItem(item) => {
match item.node {
ForeignItemStatic(..) => &no_generics,
ForeignItemFn(_, _, ref generics) => generics
ForeignItemFn(_, _, ref generics) => generics,
ForeignItemType => &no_generics,
}
}

View File

@ -305,7 +305,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
match ty.sty {
ty::TyBool | ty::TyChar | ty::TyInt(_) | ty::TyUint(_) | ty::TyFloat(_) |
ty::TyStr | ty::TyNever => {
ty::TyStr | ty::TyNever | ty::TyForeign(..) => {
// leaf type -- noop
}

View File

@ -419,6 +419,8 @@ pub enum ItemEnum {
ForeignFunctionItem(Function),
/// `static`s from an extern block
ForeignStaticItem(Static),
/// `type`s from an extern block
ForeignTypeItem,
MacroItem(Macro),
PrimitiveItem(PrimitiveType),
AssociatedConstItem(Type, Option<String>),
@ -1646,6 +1648,7 @@ pub enum TypeKind {
Trait,
Variant,
Typedef,
Foreign,
}
pub trait GetDefId {
@ -2027,6 +2030,17 @@ impl<'tcx> Clean<Type> for Ty<'tcx> {
is_generic: false,
}
}
ty::TyForeign(did) => {
inline::record_extern_fqn(cx, did, TypeKind::Foreign);
let path = external_path(cx, &cx.tcx.item_name(did),
None, false, vec![], Substs::empty());
ResolvedPath {
path: path,
typarams: None,
did: did,
is_generic: false,
}
}
ty::TyDynamic(ref obj, ref reg) => {
if let Some(principal) = obj.principal() {
let did = principal.def_id();
@ -2840,6 +2854,9 @@ impl Clean<Item> for hir::ForeignItem {
expr: "".to_string(),
})
}
hir::ForeignItemType => {
ForeignTypeItem
}
};
Item {
name: Some(self.name.clean(cx)),

View File

@ -41,6 +41,7 @@ pub enum ItemType {
Constant = 17,
AssociatedConst = 18,
Union = 19,
ForeignType = 20,
}
@ -82,6 +83,7 @@ impl<'a> From<&'a clean::Item> for ItemType {
clean::AssociatedConstItem(..) => ItemType::AssociatedConst,
clean::AssociatedTypeItem(..) => ItemType::AssociatedType,
clean::DefaultImplItem(..) => ItemType::Impl,
clean::ForeignTypeItem => ItemType::ForeignType,
clean::StrippedItem(..) => unreachable!(),
}
}
@ -100,6 +102,7 @@ impl From<clean::TypeKind> for ItemType {
clean::TypeKind::Const => ItemType::Constant,
clean::TypeKind::Variant => ItemType::Variant,
clean::TypeKind::Typedef => ItemType::Typedef,
clean::TypeKind::Foreign => ItemType::ForeignType,
}
}
}
@ -127,6 +130,7 @@ impl ItemType {
ItemType::AssociatedType => "associatedtype",
ItemType::Constant => "constant",
ItemType::AssociatedConst => "associatedconstant",
ItemType::ForeignType => "foreigntype",
}
}
@ -139,7 +143,8 @@ impl ItemType {
ItemType::Typedef |
ItemType::Trait |
ItemType::Primitive |
ItemType::AssociatedType => NameSpace::Type,
ItemType::AssociatedType |
ItemType::ForeignType => NameSpace::Type,
ItemType::ExternCrate |
ItemType::Import |

View File

@ -2044,6 +2044,7 @@ fn item_module(w: &mut fmt::Formatter, cx: &Context,
ItemType::Primitive => ("primitives", "Primitive Types"),
ItemType::AssociatedType => ("associated-types", "Associated Types"),
ItemType::AssociatedConst => ("associated-consts", "Associated Constants"),
ItemType::ForeignType => ("foreign-types", "Foreign Types"),
};
write!(w, "<h2 id='{id}' class='section-header'>\
<a href=\"#{id}\">{name}</a></h2>\n<table>",
@ -3679,7 +3680,7 @@ fn sidebar_module(fmt: &mut fmt::Formatter, _it: &clean::Item,
ItemType::Enum, ItemType::Constant, ItemType::Static, ItemType::Trait,
ItemType::Function, ItemType::Typedef, ItemType::Union, ItemType::Impl,
ItemType::TyMethod, ItemType::Method, ItemType::StructField, ItemType::Variant,
ItemType::AssociatedType, ItemType::AssociatedConst] {
ItemType::AssociatedType, ItemType::AssociatedConst, ItemType::ForeignType] {
if items.iter().any(|it| {
if let clean::DefaultImplItem(..) = it.inner {
false
@ -3708,6 +3709,7 @@ fn sidebar_module(fmt: &mut fmt::Formatter, _it: &clean::Item,
ItemType::Primitive => ("primitives", "Primitive Types"),
ItemType::AssociatedType => ("associated-types", "Associated Types"),
ItemType::AssociatedConst => ("associated-consts", "Associated Constants"),
ItemType::ForeignType => ("foreign-types", "Foreign Types"),
};
sidebar.push_str(&format!("<li><a href=\"#{id}\">{name}</a></li>",
id = short,

View File

@ -90,7 +90,7 @@ impl<'a> fold::DocFolder for Stripper<'a> {
clean::VariantItem(..) | clean::MethodItem(..) |
clean::ForeignFunctionItem(..) | clean::ForeignStaticItem(..) |
clean::ConstantItem(..) | clean::UnionItem(..) |
clean::AssociatedConstItem(..) => {
clean::AssociatedConstItem(..) | clean::ForeignTypeItem => {
if i.def_id.is_local() {
if !self.access_levels.is_exported(i.def_id) {
return None;

View File

@ -2007,13 +2007,16 @@ pub enum ForeignItemKind {
/// A foreign static item (`static ext: u8`), with optional mutability
/// (the boolean is true when mutable)
Static(P<Ty>, bool),
/// A foreign type
Ty,
}
impl ForeignItemKind {
pub fn descriptive_variant(&self) -> &str {
match *self {
ForeignItemKind::Fn(..) => "foreign function",
ForeignItemKind::Static(..) => "foreign static item"
ForeignItemKind::Static(..) => "foreign static item",
ForeignItemKind::Ty => "foreign type",
}
}
}

View File

@ -404,6 +404,9 @@ declare_features! (
// `crate` as visibility modifier, synonymous to `pub(crate)`
(active, crate_visibility_modifier, "1.23.0", Some(45388)),
// extern types
(active, extern_types, "1.23.0", Some(43467)),
);
declare_features! (
@ -1398,13 +1401,23 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
}
fn visit_foreign_item(&mut self, i: &'a ast::ForeignItem) {
let links_to_llvm = match attr::first_attr_value_str_by_name(&i.attrs, "link_name") {
Some(val) => val.as_str().starts_with("llvm."),
_ => false
};
if links_to_llvm {
gate_feature_post!(&self, link_llvm_intrinsics, i.span,
"linking to LLVM intrinsics is experimental");
match i.node {
ast::ForeignItemKind::Fn(..) |
ast::ForeignItemKind::Static(..) => {
let link_name = attr::first_attr_value_str_by_name(&i.attrs, "link_name");
let links_to_llvm = match link_name {
Some(val) => val.as_str().starts_with("llvm."),
_ => false
};
if links_to_llvm {
gate_feature_post!(&self, link_llvm_intrinsics, i.span,
"linking to LLVM intrinsics is experimental");
}
}
ast::ForeignItemKind::Ty => {
gate_feature_post!(&self, extern_types, i.span,
"extern types are experimental");
}
}
visit::walk_foreign_item(self, i)

View File

@ -1069,6 +1069,7 @@ pub fn noop_fold_foreign_item<T: Folder>(ni: ForeignItem, folder: &mut T) -> For
ForeignItemKind::Static(t, m) => {
ForeignItemKind::Static(folder.fold_ty(t), m)
}
ForeignItemKind::Ty => ForeignItemKind::Ty,
},
span: folder.new_span(ni.span)
}

View File

@ -5687,6 +5687,24 @@ impl<'a> Parser<'a> {
})
}
/// Parse a type from a foreign module
fn parse_item_foreign_type(&mut self, vis: ast::Visibility, lo: Span, attrs: Vec<Attribute>)
-> PResult<'a, ForeignItem> {
self.expect_keyword(keywords::Type)?;
let ident = self.parse_ident()?;
let hi = self.span;
self.expect(&token::Semi)?;
Ok(ast::ForeignItem {
ident: ident,
attrs: attrs,
node: ForeignItemKind::Ty,
id: ast::DUMMY_NODE_ID,
span: lo.to(hi),
vis: vis
})
}
/// Parse extern crate links
///
/// # Examples
@ -6161,6 +6179,10 @@ impl<'a> Parser<'a> {
if self.check_keyword(keywords::Fn) {
return Ok(Some(self.parse_item_foreign_fn(visibility, lo, attrs)?));
}
// FOREIGN TYPE ITEM
if self.check_keyword(keywords::Type) {
return Ok(Some(self.parse_item_foreign_type(visibility, lo, attrs)?));
}
// FIXME #5668: this will occur for a macro invocation:
match self.parse_macro_use_or_failure(attrs, true, false, lo, visibility)? {

View File

@ -1112,6 +1112,13 @@ impl<'a> State<'a> {
self.end()?; // end the head-ibox
self.end() // end the outer cbox
}
ast::ForeignItemKind::Ty => {
self.head(&visibility_qualified(&item.vis, "type"))?;
self.print_ident(item.ident)?;
self.s.word(";")?;
self.end()?; // end the head-ibox
self.end() // end the outer cbox
}
}
}

View File

@ -477,6 +477,7 @@ pub fn walk_foreign_item<'a, V: Visitor<'a>>(visitor: &mut V, foreign_item: &'a
visitor.visit_generics(generics)
}
ForeignItemKind::Static(ref typ, _) => visitor.visit_ty(typ),
ForeignItemKind::Ty => (),
}
walk_list!(visitor, visit_attribute, &foreign_item.attrs);

View File

@ -0,0 +1,22 @@
// Copyright 2017 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(extern_types)]
extern {
type A;
type B;
}
fn foo(r: &A) -> &B {
r //~ ERROR mismatched types
}
fn main() { }

View File

@ -0,0 +1,28 @@
// Copyright 2017 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// Make sure extern types are !Sync and !Send.
#![feature(extern_types)]
extern {
type A;
}
fn assert_sync<T: ?Sized + Sync>() { }
fn assert_send<T: ?Sized + Send>() { }
fn main() {
assert_sync::<A>();
//~^ ERROR the trait bound `A: std::marker::Sync` is not satisfied
assert_send::<A>();
//~^ ERROR the trait bound `A: std::marker::Send` is not satisfied
}

View File

@ -0,0 +1,43 @@
// Copyright 2017 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// Make sure extern types are !Sized.
#![feature(extern_types)]
extern {
type A;
}
struct Foo {
x: u8,
tail: A,
}
struct Bar<T: ?Sized> {
x: u8,
tail: T,
}
fn assert_sized<T>() { }
fn main() {
assert_sized::<A>();
//~^ ERROR the trait bound `A: std::marker::Sized` is not satisfied
assert_sized::<Foo>();
//~^ ERROR the trait bound `A: std::marker::Sized` is not satisfied
assert_sized::<Bar<A>>();
//~^ ERROR the trait bound `A: std::marker::Sized` is not satisfied
assert_sized::<Bar<Bar<A>>>();
//~^ ERROR the trait bound `A: std::marker::Sized` is not satisfied
}

View File

@ -0,0 +1,15 @@
// Copyright 2016 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
extern {
type T; //~ ERROR extern types are experimental
}
fn main() {}

View File

@ -0,0 +1,5 @@
-include ../tools.mk
all: $(call NATIVE_STATICLIB,ctest)
$(RUSTC) test.rs
$(call RUN,test) || exit 1

View File

@ -0,0 +1,17 @@
// ignore-license
#include <stdio.h>
#include <stdint.h>
typedef struct data {
uint32_t magic;
} data;
data* data_create(uint32_t magic) {
static data d;
d.magic = magic;
return &d;
}
uint32_t data_get(data* p) {
return p->magic;
}

View File

@ -0,0 +1,27 @@
// Copyright 2017 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(extern_types)]
#[link(name = "ctest", kind = "static")]
extern {
type data;
fn data_create(magic: u32) -> *mut data;
fn data_get(data: *mut data) -> u32;
}
const MAGIC: u32 = 0xdeadbeef;
fn main() {
unsafe {
let data = data_create(MAGIC);
assert_eq!(data_get(data), MAGIC);
}
}

View File

@ -0,0 +1,27 @@
// Copyright 2017 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// Test that inherent impls can be defined for extern types.
#![feature(extern_types)]
extern {
type A;
}
impl A {
fn foo(&self) { }
}
fn use_foo(x: &A) {
x.foo();
}
fn main() { }

View File

@ -0,0 +1,28 @@
// Copyright 2017 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// Test that unsafe impl for Sync/Send can be provided for extern types.
#![feature(extern_types)]
extern {
type A;
}
unsafe impl Sync for A { }
unsafe impl Send for A { }
fn assert_sync<T: ?Sized + Sync>() { }
fn assert_send<T: ?Sized + Send>() { }
fn main() {
assert_sync::<A>();
assert_send::<A>();
}

View File

@ -0,0 +1,40 @@
// Copyright 2017 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// Test that pointers to extern types can be casted from/to usize,
// despite being !Sized.
#![feature(extern_types)]
extern {
type A;
}
struct Foo {
x: u8,
tail: A,
}
struct Bar<T: ?Sized> {
x: u8,
tail: T,
}
#[cfg(target_pointer_width = "32")]
const MAGIC: usize = 0xdeadbeef;
#[cfg(target_pointer_width = "64")]
const MAGIC: usize = 0x12345678deadbeef;
fn main() {
assert_eq!((MAGIC as *const A) as usize, MAGIC);
assert_eq!((MAGIC as *const Foo) as usize, MAGIC);
assert_eq!((MAGIC as *const Bar<A>) as usize, MAGIC);
assert_eq!((MAGIC as *const Bar<Bar<A>>) as usize, MAGIC);
}

View File

@ -0,0 +1,26 @@
// Copyright 2017 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(extern_types)]
use std::mem::{size_of_val, align_of_val};
extern {
type A;
}
fn main() {
let x: &A = unsafe {
&*(1usize as *const A)
};
assert_eq!(size_of_val(x), 0);
assert_eq!(align_of_val(x), 1);
}

View File

@ -0,0 +1,51 @@
// Copyright 2017 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// Test that pointers and references to extern types are thin, ie they have the same size and
// alignment as a pointer to ().
#![feature(extern_types)]
use std::mem::{align_of, size_of};
extern {
type A;
}
struct Foo {
x: u8,
tail: A,
}
struct Bar<T: ?Sized> {
x: u8,
tail: T,
}
fn assert_thin<T: ?Sized>() {
assert_eq!(size_of::<*const T>(), size_of::<*const ()>());
assert_eq!(align_of::<*const T>(), align_of::<*const ()>());
assert_eq!(size_of::<*mut T>(), size_of::<*mut ()>());
assert_eq!(align_of::<*mut T>(), align_of::<*mut ()>());
assert_eq!(size_of::<&T>(), size_of::<&()>());
assert_eq!(align_of::<&T>(), align_of::<&()>());
assert_eq!(size_of::<&mut T>(), size_of::<&mut ()>());
assert_eq!(align_of::<&mut T>(), align_of::<&mut ()>());
}
fn main() {
assert_thin::<A>();
assert_thin::<Foo>();
assert_thin::<Bar<A>>();
assert_thin::<Bar<Bar<A>>>();
}

View File

@ -0,0 +1,35 @@
// Copyright 2017 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// Test that traits can be implemented for extern types.
#![feature(extern_types)]
extern {
type A;
}
trait Foo {
fn foo(&self) { }
}
impl Foo for A {
fn foo(&self) { }
}
fn assert_foo<T: ?Sized + Foo>() { }
fn use_foo<T: ?Sized + Foo>(x: &Foo) {
x.foo();
}
fn main() {
assert_foo::<A>();
}