Implement RFC 1861: Extern types

This commit is contained in:
Paul Lietar 2017-09-03 19:53:58 +01:00 committed by Paul Liétar
parent bed9a85c40
commit 77f7e85d7f
81 changed files with 737 additions and 120 deletions

View file

@ -485,8 +485,9 @@ impl<T: ?Sized> *const T {
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn is_null(self) -> bool where T: Sized {
self == null()
pub fn is_null(self) -> bool {
// cast to () pointer, as T may not be sized
self as *const () == null()
}
/// Returns `None` if the pointer is null, or else returns a reference to
@ -517,7 +518,7 @@ impl<T: ?Sized> *const T {
/// ```
#[stable(feature = "ptr_as_ref", since = "1.9.0")]
#[inline]
pub unsafe fn as_ref<'a>(self) -> Option<&'a T> where T: Sized {
pub unsafe fn as_ref<'a>(self) -> Option<&'a T> {
if self.is_null() {
None
} else {
@ -1116,8 +1117,9 @@ impl<T: ?Sized> *mut T {
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn is_null(self) -> bool where T: Sized {
self == null_mut()
pub fn is_null(self) -> bool {
// cast to () pointer, as T may not be sized
self as *mut () == null_mut()
}
/// Returns `None` if the pointer is null, or else returns a reference to
@ -1148,7 +1150,7 @@ impl<T: ?Sized> *mut T {
/// ```
#[stable(feature = "ptr_as_ref", since = "1.9.0")]
#[inline]
pub unsafe fn as_ref<'a>(self) -> Option<&'a T> where T: Sized {
pub unsafe fn as_ref<'a>(self) -> Option<&'a T> {
if self.is_null() {
None
} else {
@ -1272,7 +1274,7 @@ impl<T: ?Sized> *mut T {
/// ```
#[stable(feature = "ptr_as_ref", since = "1.9.0")]
#[inline]
pub unsafe fn as_mut<'a>(self) -> Option<&'a mut T> where T: Sized {
pub unsafe fn as_mut<'a>(self) -> Option<&'a mut T> {
if self.is_null() {
None
} else {

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;

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

@ -152,6 +152,19 @@ pub fn type_is_freeze<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty: Ty<'tcx>) -> bo
ty.is_freeze(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),
}
}
/*
* A note on nomenclature of linking: "extern", "foreign", and "upcall".
*

View file

@ -301,6 +301,10 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> {
common::type_is_freeze(self.tcx, ty)
}
pub fn type_has_metadata(&self, ty: Ty<'tcx>) -> bool {
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

@ -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

@ -5671,6 +5671,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
@ -6145,6 +6163,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>();
}