From 3d33d05c81f949f743b3441cc1e960f2dc2bd5ac Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Sat, 17 Nov 2018 13:55:35 +0100 Subject: [PATCH 01/29] We're looking at the miri memory for constants instead of their initializers' MIR --- src/librustc_mir/monomorphize/collector.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/librustc_mir/monomorphize/collector.rs b/src/librustc_mir/monomorphize/collector.rs index 8e27635dee8c1..92318755ff521 100644 --- a/src/librustc_mir/monomorphize/collector.rs +++ b/src/librustc_mir/monomorphize/collector.rs @@ -178,10 +178,6 @@ //! Some things are not yet fully implemented in the current version of this //! module. //! -//! ### Initializers of Constants and Statics -//! Since no MIR is constructed yet for initializer expressions of constants and -//! statics we cannot inspect these properly. -//! //! ### Const Fns //! Ideally, no mono item should be generated for const fns unless there //! is a call to them that cannot be evaluated at compile time. At the moment From ef99b57b13f9ab04f44dd9c5c325be8f0b6b9dc1 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Sat, 17 Nov 2018 15:05:12 +0100 Subject: [PATCH 02/29] Refactor local monomorphization logic to be easier to comprehend --- src/librustc_mir/monomorphize/collector.rs | 43 +++++++++++----------- 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/src/librustc_mir/monomorphize/collector.rs b/src/librustc_mir/monomorphize/collector.rs index 92318755ff521..977285b27be38 100644 --- a/src/librustc_mir/monomorphize/collector.rs +++ b/src/librustc_mir/monomorphize/collector.rs @@ -187,7 +187,6 @@ use rustc::hir::{self, CodegenFnAttrFlags}; use rustc::hir::itemlikevisit::ItemLikeVisitor; -use rustc::hir::Node; use rustc::hir::def_id::DefId; use rustc::mir::interpret::{AllocId, ConstValue}; use rustc::middle::lang_items::{ExchangeMallocFnLangItem, StartFnLangItem}; @@ -737,27 +736,27 @@ fn should_monomorphize_locally<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, instance: ty::InstanceDef::CloneShim(..) => return true }; - return match tcx.hir.get_if_local(def_id) { - Some(Node::ForeignItem(..)) => { - false // foreign items are linked against, not codegened. - } - Some(_) => true, - None => { - if tcx.is_reachable_non_generic(def_id) || - tcx.is_foreign_item(def_id) || - is_available_upstream_generic(tcx, def_id, instance.substs) - { - // We can link to the item in question, no instance needed - // in this crate - false - } else { - if !tcx.is_mir_available(def_id) { - bug!("Cannot create local mono-item for {:?}", def_id) - } - true - } - } - }; + if tcx.is_foreign_item(def_id) { + // We can always link to foreign items + return false; + } + + if def_id.is_local() { + // local items cannot be referred to locally without monomorphizing them locally + return true; + } + + if tcx.is_reachable_non_generic(def_id) || + is_available_upstream_generic(tcx, def_id, instance.substs) { + // We can link to the item in question, no instance needed + // in this crate + return false; + } + + if !tcx.is_mir_available(def_id) { + bug!("Cannot create local mono-item for {:?}", def_id) + } + return true; fn is_available_upstream_generic<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId, From eb18ddd8f4fede5e12a97f724014a8406dd75881 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Sat, 17 Nov 2018 15:36:06 +0100 Subject: [PATCH 03/29] Don't auto-inline `const fn` --- src/librustc/ty/instance.rs | 5 +---- .../item-collection/unreferenced-const-fn.rs | 3 +-- src/test/ui/consts/auxiliary/const_fn_lib.rs | 20 ++++++++++++++++++- .../consts/const_fn_return_nested_fn_ptr.rs | 10 ++++++++++ 4 files changed, 31 insertions(+), 7 deletions(-) create mode 100644 src/test/ui/consts/const_fn_return_nested_fn_ptr.rs diff --git a/src/librustc/ty/instance.rs b/src/librustc/ty/instance.rs index b6691df39c120..411a6e7e6238e 100644 --- a/src/librustc/ty/instance.rs +++ b/src/librustc/ty/instance.rs @@ -173,10 +173,7 @@ impl<'tcx> InstanceDef<'tcx> { // available to normal end-users. return true } - let codegen_fn_attrs = tcx.codegen_fn_attrs(self.def_id()); - // need to use `is_const_fn_raw` since we don't really care if the user can use it as a - // const fn, just whether the function should be inlined - codegen_fn_attrs.requests_inline() || tcx.is_const_fn_raw(self.def_id()) + tcx.codegen_fn_attrs(self.def_id()).requests_inline() } } diff --git a/src/test/codegen-units/item-collection/unreferenced-const-fn.rs b/src/test/codegen-units/item-collection/unreferenced-const-fn.rs index c4a49fd4ec4d6..5e181870fed65 100644 --- a/src/test/codegen-units/item-collection/unreferenced-const-fn.rs +++ b/src/test/codegen-units/item-collection/unreferenced-const-fn.rs @@ -11,11 +11,10 @@ // ignore-tidy-linelength // compile-flags:-Zprint-mono-items=lazy -// NB: We do not expect *any* monomorphization to be generated here. - #![deny(dead_code)] #![crate_type = "rlib"] +//~ MONO_ITEM fn unreferenced_const_fn::foo[0] @@ unreferenced_const_fn-cgu.0[External] pub const fn foo(x: u32) -> u32 { x + 0xf00 } diff --git a/src/test/ui/consts/auxiliary/const_fn_lib.rs b/src/test/ui/consts/auxiliary/const_fn_lib.rs index 5063c8d1d1f54..72369aae97ce3 100644 --- a/src/test/ui/consts/auxiliary/const_fn_lib.rs +++ b/src/test/ui/consts/auxiliary/const_fn_lib.rs @@ -10,6 +10,24 @@ // Crate that exports a const fn. Used for testing cross-crate. +#![feature(const_fn)] #![crate_type="rlib"] -pub const fn foo() -> usize { 22 } //~ ERROR const fn is unstable +pub const fn foo() -> usize { 22 } + +pub const fn bar() -> fn() { + fn x() {} + x +} + +#[inline] +pub const fn bar_inlined() -> fn() { + fn x() {} + x +} + +#[inline(always)] +pub const fn bar_inlined_always() -> fn() { + fn x() {} + x +} diff --git a/src/test/ui/consts/const_fn_return_nested_fn_ptr.rs b/src/test/ui/consts/const_fn_return_nested_fn_ptr.rs new file mode 100644 index 0000000000000..c7617c9c7ad03 --- /dev/null +++ b/src/test/ui/consts/const_fn_return_nested_fn_ptr.rs @@ -0,0 +1,10 @@ +// compile-pass +// aux-build:const_fn_lib.rs + +extern crate const_fn_lib; + +fn main() { + const_fn_lib::bar()(); + const_fn_lib::bar_inlined()(); + const_fn_lib::bar_inlined_always()(); +} From 089a50411f3bceb233dd5da8057252ff7b6b47e1 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 19 Nov 2018 12:05:21 -0800 Subject: [PATCH 04/29] Encode a custom "producers" section in wasm files This commit implements WebAssembly/tool-conventions#65 for wasm files produced by the Rust compiler. This adds a bit of metadata to wasm modules to indicate that the file's language includes Rust and the file's "processed-by" tools includes rustc. The thinking with this section is to eventually have telemetry in browsers tracking all this. --- src/librustc_codegen_llvm/back/link.rs | 5 ++ src/librustc_codegen_llvm/back/wasm.rs | 107 +++++++++++++++++++++++++ 2 files changed, 112 insertions(+) diff --git a/src/librustc_codegen_llvm/back/link.rs b/src/librustc_codegen_llvm/back/link.rs index 20f05d110877a..fa9a852ad0135 100644 --- a/src/librustc_codegen_llvm/back/link.rs +++ b/src/librustc_codegen_llvm/back/link.rs @@ -692,6 +692,11 @@ fn link_natively(sess: &Session, if sess.opts.target_triple.triple() == "wasm32-unknown-unknown" { wasm::rewrite_imports(&out_filename, &codegen_results.crate_info.wasm_imports); + wasm::add_producer_section( + &out_filename, + &sess.edition().to_string(), + option_env!("CFG_VERSION").unwrap_or("unknown"), + ); } } diff --git a/src/librustc_codegen_llvm/back/wasm.rs b/src/librustc_codegen_llvm/back/wasm.rs index 7101255173caf..1a5c65f3c4397 100644 --- a/src/librustc_codegen_llvm/back/wasm.rs +++ b/src/librustc_codegen_llvm/back/wasm.rs @@ -17,6 +17,7 @@ use serialize::leb128; // https://webassembly.github.io/spec/core/binary/modules.html#binary-importsec const WASM_IMPORT_SECTION_ID: u8 = 2; +const WASM_CUSTOM_SECTION_ID: u8 = 0; const WASM_EXTERNAL_KIND_FUNCTION: u8 = 0; const WASM_EXTERNAL_KIND_TABLE: u8 = 1; @@ -121,6 +122,112 @@ pub fn rewrite_imports(path: &Path, import_map: &FxHashMap) { } } +/// Add or augment the existing `producers` section to encode information about +/// the Rust compiler used to produce the wasm file. +pub fn add_producer_section( + path: &Path, + rust_version: &str, + rustc_version: &str, +) { + struct Field<'a> { + name: &'a str, + values: Vec>, + } + + #[derive(Copy, Clone)] + struct FieldValue<'a> { + name: &'a str, + version: &'a str, + } + + let wasm = fs::read(path).expect("failed to read wasm output"); + let mut ret = WasmEncoder::new(); + ret.data.extend(&wasm[..8]); + + // skip the 8 byte wasm/version header + let rustc_value = FieldValue { + name: "rustc", + version: rustc_version, + }; + let rust_value = FieldValue { + name: "Rust", + version: rust_version, + }; + let mut fields = Vec::new(); + let mut wrote_rustc = false; + let mut wrote_rust = false; + + // Move all sections from the original wasm file to our output, skipping + // everything except the producers section + for (id, raw) in WasmSections(WasmDecoder::new(&wasm[8..])) { + if id != WASM_CUSTOM_SECTION_ID { + ret.byte(id); + ret.bytes(raw); + continue + } + let mut decoder = WasmDecoder::new(raw); + if decoder.str() != "producers" { + ret.byte(id); + ret.bytes(raw); + continue + } + + // Read off the producers section into our fields outside the loop, + // we'll re-encode the producers section when we're done (to handle an + // entirely missing producers section as well). + info!("rewriting existing producers section"); + + for _ in 0..decoder.u32() { + let name = decoder.str(); + let mut values = Vec::new(); + for _ in 0..decoder.u32() { + let name = decoder.str(); + let version = decoder.str(); + values.push(FieldValue { name, version }); + } + + if name == "language" { + values.push(rust_value); + wrote_rust = true; + } else if name == "processed-by" { + values.push(rustc_value); + wrote_rustc = true; + } + fields.push(Field { name, values }); + } + } + + if !wrote_rust { + fields.push(Field { + name: "language", + values: vec![rust_value], + }); + } + if !wrote_rustc { + fields.push(Field { + name: "processed-by", + values: vec![rustc_value], + }); + } + + // Append the producers section to the end of the wasm file. + let mut section = WasmEncoder::new(); + section.str("producers"); + section.u32(fields.len() as u32); + for field in fields { + section.str(field.name); + section.u32(field.values.len() as u32); + for value in field.values { + section.str(value.name); + section.str(value.version); + } + } + ret.byte(WASM_CUSTOM_SECTION_ID); + ret.bytes(§ion.data); + + fs::write(path, &ret.data).expect("failed to write wasm output"); +} + struct WasmSections<'a>(WasmDecoder<'a>); impl<'a> Iterator for WasmSections<'a> { From 6eeedbcd70855b45cf41ef14bc91a15f0ee67c7c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 20 Nov 2018 15:08:26 +0100 Subject: [PATCH 05/29] generator fields are not necessarily initialized --- src/librustc_mir/interpret/visitor.rs | 33 ++++++++++++++++++--------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/src/librustc_mir/interpret/visitor.rs b/src/librustc_mir/interpret/visitor.rs index f0a71242599bf..505195763d062 100644 --- a/src/librustc_mir/interpret/visitor.rs +++ b/src/librustc_mir/interpret/visitor.rs @@ -142,6 +142,7 @@ macro_rules! make_value_visitor { self.walk_value(v) } /// Visit the given value as a union. No automatic recursion can happen here. + /// Also called for the fields of a generator, which may or may not be initialized. #[inline(always)] fn visit_union(&mut self, _v: Self::V) -> EvalResult<'tcx> { @@ -291,17 +292,28 @@ macro_rules! make_value_visitor { // use that as an unambiguous signal for detecting primitives. Make sure // we did not miss any primitive. debug_assert!(fields > 0); - self.visit_union(v)?; + self.visit_union(v) }, layout::FieldPlacement::Arbitrary { ref offsets, .. } => { - // FIXME: We collect in a vec because otherwise there are lifetime errors: - // Projecting to a field needs (mutable!) access to `ecx`. - let fields: Vec> = - (0..offsets.len()).map(|i| { - v.project_field(self.ecx(), i as u64) - }) - .collect(); - self.visit_aggregate(v, fields.into_iter())?; + // Special handling needed for generators: All but the first field + // (which is the state) are actually implicitly `MaybeUninit`, i.e., + // they may or may not be initialized, so we cannot visit them. + match v.layout().ty.sty { + ty::Generator(..) => { + let field = v.project_field(self.ecx(), 0)?; + self.visit_aggregate(v, std::iter::once(Ok(field))) + } + _ => { + // FIXME: We collect in a vec because otherwise there are lifetime + // errors: Projecting to a field needs access to `ecx`. + let fields: Vec> = + (0..offsets.len()).map(|i| { + v.project_field(self.ecx(), i as u64) + }) + .collect(); + self.visit_aggregate(v, fields.into_iter()) + } + } }, layout::FieldPlacement::Array { .. } => { // Let's get an mplace first. @@ -317,10 +329,9 @@ macro_rules! make_value_visitor { .map(|f| f.and_then(|f| { Ok(Value::from_mem_place(f)) })); - self.visit_aggregate(v, iter)?; + self.visit_aggregate(v, iter) } } - Ok(()) } } } From 033cbfec4d3bb23948a99379f8d63b7cfe5eed45 Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Tue, 20 Nov 2018 09:34:15 -0500 Subject: [PATCH 06/29] Incorporate `dyn` into more comments and docs. --- src/liballoc/boxed.rs | 16 ++++++++-------- src/liballoc/rc.rs | 4 ++-- src/libcore/raw.rs | 2 +- src/librustc/mir/mod.rs | 2 +- src/librustc/ty/adjustment.rs | 2 +- src/librustc/ty/util.rs | 2 +- src/librustc_codegen_ssa/meth.rs | 2 +- src/libstd/fs.rs | 4 ++-- src/test/run-pass/string-box-error.rs | 3 ++- 9 files changed, 19 insertions(+), 18 deletions(-) diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index 63b262d1f3d98..c3a84bf778d03 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -489,7 +489,7 @@ impl Box { /// ``` /// use std::any::Any; /// - /// fn print_if_string(value: Box) { + /// fn print_if_string(value: Box) { /// if let Ok(string) = value.downcast::() { /// println!("String ({}): {}", string.len(), string); /// } @@ -523,7 +523,7 @@ impl Box { /// ``` /// use std::any::Any; /// - /// fn print_if_string(value: Box) { + /// fn print_if_string(value: Box) { /// if let Ok(string) = value.downcast::() { /// println!("String ({}): {}", string.len(), string); /// } @@ -618,10 +618,10 @@ impl FusedIterator for Box {} /// `FnBox` is a version of the `FnOnce` intended for use with boxed /// closure objects. The idea is that where one would normally store a -/// `Box` in a data structure, you should use -/// `Box`. The two traits behave essentially the same, except +/// `Box` in a data structure, you should use +/// `Box`. The two traits behave essentially the same, except /// that a `FnBox` closure can only be called if it is boxed. (Note -/// that `FnBox` may be deprecated in the future if `Box` +/// that `FnBox` may be deprecated in the future if `Box` /// closures become directly usable.) /// /// # Examples @@ -629,7 +629,7 @@ impl FusedIterator for Box {} /// Here is a snippet of code which creates a hashmap full of boxed /// once closures and then removes them one by one, calling each /// closure as it is removed. Note that the type of the closures -/// stored in the map is `Box i32>` and not `Box i32>` and not `Box i32>`. /// /// ``` @@ -638,8 +638,8 @@ impl FusedIterator for Box {} /// use std::boxed::FnBox; /// use std::collections::HashMap; /// -/// fn make_map() -> HashMap i32>> { -/// let mut map: HashMap i32>> = HashMap::new(); +/// fn make_map() -> HashMap i32>> { +/// let mut map: HashMap i32>> = HashMap::new(); /// map.insert(1, Box::new(|| 22)); /// map.insert(2, Box::new(|| 44)); /// map diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index bb52d7990ff57..12c19912662fc 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -634,7 +634,7 @@ impl Rc { impl Rc { #[inline] #[stable(feature = "rc_downcast", since = "1.29.0")] - /// Attempt to downcast the `Rc` to a concrete type. + /// Attempt to downcast the `Rc` to a concrete type. /// /// # Examples /// @@ -642,7 +642,7 @@ impl Rc { /// use std::any::Any; /// use std::rc::Rc; /// - /// fn print_if_string(value: Rc) { + /// fn print_if_string(value: Rc) { /// if let Ok(string) = value.downcast::() { /// println!("String ({}): {}", string.len(), string); /// } diff --git a/src/libcore/raw.rs b/src/libcore/raw.rs index a95f05227fb8b..b7597795b5e62 100644 --- a/src/libcore/raw.rs +++ b/src/libcore/raw.rs @@ -21,7 +21,7 @@ /// The representation of a trait object like `&SomeTrait`. /// /// This struct has the same layout as types like `&SomeTrait` and -/// `Box`. The [Trait Objects chapter of the +/// `Box`. The [Trait Objects chapter of the /// Book][moreinfo] contains more details about the precise nature of /// these internals. /// diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index d8e45c881f555..acc03bd4a48b1 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -2207,7 +2207,7 @@ pub enum CastKind { /// "Unsize" -- convert a thin-or-fat pointer to a fat pointer. /// codegen must figure out the details once full monomorphization /// is known. For example, this could be used to cast from a - /// `&[i32;N]` to a `&[i32]`, or a `Box` to a `Box` + /// `&[i32;N]` to a `&[i32]`, or a `Box` to a `Box` /// (presuming `T: Trait`). Unsize, } diff --git a/src/librustc/ty/adjustment.rs b/src/librustc/ty/adjustment.rs index 3263da8fda365..83521c5f72406 100644 --- a/src/librustc/ty/adjustment.rs +++ b/src/librustc/ty/adjustment.rs @@ -48,7 +48,7 @@ use ty::subst::Substs; /// stored in `unsize` is `Foo<[i32]>`, we don't store any further detail about /// the underlying conversions from `[i32; 4]` to `[i32]`. /// -/// 3. Coercing a `Box` to `Box` is an interesting special case. In +/// 3. Coercing a `Box` to `Box` is an interesting special case. In /// that case, we have the pointer we need coming in, so there are no /// autoderefs, and no autoref. Instead we just do the `Unsize` transformation. /// At some point, of course, `Box` should move out of the compiler, in which diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index 3d0c54d6b0a5b..0d756aa078195 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -303,7 +303,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { /// Same as applying struct_tail on `source` and `target`, but only /// keeps going as long as the two types are instances of the same /// structure definitions. - /// For `(Foo>, Foo)`, the result will be `(Foo, Trait)`, + /// For `(Foo>, Foo)`, the result will be `(Foo, Trait)`, /// whereas struct_tail produces `T`, and `Trait`, respectively. pub fn struct_lockstep_tails(self, source: Ty<'tcx>, diff --git a/src/librustc_codegen_ssa/meth.rs b/src/librustc_codegen_ssa/meth.rs index 06c4f7a87d880..24be932141c7e 100644 --- a/src/librustc_codegen_ssa/meth.rs +++ b/src/librustc_codegen_ssa/meth.rs @@ -74,7 +74,7 @@ impl<'a, 'tcx: 'a> VirtualIndex { /// The vtables are cached instead of created on every call. /// /// The `trait_ref` encodes the erased self type. Hence if we are -/// making an object `Foo` from a value of type `Foo`, then +/// making an object `Foo` from a value of type `Foo`, then /// `trait_ref` would map `T:Trait`. pub fn get_vtable<'tcx, Cx: CodegenMethods<'tcx>>( cx: &Cx, diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs index f4703dec187b8..92678dd5cede0 100644 --- a/src/libstd/fs.rs +++ b/src/libstd/fs.rs @@ -256,7 +256,7 @@ fn initial_buffer_size(file: &File) -> usize { /// use std::fs; /// use std::net::SocketAddr; /// -/// fn main() -> Result<(), Box> { +/// fn main() -> Result<(), Box> { /// let foo: SocketAddr = String::from_utf8_lossy(&fs::read("address.txt")?).parse()?; /// Ok(()) /// } @@ -298,7 +298,7 @@ pub fn read>(path: P) -> io::Result> { /// use std::fs; /// use std::net::SocketAddr; /// -/// fn main() -> Result<(), Box> { +/// fn main() -> Result<(), Box> { /// let foo: SocketAddr = fs::read_to_string("address.txt")?.parse()?; /// Ok(()) /// } diff --git a/src/test/run-pass/string-box-error.rs b/src/test/run-pass/string-box-error.rs index a80d9a0593566..5d8a664b93dad 100644 --- a/src/test/run-pass/string-box-error.rs +++ b/src/test/run-pass/string-box-error.rs @@ -8,7 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// Ensure that both `Box` and `Box` can be obtained from `String`. +// Ensure that both `Box` and `Box` can be +// obtained from `String`. use std::error::Error; From 7f1077700c019b2dc8d651528ecad106c9267858 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 20 Nov 2018 15:55:23 +0100 Subject: [PATCH 07/29] fix comment --- src/librustc_mir/interpret/visitor.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/librustc_mir/interpret/visitor.rs b/src/librustc_mir/interpret/visitor.rs index 505195763d062..a645e06732269 100644 --- a/src/librustc_mir/interpret/visitor.rs +++ b/src/librustc_mir/interpret/visitor.rs @@ -142,7 +142,6 @@ macro_rules! make_value_visitor { self.walk_value(v) } /// Visit the given value as a union. No automatic recursion can happen here. - /// Also called for the fields of a generator, which may or may not be initialized. #[inline(always)] fn visit_union(&mut self, _v: Self::V) -> EvalResult<'tcx> { From 6befe6784f37d953884ef05982b41c3a11932170 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 20 Nov 2018 16:19:24 +0100 Subject: [PATCH 08/29] treat generator fields like unions --- src/librustc_mir/interpret/visitor.rs | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/src/librustc_mir/interpret/visitor.rs b/src/librustc_mir/interpret/visitor.rs index a645e06732269..81e56f3115d26 100644 --- a/src/librustc_mir/interpret/visitor.rs +++ b/src/librustc_mir/interpret/visitor.rs @@ -158,7 +158,9 @@ macro_rules! make_value_visitor { ) -> EvalResult<'tcx> { self.walk_aggregate(v, fields) } - /// Called each time we recurse down to a field, passing in old and new value. + + /// Called each time we recurse down to a field of a "product-like" aggregate + /// (structs, tuples, arrays and the like, but not enums), passing in old and new value. /// This gives the visitor the chance to track the stack of nested fields that /// we are descending through. #[inline(always)] @@ -171,6 +173,19 @@ macro_rules! make_value_visitor { self.visit_value(new_val) } + /// Called for recursing into the field of a generator. These are not known to be + /// initialized, so we treat them like unions. + #[inline(always)] + fn visit_generator_field( + &mut self, + _old_val: Self::V, + _field: usize, + new_val: Self::V, + ) -> EvalResult<'tcx> { + self.visit_union(new_val) + } + + /// Called when recursing into an enum variant. #[inline(always)] fn visit_variant( &mut self, @@ -300,7 +315,12 @@ macro_rules! make_value_visitor { match v.layout().ty.sty { ty::Generator(..) => { let field = v.project_field(self.ecx(), 0)?; - self.visit_aggregate(v, std::iter::once(Ok(field))) + self.visit_aggregate(v, std::iter::once(Ok(field)))?; + for i in 1..offsets.len() { + let field = v.project_field(self.ecx(), i as u64)?; + self.visit_generator_field(v, i, field)?; + } + Ok(()) } _ => { // FIXME: We collect in a vec because otherwise there are lifetime From 682b33a1103695de3c6520d55204b3c3d45f68ec Mon Sep 17 00:00:00 2001 From: Masaki Hara Date: Mon, 19 Nov 2018 00:15:41 +0900 Subject: [PATCH 09/29] Add require_type_is_sized_deferred. --- src/librustc_typeck/check/mod.rs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index aabef5c323483..b882d982c1fe5 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -208,6 +208,10 @@ pub struct Inherited<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { fulfillment_cx: RefCell>>, + // Some additional `Sized` obligations badly affect type inference. + // These obligations are added in a later stage of typeck. + deferred_sized_obligations: RefCell, Span, traits::ObligationCauseCode<'tcx>)>>, + // When we process a call like `c()` where `c` is a closure type, // we may not have decided yet whether `c` is a `Fn`, `FnMut`, or // `FnOnce` closure. In that case, we defer full resolution of the @@ -644,6 +648,7 @@ impl<'a, 'gcx, 'tcx> Inherited<'a, 'gcx, 'tcx> { infcx, fulfillment_cx: RefCell::new(TraitEngine::new(tcx)), locals: RefCell::new(Default::default()), + deferred_sized_obligations: RefCell::new(Vec::new()), deferred_call_resolutions: RefCell::new(Default::default()), deferred_cast_checks: RefCell::new(Vec::new()), deferred_generator_interiors: RefCell::new(Vec::new()), @@ -907,6 +912,10 @@ fn typeck_tables_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, fcx.closure_analyze(body); assert!(fcx.deferred_call_resolutions.borrow().is_empty()); fcx.resolve_generator_interiors(def_id); + + for (ty, span, code) in fcx.deferred_sized_obligations.borrow_mut().drain(..) { + fcx.require_type_is_sized(ty, span, code); + } fcx.select_all_obligations_or_error(); if fn_decl.is_some() { @@ -2345,6 +2354,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.require_type_meets(ty, span, code, lang_item); } + pub fn require_type_is_sized_deferred(&self, + ty: Ty<'tcx>, + span: Span, + code: traits::ObligationCauseCode<'tcx>) + { + self.deferred_sized_obligations.borrow_mut().push((ty, span, code)); + } + pub fn register_bound(&self, ty: Ty<'tcx>, def_id: DefId, From 8b426232eef0629265bbfd0bc81fab75e113762b Mon Sep 17 00:00:00 2001 From: Masaki Hara Date: Mon, 19 Nov 2018 00:18:13 +0900 Subject: [PATCH 10/29] Check arg/ret sizedness at ExprKind::Path. --- src/librustc_typeck/check/mod.rs | 25 +++++++++++++++++++ src/test/ui/issues/issue-30355.nll.stderr | 22 ---------------- src/test/ui/issues/issue-30355.rs | 4 +-- src/test/ui/issues/issue-30355.stderr | 24 ++++++------------ src/test/ui/unsized-locals/unsized-exprs.rs | 2 ++ .../ui/unsized-locals/unsized-exprs.stderr | 13 +++++++++- src/test/ui/unsized-locals/unsized-exprs2.rs | 2 -- 7 files changed, 48 insertions(+), 44 deletions(-) delete mode 100644 src/test/ui/issues/issue-30355.nll.stderr diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index b882d982c1fe5..572979d063d2f 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -3956,6 +3956,31 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { tcx.types.err }; + if let ty::FnDef(..) = ty.sty { + let fn_sig = ty.fn_sig(tcx); + if !tcx.features().unsized_locals { + // We want to remove some Sized bounds from std functions, + // but don't want to expose the removal to stable Rust. + // i.e. we don't want to allow + // + // ```rust + // drop as fn(str); + // ``` + // + // to work in stable even if the Sized bound on `drop` is relaxed. + for i in 0..fn_sig.inputs().skip_binder().len() { + let input = tcx.erase_late_bound_regions(&fn_sig.input(i)); + self.require_type_is_sized_deferred(input, expr.span, + traits::SizedArgumentType); + } + } + // Here we want to prevent struct constructors from returning unsized types. + // There were two cases this happened: fn pointer coercion in stable + // and usual function call in presense of unsized_locals. + let output = tcx.erase_late_bound_regions(&fn_sig.output()); + self.require_type_is_sized_deferred(output, expr.span, traits::SizedReturnType); + } + // We always require that the type provided as the value for // a type parameter outlives the moment of instantiation. let substs = self.tables.borrow().node_substs(expr.hir_id); diff --git a/src/test/ui/issues/issue-30355.nll.stderr b/src/test/ui/issues/issue-30355.nll.stderr deleted file mode 100644 index fdf8157dcf833..0000000000000 --- a/src/test/ui/issues/issue-30355.nll.stderr +++ /dev/null @@ -1,22 +0,0 @@ -error[E0161]: cannot move a value of type X: the size of X cannot be statically determined - --> $DIR/issue-30355.rs:15:6 - | -LL | &X(*Y) - | ^^^^^ - -error[E0161]: cannot move a value of type [u8]: the size of [u8] cannot be statically determined - --> $DIR/issue-30355.rs:15:8 - | -LL | &X(*Y) - | ^^ - -error[E0508]: cannot move out of type `[u8]`, a non-copy slice - --> $DIR/issue-30355.rs:15:8 - | -LL | &X(*Y) - | ^^ cannot move out of here - -error: aborting due to 3 previous errors - -Some errors occurred: E0161, E0508. -For more information about an error, try `rustc --explain E0161`. diff --git a/src/test/ui/issues/issue-30355.rs b/src/test/ui/issues/issue-30355.rs index ee19d04031893..8d5eac06c4379 100644 --- a/src/test/ui/issues/issue-30355.rs +++ b/src/test/ui/issues/issue-30355.rs @@ -13,9 +13,7 @@ pub struct X([u8]); pub static Y: &'static X = { const Y: &'static [u8] = b""; &X(*Y) - //~^ ERROR cannot move out - //~^^ ERROR cannot move a - //~^^^ ERROR cannot move a + //~^ ERROR E0277 }; fn main() {} diff --git a/src/test/ui/issues/issue-30355.stderr b/src/test/ui/issues/issue-30355.stderr index 7e843688035af..1b55f20e6b431 100644 --- a/src/test/ui/issues/issue-30355.stderr +++ b/src/test/ui/issues/issue-30355.stderr @@ -1,22 +1,14 @@ -error[E0161]: cannot move a value of type X: the size of X cannot be statically determined +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> $DIR/issue-30355.rs:15:6 | LL | &X(*Y) - | ^^^^^ - -error[E0161]: cannot move a value of type [u8]: the size of [u8] cannot be statically determined - --> $DIR/issue-30355.rs:15:8 + | ^ doesn't have a size known at compile-time | -LL | &X(*Y) - | ^^ - -error[E0507]: cannot move out of borrowed content - --> $DIR/issue-30355.rs:15:8 - | -LL | &X(*Y) - | ^^ cannot move out of borrowed content + = help: the trait `std::marker::Sized` is not implemented for `[u8]` + = note: to learn more, visit + = note: all function arguments must have a statically known size + = help: unsized locals are gated as an unstable feature -error: aborting due to 3 previous errors +error: aborting due to previous error -Some errors occurred: E0161, E0507. -For more information about an error, try `rustc --explain E0161`. +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/unsized-locals/unsized-exprs.rs b/src/test/ui/unsized-locals/unsized-exprs.rs index 0cf93c78c4abe..8ca88edcb6add 100644 --- a/src/test/ui/unsized-locals/unsized-exprs.rs +++ b/src/test/ui/unsized-locals/unsized-exprs.rs @@ -23,4 +23,6 @@ fn main() { //~^ERROR E0277 udrop::>(A { 0: *foo() }); //~^ERROR E0277 + udrop::>(A(*foo())); + //~^ERROR E0277 } diff --git a/src/test/ui/unsized-locals/unsized-exprs.stderr b/src/test/ui/unsized-locals/unsized-exprs.stderr index eb2016941770c..0ca60e8dea0d9 100644 --- a/src/test/ui/unsized-locals/unsized-exprs.stderr +++ b/src/test/ui/unsized-locals/unsized-exprs.stderr @@ -20,6 +20,17 @@ LL | udrop::>(A { 0: *foo() }); = note: required because it appears within the type `A<[u8]>` = note: structs must have a statically known size to be initialized -error: aborting due to 2 previous errors +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> $DIR/unsized-exprs.rs:26:22 + | +LL | udrop::>(A(*foo())); + | ^ doesn't have a size known at compile-time + | + = help: within `A<[u8]>`, the trait `std::marker::Sized` is not implemented for `[u8]` + = note: to learn more, visit + = note: required because it appears within the type `A<[u8]>` + = note: the return type of a function must have a statically known size + +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/unsized-locals/unsized-exprs2.rs b/src/test/ui/unsized-locals/unsized-exprs2.rs index ae69893a83577..3fb5a002e0e3c 100644 --- a/src/test/ui/unsized-locals/unsized-exprs2.rs +++ b/src/test/ui/unsized-locals/unsized-exprs2.rs @@ -21,6 +21,4 @@ impl std::ops::Add for A<[u8]> { fn main() { udrop::<[u8]>(foo()[..]); //~^ERROR cannot move out of indexed content - // FIXME: should be error - udrop::>(A(*foo())); } From 8ab5be13a31261317c0e4b52bd4743da03e5bf74 Mon Sep 17 00:00:00 2001 From: Masaki Hara Date: Mon, 19 Nov 2018 00:19:14 +0900 Subject: [PATCH 11/29] Add tests verifying #50940. --- .../ui/unsized-locals/issue-50940-with-feature.rs | 7 +++++++ .../unsized-locals/issue-50940-with-feature.stderr | 14 ++++++++++++++ src/test/ui/unsized-locals/issue-50940.rs | 5 +++++ src/test/ui/unsized-locals/issue-50940.stderr | 14 ++++++++++++++ 4 files changed, 40 insertions(+) create mode 100644 src/test/ui/unsized-locals/issue-50940-with-feature.rs create mode 100644 src/test/ui/unsized-locals/issue-50940-with-feature.stderr create mode 100644 src/test/ui/unsized-locals/issue-50940.rs create mode 100644 src/test/ui/unsized-locals/issue-50940.stderr diff --git a/src/test/ui/unsized-locals/issue-50940-with-feature.rs b/src/test/ui/unsized-locals/issue-50940-with-feature.rs new file mode 100644 index 0000000000000..3e5d39ab31150 --- /dev/null +++ b/src/test/ui/unsized-locals/issue-50940-with-feature.rs @@ -0,0 +1,7 @@ +#![feature(unsized_locals)] + +fn main() { + struct A(X); + A as fn(str) -> A; + //~^ERROR the size for values of type `str` cannot be known at compilation time +} diff --git a/src/test/ui/unsized-locals/issue-50940-with-feature.stderr b/src/test/ui/unsized-locals/issue-50940-with-feature.stderr new file mode 100644 index 0000000000000..f4f015fa19065 --- /dev/null +++ b/src/test/ui/unsized-locals/issue-50940-with-feature.stderr @@ -0,0 +1,14 @@ +error[E0277]: the size for values of type `str` cannot be known at compilation time + --> $DIR/issue-50940-with-feature.rs:5:5 + | +LL | A as fn(str) -> A; + | ^ doesn't have a size known at compile-time + | + = help: within `main::A`, the trait `std::marker::Sized` is not implemented for `str` + = note: to learn more, visit + = note: required because it appears within the type `main::A` + = note: the return type of a function must have a statically known size + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/unsized-locals/issue-50940.rs b/src/test/ui/unsized-locals/issue-50940.rs new file mode 100644 index 0000000000000..7ba809b7e83e3 --- /dev/null +++ b/src/test/ui/unsized-locals/issue-50940.rs @@ -0,0 +1,5 @@ +fn main() { + struct A(X); + A as fn(str) -> A; + //~^ERROR the size for values of type `str` cannot be known at compilation time +} diff --git a/src/test/ui/unsized-locals/issue-50940.stderr b/src/test/ui/unsized-locals/issue-50940.stderr new file mode 100644 index 0000000000000..9f3669ccf1f15 --- /dev/null +++ b/src/test/ui/unsized-locals/issue-50940.stderr @@ -0,0 +1,14 @@ +error[E0277]: the size for values of type `str` cannot be known at compilation time + --> $DIR/issue-50940.rs:3:5 + | +LL | A as fn(str) -> A; + | ^ doesn't have a size known at compile-time + | + = help: the trait `std::marker::Sized` is not implemented for `str` + = note: to learn more, visit + = note: all function arguments must have a statically known size + = help: unsized locals are gated as an unstable feature + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. From 2ff6ffc872645bf6f5bc7dda4a817a1fc7789684 Mon Sep 17 00:00:00 2001 From: Masaki Hara Date: Mon, 19 Nov 2018 00:26:05 +0900 Subject: [PATCH 12/29] Add tests for unsized-locals functions stability. --- src/test/run-pass/unsized-locals/unsized-exprs.rs | 1 + src/test/ui/unsized-locals/auxiliary/ufuncs.rs | 3 +++ src/test/ui/unsized-locals/unsized-exprs3.rs | 10 ++++++++++ src/test/ui/unsized-locals/unsized-exprs3.stderr | 14 ++++++++++++++ 4 files changed, 28 insertions(+) create mode 100644 src/test/ui/unsized-locals/auxiliary/ufuncs.rs create mode 100644 src/test/ui/unsized-locals/unsized-exprs3.rs create mode 100644 src/test/ui/unsized-locals/unsized-exprs3.stderr diff --git a/src/test/run-pass/unsized-locals/unsized-exprs.rs b/src/test/run-pass/unsized-locals/unsized-exprs.rs index 4b988f1e72d5a..bc64fcdec2e39 100644 --- a/src/test/run-pass/unsized-locals/unsized-exprs.rs +++ b/src/test/run-pass/unsized-locals/unsized-exprs.rs @@ -34,4 +34,5 @@ fn main() { udrop::<[u8]>((*foo())); udrop::<[u8]>((*tfoo()).1); *afoo() + 42; + udrop as fn([u8]); } diff --git a/src/test/ui/unsized-locals/auxiliary/ufuncs.rs b/src/test/ui/unsized-locals/auxiliary/ufuncs.rs new file mode 100644 index 0000000000000..065563d45a472 --- /dev/null +++ b/src/test/ui/unsized-locals/auxiliary/ufuncs.rs @@ -0,0 +1,3 @@ +#![feature(unsized_locals)] + +pub fn udrop(_x: T) {} diff --git a/src/test/ui/unsized-locals/unsized-exprs3.rs b/src/test/ui/unsized-locals/unsized-exprs3.rs new file mode 100644 index 0000000000000..2133b01e09480 --- /dev/null +++ b/src/test/ui/unsized-locals/unsized-exprs3.rs @@ -0,0 +1,10 @@ +// aux-build:ufuncs.rs + +extern crate ufuncs; + +use ufuncs::udrop; + +fn main() { + udrop as fn([u8]); + //~^ERROR E0277 +} diff --git a/src/test/ui/unsized-locals/unsized-exprs3.stderr b/src/test/ui/unsized-locals/unsized-exprs3.stderr new file mode 100644 index 0000000000000..42f91a946a851 --- /dev/null +++ b/src/test/ui/unsized-locals/unsized-exprs3.stderr @@ -0,0 +1,14 @@ +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> $DIR/unsized-exprs3.rs:8:5 + | +LL | udrop as fn([u8]); + | ^^^^^ doesn't have a size known at compile-time + | + = help: the trait `std::marker::Sized` is not implemented for `[u8]` + = note: to learn more, visit + = note: all function arguments must have a statically known size + = help: unsized locals are gated as an unstable feature + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. From c6a803a286faae901a6ebd35ec222901f691c7ec Mon Sep 17 00:00:00 2001 From: Masaki Hara Date: Mon, 19 Nov 2018 00:27:16 +0900 Subject: [PATCH 13/29] Modify doc to reflect the unsized-locals improvement. --- src/doc/unstable-book/src/language-features/unsized-locals.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/doc/unstable-book/src/language-features/unsized-locals.md b/src/doc/unstable-book/src/language-features/unsized-locals.md index 6f7cf754ae083..1165ab93a1469 100644 --- a/src/doc/unstable-book/src/language-features/unsized-locals.md +++ b/src/doc/unstable-book/src/language-features/unsized-locals.md @@ -80,8 +80,6 @@ fn main() { } ``` -However, the current implementation allows `MyTupleStruct(..)` to be unsized. This will be fixed in the future. - ## By-value trait objects With this feature, you can have by-value `self` arguments without `Self: Sized` bounds. From fc284c1eee0180903fe11463dcee06e414202cf7 Mon Sep 17 00:00:00 2001 From: Dan Aloni Date: Mon, 19 Nov 2018 16:32:18 +0200 Subject: [PATCH 14/29] Stabilize macro_literal_matcher --- .../macro-literal-matcher.md | 17 ---------- src/libsyntax/ext/tt/macro_rules.rs | 31 ++++++++----------- src/libsyntax/feature_gate.rs | 8 ++--- src/test/run-pass/issues/issue-52169.rs | 2 +- src/test/run-pass/macros/macro-literal.rs | 2 +- .../feature-gate-macro-literal-matcher.rs | 19 ------------ .../feature-gate-macro-literal-matcher.stderr | 11 ------- 7 files changed, 17 insertions(+), 73 deletions(-) delete mode 100644 src/doc/unstable-book/src/language-features/macro-literal-matcher.md delete mode 100644 src/test/ui/feature-gates/feature-gate-macro-literal-matcher.rs delete mode 100644 src/test/ui/feature-gates/feature-gate-macro-literal-matcher.stderr diff --git a/src/doc/unstable-book/src/language-features/macro-literal-matcher.md b/src/doc/unstable-book/src/language-features/macro-literal-matcher.md deleted file mode 100644 index 870158200dee9..0000000000000 --- a/src/doc/unstable-book/src/language-features/macro-literal-matcher.md +++ /dev/null @@ -1,17 +0,0 @@ -# `macro_literal_matcher` - -The tracking issue for this feature is: [#35625] - -The RFC is: [rfc#1576]. - -With this feature gate enabled, the [list of designators] gains one more entry: - -* `literal`: a literal. Examples: 2, "string", 'c' - -A `literal` may be followed by anything, similarly to the `ident` specifier. - -[rfc#1576]: http://rust-lang.github.io/rfcs/1576-macros-literal-matcher.html -[#35625]: https://github.com/rust-lang/rust/issues/35625 -[list of designators]: ../reference/macros-by-example.html - ------------------------- diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs index 6bba891278aca..55c1904bd274a 100644 --- a/src/libsyntax/ext/tt/macro_rules.rs +++ b/src/libsyntax/ext/tt/macro_rules.rs @@ -19,7 +19,7 @@ use ext::tt::macro_parser::{MatchedSeq, MatchedNonterminal}; use ext::tt::macro_parser::{parse, parse_failure_msg}; use ext::tt::quoted; use ext::tt::transcribe::transcribe; -use feature_gate::{self, emit_feature_err, Features, GateIssue}; +use feature_gate::Features; use parse::{Directory, ParseSess}; use parse::parser::Parser; use parse::token::{self, NtTT}; @@ -1027,26 +1027,21 @@ fn has_legal_fragment_specifier(sess: &ParseSess, Ok(()) } -fn is_legal_fragment_specifier(sess: &ParseSess, - features: &Features, - attrs: &[ast::Attribute], +fn is_legal_fragment_specifier(_sess: &ParseSess, + _features: &Features, + _attrs: &[ast::Attribute], frag_name: &str, - frag_span: Span) -> bool { + _frag_span: Span) -> bool { + /* + * If new fragmnet specifiers are invented in nightly, `_sess`, + * `_features`, `_attrs`, and `_frag_span` will be useful for + * here for checking against feature gates. See past versions of + * this function. + */ match frag_name { "item" | "block" | "stmt" | "expr" | "pat" | "lifetime" | - "path" | "ty" | "ident" | "meta" | "tt" | "vis" | "" => true, - "literal" => { - if !features.macro_literal_matcher && - !attr::contains_name(attrs, "allow_internal_unstable") { - let explain = feature_gate::EXPLAIN_LITERAL_MATCHER; - emit_feature_err(sess, - "macro_literal_matcher", - frag_span, - GateIssue::Language, - explain); - } - true - }, + "path" | "ty" | "ident" | "meta" | "tt" | "vis" | "literal" | + "" => true, _ => false, } } diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 2f5db9bd08155..73567765a04c4 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -436,9 +436,6 @@ declare_features! ( // Allows irrefutable patterns in if-let and while-let statements (RFC 2086) (active, irrefutable_let_patterns, "1.27.0", Some(44495), None), - // Allows use of the :literal macro fragment specifier (RFC 1576) - (active, macro_literal_matcher, "1.27.0", Some(35625), None), - // inconsistent bounds in where clauses (active, trivial_bounds, "1.28.0", Some(48214), None), @@ -690,6 +687,8 @@ declare_features! ( (accepted, impl_header_lifetime_elision, "1.31.0", Some(15872), None), // `extern crate foo as bar;` puts `bar` into extern prelude. (accepted, extern_crate_item_prelude, "1.31.0", Some(55599), None), + // Allows use of the :literal macro fragment specifier (RFC 1576) + (accepted, macro_literal_matcher, "1.31.0", Some(35625), None), ); // If you change this, please modify src/doc/unstable-book as well. You must @@ -1425,9 +1424,6 @@ pub const EXPLAIN_DEPR_CUSTOM_DERIVE: &'static str = pub const EXPLAIN_DERIVE_UNDERSCORE: &'static str = "attributes of the form `#[derive_*]` are reserved for the compiler"; -pub const EXPLAIN_LITERAL_MATCHER: &'static str = - ":literal fragment specifier is experimental and subject to change"; - pub const EXPLAIN_UNSIZED_TUPLE_COERCION: &'static str = "unsized tuple coercion is not stable enough for use and is subject to change"; diff --git a/src/test/run-pass/issues/issue-52169.rs b/src/test/run-pass/issues/issue-52169.rs index 19c0f51d235bc..9421dfc7897d0 100644 --- a/src/test/run-pass/issues/issue-52169.rs +++ b/src/test/run-pass/issues/issue-52169.rs @@ -9,7 +9,7 @@ // except according to those terms. // run-pass -#![feature(macro_literal_matcher)] +#![cfg_attr(stage0, feature(macro_literal_matcher))] macro_rules! a { ($i:literal) => { "right" }; diff --git a/src/test/run-pass/macros/macro-literal.rs b/src/test/run-pass/macros/macro-literal.rs index ecbb47757d11e..07e27d9f516cb 100644 --- a/src/test/run-pass/macros/macro-literal.rs +++ b/src/test/run-pass/macros/macro-literal.rs @@ -9,7 +9,7 @@ // except according to those terms. // run-pass -#![feature(macro_literal_matcher)] +#![cfg_attr(stage0, feature(macro_literal_matcher))] macro_rules! mtester { ($l:literal) => { diff --git a/src/test/ui/feature-gates/feature-gate-macro-literal-matcher.rs b/src/test/ui/feature-gates/feature-gate-macro-literal-matcher.rs deleted file mode 100644 index db5cca193ab4e..0000000000000 --- a/src/test/ui/feature-gates/feature-gate-macro-literal-matcher.rs +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2018 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 the :lifetime macro fragment cannot be used when macro_lifetime_matcher -// feature gate is not used. - -macro_rules! m { ($lt:literal) => {} } -//~^ ERROR :literal fragment specifier is experimental and subject to change - -fn main() { - m!("some string literal"); -} diff --git a/src/test/ui/feature-gates/feature-gate-macro-literal-matcher.stderr b/src/test/ui/feature-gates/feature-gate-macro-literal-matcher.stderr deleted file mode 100644 index f714b916966a1..0000000000000 --- a/src/test/ui/feature-gates/feature-gate-macro-literal-matcher.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0658]: :literal fragment specifier is experimental and subject to change (see issue #35625) - --> $DIR/feature-gate-macro-literal-matcher.rs:14:19 - | -LL | macro_rules! m { ($lt:literal) => {} } - | ^^^^^^^^^^^ - | - = help: add #![feature(macro_literal_matcher)] to the crate attributes to enable - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0658`. From b8ae7b801bf1f3d298493b2e7e1328a1a7ecace7 Mon Sep 17 00:00:00 2001 From: Dan Aloni Date: Tue, 20 Nov 2018 09:11:12 +0200 Subject: [PATCH 15/29] macro_literal_matcher: fixes per petrochenkov's review --- src/libsyntax/ext/tt/macro_rules.rs | 6 +++--- src/test/run-pass/issues/issue-52169.rs | 1 - src/test/run-pass/macros/macro-literal.rs | 1 - 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs index 55c1904bd274a..d526e464ba4f5 100644 --- a/src/libsyntax/ext/tt/macro_rules.rs +++ b/src/libsyntax/ext/tt/macro_rules.rs @@ -1033,9 +1033,9 @@ fn is_legal_fragment_specifier(_sess: &ParseSess, frag_name: &str, _frag_span: Span) -> bool { /* - * If new fragmnet specifiers are invented in nightly, `_sess`, - * `_features`, `_attrs`, and `_frag_span` will be useful for - * here for checking against feature gates. See past versions of + * If new fragment specifiers are invented in nightly, `_sess`, + * `_features`, `_attrs`, and `_frag_span` will be useful here + * for checking against feature gates. See past versions of * this function. */ match frag_name { diff --git a/src/test/run-pass/issues/issue-52169.rs b/src/test/run-pass/issues/issue-52169.rs index 9421dfc7897d0..c4ed534cc20ec 100644 --- a/src/test/run-pass/issues/issue-52169.rs +++ b/src/test/run-pass/issues/issue-52169.rs @@ -9,7 +9,6 @@ // except according to those terms. // run-pass -#![cfg_attr(stage0, feature(macro_literal_matcher))] macro_rules! a { ($i:literal) => { "right" }; diff --git a/src/test/run-pass/macros/macro-literal.rs b/src/test/run-pass/macros/macro-literal.rs index 07e27d9f516cb..de268e3388a5e 100644 --- a/src/test/run-pass/macros/macro-literal.rs +++ b/src/test/run-pass/macros/macro-literal.rs @@ -9,7 +9,6 @@ // except according to those terms. // run-pass -#![cfg_attr(stage0, feature(macro_literal_matcher))] macro_rules! mtester { ($l:literal) => { From d4ee1c93ff25a7fa6f5e35dc774a648a7e6d578e Mon Sep 17 00:00:00 2001 From: Tom Tromey Date: Wed, 21 Nov 2018 11:35:49 -0700 Subject: [PATCH 16/29] Fix BTreeSet and BTreeMap gdb pretty-printers The BTreeSet and BTreeMap gdb pretty-printers did not take the node structure into account, and consequently only worked for shallow sets. This fixes the problem by iterating over child nodes when needed. This patch avoids the current approach of implementing some of the value manipulations in debugger-indepdendent code. This was done for convenience: a type lookup was needed for the first time, and there currently are no lldb formatters for these types. Closes #55771 --- src/etc/debugger_pretty_printers_common.py | 26 -------- src/etc/gdb_rust_pretty_printing.py | 70 ++++++++++++-------- src/test/debuginfo/pretty-std-collections.rs | 17 ++--- 3 files changed, 50 insertions(+), 63 deletions(-) diff --git a/src/etc/debugger_pretty_printers_common.py b/src/etc/debugger_pretty_printers_common.py index 1797f6708ac5b..b99e401929e62 100644 --- a/src/etc/debugger_pretty_printers_common.py +++ b/src/etc/debugger_pretty_printers_common.py @@ -375,32 +375,6 @@ def extract_tail_head_ptr_and_cap_from_std_vecdeque(vec_val): assert data_ptr.type.get_dwarf_type_kind() == DWARF_TYPE_CODE_PTR return (tail, head, data_ptr, capacity) - -def extract_length_and_ptr_from_std_btreeset(vec_val): - assert vec_val.type.get_type_kind() == TYPE_KIND_STD_BTREESET - map = vec_val.get_child_at_index(0) - root = map.get_child_at_index(0) - length = map.get_child_at_index(1).as_integer() - node = root.get_child_at_index(0) - ptr = node.get_child_at_index(0) - unique_ptr_val = ptr.get_child_at_index(0) - data_ptr = unique_ptr_val.get_child_at_index(0) - assert data_ptr.type.get_dwarf_type_kind() == DWARF_TYPE_CODE_PTR - return (length, data_ptr) - - -def extract_length_and_ptr_from_std_btreemap(vec_val): - assert vec_val.type.get_type_kind() == TYPE_KIND_STD_BTREEMAP - root = vec_val.get_child_at_index(0) - length = vec_val.get_child_at_index(1).as_integer() - node = root.get_child_at_index(0) - ptr = node.get_child_at_index(0) - unique_ptr_val = ptr.get_child_at_index(0) - data_ptr = unique_ptr_val.get_child_at_index(0) - assert data_ptr.type.get_dwarf_type_kind() == DWARF_TYPE_CODE_PTR - return (length, data_ptr) - - def extract_length_and_ptr_from_slice(slice_val): assert (slice_val.type.get_type_kind() == TYPE_KIND_SLICE or slice_val.type.get_type_kind() == TYPE_KIND_STR_SLICE) diff --git a/src/etc/gdb_rust_pretty_printing.py b/src/etc/gdb_rust_pretty_printing.py index e6d5ef1a23ff7..11e46e8c54cc9 100755 --- a/src/etc/gdb_rust_pretty_printing.py +++ b/src/etc/gdb_rust_pretty_printing.py @@ -304,6 +304,32 @@ def children(self): yield (str(index), (gdb_ptr + index).dereference()) +# Yield each key (and optionally value) from a BoxedNode. +def children_of_node(boxed_node, height, want_values): + ptr = boxed_node['ptr']['pointer'] + # This is written oddly because we don't want to rely on the field name being `__0`. + node_ptr = ptr[ptr.type.fields()[0]] + if height > 0: + type_name = str(node_ptr.type.target()).replace('LeafNode', 'InternalNode') + node_type = gdb.lookup_type(type_name) + node_ptr = node_ptr.cast(node_type.pointer()) + leaf = node_ptr['data'] + else: + leaf = node_ptr.dereference() + keys = leaf['keys']['value']['value'] + if want_values: + values = leaf['vals']['value']['value'] + length = int(leaf['len']) + for i in xrange(0, length + 1): + if height > 0: + for child in children_of_node(node_ptr['edges'][i], height - 1, want_values): + yield child + if i < length: + if want_values: + yield (keys[i], values[i]) + else: + yield keys[i] + class RustStdBTreeSetPrinter(object): def __init__(self, val): self.__val = val @@ -313,21 +339,16 @@ def display_hint(): return "array" def to_string(self): - (length, data_ptr) = \ - rustpp.extract_length_and_ptr_from_std_btreeset(self.__val) return (self.__val.type.get_unqualified_type_name() + - ("(len: %i)" % length)) + ("(len: %i)" % self.__val.get_wrapped_value()['map']['length'])) def children(self): - (length, data_ptr) = \ - rustpp.extract_length_and_ptr_from_std_btreeset(self.__val) - leaf_node = GdbValue(data_ptr.get_wrapped_value().dereference()) - maybe_uninit_keys = leaf_node.get_child_at_index(3) - manually_drop_keys = maybe_uninit_keys.get_child_at_index(1) - keys = manually_drop_keys.get_child_at_index(0) - gdb_ptr = keys.get_wrapped_value() - for index in xrange(length): - yield (str(index), gdb_ptr[index]) + root = self.__val.get_wrapped_value()['map']['root'] + node_ptr = root['node'] + i = 0 + for child in children_of_node(node_ptr, root['height'], False): + yield (str(i), child) + i = i + 1 class RustStdBTreeMapPrinter(object): @@ -339,26 +360,17 @@ def display_hint(): return "map" def to_string(self): - (length, data_ptr) = \ - rustpp.extract_length_and_ptr_from_std_btreemap(self.__val) return (self.__val.type.get_unqualified_type_name() + - ("(len: %i)" % length)) + ("(len: %i)" % self.__val.get_wrapped_value()['length'])) def children(self): - (length, data_ptr) = \ - rustpp.extract_length_and_ptr_from_std_btreemap(self.__val) - leaf_node = GdbValue(data_ptr.get_wrapped_value().dereference()) - maybe_uninit_keys = leaf_node.get_child_at_index(3) - manually_drop_keys = maybe_uninit_keys.get_child_at_index(1) - keys = manually_drop_keys.get_child_at_index(0) - keys_ptr = keys.get_wrapped_value() - maybe_uninit_vals = leaf_node.get_child_at_index(4) - manually_drop_vals = maybe_uninit_vals.get_child_at_index(1) - vals = manually_drop_vals.get_child_at_index(0) - vals_ptr = vals.get_wrapped_value() - for index in xrange(length): - yield (str(index), keys_ptr[index]) - yield (str(index), vals_ptr[index]) + root = self.__val.get_wrapped_value()['root'] + node_ptr = root['node'] + i = 0 + for child in children_of_node(node_ptr, root['height'], True): + yield (str(i), child[0]) + yield (str(i), child[1]) + i = i + 1 class RustStdStringPrinter(object): diff --git a/src/test/debuginfo/pretty-std-collections.rs b/src/test/debuginfo/pretty-std-collections.rs index 8e37a884b34bb..55e20d67276cd 100644 --- a/src/test/debuginfo/pretty-std-collections.rs +++ b/src/test/debuginfo/pretty-std-collections.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-tidy-linelength // ignore-windows failing on win32 bot // ignore-freebsd: gdb package too new // ignore-android: FIXME(#10381) @@ -20,10 +21,10 @@ // gdb-command: run // gdb-command: print btree_set -// gdb-check:$1 = BTreeSet(len: 3) = {3, 5, 7} +// gdb-check:$1 = BTreeSet(len: 15) = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14} // gdb-command: print btree_map -// gdb-check:$2 = BTreeMap(len: 3) = {[3] = 3, [5] = 7, [7] = 4} +// gdb-check:$2 = BTreeMap(len: 15) = {[0] = 0, [1] = 1, [2] = 2, [3] = 3, [4] = 4, [5] = 5, [6] = 6, [7] = 7, [8] = 8, [9] = 9, [10] = 10, [11] = 11, [12] = 12, [13] = 13, [14] = 14} // gdb-command: print vec_deque // gdb-check:$3 = VecDeque(len: 3, cap: 8) = {5, 3, 7} @@ -38,15 +39,15 @@ fn main() { // BTreeSet let mut btree_set = BTreeSet::new(); - btree_set.insert(5); - btree_set.insert(3); - btree_set.insert(7); + for i in 0..15 { + btree_set.insert(i); + } // BTreeMap let mut btree_map = BTreeMap::new(); - btree_map.insert(5, 7); - btree_map.insert(3, 3); - btree_map.insert(7, 4); + for i in 0..15 { + btree_map.insert(i, i); + } // VecDeque let mut vec_deque = VecDeque::new(); From d1cd4e8d0d383842acfe2d6ea75eed1e0c0909ac Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 21 Nov 2018 21:56:23 -0800 Subject: [PATCH 17/29] Move a flaky process test out of libstd This test ensures that everything in `env::vars()` is inherited but that's not actually true because other tests may add env vars after we spawn the process, causing the test to be flaky! This commit moves the test to a run-pass test where it can execute in isolation. Along the way this removes a lot of the platform specificity of the test, using iteslf to print the environment instead of a foreign process. --- src/libstd/process.rs | 36 -------------------------------- src/test/run-pass/inherit-env.rs | 25 ++++++++++++++++++++++ 2 files changed, 25 insertions(+), 36 deletions(-) create mode 100644 src/test/run-pass/inherit-env.rs diff --git a/src/libstd/process.rs b/src/libstd/process.rs index 51481e129df8d..2d0848252be6d 100644 --- a/src/libstd/process.rs +++ b/src/libstd/process.rs @@ -1889,42 +1889,6 @@ mod tests { cmd } - #[test] - fn test_inherit_env() { - use env; - - let result = env_cmd().output().unwrap(); - let output = String::from_utf8(result.stdout).unwrap(); - - for (ref k, ref v) in env::vars() { - // Don't check android RANDOM variable which seems to change - // whenever the shell runs, and our `env_cmd` is indeed running a - // shell which means it'll get a different RANDOM than we probably - // have. - // - // Also skip env vars with `-` in the name on android because, well, - // I'm not sure. It appears though that the `set` command above does - // not print env vars with `-` in the name, so we just skip them - // here as we won't find them in the output. Note that most env vars - // use `_` instead of `-`, but our build system sets a few env vars - // with `-` in the name. - if cfg!(target_os = "android") && - (*k == "RANDOM" || k.contains("-")) { - continue - } - - // Windows has hidden environment variables whose names start with - // equals signs (`=`). Those do not show up in the output of the - // `set` command. - assert!((cfg!(windows) && k.starts_with("=")) || - k.starts_with("DYLD") || - output.contains(&format!("{}={}", *k, *v)) || - output.contains(&format!("{}='{}'", *k, *v)), - "output doesn't contain `{}={}`\n{}", - k, v, output); - } - } - #[test] fn test_override_env() { use env; diff --git a/src/test/run-pass/inherit-env.rs b/src/test/run-pass/inherit-env.rs new file mode 100644 index 0000000000000..856d3a5f72d34 --- /dev/null +++ b/src/test/run-pass/inherit-env.rs @@ -0,0 +1,25 @@ +// ignore-emscripten +// ignore-wasm32 + +use std::env; +use std::process::Command; + +fn main() { + if env::args().nth(1).map(|s| s == "print").unwrap_or(false) { + for (k, v) in env::vars() { + println!("{}={}", k, v); + } + return + } + + let me = env::current_exe().unwrap(); + let result = Command::new(me).arg("print").output().unwrap(); + let output = String::from_utf8(result.stdout).unwrap(); + + for (k, v) in env::vars() { + assert!(output.contains(&format!("{}={}", k, v)), + "output doesn't contain `{}={}`\n{}", + k, v, output); + } +} + From b319715456c08097f2cd936da309ed6e8aec2843 Mon Sep 17 00:00:00 2001 From: Wesley Wiser Date: Thu, 22 Nov 2018 12:56:15 -0500 Subject: [PATCH 18/29] Disable the self-profiler unless the `-Z self-profile` flag is set Related to #51648 --- src/librustc/session/mod.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index d688d93b80842..1187c53305d1c 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -826,8 +826,10 @@ impl Session { } pub fn profiler ()>(&self, f: F) { - let mut profiler = self.self_profiling.borrow_mut(); - f(&mut profiler); + if self.opts.debugging_opts.self_profile { + let mut profiler = self.self_profiling.borrow_mut(); + f(&mut profiler); + } } pub fn print_profiler_results(&self) { From 4381772695dfb8ced845fd47e7eada74f9f6bd21 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 22 Nov 2018 22:17:23 +0100 Subject: [PATCH 19/29] Fix invalid panic setup message --- src/librustc/session/config.rs | 2 +- src/test/ui/panic-runtime/bad-panic-flag1.rs | 2 +- src/test/ui/panic-runtime/bad-panic-flag1.stderr | 2 +- src/test/ui/panic-runtime/bad-panic-flag2.rs | 2 +- src/test/ui/panic-runtime/bad-panic-flag2.stderr | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 78aabf86e300d..07f095fc6139c 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -802,7 +802,7 @@ macro_rules! options { pub const parse_opt_uint: Option<&'static str> = Some("a number"); pub const parse_panic_strategy: Option<&'static str> = - Some("either `panic` or `abort`"); + Some("either `unwind` or `abort`"); pub const parse_relro_level: Option<&'static str> = Some("one of: `full`, `partial`, or `off`"); pub const parse_sanitizer: Option<&'static str> = diff --git a/src/test/ui/panic-runtime/bad-panic-flag1.rs b/src/test/ui/panic-runtime/bad-panic-flag1.rs index f067b6b8349b6..4e553c4df2fd4 100644 --- a/src/test/ui/panic-runtime/bad-panic-flag1.rs +++ b/src/test/ui/panic-runtime/bad-panic-flag1.rs @@ -9,6 +9,6 @@ // except according to those terms. // compile-flags:-C panic=foo -// error-pattern:either `panic` or `abort` was expected +// error-pattern:either `unwind` or `abort` was expected fn main() {} diff --git a/src/test/ui/panic-runtime/bad-panic-flag1.stderr b/src/test/ui/panic-runtime/bad-panic-flag1.stderr index 3a65419c98fb7..013373c6f9313 100644 --- a/src/test/ui/panic-runtime/bad-panic-flag1.stderr +++ b/src/test/ui/panic-runtime/bad-panic-flag1.stderr @@ -1,2 +1,2 @@ -error: incorrect value `foo` for codegen option `panic` - either `panic` or `abort` was expected +error: incorrect value `foo` for codegen option `panic` - either `unwind` or `abort` was expected diff --git a/src/test/ui/panic-runtime/bad-panic-flag2.rs b/src/test/ui/panic-runtime/bad-panic-flag2.rs index 0ecf65f080fa9..f560e7f4eb2de 100644 --- a/src/test/ui/panic-runtime/bad-panic-flag2.rs +++ b/src/test/ui/panic-runtime/bad-panic-flag2.rs @@ -9,6 +9,6 @@ // except according to those terms. // compile-flags:-C panic -// error-pattern:requires either `panic` or `abort` +// error-pattern:requires either `unwind` or `abort` fn main() {} diff --git a/src/test/ui/panic-runtime/bad-panic-flag2.stderr b/src/test/ui/panic-runtime/bad-panic-flag2.stderr index 8d919e55c9068..6ab94ea704d30 100644 --- a/src/test/ui/panic-runtime/bad-panic-flag2.stderr +++ b/src/test/ui/panic-runtime/bad-panic-flag2.stderr @@ -1,2 +1,2 @@ -error: codegen option `panic` requires either `panic` or `abort` (C panic=) +error: codegen option `panic` requires either `unwind` or `abort` (C panic=) From 6b338e034adfc1bffed942c084c892d34f1cd9b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sat, 24 Nov 2018 16:23:11 -0800 Subject: [PATCH 20/29] Suggest correct enum variant on typo --- src/librustc_typeck/astconv.rs | 29 ++++++++++++++++++- src/test/ui/issues/issue-34209.rs | 4 +-- src/test/ui/issues/issue-34209.stderr | 7 ++--- src/test/ui/suggestions/suggest-variants.rs | 15 ++++++++++ .../ui/suggestions/suggest-variants.stderr | 20 +++++++++++++ 5 files changed, 68 insertions(+), 7 deletions(-) create mode 100644 src/test/ui/suggestions/suggest-variants.rs create mode 100644 src/test/ui/suggestions/suggest-variants.stderr diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index a8164c85e821d..4fbbe58445254 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -36,8 +36,9 @@ use lint; use std::iter; use syntax::ast; -use syntax::ptr::P; use syntax::feature_gate::{GateIssue, emit_feature_err}; +use syntax::ptr::P; +use syntax::util::lev_distance::find_best_match_for_name; use syntax_pos::{DUMMY_SP, Span, MultiSpan}; pub trait AstConv<'gcx, 'tcx> { @@ -1303,6 +1304,32 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o { Err(ErrorReported) => return (tcx.types.err, Def::Err), } } + (&ty::Adt(adt_def, _substs), Def::Enum(_did)) => { + let ty_str = ty.to_string(); + // Incorrect enum variant + let mut err = tcx.sess.struct_span_err( + span, + &format!("no variant `{}` on enum `{}`", &assoc_name.as_str(), ty_str), + ); + // Check if it was a typo + let input = adt_def.variants.iter().map(|variant| &variant.name); + if let Some(suggested_name) = find_best_match_for_name( + input, + &assoc_name.as_str(), + None, + ) { + err.span_suggestion_with_applicability( + span, + "did you mean", + format!("{}::{}", ty_str, suggested_name.to_string()), + Applicability::MaybeIncorrect, + ); + } else { + err.span_label(span, "unknown variant"); + } + err.emit(); + return (tcx.types.err, Def::Err); + } _ => { // Don't print TyErr to the user. if !ty.references_error() { diff --git a/src/test/ui/issues/issue-34209.rs b/src/test/ui/issues/issue-34209.rs index b3cb7d4cc3053..86eb624edcac1 100644 --- a/src/test/ui/issues/issue-34209.rs +++ b/src/test/ui/issues/issue-34209.rs @@ -14,8 +14,8 @@ enum S { fn bug(l: S) { match l { - S::B{ } => { }, - //~^ ERROR ambiguous associated type + S::B { } => { }, + //~^ ERROR no variant `B` on enum `S` } } diff --git a/src/test/ui/issues/issue-34209.stderr b/src/test/ui/issues/issue-34209.stderr index 0dfdd8b588634..d5a5647422f41 100644 --- a/src/test/ui/issues/issue-34209.stderr +++ b/src/test/ui/issues/issue-34209.stderr @@ -1,9 +1,8 @@ -error[E0223]: ambiguous associated type +error: no variant `B` on enum `S` --> $DIR/issue-34209.rs:17:9 | -LL | S::B{ } => { }, - | ^^^^ help: use fully-qualified syntax: `::B` +LL | S::B { } => { }, + | ^^^^ help: did you mean: `S::A` error: aborting due to previous error -For more information about this error, try `rustc --explain E0223`. diff --git a/src/test/ui/suggestions/suggest-variants.rs b/src/test/ui/suggestions/suggest-variants.rs new file mode 100644 index 0000000000000..4a131ed837b87 --- /dev/null +++ b/src/test/ui/suggestions/suggest-variants.rs @@ -0,0 +1,15 @@ +#[derive(Debug)] +enum Shape { + Square { size: i32 }, + Circle { radius: i32 }, +} + +struct S { + x: usize, +} + +fn main() { + println!("My shape is {:?}", Shape::Squareee { size: 5}); + println!("My shape is {:?}", Shape::Circl { size: 5}); + println!("My shape is {:?}", Shape::Rombus{ size: 5}); +} diff --git a/src/test/ui/suggestions/suggest-variants.stderr b/src/test/ui/suggestions/suggest-variants.stderr new file mode 100644 index 0000000000000..08ae68ea71302 --- /dev/null +++ b/src/test/ui/suggestions/suggest-variants.stderr @@ -0,0 +1,20 @@ +error: no variant `Squareee` on enum `Shape` + --> $DIR/suggest-variants.rs:12:34 + | +LL | println!("My shape is {:?}", Shape::Squareee { size: 5}); + | ^^^^^^^^^^^^^^^ help: did you mean: `Shape::Square` + +error: no variant `Circl` on enum `Shape` + --> $DIR/suggest-variants.rs:13:34 + | +LL | println!("My shape is {:?}", Shape::Circl { size: 5}); + | ^^^^^^^^^^^^ help: did you mean: `Shape::Circle` + +error: no variant `Rombus` on enum `Shape` + --> $DIR/suggest-variants.rs:14:34 + | +LL | println!("My shape is {:?}", Shape::Rombus{ size: 5}); + | ^^^^^^^^^^^^^ unknown variant + +error: aborting due to 3 previous errors + From dce1c4530e2707c338fe56b26a36797377f11514 Mon Sep 17 00:00:00 2001 From: Wesley Wiser Date: Thu, 22 Nov 2018 13:05:25 -0500 Subject: [PATCH 21/29] [Windows] Work around non-monotonic clocks in the self-profiler On Windows, the high-resolution timestamp api doesn't seem to always be monotonic. This can cause panics when the self-profiler uses the `Instant` api to find elapsed time. Work around this by detecting the case where now is less than the start time and just use 0 elapsed ticks as the measurement. Fixes #51648 --- src/librustc/util/profiling.rs | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/librustc/util/profiling.rs b/src/librustc/util/profiling.rs index 37073b6e82080..1f05043976491 100644 --- a/src/librustc/util/profiling.rs +++ b/src/librustc/util/profiling.rs @@ -12,7 +12,7 @@ use session::config::Options; use std::fs; use std::io::{self, StdoutLock, Write}; -use std::time::Instant; +use std::time::{Duration, Instant}; macro_rules! define_categories { ($($name:ident,)*) => { @@ -197,7 +197,20 @@ impl SelfProfiler { } fn stop_timer(&mut self) -> u64 { - let elapsed = self.current_timer.elapsed(); + let elapsed = if cfg!(windows) { + // On Windows, timers don't always appear to be monotonic (see #51648) + // which can lead to panics when calculating elapsed time. + // Work around this by testing to see if the current time is less than + // our recorded time, and if it is, just returning 0. + let now = Instant::now(); + if self.current_timer >= now { + Duration::new(0, 0) + } else { + self.current_timer.elapsed() + } + } else { + self.current_timer.elapsed() + }; self.current_timer = Instant::now(); From 68a26ec647147d70bcd7f0e7f56a0bf9fedb5f06 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Sun, 25 Nov 2018 08:26:22 +0100 Subject: [PATCH 22/29] Stabilize the int_to_from_bytes feature Fixes #52963 --- src/libcore/num/mod.rs | 48 ++++++---------------- src/test/run-pass/const-int-conversion.rs | 2 +- src/test/ui/consts/const-int-conversion.rs | 2 +- 3 files changed, 14 insertions(+), 38 deletions(-) diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 30b7b45468412..9deae12482976 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -1921,12 +1921,10 @@ big-endian (network) byte order. # Examples ``` -#![feature(int_to_from_bytes)] - let bytes = ", $swap_op, stringify!($SelfT), ".to_be_bytes(); assert_eq!(bytes, ", $be_bytes, "); ```"), - #[unstable(feature = "int_to_from_bytes", issue = "52963")] + #[stable(feature = "int_to_from_bytes", since = "1.32.0")] #[rustc_const_unstable(feature = "const_int_conversion")] #[inline] pub const fn to_be_bytes(self) -> [u8; mem::size_of::()] { @@ -1941,12 +1939,10 @@ little-endian byte order. # Examples ``` -#![feature(int_to_from_bytes)] - let bytes = ", $swap_op, stringify!($SelfT), ".to_le_bytes(); assert_eq!(bytes, ", $le_bytes, "); ```"), - #[unstable(feature = "int_to_from_bytes", issue = "52963")] + #[stable(feature = "int_to_from_bytes", since = "1.32.0")] #[rustc_const_unstable(feature = "const_int_conversion")] #[inline] pub const fn to_le_bytes(self) -> [u8; mem::size_of::()] { @@ -1969,8 +1965,6 @@ instead. # Examples ``` -#![feature(int_to_from_bytes)] - let bytes = ", $swap_op, stringify!($SelfT), ".to_ne_bytes(); assert_eq!(bytes, if cfg!(target_endian = \"big\") { ", $be_bytes, " @@ -1978,7 +1972,7 @@ assert_eq!(bytes, if cfg!(target_endian = \"big\") { ", $le_bytes, " }); ```"), - #[unstable(feature = "int_to_from_bytes", issue = "52963")] + #[stable(feature = "int_to_from_bytes", since = "1.32.0")] #[rustc_const_unstable(feature = "const_int_conversion")] #[inline] pub const fn to_ne_bytes(self) -> [u8; mem::size_of::()] { @@ -1993,12 +1987,10 @@ big endian. # Examples ``` -#![feature(int_to_from_bytes)] - let value = ", stringify!($SelfT), "::from_be_bytes(", $be_bytes, "); assert_eq!(value, ", $swap_op, "); ```"), - #[unstable(feature = "int_to_from_bytes", issue = "52963")] + #[stable(feature = "int_to_from_bytes", since = "1.32.0")] #[rustc_const_unstable(feature = "const_int_conversion")] #[inline] pub const fn from_be_bytes(bytes: [u8; mem::size_of::()]) -> Self { @@ -2014,12 +2006,10 @@ little endian. # Examples ``` -#![feature(int_to_from_bytes)] - let value = ", stringify!($SelfT), "::from_le_bytes(", $le_bytes, "); assert_eq!(value, ", $swap_op, "); ```"), - #[unstable(feature = "int_to_from_bytes", issue = "52963")] + #[stable(feature = "int_to_from_bytes", since = "1.32.0")] #[rustc_const_unstable(feature = "const_int_conversion")] #[inline] pub const fn from_le_bytes(bytes: [u8; mem::size_of::()]) -> Self { @@ -2041,8 +2031,6 @@ appropriate instead. # Examples ``` -#![feature(int_to_from_bytes)] - let value = ", stringify!($SelfT), "::from_ne_bytes(if cfg!(target_endian = \"big\") { ", $be_bytes, " } else { @@ -2050,7 +2038,7 @@ let value = ", stringify!($SelfT), "::from_ne_bytes(if cfg!(target_endian = \"bi }); assert_eq!(value, ", $swap_op, "); ```"), - #[unstable(feature = "int_to_from_bytes", issue = "52963")] + #[stable(feature = "int_to_from_bytes", since = "1.32.0")] #[rustc_const_unstable(feature = "const_int_conversion")] #[inline] pub const fn from_ne_bytes(bytes: [u8; mem::size_of::()]) -> Self { @@ -3663,12 +3651,10 @@ big-endian (network) byte order. # Examples ``` -#![feature(int_to_from_bytes)] - let bytes = ", $swap_op, stringify!($SelfT), ".to_be_bytes(); assert_eq!(bytes, ", $be_bytes, "); ```"), - #[unstable(feature = "int_to_from_bytes", issue = "52963")] + #[stable(feature = "int_to_from_bytes", since = "1.32.0")] #[rustc_const_unstable(feature = "const_int_conversion")] #[inline] pub const fn to_be_bytes(self) -> [u8; mem::size_of::()] { @@ -3683,12 +3669,10 @@ little-endian byte order. # Examples ``` -#![feature(int_to_from_bytes)] - let bytes = ", $swap_op, stringify!($SelfT), ".to_le_bytes(); assert_eq!(bytes, ", $le_bytes, "); ```"), - #[unstable(feature = "int_to_from_bytes", issue = "52963")] + #[stable(feature = "int_to_from_bytes", since = "1.32.0")] #[rustc_const_unstable(feature = "const_int_conversion")] #[inline] pub const fn to_le_bytes(self) -> [u8; mem::size_of::()] { @@ -3711,8 +3695,6 @@ instead. # Examples ``` -#![feature(int_to_from_bytes)] - let bytes = ", $swap_op, stringify!($SelfT), ".to_ne_bytes(); assert_eq!(bytes, if cfg!(target_endian = \"big\") { ", $be_bytes, " @@ -3720,7 +3702,7 @@ assert_eq!(bytes, if cfg!(target_endian = \"big\") { ", $le_bytes, " }); ```"), - #[unstable(feature = "int_to_from_bytes", issue = "52963")] + #[stable(feature = "int_to_from_bytes", since = "1.32.0")] #[rustc_const_unstable(feature = "const_int_conversion")] #[inline] pub const fn to_ne_bytes(self) -> [u8; mem::size_of::()] { @@ -3735,12 +3717,10 @@ big endian. # Examples ``` -#![feature(int_to_from_bytes)] - let value = ", stringify!($SelfT), "::from_be_bytes(", $be_bytes, "); assert_eq!(value, ", $swap_op, "); ```"), - #[unstable(feature = "int_to_from_bytes", issue = "52963")] + #[stable(feature = "int_to_from_bytes", since = "1.32.0")] #[rustc_const_unstable(feature = "const_int_conversion")] #[inline] pub const fn from_be_bytes(bytes: [u8; mem::size_of::()]) -> Self { @@ -3756,12 +3736,10 @@ little endian. # Examples ``` -#![feature(int_to_from_bytes)] - let value = ", stringify!($SelfT), "::from_le_bytes(", $le_bytes, "); assert_eq!(value, ", $swap_op, "); ```"), - #[unstable(feature = "int_to_from_bytes", issue = "52963")] + #[stable(feature = "int_to_from_bytes", since = "1.32.0")] #[rustc_const_unstable(feature = "const_int_conversion")] #[inline] pub const fn from_le_bytes(bytes: [u8; mem::size_of::()]) -> Self { @@ -3783,8 +3761,6 @@ appropriate instead. # Examples ``` -#![feature(int_to_from_bytes)] - let value = ", stringify!($SelfT), "::from_ne_bytes(if cfg!(target_endian = \"big\") { ", $be_bytes, " } else { @@ -3792,7 +3768,7 @@ let value = ", stringify!($SelfT), "::from_ne_bytes(if cfg!(target_endian = \"bi }); assert_eq!(value, ", $swap_op, "); ```"), - #[unstable(feature = "int_to_from_bytes", issue = "52963")] + #[stable(feature = "int_to_from_bytes", since = "1.32.0")] #[rustc_const_unstable(feature = "const_int_conversion")] #[inline] pub const fn from_ne_bytes(bytes: [u8; mem::size_of::()]) -> Self { diff --git a/src/test/run-pass/const-int-conversion.rs b/src/test/run-pass/const-int-conversion.rs index 790c62288d38b..e199c43858521 100644 --- a/src/test/run-pass/const-int-conversion.rs +++ b/src/test/run-pass/const-int-conversion.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(const_int_conversion, const_int_ops, reverse_bits, int_to_from_bytes)] +#![feature(const_int_conversion, const_int_ops, reverse_bits)] const REVERSE: u32 = 0x12345678_u32.reverse_bits(); const FROM_BE_BYTES: i32 = i32::from_be_bytes([0x12, 0x34, 0x56, 0x78]); diff --git a/src/test/ui/consts/const-int-conversion.rs b/src/test/ui/consts/const-int-conversion.rs index 0abe6b4a1e49f..2a20f0df15ca2 100644 --- a/src/test/ui/consts/const-int-conversion.rs +++ b/src/test/ui/consts/const-int-conversion.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(reverse_bits, int_to_from_bytes)] +#![feature(reverse_bits)] fn main() { let x: &'static i32 = &(5_i32.reverse_bits()); From af54eb2916b9f5707c7bfa577f5db29918870ce2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 25 Nov 2018 10:56:10 +0100 Subject: [PATCH 23/29] read_c_str should call the AllocationExtra hooks --- src/librustc/mir/interpret/allocation.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/librustc/mir/interpret/allocation.rs b/src/librustc/mir/interpret/allocation.rs index c612d6ad1bb24..406d41d343684 100644 --- a/src/librustc/mir/interpret/allocation.rs +++ b/src/librustc/mir/interpret/allocation.rs @@ -172,10 +172,9 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra> Allocation { let offset = ptr.offset.bytes() as usize; match self.bytes[offset..].iter().position(|&c| c == 0) { Some(size) => { - let p1 = Size::from_bytes((size + 1) as u64); - self.check_relocations(cx, ptr, p1)?; - self.check_defined(ptr, p1)?; - Ok(&self.bytes[offset..offset + size]) + let size = Size::from_bytes((size + 1) as u64); + // Go through `get_bytes` for checks and AllocationExtra hooks + self.get_bytes(cx, ptr, size) } None => err!(UnterminatedCString(ptr.erase_tag())), } From 0fac350f9982b78ef5c74ac7db98933262d361b5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 25 Nov 2018 11:23:21 +0100 Subject: [PATCH 24/29] yay for NLL --- src/librustc/mir/interpret/allocation.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/librustc/mir/interpret/allocation.rs b/src/librustc/mir/interpret/allocation.rs index 406d41d343684..3ff0e9f177ddc 100644 --- a/src/librustc/mir/interpret/allocation.rs +++ b/src/librustc/mir/interpret/allocation.rs @@ -314,11 +314,9 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra> Allocation { }, }; - { - let endian = cx.data_layout().endian; - let dst = self.get_bytes_mut(cx, ptr, type_size)?; - write_target_uint(endian, dst, bytes).unwrap(); - } + let endian = cx.data_layout().endian; + let dst = self.get_bytes_mut(cx, ptr, type_size)?; + write_target_uint(endian, dst, bytes).unwrap(); // See if we have to also write a relocation match val { From a6ea01f2396a55c5245b93b8f9c6edd3c5a0e204 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 25 Nov 2018 12:07:20 +0100 Subject: [PATCH 25/29] fix length of slice returned from read_c_str --- src/librustc/mir/interpret/allocation.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/librustc/mir/interpret/allocation.rs b/src/librustc/mir/interpret/allocation.rs index 3ff0e9f177ddc..0ecec75339861 100644 --- a/src/librustc/mir/interpret/allocation.rs +++ b/src/librustc/mir/interpret/allocation.rs @@ -172,9 +172,11 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra> Allocation { let offset = ptr.offset.bytes() as usize; match self.bytes[offset..].iter().position(|&c| c == 0) { Some(size) => { - let size = Size::from_bytes((size + 1) as u64); - // Go through `get_bytes` for checks and AllocationExtra hooks - self.get_bytes(cx, ptr, size) + let size_with_null = Size::from_bytes((size + 1) as u64); + // Go through `get_bytes` for checks and AllocationExtra hooks. + // We read the null, so we include it in the requestm, but we want it removed + // from the result! + Ok(&self.get_bytes(cx, ptr, size_with_null)?[..size]) } None => err!(UnterminatedCString(ptr.erase_tag())), } From 2472e832503995a024a6fbf533b504a0d0bf9e9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oliver=20S=CC=B6c=CC=B6h=CC=B6n=CC=B6e=CC=B6i=CC=B6d=CC=B6?= =?UTF-8?q?e=CC=B6r=20Scherer?= Date: Sun, 25 Nov 2018 14:21:34 +0100 Subject: [PATCH 26/29] Typo Co-Authored-By: RalfJung --- src/librustc/mir/interpret/allocation.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc/mir/interpret/allocation.rs b/src/librustc/mir/interpret/allocation.rs index 0ecec75339861..ab63e882c4a55 100644 --- a/src/librustc/mir/interpret/allocation.rs +++ b/src/librustc/mir/interpret/allocation.rs @@ -174,7 +174,7 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra> Allocation { Some(size) => { let size_with_null = Size::from_bytes((size + 1) as u64); // Go through `get_bytes` for checks and AllocationExtra hooks. - // We read the null, so we include it in the requestm, but we want it removed + // We read the null, so we include it in the request, but we want it removed // from the result! Ok(&self.get_bytes(cx, ptr, size_with_null)?[..size]) } From d4a78da543fd8959edf386602537bece057a3918 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Wed, 31 Oct 2018 00:22:19 +0300 Subject: [PATCH 27/29] resolve: Prohibit relative paths in visibilities on 2018 edition --- src/librustc_resolve/lib.rs | 13 ++++++++++++- src/test/ui/privacy/restricted/relative-2018.rs | 13 +++++++++++++ .../ui/privacy/restricted/relative-2018.stderr | 16 ++++++++++++++++ 3 files changed, 41 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/privacy/restricted/relative-2018.rs create mode 100644 src/test/ui/privacy/restricted/relative-2018.stderr diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 12dabd2a31da1..a392ab717c06c 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -4710,7 +4710,18 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> { ty::Visibility::Restricted(self.current_module.normal_ancestor_id) } ast::VisibilityKind::Restricted { ref path, id, .. } => { - // Visibilities are resolved as global by default, add starting root segment. + // For visibilities we are not ready to provide correct implementation of "uniform + // paths" right now, so on 2018 edition we only allow module-relative paths for now. + let first_ident = path.segments[0].ident; + if self.session.rust_2018() && !first_ident.is_path_segment_keyword() { + let msg = "relative paths are not supported in visibilities on 2018 edition"; + self.session.struct_span_err(first_ident.span, msg) + .span_suggestion(path.span, "try", format!("crate::{}", path)) + .emit(); + return ty::Visibility::Public; + } + // On 2015 visibilities are resolved as crate-relative by default, + // add starting root segment if necessary. let segments = path.make_root().iter().chain(path.segments.iter()) .map(|seg| Segment { ident: seg.ident, id: Some(seg.id) }) .collect::>(); diff --git a/src/test/ui/privacy/restricted/relative-2018.rs b/src/test/ui/privacy/restricted/relative-2018.rs new file mode 100644 index 0000000000000..69b7c1e4d4f3c --- /dev/null +++ b/src/test/ui/privacy/restricted/relative-2018.rs @@ -0,0 +1,13 @@ +// edition:2018 + +mod m { + pub(in crate) struct S1; // OK + pub(in super) struct S2; // OK + pub(in self) struct S3; // OK + pub(in ::core) struct S4; + //~^ ERROR visibilities can only be restricted to ancestor modules + pub(in a::b) struct S5; + //~^ ERROR relative paths are not supported in visibilities on 2018 edition +} + +fn main() {} diff --git a/src/test/ui/privacy/restricted/relative-2018.stderr b/src/test/ui/privacy/restricted/relative-2018.stderr new file mode 100644 index 0000000000000..61effc463e98f --- /dev/null +++ b/src/test/ui/privacy/restricted/relative-2018.stderr @@ -0,0 +1,16 @@ +error: visibilities can only be restricted to ancestor modules + --> $DIR/relative-2018.rs:7:12 + | +LL | pub(in ::core) struct S4; + | ^^^^^^ + +error: relative paths are not supported in visibilities on 2018 edition + --> $DIR/relative-2018.rs:9:12 + | +LL | pub(in a::b) struct S5; + | ^--- + | | + | help: try: `crate::a::b` + +error: aborting due to 2 previous errors + From e593431bc7f3ad89aea8e792384d6719bf60f3f3 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sun, 25 Nov 2018 04:25:59 +0300 Subject: [PATCH 28/29] resolve: Fix bad span arithmetics in import conflict diagnostics --- src/librustc_resolve/lib.rs | 10 +++++----- src/test/ui/issues/issue-45829/import-self.rs | 3 +++ .../ui/issues/issue-45829/import-self.stderr | 20 ++++++++++++++++--- 3 files changed, 25 insertions(+), 8 deletions(-) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index a392ab717c06c..443b1ccdef836 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -4999,10 +4999,10 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> { err.span_suggestion_with_applicability( binding.span, &rename_msg, - match (&directive.subclass, snippet.as_ref()) { - (ImportDirectiveSubclass::SingleImport { .. }, "self") => + match directive.subclass { + ImportDirectiveSubclass::SingleImport { type_ns_only: true, .. } => format!("self as {}", suggested_name), - (ImportDirectiveSubclass::SingleImport { source, .. }, _) => + ImportDirectiveSubclass::SingleImport { source, .. } => format!( "{} as {}{}", &snippet[..((source.span.hi().0 - binding.span.lo().0) as usize)], @@ -5013,13 +5013,13 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> { "" } ), - (ImportDirectiveSubclass::ExternCrate { source, target, .. }, _) => + ImportDirectiveSubclass::ExternCrate { source, target, .. } => format!( "extern crate {} as {};", source.unwrap_or(target.name), suggested_name, ), - (_, _) => unreachable!(), + _ => unreachable!(), }, Applicability::MaybeIncorrect, ); diff --git a/src/test/ui/issues/issue-45829/import-self.rs b/src/test/ui/issues/issue-45829/import-self.rs index 8b13ffd0076d5..eb5fb458d8279 100644 --- a/src/test/ui/issues/issue-45829/import-self.rs +++ b/src/test/ui/issues/issue-45829/import-self.rs @@ -19,4 +19,7 @@ use foo as self; use foo::self; +use foo::A; +use foo::{self as A}; + fn main() {} diff --git a/src/test/ui/issues/issue-45829/import-self.stderr b/src/test/ui/issues/issue-45829/import-self.stderr index 985dc4e7131cf..55e51952a8804 100644 --- a/src/test/ui/issues/issue-45829/import-self.stderr +++ b/src/test/ui/issues/issue-45829/import-self.stderr @@ -25,7 +25,21 @@ help: you can use `as` to change the binding name of the import LL | use foo::{self as other_foo}; | ^^^^^^^^^^^^^^^^^ -error: aborting due to 3 previous errors +error[E0252]: the name `A` is defined multiple times + --> $DIR/import-self.rs:23:11 + | +LL | use foo::A; + | ------ previous import of the type `A` here +LL | use foo::{self as A}; + | ^^^^^^^^^ `A` reimported here + | + = note: `A` must be defined only once in the type namespace of this module +help: you can use `as` to change the binding name of the import + | +LL | use foo::{self as OtherA}; + | ^^^^^^^^^^^^^^ + +error: aborting due to 4 previous errors -Some errors occurred: E0255, E0429. -For more information about an error, try `rustc --explain E0255`. +Some errors occurred: E0252, E0255, E0429. +For more information about an error, try `rustc --explain E0252`. From fe548e311a8f3a2e193989dc959841874738423f Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sun, 25 Nov 2018 05:45:43 +0300 Subject: [PATCH 29/29] resolve: Fix some more asserts in import validation --- src/librustc_resolve/resolve_imports.rs | 3 +- src/test/ui/imports/auxiliary/issue-56125.rs | 2 + src/test/ui/imports/issue-56125.rs | 25 +++++++-- src/test/ui/imports/issue-56125.stderr | 59 +++++++++++++------- 4 files changed, 63 insertions(+), 26 deletions(-) diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index 616cc9d2fc51b..52e3e54b9f931 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -864,7 +864,8 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> { } PathResult::NonModule(path_res) if path_res.base_def() == Def::Err => { // The error was already reported earlier. - assert!(directive.imported_module.get().is_none()); + assert!(!self.ambiguity_errors.is_empty() || + directive.imported_module.get().is_none()); return None; } PathResult::Indeterminate | PathResult::NonModule(..) => unreachable!(), diff --git a/src/test/ui/imports/auxiliary/issue-56125.rs b/src/test/ui/imports/auxiliary/issue-56125.rs index 0ff407756b3ae..8e0797582970d 100644 --- a/src/test/ui/imports/auxiliary/issue-56125.rs +++ b/src/test/ui/imports/auxiliary/issue-56125.rs @@ -1,3 +1,5 @@ +pub mod issue_56125 {} + pub mod last_segment { pub mod issue_56125 {} } diff --git a/src/test/ui/imports/issue-56125.rs b/src/test/ui/imports/issue-56125.rs index 4baeb8a34dd76..843b52f18435e 100644 --- a/src/test/ui/imports/issue-56125.rs +++ b/src/test/ui/imports/issue-56125.rs @@ -2,11 +2,24 @@ // compile-flags:--extern issue_56125 // aux-build:issue-56125.rs -use issue_56125::last_segment::*; -//~^ ERROR `issue_56125` is ambiguous -//~| ERROR unresolved import `issue_56125::last_segment` -use issue_56125::non_last_segment::non_last_segment::*; -//~^ ERROR `issue_56125` is ambiguous -//~| ERROR failed to resolve: could not find `non_last_segment` in `issue_56125` +#![feature(uniform_paths)] + +mod m1 { + use issue_56125::last_segment::*; + //~^ ERROR `issue_56125` is ambiguous + //~| ERROR unresolved import `issue_56125::last_segment` +} + +mod m2 { + use issue_56125::non_last_segment::non_last_segment::*; + //~^ ERROR `issue_56125` is ambiguous + //~| ERROR failed to resolve: could not find `non_last_segment` in `issue_56125` +} + +mod m3 { + mod empty {} + use empty::issue_56125; //~ ERROR unresolved import `empty::issue_56125` + use issue_56125::*; //~ ERROR `issue_56125` is ambiguous +} fn main() {} diff --git a/src/test/ui/imports/issue-56125.stderr b/src/test/ui/imports/issue-56125.stderr index 096d5be97f0e0..b1292ef8f783e 100644 --- a/src/test/ui/imports/issue-56125.stderr +++ b/src/test/ui/imports/issue-56125.stderr @@ -1,46 +1,67 @@ error[E0433]: failed to resolve: could not find `non_last_segment` in `issue_56125` - --> $DIR/issue-56125.rs:8:18 + --> $DIR/issue-56125.rs:14:22 | -LL | use issue_56125::non_last_segment::non_last_segment::*; - | ^^^^^^^^^^^^^^^^ could not find `non_last_segment` in `issue_56125` +LL | use issue_56125::non_last_segment::non_last_segment::*; + | ^^^^^^^^^^^^^^^^ could not find `non_last_segment` in `issue_56125` error[E0432]: unresolved import `issue_56125::last_segment` - --> $DIR/issue-56125.rs:5:18 + --> $DIR/issue-56125.rs:8:22 | -LL | use issue_56125::last_segment::*; - | ^^^^^^^^^^^^ could not find `last_segment` in `issue_56125` +LL | use issue_56125::last_segment::*; + | ^^^^^^^^^^^^ could not find `last_segment` in `issue_56125` + +error[E0432]: unresolved import `empty::issue_56125` + --> $DIR/issue-56125.rs:21:9 + | +LL | use empty::issue_56125; //~ ERROR unresolved import `empty::issue_56125` + | ^^^^^^^^^^^^^^^^^^ no `issue_56125` in `m3::empty` error[E0659]: `issue_56125` is ambiguous (name vs any other name during import resolution) - --> $DIR/issue-56125.rs:5:5 + --> $DIR/issue-56125.rs:8:9 | -LL | use issue_56125::last_segment::*; - | ^^^^^^^^^^^ ambiguous name +LL | use issue_56125::last_segment::*; + | ^^^^^^^^^^^ ambiguous name | = note: `issue_56125` could refer to an extern crate passed with `--extern` = help: use `::issue_56125` to refer to this extern crate unambiguously note: `issue_56125` could also refer to the module imported here - --> $DIR/issue-56125.rs:5:5 + --> $DIR/issue-56125.rs:8:9 | -LL | use issue_56125::last_segment::*; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | use issue_56125::last_segment::*; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = help: use `self::issue_56125` to refer to this module unambiguously error[E0659]: `issue_56125` is ambiguous (name vs any other name during import resolution) - --> $DIR/issue-56125.rs:8:5 + --> $DIR/issue-56125.rs:14:9 | -LL | use issue_56125::non_last_segment::non_last_segment::*; - | ^^^^^^^^^^^ ambiguous name +LL | use issue_56125::non_last_segment::non_last_segment::*; + | ^^^^^^^^^^^ ambiguous name | = note: `issue_56125` could refer to an extern crate passed with `--extern` = help: use `::issue_56125` to refer to this extern crate unambiguously note: `issue_56125` could also refer to the module imported here - --> $DIR/issue-56125.rs:5:5 + --> $DIR/issue-56125.rs:14:9 | -LL | use issue_56125::last_segment::*; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | use issue_56125::non_last_segment::non_last_segment::*; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = help: use `self::issue_56125` to refer to this module unambiguously -error: aborting due to 4 previous errors +error[E0659]: `issue_56125` is ambiguous (name vs any other name during import resolution) + --> $DIR/issue-56125.rs:22:9 + | +LL | use issue_56125::*; //~ ERROR `issue_56125` is ambiguous + | ^^^^^^^^^^^ ambiguous name + | + = note: `issue_56125` could refer to an extern crate passed with `--extern` + = help: use `::issue_56125` to refer to this extern crate unambiguously +note: `issue_56125` could also refer to the unresolved item imported here + --> $DIR/issue-56125.rs:21:9 + | +LL | use empty::issue_56125; //~ ERROR unresolved import `empty::issue_56125` + | ^^^^^^^^^^^^^^^^^^ + = help: use `self::issue_56125` to refer to this unresolved item unambiguously + +error: aborting due to 6 previous errors Some errors occurred: E0432, E0433, E0659. For more information about an error, try `rustc --explain E0432`.