diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index b240d059114eb..bae7ae2884f90 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -1339,6 +1339,10 @@ extern "rust-intrinsic" { /// Emits a `!nontemporal` store according to LLVM (see their docs). /// Probably will never become stable. pub fn nontemporal_store(ptr: *mut T, val: T); + + /// See documentation of `<*const T>::offset_from` for details. + #[cfg(not(bootstrap))] + pub fn ptr_offset_from(ptr: *const T, base: *const T) -> isize; } // Some functions are defined here because they accidentally got made diff --git a/src/libcore/ptr/mod.rs b/src/libcore/ptr/mod.rs index 3cc0a1cd75e88..1355ce1aa43b7 100644 --- a/src/libcore/ptr/mod.rs +++ b/src/libcore/ptr/mod.rs @@ -1286,7 +1286,22 @@ impl *const T { /// } /// ``` #[unstable(feature = "ptr_offset_from", issue = "41079")] + #[cfg(not(bootstrap))] + #[rustc_const_unstable(feature = "const_ptr_offset_from")] #[inline] + pub const unsafe fn offset_from(self, origin: *const T) -> isize where T: Sized { + let pointee_size = mem::size_of::(); + let ok = 0 < pointee_size && pointee_size <= isize::max_value() as usize; + // assert that the pointee size is valid in a const eval compatible way + // FIXME: do this with a real assert at some point + [()][(!ok) as usize]; + intrinsics::ptr_offset_from(self, origin) + } + + #[unstable(feature = "ptr_offset_from", issue = "41079")] + #[inline] + #[cfg(bootstrap)] + /// bootstrap pub unsafe fn offset_from(self, origin: *const T) -> isize where T: Sized { let pointee_size = mem::size_of::(); assert!(0 < pointee_size && pointee_size <= isize::max_value() as usize); @@ -2013,8 +2028,9 @@ impl *mut T { /// } /// ``` #[unstable(feature = "ptr_offset_from", issue = "41079")] + #[rustc_const_unstable(feature = "const_ptr_offset_from")] #[inline] - pub unsafe fn offset_from(self, origin: *const T) -> isize where T: Sized { + pub const unsafe fn offset_from(self, origin: *const T) -> isize where T: Sized { (self as *const T).offset_from(origin) } diff --git a/src/librustc_codegen_llvm/intrinsic.rs b/src/librustc_codegen_llvm/intrinsic.rs index 3df8d4c26903b..97bd57a7ded06 100644 --- a/src/librustc_codegen_llvm/intrinsic.rs +++ b/src/librustc_codegen_llvm/intrinsic.rs @@ -19,6 +19,7 @@ use rustc::mir::interpret::GlobalId; use rustc_codegen_ssa::common::{IntPredicate, TypeKind}; use rustc::hir; use syntax::ast::{self, FloatTy}; +use rustc_target::abi::HasDataLayout; use rustc_codegen_ssa::common::span_invalid_monomorphization_error; use rustc_codegen_ssa::traits::*; @@ -694,6 +695,23 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { return; } + "ptr_offset_from" => { + let ty = substs.type_at(0); + let pointee_size = self.size_of(ty); + + // This is the same sequence that Clang emits for pointer subtraction. + // It can be neither `nsw` nor `nuw` because the input is treated as + // unsigned but then the output is treated as signed, so neither works. + let a = args[0].immediate(); + let b = args[1].immediate(); + let a = self.ptrtoint(a, self.type_isize()); + let b = self.ptrtoint(b, self.type_isize()); + let d = self.sub(a, b); + let pointee_size = self.const_usize(pointee_size.bytes()); + // this is where the signed magic happens (notice the `s` in `exactsdiv`) + self.exactsdiv(d, pointee_size) + } + _ => bug!("unknown intrinsic '{}'", name), }; @@ -1224,7 +1242,6 @@ fn generic_simd_intrinsic( // The `fn simd_bitmask(vector) -> unsigned integer` intrinsic takes a // vector mask and returns an unsigned integer containing the most // significant bit (MSB) of each lane. - use rustc_target::abi::HasDataLayout; // If the vector has less than 8 lanes, an u8 is returned with zeroed // trailing bits. diff --git a/src/librustc_codegen_ssa/back/write.rs b/src/librustc_codegen_ssa/back/write.rs index 8bc815f2c622e..762b50f1659cc 100644 --- a/src/librustc_codegen_ssa/back/write.rs +++ b/src/librustc_codegen_ssa/back/write.rs @@ -259,7 +259,7 @@ fn generate_lto_work( needs_thin_lto: Vec<(String, B::ThinBuffer)>, import_only_modules: Vec<(SerializedModule, WorkProduct)> ) -> Vec<(WorkItem, u64)> { - let _prof_timer = cgcx.prof.generic_activity("codegen_run_lto"); + let _prof_timer = cgcx.prof.generic_activity("codegen_generate_lto_work"); let (lto_modules, copy_jobs) = if !needs_fat_lto.is_empty() { assert!(needs_thin_lto.is_empty()); @@ -674,11 +674,11 @@ impl WorkItem { } } - pub fn name(&self) -> String { + fn profiling_event_id(&self) -> &'static str { match *self { - WorkItem::Optimize(ref m) => format!("optimize: {}", m.name), - WorkItem::CopyPostLtoArtifacts(ref m) => format!("copy post LTO artifacts: {}", m.name), - WorkItem::LTO(ref m) => format!("lto: {}", m.name()), + WorkItem::Optimize(_) => "codegen_module_optimize", + WorkItem::CopyPostLtoArtifacts(_) => "codegen_copy_artifacts_from_incr_cache", + WorkItem::LTO(_) => "codegen_module_perform_lto", } } } @@ -1587,7 +1587,7 @@ fn spawn_work( // as a diagnostic was already sent off to the main thread - just // surface that there was an error in this worker. bomb.result = { - let _prof_timer = cgcx.prof.generic_activity(&work.name()); + let _prof_timer = cgcx.prof.generic_activity(work.profiling_event_id()); execute_work_item(&cgcx, work).ok() }; }); diff --git a/src/librustc_codegen_ssa/base.rs b/src/librustc_codegen_ssa/base.rs index f4f3dd4d2d295..e8ffe868231a6 100644 --- a/src/librustc_codegen_ssa/base.rs +++ b/src/librustc_codegen_ssa/base.rs @@ -406,6 +406,8 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(cx: &' rust_main_def_id: DefId, use_start_lang_item: bool, ) { + // The entry function is either `int main(void)` or `int main(int argc, char **argv)`, + // depending on whether the target needs `argc` and `argv` to be passed in. let llfty = if cx.sess().target.target.options.main_needs_argc_argv { cx.type_func(&[cx.type_int(), cx.type_ptr_to(cx.type_i8p())], cx.type_int()) } else { @@ -440,19 +442,7 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(cx: &' bx.insert_reference_to_gdb_debug_scripts_section_global(); - let (arg_argc, arg_argv) = if cx.sess().target.target.options.main_needs_argc_argv { - // Params from native main() used as args for rust start function - let param_argc = bx.get_param(0); - let param_argv = bx.get_param(1); - let arg_argc = bx.intcast(param_argc, cx.type_isize(), true); - let arg_argv = param_argv; - (arg_argc, arg_argv) - } else { - // The Rust start function doesn't need argc and argv, so just pass zeros. - let arg_argc = bx.const_int(cx.type_int(), 0); - let arg_argv = bx.const_null(cx.type_ptr_to(cx.type_i8p())); - (arg_argc, arg_argv) - }; + let (arg_argc, arg_argv) = get_argc_argv(cx, &mut bx); let (start_fn, args) = if use_start_lang_item { let start_def_id = cx.tcx().require_lang_item(StartFnLangItem, None); @@ -477,6 +467,27 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(cx: &' } } +/// Obtain the `argc` and `argv` values to pass to the rust start function. +fn get_argc_argv<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( + cx: &'a Bx::CodegenCx, + bx: &mut Bx +) -> (Bx::Value, Bx::Value) +{ + if cx.sess().target.target.options.main_needs_argc_argv { + // Params from native `main()` used as args for rust start function + let param_argc = bx.get_param(0); + let param_argv = bx.get_param(1); + let arg_argc = bx.intcast(param_argc, cx.type_isize(), true); + let arg_argv = param_argv; + (arg_argc, arg_argv) + } else { + // The Rust start function doesn't need `argc` and `argv`, so just pass zeros. + let arg_argc = bx.const_int(cx.type_int(), 0); + let arg_argv = bx.const_null(cx.type_ptr_to(cx.type_i8p())); + (arg_argc, arg_argv) + } +} + pub const CODEGEN_WORKER_ID: usize = ::std::usize::MAX; pub fn codegen_crate( diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index b8b0030244028..1333e3fb3ce3e 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -448,7 +448,7 @@ impl<'tcx> EntryKind<'tcx> { EntryKind::Mod(_) => DefKind::Mod, EntryKind::Variant(_) => DefKind::Variant, EntryKind::Trait(_) => DefKind::Trait, - EntryKind::TraitAlias(_) => DefKind::TraitAlias, + EntryKind::TraitAlias => DefKind::TraitAlias, EntryKind::Enum(..) => DefKind::Enum, EntryKind::MacroDef(_) => DefKind::Macro(MacroKind::Bang), EntryKind::ForeignType => DefKind::ForeignTy, @@ -458,7 +458,7 @@ impl<'tcx> EntryKind<'tcx> { EntryKind::Impl(_) | EntryKind::Field | EntryKind::Generator(_) | - EntryKind::Closure(_) => return None, + EntryKind::Closure => return None, }) } } @@ -575,7 +575,7 @@ impl<'a, 'tcx> CrateMetadata { data.is_marker, self.def_path_table.def_path_hash(item_id)) }, - EntryKind::TraitAlias(_) => { + EntryKind::TraitAlias => { ty::TraitDef::new(self.local_def_id(item_id), hir::Unsafety::Normal, false, @@ -680,13 +680,7 @@ impl<'a, 'tcx> CrateMetadata { item_id: DefIndex, tcx: TyCtxt<'tcx>, ) -> ty::GenericPredicates<'tcx> { - let super_predicates = match self.kind(item_id) { - EntryKind::Trait(data) => data.decode(self).super_predicates, - EntryKind::TraitAlias(data) => data.decode(self).super_predicates, - _ => bug!("def-index does not refer to trait or trait alias"), - }; - - super_predicates.decode((self, tcx)) + self.root.per_def.super_predicates.get(self, item_id).unwrap().decode((self, tcx)) } crate fn get_generics(&self, item_id: DefIndex, sess: &Session) -> ty::Generics { @@ -717,7 +711,7 @@ impl<'a, 'tcx> CrateMetadata { } } - fn get_impl_data(&self, id: DefIndex) -> ImplData<'tcx> { + fn get_impl_data(&self, id: DefIndex) -> ImplData { match self.kind(id) { EntryKind::Impl(data) => data.decode(self), _ => bug!(), @@ -744,7 +738,7 @@ impl<'a, 'tcx> CrateMetadata { } crate fn get_impl_trait(&self, id: DefIndex, tcx: TyCtxt<'tcx>) -> Option> { - self.get_impl_data(id).trait_ref.map(|tr| tr.decode((self, tcx))) + self.root.per_def.impl_trait_ref.get(self, id).map(|tr| tr.decode((self, tcx))) } /// Iterates over all the stability attributes in the given crate. @@ -1118,7 +1112,7 @@ impl<'a, 'tcx> CrateMetadata { def_key.parent.and_then(|parent_index| { match self.kind(parent_index) { EntryKind::Trait(_) | - EntryKind::TraitAlias(_) => Some(self.local_def_id(parent_index)), + EntryKind::TraitAlias => Some(self.local_def_id(parent_index)), _ => None, } }) @@ -1245,16 +1239,7 @@ impl<'a, 'tcx> CrateMetadata { } crate fn fn_sig(&self, id: DefIndex, tcx: TyCtxt<'tcx>) -> ty::PolyFnSig<'tcx> { - let sig = match self.kind(id) { - EntryKind::Fn(data) | - EntryKind::ForeignFn(data) => data.decode(self).sig, - EntryKind::Method(data) => data.decode(self).fn_data.sig, - EntryKind::Variant(data) | - EntryKind::Struct(data, _) => data.decode(self).ctor_sig.unwrap(), - EntryKind::Closure(data) => data.decode(self).sig, - _ => bug!(), - }; - sig.decode((self, tcx)) + self.root.per_def.fn_sig.get(self, id).unwrap().decode((self, tcx)) } #[inline] diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 6ae8c2fc6c694..0dc9f91ae00e1 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -71,11 +71,14 @@ struct PerDefTables<'tcx> { deprecation: PerDefTable>, ty: PerDefTable>>, + fn_sig: PerDefTable>>, + impl_trait_ref: PerDefTable>>, inherent_impls: PerDefTable>, variances: PerDefTable>, generics: PerDefTable>, predicates: PerDefTable>>, predicates_defined_on: PerDefTable>>, + super_predicates: PerDefTable>>, mir: PerDefTable>>, promoted_mir: PerDefTable>>>, @@ -508,11 +511,14 @@ impl<'tcx> EncodeContext<'tcx> { deprecation: self.per_def.deprecation.encode(&mut self.opaque), ty: self.per_def.ty.encode(&mut self.opaque), + fn_sig: self.per_def.fn_sig.encode(&mut self.opaque), + impl_trait_ref: self.per_def.impl_trait_ref.encode(&mut self.opaque), inherent_impls: self.per_def.inherent_impls.encode(&mut self.opaque), variances: self.per_def.variances.encode(&mut self.opaque), generics: self.per_def.generics.encode(&mut self.opaque), predicates: self.per_def.predicates.encode(&mut self.opaque), predicates_defined_on: self.per_def.predicates_defined_on.encode(&mut self.opaque), + super_predicates: self.per_def.super_predicates.encode(&mut self.opaque), mir: self.per_def.mir.encode(&mut self.opaque), promoted_mir: self.per_def.promoted_mir.encode(&mut self.opaque), @@ -635,13 +641,7 @@ impl EncodeContext<'tcx> { let data = VariantData { ctor_kind: variant.ctor_kind, discr: variant.discr, - // FIXME(eddyb) deduplicate these with `encode_enum_variant_ctor`. ctor: variant.ctor_def_id.map(|did| did.index), - ctor_sig: if variant.ctor_kind == CtorKind::Fn { - variant.ctor_def_id.map(|ctor_def_id| self.lazy(&tcx.fn_sig(ctor_def_id))) - } else { - None - }, }; let enum_id = tcx.hir().as_local_hir_id(enum_did).unwrap(); @@ -660,6 +660,11 @@ impl EncodeContext<'tcx> { self.encode_deprecation(def_id); self.encode_item_type(def_id); if variant.ctor_kind == CtorKind::Fn { + // FIXME(eddyb) encode signature only in `encode_enum_variant_ctor`. + if let Some(ctor_def_id) = variant.ctor_def_id { + record!(self.per_def.fn_sig[def_id] <- tcx.fn_sig(ctor_def_id)); + } + // FIXME(eddyb) is this ever used? self.encode_variances_of(def_id); } self.encode_generics(def_id); @@ -679,15 +684,11 @@ impl EncodeContext<'tcx> { let def_id = variant.ctor_def_id.unwrap(); debug!("EncodeContext::encode_enum_variant_ctor({:?})", def_id); + // FIXME(eddyb) encode only the `CtorKind` for constructors. let data = VariantData { ctor_kind: variant.ctor_kind, discr: variant.discr, ctor: Some(def_id.index), - ctor_sig: if variant.ctor_kind == CtorKind::Fn { - Some(self.lazy(tcx.fn_sig(def_id))) - } else { - None - } }; // Variant constructors have the same visibility as the parent enums, unless marked as @@ -706,6 +707,7 @@ impl EncodeContext<'tcx> { self.encode_deprecation(def_id); self.encode_item_type(def_id); if variant.ctor_kind == CtorKind::Fn { + record!(self.per_def.fn_sig[def_id] <- tcx.fn_sig(def_id)); self.encode_variances_of(def_id); } self.encode_generics(def_id); @@ -780,11 +782,6 @@ impl EncodeContext<'tcx> { ctor_kind: variant.ctor_kind, discr: variant.discr, ctor: Some(def_id.index), - ctor_sig: if variant.ctor_kind == CtorKind::Fn { - Some(self.lazy(tcx.fn_sig(def_id))) - } else { - None - } }; let struct_id = tcx.hir().as_local_hir_id(adt_def_id).unwrap(); @@ -811,6 +808,7 @@ impl EncodeContext<'tcx> { self.encode_deprecation(def_id); self.encode_item_type(def_id); if variant.ctor_kind == CtorKind::Fn { + record!(self.per_def.fn_sig[def_id] <- tcx.fn_sig(def_id)); self.encode_variances_of(def_id); } self.encode_generics(def_id); @@ -835,6 +833,11 @@ impl EncodeContext<'tcx> { self.tcx.predicates_defined_on(def_id)) } + fn encode_super_predicates(&mut self, def_id: DefId) { + debug!("EncodeContext::encode_super_predicates({:?})", def_id); + record!(self.per_def.super_predicates[def_id] <- self.tcx.super_predicates_of(def_id)); + } + fn encode_info_for_trait_item(&mut self, def_id: DefId) { debug!("EncodeContext::encode_info_for_trait_item({:?})", def_id); let tcx = self.tcx; @@ -874,7 +877,6 @@ impl EncodeContext<'tcx> { asyncness: m_sig.header.asyncness, constness: hir::Constness::NotConst, param_names, - sig: self.lazy(tcx.fn_sig(def_id)), } } else { bug!() @@ -906,6 +908,7 @@ impl EncodeContext<'tcx> { ty::AssocKind::OpaqueTy => unreachable!(), } if trait_item.kind == ty::AssocKind::Method { + record!(self.per_def.fn_sig[def_id] <- tcx.fn_sig(def_id)); self.encode_variances_of(def_id); } self.encode_generics(def_id); @@ -952,7 +955,6 @@ impl EncodeContext<'tcx> { asyncness: sig.header.asyncness, constness: sig.header.constness, param_names: self.encode_fn_param_names_for_body(body), - sig: self.lazy(tcx.fn_sig(def_id)), } } else { bug!() @@ -973,6 +975,7 @@ impl EncodeContext<'tcx> { self.encode_deprecation(def_id); self.encode_item_type(def_id); if impl_item.kind == ty::AssocKind::Method { + record!(self.per_def.fn_sig[def_id] <- tcx.fn_sig(def_id)); self.encode_variances_of(def_id); } self.encode_generics(def_id); @@ -1081,7 +1084,6 @@ impl EncodeContext<'tcx> { asyncness: header.asyncness, constness: header.constness, param_names: self.encode_fn_param_names_for_body(body), - sig: self.lazy(tcx.fn_sig(def_id)), }; EntryKind::Fn(self.lazy(data)) @@ -1109,7 +1111,6 @@ impl EncodeContext<'tcx> { ctor_kind: variant.ctor_kind, discr: variant.discr, ctor, - ctor_sig: None, }), adt_def.repr) } hir::ItemKind::Union(..) => { @@ -1120,7 +1121,6 @@ impl EncodeContext<'tcx> { ctor_kind: variant.ctor_kind, discr: variant.discr, ctor: None, - ctor_sig: None, }), adt_def.repr) } hir::ItemKind::Impl(_, _, defaultness, ..) => { @@ -1154,7 +1154,6 @@ impl EncodeContext<'tcx> { defaultness, parent_impl: parent, coerce_unsized_info, - trait_ref: trait_ref.map(|trait_ref| self.lazy(trait_ref)), }; EntryKind::Impl(self.lazy(data)) @@ -1166,18 +1165,11 @@ impl EncodeContext<'tcx> { paren_sugar: trait_def.paren_sugar, has_auto_impl: self.tcx.trait_is_auto(def_id), is_marker: trait_def.is_marker, - super_predicates: self.lazy(tcx.super_predicates_of(def_id)), }; EntryKind::Trait(self.lazy(data)) } - hir::ItemKind::TraitAlias(..) => { - let data = TraitAliasData { - super_predicates: self.lazy(tcx.super_predicates_of(def_id)), - }; - - EntryKind::TraitAlias(self.lazy(data)) - } + hir::ItemKind::TraitAlias(..) => EntryKind::TraitAlias, hir::ItemKind::ExternCrate(_) | hir::ItemKind::Use(..) => bug!("cannot encode info for item {:?}", item), }); @@ -1232,6 +1224,14 @@ impl EncodeContext<'tcx> { hir::ItemKind::Impl(..) => self.encode_item_type(def_id), _ => {} } + if let hir::ItemKind::Fn(..) = item.kind { + record!(self.per_def.fn_sig[def_id] <- tcx.fn_sig(def_id)); + } + if let hir::ItemKind::Impl(..) = item.kind { + if let Some(trait_ref) = self.tcx.impl_trait_ref(def_id) { + record!(self.per_def.impl_trait_ref[def_id] <- trait_ref); + } + } self.encode_inherent_implementations(def_id); match item.kind { hir::ItemKind::Enum(..) | @@ -1269,6 +1269,13 @@ impl EncodeContext<'tcx> { } _ => {} // not *wrong* for other kinds of items, but not needed } + match item.kind { + hir::ItemKind::Trait(..) | + hir::ItemKind::TraitAlias(..) => { + self.encode_super_predicates(def_id); + } + _ => {} + } let mir = match item.kind { hir::ItemKind::Static(..) | hir::ItemKind::Const(..) => true, @@ -1321,10 +1328,12 @@ impl EncodeContext<'tcx> { fn encode_info_for_closure(&mut self, def_id: DefId) { debug!("EncodeContext::encode_info_for_closure({:?})", def_id); - let tables = self.tcx.typeck_tables_of(def_id); + // NOTE(eddyb) `tcx.type_of(def_id)` isn't used because it's fully generic, + // including on the signature, which is inferred in `typeck_tables_of. let hir_id = self.tcx.hir().as_local_hir_id(def_id).unwrap(); + let ty = self.tcx.typeck_tables_of(def_id).node_type(hir_id); - record!(self.per_def.kind[def_id] <- match tables.node_type(hir_id).kind { + record!(self.per_def.kind[def_id] <- match ty.kind { ty::Generator(def_id, ..) => { let layout = self.tcx.generator_layout(def_id); let data = GeneratorData { @@ -1333,11 +1342,7 @@ impl EncodeContext<'tcx> { EntryKind::Generator(self.lazy(data)) } - ty::Closure(def_id, substs) => { - let sig = substs.as_closure().sig(def_id, self.tcx); - let data = ClosureData { sig: self.lazy(sig) }; - EntryKind::Closure(self.lazy(data)) - } + ty::Closure(..) => EntryKind::Closure, _ => bug!("closure that is neither generator nor closure"), }); @@ -1345,6 +1350,9 @@ impl EncodeContext<'tcx> { record!(self.per_def.span[def_id] <- self.tcx.def_span(def_id)); record!(self.per_def.attributes[def_id] <- &self.tcx.get_attrs(def_id)[..]); self.encode_item_type(def_id); + if let ty::Closure(def_id, substs) = ty.kind { + record!(self.per_def.fn_sig[def_id] <- substs.as_closure().sig(def_id, self.tcx)); + } self.encode_generics(def_id); self.encode_optimized_mir(def_id); self.encode_promoted_mir(def_id); @@ -1553,7 +1561,6 @@ impl EncodeContext<'tcx> { asyncness: hir::IsAsync::NotAsync, constness: hir::Constness::NotConst, param_names: self.encode_fn_param_names(names), - sig: self.lazy(tcx.fn_sig(def_id)), }; EntryKind::ForeignFn(self.lazy(data)) } @@ -1569,6 +1576,7 @@ impl EncodeContext<'tcx> { self.encode_deprecation(def_id); self.encode_item_type(def_id); if let hir::ForeignItemKind::Fn(..) = nitem.kind { + record!(self.per_def.fn_sig[def_id] <- tcx.fn_sig(def_id)); self.encode_variances_of(def_id); } self.encode_generics(def_id); diff --git a/src/librustc_metadata/schema.rs b/src/librustc_metadata/schema.rs index 96f35783278fa..ad39aa34fd5c8 100644 --- a/src/librustc_metadata/schema.rs +++ b/src/librustc_metadata/schema.rs @@ -238,11 +238,14 @@ crate struct LazyPerDefTables<'tcx> { pub deprecation: Lazy!(PerDefTable>), pub ty: Lazy!(PerDefTable)>), + pub fn_sig: Lazy!(PerDefTable)>), + pub impl_trait_ref: Lazy!(PerDefTable)>), pub inherent_impls: Lazy!(PerDefTable>), pub variances: Lazy!(PerDefTable>), pub generics: Lazy!(PerDefTable>), pub predicates: Lazy!(PerDefTable)>), pub predicates_defined_on: Lazy!(PerDefTable)>), + pub super_predicates: Lazy!(PerDefTable)>), pub mir: Lazy!(PerDefTable)>), pub promoted_mir: Lazy!(PerDefTable>)>), @@ -264,22 +267,22 @@ crate enum EntryKind<'tcx> { OpaqueTy, Enum(ReprOptions), Field, - Variant(Lazy!(VariantData<'tcx>)), - Struct(Lazy!(VariantData<'tcx>), ReprOptions), - Union(Lazy!(VariantData<'tcx>), ReprOptions), - Fn(Lazy!(FnData<'tcx>)), - ForeignFn(Lazy!(FnData<'tcx>)), + Variant(Lazy), + Struct(Lazy, ReprOptions), + Union(Lazy, ReprOptions), + Fn(Lazy), + ForeignFn(Lazy), Mod(Lazy), MacroDef(Lazy), - Closure(Lazy!(ClosureData<'tcx>)), + Closure, Generator(Lazy!(GeneratorData<'tcx>)), - Trait(Lazy!(TraitData<'tcx>)), - Impl(Lazy!(ImplData<'tcx>)), - Method(Lazy!(MethodData<'tcx>)), + Trait(Lazy), + Impl(Lazy), + Method(Lazy), AssocType(AssocContainer), AssocOpaqueTy(AssocContainer), AssocConst(AssocContainer, ConstQualif, Lazy), - TraitAlias(Lazy!(TraitAliasData<'tcx>)), + TraitAlias, } /// Additional data for EntryKind::Const and EntryKind::AssocConst @@ -305,47 +308,37 @@ crate struct MacroDef { } #[derive(RustcEncodable, RustcDecodable)] -crate struct FnData<'tcx> { +crate struct FnData { pub asyncness: hir::IsAsync, pub constness: hir::Constness, pub param_names: Lazy<[ast::Name]>, - pub sig: Lazy!(ty::PolyFnSig<'tcx>), } #[derive(RustcEncodable, RustcDecodable)] -crate struct VariantData<'tcx> { +crate struct VariantData { pub ctor_kind: CtorKind, pub discr: ty::VariantDiscr, /// If this is unit or tuple-variant/struct, then this is the index of the ctor id. pub ctor: Option, - /// If this is a tuple struct or variant - /// ctor, this is its "function" signature. - pub ctor_sig: Option)>, } #[derive(RustcEncodable, RustcDecodable)] -crate struct TraitData<'tcx> { +crate struct TraitData { pub unsafety: hir::Unsafety, pub paren_sugar: bool, pub has_auto_impl: bool, pub is_marker: bool, - pub super_predicates: Lazy!(ty::GenericPredicates<'tcx>), } #[derive(RustcEncodable, RustcDecodable)] -crate struct TraitAliasData<'tcx> { - pub super_predicates: Lazy!(ty::GenericPredicates<'tcx>), -} - -#[derive(RustcEncodable, RustcDecodable)] -crate struct ImplData<'tcx> { +crate struct ImplData { pub polarity: ty::ImplPolarity, pub defaultness: hir::Defaultness, pub parent_impl: Option, /// This is `Some` only for impls of `CoerceUnsized`. + // FIXME(eddyb) perhaps compute this on the fly if cheap enough? pub coerce_unsized_info: Option, - pub trait_ref: Option)>, } @@ -388,17 +381,12 @@ impl AssocContainer { } #[derive(RustcEncodable, RustcDecodable)] -crate struct MethodData<'tcx> { - pub fn_data: FnData<'tcx>, +crate struct MethodData { + pub fn_data: FnData, pub container: AssocContainer, pub has_self: bool, } -#[derive(RustcEncodable, RustcDecodable)] -crate struct ClosureData<'tcx> { - pub sig: Lazy!(ty::PolyFnSig<'tcx>), -} - #[derive(RustcEncodable, RustcDecodable)] crate struct GeneratorData<'tcx> { pub layout: mir::GeneratorLayout<'tcx>, diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index 2ab7c41bb787e..d929e958f05d0 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -91,7 +91,7 @@ pub struct Frame<'mir, 'tcx, Tag=(), Extra=()> { pub extra: Extra, } -#[derive(Clone, Eq, PartialEq)] +#[derive(Clone, Eq, PartialEq, Debug)] // Miri debug-prints these pub enum StackPopCleanup { /// Jump to the next block in the caller, or cause UB if None (that's a function /// that may never return). Also store layout of return place so @@ -113,7 +113,7 @@ pub struct LocalState<'tcx, Tag=(), Id=AllocId> { } /// Current value of a local variable -#[derive(Clone, PartialEq, Eq)] +#[derive(Clone, PartialEq, Eq, Debug)] // Miri debug-prints these pub enum LocalValue { /// This local is not currently alive, and cannot be used at all. Dead, diff --git a/src/librustc_mir/interpret/intrinsics.rs b/src/librustc_mir/interpret/intrinsics.rs index 5fc23b4a69ec5..e3d3ff70c4e8a 100644 --- a/src/librustc_mir/interpret/intrinsics.rs +++ b/src/librustc_mir/interpret/intrinsics.rs @@ -12,7 +12,7 @@ use rustc::mir::BinOp; use rustc::mir::interpret::{InterpResult, Scalar, GlobalId, ConstValue}; use super::{ - Machine, PlaceTy, OpTy, InterpCx, + Machine, PlaceTy, OpTy, InterpCx, ImmTy, }; mod type_name; @@ -236,6 +236,29 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let result = Scalar::from_uint(truncated_bits, layout.size); self.write_scalar(result, dest)?; } + + "ptr_offset_from" => { + let a = self.read_immediate(args[0])?.to_scalar()?.to_ptr()?; + let b = self.read_immediate(args[1])?.to_scalar()?.to_ptr()?; + if a.alloc_id != b.alloc_id { + throw_ub_format!( + "ptr_offset_from cannot compute offset of pointers into different \ + allocations.", + ); + } + let usize_layout = self.layout_of(self.tcx.types.usize)?; + let a_offset = ImmTy::from_uint(a.offset.bytes(), usize_layout); + let b_offset = ImmTy::from_uint(b.offset.bytes(), usize_layout); + let (val, _overflowed, _ty) = self.overflowing_binary_op( + BinOp::Sub, a_offset, b_offset, + )?; + let pointee_layout = self.layout_of(substs.type_at(0))?; + let isize_layout = self.layout_of(self.tcx.types.isize)?; + let val = ImmTy::from_scalar(val, isize_layout); + let size = ImmTy::from_int(pointee_layout.size.bytes(), isize_layout); + self.exact_div(val, size, dest)?; + } + "transmute" => { self.copy_op_transmute(args[0], dest)?; } @@ -340,4 +363,30 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { return Ok(false); } } + + pub fn exact_div( + &mut self, + a: ImmTy<'tcx, M::PointerTag>, + b: ImmTy<'tcx, M::PointerTag>, + dest: PlaceTy<'tcx, M::PointerTag>, + ) -> InterpResult<'tcx> { + // Performs an exact division, resulting in undefined behavior where + // `x % y != 0` or `y == 0` or `x == T::min_value() && y == -1`. + // First, check x % y != 0. + if self.binary_op(BinOp::Rem, a, b)?.to_bits()? != 0 { + // Then, check if `b` is -1, which is the "min_value / -1" case. + let minus1 = Scalar::from_int(-1, dest.layout.size); + let b = b.to_scalar().unwrap(); + if b == minus1 { + throw_ub_format!("exact_div: result of dividing MIN by -1 cannot be represented") + } else { + throw_ub_format!( + "exact_div: {} cannot be divided by {} without remainder", + a.to_scalar().unwrap(), + b, + ) + } + } + self.binop_ignore_overflow(BinOp::Div, a, b, dest) + } } diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index da1abb9747c1a..713a5b4ced0e2 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -560,6 +560,7 @@ impl Qualif for IsNotPromotable { | "transmute" | "simd_insert" | "simd_extract" + | "ptr_offset_from" => return true, _ => {} diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs index aeb2c40e2ef83..0ebdc0672fcb1 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -307,6 +307,8 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem) { (1, vec![param(0), param(0)], tcx.intern_tup(&[param(0), tcx.types.bool])), + "ptr_offset_from" => + (1, vec![ tcx.mk_imm_ptr(param(0)), tcx.mk_imm_ptr(param(0)) ], tcx.types.isize), "unchecked_div" | "unchecked_rem" | "exact_div" => (1, vec![param(0), param(0)], param(0)), "unchecked_shl" | "unchecked_shr" | diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 72a72e892814a..414c3137376a9 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -1241,6 +1241,7 @@ fn settings(root_path: &str, suffix: &str) -> String { ("go-to-only-result", "Directly go to item in search if there is only one result", false), ("line-numbers", "Show line numbers on code examples", false), + ("disable-shortcuts", "Disable keyboard shortcuts", false), ]; format!( "

\ diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index 17a940cc4c9f8..f0104c9156ded 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -79,6 +79,7 @@ function getSearchElement() { "derive", "traitalias"]; + var disableShortcuts = getCurrentValue("rustdoc-disable-shortcuts") !== "true"; var search_input = getSearchInput(); // On the search screen, so you remain on the last tab you opened. @@ -294,7 +295,7 @@ function getSearchElement() { function handleShortcut(ev) { // Don't interfere with browser shortcuts - if (ev.ctrlKey || ev.altKey || ev.metaKey) { + if (ev.ctrlKey || ev.altKey || ev.metaKey || disableShortcuts === true) { return; } diff --git a/src/libstd/sys/wasi/thread.rs b/src/libstd/sys/wasi/thread.rs index 28a504f197974..6ce41420284e5 100644 --- a/src/libstd/sys/wasi/thread.rs +++ b/src/libstd/sys/wasi/thread.rs @@ -31,10 +31,10 @@ impl Thread { let nanos = dur.as_nanos(); assert!(nanos <= u64::max_value() as u128); - const CLOCK_ID: wasi::Userdata = 0x0123_45678; + const USERDATA: wasi::Userdata = 0x0123_45678; let clock = wasi::raw::__wasi_subscription_u_clock_t { - identifier: CLOCK_ID, + identifier: 0, clock_id: wasi::CLOCK_MONOTONIC, timeout: nanos as u64, precision: 0, @@ -42,7 +42,7 @@ impl Thread { }; let in_ = [wasi::Subscription { - userdata: 0, + userdata: USERDATA, type_: wasi::EVENTTYPE_CLOCK, u: wasi::raw::__wasi_subscription_u { clock: clock }, }]; @@ -53,7 +53,7 @@ impl Thread { }; match (res, event) { (Ok(1), wasi::Event { - userdata: CLOCK_ID, + userdata: USERDATA, error: 0, type_: wasi::EVENTTYPE_CLOCK, .. diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 6bbd8be0cb982..2ce0046ca276c 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -86,13 +86,6 @@ macro_rules! maybe_recover_from_interpolated_ty_qpath { } } -fn maybe_append(mut lhs: Vec, mut rhs: Option>) -> Vec { - if let Some(ref mut rhs) = rhs { - lhs.append(rhs); - } - lhs -} - #[derive(Debug, Clone, Copy, PartialEq)] enum PrevTokenKind { DocComment, diff --git a/src/libsyntax/parse/parser/item.rs b/src/libsyntax/parse/parser/item.rs index 0acfd1450d819..73bd80e2a21f7 100644 --- a/src/libsyntax/parse/parser/item.rs +++ b/src/libsyntax/parse/parser/item.rs @@ -10,7 +10,6 @@ use crate::ast::{Visibility, VisibilityKind, Mutability, FnHeader, ForeignItem, use crate::ast::{Ty, TyKind, Generics, GenericBounds, TraitRef, EnumDef, VariantData, StructField}; use crate::ast::{Mac, MacDelimiter, Block, BindingMode, FnDecl, MethodSig, SelfKind, Param}; use crate::parse::token; -use crate::parse::parser::maybe_append; use crate::tokenstream::{TokenTree, TokenStream}; use crate::symbol::{kw, sym}; use crate::source_map::{self, respan, Span}; @@ -416,10 +415,17 @@ impl<'a> Parser<'a> { ) -> PResult<'a, Option>> { let (ident, item, extra_attrs) = info; let span = lo.to(self.prev_span); - let attrs = maybe_append(attrs, extra_attrs); + let attrs = Self::maybe_append(attrs, extra_attrs); Ok(Some(self.mk_item(span, ident, item, vis, attrs))) } + fn maybe_append(mut lhs: Vec, mut rhs: Option>) -> Vec { + if let Some(ref mut rhs) = rhs { + lhs.append(rhs); + } + lhs + } + /// This is the fall-through for parsing items. fn parse_macro_use_or_failure( &mut self, diff --git a/src/libsyntax/tokenstream.rs b/src/libsyntax/tokenstream.rs index ac155556cdae2..0559f224f1f4b 100644 --- a/src/libsyntax/tokenstream.rs +++ b/src/libsyntax/tokenstream.rs @@ -19,7 +19,6 @@ use syntax_pos::{BytePos, Span, DUMMY_SP}; #[cfg(target_arch = "x86_64")] use rustc_data_structures::static_assert_size; use rustc_data_structures::sync::Lrc; -use rustc_serialize::{Decoder, Decodable, Encoder, Encodable}; use smallvec::{SmallVec, smallvec}; use std::{iter, mem}; @@ -136,7 +135,7 @@ impl TokenTree { /// The goal is for procedural macros to work with `TokenStream`s and `TokenTree`s /// instead of a representation of the abstract syntax tree. /// Today's `TokenTree`s can still contain AST via `token::Interpolated` for back-compat. -#[derive(Clone, Debug, Default)] +#[derive(Clone, Debug, Default, RustcEncodable, RustcDecodable)] pub struct TokenStream(pub Lrc>); pub type TreeAndJoint = (TokenTree, IsJoint); @@ -145,7 +144,7 @@ pub type TreeAndJoint = (TokenTree, IsJoint); #[cfg(target_arch = "x86_64")] static_assert_size!(TokenStream, 8); -#[derive(Clone, Copy, Debug, PartialEq)] +#[derive(Clone, Copy, Debug, PartialEq, RustcEncodable, RustcDecodable)] pub enum IsJoint { Joint, NonJoint @@ -460,18 +459,6 @@ impl Cursor { } } -impl Encodable for TokenStream { - fn encode(&self, encoder: &mut E) -> Result<(), E::Error> { - self.trees().collect::>().encode(encoder) - } -} - -impl Decodable for TokenStream { - fn decode(decoder: &mut D) -> Result { - Vec::::decode(decoder).map(|vec| vec.into_iter().collect()) - } -} - #[derive(Debug, Copy, Clone, PartialEq, RustcEncodable, RustcDecodable)] pub struct DelimSpan { pub open: Span, diff --git a/src/test/ui/asm/issue-51431.rs b/src/test/ui/asm/issue-51431.rs new file mode 100644 index 0000000000000..d29c31fafc286 --- /dev/null +++ b/src/test/ui/asm/issue-51431.rs @@ -0,0 +1,10 @@ +// ignore-emscripten no asm! support + +#![feature(asm)] + +fn main() { + unsafe { + asm! {"mov $0,$1"::"0"("bx"),"1"(0x00)} + //~^ ERROR: invalid value for constraint in inline assembly + } +} diff --git a/src/test/ui/asm/issue-51431.stderr b/src/test/ui/asm/issue-51431.stderr new file mode 100644 index 0000000000000..132eea126d642 --- /dev/null +++ b/src/test/ui/asm/issue-51431.stderr @@ -0,0 +1,8 @@ +error[E0669]: invalid value for constraint in inline assembly + --> $DIR/issue-51431.rs:7:32 + | +LL | asm! {"mov $0,$1"::"0"("bx"),"1"(0x00)} + | ^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/associated-const/issue-63496.rs b/src/test/ui/associated-const/issue-63496.rs new file mode 100644 index 0000000000000..311c48b5e48c5 --- /dev/null +++ b/src/test/ui/associated-const/issue-63496.rs @@ -0,0 +1,9 @@ +trait A { + const C: usize; + + fn f() -> ([u8; A::C], [u8; A::C]); + //~^ ERROR: type annotations needed: cannot resolve + //~| ERROR: type annotations needed: cannot resolve +} + +fn main() {} diff --git a/src/test/ui/associated-const/issue-63496.stderr b/src/test/ui/associated-const/issue-63496.stderr new file mode 100644 index 0000000000000..70bb12de1fb72 --- /dev/null +++ b/src/test/ui/associated-const/issue-63496.stderr @@ -0,0 +1,21 @@ +error[E0283]: type annotations needed: cannot resolve `_: A` + --> $DIR/issue-63496.rs:4:21 + | +LL | const C: usize; + | --------------- required by `A::C` +LL | +LL | fn f() -> ([u8; A::C], [u8; A::C]); + | ^^^^ + +error[E0283]: type annotations needed: cannot resolve `_: A` + --> $DIR/issue-63496.rs:4:33 + | +LL | const C: usize; + | --------------- required by `A::C` +LL | +LL | fn f() -> ([u8; A::C], [u8; A::C]); + | ^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0283`. diff --git a/src/test/ui/ast-json/ast-json-output.stdout b/src/test/ui/ast-json/ast-json-output.stdout index 563885133a4c1..64c9f69311582 100644 --- a/src/test/ui/ast-json/ast-json-output.stdout +++ b/src/test/ui/ast-json/ast-json-output.stdout @@ -1 +1 @@ -{"module":{"inner":{"lo":0,"hi":0},"items":[{"ident":{"name":"core","span":{"lo":0,"hi":0}},"attrs":[],"id":0,"kind":{"variant":"ExternCrate","fields":[null]},"vis":{"node":"Inherited","span":{"lo":0,"hi":0}},"span":{"lo":0,"hi":0},"tokens":[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["extern",false]},"span":{"lo":0,"hi":0}}]},{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["crate",false]},"span":{"lo":0,"hi":0}}]},{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["core",false]},"span":{"lo":0,"hi":0}}]},{"variant":"Token","fields":[{"kind":"Semi","span":{"lo":0,"hi":0}}]}]}],"inline":true},"attrs":[],"span":{"lo":0,"hi":0}} +{"module":{"inner":{"lo":0,"hi":0},"items":[{"ident":{"name":"core","span":{"lo":0,"hi":0}},"attrs":[],"id":0,"kind":{"variant":"ExternCrate","fields":[null]},"vis":{"node":"Inherited","span":{"lo":0,"hi":0}},"span":{"lo":0,"hi":0},"tokens":{"_field0":[[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["extern",false]},"span":{"lo":0,"hi":0}}]},"NonJoint"],[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["crate",false]},"span":{"lo":0,"hi":0}}]},"NonJoint"],[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["core",false]},"span":{"lo":0,"hi":0}}]},"NonJoint"],[{"variant":"Token","fields":[{"kind":"Semi","span":{"lo":0,"hi":0}}]},"NonJoint"]]}}],"inline":true},"attrs":[],"span":{"lo":0,"hi":0}} diff --git a/src/test/ui/closures/issue-41366.rs b/src/test/ui/closures/issue-41366.rs new file mode 100644 index 0000000000000..5cae0e76d1acb --- /dev/null +++ b/src/test/ui/closures/issue-41366.rs @@ -0,0 +1,13 @@ +trait T<'x> { + type V; +} + +impl<'g> T<'g> for u32 { + type V = u16; +} + +fn main() { + (&|_|()) as &dyn for<'x> Fn(>::V); + //~^ ERROR: type mismatch in closure arguments + //~| ERROR: type mismatch resolving +} diff --git a/src/test/ui/closures/issue-41366.stderr b/src/test/ui/closures/issue-41366.stderr new file mode 100644 index 0000000000000..91d26efbc4f35 --- /dev/null +++ b/src/test/ui/closures/issue-41366.stderr @@ -0,0 +1,22 @@ +error[E0631]: type mismatch in closure arguments + --> $DIR/issue-41366.rs:10:5 + | +LL | (&|_|()) as &dyn for<'x> Fn(>::V); + | ^^-----^ + | | | + | | found signature of `fn(_) -> _` + | expected signature of `for<'x> fn(>::V) -> _` + | + = note: required for the cast to the object type `dyn for<'x> std::ops::Fn(>::V)` + +error[E0271]: type mismatch resolving `for<'x> <[closure@$DIR/issue-41366.rs:10:7: 10:12] as std::ops::FnOnce<(>::V,)>>::Output == ()` + --> $DIR/issue-41366.rs:10:5 + | +LL | (&|_|()) as &dyn for<'x> Fn(>::V); + | ^^^^^^^^ expected bound lifetime parameter 'x, found concrete lifetime + | + = note: required for the cast to the object type `dyn for<'x> std::ops::Fn(>::V)` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0271`. diff --git a/src/test/ui/closures/issue-52437.rs b/src/test/ui/closures/issue-52437.rs new file mode 100644 index 0000000000000..6ac5380a5aa23 --- /dev/null +++ b/src/test/ui/closures/issue-52437.rs @@ -0,0 +1,5 @@ +fn main() { + [(); &(&'static: loop { |x| {}; }) as *const _ as usize] + //~^ ERROR: invalid label name `'static` + //~| ERROR: type annotations needed +} diff --git a/src/test/ui/closures/issue-52437.stderr b/src/test/ui/closures/issue-52437.stderr new file mode 100644 index 0000000000000..e76f942e9ba57 --- /dev/null +++ b/src/test/ui/closures/issue-52437.stderr @@ -0,0 +1,15 @@ +error: invalid label name `'static` + --> $DIR/issue-52437.rs:2:13 + | +LL | [(); &(&'static: loop { |x| {}; }) as *const _ as usize] + | ^^^^^^^ + +error[E0282]: type annotations needed + --> $DIR/issue-52437.rs:2:30 + | +LL | [(); &(&'static: loop { |x| {}; }) as *const _ as usize] + | ^ consider giving this closure parameter a type + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0282`. diff --git a/src/test/ui/consts/offset_from.rs b/src/test/ui/consts/offset_from.rs new file mode 100644 index 0000000000000..4d6800681889c --- /dev/null +++ b/src/test/ui/consts/offset_from.rs @@ -0,0 +1,47 @@ +// run-pass + +#![feature(const_raw_ptr_deref)] +#![feature(const_ptr_offset_from)] +#![feature(ptr_offset_from)] + +struct Struct { + field: (), +} + +#[repr(C)] +struct Struct2 { + data: u8, + field: u8, +} + +pub const OFFSET: usize = { + let uninit = std::mem::MaybeUninit::::uninit(); + let base_ptr: *const Struct = &uninit as *const _ as *const Struct; + // The following statement is UB (taking the address of an uninitialized field). + // Const eval doesn't detect this right now, but it may stop compiling at some point + // in the future. + let field_ptr = unsafe { &(*base_ptr).field as *const () as *const u8 }; + let offset = unsafe { field_ptr.offset_from(base_ptr as *const u8) }; + offset as usize +}; + +pub const OFFSET_2: usize = { + let uninit = std::mem::MaybeUninit::::uninit(); + let base_ptr: *const Struct2 = &uninit as *const _ as *const Struct2; + let field_ptr = unsafe { &(*base_ptr).field as *const u8 }; + let offset = unsafe { field_ptr.offset_from(base_ptr as *const u8) }; + offset as usize +}; + +pub const OVERFLOW: isize = { + let uninit = std::mem::MaybeUninit::::uninit(); + let base_ptr: *const Struct2 = &uninit as *const _ as *const Struct2; + let field_ptr = unsafe { &(*base_ptr).field as *const u8 }; + unsafe { (base_ptr as *const u8).offset_from(field_ptr) } +}; + +fn main() { + assert_eq!(OFFSET, 0); + assert_eq!(OFFSET_2, 1); + assert_eq!(OVERFLOW, -1); +} diff --git a/src/test/ui/consts/offset_from_ub.rs b/src/test/ui/consts/offset_from_ub.rs new file mode 100644 index 0000000000000..a233c24a7c52c --- /dev/null +++ b/src/test/ui/consts/offset_from_ub.rs @@ -0,0 +1,38 @@ +// ingoring on musl because it's ui output hides libcore backtraces +// ignore-musl + +#![feature(const_raw_ptr_deref)] +#![feature(const_ptr_offset_from)] +#![feature(ptr_offset_from)] + +#[repr(C)] +struct Struct { + data: u8, + field: u8, +} + +pub const DIFFERENT_ALLOC: usize = { + //~^ NOTE + let uninit = std::mem::MaybeUninit::::uninit(); + let base_ptr: *const Struct = &uninit as *const _ as *const Struct; + let uninit2 = std::mem::MaybeUninit::::uninit(); + let field_ptr: *const Struct = &uninit2 as *const _ as *const Struct; + let offset = unsafe { field_ptr.offset_from(base_ptr) }; + offset as usize +}; + +pub const NOT_PTR: usize = { + //~^ NOTE + unsafe { (42 as *const u8).offset_from(&5u8) as usize } +}; + +pub const NOT_MULTIPLE_OF_SIZE: usize = { + //~^ NOTE + let data = [5u8, 6, 7]; + let base_ptr = data.as_ptr(); + let field_ptr = &data[1] as *const u8 as *const u16; + let offset = unsafe { field_ptr.offset_from(base_ptr as *const u16) }; + offset as usize +}; + +fn main() {} diff --git a/src/test/ui/consts/offset_from_ub.stderr b/src/test/ui/consts/offset_from_ub.stderr new file mode 100644 index 0000000000000..1460170a108cb --- /dev/null +++ b/src/test/ui/consts/offset_from_ub.stderr @@ -0,0 +1,61 @@ +error: any use of this value will cause an error + --> $SRC_DIR/libcore/ptr/mod.rs:LL:COL + | +LL | intrinsics::ptr_offset_from(self, origin) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | ptr_offset_from cannot compute offset of pointers into different allocations. + | inside call to `std::ptr::::offset_from` at $DIR/offset_from_ub.rs:20:27 + | + ::: $DIR/offset_from_ub.rs:14:1 + | +LL | / pub const DIFFERENT_ALLOC: usize = { +LL | | +LL | | let uninit = std::mem::MaybeUninit::::uninit(); +LL | | let base_ptr: *const Struct = &uninit as *const _ as *const Struct; +... | +LL | | offset as usize +LL | | }; + | |__- + | + = note: `#[deny(const_err)]` on by default + +error: any use of this value will cause an error + --> $SRC_DIR/libcore/ptr/mod.rs:LL:COL + | +LL | intrinsics::ptr_offset_from(self, origin) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | a memory access tried to interpret some bytes as a pointer + | inside call to `std::ptr::::offset_from` at $DIR/offset_from_ub.rs:26:14 + | + ::: $DIR/offset_from_ub.rs:24:1 + | +LL | / pub const NOT_PTR: usize = { +LL | | +LL | | unsafe { (42 as *const u8).offset_from(&5u8) as usize } +LL | | }; + | |__- + +error: any use of this value will cause an error + --> $SRC_DIR/libcore/ptr/mod.rs:LL:COL + | +LL | intrinsics::ptr_offset_from(self, origin) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | exact_div: 1 cannot be divided by 2 without remainder + | inside call to `std::ptr::::offset_from` at $DIR/offset_from_ub.rs:34:27 + | + ::: $DIR/offset_from_ub.rs:29:1 + | +LL | / pub const NOT_MULTIPLE_OF_SIZE: usize = { +LL | | +LL | | let data = [5u8, 6, 7]; +LL | | let base_ptr = data.as_ptr(); +... | +LL | | offset as usize +LL | | }; + | |__- + +error: aborting due to 3 previous errors + diff --git a/src/test/ui/offset_from.rs b/src/test/ui/offset_from.rs new file mode 100644 index 0000000000000..cbbb2adf15f91 --- /dev/null +++ b/src/test/ui/offset_from.rs @@ -0,0 +1,15 @@ +// run-pass + +#![feature(ptr_offset_from)] + +fn main() { + let mut a = [0; 5]; + let ptr1: *mut i32 = &mut a[1]; + let ptr2: *mut i32 = &mut a[3]; + unsafe { + assert_eq!(ptr2.offset_from(ptr1), 2); + assert_eq!(ptr1.offset_from(ptr2), -2); + assert_eq!(ptr1.offset(2), ptr2); + assert_eq!(ptr2.offset(-2), ptr1); + } +}