From 907c7a33574bf67cd902ed19309c5b1b9f497f9a Mon Sep 17 00:00:00 2001 From: Paul Lietar Date: Sun, 3 Sep 2017 19:53:58 +0100 Subject: [PATCH 1/7] Implement RFC 1861: Extern types --- src/libcore/ptr.rs | 16 +++-- src/librustc/hir/def.rs | 4 +- src/librustc/hir/intravisit.rs | 1 + src/librustc/hir/lowering.rs | 3 + src/librustc/hir/mod.rs | 3 + src/librustc/hir/print.rs | 7 ++ src/librustc/ich/impls_hir.rs | 4 +- src/librustc/ich/impls_ty.rs | 6 +- src/librustc/infer/freshen.rs | 1 + src/librustc/middle/resolve_lifetime.rs | 3 + src/librustc/traits/coherence.rs | 4 ++ src/librustc/traits/error_reporting.rs | 1 + src/librustc/traits/select.rs | 12 +++- src/librustc/ty/context.rs | 6 +- src/librustc/ty/error.rs | 1 + src/librustc/ty/fast_reject.rs | 6 ++ src/librustc/ty/flags.rs | 3 +- src/librustc/ty/item_path.rs | 7 +- src/librustc/ty/layout.rs | 22 ++++--- src/librustc/ty/mod.rs | 2 +- src/librustc/ty/outlives.rs | 1 + src/librustc/ty/relate.rs | 6 ++ src/librustc/ty/structural_impls.rs | 4 +- src/librustc/ty/sty.rs | 11 ++-- src/librustc/ty/util.rs | 6 +- src/librustc/ty/walk.rs | 3 +- src/librustc/ty/wf.rs | 3 +- src/librustc/util/ppaux.rs | 3 +- src/librustc_lint/types.rs | 3 + src/librustc_metadata/decoder.rs | 1 + src/librustc_metadata/encoder.rs | 1 + src/librustc_metadata/schema.rs | 2 + src/librustc_passes/ast_validation.rs | 2 +- src/librustc_privacy/lib.rs | 16 ++++- src/librustc_resolve/build_reduced_graph.rs | 13 ++-- src/librustc_resolve/lib.rs | 4 +- src/librustc_save_analysis/dump_visitor.rs | 7 ++ src/librustc_save_analysis/lib.rs | 3 + src/librustc_save_analysis/sig.rs | 17 +++++ src/librustc_trans/collector.rs | 4 +- src/librustc_trans/common.rs | 13 ++++ src/librustc_trans/context.rs | 4 ++ src/librustc_trans/debuginfo/metadata.rs | 16 +++++ src/librustc_trans/debuginfo/type_names.rs | 1 + src/librustc_trans/intrinsic.rs | 14 ++-- src/librustc_trans/mir/constant.rs | 6 +- src/librustc_trans/mir/lvalue.rs | 18 ++++-- src/librustc_trans/mir/rvalue.rs | 2 +- src/librustc_trans/trans_item.rs | 1 + src/librustc_trans/type_of.rs | 8 +-- src/librustc_typeck/astconv.rs | 3 +- src/librustc_typeck/check/cast.rs | 64 +++++++++++-------- src/librustc_typeck/check/method/probe.rs | 3 + src/librustc_typeck/check/method/suggest.rs | 1 + .../coherence/inherent_impls.rs | 3 + src/librustc_typeck/coherence/orphan.rs | 11 ++-- src/librustc_typeck/collect.rs | 9 ++- src/librustc_typeck/variance/constraints.rs | 2 +- src/librustdoc/clean/mod.rs | 17 +++++ src/librustdoc/html/item_type.rs | 7 +- src/librustdoc/html/render.rs | 4 +- src/librustdoc/passes/mod.rs | 2 +- src/libsyntax/ast.rs | 5 +- src/libsyntax/feature_gate.rs | 27 ++++++-- src/libsyntax/fold.rs | 1 + src/libsyntax/parse/parser.rs | 22 +++++++ src/libsyntax/print/pprust.rs | 7 ++ src/libsyntax/visit.rs | 1 + .../extern-types-distinct-types.rs | 22 +++++++ .../extern-types-not-sync-send.rs | 28 ++++++++ src/test/compile-fail/extern-types-unsized.rs | 43 +++++++++++++ .../compile-fail/feature-gate-extern_types.rs | 15 +++++ .../extern-fn-with-extern-types/Makefile | 5 ++ .../extern-fn-with-extern-types/ctest.c | 17 +++++ .../extern-fn-with-extern-types/test.rs | 27 ++++++++ .../run-pass/extern-types-inherent-impl.rs | 27 ++++++++ .../run-pass/extern-types-manual-sync-send.rs | 28 ++++++++ .../run-pass/extern-types-pointer-cast.rs | 40 ++++++++++++ src/test/run-pass/extern-types-size_of_val.rs | 26 ++++++++ .../run-pass/extern-types-thin-pointer.rs | 51 +++++++++++++++ src/test/run-pass/extern-types-trait-impl.rs | 35 ++++++++++ 81 files changed, 739 insertions(+), 119 deletions(-) create mode 100644 src/test/compile-fail/extern-types-distinct-types.rs create mode 100644 src/test/compile-fail/extern-types-not-sync-send.rs create mode 100644 src/test/compile-fail/extern-types-unsized.rs create mode 100644 src/test/compile-fail/feature-gate-extern_types.rs create mode 100644 src/test/run-make/extern-fn-with-extern-types/Makefile create mode 100644 src/test/run-make/extern-fn-with-extern-types/ctest.c create mode 100644 src/test/run-make/extern-fn-with-extern-types/test.rs create mode 100644 src/test/run-pass/extern-types-inherent-impl.rs create mode 100644 src/test/run-pass/extern-types-manual-sync-send.rs create mode 100644 src/test/run-pass/extern-types-pointer-cast.rs create mode 100644 src/test/run-pass/extern-types-size_of_val.rs create mode 100644 src/test/run-pass/extern-types-thin-pointer.rs create mode 100644 src/test/run-pass/extern-types-trait-impl.rs diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 4041a3760e5ca..4d7d151ca8983 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -487,8 +487,9 @@ impl *const T { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn is_null(self) -> bool where T: Sized { - self == null() + pub fn is_null(self) -> bool { + // cast to () pointer, as T may not be sized + self as *const () == null() } /// Returns `None` if the pointer is null, or else returns a reference to @@ -519,7 +520,7 @@ impl *const T { /// ``` #[stable(feature = "ptr_as_ref", since = "1.9.0")] #[inline] - pub unsafe fn as_ref<'a>(self) -> Option<&'a T> where T: Sized { + pub unsafe fn as_ref<'a>(self) -> Option<&'a T> { if self.is_null() { None } else { @@ -1118,8 +1119,9 @@ impl *mut T { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn is_null(self) -> bool where T: Sized { - self == null_mut() + pub fn is_null(self) -> bool { + // cast to () pointer, as T may not be sized + self as *mut () == null_mut() } /// Returns `None` if the pointer is null, or else returns a reference to @@ -1150,7 +1152,7 @@ impl *mut T { /// ``` #[stable(feature = "ptr_as_ref", since = "1.9.0")] #[inline] - pub unsafe fn as_ref<'a>(self) -> Option<&'a T> where T: Sized { + pub unsafe fn as_ref<'a>(self) -> Option<&'a T> { if self.is_null() { None } else { @@ -1274,7 +1276,7 @@ impl *mut T { /// ``` #[stable(feature = "ptr_as_ref", since = "1.9.0")] #[inline] - pub unsafe fn as_mut<'a>(self) -> Option<&'a mut T> where T: Sized { + pub unsafe fn as_mut<'a>(self) -> Option<&'a mut T> { if self.is_null() { None } else { 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 1755b3bca0572..12dea2ca382e4 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 411cdde3190b2..2a8e4e61272a7 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -1715,6 +1715,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 bff71155440a3..ca96ccdaacfcb 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -1904,6 +1904,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_ { @@ -1911,6 +1913,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 5daffe667fde5..57ea3c3b4362a 100644 --- a/src/librustc/hir/print.rs +++ b/src/librustc/hir/print.rs @@ -477,6 +477,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 96d5940caf6a4..bf12a0a585758 100644 --- a/src/librustc/ich/impls_hir.rs +++ b/src/librustc/ich/impls_hir.rs @@ -968,7 +968,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_ { @@ -1077,6 +1078,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 2bbf807807bad..b1c18d5d934e4 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -606,8 +606,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); @@ -626,6 +625,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 d0c5460fa9714..e215579331e17 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 f3682f8d35d84..7fd20c0a41a9e 100644 --- a/src/librustc/traits/coherence.rs +++ b/src/librustc/traits/coherence.rs @@ -305,6 +305,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 c7c8141f4f768..5e9b853895588 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 00f0672822fc1..2ecb82b77d34c 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -1707,6 +1707,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 @@ -2024,7 +2030,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())) @@ -2068,7 +2074,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 } @@ -2150,6 +2157,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 315ba622ccf6d..5b9639507a718 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -1576,7 +1576,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()); @@ -1827,6 +1827,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 2c1b3e28ffb00..cdc5e1c404411 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -1724,7 +1724,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 657ed4077911c..9d29c2adb1869 100644 --- a/src/librustc/ty/outlives.rs +++ b/src/librustc/ty/outlives.rs @@ -178,6 +178,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 a203e290dbaeb..d2b45eccc9dc7 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -105,6 +105,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, @@ -1165,13 +1167,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 { @@ -1395,6 +1390,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, } @@ -1444,6 +1440,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 27819f551b9b3..1675c3f5a8319 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 214973e308586..4c6b7d3e5b343 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}; @@ -788,6 +788,7 @@ impl<'tcx> fmt::Display for ty::TypeVariants<'tcx> { TyError => write!(f, "[type error]"), TyParam(ref param_ty) => write!(f, "{}", param_ty), TyAdt(def, substs) => parameterized(f, substs, def.did, &[]), + TyForeign(def_id) => parameterized(f, subst::Substs::empty(), def_id, &[]), TyDynamic(data, r) => { write!(f, "{}", data)?; let r = r.to_string(); diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index d3a5d52b295af..ca2c1bd3a1807 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -615,6 +615,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { FfiSafe } + ty::TyForeign(..) => FfiSafe, + ty::TyParam(..) | ty::TyInfer(..) | ty::TyError | @@ -717,6 +719,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 dad0d26d2715d..a1b5d052e1cda 100644 --- a/src/librustc_metadata/schema.rs +++ b/src/librustc_metadata/schema.rs @@ -291,6 +291,7 @@ pub enum EntryKind<'tcx> { ForeignImmStatic, ForeignMutStatic, ForeignMod, + ForeignType, GlobalAsm, Type, Enum(ReprOptions), @@ -324,6 +325,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 efb5b03180998..d2e8b87269e20 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 e7a1dd6b043b1..ac0ddbf3f7178 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 a4d1ae1621571..5ddde096d72b3 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 36cd69f91b9c3..c6fc42c501e1f 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -464,7 +464,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 { @@ -703,6 +704,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 3e730cf836523..49e3ce2f5ed0d 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 { @@ -1536,6 +1537,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 c7e00245d6350..d540b2bf6e825 100644 --- a/src/librustc_save_analysis/sig.rs +++ b/src/librustc_save_analysis/sig.rs @@ -807,6 +807,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/collector.rs b/src/librustc_trans/collector.rs index 6fa69de74b0a1..b3a8a25a48983 100644 --- a/src/librustc_trans/collector.rs +++ b/src/librustc_trans/collector.rs @@ -202,7 +202,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}; @@ -775,7 +775,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/common.rs b/src/librustc_trans/common.rs index 52607904f73c4..8b1976c49a665 100644 --- a/src/librustc_trans/common.rs +++ b/src/librustc_trans/common.rs @@ -153,6 +153,19 @@ pub fn type_is_freeze<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty: Ty<'tcx>) -> bo ty.is_freeze(tcx, ty::ParamEnv::empty(traits::Reveal::All), DUMMY_SP) } +pub fn type_has_metadata<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty: Ty<'tcx>) -> bool { + if type_is_sized(tcx, ty) { + return false; + } + + let tail = tcx.struct_tail(ty); + match tail.sty { + ty::TyForeign(..) => false, + ty::TyStr | ty::TySlice(..) | ty::TyDynamic(..) => true, + _ => bug!("unexpected unsized tail: {:?}", tail.sty), + } +} + /* * A note on nomenclature of linking: "extern", "foreign", and "upcall". * diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index b394911c9234d..b03bc46b6f5fd 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -301,6 +301,10 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> { common::type_is_freeze(self.tcx, ty) } + pub fn type_has_metadata(&self, ty: Ty<'tcx>) -> bool { + common::type_has_metadata(self.tcx, ty) + } + pub fn tcx(&self) -> TyCtxt<'b, 'tcx, 'tcx> { self.tcx } diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs index 8a89bfee4ac26..6799c2ea1c294 100644 --- a/src/librustc_trans/debuginfo/metadata.rs +++ b/src/librustc_trans/debuginfo/metadata.rs @@ -544,6 +544,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) { @@ -753,6 +758,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 9232d73f832e7..45d857fe49910 100644 --- a/src/librustc_trans/mir/constant.rs +++ b/src/librustc_trans/mir/constant.rs @@ -425,11 +425,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() @@ -460,7 +460,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 526b61303e153..9e624d83a5b7c 100644 --- a/src/librustc_trans/trans_item.rs +++ b/src/librustc_trans/trans_item.rs @@ -411,6 +411,7 @@ impl<'a, 'tcx> DefPathBasedNames<'a, 'tcx> { ty::TyUint(ast::UintTy::U128) => output.push_str("u128"), ty::TyFloat(ast::FloatTy::F32) => output.push_str("f32"), ty::TyFloat(ast::FloatTy::F64) => output.push_str("f64"), + ty::TyForeign(def_id) => self.push_def_path(def_id, output), ty::TyAdt(adt_def, substs) => { self.push_def_path(adt_def.did, output); self.push_type_params(substs, iter::empty(), output); 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_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 54fd070e93cbc..58a09d5aa65ee 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 a3b196f99d629..5ff76752bf9a2 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -413,6 +413,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 90c5297b39985..00a6746a8a06c 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -448,6 +448,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 a36594cb6e557..688f50777dd40 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -935,7 +935,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, } } @@ -1111,7 +1112,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), } } @@ -1380,7 +1382,8 @@ fn 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 29da763f334c7..8f2c4ea835089 100644 --- a/src/librustc_typeck/variance/constraints.rs +++ b/src/librustc_typeck/variance/constraints.rs @@ -301,7 +301,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 c9afa3646b2da..4b5ac75242d5b 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -416,6 +416,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), @@ -1642,6 +1644,7 @@ pub enum TypeKind { Trait, Variant, Typedef, + Foreign, } pub trait GetDefId { @@ -1998,6 +2001,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(); @@ -2810,6 +2824,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 485e75443fe08..4dd276e8ec907 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -2017,6 +2017,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", @@ -3627,7 +3628,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 @@ -3656,6 +3657,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 0504e889ea10b..137eb89a907f8 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -1992,13 +1992,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 4da0df5b0de01..b1ba96f7773b0 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -395,6 +395,9 @@ declare_features! ( // allow `..=` in patterns (RFC 1192) (active, dotdoteq_in_patterns, "1.22.0", Some(28237)), + + // extern types + (active, extern_types, "1.22.0", Some(43467)), ); declare_features! ( @@ -1382,13 +1385,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 03c47b71d02d7..0f4722e87145a 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -1067,6 +1067,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 d5ba4b54d9014..f02b46c69f27f 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -5621,6 +5621,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 @@ -6095,6 +6113,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 959dd4ef30f29..5b735c8717f66 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -1111,6 +1111,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 05077d42a0bed..5657300e629d6 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -464,6 +464,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::(); +} From da549e116a335c3febbe40b72bb7deeca7039b2d Mon Sep 17 00:00:00 2001 From: Paul Lietar Date: Fri, 29 Sep 2017 13:14:36 +0200 Subject: [PATCH 2/7] Mark rustfmt and rls as broken. Rustfmt needs support for extern types, and rls depends on rustfmt. --- src/tools/toolstate.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tools/toolstate.toml b/src/tools/toolstate.toml index 1700daa0aff14..c36d50ad710e4 100644 --- a/src/tools/toolstate.toml +++ b/src/tools/toolstate.toml @@ -29,8 +29,8 @@ miri = "Broken" clippy = "Broken" # ping @nrc -rls = "Testing" +rls = "Broken" # ping @nrc -rustfmt = "Testing" +rustfmt = "Broken" From c0cf410878e32fda6f506c17cbe31dedcc321c97 Mon Sep 17 00:00:00 2001 From: Paul Lietar Date: Sun, 3 Sep 2017 23:48:02 +0100 Subject: [PATCH 3/7] Add a DynSized trait. The DynSized trait is implemented by all types which have a size and alignment known at runtime. This includes every type other than extern types, introduced in RFC 1861 and implemented in #44295, which are completely opaque. The main motivation for this trait is to prevent the use of !DynSized types as struct tails. Consider for example the following types : ```rust extern { type foo; } struct A { a_x: u8 a_y: T } struct B { b_x: u8 b_y: T } ``` Before this change, the type `A>` is considered well-formed. However, the alignment of `B` and thus the offset of the `a_y` field depends on the alignment of `foo`, which is unknown. By introducing this new trait, struct tails are now required to implement `DynSized`, such that their alignment is known. The trait is an implicit bound, making `A>` ill-formed. Just like the `Sized` trait, the default bound can be opted-out by using `?DynSized`. --- src/libcore/marker.rs | 97 +++++++++++++++++------ src/libcore/ptr.rs | 2 +- src/librustc/dep_graph/dep_node.rs | 2 + src/librustc/lib.rs | 2 +- src/librustc/middle/lang_items.rs | 1 + src/librustc/traits/error_reporting.rs | 3 + src/librustc/traits/mod.rs | 3 + src/librustc/traits/select.rs | 56 +++++++++++++ src/librustc/traits/structural_impls.rs | 3 + src/librustc/ty/maps/config.rs | 6 ++ src/librustc/ty/maps/mod.rs | 6 ++ src/librustc/ty/mod.rs | 98 +++++++++++++++++++++++ src/librustc/ty/util.rs | 25 +++++- src/librustc/ty/wf.rs | 14 +++- src/librustc/util/ppaux.rs | 10 ++- src/librustc_passes/ast_validation.rs | 35 +++----- src/librustc_trans/common.rs | 4 + src/librustc_trans/context.rs | 4 + src/librustc_trans/intrinsic.rs | 8 +- src/librustc_trans/mir/lvalue.rs | 15 ++-- src/librustc_typeck/astconv.rs | 11 +++ src/librustc_typeck/check/wfcheck.rs | 11 +++ src/librustc_typeck/coherence/mod.rs | 10 ++- src/librustc_typeck/collect.rs | 101 ++++++++++++++++-------- src/libstd/lib.rs | 1 + src/libstd/panic.rs | 31 +++++++- 26 files changed, 452 insertions(+), 107 deletions(-) diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs index e8fd729b638be..6c003506846b9 100644 --- a/src/libcore/marker.rs +++ b/src/libcore/marker.rs @@ -40,6 +40,16 @@ use hash::Hasher; /// [ub]: ../../reference/behavior-considered-undefined.html #[stable(feature = "rust1", since = "1.0.0")] #[lang = "send"] +#[cfg(not(stage0))] +#[rustc_on_unimplemented = "`{Self}` cannot be sent between threads safely"] +pub unsafe trait Send: ?DynSized { + // empty. +} + +/// docs +#[stable(feature = "rust1", since = "1.0.0")] +#[lang = "send"] +#[cfg(stage0)] #[rustc_on_unimplemented = "`{Self}` cannot be sent between threads safely"] pub unsafe trait Send { // empty. @@ -49,9 +59,9 @@ pub unsafe trait Send { unsafe impl Send for .. { } #[stable(feature = "rust1", since = "1.0.0")] -impl !Send for *const T { } +impl !Send for *const T { } #[stable(feature = "rust1", since = "1.0.0")] -impl !Send for *mut T { } +impl !Send for *mut T { } /// Types with a constant size known at compile time. /// @@ -94,6 +104,29 @@ pub trait Sized { // Empty. } +/// Types with a size known at run time. +/// +/// This trait is implemented both by `Sized` types, and by dynamically sized +/// types such as slices and [trait objects]. [Extern types], whose size is not +/// known, even at runtime, do not implement this trait. +/// +/// All traits and type parameters have an implicit bound of `DynSized`. The +/// special syntax `?DynSized` can be used to remove this bound if it's not +/// appropriate. +/// +/// [trait object]: ../../book/first-edition/trait-objects.html +#[cfg(not(stage0))] +#[unstable(feature = "dynsized", issue = "0")] +#[lang = "dynsized"] +#[rustc_on_unimplemented = "`{Self}` does not have a size known at run-time"] +#[fundamental] +pub trait DynSized: ?DynSized { + // Empty. +} + +#[cfg(stage0)] +use self::Sized as DynSized; // This is just so we don't have to stage too much stuff + /// Types that can be "unsized" to a dynamically-sized type. /// /// For example, the sized array type `[i8; 2]` implements `Unsize<[i8]>` and @@ -343,6 +376,16 @@ pub trait Copy : Clone { /// [transmute]: ../../std/mem/fn.transmute.html #[stable(feature = "rust1", since = "1.0.0")] #[lang = "sync"] +#[cfg(not(stage0))] +#[rustc_on_unimplemented = "`{Self}` cannot be shared between threads safely"] +pub unsafe trait Sync: ?DynSized { + // Empty +} + +/// docs +#[stable(feature = "rust1", since = "1.0.0")] +#[lang = "sync"] +#[cfg(stage0)] #[rustc_on_unimplemented = "`{Self}` cannot be shared between threads safely"] pub unsafe trait Sync { // Empty @@ -352,56 +395,56 @@ pub unsafe trait Sync { unsafe impl Sync for .. { } #[stable(feature = "rust1", since = "1.0.0")] -impl !Sync for *const T { } +impl !Sync for *const T { } #[stable(feature = "rust1", since = "1.0.0")] -impl !Sync for *mut T { } +impl !Sync for *mut T { } macro_rules! impls{ ($t: ident) => ( #[stable(feature = "rust1", since = "1.0.0")] - impl Hash for $t { + impl Hash for $t { #[inline] fn hash(&self, _: &mut H) { } } #[stable(feature = "rust1", since = "1.0.0")] - impl cmp::PartialEq for $t { + impl cmp::PartialEq for $t { fn eq(&self, _other: &$t) -> bool { true } } #[stable(feature = "rust1", since = "1.0.0")] - impl cmp::Eq for $t { + impl cmp::Eq for $t { } #[stable(feature = "rust1", since = "1.0.0")] - impl cmp::PartialOrd for $t { + impl cmp::PartialOrd for $t { fn partial_cmp(&self, _other: &$t) -> Option { Option::Some(cmp::Ordering::Equal) } } #[stable(feature = "rust1", since = "1.0.0")] - impl cmp::Ord for $t { + impl cmp::Ord for $t { fn cmp(&self, _other: &$t) -> cmp::Ordering { cmp::Ordering::Equal } } #[stable(feature = "rust1", since = "1.0.0")] - impl Copy for $t { } + impl Copy for $t { } #[stable(feature = "rust1", since = "1.0.0")] - impl Clone for $t { + impl Clone for $t { fn clone(&self) -> $t { $t } } #[stable(feature = "rust1", since = "1.0.0")] - impl Default for $t { + impl Default for $t { fn default() -> $t { $t } @@ -544,29 +587,33 @@ macro_rules! impls{ /// [drop check]: ../../nomicon/dropck.html #[lang = "phantom_data"] #[stable(feature = "rust1", since = "1.0.0")] -pub struct PhantomData; +pub struct PhantomData; impls! { PhantomData } -mod impls { - #[stable(feature = "rust1", since = "1.0.0")] - unsafe impl<'a, T: Sync + ?Sized> Send for &'a T {} - #[stable(feature = "rust1", since = "1.0.0")] - unsafe impl<'a, T: Send + ?Sized> Send for &'a mut T {} -} +#[stable(feature = "rust1", since = "1.0.0")] +unsafe impl<'a, T: Sync + ?DynSized> Send for &'a T {} +#[stable(feature = "rust1", since = "1.0.0")] +unsafe impl<'a, T: Send + ?DynSized> Send for &'a mut T {} /// Compiler-internal trait used to determine whether a type contains /// any `UnsafeCell` internally, but not through an indirection. /// This affects, for example, whether a `static` of that type is /// placed in read-only static memory or writable static memory. #[lang = "freeze"] +#[cfg(not(stage0))] +unsafe trait Freeze: ?DynSized {} + +/// docs +#[lang = "freeze"] +#[cfg(stage0)] unsafe trait Freeze {} unsafe impl Freeze for .. {} -impl !Freeze for UnsafeCell {} -unsafe impl Freeze for PhantomData {} -unsafe impl Freeze for *const T {} -unsafe impl Freeze for *mut T {} -unsafe impl<'a, T: ?Sized> Freeze for &'a T {} -unsafe impl<'a, T: ?Sized> Freeze for &'a mut T {} +impl !Freeze for UnsafeCell {} +unsafe impl Freeze for PhantomData {} +unsafe impl Freeze for *const T {} +unsafe impl Freeze for *mut T {} +unsafe impl<'a, T: ?DynSized> Freeze for &'a T {} +unsafe impl<'a, T: ?DynSized> Freeze for &'a mut T {} diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 4d7d151ca8983..60ff90de77bfa 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -58,7 +58,7 @@ pub use intrinsics::write_bytes; #[stable(feature = "drop_in_place", since = "1.8.0")] #[lang="drop_in_place"] #[allow(unconditional_recursion)] -pub unsafe fn drop_in_place(to_drop: *mut T) { +pub unsafe fn drop_in_place(to_drop: *mut T) { // Code here does not matter - this is replaced by the // real drop glue by the compiler. drop_in_place(to_drop); diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index 7a78765365db0..b14543afa8e5a 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -477,6 +477,7 @@ define_dep_nodes!( <'tcx> [] IsForeignItem(DefId), [] TypeParamPredicates { item_id: DefId, param_id: DefId }, [] SizedConstraint(DefId), + [] DynSizedConstraint(DefId), [] DtorckConstraint(DefId), [] AdtDestructor(DefId), [] AssociatedItemDefIds(DefId), @@ -492,6 +493,7 @@ define_dep_nodes!( <'tcx> [anon] IsCopy, [anon] IsSized, + [anon] IsDynSized, [anon] IsFreeze, [anon] NeedsDrop, [anon] Layout, diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 1e90aa47267ff..a047ce5357984 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -59,7 +59,7 @@ #![cfg_attr(stage0, feature(const_fn))] #![cfg_attr(not(stage0), feature(const_atomic_bool_new))] -#![recursion_limit="256"] +#![recursion_limit="512"] extern crate arena; #[macro_use] extern crate bitflags; diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs index 679c4f17a6c03..28f4a3fbbb182 100644 --- a/src/librustc/middle/lang_items.rs +++ b/src/librustc/middle/lang_items.rs @@ -230,6 +230,7 @@ language_item_table! { SendTraitLangItem, "send", send_trait; SizedTraitLangItem, "sized", sized_trait; + DynSizedTraitLangItem, "dynsized", dynsized_trait; UnsizeTraitLangItem, "unsize", unsize_trait; CopyTraitLangItem, "copy", copy_trait; CloneTraitLangItem, "clone", clone_trait; diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 5e9b853895588..8e26065d66b7a 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -1125,6 +1125,9 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { ObligationCauseCode::StructInitializerSized => { err.note("structs must have a statically known size to be initialized"); } + ObligationCauseCode::FieldDynSized => { + err.note("the last field of a struct or tuple must have a dynamically sized type"); + } ObligationCauseCode::FieldSized(ref item) => { match *item { AdtKind::Struct => { diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index a1817f181066c..1f14e999a9edd 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -137,6 +137,9 @@ pub enum ObligationCauseCode<'tcx> { /// Types of fields (other than the last) in a struct must be sized. FieldSized(AdtKind), + /// Last field of a struct must be DynSized. + FieldDynSized, + /// Constant expressions must be sized. ConstSized, diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 2ecb82b77d34c..646926a98bf51 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -1348,6 +1348,12 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { let sized_conditions = self.sized_conditions(obligation); self.assemble_builtin_bound_candidates(sized_conditions, &mut candidates)?; + } else if lang_items.dynsized_trait() == Some(def_id) { + // DynSized is never implementable by end-users, it is + // always automatically computed. + let dynsized_conditions = self.dynsized_conditions(obligation); + self.assemble_builtin_bound_candidates(dynsized_conditions, + &mut candidates)?; } else if lang_items.unsize_trait() == Some(def_id) { self.assemble_candidates_for_unsizing(obligation, &mut candidates); } else { @@ -2056,6 +2062,53 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { } } + fn dynsized_conditions(&mut self, obligation: &TraitObligation<'tcx>) + -> BuiltinImplConditions<'tcx> + { + use self::BuiltinImplConditions::{Ambiguous, None, Never, Where}; + + // NOTE: binder moved to (*) + let self_ty = self.infcx.shallow_resolve( + obligation.predicate.skip_binder().self_ty()); + + match self_ty.sty { + ty::TyInfer(ty::IntVar(_)) | ty::TyInfer(ty::FloatVar(_)) | + ty::TyUint(_) | ty::TyInt(_) | ty::TyBool | ty::TyFloat(_) | + ty::TyFnDef(..) | ty::TyFnPtr(_) | ty::TyRawPtr(..) | + ty::TyChar | ty::TyRef(..) | ty::TyGenerator(..) | + ty::TyArray(..) | ty::TyClosure(..) | ty::TyNever | + ty::TyStr | ty::TySlice(_) | ty::TyDynamic(..) | + ty::TyError => { + // safe for everything + Where(ty::Binder(Vec::new())) + } + + ty::TyTuple(tys, _) => { + Where(ty::Binder(tys.last().into_iter().cloned().collect())) + } + + ty::TyAdt(def, substs) => { + let dynsized_crit = def.dynsized_constraint(self.tcx()); + // (*) binder moved here + Where(ty::Binder( + dynsized_crit.iter().map(|ty| ty.subst(self.tcx(), substs)).collect() + )) + } + + ty::TyForeign(..) => Never, + + ty::TyProjection(_) | ty::TyParam(_) | ty::TyAnon(..) => None, + ty::TyInfer(ty::TyVar(_)) => Ambiguous, + + ty::TyInfer(ty::FreshTy(_)) + | ty::TyInfer(ty::FreshIntTy(_)) + | ty::TyInfer(ty::FreshFloatTy(_)) => { + bug!("asked to assemble builtin bounds of unexpected type: {:?}", + self_ty); + } + } + } + fn copy_clone_conditions(&mut self, obligation: &TraitObligation<'tcx>) -> BuiltinImplConditions<'tcx> { @@ -2392,6 +2445,9 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { _ if Some(trait_def) == lang_items.sized_trait() => { self.sized_conditions(obligation) } + _ if Some(trait_def) == lang_items.dynsized_trait() => { + self.dynsized_conditions(obligation) + } _ if Some(trait_def) == lang_items.copy_trait() => { self.copy_clone_conditions(obligation) } diff --git a/src/librustc/traits/structural_impls.rs b/src/librustc/traits/structural_impls.rs index 19ed03aa14917..e659dee19364e 100644 --- a/src/librustc/traits/structural_impls.rs +++ b/src/librustc/traits/structural_impls.rs @@ -211,6 +211,7 @@ impl<'a, 'tcx> Lift<'tcx> for traits::ObligationCauseCode<'a> { super::SizedReturnType => Some(super::SizedReturnType), super::RepeatVec => Some(super::RepeatVec), super::FieldSized(item) => Some(super::FieldSized(item)), + super::FieldDynSized => Some(super::FieldDynSized), super::ConstSized => Some(super::ConstSized), super::SharedStatic => Some(super::SharedStatic), super::BuiltinDerivedObligation(ref cause) => { @@ -531,6 +532,7 @@ impl<'tcx> TypeFoldable<'tcx> for traits::ObligationCauseCode<'tcx> { super::ReturnNoExpression | super::RepeatVec | super::FieldSized(_) | + super::FieldDynSized | super::ConstSized | super::SharedStatic | super::BlockTailExpression(_) | @@ -579,6 +581,7 @@ impl<'tcx> TypeFoldable<'tcx> for traits::ObligationCauseCode<'tcx> { super::ReturnNoExpression | super::RepeatVec | super::FieldSized(_) | + super::FieldDynSized | super::ConstSized | super::SharedStatic | super::BlockTailExpression(_) | diff --git a/src/librustc/ty/maps/config.rs b/src/librustc/ty/maps/config.rs index c8520c5be2df5..e759430bda0da 100644 --- a/src/librustc/ty/maps/config.rs +++ b/src/librustc/ty/maps/config.rs @@ -45,6 +45,12 @@ impl<'tcx> QueryDescription for queries::is_sized_raw<'tcx> { } } +impl<'tcx> QueryDescription for queries::is_dynsized_raw<'tcx> { + fn describe(_tcx: TyCtxt, env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> String { + format!("computing whether `{}` is `DynSized`", env.value) + } +} + impl<'tcx> QueryDescription for queries::is_freeze_raw<'tcx> { fn describe(_tcx: TyCtxt, env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> String { format!("computing whether `{}` is freeze", env.value) diff --git a/src/librustc/ty/maps/mod.rs b/src/librustc/ty/maps/mod.rs index 4bd2d5be6d716..9847c94e19152 100644 --- a/src/librustc/ty/maps/mod.rs +++ b/src/librustc/ty/maps/mod.rs @@ -100,6 +100,7 @@ define_maps! { <'tcx> [] fn adt_def: AdtDefOfItem(DefId) -> &'tcx ty::AdtDef, [] fn adt_destructor: AdtDestructor(DefId) -> Option, [] fn adt_sized_constraint: SizedConstraint(DefId) -> &'tcx [Ty<'tcx>], + [] fn adt_dynsized_constraint: DynSizedConstraint(DefId) -> &'tcx [Ty<'tcx>], [] fn adt_dtorck_constraint: DtorckConstraint(DefId) -> ty::DtorckConstraint<'tcx>, /// True if this is a const fn @@ -244,6 +245,7 @@ define_maps! { <'tcx> // `ty.is_copy()`, etc, since that will prune the environment where possible. [] fn is_copy_raw: is_copy_dep_node(ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool, [] fn is_sized_raw: is_sized_dep_node(ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool, + [] fn is_dynsized_raw: is_dynsized_dep_node(ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool, [] fn is_freeze_raw: is_freeze_dep_node(ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool, [] fn needs_drop_raw: needs_drop_dep_node(ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool, [] fn layout_raw: layout_dep_node(ty::ParamEnvAnd<'tcx, Ty<'tcx>>) @@ -398,6 +400,10 @@ fn is_sized_dep_node<'tcx>(_: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> DepConstructor DepConstructor::IsSized } +fn is_dynsized_dep_node<'tcx>(_: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> DepConstructor<'tcx> { + DepConstructor::IsDynSized +} + fn is_freeze_dep_node<'tcx>(_: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> DepConstructor<'tcx> { DepConstructor::IsFreeze } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index cdc5e1c404411..d5b436e8c5844 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -1713,6 +1713,18 @@ impl<'a, 'gcx, 'tcx> AdtDef { } } + /// Same as `sized_constraint`, but for DynSized + pub fn dynsized_constraint(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> &'tcx [Ty<'tcx>] { + match queries::adt_dynsized_constraint::try_get(tcx, DUMMY_SP, self.did) { + Ok(tys) => tys, + Err(mut bug) => { + debug!("adt_dynsized_constraint: {:?} is recursive", self); + bug.delay_as_bug(); + tcx.intern_type_list(&[tcx.types.err]) + } + } + } + fn sized_constraint_for_ty(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, ty: Ty<'tcx>) @@ -1782,6 +1794,74 @@ impl<'a, 'gcx, 'tcx> AdtDef { debug!("sized_constraint_for_ty({:?}) = {:?}", ty, result); result } + + fn dynsized_constraint_for_ty(&self, + tcx: TyCtxt<'a, 'tcx, 'tcx>, + ty: Ty<'tcx>) + -> Vec> { + let result = match ty.sty { + TyBool | TyChar | TyInt(..) | TyUint(..) | TyFloat(..) | + TyRawPtr(..) | TyRef(..) | TyFnDef(..) | TyFnPtr(_) | + TyStr | TyDynamic(..) | TySlice(_) | TyArray(..) | + TyTuple(..) | TyAdt(..) | TyClosure(..) | TyGenerator(..) | + TyNever => { + vec![] + } + + TyForeign(..) | TyError => { + // these are never DynSized - return the target type + vec![ty] + } + + TyProjection(..) | TyAnon(..) => { + // must calculate explicitly. + // FIXME: consider special-casing always-DynSized projections + vec![ty] + } + + TyParam(..) => { + // perf hack: if there is a `T: Sized` or `T: DynSized` bound, then + // we know that `T` is DynSized and do not need to check + // it on the impl. + + let sized_trait = match tcx.lang_items().sized_trait() { + Some(x) => x, + _ => return vec![ty] + }; + + let dynsized_trait = match tcx.lang_items().dynsized_trait() { + Some(x) => x, + _ => return vec![ty] + }; + + let sized_predicate = Binder(TraitRef { + def_id: sized_trait, + substs: tcx.mk_substs_trait(ty, &[]) + }).to_predicate(); + + let dynsized_predicate = Binder(TraitRef { + def_id: dynsized_trait, + substs: tcx.mk_substs_trait(ty, &[]) + }).to_predicate(); + + let predicates = tcx.predicates_of(self.did).predicates; + if predicates.into_iter().any(|p| { + p == sized_predicate || p == dynsized_predicate + }) { + vec![] + } else { + vec![ty] + } + } + + TyInfer(..) => { + bug!("unexpected type `{:?}` in dynsized_constraint_for_ty", + ty) + } + }; + debug!("dynsized_constraint_for_ty({:?}) = {:?}", ty, result); + result + } } impl<'a, 'gcx, 'tcx> VariantDef { @@ -2371,6 +2451,22 @@ fn adt_sized_constraint<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, result } +fn adt_dynsized_constraint<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + def_id: DefId) + -> &'tcx [Ty<'tcx>] { + let def = tcx.adt_def(def_id); + + let result = tcx.intern_type_list(&def.variants.iter().flat_map(|v| { + v.fields.last() + }).flat_map(|f| { + def.dynsized_constraint_for_ty(tcx, tcx.type_of(f.did)) + }).collect::>()); + + debug!("adt_dynsized_constraint: {:?} => {:?}", def, result); + + result +} + /// Calculates the dtorck constraint for a type. fn adt_dtorck_constraint<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) @@ -2493,6 +2589,7 @@ pub fn provide(providers: &mut ty::maps::Providers) { associated_item, associated_item_def_ids, adt_sized_constraint, + adt_dynsized_constraint, adt_dtorck_constraint, def_span, param_env, @@ -2507,6 +2604,7 @@ pub fn provide(providers: &mut ty::maps::Providers) { pub fn provide_extern(providers: &mut ty::maps::Providers) { *providers = ty::maps::Providers { adt_sized_constraint, + adt_dynsized_constraint, adt_dtorck_constraint, trait_impls_of: trait_def::trait_impls_of_provider, param_env, diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index 1675c3f5a8319..c0f81b0c1a9bc 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -799,11 +799,19 @@ impl<'a, 'tcx> ty::TyS<'tcx> { pub fn is_sized(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>, param_env: ty::ParamEnv<'tcx>, - span: Span)-> bool + span: Span) -> bool { tcx.at(span).is_sized_raw(param_env.and(self)) } + pub fn is_dynsized(&'tcx self, + tcx: TyCtxt<'a, 'tcx, 'tcx>, + param_env: ty::ParamEnv<'tcx>, + span: Span) -> bool + { + tcx.at(span).is_dynsized_raw(param_env.and(self)) + } + pub fn is_freeze(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>, param_env: ty::ParamEnv<'tcx>, @@ -1064,6 +1072,20 @@ fn is_sized_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, DUMMY_SP)) } +fn is_dynsized_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) + -> bool +{ + let (param_env, ty) = query.into_parts(); + let trait_def_id = tcx.require_lang_item(lang_items::DynSizedTraitLangItem); + tcx.infer_ctxt() + .enter(|infcx| traits::type_known_to_meet_bound(&infcx, + param_env, + ty, + trait_def_id, + DUMMY_SP)) +} + fn is_freeze_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool @@ -1182,6 +1204,7 @@ pub fn provide(providers: &mut ty::maps::Providers) { *providers = ty::maps::Providers { is_copy_raw, is_sized_raw, + is_dynsized_raw, is_freeze_raw, needs_drop_raw, layout_raw, diff --git a/src/librustc/ty/wf.rs b/src/librustc/ty/wf.rs index c631e2c4db51b..9ce0dbdca44d7 100644 --- a/src/librustc/ty/wf.rs +++ b/src/librustc/ty/wf.rs @@ -267,6 +267,17 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> { } } + fn require_dynsized(&mut self, subty: Ty<'tcx>, cause: traits::ObligationCauseCode<'tcx>) { + if !subty.has_escaping_regions() { + let cause = self.cause(cause); + let trait_ref = ty::TraitRef { + def_id: self.infcx.tcx.require_lang_item(lang_items::DynSizedTraitLangItem), + substs: self.infcx.tcx.mk_substs_trait(subty, &[]), + }; + self.out.push(traits::Obligation::new(cause, self.param_env, trait_ref.to_predicate())); + } + } + /// Push new obligations into `out`. Returns true if it was able /// to generate all the predicates needed to validate that `ty0` /// is WF. Returns false if `ty0` is an unresolved type variable, @@ -300,10 +311,11 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> { } ty::TyTuple(ref tys, _) => { - if let Some((_last, rest)) = tys.split_last() { + if let Some((last, rest)) = tys.split_last() { for elem in rest { self.require_sized(elem, traits::TupleElem); } + self.require_dynsized(last, traits::FieldDynSized); } } diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 4c6b7d3e5b343..4fd988839701e 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -811,20 +811,26 @@ impl<'tcx> fmt::Display for ty::TypeVariants<'tcx> { let mut first = true; let mut is_sized = false; + let mut is_dynsized = false; write!(f, "impl")?; for predicate in bounds.predicates { if let Some(trait_ref) = predicate.to_opt_poly_trait_ref() { - // Don't print +Sized, but rather +?Sized if absent. + // Don't print +Sized/DynSized, but rather +?Sized/DynSized if absent. if Some(trait_ref.def_id()) == tcx.lang_items().sized_trait() { is_sized = true; continue; + } else if Some(trait_ref.def_id()) == tcx.lang_items().dynsized_trait() { + is_dynsized = true; + continue; } write!(f, "{}{}", if first { " " } else { "+" }, trait_ref)?; first = false; } } - if !is_sized { + if !is_dynsized { + write!(f, "{}?DynSized", if first { " " } else { "+" })?; + } else if !is_sized { write!(f, "{}?Sized", if first { " " } else { "+" })?; } Ok(()) diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs index d2e8b87269e20..0e6be49a7cd97 100644 --- a/src/librustc_passes/ast_validation.rs +++ b/src/librustc_passes/ast_validation.rs @@ -81,19 +81,6 @@ impl<'a> AstValidator<'a> { } } - fn no_questions_in_bounds(&self, bounds: &TyParamBounds, where_: &str, is_trait: bool) { - for bound in bounds { - if let TraitTyParamBound(ref poly, TraitBoundModifier::Maybe) = *bound { - let mut err = self.err_handler().struct_span_err(poly.span, - &format!("`?Trait` is not permitted in {}", where_)); - if is_trait { - err.note(&format!("traits are `?{}` by default", poly.trait_ref.path)); - } - err.emit(); - } - } - } - /// matches '-' lit | lit (cf. parser::Parser::parse_pat_literal_maybe_minus), /// or path for ranges. /// @@ -155,16 +142,21 @@ impl<'a> Visitor<'a> for AstValidator<'a> { TyKind::TraitObject(ref bounds) => { let mut any_lifetime_bounds = false; for bound in bounds { - if let RegionTyParamBound(ref lifetime) = *bound { - if any_lifetime_bounds { - span_err!(self.session, lifetime.span, E0226, - "only a single explicit lifetime bound is permitted"); - break; + match *bound { + RegionTyParamBound(ref lifetime) => { + if any_lifetime_bounds { + span_err!(self.session, lifetime.span, E0226, + "only a single explicit lifetime bound is permitted"); + break; + } + any_lifetime_bounds = true; + } + TraitTyParamBound(ref poly, TraitBoundModifier::Maybe) => { + self.session.span_err(poly.span, "`?Trait` is not permitted in trait object types"); } - any_lifetime_bounds = true; + _ => (), } } - self.no_questions_in_bounds(bounds, "trait object types", false); } TyKind::ImplTrait(ref bounds) => { if !bounds.iter() @@ -229,8 +221,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } } } - ItemKind::Trait(.., ref bounds, ref trait_items) => { - self.no_questions_in_bounds(bounds, "supertraits", true); + ItemKind::Trait(.., ref trait_items) => { for trait_item in trait_items { if let TraitItemKind::Method(ref sig, ref block) = trait_item.node { self.check_trait_fn_not_const(sig.constness); diff --git a/src/librustc_trans/common.rs b/src/librustc_trans/common.rs index 8b1976c49a665..e907a120696fa 100644 --- a/src/librustc_trans/common.rs +++ b/src/librustc_trans/common.rs @@ -149,6 +149,10 @@ 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_is_dynsized<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty: Ty<'tcx>) -> bool { + ty.is_dynsized(tcx, ty::ParamEnv::empty(traits::Reveal::All), DUMMY_SP) +} + pub fn type_is_freeze<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty: Ty<'tcx>) -> bool { ty.is_freeze(tcx, ty::ParamEnv::empty(traits::Reveal::All), DUMMY_SP) } diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index b03bc46b6f5fd..c54bab74582a4 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -297,6 +297,10 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> { common::type_is_sized(self.tcx, ty) } + pub fn type_is_dynsized(&self, ty: Ty<'tcx>) -> bool { + common::type_is_dynsized(self.tcx, ty) + } + pub fn type_is_freeze(&self, ty: Ty<'tcx>) -> bool { common::type_is_freeze(self.tcx, ty) } diff --git a/src/librustc_trans/intrinsic.rs b/src/librustc_trans/intrinsic.rs index e80239175681e..f84d8f672a01f 100644 --- a/src/librustc_trans/intrinsic.rs +++ b/src/librustc_trans/intrinsic.rs @@ -142,12 +142,12 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, 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) { + } else if bcx.ccx.shared().type_is_dynsized(tp_ty) { let (llsize, _) = glue::size_and_align_of_dst(bcx, tp_ty, llargs[1]); llsize } else { - C_usize(ccx, 0u64) + bug!("trying to get size of !DynSized type") } } "min_align_of" => { @@ -158,12 +158,12 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, let tp_ty = substs.type_at(0); 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) { + } else if bcx.ccx.shared().type_is_dynsized(tp_ty) { let (_, llalign) = glue::size_and_align_of_dst(bcx, tp_ty, llargs[1]); llalign } else { - C_usize(ccx, 1u64) + bug!("trying to get alignment of !DynSized type") } } "pref_align_of" => { diff --git a/src/librustc_trans/mir/lvalue.rs b/src/librustc_trans/mir/lvalue.rs index d939acaccd99c..8194e4f5ef8df 100644 --- a/src/librustc_trans/mir/lvalue.rs +++ b/src/librustc_trans/mir/lvalue.rs @@ -153,21 +153,16 @@ impl<'a, 'tcx> LvalueRef<'tcx> { ptr_val, adt::struct_llfields_index(st, ix)), alignment); } - // If the type of the last field is [T], str or a foreign type, then we don't need to do - // any adjusments + // If the type of the last field is [T] or str, then we don't need to do + // any adjusments. Otherwise it must a trait object. match fty.sty { - ty::TySlice(..) | ty::TyStr | ty::TyForeign(..) => { + ty::TySlice(..) | ty::TyStr => { return (bcx.struct_gep( ptr_val, adt::struct_llfields_index(st, ix)), alignment); } - _ => () - } - // There's no metadata available, log the case and just do the GEP. - if !self.has_extra() { - debug!("Unsized field `{}`, of `{:?}` has no metadata for adjustment", - ix, Value(ptr_val)); - return (bcx.struct_gep(ptr_val, adt::struct_llfields_index(st, ix)), alignment); + ty::TyDynamic(..) => (), + _ => bug!("unexpected DST tail: {:?}", fty.sty), } // We need to get the pointer manually now. diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 58a09d5aa65ee..a5741358bbe73 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -1428,6 +1428,7 @@ fn report_lifetime_number_error(tcx: TyCtxt, span: Span, number: usize, expected pub struct Bounds<'tcx> { pub region_bounds: Vec>, pub implicitly_sized: bool, + pub implicitly_dynsized: bool, pub trait_bounds: Vec>, pub projection_bounds: Vec>, } @@ -1449,6 +1450,16 @@ impl<'a, 'gcx, 'tcx> Bounds<'tcx> { } } + if self.implicitly_dynsized { + if let Some(dynsized) = tcx.lang_items().dynsized_trait() { + let trait_ref = ty::TraitRef { + def_id: dynsized, + substs: tcx.mk_substs_trait(param_ty, &[]) + }; + vec.push(trait_ref.to_predicate()); + } + } + for ®ion_bound in &self.region_bounds { // account for the binder being introduced below; no need to shift `param_ty` // because, at present at least, it can only refer to early-bound regions diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index ddbdd20430589..f6f387aa09a8d 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -239,6 +239,17 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> { }))); } + // Last field must be DynSized. + if !all_sized && !variant.fields.is_empty() { + let field = &variant.fields[variant.fields.len() - 1]; + fcx.register_bound( + field.ty, + fcx.tcx.require_lang_item(lang_items::DynSizedTraitLangItem), + traits::ObligationCause::new(field.span, + fcx.body_id, + traits::FieldDynSized)); + } + // All field types must be well-formed. for field in &variant.fields { fcx.register_wf_obligation(field.ty, field.span, this.code.clone()) diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index 6109fc57b0dfc..e074f85f5a4fb 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -53,7 +53,7 @@ fn enforce_trait_manually_implementable(tcx: TyCtxt, impl_def_id: DefId, trait_d let did = Some(trait_def_id); let li = tcx.lang_items(); - // Disallow *all* explicit impls of `Sized` and `Unsize` for now. + // Disallow *all* explicit impls of `Sized`, `DynSized` and `Unsize` for now. if did == li.sized_trait() { let span = tcx.span_of_impl(impl_def_id).unwrap(); struct_span_err!(tcx.sess, @@ -65,6 +65,14 @@ fn enforce_trait_manually_implementable(tcx: TyCtxt, impl_def_id: DefId, trait_d return; } + if did == li.dynsized_trait() { + let span = tcx.span_of_impl(impl_def_id).unwrap(); + tcx.sess.struct_span_err(span, "explicit impls for the `DynSized` trait are not permitted") + .span_label(span, "impl of 'DynSized' not allowed") + .emit(); + return; + } + if did == li.unsize_trait() { let span = tcx.span_of_impl(impl_def_id).unwrap(); span_err!(tcx.sess, diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 688f50777dd40..e7b2af025f27d 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -27,7 +27,7 @@ use astconv::{AstConv, Bounds}; use lint; use constrained_type_params as ctp; -use middle::lang_items::SizedTraitLangItem; +use middle::lang_items::{DynSizedTraitLangItem, SizedTraitLangItem}; use middle::const_val::ConstVal; use middle::resolve_lifetime as rl; use rustc::traits::Reveal; @@ -1265,10 +1265,35 @@ fn impl_polarity<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } } -// Is it marked with ?Sized -fn is_unsized<'gcx: 'tcx, 'tcx>(astconv: &AstConv<'gcx, 'tcx>, - ast_bounds: &[hir::TyParamBound], - span: Span) -> bool +// Implicit sizing constraint in bounds. +// This only takes into account defaults and ?Trait bounds, +// not positive bounds such as trait Tr: Sized { } +enum ImplicitSizing { + Sized, + DynSized, + None, +} + +impl ImplicitSizing { + fn implicitly_sized(&self) -> bool { + match *self { + ImplicitSizing::Sized => true, + ImplicitSizing::DynSized | ImplicitSizing::None => false, + } + } + + fn implicitly_dynsized(&self) -> bool { + match *self { + ImplicitSizing::Sized | ImplicitSizing::DynSized => true, + ImplicitSizing::None => false, + } + } +} + +fn find_implicit_sizing<'gcx: 'tcx, 'tcx>(astconv: &AstConv<'gcx, 'tcx>, + ast_bounds: &[hir::TyParamBound], + span: Span, + sized_by_default: SizedByDefault) -> ImplicitSizing { let tcx = astconv.tcx(); @@ -1286,27 +1311,36 @@ fn is_unsized<'gcx: 'tcx, 'tcx>(astconv: &AstConv<'gcx, 'tcx>, } } - let kind_id = tcx.lang_items().require(SizedTraitLangItem); - match unbound { - Some(ref tpb) => { - // FIXME(#8559) currently requires the unbound to be built-in. - if let Ok(kind_id) = kind_id { - if tpb.path.def != Def::Trait(kind_id) { - tcx.sess.span_warn(span, - "default bound relaxed for a type parameter, but \ - this does nothing because the given bound is not \ - a default. Only `?Sized` is supported"); - } + let sized_trait = tcx.lang_items().require(SizedTraitLangItem).map(Def::Trait); + let dynsized_trait = tcx.lang_items().require(DynSizedTraitLangItem).map(Def::Trait); + + let mut sizing = match sized_by_default { + SizedByDefault::Yes => ImplicitSizing::Sized, + SizedByDefault::No => ImplicitSizing::DynSized, + }; + + if let Some(ref tpb) = unbound { + if Ok(tpb.path.def) == sized_trait { + if sized_by_default == SizedByDefault::No { + let mut err = tcx.sess.struct_span_err(span, + "`?Sized` is not permitted in supertraits"); + + err.note("traits are `?Sized` by default"); + err.emit(); } + + sizing = ImplicitSizing::DynSized; + } else if Ok(tpb.path.def) == dynsized_trait { + sizing = ImplicitSizing::None; + } else { + tcx.sess.span_warn(span, + "default bound relaxed for a type parameter, but \ + this does nothing because the given bound is not \ + a default. Only `?Sized` and `?DynSized` are supported"); } - _ if kind_id.is_ok() => { - return false; - } - // No lang item for Sized, so we can't add it as a bound. - None => {} } - true + sizing } /// Returns the early-bound lifetimes declared in this generics @@ -1552,17 +1586,17 @@ fn predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } } -pub enum SizedByDefault { Yes, No, } +#[derive(PartialEq, Eq)] +enum SizedByDefault { Yes, No } /// Translate the AST's notion of ty param bounds (which are an enum consisting of a newtyped Ty or /// a region) to ty's notion of ty param bounds, which can either be user-defined traits, or the /// built-in trait (formerly known as kind): Send. -pub fn compute_bounds<'gcx: 'tcx, 'tcx>(astconv: &AstConv<'gcx, 'tcx>, - param_ty: Ty<'tcx>, - ast_bounds: &[hir::TyParamBound], - sized_by_default: SizedByDefault, - span: Span) - -> Bounds<'tcx> +fn compute_bounds<'gcx: 'tcx, 'tcx>(astconv: &AstConv<'gcx, 'tcx>, + param_ty: Ty<'tcx>, + ast_bounds: &[hir::TyParamBound], + sized_by_default: SizedByDefault, + span: Span) -> Bounds<'tcx> { let mut region_bounds = vec![]; let mut trait_bounds = vec![]; @@ -1592,15 +1626,12 @@ pub fn compute_bounds<'gcx: 'tcx, 'tcx>(astconv: &AstConv<'gcx, 'tcx>, trait_bounds.sort_by(|a,b| a.def_id().cmp(&b.def_id())); - let implicitly_sized = if let SizedByDefault::Yes = sized_by_default { - !is_unsized(astconv, ast_bounds, span) - } else { - false - }; + let sizing = find_implicit_sizing(astconv, ast_bounds, span, sized_by_default); Bounds { region_bounds, - implicitly_sized, + implicitly_sized: sizing.implicitly_sized(), + implicitly_dynsized: sizing.implicitly_dynsized(), trait_bounds, projection_bounds, } diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 9fc7e2c01aa19..1d03f73e0de51 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -256,6 +256,7 @@ #![feature(core_float)] #![feature(core_intrinsics)] #![feature(dropck_eyepatch)] +#![feature(dynsized)] #![feature(exact_size_is_empty)] #![feature(float_from_str_radix)] #![feature(fn_traits)] diff --git a/src/libstd/panic.rs b/src/libstd/panic.rs index 97b09b7e2ad99..74228c0c2df3c 100644 --- a/src/libstd/panic.rs +++ b/src/libstd/panic.rs @@ -22,6 +22,12 @@ use rc::Rc; use sync::{Arc, Mutex, RwLock, atomic}; use thread::Result; +#[cfg(stage0)] +use core::marker::Sized as DynSized; + +#[cfg(not(stage0))] +use core::marker::DynSized; + #[stable(feature = "panic_hooks", since = "1.10.0")] pub use panicking::{take_hook, set_hook, PanicInfo, Location}; @@ -101,6 +107,14 @@ pub use panicking::{take_hook, set_hook, PanicInfo, Location}; #[stable(feature = "catch_unwind", since = "1.9.0")] #[rustc_on_unimplemented = "the type {Self} may not be safely transferred \ across an unwind boundary"] +#[cfg(not(stage0))] +pub trait UnwindSafe: ?DynSized {} + +/// docs +#[stable(feature = "catch_unwind", since = "1.9.0")] +#[rustc_on_unimplemented = "the type {Self} may not be safely transferred \ + across an unwind boundary"] +#[cfg(stage0)] pub trait UnwindSafe {} /// A marker trait representing types where a shared reference is considered @@ -115,6 +129,15 @@ pub trait UnwindSafe {} #[rustc_on_unimplemented = "the type {Self} may contain interior mutability \ and a reference may not be safely transferrable \ across a catch_unwind boundary"] +#[cfg(not(stage0))] +pub trait RefUnwindSafe: ?DynSized {} + +/// docs +#[stable(feature = "catch_unwind", since = "1.9.0")] +#[rustc_on_unimplemented = "the type {Self} may contain interior mutability \ + and a reference may not be safely transferrable \ + across a catch_unwind boundary"] +#[cfg(stage0)] pub trait RefUnwindSafe {} /// A simple wrapper around a type to assert that it is unwind safe. @@ -190,13 +213,13 @@ pub struct AssertUnwindSafe( #[stable(feature = "catch_unwind", since = "1.9.0")] impl UnwindSafe for .. {} #[stable(feature = "catch_unwind", since = "1.9.0")] -impl<'a, T: ?Sized> !UnwindSafe for &'a mut T {} +impl<'a, T: ?DynSized> !UnwindSafe for &'a mut T {} #[stable(feature = "catch_unwind", since = "1.9.0")] -impl<'a, T: RefUnwindSafe + ?Sized> UnwindSafe for &'a T {} +impl<'a, T: RefUnwindSafe + ?DynSized> UnwindSafe for &'a T {} #[stable(feature = "catch_unwind", since = "1.9.0")] -impl UnwindSafe for *const T {} +impl UnwindSafe for *const T {} #[stable(feature = "catch_unwind", since = "1.9.0")] -impl UnwindSafe for *mut T {} +impl UnwindSafe for *mut T {} #[unstable(feature = "unique", issue = "27730")] impl UnwindSafe for Unique {} #[unstable(feature = "shared", issue = "27730")] From 2d3e2b575d5a2bec4129b5b57553426acd3cea12 Mon Sep 17 00:00:00 2001 From: Paul Lietar Date: Fri, 8 Sep 2017 19:55:10 +0200 Subject: [PATCH 4/7] Make <*const T>::is_null() and al work with T: ?DynSized. --- src/libcore/ptr.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 60ff90de77bfa..3e108c93c194d 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -27,6 +27,11 @@ use nonzero::NonZero; use cmp::Ordering::{self, Less, Equal, Greater}; +#[cfg(stage0)] +use marker::Sized as DynSized; +#[cfg(not(stage0))] +use marker::DynSized; + // FIXME #19649: intrinsic docs don't render, so these have no docs :( #[stable(feature = "rust1", since = "1.0.0")] @@ -473,7 +478,7 @@ pub unsafe fn write_volatile(dst: *mut T, src: T) { } #[lang = "const_ptr"] -impl *const T { +impl *const T { /// Returns `true` if the pointer is null. /// /// # Examples @@ -1105,7 +1110,7 @@ impl *const T { } #[lang = "mut_ptr"] -impl *mut T { +impl *mut T { /// Returns `true` if the pointer is null. /// /// # Examples From 1eefab4ba0d5a4c2c325bd5de988d05353a9d87e Mon Sep 17 00:00:00 2001 From: Paul Lietar Date: Fri, 8 Sep 2017 14:42:59 +0200 Subject: [PATCH 5/7] Fix tests for DynSized --- .../auxiliary/tdticc_coherence_lib.rs | 6 ++-- .../extern-types-not-sync-send.rs | 8 +++-- src/test/compile-fail/extern-types-unsized.rs | 23 +++--------- src/test/compile-fail/maybe-bounds.rs | 9 +++-- src/test/compile-fail/phantom-oibit.rs | 6 ++-- src/test/compile-fail/privacy-sanity.rs | 10 +++--- ...-default-trait-impl-constituent-types-2.rs | 6 ++-- ...ck-default-trait-impl-constituent-types.rs | 6 ++-- .../typeck-default-trait-impl-negation.rs | 8 +++-- .../typeck-default-trait-impl-precedence.rs | 6 ++-- .../run-pass/extern-types-manual-sync-send.rs | 8 +++-- .../run-pass/extern-types-pointer-cast.rs | 13 ------- src/test/run-pass/extern-types-size_of_val.rs | 26 -------------- .../run-pass/extern-types-thin-pointer.rs | 35 +++++-------------- src/test/run-pass/issue-29516.rs | 6 ++-- .../ui/on-unimplemented/multiple-impls.stderr | 26 +------------- src/test/ui/on-unimplemented/on-impl.stderr | 10 +----- 17 files changed, 66 insertions(+), 146 deletions(-) delete mode 100644 src/test/run-pass/extern-types-size_of_val.rs diff --git a/src/test/compile-fail/auxiliary/tdticc_coherence_lib.rs b/src/test/compile-fail/auxiliary/tdticc_coherence_lib.rs index 2e425ac96c55f..a2389c9b0d7fb 100644 --- a/src/test/compile-fail/auxiliary/tdticc_coherence_lib.rs +++ b/src/test/compile-fail/auxiliary/tdticc_coherence_lib.rs @@ -8,10 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(optin_builtin_traits, core)] +#![feature(dynsized, optin_builtin_traits)] #![crate_type = "rlib"] -pub trait DefaultedTrait { } +use std::marker::DynSized; + +pub trait DefaultedTrait: ?DynSized { } impl DefaultedTrait for .. { } pub struct Something { t: T } diff --git a/src/test/compile-fail/extern-types-not-sync-send.rs b/src/test/compile-fail/extern-types-not-sync-send.rs index 2f00cf812e473..4e19215f0c513 100644 --- a/src/test/compile-fail/extern-types-not-sync-send.rs +++ b/src/test/compile-fail/extern-types-not-sync-send.rs @@ -10,14 +10,16 @@ // Make sure extern types are !Sync and !Send. -#![feature(extern_types)] +#![feature(dynsized, extern_types)] + +use std::marker::DynSized; extern { type A; } -fn assert_sync() { } -fn assert_send() { } +fn assert_sync() { } +fn assert_send() { } fn main() { assert_sync::(); diff --git a/src/test/compile-fail/extern-types-unsized.rs b/src/test/compile-fail/extern-types-unsized.rs index faa27894806f8..8a8df73171645 100644 --- a/src/test/compile-fail/extern-types-unsized.rs +++ b/src/test/compile-fail/extern-types-unsized.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// Make sure extern types are !Sized. +// Make sure extern types are !Sized and !DynSized. #![feature(extern_types)] @@ -16,28 +16,13 @@ extern { type A; } -struct Foo { - x: u8, - tail: A, -} - -struct Bar { - x: u8, - tail: T, -} - fn assert_sized() { } +fn assert_dynsized() { } 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 + assert_dynsized::(); + //~^ ERROR the trait bound `A: std::marker::DynSized` is not satisfied } diff --git a/src/test/compile-fail/maybe-bounds.rs b/src/test/compile-fail/maybe-bounds.rs index b0b412bbf89ec..743d636e4d94a 100644 --- a/src/test/compile-fail/maybe-bounds.rs +++ b/src/test/compile-fail/maybe-bounds.rs @@ -8,10 +8,15 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -trait Tr: ?Sized {} //~ ERROR `?Trait` is not permitted in supertraits +#![feature(dynsized)] + +use std::marker::DynSized; + +trait Tr: ?Sized {} //~ ERROR `?Sized` is not permitted in supertraits //~^ NOTE traits are `?Sized` by default type A1 = Tr + ?Sized; //~ ERROR `?Trait` is not permitted in trait object types -type A2 = for<'a> Tr + ?Sized; //~ ERROR `?Trait` is not permitted in trait object types +type A2 = Tr + ?DynSized; //~ ERROR `?Trait` is not permitted in trait object types +type A3 = for<'a> Tr + ?Sized; //~ ERROR `?Trait` is not permitted in trait object types fn main() {} diff --git a/src/test/compile-fail/phantom-oibit.rs b/src/test/compile-fail/phantom-oibit.rs index c84927ea26639..08d4460a364d1 100644 --- a/src/test/compile-fail/phantom-oibit.rs +++ b/src/test/compile-fail/phantom-oibit.rs @@ -12,11 +12,11 @@ // the `PhantomData` type itself (which almost always implements a "default" trait // (`impl Trait for ..`)) -#![feature(optin_builtin_traits)] +#![feature(dynsized, optin_builtin_traits)] -use std::marker::{PhantomData}; +use std::marker::{DynSized, PhantomData}; -unsafe trait Zen {} +unsafe trait Zen: ?DynSized {} unsafe impl Zen for .. {} diff --git a/src/test/compile-fail/privacy-sanity.rs b/src/test/compile-fail/privacy-sanity.rs index 933ec3837dfc7..5977068756bed 100644 --- a/src/test/compile-fail/privacy-sanity.rs +++ b/src/test/compile-fail/privacy-sanity.rs @@ -8,9 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(optin_builtin_traits)] +#![feature(dynsized, optin_builtin_traits)] -trait MarkerTr {} +use std::marker::DynSized; + +trait MarkerTr: ?DynSized {} pub trait Tr { fn f(); const C: u8; @@ -38,7 +40,7 @@ pub extern "C" { //~ ERROR unnecessary visibility qualifier } const MAIN: u8 = { - trait MarkerTr {} + trait MarkerTr: ?DynSized {} pub trait Tr { fn f(); const C: u8; @@ -69,7 +71,7 @@ const MAIN: u8 = { }; fn main() { - trait MarkerTr {} + trait MarkerTr: ?DynSized {} pub trait Tr { fn f(); const C: u8; diff --git a/src/test/compile-fail/typeck-default-trait-impl-constituent-types-2.rs b/src/test/compile-fail/typeck-default-trait-impl-constituent-types-2.rs index 8a46d6c76c30f..a8ae32421002e 100644 --- a/src/test/compile-fail/typeck-default-trait-impl-constituent-types-2.rs +++ b/src/test/compile-fail/typeck-default-trait-impl-constituent-types-2.rs @@ -8,9 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(optin_builtin_traits)] +#![feature(dynsized, optin_builtin_traits)] -trait MyTrait {} +use std::marker::DynSized; + +trait MyTrait: ?DynSized {} impl MyTrait for .. {} diff --git a/src/test/compile-fail/typeck-default-trait-impl-constituent-types.rs b/src/test/compile-fail/typeck-default-trait-impl-constituent-types.rs index 3d7746b369cc0..fc3efdf9a7893 100644 --- a/src/test/compile-fail/typeck-default-trait-impl-constituent-types.rs +++ b/src/test/compile-fail/typeck-default-trait-impl-constituent-types.rs @@ -8,9 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(optin_builtin_traits)] +#![feature(dynsized, optin_builtin_traits)] -trait MyTrait {} +use std::marker::DynSized; + +trait MyTrait: ?DynSized {} impl MyTrait for .. {} impl !MyTrait for *mut T {} diff --git a/src/test/compile-fail/typeck-default-trait-impl-negation.rs b/src/test/compile-fail/typeck-default-trait-impl-negation.rs index 8c2658b89a506..feb97ce453ec9 100644 --- a/src/test/compile-fail/typeck-default-trait-impl-negation.rs +++ b/src/test/compile-fail/typeck-default-trait-impl-negation.rs @@ -8,13 +8,15 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(optin_builtin_traits)] +#![feature(dynsized, optin_builtin_traits)] -trait MyTrait {} +use std::marker::DynSized; + +trait MyTrait: ?DynSized {} impl MyTrait for .. {} -unsafe trait MyUnsafeTrait {} +unsafe trait MyUnsafeTrait: ?DynSized {} unsafe impl MyUnsafeTrait for .. {} diff --git a/src/test/compile-fail/typeck-default-trait-impl-precedence.rs b/src/test/compile-fail/typeck-default-trait-impl-precedence.rs index 66c7a1c75ffe4..506a6a2b35c8f 100644 --- a/src/test/compile-fail/typeck-default-trait-impl-precedence.rs +++ b/src/test/compile-fail/typeck-default-trait-impl-precedence.rs @@ -13,9 +13,11 @@ // other words, the `..` impl only applies if there are no existing // impls whose types unify. -#![feature(optin_builtin_traits)] +#![feature(dynsized, optin_builtin_traits)] -trait Defaulted { } +use std::marker::DynSized; + +trait Defaulted: ?DynSized { } impl Defaulted for .. { } impl<'a,T:Signed> Defaulted for &'a T { } impl<'a,T:Signed> Defaulted for &'a mut T { } diff --git a/src/test/run-pass/extern-types-manual-sync-send.rs b/src/test/run-pass/extern-types-manual-sync-send.rs index c6530c3ea773a..113a02072b179 100644 --- a/src/test/run-pass/extern-types-manual-sync-send.rs +++ b/src/test/run-pass/extern-types-manual-sync-send.rs @@ -10,7 +10,9 @@ // Test that unsafe impl for Sync/Send can be provided for extern types. -#![feature(extern_types)] +#![feature(dynsized, extern_types)] + +use std::marker::DynSized; extern { type A; @@ -19,8 +21,8 @@ extern { unsafe impl Sync for A { } unsafe impl Send for A { } -fn assert_sync() { } -fn assert_send() { } +fn assert_sync() { } +fn assert_send() { } fn main() { assert_sync::(); diff --git a/src/test/run-pass/extern-types-pointer-cast.rs b/src/test/run-pass/extern-types-pointer-cast.rs index 628a570665a33..b53f98aa79a5a 100644 --- a/src/test/run-pass/extern-types-pointer-cast.rs +++ b/src/test/run-pass/extern-types-pointer-cast.rs @@ -17,16 +17,6 @@ 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")] @@ -34,7 +24,4 @@ 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 deleted file mode 100644 index 0aabce99debe8..0000000000000 --- a/src/test/run-pass/extern-types-size_of_val.rs +++ /dev/null @@ -1,26 +0,0 @@ -// 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 index c2444a58b5a1b..477066585d256 100644 --- a/src/test/run-pass/extern-types-thin-pointer.rs +++ b/src/test/run-pass/extern-types-thin-pointer.rs @@ -19,33 +19,16 @@ 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 ()>()); +fn main() { + assert_eq!(size_of::<*const A>(), size_of::<*const ()>()); + assert_eq!(align_of::<*const A>(), align_of::<*const ()>()); - assert_eq!(size_of::<&T>(), size_of::<&()>()); - assert_eq!(align_of::<&T>(), align_of::<&()>()); + assert_eq!(size_of::<*mut A>(), size_of::<*mut ()>()); + assert_eq!(align_of::<*mut A>(), align_of::<*mut ()>()); - assert_eq!(size_of::<&mut T>(), size_of::<&mut ()>()); - assert_eq!(align_of::<&mut T>(), align_of::<&mut ()>()); -} + assert_eq!(size_of::<&A>(), size_of::<&()>()); + assert_eq!(align_of::<&A>(), align_of::<&()>()); -fn main() { - assert_thin::(); - assert_thin::(); - assert_thin::>(); - assert_thin::>>(); + assert_eq!(size_of::<&mut A>(), size_of::<&mut ()>()); + assert_eq!(align_of::<&mut A>(), align_of::<&mut ()>()); } diff --git a/src/test/run-pass/issue-29516.rs b/src/test/run-pass/issue-29516.rs index b586abc29e243..8d76112ecde03 100644 --- a/src/test/run-pass/issue-29516.rs +++ b/src/test/run-pass/issue-29516.rs @@ -8,9 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(optin_builtin_traits)] +#![feature(dynsized, optin_builtin_traits)] -trait NotSame {} +use std::marker::DynSized; + +trait NotSame: ?DynSized {} impl NotSame for .. {} impl !NotSame for (A, A) {} diff --git a/src/test/ui/on-unimplemented/multiple-impls.stderr b/src/test/ui/on-unimplemented/multiple-impls.stderr index a1fa8b720a829..d377f46547f48 100644 --- a/src/test/ui/on-unimplemented/multiple-impls.stderr +++ b/src/test/ui/on-unimplemented/multiple-impls.stderr @@ -7,14 +7,6 @@ error[E0277]: the trait bound `[i32]: Index` is not satisfied = help: the trait `Index` is not implemented for `[i32]` = note: required by `Index::index` -error[E0277]: the trait bound `[i32]: Index` is not satisfied - --> $DIR/multiple-impls.rs:43:5 - | -43 | Index::index(&[] as &[i32], 2u32); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trait message - | - = help: the trait `Index` is not implemented for `[i32]` - error[E0277]: the trait bound `[i32]: Index>` is not satisfied --> $DIR/multiple-impls.rs:49:5 | @@ -24,14 +16,6 @@ error[E0277]: the trait bound `[i32]: Index>` is not satisfied = help: the trait `Index>` is not implemented for `[i32]` = note: required by `Index::index` -error[E0277]: the trait bound `[i32]: Index>` is not satisfied - --> $DIR/multiple-impls.rs:49:5 - | -49 | Index::index(&[] as &[i32], Foo(2u32)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ on impl for Foo - | - = help: the trait `Index>` is not implemented for `[i32]` - error[E0277]: the trait bound `[i32]: Index>` is not satisfied --> $DIR/multiple-impls.rs:55:5 | @@ -41,13 +25,5 @@ error[E0277]: the trait bound `[i32]: Index>` is not satisfied = help: the trait `Index>` is not implemented for `[i32]` = note: required by `Index::index` -error[E0277]: the trait bound `[i32]: Index>` is not satisfied - --> $DIR/multiple-impls.rs:55:5 - | -55 | Index::index(&[] as &[i32], Bar(2u32)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ on impl for Bar - | - = help: the trait `Index>` is not implemented for `[i32]` - -error: aborting due to 6 previous errors +error: aborting due to 3 previous errors diff --git a/src/test/ui/on-unimplemented/on-impl.stderr b/src/test/ui/on-unimplemented/on-impl.stderr index c8c06bf44fd6f..d3edc9dde8033 100644 --- a/src/test/ui/on-unimplemented/on-impl.stderr +++ b/src/test/ui/on-unimplemented/on-impl.stderr @@ -7,13 +7,5 @@ error[E0277]: the trait bound `[i32]: Index` is not satisfied = help: the trait `Index` is not implemented for `[i32]` = note: required by `Index::index` -error[E0277]: the trait bound `[i32]: Index` is not satisfied - --> $DIR/on-impl.rs:32:5 - | -32 | Index::::index(&[1, 2, 3] as &[i32], 2u32); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ a usize is required to index into a slice - | - = help: the trait `Index` is not implemented for `[i32]` - -error: aborting due to 2 previous errors +error: aborting due to previous error From d51764d04739cf718f32322a524019d37460f542 Mon Sep 17 00:00:00 2001 From: Paul Lietar Date: Fri, 8 Sep 2017 19:28:21 +0200 Subject: [PATCH 6/7] Add DynSized related tests --- .../compile-fail/dynsized/no-manual-impl.rs | 25 +++++++++++++ src/test/compile-fail/dynsized/size_of_val.rs | 29 +++++++++++++++ .../dynsized/struct-last-field.rs | 36 +++++++++++++++++++ .../dynsized/supertait-unbound.rs | 28 +++++++++++++++ .../compile-fail/dynsized/tuple-last-field.rs | 28 +++++++++++++++ .../dynsized/sized-implies-dynsized.rs | 26 ++++++++++++++ .../run-pass/dynsized/supertrait-default.rs | 27 ++++++++++++++ 7 files changed, 199 insertions(+) create mode 100644 src/test/compile-fail/dynsized/no-manual-impl.rs create mode 100644 src/test/compile-fail/dynsized/size_of_val.rs create mode 100644 src/test/compile-fail/dynsized/struct-last-field.rs create mode 100644 src/test/compile-fail/dynsized/supertait-unbound.rs create mode 100644 src/test/compile-fail/dynsized/tuple-last-field.rs create mode 100644 src/test/run-pass/dynsized/sized-implies-dynsized.rs create mode 100644 src/test/run-pass/dynsized/supertrait-default.rs diff --git a/src/test/compile-fail/dynsized/no-manual-impl.rs b/src/test/compile-fail/dynsized/no-manual-impl.rs new file mode 100644 index 0000000000000..b591bc49246c1 --- /dev/null +++ b/src/test/compile-fail/dynsized/no-manual-impl.rs @@ -0,0 +1,25 @@ +// 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 DynSized cannot be implemented manually. + +#![feature(extern_types)] +#![feature(dynsized)] + +use std::marker::DynSized; + +extern { + type foo; +} + +impl DynSized for foo { } +//~^ ERROR explicit impls for the `DynSized` trait are not permitted + +fn main() { } diff --git a/src/test/compile-fail/dynsized/size_of_val.rs b/src/test/compile-fail/dynsized/size_of_val.rs new file mode 100644 index 0000000000000..756372978360e --- /dev/null +++ b/src/test/compile-fail/dynsized/size_of_val.rs @@ -0,0 +1,29 @@ +// 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. + +// Ensure `size_of_val` / `align_of_val` can't be used on !DynSized types + +#![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) + }; + + size_of_val(x); //~ERROR the trait bound `A: std::marker::DynSized` is not satisfied + + align_of_val(x); //~ERROR the trait bound `A: std::marker::DynSized` is not satisfied +} diff --git a/src/test/compile-fail/dynsized/struct-last-field.rs b/src/test/compile-fail/dynsized/struct-last-field.rs new file mode 100644 index 0000000000000..de27126748855 --- /dev/null +++ b/src/test/compile-fail/dynsized/struct-last-field.rs @@ -0,0 +1,36 @@ +// 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. + +// Ensure !DynSized fields can't be used in structs, even as the last field. + +#![feature(extern_types)] +#![feature(dynsized)] + +use std::marker::DynSized; + +extern { + type foo; +} + +struct A { + x: foo, //~ERROR the trait bound `foo: std::marker::DynSized` is not satisfied +} + +struct B { + x: usize, + y: foo, //~ERROR the trait bound `foo: std::marker::DynSized` is not satisfied +} + +struct C { + x: usize, + y: T, //~ERROR the trait bound `T: std::marker::DynSized` is not satisfied +} + +fn main() { } diff --git a/src/test/compile-fail/dynsized/supertait-unbound.rs b/src/test/compile-fail/dynsized/supertait-unbound.rs new file mode 100644 index 0000000000000..e4d6ae3cbf213 --- /dev/null +++ b/src/test/compile-fail/dynsized/supertait-unbound.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 traits can opt-out of being DynSized by default. +// See also run-pass/dynsized/supertrait-default.rs + +#![feature(dynsized)] + +use std::marker::DynSized; + +fn assert_dynsized() { } + +trait Tr: ?DynSized { + fn foo() { + assert_dynsized::(); + //~^ ERROR the trait bound `Self: std::marker::DynSized` is not satisfied + } +} + +fn main() { } + diff --git a/src/test/compile-fail/dynsized/tuple-last-field.rs b/src/test/compile-fail/dynsized/tuple-last-field.rs new file mode 100644 index 0000000000000..df86a100f90b4 --- /dev/null +++ b/src/test/compile-fail/dynsized/tuple-last-field.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. + +// Ensure !DynSized fields can't be used in tuples, even as the last field. + +#![feature(extern_types)] +#![feature(dynsized)] + +use std::marker::DynSized; + +extern { + type foo; +} + +fn baz() { + let x: &(u8, foo); //~ERROR the trait bound `foo: std::marker::DynSized` is not satisfied + + let y: &(u8, T); //~ERROR the trait bound `T: std::marker::DynSized` is not satisfied +} + +fn main() { } diff --git a/src/test/run-pass/dynsized/sized-implies-dynsized.rs b/src/test/run-pass/dynsized/sized-implies-dynsized.rs new file mode 100644 index 0000000000000..9aa61b4e6b595 --- /dev/null +++ b/src/test/run-pass/dynsized/sized-implies-dynsized.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(dynsized)] + +use std::marker::DynSized; + +fn foo() { +} + +fn bar() { + foo::(); +} + +fn baz() { + bar::(); +} + +fn main() { } diff --git a/src/test/run-pass/dynsized/supertrait-default.rs b/src/test/run-pass/dynsized/supertrait-default.rs new file mode 100644 index 0000000000000..dabc76112fe07 --- /dev/null +++ b/src/test/run-pass/dynsized/supertrait-default.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 traits have DynSized as a super trait by default. +// See also compile-fail/dynsized/supertrait-unbound.rs + +#![feature(dynsized)] + +use std::marker::DynSized; + +fn assert_dynsized() { } + +trait Tr { + fn foo() { + assert_dynsized::(); + } +} + +fn main() { } + From 55c2522b262c2672989e37c29ede4dc6b3ed64ac Mon Sep 17 00:00:00 2001 From: Paul Lietar Date: Fri, 29 Sep 2017 20:50:57 +0200 Subject: [PATCH 7/7] Fix tidy errors --- src/librustc/util/ppaux.rs | 6 ++++-- src/librustc_passes/ast_validation.rs | 3 ++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 4fd988839701e..ff2c00aa43e24 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -815,11 +815,13 @@ impl<'tcx> fmt::Display for ty::TypeVariants<'tcx> { write!(f, "impl")?; for predicate in bounds.predicates { if let Some(trait_ref) = predicate.to_opt_poly_trait_ref() { + let did = trait_ref.def_id(); + // Don't print +Sized/DynSized, but rather +?Sized/DynSized if absent. - if Some(trait_ref.def_id()) == tcx.lang_items().sized_trait() { + if Some(did) == tcx.lang_items().sized_trait() { is_sized = true; continue; - } else if Some(trait_ref.def_id()) == tcx.lang_items().dynsized_trait() { + } else if Some(did) == tcx.lang_items().dynsized_trait() { is_dynsized = true; continue; } diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs index 0e6be49a7cd97..36f71025ea3dc 100644 --- a/src/librustc_passes/ast_validation.rs +++ b/src/librustc_passes/ast_validation.rs @@ -152,7 +152,8 @@ impl<'a> Visitor<'a> for AstValidator<'a> { any_lifetime_bounds = true; } TraitTyParamBound(ref poly, TraitBoundModifier::Maybe) => { - self.session.span_err(poly.span, "`?Trait` is not permitted in trait object types"); + self.session.span_err(poly.span, + "`?Trait` is not permitted in trait object types"); } _ => (), }