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:
commit
dce604a8fe
@ -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",
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
|
@ -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",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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),
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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())
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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(_)) |
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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 |
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
|
@ -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]
|
||||
}
|
||||
|
@ -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(..) | // ...
|
||||
|
@ -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| {
|
||||
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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 => {
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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| {
|
||||
|
@ -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 => ()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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(_) |
|
||||
|
@ -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 {
|
||||
|
@ -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.
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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(..) => {
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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) => {
|
||||
|
@ -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![],
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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" => {
|
||||
|
@ -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
|
||||
|
@ -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))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
|
@ -230,4 +230,3 @@ fn predefine_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
||||
|
||||
ccx.instances().borrow_mut().insert(instance, lldecl);
|
||||
}
|
||||
|
||||
|
@ -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) => {
|
||||
|
@ -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)
|
||||
|
@ -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>
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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())
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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()),
|
||||
|
@ -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());
|
||||
}
|
||||
|
@ -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>`.
|
||||
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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)),
|
||||
|
@ -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 |
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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)? {
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
22
src/test/compile-fail/extern-types-distinct-types.rs
Normal file
22
src/test/compile-fail/extern-types-distinct-types.rs
Normal 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() { }
|
28
src/test/compile-fail/extern-types-not-sync-send.rs
Normal file
28
src/test/compile-fail/extern-types-not-sync-send.rs
Normal 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
|
||||
}
|
43
src/test/compile-fail/extern-types-unsized.rs
Normal file
43
src/test/compile-fail/extern-types-unsized.rs
Normal 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
|
||||
}
|
15
src/test/compile-fail/feature-gate-extern_types.rs
Normal file
15
src/test/compile-fail/feature-gate-extern_types.rs
Normal 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() {}
|
5
src/test/run-make/extern-fn-with-extern-types/Makefile
Normal file
5
src/test/run-make/extern-fn-with-extern-types/Makefile
Normal file
@ -0,0 +1,5 @@
|
||||
-include ../tools.mk
|
||||
|
||||
all: $(call NATIVE_STATICLIB,ctest)
|
||||
$(RUSTC) test.rs
|
||||
$(call RUN,test) || exit 1
|
17
src/test/run-make/extern-fn-with-extern-types/ctest.c
Normal file
17
src/test/run-make/extern-fn-with-extern-types/ctest.c
Normal 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;
|
||||
}
|
27
src/test/run-make/extern-fn-with-extern-types/test.rs
Normal file
27
src/test/run-make/extern-fn-with-extern-types/test.rs
Normal 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);
|
||||
}
|
||||
}
|
27
src/test/run-pass/extern-types-inherent-impl.rs
Normal file
27
src/test/run-pass/extern-types-inherent-impl.rs
Normal 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() { }
|
28
src/test/run-pass/extern-types-manual-sync-send.rs
Normal file
28
src/test/run-pass/extern-types-manual-sync-send.rs
Normal 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>();
|
||||
}
|
40
src/test/run-pass/extern-types-pointer-cast.rs
Normal file
40
src/test/run-pass/extern-types-pointer-cast.rs
Normal 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);
|
||||
}
|
26
src/test/run-pass/extern-types-size_of_val.rs
Normal file
26
src/test/run-pass/extern-types-size_of_val.rs
Normal 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);
|
||||
}
|
51
src/test/run-pass/extern-types-thin-pointer.rs
Normal file
51
src/test/run-pass/extern-types-thin-pointer.rs
Normal 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>>>();
|
||||
}
|
35
src/test/run-pass/extern-types-trait-impl.rs
Normal file
35
src/test/run-pass/extern-types-trait-impl.rs
Normal 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>();
|
||||
}
|
Loading…
Reference in New Issue
Block a user