diff --git a/src/librustc/hir/def.rs b/src/librustc/hir/def.rs index 4e0c6479abf14..64bcdc7920a01 100644 --- a/src/librustc/hir/def.rs +++ b/src/librustc/hir/def.rs @@ -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", diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs index d99d7cd897b9f..ae25924ab420c 100644 --- a/src/librustc/hir/intravisit.rs +++ b/src/librustc/hir/intravisit.rs @@ -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); diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 184e664655870..3834852cac5a9 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -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, diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index fb3fc8a2da4f3..ca5ffe830488d 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -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, 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", } } } diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs index b461487355007..24a0b5fcea9b8 100644 --- a/src/librustc/hir/print.rs +++ b/src/librustc/hir/print.rs @@ -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 + } } } diff --git a/src/librustc/ich/impls_hir.rs b/src/librustc/ich/impls_hir.rs index 994f0bd16b1f8..181b97aa7b54a 100644 --- a/src/librustc/ich/impls_hir.rs +++ b/src/librustc/ich/impls_hir.rs @@ -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), diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index 8a8dfbabbe117..48d3017f59763 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -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) } diff --git a/src/librustc/infer/freshen.rs b/src/librustc/infer/freshen.rs index c274f8bda9fb0..41e7dffe54dc1 100644 --- a/src/librustc/infer/freshen.rs +++ b/src/librustc/infer/freshen.rs @@ -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) diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index dc912f1c1b616..ee0e580920e1f 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -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); + } } } diff --git a/src/librustc/traits/coherence.rs b/src/librustc/traits/coherence.rs index dc5ce7353246a..10a32c26e741d 100644 --- a/src/librustc/traits/coherence.rs +++ b/src/librustc/traits/coherence.rs @@ -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()) } diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 030b7e4f646f9..e2b23c12cf1f3 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -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 } } diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index cec79faff315d..6c573acf07d63 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -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(_)) | diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index ebd9fa93236e1..6ab81a41d6809 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -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); diff --git a/src/librustc/ty/error.rs b/src/librustc/ty/error.rs index 52a8389bd8f5f..5cfa72c07126f 100644 --- a/src/librustc/ty/error.rs +++ b/src/librustc/ty/error.rs @@ -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) diff --git a/src/librustc/ty/fast_reject.rs b/src/librustc/ty/fast_reject.rs index 490bfe78a9a1f..138f6af77c658 100644 --- a/src/librustc/ty/fast_reject.rs +++ b/src/librustc/ty/fast_reject.rs @@ -49,6 +49,7 @@ pub enum SimplifiedTypeGen 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 SimplifiedTypeGen { AnonSimplifiedType(d) => AnonSimplifiedType(map(d)), FunctionSimplifiedType(n) => FunctionSimplifiedType(n), ParameterSimplifiedType => ParameterSimplifiedType, + ForeignSimplifiedType(d) => ForeignSimplifiedType(d), } } } @@ -172,6 +177,7 @@ impl<'gcx, D> HashStable> for SimplifiedTypeGen 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), } } } diff --git a/src/librustc/ty/flags.rs b/src/librustc/ty/flags.rs index 9ece719c76470..63c646dbd2310 100644 --- a/src/librustc/ty/flags.rs +++ b/src/librustc/ty/flags.rs @@ -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 diff --git a/src/librustc/ty/item_path.rs b/src/librustc/ty/item_path.rs index a8ccb3e269ffc..98c55331f8a10 100644 --- a/src/librustc/ty/item_path.rs +++ b/src/librustc/ty/item_path.rs @@ -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 { .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 | diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index 1709f9ed2df1c..491fa2a240cce 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -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) } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 9b239a35f90a1..b3f2886cdf9de 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -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] } diff --git a/src/librustc/ty/outlives.rs b/src/librustc/ty/outlives.rs index 5e1dc485d420f..707137649d771 100644 --- a/src/librustc/ty/outlives.rs +++ b/src/librustc/ty/outlives.rs @@ -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(..) | // ... diff --git a/src/librustc/ty/relate.rs b/src/librustc/ty/relate.rs index 309880ba06333..376cdc462e82f 100644 --- a/src/librustc/ty/relate.rs +++ b/src/librustc/ty/relate.rs @@ -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| { diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index 54d55748c8e3a..5f1448cd1f18e 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -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, } } diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index 064627c21bfe6..d0ac7d0183a58 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -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 => { diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index c8037ce081a71..39842a543b54b 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -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 diff --git a/src/librustc/ty/walk.rs b/src/librustc/ty/walk.rs index df07844ccebaf..448ad4cf675c7 100644 --- a/src/librustc/ty/walk.rs +++ b/src/librustc/ty/walk.rs @@ -82,7 +82,8 @@ pub fn walk_shallow<'tcx>(ty: Ty<'tcx>) -> AccIntoIter> { 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); diff --git a/src/librustc/ty/wf.rs b/src/librustc/ty/wf.rs index 41e27fca3f320..c631e2c4db51b 100644 --- a/src/librustc/ty/wf.rs +++ b/src/librustc/ty/wf.rs @@ -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 } diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 0eb2c19fe44dd..acb929981fbf2 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -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| { diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index 38461b0b36419..8f08987505b94 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -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 => () } } } diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 65cf15e5a0ec7..909e01376b92c 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -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(_) | diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 6b49be3e12192..abe2b6d0c1b19 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -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 { diff --git a/src/librustc_metadata/schema.rs b/src/librustc_metadata/schema.rs index 43dbce5288a7e..3c3162bcb5138 100644 --- a/src/librustc_metadata/schema.rs +++ b/src/librustc_metadata/schema.rs @@ -292,6 +292,7 @@ pub enum EntryKind<'tcx> { ForeignImmStatic, ForeignMutStatic, ForeignMod, + ForeignType, GlobalAsm, Type, Enum(ReprOptions), @@ -325,6 +326,7 @@ impl<'gcx> HashStable> for EntryKind<'gcx> { EntryKind::ForeignMutStatic | EntryKind::ForeignMod | EntryKind::GlobalAsm | + EntryKind::ForeignType | EntryKind::Field | EntryKind::Type => { // Nothing else to hash here. diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs index 14e33378969aa..e44f3f3982491 100644 --- a/src/librustc_passes/ast_validation.rs +++ b/src/librustc_passes/ast_validation.rs @@ -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) diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index 8abf7d3d09cd8..3beba03ee1401 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -85,6 +85,7 @@ impl<'a, 'tcx> EmbargoVisitor<'a, 'tcx> { fn item_ty_level(&self, item_def_id: DefId) -> Option { 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; diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 7b1a602d84950..880b370c7f66b 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -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(..) => { diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 8d8e6105e47a6..83eeaf551c56c 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -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); diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index ca44a088e2379..4eac4398c1827 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -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); + } + } } } } diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index 1c6007966afa3..cf2cad1b38c42 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -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) => { diff --git a/src/librustc_save_analysis/sig.rs b/src/librustc_save_analysis/sig.rs index 88f574d513bd8..b0844d1b82404 100644 --- a/src/librustc_save_analysis/sig.rs +++ b/src/librustc_save_analysis/sig.rs @@ -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![], + }) + } } } } diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index 6fd24c1786c69..9df057c77a95d 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -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 } diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs index 3bde78e2c6a60..4f07af9071da3 100644 --- a/src/librustc_trans/debuginfo/metadata.rs +++ b/src/librustc_trans/debuginfo/metadata.rs @@ -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) diff --git a/src/librustc_trans/debuginfo/type_names.rs b/src/librustc_trans/debuginfo/type_names.rs index 7bf9d39ea2f25..85467f5bfbd22 100644 --- a/src/librustc_trans/debuginfo/type_names.rs +++ b/src/librustc_trans/debuginfo/type_names.rs @@ -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); diff --git a/src/librustc_trans/intrinsic.rs b/src/librustc_trans/intrinsic.rs index f78d80a197ca9..e80239175681e 100644 --- a/src/librustc_trans/intrinsic.rs +++ b/src/librustc_trans/intrinsic.rs @@ -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" => { diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs index 1b8e68f691ae6..cea7b9585d8e3 100644 --- a/src/librustc_trans/mir/constant.rs +++ b/src/librustc_trans/mir/constant.rs @@ -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 diff --git a/src/librustc_trans/mir/lvalue.rs b/src/librustc_trans/mir/lvalue.rs index 6799e52904d34..d939acaccd99c 100644 --- a/src/librustc_trans/mir/lvalue.rs +++ b/src/librustc_trans/mir/lvalue.rs @@ -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)) } } + diff --git a/src/librustc_trans/mir/rvalue.rs b/src/librustc_trans/mir/rvalue.rs index 822431eba42f1..777b86387e8bf 100644 --- a/src/librustc_trans/mir/rvalue.rs +++ b/src/librustc_trans/mir/rvalue.rs @@ -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, diff --git a/src/librustc_trans/trans_item.rs b/src/librustc_trans/trans_item.rs index db1af8cdefbe9..fb68be293a79e 100644 --- a/src/librustc_trans/trans_item.rs +++ b/src/librustc_trans/trans_item.rs @@ -230,4 +230,3 @@ fn predefine_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ccx.instances().borrow_mut().insert(instance, lldecl); } - diff --git a/src/librustc_trans/type_of.rs b/src/librustc_trans/type_of.rs index 992c74b9020c3..cac09a81361f0 100644 --- a/src/librustc_trans/type_of.rs +++ b/src/librustc_trans/type_of.rs @@ -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) => { diff --git a/src/librustc_trans_utils/collector.rs b/src/librustc_trans_utils/collector.rs index c87d86262efdd..cf9b80e5ed404 100644 --- a/src/librustc_trans_utils/collector.rs +++ b/src/librustc_trans_utils/collector.rs @@ -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) diff --git a/src/librustc_trans_utils/common.rs b/src/librustc_trans_utils/common.rs index 634e37220e2f1..ec9c5b1119b74 100644 --- a/src/librustc_trans_utils/common.rs +++ b/src/librustc_trans_utils/common.rs @@ -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> diff --git a/src/librustc_trans_utils/lib.rs b/src/librustc_trans_utils/lib.rs index b468c510c0997..6a341a1e7d378 100644 --- a/src/librustc_trans_utils/lib.rs +++ b/src/librustc_trans_utils/lib.rs @@ -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; diff --git a/src/librustc_trans_utils/trans_item.rs b/src/librustc_trans_utils/trans_item.rs index 0ada39d7d2711..817ceefeb7fe9 100644 --- a/src/librustc_trans_utils/trans_item.rs +++ b/src/librustc_trans_utils/trans_item.rs @@ -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); diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 7c9497badfbea..c7f7e62fd61ef 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -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()) diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs index 9c6cacb9d25f9..7b35b46683099 100644 --- a/src/librustc_typeck/check/cast.rs +++ b/src/librustc_typeck/check/cast.rs @@ -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`) 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), + /// 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> { + 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 { - // 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 { - // 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 { // 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) diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 78941cb3a5686..a24f420af80dc 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -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); } diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index 23148406a111e..8613ec86b4a73 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -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()), diff --git a/src/librustc_typeck/coherence/inherent_impls.rs b/src/librustc_typeck/coherence/inherent_impls.rs index 15e15abfb3606..c56a3b91ca37f 100644 --- a/src/librustc_typeck/coherence/inherent_impls.rs +++ b/src/librustc_typeck/coherence/inherent_impls.rs @@ -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()); } diff --git a/src/librustc_typeck/coherence/orphan.rs b/src/librustc_typeck/coherence/orphan.rs index 097720adad447..a5edc95b79b08 100644 --- a/src/librustc_typeck/coherence/orphan.rs +++ b/src/librustc_typeck/coherence/orphan.rs @@ -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` or // `impl !Send for Box`. diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 68ba1b4c44c81..75e864d07a6c2 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -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, } } diff --git a/src/librustc_typeck/variance/constraints.rs b/src/librustc_typeck/variance/constraints.rs index 857b35158f273..ef6552c8e33f4 100644 --- a/src/librustc_typeck/variance/constraints.rs +++ b/src/librustc_typeck/variance/constraints.rs @@ -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 } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 4e8bf5f91092b..f8fea643d5e14 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -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), @@ -1646,6 +1648,7 @@ pub enum TypeKind { Trait, Variant, Typedef, + Foreign, } pub trait GetDefId { @@ -2027,6 +2030,17 @@ impl<'tcx> Clean 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 for hir::ForeignItem { expr: "".to_string(), }) } + hir::ForeignItemType => { + ForeignTypeItem + } }; Item { name: Some(self.name.clean(cx)), diff --git a/src/librustdoc/html/item_type.rs b/src/librustdoc/html/item_type.rs index f584c4e2f4d9c..c9c5f01f0aea1 100644 --- a/src/librustdoc/html/item_type.rs +++ b/src/librustdoc/html/item_type.rs @@ -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 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 | diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index d538428a7e9a9..ac2cb1665a77a 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -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, "

\ {name}

\n", @@ -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!("
  • {name}
  • ", id = short, diff --git a/src/librustdoc/passes/mod.rs b/src/librustdoc/passes/mod.rs index 146629486fabd..959543404d8d2 100644 --- a/src/librustdoc/passes/mod.rs +++ b/src/librustdoc/passes/mod.rs @@ -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; diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 090fc193b38a9..d3995d957928e 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -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, 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", } } } diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 02aba8a3612a6..30451ec757a9f 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -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) diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 518386a2ad29c..fea49424dc8d2 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -1069,6 +1069,7 @@ pub fn noop_fold_foreign_item(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) } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index e96a5417aff5f..a3a265450ab0e 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -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) + -> 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)? { diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 656a51c663721..8a970fd409895 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -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 + } } } diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 4198055f6702a..96e47a6cc0ff6 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -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); diff --git a/src/test/compile-fail/extern-types-distinct-types.rs b/src/test/compile-fail/extern-types-distinct-types.rs new file mode 100644 index 0000000000000..8b434bbfc6d33 --- /dev/null +++ b/src/test/compile-fail/extern-types-distinct-types.rs @@ -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 or the MIT license +// , 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() { } diff --git a/src/test/compile-fail/extern-types-not-sync-send.rs b/src/test/compile-fail/extern-types-not-sync-send.rs new file mode 100644 index 0000000000000..2f00cf812e473 --- /dev/null +++ b/src/test/compile-fail/extern-types-not-sync-send.rs @@ -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 or the MIT license +// , 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() { } +fn assert_send() { } + +fn main() { + assert_sync::(); + //~^ ERROR the trait bound `A: std::marker::Sync` is not satisfied + + assert_send::(); + //~^ ERROR the trait bound `A: std::marker::Send` is not satisfied +} diff --git a/src/test/compile-fail/extern-types-unsized.rs b/src/test/compile-fail/extern-types-unsized.rs new file mode 100644 index 0000000000000..faa27894806f8 --- /dev/null +++ b/src/test/compile-fail/extern-types-unsized.rs @@ -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 or the MIT license +// , 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 { + x: u8, + tail: T, +} + +fn assert_sized() { } + +fn main() { + assert_sized::(); + //~^ ERROR the trait bound `A: std::marker::Sized` is not satisfied + + assert_sized::(); + //~^ ERROR the trait bound `A: std::marker::Sized` is not satisfied + + assert_sized::>(); + //~^ ERROR the trait bound `A: std::marker::Sized` is not satisfied + + assert_sized::>>(); + //~^ ERROR the trait bound `A: std::marker::Sized` is not satisfied +} diff --git a/src/test/compile-fail/feature-gate-extern_types.rs b/src/test/compile-fail/feature-gate-extern_types.rs new file mode 100644 index 0000000000000..1203b598df3c2 --- /dev/null +++ b/src/test/compile-fail/feature-gate-extern_types.rs @@ -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 or the MIT license +// , 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() {} diff --git a/src/test/run-make/extern-fn-with-extern-types/Makefile b/src/test/run-make/extern-fn-with-extern-types/Makefile new file mode 100644 index 0000000000000..8977e14c3ad1a --- /dev/null +++ b/src/test/run-make/extern-fn-with-extern-types/Makefile @@ -0,0 +1,5 @@ +-include ../tools.mk + +all: $(call NATIVE_STATICLIB,ctest) + $(RUSTC) test.rs + $(call RUN,test) || exit 1 diff --git a/src/test/run-make/extern-fn-with-extern-types/ctest.c b/src/test/run-make/extern-fn-with-extern-types/ctest.c new file mode 100644 index 0000000000000..c3d6166fb1284 --- /dev/null +++ b/src/test/run-make/extern-fn-with-extern-types/ctest.c @@ -0,0 +1,17 @@ +// ignore-license +#include +#include + +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; +} diff --git a/src/test/run-make/extern-fn-with-extern-types/test.rs b/src/test/run-make/extern-fn-with-extern-types/test.rs new file mode 100644 index 0000000000000..9d6c87885b16e --- /dev/null +++ b/src/test/run-make/extern-fn-with-extern-types/test.rs @@ -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 or the MIT license +// , 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); + } +} diff --git a/src/test/run-pass/extern-types-inherent-impl.rs b/src/test/run-pass/extern-types-inherent-impl.rs new file mode 100644 index 0000000000000..4e44af3690064 --- /dev/null +++ b/src/test/run-pass/extern-types-inherent-impl.rs @@ -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 or the MIT license +// , 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() { } diff --git a/src/test/run-pass/extern-types-manual-sync-send.rs b/src/test/run-pass/extern-types-manual-sync-send.rs new file mode 100644 index 0000000000000..c6530c3ea773a --- /dev/null +++ b/src/test/run-pass/extern-types-manual-sync-send.rs @@ -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 or the MIT license +// , 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() { } +fn assert_send() { } + +fn main() { + assert_sync::(); + assert_send::(); +} diff --git a/src/test/run-pass/extern-types-pointer-cast.rs b/src/test/run-pass/extern-types-pointer-cast.rs new file mode 100644 index 0000000000000..628a570665a33 --- /dev/null +++ b/src/test/run-pass/extern-types-pointer-cast.rs @@ -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 or the MIT license +// , 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 { + 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) as usize, MAGIC); + assert_eq!((MAGIC as *const Bar>) as usize, MAGIC); +} diff --git a/src/test/run-pass/extern-types-size_of_val.rs b/src/test/run-pass/extern-types-size_of_val.rs new file mode 100644 index 0000000000000..0aabce99debe8 --- /dev/null +++ b/src/test/run-pass/extern-types-size_of_val.rs @@ -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 or the MIT license +// , 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); +} diff --git a/src/test/run-pass/extern-types-thin-pointer.rs b/src/test/run-pass/extern-types-thin-pointer.rs new file mode 100644 index 0000000000000..c2444a58b5a1b --- /dev/null +++ b/src/test/run-pass/extern-types-thin-pointer.rs @@ -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 or the MIT license +// , 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 { + x: u8, + tail: T, +} + +fn assert_thin() { + 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::(); + assert_thin::(); + assert_thin::>(); + assert_thin::>>(); +} diff --git a/src/test/run-pass/extern-types-trait-impl.rs b/src/test/run-pass/extern-types-trait-impl.rs new file mode 100644 index 0000000000000..0f61c936deb61 --- /dev/null +++ b/src/test/run-pass/extern-types-trait-impl.rs @@ -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 or the MIT license +// , 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() { } + +fn use_foo(x: &Foo) { + x.foo(); +} + +fn main() { + assert_foo::(); +}