From 8a6ef505750152cf9034dfe26858b241221a3400 Mon Sep 17 00:00:00 2001 From: Austin Bonander Date: Thu, 16 Mar 2017 14:41:08 -0700 Subject: Regression test for rust-lang/rust#40535 --- src/test/run-make/issue-40535/Makefile | 11 +++++++++++ src/test/run-make/issue-40535/bar.rs | 13 +++++++++++++ src/test/run-make/issue-40535/baz.rs | 11 +++++++++++ src/test/run-make/issue-40535/foo.rs | 14 ++++++++++++++ 4 files changed, 49 insertions(+) create mode 100644 src/test/run-make/issue-40535/Makefile create mode 100644 src/test/run-make/issue-40535/bar.rs create mode 100644 src/test/run-make/issue-40535/baz.rs create mode 100644 src/test/run-make/issue-40535/foo.rs (limited to 'src/test') diff --git a/src/test/run-make/issue-40535/Makefile b/src/test/run-make/issue-40535/Makefile new file mode 100644 index 00000000000..7d513a86a7f --- /dev/null +++ b/src/test/run-make/issue-40535/Makefile @@ -0,0 +1,11 @@ +# The ICE occurred in the following situation: +# * `foo` declares `extern crate bar, baz`, depends only on `bar` (forgetting `baz` in `Cargo.toml`) +# * `bar` declares and depends on `extern crate baz` +# * All crates built in metadata-only mode (`cargo check`) +all: + # cc https://github.com/rust-lang/rust/issues/40623 + $(RUSTC) baz.rs --emit=metadata --out-dir=$(TMPDIR) + $(RUSTC) bar.rs --emit=metadata --extern baz=$(TMPDIR)/libbaz.rmeta --out-dir=$(TMPDIR) + $(RUSTC) foo.rs --emit=metadata --extern bar=$(TMPDIR)/libbar.rmeta --out-dir=$(TMPDIR) 2>&1 | \ + grep -vq "unexpectedly panicked" + # ^ Succeeds if it doesn't find the ICE message diff --git a/src/test/run-make/issue-40535/bar.rs b/src/test/run-make/issue-40535/bar.rs new file mode 100644 index 00000000000..4c22f181975 --- /dev/null +++ b/src/test/run-make/issue-40535/bar.rs @@ -0,0 +1,13 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![crate_type = "lib"] + +extern crate baz; diff --git a/src/test/run-make/issue-40535/baz.rs b/src/test/run-make/issue-40535/baz.rs new file mode 100644 index 00000000000..737a918a039 --- /dev/null +++ b/src/test/run-make/issue-40535/baz.rs @@ -0,0 +1,11 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![crate_type = "lib"] diff --git a/src/test/run-make/issue-40535/foo.rs b/src/test/run-make/issue-40535/foo.rs new file mode 100644 index 00000000000..53a8c8636b1 --- /dev/null +++ b/src/test/run-make/issue-40535/foo.rs @@ -0,0 +1,14 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![crate_type = "lib"] + +extern crate bar; +extern crate baz; -- cgit 1.4.1-3-g733a5 From ef90d32f07e187d3e1824d980ad01caac5313101 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 15 Mar 2017 08:09:59 -0700 Subject: rustc: Always emit the `uwtable` attribute on Windows This commit alters the translation layer to unconditionally emit the `uwtable` LLVM attribute on Windows regardless of the `no_landing_pads` setting. Previously I believe we omitted this attribute as an optimization when the `-Cpanic=abort` flag was passed, but this unfortunately caused problems for Gecko. It [was discovered] that there was trouble unwinding through Rust functions due to foreign exceptions such as illegal instructions or otherwise in-practice methods used to abort a process. In testing it looked like the major difference between a working binary and a non-working binary is indeed this `uwtable` attribute, but this PR has unfortunately not been thoroughly tested in terms of compiling Gecko with `-C panic=abort` *and* this PR to see whether it works, so this is still somewhat working on just suspicion. [was discovered]: https://bugzilla.mozilla.org/show_bug.cgi?id=1302078 --- src/librustc_trans/base.rs | 19 ++++++++++++++- src/test/codegen/panic-abort-windows.rs | 41 +++++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+), 1 deletion(-) create mode 100644 src/test/codegen/panic-abort-windows.rs (limited to 'src/test') diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index 6593b8e68d4..80b563729f5 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -583,7 +583,24 @@ pub fn trans_instance<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, instance: Instance ccx.stats().n_closures.set(ccx.stats().n_closures.get() + 1); - if !ccx.sess().no_landing_pads() { + // The `uwtable` attribute according to LLVM is: + // + // This attribute indicates that the ABI being targeted requires that an + // unwind table entry be produced for this function even if we can show + // that no exceptions passes by it. This is normally the case for the + // ELF x86-64 abi, but it can be disabled for some compilation units. + // + // Typically when we're compiling with `-C panic=abort` (which implies this + // `no_landing_pads` check) we don't need `uwtable` because we can't + // generate any exceptions! On Windows, however, exceptions include other + // events such as illegal instructions, segfaults, etc. This means that on + // Windows we end up still needing the `uwtable` attribute even if the `-C + // panic=abort` flag is passed. + // + // You can also find more info on why Windows is whitelisted here in: + // https://bugzilla.mozilla.org/show_bug.cgi?id=1302078 + if !ccx.sess().no_landing_pads() || + ccx.sess().target.target.options.is_like_windows { attributes::emit_uwtable(lldecl, true); } diff --git a/src/test/codegen/panic-abort-windows.rs b/src/test/codegen/panic-abort-windows.rs new file mode 100644 index 00000000000..2ab15277084 --- /dev/null +++ b/src/test/codegen/panic-abort-windows.rs @@ -0,0 +1,41 @@ +// Copyright 2015 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. + +// ignore-tidy-linelength + +// This test is for *-windows-msvc only. +// ignore-android +// ignore-bitrig +// ignore-macos +// ignore-dragonfly +// ignore-freebsd +// ignore-haiku +// ignore-ios +// ignore-linux +// ignore-netbsd +// ignore-openbsd +// ignore-solaris +// ignore-emscripten + +// compile-flags: -C no-prepopulate-passes -C panic=abort -O + +#![crate_type = "lib"] + +// CHECK: Function Attrs: uwtable +// CHECK-NEXT: define void @normal_uwtable() +#[no_mangle] +pub fn normal_uwtable() { +} + +// CHECK: Function Attrs: nounwind uwtable +// CHECK-NEXT: define void @extern_uwtable() +#[no_mangle] +pub extern fn extern_uwtable() { +} -- cgit 1.4.1-3-g733a5 From 89ddd717caf7084c9fe292ceaa46828c65573097 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sat, 18 Mar 2017 12:24:42 -0400 Subject: Revert "Auto merge of #39485 - canndrew:inference-fix-39297, r=nikomatsakis" This reverts commit dc0bb3f2839c13ab42feacd423f728fbfd2f2f7a, reversing changes made to e879aa43ef63962f8e4d797292194a9f40a22a13. This is a temporary step intended to fix regressions. A more comprehensive fix for type inference and dead-code is in the works. --- src/librustc_typeck/check/mod.rs | 11 +++++++++++ src/test/compile-fail/issue-10176.rs | 19 +++++++++++++++++++ src/test/compile-fail/issue-5500.rs | 17 +++++++++++++++++ src/test/run-pass/inference-changes-39485.rs | 19 ------------------- src/test/run-pass/issue-15763.rs | 7 +++---- src/test/run-pass/project-defer-unification.rs | 4 +--- 6 files changed, 51 insertions(+), 26 deletions(-) create mode 100644 src/test/compile-fail/issue-10176.rs create mode 100644 src/test/compile-fail/issue-5500.rs delete mode 100644 src/test/run-pass/inference-changes-39485.rs (limited to 'src/test') diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index c857388106d..9c62fd486d4 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -4099,6 +4099,17 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }; if self.diverges.get().always() { + if let ExpectHasType(ety) = expected { + // Avoid forcing a type (only `!` for now) in unreachable code. + // FIXME(aburka) do we need this special case? and should it be is_uninhabited? + if !ety.is_never() { + if let Some(ref e) = blk.expr { + // Coerce the tail expression to the right type. + self.demand_coerce(e, ty, ety); + } + } + } + ty = self.next_diverging_ty_var(TypeVariableOrigin::DivergingBlockExpr(blk.span)); } else if let ExpectHasType(ety) = expected { if let Some(ref e) = blk.expr { diff --git a/src/test/compile-fail/issue-10176.rs b/src/test/compile-fail/issue-10176.rs new file mode 100644 index 00000000000..434b795ff31 --- /dev/null +++ b/src/test/compile-fail/issue-10176.rs @@ -0,0 +1,19 @@ +// Copyright 2014 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. + +fn f() -> isize { + (return 1, return 2) +//~^ ERROR mismatched types +//~| expected type `isize` +//~| found type `(_, _)` +//~| expected isize, found tuple +} + +fn main() {} diff --git a/src/test/compile-fail/issue-5500.rs b/src/test/compile-fail/issue-5500.rs new file mode 100644 index 00000000000..1cbb7588e17 --- /dev/null +++ b/src/test/compile-fail/issue-5500.rs @@ -0,0 +1,17 @@ +// Copyright 2013 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. + +fn main() { + &panic!() + //~^ ERROR mismatched types + //~| expected type `()` + //~| found type `&_` + //~| expected (), found reference +} diff --git a/src/test/run-pass/inference-changes-39485.rs b/src/test/run-pass/inference-changes-39485.rs deleted file mode 100644 index 193c66b2a2a..00000000000 --- a/src/test/run-pass/inference-changes-39485.rs +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2014 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. - -fn g() { - &panic!() -} - -fn f() -> isize { - (return 1, return 2) -} - -fn main() {} diff --git a/src/test/run-pass/issue-15763.rs b/src/test/run-pass/issue-15763.rs index f77888c2955..0baaaac2676 100644 --- a/src/test/run-pass/issue-15763.rs +++ b/src/test/run-pass/issue-15763.rs @@ -8,8 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![allow(unused_features)] -#![allow(unreachable_code)] +#![allow(unknown_features)] #![feature(box_syntax)] #[derive(PartialEq, Debug)] @@ -29,14 +28,14 @@ struct Foo { } fn foo() -> Result { - return Ok::(Foo { + return Ok(Foo { x: Bar { x: 22 }, a: return Err(32) }); } fn baz() -> Result { - Ok::(Foo { + Ok(Foo { x: Bar { x: 22 }, a: return Err(32) }) diff --git a/src/test/run-pass/project-defer-unification.rs b/src/test/run-pass/project-defer-unification.rs index 8e008c639b3..9a6ea2272fe 100644 --- a/src/test/run-pass/project-defer-unification.rs +++ b/src/test/run-pass/project-defer-unification.rs @@ -11,8 +11,6 @@ // A regression test extracted from image-0.3.11. The point of // failure was in `index_colors` below. -#![allow(unused)] - use std::ops::{Deref, DerefMut}; #[derive(Copy, Clone)] @@ -94,7 +92,7 @@ pub fn index_colors(image: &ImageBuffer>) -> ImageBuffer, Vec> where Pix: Pixel + 'static, { - let mut indices: ImageBuffer, Vec> = loop { }; + let mut indices: ImageBuffer<_,Vec<_>> = loop { }; for (pixel, idx) in image.pixels().zip(indices.pixels_mut()) { // failured occurred here ^^ because we were requiring that we // could project Pixel or Subpixel from `T_indices` (type of -- cgit 1.4.1-3-g733a5 From 0f1eb8a70f0f877eba4b55151949df8861377c65 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sat, 18 Mar 2017 12:28:34 -0400 Subject: add regression test for #39984 Fixes #39984 --- src/test/run-pass/issue-39984.rs | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 src/test/run-pass/issue-39984.rs (limited to 'src/test') diff --git a/src/test/run-pass/issue-39984.rs b/src/test/run-pass/issue-39984.rs new file mode 100644 index 00000000000..a0019e7215c --- /dev/null +++ b/src/test/run-pass/issue-39984.rs @@ -0,0 +1,21 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Regression test for issue #39984. +// +// The key here is that the error type of the `Ok` call ought to be +// constrained to `String`, even though it is dead-code. + +fn main() {} + +fn t() -> Result<(), String> { + return Err("".into()); + Ok(()) +} -- cgit 1.4.1-3-g733a5 From bc259ee844f608599293c83d96de353005681cca Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Tue, 14 Mar 2017 15:50:40 +0100 Subject: Introduce HirId, a replacement for NodeId after lowering to HIR. HirId has a more stable representation than NodeId, meaning that modifications to one item don't influence (part of) the IDs within other items. The other part is a DefIndex for which there already is a way of stable hashing and persistence. This commit introduces the HirId type and generates a HirId for every NodeId during HIR lowering, but the resulting values are not yet used anywhere, except in consistency checks. --- src/librustc/hir/lowering.rs | 1773 +++++++++++--------- src/librustc/hir/map/definitions.rs | 30 + src/librustc/hir/map/hir_id_validator.rs | 184 ++ src/librustc/hir/map/mod.rs | 9 +- src/librustc/hir/mod.rs | 61 +- src/libsyntax/ext/placeholders.rs | 14 +- ...region-bounds-on-objects-and-type-parameters.rs | 2 +- 7 files changed, 1286 insertions(+), 787 deletions(-) create mode 100644 src/librustc/hir/map/hir_id_validator.rs (limited to 'src/test') diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 81591a5650f..22ca0e421be 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -43,12 +43,14 @@ use hir; use hir::map::{Definitions, DefKey}; use hir::map::definitions::DefPathData; -use hir::def_id::{DefIndex, DefId}; +use hir::def_id::{DefIndex, DefId, CRATE_DEF_INDEX}; use hir::def::{Def, PathResolution}; +use rustc_data_structures::indexed_vec::IndexVec; use session::Session; use util::nodemap::{DefIdMap, NodeMap}; use std::collections::BTreeMap; +use std::fmt::Debug; use std::iter; use std::mem; @@ -63,6 +65,8 @@ use syntax::util::small_vector::SmallVector; use syntax::visit::{self, Visitor}; use syntax_pos::Span; +const HIR_ID_COUNTER_LOCKED: u32 = 0xFFFFFFFF; + pub struct LoweringContext<'a> { crate_root: Option<&'static str>, // Use to assign ids to hir nodes that do not directly correspond to an ast node @@ -89,6 +93,10 @@ pub struct LoweringContext<'a> { is_in_loop_condition: bool, type_def_lifetime_params: DefIdMap, + + current_hir_id_owner: Vec<(DefIndex, u32)>, + item_local_id_counters: NodeMap, + node_id_to_hir_id: IndexVec, } pub trait Resolver { @@ -128,6 +136,9 @@ pub fn lower_crate(sess: &Session, loop_scopes: Vec::new(), is_in_loop_condition: false, type_def_lifetime_params: DefIdMap(), + current_hir_id_owner: vec![(CRATE_DEF_INDEX, 0)], + item_local_id_counters: NodeMap(), + node_id_to_hir_id: IndexVec::new(), }.lower_crate(krate) } @@ -152,6 +163,8 @@ impl<'a> LoweringContext<'a> { impl<'lcx, 'interner> Visitor<'lcx> for MiscCollector<'lcx, 'interner> { fn visit_item(&mut self, item: &'lcx Item) { + self.lctx.allocate_hir_id_counter(item.id, item); + match item.node { ItemKind::Struct(_, ref generics) | ItemKind::Union(_, ref generics) | @@ -166,6 +179,16 @@ impl<'a> LoweringContext<'a> { } visit::walk_item(self, item); } + + fn visit_trait_item(&mut self, item: &'lcx TraitItem) { + self.lctx.allocate_hir_id_counter(item.id, item); + visit::walk_trait_item(self, item); + } + + fn visit_impl_item(&mut self, item: &'lcx ImplItem) { + self.lctx.allocate_hir_id_counter(item.id, item); + visit::walk_impl_item(self, item); + } } struct ItemLowerer<'lcx, 'interner: 'lcx> { @@ -174,27 +197,43 @@ impl<'a> LoweringContext<'a> { impl<'lcx, 'interner> Visitor<'lcx> for ItemLowerer<'lcx, 'interner> { fn visit_item(&mut self, item: &'lcx Item) { - if let Some(hir_item) = self.lctx.lower_item(item) { - self.lctx.items.insert(item.id, hir_item); + let mut item_lowered = true; + self.lctx.with_hir_id_owner(item.id, |lctx| { + if let Some(hir_item) = lctx.lower_item(item) { + lctx.items.insert(item.id, hir_item); + } else { + item_lowered = false; + } + }); + + if item_lowered { visit::walk_item(self, item); } } fn visit_trait_item(&mut self, item: &'lcx TraitItem) { - let id = hir::TraitItemId { node_id: item.id }; - let hir_item = self.lctx.lower_trait_item(item); - self.lctx.trait_items.insert(id, hir_item); + self.lctx.with_hir_id_owner(item.id, |lctx| { + let id = hir::TraitItemId { node_id: item.id }; + let hir_item = lctx.lower_trait_item(item); + lctx.trait_items.insert(id, hir_item); + }); + visit::walk_trait_item(self, item); } fn visit_impl_item(&mut self, item: &'lcx ImplItem) { - let id = hir::ImplItemId { node_id: item.id }; - let hir_item = self.lctx.lower_impl_item(item); - self.lctx.impl_items.insert(id, hir_item); + self.lctx.with_hir_id_owner(item.id, |lctx| { + let id = hir::ImplItemId { node_id: item.id }; + let hir_item = lctx.lower_impl_item(item); + lctx.impl_items.insert(id, hir_item); + }); visit::walk_impl_item(self, item); } } + self.lower_node_id(CRATE_NODE_ID); + debug_assert!(self.node_id_to_hir_id[CRATE_NODE_ID] == hir::CRATE_HIR_ID); + visit::walk_crate(&mut MiscCollector { lctx: &mut self }, c); visit::walk_crate(&mut ItemLowerer { lctx: &mut self }, c); @@ -202,6 +241,10 @@ impl<'a> LoweringContext<'a> { let attrs = self.lower_attrs(&c.attrs); let body_ids = body_ids(&self.bodies); + self.resolver + .definitions() + .init_node_id_to_hir_id_mapping(self.node_id_to_hir_id); + hir::Crate { module: module, attrs: attrs, @@ -217,6 +260,103 @@ impl<'a> LoweringContext<'a> { } } + fn allocate_hir_id_counter(&mut self, + owner: NodeId, + debug: &T) { + if self.item_local_id_counters.insert(owner, 0).is_some() { + bug!("Tried to allocate item_local_id_counter for {:?} twice", debug); + } + // Always allocate the first HirId for the owner itself + self.lower_node_id_with_owner(owner, owner); + } + + fn lower_node_id_generic(&mut self, + ast_node_id: NodeId, + alloc_hir_id: F) + -> NodeId + where F: FnOnce(&mut Self) -> hir::HirId + { + if ast_node_id == DUMMY_NODE_ID { + return ast_node_id; + } + + let min_size = ast_node_id.as_usize() + 1; + + if min_size > self.node_id_to_hir_id.len() { + self.node_id_to_hir_id.resize(min_size, hir::DUMMY_HIR_ID); + } + + if self.node_id_to_hir_id[ast_node_id] == hir::DUMMY_HIR_ID { + // Generate a new HirId + self.node_id_to_hir_id[ast_node_id] = alloc_hir_id(self); + } + + ast_node_id + } + + fn with_hir_id_owner(&mut self, owner: NodeId, f: F) + where F: FnOnce(&mut Self) + { + let counter = self.item_local_id_counters + .insert(owner, HIR_ID_COUNTER_LOCKED) + .unwrap(); + let def_index = self.resolver.definitions().opt_def_index(owner).unwrap(); + self.current_hir_id_owner.push((def_index, counter)); + f(self); + let (new_def_index, new_counter) = self.current_hir_id_owner.pop().unwrap(); + + debug_assert!(def_index == new_def_index); + debug_assert!(new_counter >= counter); + + let prev = self.item_local_id_counters.insert(owner, new_counter).unwrap(); + debug_assert!(prev == HIR_ID_COUNTER_LOCKED); + } + + /// This method allocates a new HirId for the given NodeId and stores it in + /// the LoweringContext's NodeId => HirId map. + /// Take care not to call this method if the resulting HirId is then not + /// actually used in the HIR, as that would trigger an assertion in the + /// HirIdValidator later on, which makes sure that all NodeIds got mapped + /// properly. Calling the method twice with the same NodeId is fine though. + fn lower_node_id(&mut self, ast_node_id: NodeId) -> NodeId { + self.lower_node_id_generic(ast_node_id, |this| { + let &mut (def_index, ref mut local_id_counter) = this.current_hir_id_owner + .last_mut() + .unwrap(); + let local_id = *local_id_counter; + *local_id_counter += 1; + hir::HirId { + owner: def_index, + local_id: hir::ItemLocalId(local_id), + } + }) + } + + fn lower_node_id_with_owner(&mut self, + ast_node_id: NodeId, + owner: NodeId) + -> NodeId { + self.lower_node_id_generic(ast_node_id, |this| { + let local_id_counter = this.item_local_id_counters + .get_mut(&owner) + .unwrap(); + let local_id = *local_id_counter; + + // We want to be sure not to modify the counter in the map while it + // is also on the stack. Otherwise we'll get lost updates when writing + // back from the stack to the map. + debug_assert!(local_id != HIR_ID_COUNTER_LOCKED); + + *local_id_counter += 1; + let def_index = this.resolver.definitions().opt_def_index(owner).unwrap(); + + hir::HirId { + owner: def_index, + local_id: hir::ItemLocalId(local_id), + } + }) + } + fn record_body(&mut self, value: hir::Expr, decl: Option<&FnDecl>) -> hir::BodyId { let body = hir::Body { @@ -230,8 +370,8 @@ impl<'a> LoweringContext<'a> { id } - fn next_id(&self) -> NodeId { - self.sess.next_node_id() + fn next_id(&mut self) -> NodeId { + self.lower_node_id(self.sess.next_node_id()) } fn expect_full_def(&mut self, id: NodeId) -> Def { @@ -362,7 +502,7 @@ impl<'a> LoweringContext<'a> { match destination { Some((id, label_ident)) => { let target = if let Def::Label(loop_id) = self.expect_full_def(id) { - hir::LoopIdResult::Ok(loop_id) + hir::LoopIdResult::Ok(self.lower_node_id(loop_id)) } else { hir::LoopIdResult::Err(hir::LoopIdError::UnresolvedLabel) }; @@ -371,11 +511,18 @@ impl<'a> LoweringContext<'a> { target_id: hir::ScopeTarget::Loop(target), } }, - None => hir::Destination { - ident: None, - target_id: hir::ScopeTarget::Loop( - self.loop_scopes.last().map(|innermost_loop_id| Ok(*innermost_loop_id)) - .unwrap_or(Err(hir::LoopIdError::OutsideLoopScope)).into()) + None => { + let loop_id = self.loop_scopes + .last() + .map(|innermost_loop_id| *innermost_loop_id); + + hir::Destination { + ident: None, + target_id: hir::ScopeTarget::Loop( + loop_id.map(|id| Ok(self.lower_node_id(id))) + .unwrap_or(Err(hir::LoopIdError::OutsideLoopScope)) + .into()) + } } } } @@ -395,7 +542,7 @@ impl<'a> LoweringContext<'a> { fn lower_ty_binding(&mut self, b: &TypeBinding) -> hir::TypeBinding { hir::TypeBinding { - id: b.id, + id: self.lower_node_id(b.id), name: b.ident.name, ty: self.lower_ty(&b.ty), span: b.span, @@ -403,82 +550,87 @@ impl<'a> LoweringContext<'a> { } fn lower_ty(&mut self, t: &Ty) -> P { - P(hir::Ty { - id: t.id, - node: match t.node { - TyKind::Infer => hir::TyInfer, - TyKind::Slice(ref ty) => hir::TySlice(self.lower_ty(ty)), - TyKind::Ptr(ref mt) => hir::TyPtr(self.lower_mt(mt)), - TyKind::Rptr(ref region, ref mt) => { - let span = Span { hi: t.span.lo, ..t.span }; - let lifetime = match *region { - Some(ref lt) => self.lower_lifetime(lt), - None => self.elided_lifetime(span) - }; - hir::TyRptr(lifetime, self.lower_mt(mt)) - } - TyKind::BareFn(ref f) => { - hir::TyBareFn(P(hir::BareFnTy { - lifetimes: self.lower_lifetime_defs(&f.lifetimes), - unsafety: self.lower_unsafety(f.unsafety), - abi: f.abi, - decl: self.lower_fn_decl(&f.decl), - })) - } - TyKind::Never => hir::TyNever, - TyKind::Tup(ref tys) => { - hir::TyTup(tys.iter().map(|ty| self.lower_ty(ty)).collect()) - } - TyKind::Paren(ref ty) => { - return self.lower_ty(ty); - } - TyKind::Path(ref qself, ref path) => { - let qpath = self.lower_qpath(t.id, qself, path, ParamMode::Explicit); - return self.ty_path(t.id, t.span, qpath); - } - TyKind::ImplicitSelf => { - hir::TyPath(hir::QPath::Resolved(None, P(hir::Path { - def: self.expect_full_def(t.id), - segments: hir_vec![hir::PathSegment { - name: keywords::SelfType.name(), - parameters: hir::PathParameters::none() - }], - span: t.span, - }))) - } - TyKind::Array(ref ty, ref length) => { - let length = self.lower_expr(length); - hir::TyArray(self.lower_ty(ty), - self.record_body(length, None)) - } - TyKind::Typeof(ref expr) => { - let expr = self.lower_expr(expr); - hir::TyTypeof(self.record_body(expr, None)) - } - TyKind::TraitObject(ref bounds) => { - let mut lifetime_bound = None; - let bounds = bounds.iter().filter_map(|bound| { - match *bound { - TraitTyParamBound(ref ty, TraitBoundModifier::None) => { - Some(self.lower_poly_trait_ref(ty)) - } - TraitTyParamBound(_, TraitBoundModifier::Maybe) => None, - RegionTyParamBound(ref lifetime) => { + let kind = match t.node { + TyKind::Infer => hir::TyInfer, + TyKind::Slice(ref ty) => hir::TySlice(self.lower_ty(ty)), + TyKind::Ptr(ref mt) => hir::TyPtr(self.lower_mt(mt)), + TyKind::Rptr(ref region, ref mt) => { + let span = Span { hi: t.span.lo, ..t.span }; + let lifetime = match *region { + Some(ref lt) => self.lower_lifetime(lt), + None => self.elided_lifetime(span) + }; + hir::TyRptr(lifetime, self.lower_mt(mt)) + } + TyKind::BareFn(ref f) => { + hir::TyBareFn(P(hir::BareFnTy { + lifetimes: self.lower_lifetime_defs(&f.lifetimes), + unsafety: self.lower_unsafety(f.unsafety), + abi: f.abi, + decl: self.lower_fn_decl(&f.decl), + })) + } + TyKind::Never => hir::TyNever, + TyKind::Tup(ref tys) => { + hir::TyTup(tys.iter().map(|ty| self.lower_ty(ty)).collect()) + } + TyKind::Paren(ref ty) => { + return self.lower_ty(ty); + } + TyKind::Path(ref qself, ref path) => { + let id = self.lower_node_id(t.id); + let qpath = self.lower_qpath(t.id, qself, path, ParamMode::Explicit); + return self.ty_path(id, t.span, qpath); + } + TyKind::ImplicitSelf => { + hir::TyPath(hir::QPath::Resolved(None, P(hir::Path { + def: self.expect_full_def(t.id), + segments: hir_vec![hir::PathSegment { + name: keywords::SelfType.name(), + parameters: hir::PathParameters::none() + }], + span: t.span, + }))) + } + TyKind::Array(ref ty, ref length) => { + let length = self.lower_expr(length); + hir::TyArray(self.lower_ty(ty), + self.record_body(length, None)) + } + TyKind::Typeof(ref expr) => { + let expr = self.lower_expr(expr); + hir::TyTypeof(self.record_body(expr, None)) + } + TyKind::TraitObject(ref bounds) => { + let mut lifetime_bound = None; + let bounds = bounds.iter().filter_map(|bound| { + match *bound { + TraitTyParamBound(ref ty, TraitBoundModifier::None) => { + Some(self.lower_poly_trait_ref(ty)) + } + TraitTyParamBound(_, TraitBoundModifier::Maybe) => None, + RegionTyParamBound(ref lifetime) => { + if lifetime_bound.is_none() { lifetime_bound = Some(self.lower_lifetime(lifetime)); - None } + None } - }).collect(); - let lifetime_bound = lifetime_bound.unwrap_or_else(|| { - self.elided_lifetime(t.span) - }); - hir::TyTraitObject(bounds, lifetime_bound) - } - TyKind::ImplTrait(ref bounds) => { - hir::TyImplTrait(self.lower_bounds(bounds)) - } - TyKind::Mac(_) => panic!("TyMac should have been expanded by now."), - }, + } + }).collect(); + let lifetime_bound = lifetime_bound.unwrap_or_else(|| { + self.elided_lifetime(t.span) + }); + hir::TyTraitObject(bounds, lifetime_bound) + } + TyKind::ImplTrait(ref bounds) => { + hir::TyImplTrait(self.lower_bounds(bounds)) + } + TyKind::Mac(_) => panic!("TyMac should have been expanded by now."), + }; + + P(hir::Ty { + id: self.lower_node_id(t.id), + node: kind, span: t.span, }) } @@ -712,7 +864,7 @@ impl<'a> LoweringContext<'a> { fn lower_local(&mut self, l: &Local) -> P { P(hir::Local { - id: l.id, + id: self.lower_node_id(l.id), ty: l.ty.as_ref().map(|t| self.lower_ty(t)), pat: self.lower_pat(&l.pat), init: l.init.as_ref().map(|e| P(self.lower_expr(e))), @@ -730,7 +882,7 @@ impl<'a> LoweringContext<'a> { fn lower_arg(&mut self, arg: &Arg) -> hir::Arg { hir::Arg { - id: arg.id, + id: self.lower_node_id(arg.id), pat: self.lower_pat(&arg.pat), } } @@ -786,7 +938,7 @@ impl<'a> LoweringContext<'a> { } hir::TyParam { - id: tp.id, + id: self.lower_node_id(tp.id), name: name, bounds: bounds, default: tp.default.as_ref().map(|x| self.lower_ty(x)), @@ -804,7 +956,7 @@ impl<'a> LoweringContext<'a> { fn lower_lifetime(&mut self, l: &Lifetime) -> hir::Lifetime { hir::Lifetime { - id: l.id, + id: self.lower_node_id(l.id), name: l.name, span: l.span, } @@ -876,7 +1028,7 @@ impl<'a> LoweringContext<'a> { fn lower_where_clause(&mut self, wc: &WhereClause) -> hir::WhereClause { hir::WhereClause { - id: wc.id, + id: self.lower_node_id(wc.id), predicates: wc.predicates .iter() .map(|predicate| self.lower_where_predicate(predicate)) @@ -915,7 +1067,7 @@ impl<'a> LoweringContext<'a> { ref rhs_ty, span}) => { hir::WherePredicate::EqPredicate(hir::WhereEqPredicate { - id: id, + id: self.lower_node_id(id), lhs_ty: self.lower_ty(lhs_ty), rhs_ty: self.lower_ty(rhs_ty), span: span, @@ -931,16 +1083,16 @@ impl<'a> LoweringContext<'a> { .enumerate() .map(|f| self.lower_struct_field(f)) .collect(), - id) + self.lower_node_id(id)) } VariantData::Tuple(ref fields, id) => { hir::VariantData::Tuple(fields.iter() .enumerate() .map(|f| self.lower_struct_field(f)) .collect(), - id) + self.lower_node_id(id)) } - VariantData::Unit(id) => hir::VariantData::Unit(id), + VariantData::Unit(id) => hir::VariantData::Unit(self.lower_node_id(id)), } } @@ -951,7 +1103,7 @@ impl<'a> LoweringContext<'a> { }; hir::TraitRef { path: path, - ref_id: p.ref_id, + ref_id: self.lower_node_id(p.ref_id), } } @@ -966,9 +1118,9 @@ impl<'a> LoweringContext<'a> { fn lower_struct_field(&mut self, (index, f): (usize, &StructField)) -> hir::StructField { hir::StructField { span: f.span, - id: f.id, + id: self.lower_node_id(f.id), name: f.ident.map(|ident| ident.name).unwrap_or(Symbol::intern(&index.to_string())), - vis: self.lower_visibility(&f.vis), + vis: self.lower_visibility(&f.vis, None), ty: self.lower_ty(&f.ty), attrs: self.lower_attrs(&f.attrs), } @@ -997,17 +1149,22 @@ impl<'a> LoweringContext<'a> { fn lower_block(&mut self, b: &Block, break_to: Option) -> P { let mut expr = None; - let mut stmts = b.stmts.iter().flat_map(|s| self.lower_stmt(s)).collect::>(); - if let Some(last) = stmts.pop() { - if let hir::StmtExpr(e, _) = last.node { - expr = Some(e); + let mut stmts = vec![]; + + for (index, stmt) in b.stmts.iter().enumerate() { + if index == b.stmts.len() - 1 { + if let StmtKind::Expr(ref e) = stmt.node { + expr = Some(P(self.lower_expr(e))); + } else { + stmts.extend(self.lower_stmt(stmt)); + } } else { - stmts.push(last); + stmts.extend(self.lower_stmt(stmt)); } } P(hir::Block { - id: b.id, + id: self.lower_node_id(b.id), stmts: stmts.into(), expr: expr, rules: self.lower_block_check_mode(&b.rules), @@ -1046,13 +1203,30 @@ impl<'a> LoweringContext<'a> { let mut path = self.lower_path_extra(import.id, path, suffix, ParamMode::Explicit, true); path.span = span; - self.items.insert(import.id, hir::Item { - id: import.id, - name: import.rename.unwrap_or(ident).name, - attrs: attrs.clone(), - node: hir::ItemUse(P(path), hir::UseKind::Single), - vis: vis.clone(), - span: span, + + self.allocate_hir_id_counter(import.id, import); + self.with_hir_id_owner(import.id, |this| { + let vis = match *vis { + hir::Visibility::Public => hir::Visibility::Public, + hir::Visibility::Crate => hir::Visibility::Crate, + hir::Visibility::Inherited => hir::Visibility::Inherited, + hir::Visibility::Restricted { ref path, id: _ } => { + hir::Visibility::Restricted { + path: path.clone(), + // We are allocating a new NodeId here + id: this.next_id(), + } + } + }; + + this.items.insert(import.id, hir::Item { + id: import.id, + name: import.rename.unwrap_or(ident).name, + attrs: attrs.clone(), + node: hir::ItemUse(P(path), hir::UseKind::Single), + vis: vis, + span: span, + }); }); } path @@ -1167,7 +1341,7 @@ impl<'a> LoweringContext<'a> { fn lower_trait_item(&mut self, i: &TraitItem) -> hir::TraitItem { self.with_parent_def(i.id, |this| { hir::TraitItem { - id: i.id, + id: this.lower_node_id(i.id), name: i.ident.name, attrs: this.lower_attrs(&i.attrs), node: match i.node { @@ -1228,10 +1402,10 @@ impl<'a> LoweringContext<'a> { fn lower_impl_item(&mut self, i: &ImplItem) -> hir::ImplItem { self.with_parent_def(i.id, |this| { hir::ImplItem { - id: i.id, + id: this.lower_node_id(i.id), name: i.ident.name, attrs: this.lower_attrs(&i.attrs), - vis: this.lower_visibility(&i.vis), + vis: this.lower_visibility(&i.vis, None), defaultness: this.lower_defaultness(i.defaultness, true /* [1] */), node: match i.node { ImplItemKind::Const(ref ty, ref expr) => { @@ -1260,7 +1434,7 @@ impl<'a> LoweringContext<'a> { id: hir::ImplItemId { node_id: i.id }, name: i.ident.name, span: i.span, - vis: self.lower_visibility(&i.vis), + vis: self.lower_visibility(&i.vis, Some(i.id)), defaultness: self.lower_defaultness(i.defaultness, true /* [1] */), kind: match i.node { ImplItemKind::Const(..) => hir::AssociatedItemKind::Const, @@ -1299,7 +1473,6 @@ impl<'a> LoweringContext<'a> { pub fn lower_item(&mut self, i: &Item) -> Option { let mut name = i.ident.name; let attrs = self.lower_attrs(&i.attrs); - let mut vis = self.lower_visibility(&i.vis); if let ItemKind::MacroDef(ref tts) = i.node { if i.attrs.iter().any(|attr| attr.path == "macro_export") { self.exported_macros.push(hir::MacroDef { @@ -1309,12 +1482,13 @@ impl<'a> LoweringContext<'a> { return None; } + let mut vis = self.lower_visibility(&i.vis, None); let node = self.with_parent_def(i.id, |this| { this.lower_item_kind(i.id, &mut name, &attrs, &mut vis, &i.node) }); Some(hir::Item { - id: i.id, + id: self.lower_node_id(i.id), name: name, attrs: attrs, node: node, @@ -1326,7 +1500,7 @@ impl<'a> LoweringContext<'a> { fn lower_foreign_item(&mut self, i: &ForeignItem) -> hir::ForeignItem { self.with_parent_def(i.id, |this| { hir::ForeignItem { - id: i.id, + id: this.lower_node_id(i.id), name: i.ident.name, attrs: this.lower_attrs(&i.attrs), node: match i.node { @@ -1339,7 +1513,7 @@ impl<'a> LoweringContext<'a> { hir::ForeignItemStatic(this.lower_ty(t), m) } }, - vis: this.lower_visibility(&i.vis), + vis: this.lower_visibility(&i.vis, None), span: i.span, } }) @@ -1405,7 +1579,7 @@ impl<'a> LoweringContext<'a> { fn lower_pat(&mut self, p: &Pat) -> P { P(hir::Pat { - id: p.id, + id: self.lower_node_id(p.id), node: match p.node { PatKind::Wild => hir::PatKind::Wild, PatKind::Ident(ref binding_mode, pth1, ref sub) => { @@ -1491,707 +1665,746 @@ impl<'a> LoweringContext<'a> { } fn lower_expr(&mut self, e: &Expr) -> hir::Expr { - hir::Expr { - id: e.id, - node: match e.node { - // Issue #22181: - // Eventually a desugaring for `box EXPR` - // (similar to the desugaring above for `in PLACE BLOCK`) - // should go here, desugaring - // + let kind = match e.node { + // Issue #22181: + // Eventually a desugaring for `box EXPR` + // (similar to the desugaring above for `in PLACE BLOCK`) + // should go here, desugaring + // + // to: + // + // let mut place = BoxPlace::make_place(); + // let raw_place = Place::pointer(&mut place); + // let value = $value; + // unsafe { + // ::std::ptr::write(raw_place, value); + // Boxed::finalize(place) + // } + // + // But for now there are type-inference issues doing that. + ExprKind::Box(ref inner) => { + hir::ExprBox(P(self.lower_expr(inner))) + } + + // Desugar ExprBox: `in (PLACE) EXPR` + ExprKind::InPlace(ref placer, ref value_expr) => { // to: // - // let mut place = BoxPlace::make_place(); + // let p = PLACE; + // let mut place = Placer::make_place(p); // let raw_place = Place::pointer(&mut place); - // let value = $value; - // unsafe { - // ::std::ptr::write(raw_place, value); - // Boxed::finalize(place) - // } - // - // But for now there are type-inference issues doing that. - ExprKind::Box(ref e) => { - hir::ExprBox(P(self.lower_expr(e))) - } - - // Desugar ExprBox: `in (PLACE) EXPR` - ExprKind::InPlace(ref placer, ref value_expr) => { - // to: - // - // let p = PLACE; - // let mut place = Placer::make_place(p); - // let raw_place = Place::pointer(&mut place); - // push_unsafe!({ - // std::intrinsics::move_val_init(raw_place, pop_unsafe!( EXPR )); - // InPlace::finalize(place) - // }) - let placer_expr = P(self.lower_expr(placer)); - let value_expr = P(self.lower_expr(value_expr)); - - let placer_ident = self.str_to_ident("placer"); - let place_ident = self.str_to_ident("place"); - let p_ptr_ident = self.str_to_ident("p_ptr"); - - let make_place = ["ops", "Placer", "make_place"]; - let place_pointer = ["ops", "Place", "pointer"]; - let move_val_init = ["intrinsics", "move_val_init"]; - let inplace_finalize = ["ops", "InPlace", "finalize"]; - - let unstable_span = self.allow_internal_unstable("<-", e.span); - let make_call = |this: &mut LoweringContext, p, args| { - let path = P(this.expr_std_path(unstable_span, p, ThinVec::new())); - P(this.expr_call(e.span, path, args)) - }; + // push_unsafe!({ + // std::intrinsics::move_val_init(raw_place, pop_unsafe!( EXPR )); + // InPlace::finalize(place) + // }) + let placer_expr = P(self.lower_expr(placer)); + let value_expr = P(self.lower_expr(value_expr)); + + let placer_ident = self.str_to_ident("placer"); + let place_ident = self.str_to_ident("place"); + let p_ptr_ident = self.str_to_ident("p_ptr"); + + let make_place = ["ops", "Placer", "make_place"]; + let place_pointer = ["ops", "Place", "pointer"]; + let move_val_init = ["intrinsics", "move_val_init"]; + let inplace_finalize = ["ops", "InPlace", "finalize"]; + + let unstable_span = self.allow_internal_unstable("<-", e.span); + let make_call = |this: &mut LoweringContext, p, args| { + let path = P(this.expr_std_path(unstable_span, p, ThinVec::new())); + P(this.expr_call(e.span, path, args)) + }; - let mk_stmt_let = |this: &mut LoweringContext, bind, expr| { - this.stmt_let(e.span, false, bind, expr) - }; + let mk_stmt_let = |this: &mut LoweringContext, bind, expr| { + this.stmt_let(e.span, false, bind, expr) + }; - let mk_stmt_let_mut = |this: &mut LoweringContext, bind, expr| { - this.stmt_let(e.span, true, bind, expr) - }; + let mk_stmt_let_mut = |this: &mut LoweringContext, bind, expr| { + this.stmt_let(e.span, true, bind, expr) + }; - // let placer = ; - let (s1, placer_binding) = { - mk_stmt_let(self, placer_ident, placer_expr) - }; + // let placer = ; + let (s1, placer_binding) = { + mk_stmt_let(self, placer_ident, placer_expr) + }; - // let mut place = Placer::make_place(placer); - let (s2, place_binding) = { - let placer = self.expr_ident(e.span, placer_ident, placer_binding); - let call = make_call(self, &make_place, hir_vec![placer]); - mk_stmt_let_mut(self, place_ident, call) - }; + // let mut place = Placer::make_place(placer); + let (s2, place_binding) = { + let placer = self.expr_ident(e.span, placer_ident, placer_binding); + let call = make_call(self, &make_place, hir_vec![placer]); + mk_stmt_let_mut(self, place_ident, call) + }; - // let p_ptr = Place::pointer(&mut place); - let (s3, p_ptr_binding) = { - let agent = P(self.expr_ident(e.span, place_ident, place_binding)); - let args = hir_vec![self.expr_mut_addr_of(e.span, agent)]; - let call = make_call(self, &place_pointer, args); - mk_stmt_let(self, p_ptr_ident, call) - }; + // let p_ptr = Place::pointer(&mut place); + let (s3, p_ptr_binding) = { + let agent = P(self.expr_ident(e.span, place_ident, place_binding)); + let args = hir_vec![self.expr_mut_addr_of(e.span, agent)]; + let call = make_call(self, &place_pointer, args); + mk_stmt_let(self, p_ptr_ident, call) + }; - // pop_unsafe!(EXPR)); - let pop_unsafe_expr = { - self.signal_block_expr(hir_vec![], - value_expr, - e.span, - hir::PopUnsafeBlock(hir::CompilerGenerated), - ThinVec::new()) - }; + // pop_unsafe!(EXPR)); + let pop_unsafe_expr = { + self.signal_block_expr(hir_vec![], + value_expr, + e.span, + hir::PopUnsafeBlock(hir::CompilerGenerated), + ThinVec::new()) + }; - // push_unsafe!({ - // std::intrinsics::move_val_init(raw_place, pop_unsafe!( EXPR )); - // InPlace::finalize(place) - // }) - let expr = { - let ptr = self.expr_ident(e.span, p_ptr_ident, p_ptr_binding); - let call_move_val_init = - hir::StmtSemi( - make_call(self, &move_val_init, hir_vec![ptr, pop_unsafe_expr]), - self.next_id()); - let call_move_val_init = respan(e.span, call_move_val_init); - - let place = self.expr_ident(e.span, place_ident, place_binding); - let call = make_call(self, &inplace_finalize, hir_vec![place]); - P(self.signal_block_expr(hir_vec![call_move_val_init], - call, - e.span, - hir::PushUnsafeBlock(hir::CompilerGenerated), - ThinVec::new())) - }; + // push_unsafe!({ + // std::intrinsics::move_val_init(raw_place, pop_unsafe!( EXPR )); + // InPlace::finalize(place) + // }) + let expr = { + let ptr = self.expr_ident(e.span, p_ptr_ident, p_ptr_binding); + let call_move_val_init = + hir::StmtSemi( + make_call(self, &move_val_init, hir_vec![ptr, pop_unsafe_expr]), + self.next_id()); + let call_move_val_init = respan(e.span, call_move_val_init); + + let place = self.expr_ident(e.span, place_ident, place_binding); + let call = make_call(self, &inplace_finalize, hir_vec![place]); + P(self.signal_block_expr(hir_vec![call_move_val_init], + call, + e.span, + hir::PushUnsafeBlock(hir::CompilerGenerated), + ThinVec::new())) + }; - let block = self.block_all(e.span, hir_vec![s1, s2, s3], Some(expr)); - // add the attributes to the outer returned expr node - return self.expr_block(P(block), e.attrs.clone()); - } + let block = self.block_all(e.span, hir_vec![s1, s2, s3], Some(expr)); + hir::ExprBlock(P(block)) + } - ExprKind::Array(ref exprs) => { - hir::ExprArray(exprs.iter().map(|x| self.lower_expr(x)).collect()) - } - ExprKind::Repeat(ref expr, ref count) => { - let expr = P(self.lower_expr(expr)); - let count = self.lower_expr(count); - hir::ExprRepeat(expr, self.record_body(count, None)) - } - ExprKind::Tup(ref elts) => { - hir::ExprTup(elts.iter().map(|x| self.lower_expr(x)).collect()) - } - ExprKind::Call(ref f, ref args) => { - let f = P(self.lower_expr(f)); - hir::ExprCall(f, args.iter().map(|x| self.lower_expr(x)).collect()) - } - ExprKind::MethodCall(i, ref tps, ref args) => { - let tps = tps.iter().map(|x| self.lower_ty(x)).collect(); - let args = args.iter().map(|x| self.lower_expr(x)).collect(); - hir::ExprMethodCall(respan(i.span, i.node.name), tps, args) - } - ExprKind::Binary(binop, ref lhs, ref rhs) => { - let binop = self.lower_binop(binop); - let lhs = P(self.lower_expr(lhs)); - let rhs = P(self.lower_expr(rhs)); - hir::ExprBinary(binop, lhs, rhs) - } - ExprKind::Unary(op, ref ohs) => { - let op = self.lower_unop(op); - let ohs = P(self.lower_expr(ohs)); - hir::ExprUnary(op, ohs) - } - ExprKind::Lit(ref l) => hir::ExprLit(P((**l).clone())), - ExprKind::Cast(ref expr, ref ty) => { - let expr = P(self.lower_expr(expr)); - hir::ExprCast(expr, self.lower_ty(ty)) - } - ExprKind::Type(ref expr, ref ty) => { - let expr = P(self.lower_expr(expr)); - hir::ExprType(expr, self.lower_ty(ty)) - } - ExprKind::AddrOf(m, ref ohs) => { - let m = self.lower_mutability(m); - let ohs = P(self.lower_expr(ohs)); - hir::ExprAddrOf(m, ohs) - } - // More complicated than you might expect because the else branch - // might be `if let`. - ExprKind::If(ref cond, ref blk, ref else_opt) => { - let else_opt = else_opt.as_ref().map(|els| { - match els.node { - ExprKind::IfLet(..) => { - // wrap the if-let expr in a block - let span = els.span; - let els = P(self.lower_expr(els)); - let id = self.next_id(); - let blk = P(hir::Block { - stmts: hir_vec![], - expr: Some(els), - id: id, - rules: hir::DefaultBlock, - span: span, - break_to_expr_id: None, - }); - P(self.expr_block(blk, ThinVec::new())) - } - _ => P(self.lower_expr(els)), + ExprKind::Array(ref exprs) => { + hir::ExprArray(exprs.iter().map(|x| self.lower_expr(x)).collect()) + } + ExprKind::Repeat(ref expr, ref count) => { + let expr = P(self.lower_expr(expr)); + let count = self.lower_expr(count); + hir::ExprRepeat(expr, self.record_body(count, None)) + } + ExprKind::Tup(ref elts) => { + hir::ExprTup(elts.iter().map(|x| self.lower_expr(x)).collect()) + } + ExprKind::Call(ref f, ref args) => { + let f = P(self.lower_expr(f)); + hir::ExprCall(f, args.iter().map(|x| self.lower_expr(x)).collect()) + } + ExprKind::MethodCall(i, ref tps, ref args) => { + let tps = tps.iter().map(|x| self.lower_ty(x)).collect(); + let args = args.iter().map(|x| self.lower_expr(x)).collect(); + hir::ExprMethodCall(respan(i.span, i.node.name), tps, args) + } + ExprKind::Binary(binop, ref lhs, ref rhs) => { + let binop = self.lower_binop(binop); + let lhs = P(self.lower_expr(lhs)); + let rhs = P(self.lower_expr(rhs)); + hir::ExprBinary(binop, lhs, rhs) + } + ExprKind::Unary(op, ref ohs) => { + let op = self.lower_unop(op); + let ohs = P(self.lower_expr(ohs)); + hir::ExprUnary(op, ohs) + } + ExprKind::Lit(ref l) => hir::ExprLit(P((**l).clone())), + ExprKind::Cast(ref expr, ref ty) => { + let expr = P(self.lower_expr(expr)); + hir::ExprCast(expr, self.lower_ty(ty)) + } + ExprKind::Type(ref expr, ref ty) => { + let expr = P(self.lower_expr(expr)); + hir::ExprType(expr, self.lower_ty(ty)) + } + ExprKind::AddrOf(m, ref ohs) => { + let m = self.lower_mutability(m); + let ohs = P(self.lower_expr(ohs)); + hir::ExprAddrOf(m, ohs) + } + // More complicated than you might expect because the else branch + // might be `if let`. + ExprKind::If(ref cond, ref blk, ref else_opt) => { + let else_opt = else_opt.as_ref().map(|els| { + match els.node { + ExprKind::IfLet(..) => { + // wrap the if-let expr in a block + let span = els.span; + let els = P(self.lower_expr(els)); + let id = self.next_id(); + let blk = P(hir::Block { + stmts: hir_vec![], + expr: Some(els), + id: id, + rules: hir::DefaultBlock, + span: span, + break_to_expr_id: None, + }); + P(self.expr_block(blk, ThinVec::new())) } - }); + _ => P(self.lower_expr(els)), + } + }); - hir::ExprIf(P(self.lower_expr(cond)), self.lower_block(blk, None), else_opt) - } - ExprKind::While(ref cond, ref body, opt_ident) => { - self.with_loop_scope(e.id, |this| - hir::ExprWhile( - this.with_loop_condition_scope(|this| P(this.lower_expr(cond))), - this.lower_block(body, None), - this.lower_opt_sp_ident(opt_ident))) - } - ExprKind::Loop(ref body, opt_ident) => { - self.with_loop_scope(e.id, |this| - hir::ExprLoop(this.lower_block(body, None), - this.lower_opt_sp_ident(opt_ident), - hir::LoopSource::Loop)) - } - ExprKind::Catch(ref body) => { - self.with_catch_scope(e.id, |this| - hir::ExprBlock(this.lower_block(body, Some(e.id)))) - } - ExprKind::Match(ref expr, ref arms) => { - hir::ExprMatch(P(self.lower_expr(expr)), - arms.iter().map(|x| self.lower_arm(x)).collect(), - hir::MatchSource::Normal) - } - ExprKind::Closure(capture_clause, ref decl, ref body, fn_decl_span) => { - self.with_new_scopes(|this| { - this.with_parent_def(e.id, |this| { - let expr = this.lower_expr(body); - hir::ExprClosure(this.lower_capture_clause(capture_clause), - this.lower_fn_decl(decl), - this.record_body(expr, Some(decl)), - fn_decl_span) - }) + hir::ExprIf(P(self.lower_expr(cond)), self.lower_block(blk, None), else_opt) + } + ExprKind::While(ref cond, ref body, opt_ident) => { + self.with_loop_scope(e.id, |this| + hir::ExprWhile( + this.with_loop_condition_scope(|this| P(this.lower_expr(cond))), + this.lower_block(body, None), + this.lower_opt_sp_ident(opt_ident))) + } + ExprKind::Loop(ref body, opt_ident) => { + self.with_loop_scope(e.id, |this| + hir::ExprLoop(this.lower_block(body, None), + this.lower_opt_sp_ident(opt_ident), + hir::LoopSource::Loop)) + } + ExprKind::Catch(ref body) => { + self.with_catch_scope(e.id, |this| + hir::ExprBlock(this.lower_block(body, Some(e.id)))) + } + ExprKind::Match(ref expr, ref arms) => { + hir::ExprMatch(P(self.lower_expr(expr)), + arms.iter().map(|x| self.lower_arm(x)).collect(), + hir::MatchSource::Normal) + } + ExprKind::Closure(capture_clause, ref decl, ref body, fn_decl_span) => { + self.with_new_scopes(|this| { + this.with_parent_def(e.id, |this| { + let expr = this.lower_expr(body); + hir::ExprClosure(this.lower_capture_clause(capture_clause), + this.lower_fn_decl(decl), + this.record_body(expr, Some(decl)), + fn_decl_span) }) - } - ExprKind::Block(ref blk) => hir::ExprBlock(self.lower_block(blk, None)), - ExprKind::Assign(ref el, ref er) => { - hir::ExprAssign(P(self.lower_expr(el)), P(self.lower_expr(er))) - } - ExprKind::AssignOp(op, ref el, ref er) => { - hir::ExprAssignOp(self.lower_binop(op), - P(self.lower_expr(el)), - P(self.lower_expr(er))) - } - ExprKind::Field(ref el, ident) => { - hir::ExprField(P(self.lower_expr(el)), respan(ident.span, ident.node.name)) - } - ExprKind::TupField(ref el, ident) => { - hir::ExprTupField(P(self.lower_expr(el)), ident) - } - ExprKind::Index(ref el, ref er) => { - hir::ExprIndex(P(self.lower_expr(el)), P(self.lower_expr(er))) - } - ExprKind::Range(ref e1, ref e2, lims) => { - fn make_struct(this: &mut LoweringContext, - ast_expr: &Expr, - path: &[&str], - fields: &[(&str, &P)]) -> hir::Expr { - let struct_path = &iter::once(&"ops").chain(path).map(|s| *s) - .collect::>(); - let unstable_span = this.allow_internal_unstable("...", ast_expr.span); - - if fields.len() == 0 { - this.expr_std_path(unstable_span, struct_path, - ast_expr.attrs.clone()) - } else { - let fields = fields.into_iter().map(|&(s, e)| { - let expr = P(this.lower_expr(&e)); - let unstable_span = this.allow_internal_unstable("...", e.span); - this.field(Symbol::intern(s), expr, unstable_span) - }).collect(); - let attrs = ast_expr.attrs.clone(); - - this.expr_std_struct(unstable_span, struct_path, fields, None, attrs) - } + }) + } + ExprKind::Block(ref blk) => hir::ExprBlock(self.lower_block(blk, None)), + ExprKind::Assign(ref el, ref er) => { + hir::ExprAssign(P(self.lower_expr(el)), P(self.lower_expr(er))) + } + ExprKind::AssignOp(op, ref el, ref er) => { + hir::ExprAssignOp(self.lower_binop(op), + P(self.lower_expr(el)), + P(self.lower_expr(er))) + } + ExprKind::Field(ref el, ident) => { + hir::ExprField(P(self.lower_expr(el)), respan(ident.span, ident.node.name)) + } + ExprKind::TupField(ref el, ident) => { + hir::ExprTupField(P(self.lower_expr(el)), ident) + } + ExprKind::Index(ref el, ref er) => { + hir::ExprIndex(P(self.lower_expr(el)), P(self.lower_expr(er))) + } + ExprKind::Range(ref e1, ref e2, lims) => { + fn make_struct(this: &mut LoweringContext, + ast_expr: &Expr, + path: &[&str], + fields: &[(&str, &P)]) -> hir::Expr { + let struct_path = &iter::once(&"ops").chain(path).map(|s| *s) + .collect::>(); + let unstable_span = this.allow_internal_unstable("...", ast_expr.span); + + if fields.len() == 0 { + this.expr_std_path(unstable_span, struct_path, + ast_expr.attrs.clone()) + } else { + let fields = fields.into_iter().map(|&(s, e)| { + let expr = P(this.lower_expr(&e)); + let unstable_span = this.allow_internal_unstable("...", e.span); + this.field(Symbol::intern(s), expr, unstable_span) + }).collect(); + let attrs = ast_expr.attrs.clone(); + + this.expr_std_struct(unstable_span, struct_path, fields, None, attrs) } + } - use syntax::ast::RangeLimits::*; + use syntax::ast::RangeLimits::*; - return match (e1, e2, lims) { - (&None, &None, HalfOpen) => - make_struct(self, e, &["RangeFull"], &[]), + return match (e1, e2, lims) { + (&None, &None, HalfOpen) => + make_struct(self, e, &["RangeFull"], &[]), - (&Some(ref e1), &None, HalfOpen) => - make_struct(self, e, &["RangeFrom"], - &[("start", e1)]), + (&Some(ref e1), &None, HalfOpen) => + make_struct(self, e, &["RangeFrom"], + &[("start", e1)]), - (&None, &Some(ref e2), HalfOpen) => - make_struct(self, e, &["RangeTo"], - &[("end", e2)]), + (&None, &Some(ref e2), HalfOpen) => + make_struct(self, e, &["RangeTo"], + &[("end", e2)]), - (&Some(ref e1), &Some(ref e2), HalfOpen) => - make_struct(self, e, &["Range"], - &[("start", e1), ("end", e2)]), + (&Some(ref e1), &Some(ref e2), HalfOpen) => + make_struct(self, e, &["Range"], + &[("start", e1), ("end", e2)]), - (&None, &Some(ref e2), Closed) => - make_struct(self, e, &["RangeToInclusive"], - &[("end", e2)]), + (&None, &Some(ref e2), Closed) => + make_struct(self, e, &["RangeToInclusive"], + &[("end", e2)]), - (&Some(ref e1), &Some(ref e2), Closed) => - make_struct(self, e, &["RangeInclusive", "NonEmpty"], - &[("start", e1), ("end", e2)]), + (&Some(ref e1), &Some(ref e2), Closed) => + make_struct(self, e, &["RangeInclusive", "NonEmpty"], + &[("start", e1), ("end", e2)]), - _ => panic!(self.diagnostic() - .span_fatal(e.span, "inclusive range with no end")), - }; - } - ExprKind::Path(ref qself, ref path) => { - hir::ExprPath(self.lower_qpath(e.id, qself, path, ParamMode::Optional)) - } - ExprKind::Break(opt_ident, ref opt_expr) => { - let label_result = if self.is_in_loop_condition && opt_ident.is_none() { + _ => panic!(self.diagnostic() + .span_fatal(e.span, "inclusive range with no end")), + }; + } + ExprKind::Path(ref qself, ref path) => { + hir::ExprPath(self.lower_qpath(e.id, qself, path, ParamMode::Optional)) + } + ExprKind::Break(opt_ident, ref opt_expr) => { + let label_result = if self.is_in_loop_condition && opt_ident.is_none() { + hir::Destination { + ident: opt_ident, + target_id: hir::ScopeTarget::Loop( + Err(hir::LoopIdError::UnlabeledCfInWhileCondition).into()), + } + } else { + self.lower_loop_destination(opt_ident.map(|ident| (e.id, ident))) + }; + hir::ExprBreak( + label_result, + opt_expr.as_ref().map(|x| P(self.lower_expr(x)))) + } + ExprKind::Continue(opt_ident) => + hir::ExprAgain( + if self.is_in_loop_condition && opt_ident.is_none() { hir::Destination { ident: opt_ident, - target_id: hir::ScopeTarget::Loop( - Err(hir::LoopIdError::UnlabeledCfInWhileCondition).into()), + target_id: hir::ScopeTarget::Loop(Err( + hir::LoopIdError::UnlabeledCfInWhileCondition).into()), } } else { - self.lower_loop_destination(opt_ident.map(|ident| (e.id, ident))) - }; - hir::ExprBreak( - label_result, - opt_expr.as_ref().map(|x| P(self.lower_expr(x)))) - } - ExprKind::Continue(opt_ident) => - hir::ExprAgain( - if self.is_in_loop_condition && opt_ident.is_none() { - hir::Destination { - ident: opt_ident, - target_id: hir::ScopeTarget::Loop(Err( - hir::LoopIdError::UnlabeledCfInWhileCondition).into()), - } + self.lower_loop_destination(opt_ident.map( |ident| (e.id, ident))) + }), + ExprKind::Ret(ref e) => hir::ExprRet(e.as_ref().map(|x| P(self.lower_expr(x)))), + ExprKind::InlineAsm(ref asm) => { + let hir_asm = hir::InlineAsm { + inputs: asm.inputs.iter().map(|&(ref c, _)| c.clone()).collect(), + outputs: asm.outputs.iter().map(|out| { + hir::InlineAsmOutput { + constraint: out.constraint.clone(), + is_rw: out.is_rw, + is_indirect: out.is_indirect, + } + }).collect(), + asm: asm.asm.clone(), + asm_str_style: asm.asm_str_style, + clobbers: asm.clobbers.clone().into(), + volatile: asm.volatile, + alignstack: asm.alignstack, + dialect: asm.dialect, + expn_id: asm.expn_id, + }; + let outputs = + asm.outputs.iter().map(|out| self.lower_expr(&out.expr)).collect(); + let inputs = + asm.inputs.iter().map(|&(_, ref input)| self.lower_expr(input)).collect(); + hir::ExprInlineAsm(P(hir_asm), outputs, inputs) + } + ExprKind::Struct(ref path, ref fields, ref maybe_expr) => { + hir::ExprStruct(self.lower_qpath(e.id, &None, path, ParamMode::Optional), + fields.iter().map(|x| self.lower_field(x)).collect(), + maybe_expr.as_ref().map(|x| P(self.lower_expr(x)))) + } + ExprKind::Paren(ref ex) => { + let mut ex = self.lower_expr(ex); + // include parens in span, but only if it is a super-span. + if e.span.contains(ex.span) { + ex.span = e.span; + } + // merge attributes into the inner expression. + let mut attrs = e.attrs.clone(); + attrs.extend::>(ex.attrs.into()); + ex.attrs = attrs; + return ex; + } + + // Desugar ExprIfLet + // From: `if let = []` + ExprKind::IfLet(ref pat, ref sub_expr, ref body, ref else_opt) => { + // to: + // + // match { + // => , + // [_ if => ,] + // _ => [ | ()] + // } + + let mut arms = vec![]; + + // ` => ` + { + let body = self.lower_block(body, None); + let body_expr = P(self.expr_block(body, ThinVec::new())); + let pat = self.lower_pat(pat); + arms.push(self.arm(hir_vec![pat], body_expr)); + } + + // `[_ if => ,]` + // `_ => [ | ()]` + { + let mut current: Option<&Expr> = else_opt.as_ref().map(|p| &**p); + let mut else_exprs: Vec> = vec![current]; + + // First, we traverse the AST and recursively collect all + // `else` branches into else_exprs, e.g.: + // + // if let Some(_) = x { + // ... + // } else if ... { // Expr1 + // ... + // } else if ... { // Expr2 + // ... + // } else { // Expr3 + // ... + // } + // + // ... results in else_exprs = [Some(&Expr1), + // Some(&Expr2), + // Some(&Expr3)] + // + // Because there also the case there is no `else`, these + // entries can also be `None`, as in: + // + // if let Some(_) = x { + // ... + // } else if ... { // Expr1 + // ... + // } else if ... { // Expr2 + // ... + // } + // + // ... results in else_exprs = [Some(&Expr1), + // Some(&Expr2), + // None] + // + // The last entry in this list is always translated into + // the final "unguard" wildcard arm of the `match`. In the + // case of a `None`, it becomes `_ => ()`. + loop { + if let Some(e) = current { + // There is an else branch at this level + if let ExprKind::If(_, _, ref else_opt) = e.node { + // The else branch is again an if-expr + current = else_opt.as_ref().map(|p| &**p); + else_exprs.push(current); + } else { + // The last item in the list is not an if-expr, + // stop here + break + } } else { - self.lower_loop_destination(opt_ident.map( |ident| (e.id, ident))) - }), - ExprKind::Ret(ref e) => hir::ExprRet(e.as_ref().map(|x| P(self.lower_expr(x)))), - ExprKind::InlineAsm(ref asm) => { - let hir_asm = hir::InlineAsm { - inputs: asm.inputs.iter().map(|&(ref c, _)| c.clone()).collect(), - outputs: asm.outputs.iter().map(|out| { - hir::InlineAsmOutput { - constraint: out.constraint.clone(), - is_rw: out.is_rw, - is_indirect: out.is_indirect, - } - }).collect(), - asm: asm.asm.clone(), - asm_str_style: asm.asm_str_style, - clobbers: asm.clobbers.clone().into(), - volatile: asm.volatile, - alignstack: asm.alignstack, - dialect: asm.dialect, - expn_id: asm.expn_id, - }; - let outputs = - asm.outputs.iter().map(|out| self.lower_expr(&out.expr)).collect(); - let inputs = - asm.inputs.iter().map(|&(_, ref input)| self.lower_expr(input)).collect(); - hir::ExprInlineAsm(P(hir_asm), outputs, inputs) - } - ExprKind::Struct(ref path, ref fields, ref maybe_expr) => { - hir::ExprStruct(self.lower_qpath(e.id, &None, path, ParamMode::Optional), - fields.iter().map(|x| self.lower_field(x)).collect(), - maybe_expr.as_ref().map(|x| P(self.lower_expr(x)))) - } - ExprKind::Paren(ref ex) => { - let mut ex = self.lower_expr(ex); - // include parens in span, but only if it is a super-span. - if e.span.contains(ex.span) { - ex.span = e.span; + // We have no more else branch + break + } } - // merge attributes into the inner expression. - let mut attrs = e.attrs.clone(); - attrs.extend::>(ex.attrs.into()); - ex.attrs = attrs; - return ex; - } - // Desugar ExprIfLet - // From: `if let = []` - ExprKind::IfLet(ref pat, ref sub_expr, ref body, ref else_opt) => { - // to: - // - // match { - // => , - // [_ if => ,] - // _ => [ | ()] - // } - - // ` => ` - let pat_arm = { - let body = self.lower_block(body, None); - let body_expr = P(self.expr_block(body, ThinVec::new())); - let pat = self.lower_pat(pat); - self.arm(hir_vec![pat], body_expr) - }; + // Now translate the list of nested else-branches into the + // arms of the match statement. + for else_expr in else_exprs { + if let Some(else_expr) = else_expr { + let (guard, body) = if let ExprKind::If(ref cond, + ref then, + _) = else_expr.node { + let then = self.lower_block(then, None); + (Some(cond), + self.expr_block(then, ThinVec::new())) + } else { + (None, + self.lower_expr(else_expr)) + }; - // `[_ if => ,]` - let mut else_opt = else_opt.as_ref().map(|e| P(self.lower_expr(e))); - let else_if_arms = { - let mut arms = vec![]; - loop { - let else_opt_continue = else_opt.and_then(|els| { - els.and_then(|els| { - match els.node { - // else if - hir::ExprIf(cond, then, else_opt) => { - let pat_under = self.pat_wild(e.span); - arms.push(hir::Arm { - attrs: hir_vec![], - pats: hir_vec![pat_under], - guard: Some(cond), - body: P(self.expr_block(then, ThinVec::new())), - }); - else_opt.map(|else_opt| (else_opt, true)) - } - _ => Some((P(els), false)), - } - }) + arms.push(hir::Arm { + attrs: hir_vec![], + pats: hir_vec![self.pat_wild(e.span)], + guard: guard.map(|e| P(self.lower_expr(e))), + body: P(body), }); - match else_opt_continue { - Some((e, true)) => { - else_opt = Some(e); - } - Some((e, false)) => { - else_opt = Some(e); - break; - } - None => { - else_opt = None; - break; - } - } + } else { + // There was no else-branch, push a noop + let pat_under = self.pat_wild(e.span); + let unit = self.expr_tuple(e.span, hir_vec![]); + arms.push(self.arm(hir_vec![pat_under], unit)); } - arms - }; + } + } - let contains_else_clause = else_opt.is_some(); + let contains_else_clause = else_opt.is_some(); - // `_ => [ | ()]` - let else_arm = { - let pat_under = self.pat_wild(e.span); - let else_expr = - else_opt.unwrap_or_else(|| self.expr_tuple(e.span, hir_vec![])); - self.arm(hir_vec![pat_under], else_expr) - }; + let sub_expr = P(self.lower_expr(sub_expr)); - let mut arms = Vec::with_capacity(else_if_arms.len() + 2); - arms.push(pat_arm); - arms.extend(else_if_arms); - arms.push(else_arm); - - let sub_expr = P(self.lower_expr(sub_expr)); - // add attributes to the outer returned expr node - return self.expr(e.span, - hir::ExprMatch(sub_expr, - arms.into(), - hir::MatchSource::IfLetDesugar { - contains_else_clause: contains_else_clause, - }), - e.attrs.clone()); - } + hir::ExprMatch( + sub_expr, + arms.into(), + hir::MatchSource::IfLetDesugar { + contains_else_clause: contains_else_clause, + }) + } - // Desugar ExprWhileLet - // From: `[opt_ident]: while let = ` - ExprKind::WhileLet(ref pat, ref sub_expr, ref body, opt_ident) => { - // to: - // - // [opt_ident]: loop { - // match { - // => , - // _ => break - // } - // } - - // Note that the block AND the condition are evaluated in the loop scope. - // This is done to allow `break` from inside the condition of the loop. - let (body, break_expr, sub_expr) = self.with_loop_scope(e.id, |this| ( - this.lower_block(body, None), - this.expr_break(e.span, ThinVec::new()), - this.with_loop_condition_scope(|this| P(this.lower_expr(sub_expr))), - )); - - // ` => ` - let pat_arm = { - let body_expr = P(self.expr_block(body, ThinVec::new())); - let pat = self.lower_pat(pat); - self.arm(hir_vec![pat], body_expr) - }; + // Desugar ExprWhileLet + // From: `[opt_ident]: while let = ` + ExprKind::WhileLet(ref pat, ref sub_expr, ref body, opt_ident) => { + // to: + // + // [opt_ident]: loop { + // match { + // => , + // _ => break + // } + // } + + // Note that the block AND the condition are evaluated in the loop scope. + // This is done to allow `break` from inside the condition of the loop. + let (body, break_expr, sub_expr) = self.with_loop_scope(e.id, |this| ( + this.lower_block(body, None), + this.expr_break(e.span, ThinVec::new()), + this.with_loop_condition_scope(|this| P(this.lower_expr(sub_expr))), + )); + + // ` => ` + let pat_arm = { + let body_expr = P(self.expr_block(body, ThinVec::new())); + let pat = self.lower_pat(pat); + self.arm(hir_vec![pat], body_expr) + }; - // `_ => break` - let break_arm = { - let pat_under = self.pat_wild(e.span); - self.arm(hir_vec![pat_under], break_expr) - }; + // `_ => break` + let break_arm = { + let pat_under = self.pat_wild(e.span); + self.arm(hir_vec![pat_under], break_expr) + }; - // `match { ... }` - let arms = hir_vec![pat_arm, break_arm]; - let match_expr = self.expr(e.span, - hir::ExprMatch(sub_expr, - arms, - hir::MatchSource::WhileLetDesugar), - ThinVec::new()); - - // `[opt_ident]: loop { ... }` - let loop_block = P(self.block_expr(P(match_expr))); - let loop_expr = hir::ExprLoop(loop_block, self.lower_opt_sp_ident(opt_ident), - hir::LoopSource::WhileLet); - // add attributes to the outer returned expr node - let attrs = e.attrs.clone(); - return hir::Expr { id: e.id, node: loop_expr, span: e.span, attrs: attrs }; - } + // `match { ... }` + let arms = hir_vec![pat_arm, break_arm]; + let match_expr = self.expr(e.span, + hir::ExprMatch(sub_expr, + arms, + hir::MatchSource::WhileLetDesugar), + ThinVec::new()); + + // `[opt_ident]: loop { ... }` + let loop_block = P(self.block_expr(P(match_expr))); + let loop_expr = hir::ExprLoop(loop_block, self.lower_opt_sp_ident(opt_ident), + hir::LoopSource::WhileLet); + // add attributes to the outer returned expr node + loop_expr + } - // Desugar ExprForLoop - // From: `[opt_ident]: for in ` - ExprKind::ForLoop(ref pat, ref head, ref body, opt_ident) => { - // to: - // - // { - // let result = match ::std::iter::IntoIterator::into_iter() { - // mut iter => { - // [opt_ident]: loop { - // match ::std::iter::Iterator::next(&mut iter) { - // ::std::option::Option::Some() => , - // ::std::option::Option::None => break - // } - // } - // } - // }; - // result - // } - - // expand - let head = self.lower_expr(head); - - let iter = self.str_to_ident("iter"); - - // `::std::option::Option::Some() => ` - let pat_arm = { - let body_block = self.with_loop_scope(e.id, - |this| this.lower_block(body, None)); - let body_expr = P(self.expr_block(body_block, ThinVec::new())); - let pat = self.lower_pat(pat); - let some_pat = self.pat_some(e.span, pat); - - self.arm(hir_vec![some_pat], body_expr) - }; + // Desugar ExprForLoop + // From: `[opt_ident]: for in ` + ExprKind::ForLoop(ref pat, ref head, ref body, opt_ident) => { + // to: + // + // { + // let result = match ::std::iter::IntoIterator::into_iter() { + // mut iter => { + // [opt_ident]: loop { + // match ::std::iter::Iterator::next(&mut iter) { + // ::std::option::Option::Some() => , + // ::std::option::Option::None => break + // } + // } + // } + // }; + // result + // } + + // expand + let head = self.lower_expr(head); + + let iter = self.str_to_ident("iter"); + + // `::std::option::Option::Some() => ` + let pat_arm = { + let body_block = self.with_loop_scope(e.id, + |this| this.lower_block(body, None)); + let body_expr = P(self.expr_block(body_block, ThinVec::new())); + let pat = self.lower_pat(pat); + let some_pat = self.pat_some(e.span, pat); + + self.arm(hir_vec![some_pat], body_expr) + }; - // `::std::option::Option::None => break` - let break_arm = { - let break_expr = self.with_loop_scope(e.id, |this| - this.expr_break(e.span, ThinVec::new())); - let pat = self.pat_none(e.span); - self.arm(hir_vec![pat], break_expr) - }; + // `::std::option::Option::None => break` + let break_arm = { + let break_expr = self.with_loop_scope(e.id, |this| + this.expr_break(e.span, ThinVec::new())); + let pat = self.pat_none(e.span); + self.arm(hir_vec![pat], break_expr) + }; - // `mut iter` - let iter_pat = self.pat_ident_binding_mode(e.span, iter, - hir::BindByValue(hir::MutMutable)); + // `mut iter` + let iter_pat = self.pat_ident_binding_mode(e.span, iter, + hir::BindByValue(hir::MutMutable)); + + // `match ::std::iter::Iterator::next(&mut iter) { ... }` + let match_expr = { + let iter = P(self.expr_ident(e.span, iter, iter_pat.id)); + let ref_mut_iter = self.expr_mut_addr_of(e.span, iter); + let next_path = &["iter", "Iterator", "next"]; + let next_path = P(self.expr_std_path(e.span, next_path, ThinVec::new())); + let next_expr = P(self.expr_call(e.span, next_path, + hir_vec![ref_mut_iter])); + let arms = hir_vec![pat_arm, break_arm]; - // `match ::std::iter::Iterator::next(&mut iter) { ... }` - let match_expr = { - let iter = P(self.expr_ident(e.span, iter, iter_pat.id)); - let ref_mut_iter = self.expr_mut_addr_of(e.span, iter); - let next_path = &["iter", "Iterator", "next"]; - let next_path = P(self.expr_std_path(e.span, next_path, ThinVec::new())); - let next_expr = P(self.expr_call(e.span, next_path, - hir_vec![ref_mut_iter])); - let arms = hir_vec![pat_arm, break_arm]; + P(self.expr(e.span, + hir::ExprMatch(next_expr, arms, + hir::MatchSource::ForLoopDesugar), + ThinVec::new())) + }; - P(self.expr(e.span, - hir::ExprMatch(next_expr, arms, - hir::MatchSource::ForLoopDesugar), - ThinVec::new())) - }; + // `[opt_ident]: loop { ... }` + let loop_block = P(self.block_expr(match_expr)); + let loop_expr = hir::ExprLoop(loop_block, self.lower_opt_sp_ident(opt_ident), + hir::LoopSource::ForLoop); + let loop_expr = P(hir::Expr { + id: self.lower_node_id(e.id), + node: loop_expr, + span: e.span, + attrs: ThinVec::new(), + }); - // `[opt_ident]: loop { ... }` - let loop_block = P(self.block_expr(match_expr)); - let loop_expr = hir::ExprLoop(loop_block, self.lower_opt_sp_ident(opt_ident), - hir::LoopSource::ForLoop); - let loop_expr = P(hir::Expr { - id: e.id, - node: loop_expr, - span: e.span, - attrs: ThinVec::new(), - }); - - // `mut iter => { ... }` - let iter_arm = self.arm(hir_vec![iter_pat], loop_expr); - - // `match ::std::iter::IntoIterator::into_iter() { ... }` - let into_iter_expr = { - let into_iter_path = &["iter", "IntoIterator", "into_iter"]; - let into_iter = P(self.expr_std_path(e.span, into_iter_path, - ThinVec::new())); - P(self.expr_call(e.span, into_iter, hir_vec![head])) - }; + // `mut iter => { ... }` + let iter_arm = self.arm(hir_vec![iter_pat], loop_expr); - let match_expr = P(self.expr_match(e.span, - into_iter_expr, - hir_vec![iter_arm], - hir::MatchSource::ForLoopDesugar)); - - // `{ let _result = ...; _result }` - // underscore prevents an unused_variables lint if the head diverges - let result_ident = self.str_to_ident("_result"); - let (let_stmt, let_stmt_binding) = - self.stmt_let(e.span, false, result_ident, match_expr); - - let result = P(self.expr_ident(e.span, result_ident, let_stmt_binding)); - let block = P(self.block_all(e.span, hir_vec![let_stmt], Some(result))); - // add the attributes to the outer returned expr node - return self.expr_block(block, e.attrs.clone()); - } + // `match ::std::iter::IntoIterator::into_iter() { ... }` + let into_iter_expr = { + let into_iter_path = &["iter", "IntoIterator", "into_iter"]; + let into_iter = P(self.expr_std_path(e.span, into_iter_path, + ThinVec::new())); + P(self.expr_call(e.span, into_iter, hir_vec![head])) + }; - // Desugar ExprKind::Try - // From: `?` - ExprKind::Try(ref sub_expr) => { - // to: - // - // match Carrier::translate() { - // Ok(val) => #[allow(unreachable_code)] val, - // Err(err) => #[allow(unreachable_code)] - // // If there is an enclosing `catch {...}` - // break 'catch_target Carrier::from_error(From::from(err)), - // // Otherwise - // return Carrier::from_error(From::from(err)), - // } + let match_expr = P(self.expr_match(e.span, + into_iter_expr, + hir_vec![iter_arm], + hir::MatchSource::ForLoopDesugar)); + + // `{ let _result = ...; _result }` + // underscore prevents an unused_variables lint if the head diverges + let result_ident = self.str_to_ident("_result"); + let (let_stmt, let_stmt_binding) = + self.stmt_let(e.span, false, result_ident, match_expr); + + let result = P(self.expr_ident(e.span, result_ident, let_stmt_binding)); + let block = P(self.block_all(e.span, hir_vec![let_stmt], Some(result))); + // add the attributes to the outer returned expr node + return self.expr_block(block, e.attrs.clone()); + } - let unstable_span = self.allow_internal_unstable("?", e.span); + // Desugar ExprKind::Try + // From: `?` + ExprKind::Try(ref sub_expr) => { + // to: + // + // match Carrier::translate() { + // Ok(val) => #[allow(unreachable_code)] val, + // Err(err) => #[allow(unreachable_code)] + // // If there is an enclosing `catch {...}` + // break 'catch_target Carrier::from_error(From::from(err)), + // // Otherwise + // return Carrier::from_error(From::from(err)), + // } - // Carrier::translate() - let discr = { - // expand - let sub_expr = self.lower_expr(sub_expr); + let unstable_span = self.allow_internal_unstable("?", e.span); - let path = &["ops", "Carrier", "translate"]; - let path = P(self.expr_std_path(unstable_span, path, ThinVec::new())); - P(self.expr_call(e.span, path, hir_vec![sub_expr])) + // Carrier::translate() + let discr = { + // expand + let sub_expr = self.lower_expr(sub_expr); + + let path = &["ops", "Carrier", "translate"]; + let path = P(self.expr_std_path(unstable_span, path, ThinVec::new())); + P(self.expr_call(e.span, path, hir_vec![sub_expr])) + }; + + // #[allow(unreachable_code)] + let attr = { + // allow(unreachable_code) + let allow = { + let allow_ident = self.str_to_ident("allow"); + let uc_ident = self.str_to_ident("unreachable_code"); + let uc_meta_item = attr::mk_spanned_word_item(e.span, uc_ident); + let uc_nested = NestedMetaItemKind::MetaItem(uc_meta_item); + let uc_spanned = respan(e.span, uc_nested); + attr::mk_spanned_list_item(e.span, allow_ident, vec![uc_spanned]) }; + attr::mk_spanned_attr_outer(e.span, attr::mk_attr_id(), allow) + }; + let attrs = vec![attr]; + + // Ok(val) => #[allow(unreachable_code)] val, + let ok_arm = { + let val_ident = self.str_to_ident("val"); + let val_pat = self.pat_ident(e.span, val_ident); + let val_expr = P(self.expr_ident_with_attrs(e.span, + val_ident, + val_pat.id, + ThinVec::from(attrs.clone()))); + let ok_pat = self.pat_ok(e.span, val_pat); + + self.arm(hir_vec![ok_pat], val_expr) + }; - // #[allow(unreachable_code)] - let attr = { - // allow(unreachable_code) - let allow = { - let allow_ident = self.str_to_ident("allow"); - let uc_ident = self.str_to_ident("unreachable_code"); - let uc_meta_item = attr::mk_spanned_word_item(e.span, uc_ident); - let uc_nested = NestedMetaItemKind::MetaItem(uc_meta_item); - let uc_spanned = respan(e.span, uc_nested); - attr::mk_spanned_list_item(e.span, allow_ident, vec![uc_spanned]) - }; - attr::mk_spanned_attr_outer(e.span, attr::mk_attr_id(), allow) + // Err(err) => #[allow(unreachable_code)] + // return Carrier::from_error(From::from(err)), + let err_arm = { + let err_ident = self.str_to_ident("err"); + let err_local = self.pat_ident(e.span, err_ident); + let from_expr = { + let path = &["convert", "From", "from"]; + let from = P(self.expr_std_path(e.span, path, ThinVec::new())); + let err_expr = self.expr_ident(e.span, err_ident, err_local.id); + + self.expr_call(e.span, from, hir_vec![err_expr]) }; - let attrs = vec![attr]; - - // Ok(val) => #[allow(unreachable_code)] val, - let ok_arm = { - let val_ident = self.str_to_ident("val"); - let val_pat = self.pat_ident(e.span, val_ident); - let val_expr = P(self.expr_ident_with_attrs(e.span, - val_ident, - val_pat.id, - ThinVec::from(attrs.clone()))); - let ok_pat = self.pat_ok(e.span, val_pat); - - self.arm(hir_vec![ok_pat], val_expr) + let from_err_expr = { + let path = &["ops", "Carrier", "from_error"]; + let from_err = P(self.expr_std_path(unstable_span, path, + ThinVec::new())); + P(self.expr_call(e.span, from_err, hir_vec![from_expr])) }; - // Err(err) => #[allow(unreachable_code)] - // return Carrier::from_error(From::from(err)), - let err_arm = { - let err_ident = self.str_to_ident("err"); - let err_local = self.pat_ident(e.span, err_ident); - let from_expr = { - let path = &["convert", "From", "from"]; - let from = P(self.expr_std_path(e.span, path, ThinVec::new())); - let err_expr = self.expr_ident(e.span, err_ident, err_local.id); - - self.expr_call(e.span, from, hir_vec![err_expr]) - }; - let from_err_expr = { - let path = &["ops", "Carrier", "from_error"]; - let from_err = P(self.expr_std_path(unstable_span, path, - ThinVec::new())); - P(self.expr_call(e.span, from_err, hir_vec![from_expr])) - }; + let thin_attrs = ThinVec::from(attrs); + let catch_scope = self.catch_scopes.last().map(|x| *x); + let ret_expr = if let Some(catch_node) = catch_scope { + P(self.expr( + e.span, + hir::ExprBreak( + hir::Destination { + ident: None, + target_id: hir::ScopeTarget::Block(catch_node), + }, + Some(from_err_expr) + ), + thin_attrs)) + } else { + P(self.expr(e.span, + hir::Expr_::ExprRet(Some(from_err_expr)), + thin_attrs)) + }; - let thin_attrs = ThinVec::from(attrs); - let catch_scope = self.catch_scopes.last().map(|x| *x); - let ret_expr = if let Some(catch_node) = catch_scope { - P(self.expr( - e.span, - hir::ExprBreak( - hir::Destination { - ident: None, - target_id: hir::ScopeTarget::Block(catch_node), - }, - Some(from_err_expr) - ), - thin_attrs)) - } else { - P(self.expr(e.span, - hir::Expr_::ExprRet(Some(from_err_expr)), - thin_attrs)) - }; - let err_pat = self.pat_err(e.span, err_local); - self.arm(hir_vec![err_pat], ret_expr) - }; + let err_pat = self.pat_err(e.span, err_local); + self.arm(hir_vec![err_pat], ret_expr) + }; - return self.expr_match(e.span, discr, hir_vec![err_arm, ok_arm], - hir::MatchSource::TryDesugar); - } + hir::ExprMatch(discr, + hir_vec![err_arm, ok_arm], + hir::MatchSource::TryDesugar) + } - ExprKind::Mac(_) => panic!("Shouldn't exist here"), - }, + ExprKind::Mac(_) => panic!("Shouldn't exist here"), + }; + + hir::Expr { + id: self.lower_node_id(e.id), + node: kind, span: e.span, attrs: e.attrs.clone(), } @@ -2203,7 +2416,7 @@ impl<'a> LoweringContext<'a> { node: hir::StmtDecl(P(Spanned { node: hir::DeclLocal(self.lower_local(l)), span: s.span, - }), s.id), + }), self.lower_node_id(s.id)), span: s.span, }, StmtKind::Item(ref it) => { @@ -2213,19 +2426,23 @@ impl<'a> LoweringContext<'a> { node: hir::StmtDecl(P(Spanned { node: hir::DeclItem(item_id), span: s.span, - }), id.take().unwrap_or_else(|| self.next_id())), + }), id.take() + .map(|id| self.lower_node_id(id)) + .unwrap_or_else(|| self.next_id())), span: s.span, }).collect(); } StmtKind::Expr(ref e) => { Spanned { - node: hir::StmtExpr(P(self.lower_expr(e)), s.id), + node: hir::StmtExpr(P(self.lower_expr(e)), + self.lower_node_id(s.id)), span: s.span, } } StmtKind::Semi(ref e) => { Spanned { - node: hir::StmtSemi(P(self.lower_expr(e)), s.id), + node: hir::StmtSemi(P(self.lower_expr(e)), + self.lower_node_id(s.id)), span: s.span, } } @@ -2240,14 +2457,26 @@ impl<'a> LoweringContext<'a> { } } - fn lower_visibility(&mut self, v: &Visibility) -> hir::Visibility { + /// If an `explicit_owner` is given, this method allocates the `HirId` in + /// the address space of that item instead of the item currently being + /// lowered. This can happen during `lower_impl_item_ref()` where we need to + /// lower a `Visibility` value although we haven't lowered the owning + /// `ImplItem` in question yet. + fn lower_visibility(&mut self, + v: &Visibility, + explicit_owner: Option) + -> hir::Visibility { match *v { Visibility::Public => hir::Public, Visibility::Crate(_) => hir::Visibility::Crate, Visibility::Restricted { ref path, id } => { hir::Visibility::Restricted { path: P(self.lower_path(id, path, ParamMode::Explicit, true)), - id: id + id: if let Some(owner) = explicit_owner { + self.lower_node_id_with_owner(id, owner) + } else { + self.lower_node_id(id) + } } } Visibility::Inherited => hir::Inherited, diff --git a/src/librustc/hir/map/definitions.rs b/src/librustc/hir/map/definitions.rs index bf52a036cc8..0f7e54953b0 100644 --- a/src/librustc/hir/map/definitions.rs +++ b/src/librustc/hir/map/definitions.rs @@ -14,8 +14,10 @@ //! There are also some rather random cases (like const initializer //! expressions) that are mostly just leftovers. +use hir; use hir::def_id::{CrateNum, DefId, DefIndex, LOCAL_CRATE}; use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::indexed_vec::IndexVec; use rustc_data_structures::stable_hasher::StableHasher; use serialize::{Encodable, Decodable, Encoder, Decoder}; use std::fmt::Write; @@ -121,6 +123,7 @@ pub struct Definitions { table: DefPathTable, node_to_def_index: NodeMap, def_index_to_node: Vec, + pub(super) node_to_hir_id: IndexVec, } /// A unique identifier that we can use to lookup a definition @@ -206,6 +209,23 @@ impl DefPath { s } + /// Returns a string representation of the DefPath without + /// the crate-prefix. This method is useful if you don't have + /// a TyCtxt available. + pub fn to_string_no_crate(&self) -> String { + let mut s = String::with_capacity(self.data.len() * 16); + + for component in &self.data { + write!(s, + "::{}[{}]", + component.data.as_interned_str(), + component.disambiguator) + .unwrap(); + } + + s + } + pub fn deterministic_hash(&self, tcx: TyCtxt) -> u64 { debug!("deterministic_hash({:?})", self); let mut state = StableHasher::new(); @@ -275,6 +295,7 @@ impl Definitions { }, node_to_def_index: NodeMap(), def_index_to_node: vec![], + node_to_hir_id: IndexVec::new(), } } @@ -367,6 +388,15 @@ impl Definitions { index } + + /// Initialize the ast::NodeId to HirId mapping once it has been generated during + /// AST to HIR lowering. + pub fn init_node_id_to_hir_id_mapping(&mut self, + mapping: IndexVec) { + assert!(self.node_to_hir_id.is_empty(), + "Trying initialize NodeId -> HirId mapping twice"); + self.node_to_hir_id = mapping; + } } impl DefPathData { diff --git a/src/librustc/hir/map/hir_id_validator.rs b/src/librustc/hir/map/hir_id_validator.rs new file mode 100644 index 00000000000..b3cc0c542ef --- /dev/null +++ b/src/librustc/hir/map/hir_id_validator.rs @@ -0,0 +1,184 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use hir::def_id::{DefId, DefIndex, CRATE_DEF_INDEX}; +use hir::{self, intravisit, HirId, ItemLocalId}; +use syntax::ast::NodeId; +use hir::itemlikevisit::ItemLikeVisitor; +use rustc_data_structures::fx::FxHashMap; + +pub fn check_crate<'hir>(hir_map: &hir::map::Map<'hir>) { + let mut outer_visitor = OuterVisitor { + hir_map: hir_map, + errors: vec![], + }; + + hir_map.dep_graph.with_ignore(|| { + hir_map.krate().visit_all_item_likes(&mut outer_visitor); + if !outer_visitor.errors.is_empty() { + let message = outer_visitor + .errors + .iter() + .fold(String::new(), |s1, s2| s1 + "\n" + s2); + bug!("{}", message); + } + }); +} + +struct HirIdValidator<'a, 'hir: 'a> { + hir_map: &'a hir::map::Map<'hir>, + owner_def_index: Option, + hir_ids_seen: FxHashMap, + errors: Vec, +} + +struct OuterVisitor<'a, 'hir: 'a> { + hir_map: &'a hir::map::Map<'hir>, + errors: Vec, +} + +impl<'a, 'hir: 'a> OuterVisitor<'a, 'hir> { + fn new_inner_visitor(&self, + hir_map: &'a hir::map::Map<'hir>) + -> HirIdValidator<'a, 'hir> { + HirIdValidator { + hir_map: hir_map, + owner_def_index: None, + hir_ids_seen: FxHashMap(), + errors: Vec::new(), + } + } +} + +impl<'a, 'hir: 'a> ItemLikeVisitor<'hir> for OuterVisitor<'a, 'hir> { + fn visit_item(&mut self, i: &'hir hir::Item) { + let mut inner_visitor = self.new_inner_visitor(self.hir_map); + inner_visitor.check(i.id, |this| intravisit::walk_item(this, i)); + self.errors.extend(inner_visitor.errors.drain(..)); + } + + fn visit_trait_item(&mut self, i: &'hir hir::TraitItem) { + let mut inner_visitor = self.new_inner_visitor(self.hir_map); + inner_visitor.check(i.id, |this| intravisit::walk_trait_item(this, i)); + self.errors.extend(inner_visitor.errors.drain(..)); + } + + fn visit_impl_item(&mut self, i: &'hir hir::ImplItem) { + let mut inner_visitor = self.new_inner_visitor(self.hir_map); + inner_visitor.check(i.id, |this| intravisit::walk_impl_item(this, i)); + self.errors.extend(inner_visitor.errors.drain(..)); + } +} + +impl<'a, 'hir: 'a> HirIdValidator<'a, 'hir> { + + fn check)>(&mut self, + node_id: NodeId, + walk: F) { + assert!(self.owner_def_index.is_none()); + let owner_def_index = self.hir_map.local_def_id(node_id).index; + self.owner_def_index = Some(owner_def_index); + walk(self); + + if owner_def_index == CRATE_DEF_INDEX { + return + } + + // There's always at least one entry for the owning item itself + let max = self.hir_ids_seen + .keys() + .map(|local_id| local_id.as_usize()) + .max() + .unwrap(); + + if max != self.hir_ids_seen.len() - 1 { + // Collect the missing ItemLocalIds + let missing: Vec<_> = (0 .. max + 1) + .filter(|&i| !self.hir_ids_seen.contains_key(&ItemLocalId(i as u32))) + .collect(); + + // Try to map those to something more useful + let mut missing_items = vec![]; + + for local_id in missing { + let hir_id = HirId { + owner: owner_def_index, + local_id: ItemLocalId(local_id as u32), + }; + + // We are already in ICE mode here, so doing a linear search + // should be fine. + let (node_id, _) = self.hir_map + .definitions() + .node_to_hir_id + .iter() + .enumerate() + .find(|&(_, &entry)| hir_id == entry) + .unwrap(); + let node_id = NodeId::new(node_id); + missing_items.push(format!("[local_id: {}, node:{}]", + local_id, + self.hir_map.node_to_string(node_id))); + } + + self.errors.push(format!( + "ItemLocalIds not assigned densely in {}. \ + Max ItemLocalId = {}, missing IDs = {:?}", + self.hir_map.def_path(DefId::local(owner_def_index)).to_string_no_crate(), + max, + missing_items)); + } + } +} + +impl<'a, 'hir: 'a> intravisit::Visitor<'hir> for HirIdValidator<'a, 'hir> { + + fn nested_visit_map<'this>(&'this mut self) + -> intravisit::NestedVisitorMap<'this, 'hir> { + intravisit::NestedVisitorMap::OnlyBodies(self.hir_map) + } + + fn visit_id(&mut self, node_id: NodeId) { + let owner = self.owner_def_index.unwrap(); + let stable_id = self.hir_map.definitions().node_to_hir_id[node_id]; + + if stable_id == hir::DUMMY_HIR_ID { + self.errors.push(format!("HirIdValidator: No HirId assigned for NodeId {}: {:?}", + node_id, + self.hir_map.node_to_string(node_id))); + } + + if owner != stable_id.owner { + self.errors.push(format!( + "HirIdValidator: The recorded owner of {} is {} instead of {}", + self.hir_map.node_to_string(node_id), + self.hir_map.def_path(DefId::local(stable_id.owner)).to_string_no_crate(), + self.hir_map.def_path(DefId::local(owner)).to_string_no_crate())); + } + + if let Some(prev) = self.hir_ids_seen.insert(stable_id.local_id, node_id) { + if prev != node_id { + self.errors.push(format!( + "HirIdValidator: Same HirId {}/{} assigned for nodes {} and {}", + self.hir_map.def_path(DefId::local(stable_id.owner)).to_string_no_crate(), + stable_id.local_id.as_usize(), + self.hir_map.node_to_string(prev), + self.hir_map.node_to_string(node_id))); + } + } + } + + fn visit_impl_item_ref(&mut self, _: &'hir hir::ImplItemRef) { + // Explicitly do nothing here. ImplItemRefs contain hir::Visibility + // values that actually belong to an ImplItem instead of the ItemImpl + // we are currently in. So for those it's correct that they have a + // different owner. + } +} diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs index 5d074903b2b..3def41fd425 100644 --- a/src/librustc/hir/map/mod.rs +++ b/src/librustc/hir/map/mod.rs @@ -36,6 +36,7 @@ pub mod blocks; mod collector; mod def_collector; pub mod definitions; +mod hir_id_validator; #[derive(Copy, Clone, Debug)] pub enum Node<'hir> { @@ -964,13 +965,17 @@ pub fn map_crate<'hir>(forest: &'hir mut Forest, entries, vector_length, (entries as f64 / vector_length as f64) * 100.); } - Map { + let map = Map { forest: forest, dep_graph: forest.dep_graph.clone(), map: map, definitions: definitions, inlined_bodies: RefCell::new(DefIdMap()), - } + }; + + hir_id_validator::check_crate(&map); + + map } /// Identical to the `PpAnn` implementation for `hir::Crate`, diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index edcfcffaa03..1c79a02d3da 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -30,7 +30,7 @@ pub use self::Visibility::{Public, Inherited}; pub use self::PathParameters::*; use hir::def::Def; -use hir::def_id::DefId; +use hir::def_id::{DefId, DefIndex, CRATE_DEF_INDEX}; use util::nodemap::{NodeMap, FxHashSet}; use syntax_pos::{Span, ExpnId, DUMMY_SP}; @@ -43,6 +43,8 @@ use syntax::symbol::{Symbol, keywords}; use syntax::tokenstream::TokenStream; use syntax::util::ThinVec; +use rustc_data_structures::indexed_vec; + use std::collections::BTreeMap; use std::fmt; @@ -73,6 +75,63 @@ pub mod pat_util; pub mod print; pub mod svh; +/// A HirId uniquely identifies a node in the HIR of then current crate. It is +/// composed of the `owner`, which is the DefIndex of the directly enclosing +/// hir::Item, hir::TraitItem, or hir::ImplItem (i.e. the closest "item-like"), +/// and the `local_id` which is unique within the given owner. +/// +/// This two-level structure makes for more stable values: One can move an item +/// around within the source code, or add or remove stuff before it, without +/// the local_id part of the HirId changing, which is a very useful property +/// incremental compilation where we have to persist things through changes to +/// the code base. +#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, + RustcEncodable, RustcDecodable)] +pub struct HirId { + pub owner: DefIndex, + pub local_id: ItemLocalId, +} + +/// An `ItemLocalId` uniquely identifies something within a given "item-like", +/// that is within a hir::Item, hir::TraitItem, or hir::ImplItem. There is no +/// guarantee that the numerical value of a given `ItemLocalId` corresponds to +/// the node's position within the owning item in any way, but there is a +/// guarantee that the `LocalItemId`s within an owner occupy a dense range of +/// integers starting at zero, so a mapping that maps all or most nodes within +/// an "item-like" to something else can be implement by a `Vec` instead of a +/// tree or hash map. +#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, + RustcEncodable, RustcDecodable)] +pub struct ItemLocalId(pub u32); + +impl ItemLocalId { + pub fn as_usize(&self) -> usize { + self.0 as usize + } +} + +impl indexed_vec::Idx for ItemLocalId { + fn new(idx: usize) -> Self { + debug_assert!((idx as u32) as usize == idx); + ItemLocalId(idx as u32) + } + + fn index(self) -> usize { + self.0 as usize + } +} + +/// The `HirId` corresponding to CRATE_NODE_ID and CRATE_DEF_INDEX +pub const CRATE_HIR_ID: HirId = HirId { + owner: CRATE_DEF_INDEX, + local_id: ItemLocalId(0) +}; + +pub const DUMMY_HIR_ID: HirId = HirId { + owner: CRATE_DEF_INDEX, + local_id: ItemLocalId(!0) +}; + #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Copy)] pub struct Lifetime { pub id: NodeId, diff --git a/src/libsyntax/ext/placeholders.rs b/src/libsyntax/ext/placeholders.rs index f60b1d17a5e..f0e328a551d 100644 --- a/src/libsyntax/ext/placeholders.rs +++ b/src/libsyntax/ext/placeholders.rs @@ -178,17 +178,9 @@ impl<'a, 'b> Folder for PlaceholderExpander<'a, 'b> { block.stmts = block.stmts.move_flat_map(|mut stmt| { remaining_stmts -= 1; - match stmt.node { - // Avoid wasting a node id on a trailing expression statement, - // which shares a HIR node with the expression itself. - ast::StmtKind::Expr(ref expr) if remaining_stmts == 0 => stmt.id = expr.id, - - _ if self.monotonic => { - assert_eq!(stmt.id, ast::DUMMY_NODE_ID); - stmt.id = self.cx.resolver.next_node_id(); - } - - _ => {} + if self.monotonic { + assert_eq!(stmt.id, ast::DUMMY_NODE_ID); + stmt.id = self.cx.resolver.next_node_id(); } Some(stmt) diff --git a/src/test/compile-fail/region-bounds-on-objects-and-type-parameters.rs b/src/test/compile-fail/region-bounds-on-objects-and-type-parameters.rs index 503b577b1f1..fd8d5ff9e7e 100644 --- a/src/test/compile-fail/region-bounds-on-objects-and-type-parameters.rs +++ b/src/test/compile-fail/region-bounds-on-objects-and-type-parameters.rs @@ -18,7 +18,7 @@ trait SomeTrait { } // Bounds on object types: -struct Foo<'a,'b,'c> { //~ ERROR parameter `'b` is never used +struct Foo<'a,'b,'c> { //~ ERROR parameter `'c` is never used // All of these are ok, because we can derive exactly one bound: a: Box, b: Box>, -- cgit 1.4.1-3-g733a5 From 53a36923f12d6c9b7ef9cb0fe73cda50385b1f70 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Wed, 22 Mar 2017 22:02:42 +0200 Subject: Fix the tests --- src/test/compile-fail/indexing-requires-a-uint.rs | 2 +- src/test/compile-fail/integral-indexing.rs | 8 ++++---- src/test/compile-fail/on-unimplemented/slice-index.rs | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) (limited to 'src/test') diff --git a/src/test/compile-fail/indexing-requires-a-uint.rs b/src/test/compile-fail/indexing-requires-a-uint.rs index 1889d76c03c..624944f7344 100644 --- a/src/test/compile-fail/indexing-requires-a-uint.rs +++ b/src/test/compile-fail/indexing-requires-a-uint.rs @@ -13,7 +13,7 @@ fn main() { fn bar(_: T) {} - [0][0u8]; //~ ERROR: the trait bound `u8: std::slice::SliceIndex<{integer}>` is not satisfied + [0][0u8]; //~ ERROR: the trait bound `u8: std::slice::SliceIndex<[{integer}]>` is not satisfied [0][0]; // should infer to be a usize diff --git a/src/test/compile-fail/integral-indexing.rs b/src/test/compile-fail/integral-indexing.rs index 1815d0e978a..659b08b55a0 100644 --- a/src/test/compile-fail/integral-indexing.rs +++ b/src/test/compile-fail/integral-indexing.rs @@ -19,8 +19,8 @@ pub fn main() { v[3i32]; //~ERROR : std::ops::Index` is not satisfied s.as_bytes()[3_usize]; s.as_bytes()[3]; - s.as_bytes()[3u8]; //~ERROR : std::slice::SliceIndex` is not satisfied - s.as_bytes()[3i8]; //~ERROR : std::slice::SliceIndex` is not satisfied - s.as_bytes()[3u32]; //~ERROR : std::slice::SliceIndex` is not satisfied - s.as_bytes()[3i32]; //~ERROR : std::slice::SliceIndex` is not satisfied + s.as_bytes()[3u8]; //~ERROR : std::slice::SliceIndex<[u8]>` is not satisfied + s.as_bytes()[3i8]; //~ERROR : std::slice::SliceIndex<[u8]>` is not satisfied + s.as_bytes()[3u32]; //~ERROR : std::slice::SliceIndex<[u8]>` is not satisfied + s.as_bytes()[3i32]; //~ERROR : std::slice::SliceIndex<[u8]>` is not satisfied } diff --git a/src/test/compile-fail/on-unimplemented/slice-index.rs b/src/test/compile-fail/on-unimplemented/slice-index.rs index d28b823ddc1..1a9ed2dd6e4 100644 --- a/src/test/compile-fail/on-unimplemented/slice-index.rs +++ b/src/test/compile-fail/on-unimplemented/slice-index.rs @@ -20,10 +20,10 @@ fn main() { let x = &[1, 2, 3] as &[i32]; x[1i32]; //~ ERROR E0277 //~| NOTE slice indices are of type `usize` or ranges of `usize` - //~| NOTE trait `std::slice::SliceIndex` is not implemented for `i32` + //~| NOTE trait `std::slice::SliceIndex<[i32]>` is not implemented for `i32` //~| NOTE required because of the requirements on the impl of `std::ops::Index` x[..1i32]; //~ ERROR E0277 //~| NOTE slice indices are of type `usize` or ranges of `usize` - //~| NOTE trait `std::slice::SliceIndex` is not implemented for `std::ops::RangeTo` + //~| NOTE trait `std::slice::SliceIndex<[i32]>` is not implemented for `std::ops::RangeTo` //~| NOTE requirements on the impl of `std::ops::Index>` } -- cgit 1.4.1-3-g733a5 From 7d302d25826ee41703e10d6acd6d3114930e1dd2 Mon Sep 17 00:00:00 2001 From: mandeep Date: Wed, 22 Mar 2017 23:06:56 -0500 Subject: Changed E0038 error message in test to comply with new message --- src/test/compile-fail/object-safety-supertrait-mentions-Self.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/test') diff --git a/src/test/compile-fail/object-safety-supertrait-mentions-Self.rs b/src/test/compile-fail/object-safety-supertrait-mentions-Self.rs index 74d1ad62f14..a93c056c410 100644 --- a/src/test/compile-fail/object-safety-supertrait-mentions-Self.rs +++ b/src/test/compile-fail/object-safety-supertrait-mentions-Self.rs @@ -24,7 +24,7 @@ fn make_bar>(t: &T) -> &Bar { fn make_baz(t: &T) -> &Baz { //~^ ERROR E0038 - //~| NOTE the trait cannot use `Self` as a type parameter in the supertrait listing + //~| NOTE the trait cannot use `Self` as a type parameter in the supertraits or where-clauses //~| NOTE the trait `Baz` cannot be made into an object t } -- cgit 1.4.1-3-g733a5 From 769b95dc9f92edb51146727813ea7eae00b5b651 Mon Sep 17 00:00:00 2001 From: Esteban Küber Date: Fri, 17 Mar 2017 21:13:00 -0700 Subject: Add diagnostic for incorrect `pub (restriction)` Given the following statement ```rust pub (a) fn afn() {} ``` Provide the following diagnostic: ```rust error: incorrect restriction in `pub` --> file.rs:15:1 | 15 | pub (a) fn afn() {} | ^^^^^^^ | = help: some valid visibility restrictions are: `pub(crate)`: visible only on the current crate `pub(super)`: visible only in the current module's parent `pub(in path::to::module)`: visible only on the specified path help: to make this visible only to module `a`, add `in` before the path: | pub (in a) fn afn() {} ``` Remove cruft from old `pub(path)` syntax. --- src/libsyntax/parse/parser.rs | 64 +++++++++++++--------- .../privacy/restricted/tuple-struct-fields/test.rs | 7 ++- .../restricted/tuple-struct-fields/test2.rs | 7 ++- .../restricted/tuple-struct-fields/test3.rs | 7 ++- src/test/ui/pub/pub-restricted-error-fn.rs | 13 +++++ src/test/ui/pub/pub-restricted-error-fn.stderr | 8 +++ src/test/ui/pub/pub-restricted-error.rs | 19 +++++++ src/test/ui/pub/pub-restricted-error.stderr | 8 +++ src/test/ui/pub/pub-restricted-non-path.rs | 15 +++++ src/test/ui/pub/pub-restricted-non-path.stderr | 8 +++ src/test/ui/pub/pub-restricted.rs | 37 +++++++++++++ src/test/ui/pub/pub-restricted.stderr | 47 ++++++++++++++++ 12 files changed, 205 insertions(+), 35 deletions(-) create mode 100644 src/test/ui/pub/pub-restricted-error-fn.rs create mode 100644 src/test/ui/pub/pub-restricted-error-fn.stderr create mode 100644 src/test/ui/pub/pub-restricted-error.rs create mode 100644 src/test/ui/pub/pub-restricted-error.stderr create mode 100644 src/test/ui/pub/pub-restricted-non-path.rs create mode 100644 src/test/ui/pub/pub-restricted-non-path.stderr create mode 100644 src/test/ui/pub/pub-restricted.rs create mode 100644 src/test/ui/pub/pub-restricted.stderr (limited to 'src/test') diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index df4ccc94c04..649e9059934 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -4626,7 +4626,7 @@ impl<'a> Parser<'a> { let mut attrs = self.parse_outer_attributes()?; let lo = self.span.lo; - let vis = self.parse_visibility()?; + let vis = self.parse_visibility(false)?; let defaultness = self.parse_defaultness()?; let (name, node) = if self.eat_keyword(keywords::Type) { let name = self.parse_ident()?; @@ -4939,25 +4939,8 @@ impl<'a> Parser<'a> { |p| { let attrs = p.parse_outer_attributes()?; let lo = p.span.lo; - let mut vis = p.parse_visibility()?; - let ty_is_interpolated = - p.token.is_interpolated() || p.look_ahead(1, |t| t.is_interpolated()); - let mut ty = p.parse_ty()?; - - // Handle `pub(path) type`, in which `vis` will be `pub` and `ty` will be `(path)`. - if vis == Visibility::Public && !ty_is_interpolated && - p.token != token::Comma && p.token != token::CloseDelim(token::Paren) { - ty = if let TyKind::Paren(ref path_ty) = ty.node { - if let TyKind::Path(None, ref path) = path_ty.node { - vis = Visibility::Restricted { path: P(path.clone()), id: path_ty.id }; - Some(p.parse_ty()?) - } else { - None - } - } else { - None - }.unwrap_or(ty); - } + let vis = p.parse_visibility(true)?; + let ty = p.parse_ty()?; Ok(StructField { span: mk_sp(lo, p.span.hi), vis: vis, @@ -4996,18 +4979,25 @@ impl<'a> Parser<'a> { fn parse_struct_decl_field(&mut self) -> PResult<'a, StructField> { let attrs = self.parse_outer_attributes()?; let lo = self.span.lo; - let vis = self.parse_visibility()?; + let vis = self.parse_visibility(false)?; self.parse_single_struct_field(lo, vis, attrs) } - // Parse `pub`, `pub(crate)` and `pub(in path)` plus shortcuts - // `pub(self)` for `pub(in self)` and `pub(super)` for `pub(in super)`. - fn parse_visibility(&mut self) -> PResult<'a, Visibility> { + /// Parse `pub`, `pub(crate)` and `pub(in path)` plus shortcuts `pub(self)` for `pub(in self)` + /// and `pub(super)` for `pub(in super)`. If the following element can't be a tuple (i.e. it's + /// a function definition, it's not a tuple struct field) and the contents within the parens + /// isn't valid, emit a proper diagnostic. + fn parse_visibility(&mut self, can_take_tuple: bool) -> PResult<'a, Visibility> { if !self.eat_keyword(keywords::Pub) { return Ok(Visibility::Inherited) } if self.check(&token::OpenDelim(token::Paren)) { + let start_span = self.span; + // We don't `self.bump()` the `(` yet because this might be a struct definition where + // `()` or a tuple might be allowed. For example, `struct Struct(pub (), pub (usize));`. + // Because of this, we only `bump` the `(` if we're assured it is appropriate to do so + // by the following tokens. if self.look_ahead(1, |t| t.is_keyword(keywords::Crate)) { // `pub(crate)` self.bump(); // `(` @@ -5032,6 +5022,28 @@ impl<'a> Parser<'a> { let vis = Visibility::Restricted { path: P(path), id: ast::DUMMY_NODE_ID }; self.expect(&token::CloseDelim(token::Paren))?; // `)` return Ok(vis) + } else if !can_take_tuple { // Provide this diagnostic if this is not a tuple struct + // `pub(something) fn ...` or `struct X { pub(something) y: Z }` + self.bump(); // `(` + let msg = "incorrect visibility restriction"; + let suggestion = r##"some possible visibility restrictions are: +`pub(crate)`: visible only on the current crate +`pub(super)`: visible only in the current module's parent +`pub(in path::to::module)`: visible only on the specified path"##; + let path = self.parse_path(PathStyle::Mod)?; + let path_span = self.prev_span; + let help_msg = format!("to make this visible only to module `{}`, add `in` before \ + the path:", + path); + self.expect(&token::CloseDelim(token::Paren))?; // `)` + let sp = Span { + lo: start_span.lo, + hi: self.prev_span.hi, + expn_id: start_span.expn_id, + }; + let mut err = self.span_fatal_help(sp, &msg, &suggestion); + err.span_suggestion(path_span, &help_msg, format!("in {}", path)); + err.emit(); // emit diagnostic, but continue with public visibility } } @@ -5508,7 +5520,7 @@ impl<'a> Parser<'a> { let lo = self.span.lo; - let visibility = self.parse_visibility()?; + let visibility = self.parse_visibility(false)?; if self.eat_keyword(keywords::Use) { // USE ITEM @@ -5787,7 +5799,7 @@ impl<'a> Parser<'a> { fn parse_foreign_item(&mut self) -> PResult<'a, Option> { let attrs = self.parse_outer_attributes()?; let lo = self.span.lo; - let visibility = self.parse_visibility()?; + let visibility = self.parse_visibility(false)?; if self.check_keyword(keywords::Static) { // FOREIGN STATIC ITEM diff --git a/src/test/compile-fail/privacy/restricted/tuple-struct-fields/test.rs b/src/test/compile-fail/privacy/restricted/tuple-struct-fields/test.rs index 208f1a0e2ee..d17b604717e 100644 --- a/src/test/compile-fail/privacy/restricted/tuple-struct-fields/test.rs +++ b/src/test/compile-fail/privacy/restricted/tuple-struct-fields/test.rs @@ -10,7 +10,8 @@ mod foo { type T = (); - struct S1(pub(foo) (), pub(T), pub(crate) (), pub(((), T))); - struct S2(pub((foo)) ()); //~ ERROR expected `,`, found `(` - //~| ERROR expected one of `;` or `where`, found `(` + struct S1(pub(in foo) (), pub(T), pub(crate) (), pub(((), T))); + struct S2(pub((foo)) ()); + //~^ ERROR expected `,`, found `(` + //~| ERROR expected one of `;` or `where`, found `(` } diff --git a/src/test/compile-fail/privacy/restricted/tuple-struct-fields/test2.rs b/src/test/compile-fail/privacy/restricted/tuple-struct-fields/test2.rs index 57769646e3b..166d5e27e8d 100644 --- a/src/test/compile-fail/privacy/restricted/tuple-struct-fields/test2.rs +++ b/src/test/compile-fail/privacy/restricted/tuple-struct-fields/test2.rs @@ -11,9 +11,10 @@ macro_rules! define_struct { ($t:ty) => { struct S1(pub $t); - struct S2(pub (foo) ()); - struct S3(pub $t ()); //~ ERROR expected `,`, found `(` - //~| ERROR expected one of `;` or `where`, found `(` + struct S2(pub (in foo) ()); + struct S3(pub $t ()); + //~^ ERROR expected `,`, found `(` + //~| ERROR expected one of `;` or `where`, found `(` } } diff --git a/src/test/compile-fail/privacy/restricted/tuple-struct-fields/test3.rs b/src/test/compile-fail/privacy/restricted/tuple-struct-fields/test3.rs index db3358f7d50..edab175f4cd 100644 --- a/src/test/compile-fail/privacy/restricted/tuple-struct-fields/test3.rs +++ b/src/test/compile-fail/privacy/restricted/tuple-struct-fields/test3.rs @@ -11,9 +11,10 @@ macro_rules! define_struct { ($t:ty) => { struct S1(pub($t)); - struct S2(pub (foo) ()); - struct S3(pub($t) ()); //~ ERROR expected `,`, found `(` - //~| ERROR expected one of `;` or `where`, found `(` + struct S2(pub (in foo) ()); + struct S3(pub($t) ()); + //~^ ERROR expected `,`, found `(` + //~| ERROR expected one of `;` or `where`, found `(` } } diff --git a/src/test/ui/pub/pub-restricted-error-fn.rs b/src/test/ui/pub/pub-restricted-error-fn.rs new file mode 100644 index 00000000000..13514310371 --- /dev/null +++ b/src/test/ui/pub/pub-restricted-error-fn.rs @@ -0,0 +1,13 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(pub_restricted)] + +pub(crate) () fn foo() {} diff --git a/src/test/ui/pub/pub-restricted-error-fn.stderr b/src/test/ui/pub/pub-restricted-error-fn.stderr new file mode 100644 index 00000000000..470e8331247 --- /dev/null +++ b/src/test/ui/pub/pub-restricted-error-fn.stderr @@ -0,0 +1,8 @@ +error: unmatched visibility `pub` + --> $DIR/pub-restricted-error-fn.rs:13:10 + | +13 | pub(crate) () fn foo() {} + | ^ + +error: aborting due to previous error + diff --git a/src/test/ui/pub/pub-restricted-error.rs b/src/test/ui/pub/pub-restricted-error.rs new file mode 100644 index 00000000000..99af031899a --- /dev/null +++ b/src/test/ui/pub/pub-restricted-error.rs @@ -0,0 +1,19 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(pub_restricted)] + +struct Bar(pub(())); + +struct Foo { + pub(crate) () foo: usize, +} + + diff --git a/src/test/ui/pub/pub-restricted-error.stderr b/src/test/ui/pub/pub-restricted-error.stderr new file mode 100644 index 00000000000..b8b4c80778d --- /dev/null +++ b/src/test/ui/pub/pub-restricted-error.stderr @@ -0,0 +1,8 @@ +error: expected identifier, found `(` + --> $DIR/pub-restricted-error.rs:16:16 + | +16 | pub(crate) () foo: usize, + | ^ + +error: aborting due to previous error + diff --git a/src/test/ui/pub/pub-restricted-non-path.rs b/src/test/ui/pub/pub-restricted-non-path.rs new file mode 100644 index 00000000000..3f74285717a --- /dev/null +++ b/src/test/ui/pub/pub-restricted-non-path.rs @@ -0,0 +1,15 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(pub_restricted)] + +pub (.) fn afn() {} + +fn main() {} diff --git a/src/test/ui/pub/pub-restricted-non-path.stderr b/src/test/ui/pub/pub-restricted-non-path.stderr new file mode 100644 index 00000000000..ebfccc4d720 --- /dev/null +++ b/src/test/ui/pub/pub-restricted-non-path.stderr @@ -0,0 +1,8 @@ +error: expected identifier, found `.` + --> $DIR/pub-restricted-non-path.rs:13:6 + | +13 | pub (.) fn afn() {} + | ^ + +error: aborting due to previous error + diff --git a/src/test/ui/pub/pub-restricted.rs b/src/test/ui/pub/pub-restricted.rs new file mode 100644 index 00000000000..48e487f71a7 --- /dev/null +++ b/src/test/ui/pub/pub-restricted.rs @@ -0,0 +1,37 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(pub_restricted)] + +mod a {} + +pub (a) fn afn() {} +pub (b) fn bfn() {} +pub fn privfn() {} +mod x { + mod y { + pub (in x) fn foo() {} + pub (super) fn bar() {} + pub (crate) fn qux() {} + } +} + +mod y { + struct Foo { + pub (crate) c: usize, + pub (super) s: usize, + valid_private: usize, + pub (in y) valid_in_x: usize, + pub (a) invalid: usize, + pub (in x) non_parent_invalid: usize, + } +} + +fn main() {} \ No newline at end of file diff --git a/src/test/ui/pub/pub-restricted.stderr b/src/test/ui/pub/pub-restricted.stderr new file mode 100644 index 00000000000..5bc230e8da3 --- /dev/null +++ b/src/test/ui/pub/pub-restricted.stderr @@ -0,0 +1,47 @@ +error: incorrect visibility restriction + --> $DIR/pub-restricted.rs:15:5 + | +15 | pub (a) fn afn() {} + | ^^^ + | + = help: some possible visibility restrictions are: + `pub(crate)`: visible only on the current crate + `pub(super)`: visible only in the current module's parent + `pub(in path::to::module)`: visible only on the specified path +help: to make this visible only to module `a`, add `in` before the path: + | pub (in a) fn afn() {} + +error: incorrect visibility restriction + --> $DIR/pub-restricted.rs:16:5 + | +16 | pub (b) fn bfn() {} + | ^^^ + | + = help: some possible visibility restrictions are: + `pub(crate)`: visible only on the current crate + `pub(super)`: visible only in the current module's parent + `pub(in path::to::module)`: visible only on the specified path +help: to make this visible only to module `b`, add `in` before the path: + | pub (in b) fn bfn() {} + +error: incorrect visibility restriction + --> $DIR/pub-restricted.rs:32:13 + | +32 | pub (a) invalid: usize, + | ^^^ + | + = help: some possible visibility restrictions are: + `pub(crate)`: visible only on the current crate + `pub(super)`: visible only in the current module's parent + `pub(in path::to::module)`: visible only on the specified path +help: to make this visible only to module `a`, add `in` before the path: + | pub (in a) invalid: usize, + +error: visibilities can only be restricted to ancestor modules + --> $DIR/pub-restricted.rs:33:17 + | +33 | pub (in x) non_parent_invalid: usize, + | ^ + +error: aborting due to 4 previous errors + -- cgit 1.4.1-3-g733a5 From 5ca8a735ca36219abbf601624606c41148b95210 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 13 Mar 2017 22:27:12 -0700 Subject: std: Don't cache stdio handles on Windows This alters the stdio code on Windows to always call `GetStdHandle` whenever the stdio read/write functions are called as this allows us to track changes to the value over time (such as if a process calls `SetStdHandle` while it's running). Closes #40490 --- src/libstd/sys/windows/process.rs | 9 ++- src/libstd/sys/windows/stdio.rs | 92 ++++++++++++----------------- src/test/run-pass-fulldeps/switch-stdout.rs | 64 ++++++++++++++++++++ 3 files changed, 110 insertions(+), 55 deletions(-) create mode 100644 src/test/run-pass-fulldeps/switch-stdout.rs (limited to 'src/test') diff --git a/src/libstd/sys/windows/process.rs b/src/libstd/sys/windows/process.rs index 1afb3728c9d..dfbc1b581ee 100644 --- a/src/libstd/sys/windows/process.rs +++ b/src/libstd/sys/windows/process.rs @@ -257,8 +257,13 @@ impl Stdio { // INVALID_HANDLE_VALUE. Stdio::Inherit => { match stdio::get(stdio_id) { - Ok(io) => io.handle().duplicate(0, true, - c::DUPLICATE_SAME_ACCESS), + Ok(io) => { + let io = Handle::new(io.handle()); + let ret = io.duplicate(0, true, + c::DUPLICATE_SAME_ACCESS); + io.into_raw(); + return ret + } Err(..) => Ok(Handle::new(c::INVALID_HANDLE_VALUE)), } } diff --git a/src/libstd/sys/windows/stdio.rs b/src/libstd/sys/windows/stdio.rs index b1a57c349fb..d72e4b4438b 100644 --- a/src/libstd/sys/windows/stdio.rs +++ b/src/libstd/sys/windows/stdio.rs @@ -22,42 +22,43 @@ use sys::cvt; use sys::handle::Handle; use sys_common::io::read_to_end_uninitialized; -pub struct NoClose(Option); - pub enum Output { - Console(NoClose), - Pipe(NoClose), + Console(c::HANDLE), + Pipe(c::HANDLE), } pub struct Stdin { - handle: Output, utf8: Mutex>>, } -pub struct Stdout(Output); -pub struct Stderr(Output); +pub struct Stdout; +pub struct Stderr; pub fn get(handle: c::DWORD) -> io::Result { let handle = unsafe { c::GetStdHandle(handle) }; if handle == c::INVALID_HANDLE_VALUE { Err(io::Error::last_os_error()) } else if handle.is_null() { - Err(io::Error::new(io::ErrorKind::Other, - "no stdio handle available for this process")) + Err(io::Error::from_raw_os_error(c::ERROR_INVALID_HANDLE as i32)) } else { - let ret = NoClose::new(handle); let mut out = 0; match unsafe { c::GetConsoleMode(handle, &mut out) } { - 0 => Ok(Output::Pipe(ret)), - _ => Ok(Output::Console(ret)), + 0 => Ok(Output::Pipe(handle)), + _ => Ok(Output::Console(handle)), } } } -fn write(out: &Output, data: &[u8]) -> io::Result { - let handle = match *out { - Output::Console(ref c) => c.get().raw(), - Output::Pipe(ref p) => return p.get().write(data), +fn write(handle: c::DWORD, data: &[u8]) -> io::Result { + let handle = match try!(get(handle)) { + Output::Console(c) => c, + Output::Pipe(p) => { + let handle = Handle::new(p); + let ret = handle.write(data); + handle.into_raw(); + return ret + } }; + // As with stdin on windows, stdout often can't handle writes of large // sizes. For an example, see #14940. For this reason, don't try to // write the entire output buffer on windows. @@ -93,18 +94,20 @@ fn write(out: &Output, data: &[u8]) -> io::Result { impl Stdin { pub fn new() -> io::Result { - get(c::STD_INPUT_HANDLE).map(|handle| { - Stdin { - handle: handle, - utf8: Mutex::new(Cursor::new(Vec::new())), - } + Ok(Stdin { + utf8: Mutex::new(Cursor::new(Vec::new())), }) } pub fn read(&self, buf: &mut [u8]) -> io::Result { - let handle = match self.handle { - Output::Console(ref c) => c.get().raw(), - Output::Pipe(ref p) => return p.get().read(buf), + let handle = match try!(get(c::STD_INPUT_HANDLE)) { + Output::Console(c) => c, + Output::Pipe(p) => { + let handle = Handle::new(p); + let ret = handle.read(buf); + handle.into_raw(); + return ret + } }; let mut utf8 = self.utf8.lock().unwrap(); // Read more if the buffer is empty @@ -125,11 +128,9 @@ impl Stdin { Ok(utf8) => utf8.into_bytes(), Err(..) => return Err(invalid_encoding()), }; - if let Output::Console(_) = self.handle { - if let Some(&last_byte) = data.last() { - if last_byte == CTRL_Z { - data.pop(); - } + if let Some(&last_byte) = data.last() { + if last_byte == CTRL_Z { + data.pop(); } } *utf8 = Cursor::new(data); @@ -158,11 +159,11 @@ impl<'a> Read for &'a Stdin { impl Stdout { pub fn new() -> io::Result { - get(c::STD_OUTPUT_HANDLE).map(Stdout) + Ok(Stdout) } pub fn write(&self, data: &[u8]) -> io::Result { - write(&self.0, data) + write(c::STD_OUTPUT_HANDLE, data) } pub fn flush(&self) -> io::Result<()> { @@ -172,11 +173,11 @@ impl Stdout { impl Stderr { pub fn new() -> io::Result { - get(c::STD_ERROR_HANDLE).map(Stderr) + Ok(Stderr) } pub fn write(&self, data: &[u8]) -> io::Result { - write(&self.0, data) + write(c::STD_ERROR_HANDLE, data) } pub fn flush(&self) -> io::Result<()> { @@ -197,27 +198,12 @@ impl io::Write for Stderr { } } -impl NoClose { - fn new(handle: c::HANDLE) -> NoClose { - NoClose(Some(Handle::new(handle))) - } - - fn get(&self) -> &Handle { self.0.as_ref().unwrap() } -} - -impl Drop for NoClose { - fn drop(&mut self) { - self.0.take().unwrap().into_raw(); - } -} - impl Output { - pub fn handle(&self) -> &Handle { - let nc = match *self { - Output::Console(ref c) => c, - Output::Pipe(ref c) => c, - }; - nc.0.as_ref().unwrap() + pub fn handle(&self) -> c::HANDLE { + match *self { + Output::Console(c) => c, + Output::Pipe(c) => c, + } } } diff --git a/src/test/run-pass-fulldeps/switch-stdout.rs b/src/test/run-pass-fulldeps/switch-stdout.rs new file mode 100644 index 00000000000..4542e27545a --- /dev/null +++ b/src/test/run-pass-fulldeps/switch-stdout.rs @@ -0,0 +1,64 @@ +// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(rustc_private)] + +extern crate rustc_back; + +use std::fs::File; +use std::io::{Read, Write}; + +use rustc_back::tempdir::TempDir; + +#[cfg(unix)] +fn switch_stdout_to(file: File) { + use std::os::unix::prelude::*; + + extern { + fn dup2(old: i32, new: i32) -> i32; + } + + unsafe { + assert_eq!(dup2(file.as_raw_fd(), 1), 1); + } +} + +#[cfg(windows)] +fn switch_stdout_to(file: File) { + use std::os::windows::prelude::*; + + extern "system" { + fn SetStdHandle(nStdHandle: u32, handle: *mut u8) -> i32; + } + + const STD_OUTPUT_HANDLE: u32 = (-11i32) as u32; + + unsafe { + let rc = SetStdHandle(STD_OUTPUT_HANDLE, + file.into_raw_handle() as *mut _); + assert!(rc != 0); + } +} + +fn main() { + let td = TempDir::new("foo").unwrap(); + let path = td.path().join("bar"); + let f = File::create(&path).unwrap(); + + println!("foo"); + std::io::stdout().flush().unwrap(); + switch_stdout_to(f); + println!("bar"); + std::io::stdout().flush().unwrap(); + + let mut contents = String::new(); + File::open(&path).unwrap().read_to_string(&mut contents).unwrap(); + assert_eq!(contents, "bar\n"); +} -- cgit 1.4.1-3-g733a5 From 8ffe4068a6d8ff79cfccc0244a96e728387bbeb6 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Thu, 23 Mar 2017 19:26:38 +0200 Subject: keep the AST node-id when lowering ExprKind::Range When the Range expression is the root of a constant, its node-id is used for the def-id of the body, so it has to be preserved in the AST -> HIR lowering. Fixes #40749. --- src/librustc/hir/lowering.rs | 95 ++++++++++++++---------------------- src/test/compile-fail/issue-40749.rs | 16 ++++++ 2 files changed, 52 insertions(+), 59 deletions(-) create mode 100644 src/test/compile-fail/issue-40749.rs (limited to 'src/test') diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 2ac1a036f99..6ca0c971ea4 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -1900,57 +1900,45 @@ impl<'a> LoweringContext<'a> { hir::ExprIndex(P(self.lower_expr(el)), P(self.lower_expr(er))) } ExprKind::Range(ref e1, ref e2, lims) => { - fn make_struct(this: &mut LoweringContext, - ast_expr: &Expr, - path: &[&str], - fields: &[(&str, &P)]) -> hir::Expr { - let struct_path = &iter::once(&"ops").chain(path).map(|s| *s) - .collect::>(); - let unstable_span = this.allow_internal_unstable("...", ast_expr.span); - - if fields.len() == 0 { - this.expr_std_path(unstable_span, struct_path, - ast_expr.attrs.clone()) - } else { - let fields = fields.into_iter().map(|&(s, e)| { - let expr = P(this.lower_expr(&e)); - let unstable_span = this.allow_internal_unstable("...", e.span); - this.field(Symbol::intern(s), expr, unstable_span) - }).collect(); - let attrs = ast_expr.attrs.clone(); - - this.expr_std_struct(unstable_span, struct_path, fields, None, attrs) - } - } - use syntax::ast::RangeLimits::*; - return match (e1, e2, lims) { - (&None, &None, HalfOpen) => - make_struct(self, e, &["RangeFull"], &[]), - - (&Some(ref e1), &None, HalfOpen) => - make_struct(self, e, &["RangeFrom"], - &[("start", e1)]), - - (&None, &Some(ref e2), HalfOpen) => - make_struct(self, e, &["RangeTo"], - &[("end", e2)]), - - (&Some(ref e1), &Some(ref e2), HalfOpen) => - make_struct(self, e, &["Range"], - &[("start", e1), ("end", e2)]), - - (&None, &Some(ref e2), Closed) => - make_struct(self, e, &["RangeToInclusive"], - &[("end", e2)]), - - (&Some(ref e1), &Some(ref e2), Closed) => - make_struct(self, e, &["RangeInclusive", "NonEmpty"], - &[("start", e1), ("end", e2)]), + let (path, variant) = match (e1, e2, lims) { + (&None, &None, HalfOpen) => ("RangeFull", None), + (&Some(..), &None, HalfOpen) => ("RangeFrom", None), + (&None, &Some(..), HalfOpen) => ("RangeTo", None), + (&Some(..), &Some(..), HalfOpen) => ("Range", None), + (&None, &Some(..), Closed) => ("RangeToInclusive", None), + (&Some(..), &Some(..), Closed) => ("RangeInclusive", Some("NonEmpty")), + (_, &None, Closed) => + panic!(self.diagnostic().span_fatal( + e.span, "inclusive range with no end")), + }; - _ => panic!(self.diagnostic() - .span_fatal(e.span, "inclusive range with no end")), + let fields = + e1.iter().map(|e| ("start", e)).chain(e2.iter().map(|e| ("end", e))) + .map(|(s, e)| { + let expr = P(self.lower_expr(&e)); + let unstable_span = self.allow_internal_unstable("...", e.span); + self.field(Symbol::intern(s), expr, unstable_span) + }).collect::>(); + + let is_unit = fields.is_empty(); + let unstable_span = self.allow_internal_unstable("...", e.span); + let struct_path = + iter::once("ops").chain(iter::once(path)).chain(variant) + .collect::>(); + let struct_path = self.std_path(unstable_span, &struct_path, is_unit); + let struct_path = hir::QPath::Resolved(None, P(struct_path)); + + return hir::Expr { + id: self.lower_node_id(e.id), + node: if is_unit { + hir::ExprPath(struct_path) + } else { + hir::ExprStruct(struct_path, fields, None) + }, + span: unstable_span, + attrs: e.attrs.clone(), }; } ExprKind::Path(ref qself, ref path) => { @@ -2613,17 +2601,6 @@ impl<'a> LoweringContext<'a> { P(self.expr(sp, hir::ExprTup(exprs), ThinVec::new())) } - fn expr_std_struct(&mut self, - span: Span, - components: &[&str], - fields: hir::HirVec, - e: Option>, - attrs: ThinVec) -> hir::Expr { - let path = self.std_path(span, components, false); - let qpath = hir::QPath::Resolved(None, P(path)); - self.expr(span, hir::ExprStruct(qpath, fields, e), attrs) - } - fn expr(&mut self, span: Span, node: hir::Expr_, attrs: ThinVec) -> hir::Expr { hir::Expr { id: self.next_id(), diff --git a/src/test/compile-fail/issue-40749.rs b/src/test/compile-fail/issue-40749.rs new file mode 100644 index 00000000000..261ed49d10c --- /dev/null +++ b/src/test/compile-fail/issue-40749.rs @@ -0,0 +1,16 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main() { + [0; ..10]; + //~^ ERROR mismatched types + //~| expected type `usize` + //~| found type `std::ops::RangeTo<{integer}>` +} -- cgit 1.4.1-3-g733a5 From e341d603fe7c35ce174bd2e54e47ed6941ea4b03 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 15 Feb 2017 07:57:59 -0800 Subject: Remove internal liblog This commit deletes the internal liblog in favor of the implementation that lives on crates.io. Similarly it's also setting a convention for adding crates to the compiler. The main restriction right now is that we want compiler implementation details to be unreachable from normal Rust code (e.g. requires a feature), and by default everything in the sysroot is reachable via `extern crate`. The proposal here is to require that crates pulled in have these lines in their `src/lib.rs`: #![cfg_attr(rustbuild, feature(staged_api, rustc_private))] #![cfg_attr(rustbuild, unstable(feature = "rustc_private", issue = "27812"))] This'll mean that by default they're not using these attributes but when compiled as part of the compiler they do a few things: * Mark themselves as entirely unstable via the `staged_api` feature and the `#![unstable]` attribute. * Allow usage of other unstable crates via `feature(rustc_private)` which is required if the crate relies on any other crates to compile (other than std). --- src/Cargo.lock | 53 +-- src/liblog/Cargo.toml | 9 - src/liblog/directive.rs | 193 -------- src/liblog/lib.rs | 506 --------------------- src/liblog/macros.rs | 205 --------- src/librustc/Cargo.toml | 2 +- src/librustc/hir/map/mod.rs | 2 +- src/librustc/ty/item_path.rs | 3 +- src/librustc_back/Cargo.toml | 2 +- src/librustc_borrowck/Cargo.toml | 2 +- src/librustc_const_eval/Cargo.toml | 2 +- src/librustc_data_structures/Cargo.toml | 2 +- src/librustc_driver/Cargo.toml | 3 +- src/librustc_driver/driver.rs | 4 +- src/librustc_driver/lib.rs | 2 + src/librustc_incremental/Cargo.toml | 2 +- src/librustc_lint/Cargo.toml | 2 +- src/librustc_metadata/Cargo.toml | 2 +- src/librustc_metadata/creader.rs | 2 +- src/librustc_mir/Cargo.toml | 2 +- src/librustc_passes/Cargo.toml | 4 +- src/librustc_resolve/Cargo.toml | 2 +- src/librustc_save_analysis/Cargo.toml | 2 +- src/librustc_trans/Cargo.toml | 2 +- src/librustc_typeck/Cargo.toml | 2 +- src/librustdoc/Cargo.toml | 5 +- src/librustdoc/lib.rs | 2 + src/libsyntax/Cargo.toml | 2 +- src/libsyntax_ext/Cargo.toml | 2 +- .../auxiliary/logging_right_crate.rs | 18 - .../conditional-debug-macro-off.rs | 23 - .../run-pass-fulldeps/logging-enabled-debug.rs | 24 - src/test/run-pass-fulldeps/logging-enabled.rs | 27 -- src/test/run-pass-fulldeps/logging-right-crate.rs | 31 -- .../run-pass-fulldeps/logging-separate-lines.rs | 40 -- src/test/run-pass-fulldeps/rust-log-filter.rs | 58 --- src/test/run-pass/conditional-debug-macro-on.rs | 2 - src/tools/compiletest/Cargo.toml | 2 +- 38 files changed, 54 insertions(+), 1194 deletions(-) delete mode 100644 src/liblog/Cargo.toml delete mode 100644 src/liblog/directive.rs delete mode 100644 src/liblog/lib.rs delete mode 100644 src/liblog/macros.rs delete mode 100644 src/test/run-pass-fulldeps/auxiliary/logging_right_crate.rs delete mode 100644 src/test/run-pass-fulldeps/conditional-debug-macro-off.rs delete mode 100644 src/test/run-pass-fulldeps/logging-enabled-debug.rs delete mode 100644 src/test/run-pass-fulldeps/logging-enabled.rs delete mode 100644 src/test/run-pass-fulldeps/logging-right-crate.rs delete mode 100644 src/test/run-pass-fulldeps/logging-separate-lines.rs delete mode 100644 src/test/run-pass-fulldeps/rust-log-filter.rs (limited to 'src/test') diff --git a/src/Cargo.lock b/src/Cargo.lock index 9ae894061a6..a0b47f4f0b2 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -147,7 +147,7 @@ dependencies = [ name = "compiletest" version = "0.0.0" dependencies = [ - "env_logger 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "env_logger 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)", @@ -162,14 +162,6 @@ name = "dtoa" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "env_logger" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "env_logger" version = "0.4.2" @@ -270,10 +262,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "linkchecker" version = "0.1.0" -[[package]] -name = "log" -version = "0.0.0" - [[package]] name = "log" version = "0.3.7" @@ -439,7 +427,7 @@ dependencies = [ "arena 0.0.0", "fmt_macros 0.0.0", "graphviz 0.0.0", - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_back 0.0.0", "rustc_bitflags 0.0.0", "rustc_const_math 0.0.0", @@ -479,7 +467,7 @@ dependencies = [ name = "rustc_back" version = "0.0.0" dependencies = [ - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "serialize 0.0.0", "syntax 0.0.0", ] @@ -493,7 +481,7 @@ name = "rustc_borrowck" version = "0.0.0" dependencies = [ "graphviz 0.0.0", - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc_data_structures 0.0.0", "rustc_errors 0.0.0", @@ -508,7 +496,7 @@ version = "0.0.0" dependencies = [ "arena 0.0.0", "graphviz 0.0.0", - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc_back 0.0.0", "rustc_const_math 0.0.0", @@ -530,7 +518,7 @@ dependencies = [ name = "rustc_data_structures" version = "0.0.0" dependencies = [ - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "serialize 0.0.0", ] @@ -539,8 +527,9 @@ name = "rustc_driver" version = "0.0.0" dependencies = [ "arena 0.0.0", + "env_logger 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "graphviz 0.0.0", - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "proc_macro_plugin 0.0.0", "rustc 0.0.0", "rustc_back 0.0.0", @@ -579,7 +568,7 @@ name = "rustc_incremental" version = "0.0.0" dependencies = [ "graphviz 0.0.0", - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc_data_structures 0.0.0", "serialize 0.0.0", @@ -591,7 +580,7 @@ dependencies = [ name = "rustc_lint" version = "0.0.0" dependencies = [ - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc_back 0.0.0", "rustc_const_eval 0.0.0", @@ -623,7 +612,7 @@ name = "rustc_metadata" version = "0.0.0" dependencies = [ "flate 0.0.0", - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "proc_macro 0.0.0", "rustc 0.0.0", "rustc_back 0.0.0", @@ -642,7 +631,7 @@ name = "rustc_mir" version = "0.0.0" dependencies = [ "graphviz 0.0.0", - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc_bitflags 0.0.0", "rustc_const_eval 0.0.0", @@ -666,7 +655,7 @@ dependencies = [ name = "rustc_passes" version = "0.0.0" dependencies = [ - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc_const_eval 0.0.0", "rustc_const_math 0.0.0", @@ -705,7 +694,7 @@ name = "rustc_resolve" version = "0.0.0" dependencies = [ "arena 0.0.0", - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc_errors 0.0.0", "syntax 0.0.0", @@ -716,7 +705,7 @@ dependencies = [ name = "rustc_save_analysis" version = "0.0.0" dependencies = [ - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "rls-data 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "rls-span 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", @@ -730,7 +719,7 @@ name = "rustc_trans" version = "0.0.0" dependencies = [ "flate 0.0.0", - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc_back 0.0.0", "rustc_bitflags 0.0.0", @@ -762,7 +751,7 @@ version = "0.0.0" dependencies = [ "arena 0.0.0", "fmt_macros 0.0.0", - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc_back 0.0.0", "rustc_const_eval 0.0.0", @@ -780,8 +769,9 @@ version = "0.0.0" dependencies = [ "arena 0.0.0", "build_helper 0.1.0", + "env_logger 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "gcc 0.3.44 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc_back 0.0.0", "rustc_const_eval 0.0.0", @@ -857,7 +847,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "syntax" version = "0.0.0" dependencies = [ - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_bitflags 0.0.0", "rustc_data_structures 0.0.0", "rustc_errors 0.0.0", @@ -870,7 +860,7 @@ name = "syntax_ext" version = "0.0.0" dependencies = [ "fmt_macros 0.0.0", - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "proc_macro 0.0.0", "rustc_errors 0.0.0", "syntax 0.0.0", @@ -996,7 +986,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum clap 2.21.1 (registry+https://github.com/rust-lang/crates.io-index)" = "74a80f603221c9cd9aa27a28f52af452850051598537bb6b359c38a7d61e5cda" "checksum cmake 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)" = "d18d68987ed4c516dcc3e7913659bfa4076f5182eea4a7e0038bb060953e76ac" "checksum dtoa 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "80c8b71fd71146990a9742fc06dcbbde19161a267e0ad4e572c35162f4578c90" -"checksum env_logger 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "15abd780e45b3ea4f76b4e9a26ff4843258dd8a3eed2775a0e7368c2e7936c2f" "checksum env_logger 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e3856f1697098606fc6cb97a93de88ca3f3bc35bb878c725920e6e82ecf05e83" "checksum filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "5363ab8e4139b8568a6237db5248646e5a8a2f89bd5ccb02092182b11fd3e922" "checksum gcc 0.3.44 (registry+https://github.com/rust-lang/crates.io-index)" = "a32cd40070d7611ab76343dcb3204b2bb28c8a9450989a83a3d590248142f439" diff --git a/src/liblog/Cargo.toml b/src/liblog/Cargo.toml deleted file mode 100644 index 31a862478d0..00000000000 --- a/src/liblog/Cargo.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -authors = ["The Rust Project Developers"] -name = "log" -version = "0.0.0" - -[lib] -name = "log" -path = "lib.rs" -crate-type = ["dylib", "rlib"] diff --git a/src/liblog/directive.rs b/src/liblog/directive.rs deleted file mode 100644 index eb50d6e6135..00000000000 --- a/src/liblog/directive.rs +++ /dev/null @@ -1,193 +0,0 @@ -// Copyright 2014 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. - -use std::ascii::AsciiExt; -use std::cmp; - -#[derive(Debug, Clone)] -pub struct LogDirective { - pub name: Option, - pub level: u32, -} - -pub const LOG_LEVEL_NAMES: [&'static str; 5] = ["ERROR", "WARN", "INFO", "DEBUG", "TRACE"]; - -/// Parse an individual log level that is either a number or a symbolic log level -fn parse_log_level(level: &str) -> Option { - level.parse::() - .ok() - .or_else(|| { - let pos = LOG_LEVEL_NAMES.iter().position(|&name| name.eq_ignore_ascii_case(level)); - pos.map(|p| p as u32 + 1) - }) - .map(|p| cmp::min(p, ::MAX_LOG_LEVEL)) -} - -/// Parse a logging specification string (e.g: "crate1,crate2::mod3,crate3::x=1/foo") -/// and return a vector with log directives. -/// -/// Valid log levels are 0-255, with the most likely ones being 1-4 (defined in -/// std::). Also supports string log levels of error, warn, info, and debug -pub fn parse_logging_spec(spec: &str) -> (Vec, Option) { - let mut dirs = Vec::new(); - - let mut parts = spec.split('/'); - let mods = parts.next(); - let filter = parts.next(); - if parts.next().is_some() { - println!("warning: invalid logging spec '{}', ignoring it (too many '/'s)", - spec); - return (dirs, None); - } - if let Some(m) = mods { - for s in m.split(',') { - if s.is_empty() { - continue; - } - let mut parts = s.split('='); - let (log_level, name) = - match (parts.next(), parts.next().map(|s| s.trim()), parts.next()) { - (Some(part0), None, None) => { - // if the single argument is a log-level string or number, - // treat that as a global fallback - match parse_log_level(part0) { - Some(num) => (num, None), - None => (::MAX_LOG_LEVEL, Some(part0)), - } - } - (Some(part0), Some(""), None) => (::MAX_LOG_LEVEL, Some(part0)), - (Some(part0), Some(part1), None) => { - match parse_log_level(part1) { - Some(num) => (num, Some(part0)), - _ => { - println!("warning: invalid logging spec '{}', ignoring it", part1); - continue; - } - } - } - _ => { - println!("warning: invalid logging spec '{}', ignoring it", s); - continue; - } - }; - dirs.push(LogDirective { - name: name.map(str::to_owned), - level: log_level, - }); - } - } - - (dirs, filter.map(str::to_owned)) -} - -#[cfg(test)] -mod tests { - use super::parse_logging_spec; - - #[test] - fn parse_logging_spec_valid() { - let (dirs, filter) = parse_logging_spec("crate1::mod1=1,crate1::mod2,crate2=4"); - assert_eq!(dirs.len(), 3); - assert_eq!(dirs[0].name, Some("crate1::mod1".to_owned())); - assert_eq!(dirs[0].level, 1); - - assert_eq!(dirs[1].name, Some("crate1::mod2".to_owned())); - assert_eq!(dirs[1].level, ::MAX_LOG_LEVEL); - - assert_eq!(dirs[2].name, Some("crate2".to_owned())); - assert_eq!(dirs[2].level, 4); - assert!(filter.is_none()); - } - - #[test] - fn parse_logging_spec_invalid_crate() { - // test parse_logging_spec with multiple = in specification - let (dirs, filter) = parse_logging_spec("crate1::mod1=1=2,crate2=4"); - assert_eq!(dirs.len(), 1); - assert_eq!(dirs[0].name, Some("crate2".to_owned())); - assert_eq!(dirs[0].level, 4); - assert!(filter.is_none()); - } - - #[test] - fn parse_logging_spec_invalid_log_level() { - // test parse_logging_spec with 'noNumber' as log level - let (dirs, filter) = parse_logging_spec("crate1::mod1=noNumber,crate2=4"); - assert_eq!(dirs.len(), 1); - assert_eq!(dirs[0].name, Some("crate2".to_owned())); - assert_eq!(dirs[0].level, 4); - assert!(filter.is_none()); - } - - #[test] - fn parse_logging_spec_string_log_level() { - // test parse_logging_spec with 'warn' as log level - let (dirs, filter) = parse_logging_spec("crate1::mod1=wrong,crate2=warn"); - assert_eq!(dirs.len(), 1); - assert_eq!(dirs[0].name, Some("crate2".to_owned())); - assert_eq!(dirs[0].level, ::WARN); - assert!(filter.is_none()); - } - - #[test] - fn parse_logging_spec_empty_log_level() { - // test parse_logging_spec with '' as log level - let (dirs, filter) = parse_logging_spec("crate1::mod1=wrong,crate2="); - assert_eq!(dirs.len(), 1); - assert_eq!(dirs[0].name, Some("crate2".to_owned())); - assert_eq!(dirs[0].level, ::MAX_LOG_LEVEL); - assert!(filter.is_none()); - } - - #[test] - fn parse_logging_spec_global() { - // test parse_logging_spec with no crate - let (dirs, filter) = parse_logging_spec("warn,crate2=4"); - assert_eq!(dirs.len(), 2); - assert_eq!(dirs[0].name, None); - assert_eq!(dirs[0].level, 2); - assert_eq!(dirs[1].name, Some("crate2".to_owned())); - assert_eq!(dirs[1].level, 4); - assert!(filter.is_none()); - } - - #[test] - fn parse_logging_spec_valid_filter() { - let (dirs, filter) = parse_logging_spec("crate1::mod1=1,crate1::mod2,crate2=4/abc"); - assert_eq!(dirs.len(), 3); - assert_eq!(dirs[0].name, Some("crate1::mod1".to_owned())); - assert_eq!(dirs[0].level, 1); - - assert_eq!(dirs[1].name, Some("crate1::mod2".to_owned())); - assert_eq!(dirs[1].level, ::MAX_LOG_LEVEL); - - assert_eq!(dirs[2].name, Some("crate2".to_owned())); - assert_eq!(dirs[2].level, 4); - assert!(filter.is_some() && filter.unwrap().to_owned() == "abc"); - } - - #[test] - fn parse_logging_spec_invalid_crate_filter() { - let (dirs, filter) = parse_logging_spec("crate1::mod1=1=2,crate2=4/a.c"); - assert_eq!(dirs.len(), 1); - assert_eq!(dirs[0].name, Some("crate2".to_owned())); - assert_eq!(dirs[0].level, 4); - assert!(filter.is_some() && filter.unwrap().to_owned() == "a.c"); - } - - #[test] - fn parse_logging_spec_empty_with_filter() { - let (dirs, filter) = parse_logging_spec("crate1/a*c"); - assert_eq!(dirs.len(), 1); - assert_eq!(dirs[0].name, Some("crate1".to_owned())); - assert_eq!(dirs[0].level, ::MAX_LOG_LEVEL); - assert!(filter.is_some() && filter.unwrap().to_owned() == "a*c"); - } -} diff --git a/src/liblog/lib.rs b/src/liblog/lib.rs deleted file mode 100644 index 057df647c72..00000000000 --- a/src/liblog/lib.rs +++ /dev/null @@ -1,506 +0,0 @@ -// Copyright 2014 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. - -//! Utilities for program-wide and customizable logging -//! -//! # Examples -//! -//! ``` -//! # #![feature(rustc_private)] -//! #[macro_use] extern crate log; -//! -//! fn main() { -//! debug!("this is a debug {:?}", "message"); -//! error!("this is printed by default"); -//! -//! if log_enabled!(log::INFO) { -//! let x = 3 * 4; // expensive computation -//! info!("the answer was: {:?}", x); -//! } -//! } -//! ``` -//! -//! Assumes the binary is `main`: -//! -//! ```{.bash} -//! $ RUST_LOG=error ./main -//! ERROR:main: this is printed by default -//! ``` -//! -//! ```{.bash} -//! $ RUST_LOG=info ./main -//! ERROR:main: this is printed by default -//! INFO:main: the answer was: 12 -//! ``` -//! -//! ```{.bash} -//! $ RUST_LOG=debug ./main -//! DEBUG:main: this is a debug message -//! ERROR:main: this is printed by default -//! INFO:main: the answer was: 12 -//! ``` -//! -//! You can also set the log level on a per module basis: -//! -//! ```{.bash} -//! $ RUST_LOG=main=info ./main -//! ERROR:main: this is printed by default -//! INFO:main: the answer was: 12 -//! ``` -//! -//! And enable all logging: -//! -//! ```{.bash} -//! $ RUST_LOG=main ./main -//! DEBUG:main: this is a debug message -//! ERROR:main: this is printed by default -//! INFO:main: the answer was: 12 -//! ``` -//! -//! # Logging Macros -//! -//! There are five macros that the logging subsystem uses: -//! -//! * `log!(level, ...)` - the generic logging macro, takes a level as a u32 and any -//! related `format!` arguments -//! * `debug!(...)` - a macro hard-wired to the log level of `DEBUG` -//! * `info!(...)` - a macro hard-wired to the log level of `INFO` -//! * `warn!(...)` - a macro hard-wired to the log level of `WARN` -//! * `error!(...)` - a macro hard-wired to the log level of `ERROR` -//! -//! All of these macros use the same style of syntax as the `format!` syntax -//! extension. Details about the syntax can be found in the documentation of -//! `std::fmt` along with the Rust tutorial/manual. -//! -//! If you want to check at runtime if a given logging level is enabled (e.g. if the -//! information you would want to log is expensive to produce), you can use the -//! following macro: -//! -//! * `log_enabled!(level)` - returns true if logging of the given level is enabled -//! -//! # Enabling logging -//! -//! Log levels are controlled on a per-module basis, and by default all logging is -//! disabled except for `error!` (a log level of 1). Logging is controlled via the -//! `RUST_LOG` environment variable. The value of this environment variable is a -//! comma-separated list of logging directives. A logging directive is of the form: -//! -//! ```text -//! path::to::module=log_level -//! ``` -//! -//! The path to the module is rooted in the name of the crate it was compiled for, -//! so if your program is contained in a file `hello.rs`, for example, to turn on -//! logging for this file you would use a value of `RUST_LOG=hello`. -//! Furthermore, this path is a prefix-search, so all modules nested in the -//! specified module will also have logging enabled. -//! -//! The actual `log_level` is optional to specify. If omitted, all logging will be -//! enabled. If specified, the it must be either a numeric in the range of 1-255, or -//! it must be one of the strings `debug`, `error`, `info`, or `warn`. If a numeric -//! is specified, then all logging less than or equal to that numeral is enabled. -//! For example, if logging level 3 is active, error, warn, and info logs will be -//! printed, but debug will be omitted. -//! -//! As the log level for a module is optional, the module to enable logging for is -//! also optional. If only a `log_level` is provided, then the global log level for -//! all modules is set to this value. -//! -//! Some examples of valid values of `RUST_LOG` are: -//! -//! * `hello` turns on all logging for the 'hello' module -//! * `info` turns on all info logging -//! * `hello=debug` turns on debug logging for 'hello' -//! * `hello=3` turns on info logging for 'hello' -//! * `hello,std::option` turns on hello, and std's option logging -//! * `error,hello=warn` turn on global error logging and also warn for hello -//! -//! # Filtering results -//! -//! A RUST_LOG directive may include a string filter. The syntax is to append -//! `/` followed by a string. Each message is checked against the string and is -//! only logged if it contains the string. Note that the matching is done after -//! formatting the log string but before adding any logging meta-data. There is -//! a single filter for all modules. -//! -//! Some examples: -//! -//! * `hello/foo` turns on all logging for the 'hello' module where the log message -//! includes 'foo'. -//! * `info/f.o` turns on all info logging where the log message includes 'foo', -//! 'f1o', 'fao', etc. -//! * `hello=debug/foo*foo` turns on debug logging for 'hello' where the log -//! message includes 'foofoo' or 'fofoo' or 'fooooooofoo', etc. -//! * `error,hello=warn/[0-9] scopes` turn on global error logging and also warn for -//! hello. In both cases the log message must include a single digit number -//! followed by 'scopes' -//! -//! # Performance and Side Effects -//! -//! Each of these macros will expand to code similar to: -//! -//! ```rust,ignore -//! if log_level <= my_module_log_level() { -//! ::log::log(log_level, format!(...)); -//! } -//! ``` -//! -//! What this means is that each of these macros are very cheap at runtime if -//! they're turned off (just a load and an integer comparison). This also means that -//! if logging is disabled, none of the components of the log will be executed. - -#![crate_name = "log"] -#![unstable(feature = "rustc_private", - reason = "use the crates.io `log` library instead", - issue = "27812")] -#![crate_type = "rlib"] -#![crate_type = "dylib"] -#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", - html_favicon_url = "https://doc.rust-lang.org/favicon.ico", - html_root_url = "https://doc.rust-lang.org/nightly/", - html_playground_url = "https://play.rust-lang.org/", - test(attr(deny(warnings))))] -#![deny(missing_docs)] -#![deny(warnings)] - -#![feature(staged_api)] - -use std::cell::RefCell; -use std::fmt; -use std::io::{self, Stderr}; -use std::io::prelude::*; -use std::mem; -use std::env; -use std::slice; -use std::sync::{Mutex, ONCE_INIT, Once}; - -use directive::LOG_LEVEL_NAMES; - -#[macro_use] -pub mod macros; - -mod directive; - -/// Maximum logging level of a module that can be specified. Common logging -/// levels are found in the DEBUG/INFO/WARN/ERROR constants. -pub const MAX_LOG_LEVEL: u32 = 255; - -/// The default logging level of a crate if no other is specified. -const DEFAULT_LOG_LEVEL: u32 = 1; - -static mut LOCK: *mut Mutex<(Vec, Option)> = 0 as *mut _; - -/// An unsafe constant that is the maximum logging level of any module -/// specified. This is the first line of defense to determining whether a -/// logging statement should be run. -static mut LOG_LEVEL: u32 = MAX_LOG_LEVEL; - -/// Debug log level -pub const DEBUG: u32 = 4; -/// Info log level -pub const INFO: u32 = 3; -/// Warn log level -pub const WARN: u32 = 2; -/// Error log level -pub const ERROR: u32 = 1; - -thread_local! { - static LOCAL_LOGGER: RefCell>> = { - RefCell::new(None) - } -} - -/// A trait used to represent an interface to a thread-local logger. Each thread -/// can have its own custom logger which can respond to logging messages -/// however it likes. -pub trait Logger { - /// Logs a single message described by the `record`. - fn log(&mut self, record: &LogRecord); -} - -struct DefaultLogger { - handle: Stderr, -} - -/// Wraps the log level with fmt implementations. -#[derive(Copy, Clone, PartialEq, PartialOrd, Debug)] -pub struct LogLevel(pub u32); - -impl fmt::Display for LogLevel { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - let LogLevel(level) = *self; - match LOG_LEVEL_NAMES.get(level as usize - 1) { - Some(ref name) => fmt::Display::fmt(name, fmt), - None => fmt::Display::fmt(&level, fmt), - } - } -} - -impl Logger for DefaultLogger { - fn log(&mut self, record: &LogRecord) { - match writeln!(&mut self.handle, - "{}:{}: {}", - record.level, - record.module_path, - record.args) { - Err(e) => panic!("failed to log: {:?}", e), - Ok(()) => {} - } - } -} - -impl Drop for DefaultLogger { - fn drop(&mut self) { - // FIXME(#12628): is panicking the right thing to do? - match self.handle.flush() { - Err(e) => panic!("failed to flush a logger: {:?}", e), - Ok(()) => {} - } - } -} - -/// This function is called directly by the compiler when using the logging -/// macros. This function does not take into account whether the log level -/// specified is active or not, it will always log something if this method is -/// called. -/// -/// It is not recommended to call this function directly, rather it should be -/// invoked through the logging family of macros. -#[doc(hidden)] -pub fn log(level: u32, loc: &'static LogLocation, args: fmt::Arguments) { - // Test the literal string from args against the current filter, if there - // is one. - unsafe { - let filter = (*LOCK).lock().unwrap(); - if let Some(ref filter) = filter.1 { - if !args.to_string().contains(filter) { - return; - } - } - } - - // Completely remove the local logger from TLS in case anyone attempts to - // frob the slot while we're doing the logging. This will destroy any logger - // set during logging. - let logger = LOCAL_LOGGER.with(|s| s.borrow_mut().take()); - let mut logger = logger.unwrap_or_else(|| Box::new(DefaultLogger { handle: io::stderr() })); - logger.log(&LogRecord { - level: LogLevel(level), - args: args, - file: loc.file, - module_path: loc.module_path, - line: loc.line, - }); - set_logger(logger); -} - -/// Getter for the global log level. This is a function so that it can be called -/// safely -#[doc(hidden)] -#[inline(always)] -pub fn log_level() -> u32 { - unsafe { LOG_LEVEL } -} - -/// Replaces the thread-local logger with the specified logger, returning the old -/// logger. -pub fn set_logger(logger: Box) -> Option> { - LOCAL_LOGGER.with(|slot| mem::replace(&mut *slot.borrow_mut(), Some(logger))) -} - -/// A LogRecord is created by the logging macros, and passed as the only -/// argument to Loggers. -#[derive(Debug)] -pub struct LogRecord<'a> { - /// The module path of where the LogRecord originated. - pub module_path: &'a str, - - /// The LogLevel of this record. - pub level: LogLevel, - - /// The arguments from the log line. - pub args: fmt::Arguments<'a>, - - /// The file of where the LogRecord originated. - pub file: &'a str, - - /// The line number of where the LogRecord originated. - pub line: u32, -} - -#[doc(hidden)] -#[derive(Copy, Clone)] -pub struct LogLocation { - pub module_path: &'static str, - pub file: &'static str, - pub line: u32, -} - -/// Tests whether a given module's name is enabled for a particular level of -/// logging. This is the second layer of defense about determining whether a -/// module's log statement should be emitted or not. -#[doc(hidden)] -pub fn mod_enabled(level: u32, module: &str) -> bool { - static INIT: Once = ONCE_INIT; - INIT.call_once(init); - - // It's possible for many threads are in this function, only one of them - // will perform the global initialization, but all of them will need to check - // again to whether they should really be here or not. Hence, despite this - // check being expanded manually in the logging macro, this function checks - // the log level again. - if level > unsafe { LOG_LEVEL } { - return false; - } - - // This assertion should never get tripped unless we're in an at_exit - // handler after logging has been torn down and a logging attempt was made. - - unsafe { - let directives = (*LOCK).lock().unwrap(); - enabled(level, module, directives.0.iter()) - } -} - -fn enabled(level: u32, module: &str, iter: slice::Iter) -> bool { - // Search for the longest match, the vector is assumed to be pre-sorted. - for directive in iter.rev() { - match directive.name { - Some(ref name) if !module.starts_with(&name[..]) => {} - Some(..) | None => return level <= directive.level, - } - } - level <= DEFAULT_LOG_LEVEL -} - -/// Initialize logging for the current process. -/// -/// This is not threadsafe at all, so initialization is performed through a -/// `Once` primitive (and this function is called from that primitive). -fn init() { - let (mut directives, filter) = match env::var("RUST_LOG") { - Ok(spec) => directive::parse_logging_spec(&spec[..]), - Err(..) => (Vec::new(), None), - }; - - // Sort the provided directives by length of their name, this allows a - // little more efficient lookup at runtime. - directives.sort_by(|a, b| { - let alen = a.name.as_ref().map(|a| a.len()).unwrap_or(0); - let blen = b.name.as_ref().map(|b| b.len()).unwrap_or(0); - alen.cmp(&blen) - }); - - let max_level = { - let max = directives.iter().max_by_key(|d| d.level); - max.map(|d| d.level).unwrap_or(DEFAULT_LOG_LEVEL) - }; - - unsafe { - LOG_LEVEL = max_level; - - assert!(LOCK.is_null()); - LOCK = Box::into_raw(Box::new(Mutex::new((directives, filter)))); - } -} - -#[cfg(test)] -mod tests { - use super::enabled; - use directive::LogDirective; - - #[test] - fn match_full_path() { - let dirs = [LogDirective { - name: Some("crate2".to_string()), - level: 3, - }, - LogDirective { - name: Some("crate1::mod1".to_string()), - level: 2, - }]; - assert!(enabled(2, "crate1::mod1", dirs.iter())); - assert!(!enabled(3, "crate1::mod1", dirs.iter())); - assert!(enabled(3, "crate2", dirs.iter())); - assert!(!enabled(4, "crate2", dirs.iter())); - } - - #[test] - fn no_match() { - let dirs = [LogDirective { - name: Some("crate2".to_string()), - level: 3, - }, - LogDirective { - name: Some("crate1::mod1".to_string()), - level: 2, - }]; - assert!(!enabled(2, "crate3", dirs.iter())); - } - - #[test] - fn match_beginning() { - let dirs = [LogDirective { - name: Some("crate2".to_string()), - level: 3, - }, - LogDirective { - name: Some("crate1::mod1".to_string()), - level: 2, - }]; - assert!(enabled(3, "crate2::mod1", dirs.iter())); - } - - #[test] - fn match_beginning_longest_match() { - let dirs = [LogDirective { - name: Some("crate2".to_string()), - level: 3, - }, - LogDirective { - name: Some("crate2::mod".to_string()), - level: 4, - }, - LogDirective { - name: Some("crate1::mod1".to_string()), - level: 2, - }]; - assert!(enabled(4, "crate2::mod1", dirs.iter())); - assert!(!enabled(4, "crate2", dirs.iter())); - } - - #[test] - fn match_default() { - let dirs = [LogDirective { - name: None, - level: 3, - }, - LogDirective { - name: Some("crate1::mod1".to_string()), - level: 2, - }]; - assert!(enabled(2, "crate1::mod1", dirs.iter())); - assert!(enabled(3, "crate2::mod2", dirs.iter())); - } - - #[test] - fn zero_level() { - let dirs = [LogDirective { - name: None, - level: 3, - }, - LogDirective { - name: Some("crate1::mod1".to_string()), - level: 0, - }]; - assert!(!enabled(1, "crate1::mod1", dirs.iter())); - assert!(enabled(3, "crate2::mod2", dirs.iter())); - } -} diff --git a/src/liblog/macros.rs b/src/liblog/macros.rs deleted file mode 100644 index 803a2df9ccc..00000000000 --- a/src/liblog/macros.rs +++ /dev/null @@ -1,205 +0,0 @@ -// Copyright 2014 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. - -//! Logging macros - -/// The standard logging macro -/// -/// This macro will generically log over a provided level (of type u32) with a -/// format!-based argument list. See documentation in `std::fmt` for details on -/// how to use the syntax. -/// -/// # Examples -/// -/// ``` -/// # #![feature(rustc_private)] -/// #[macro_use] extern crate log; -/// -/// fn main() { -/// log!(log::WARN, "this is a warning {}", "message"); -/// log!(log::DEBUG, "this is a debug message"); -/// log!(6, "this is a custom logging level: {level}", level=6); -/// } -/// ``` -/// -/// Assumes the binary is `main`: -/// -/// ```{.bash} -/// $ RUST_LOG=warn ./main -/// WARN:main: this is a warning message -/// ``` -/// -/// ```{.bash} -/// $ RUST_LOG=debug ./main -/// DEBUG:main: this is a debug message -/// WARN:main: this is a warning message -/// ``` -/// -/// ```{.bash} -/// $ RUST_LOG=6 ./main -/// DEBUG:main: this is a debug message -/// WARN:main: this is a warning message -/// 6:main: this is a custom logging level: 6 -/// ``` -#[macro_export] -macro_rules! log { - ($lvl:expr, $($arg:tt)+) => ({ - static LOC: ::log::LogLocation = ::log::LogLocation { - line: line!(), - file: file!(), - module_path: module_path!(), - }; - let lvl = $lvl; - if log_enabled!(lvl) { - ::log::log(lvl, &LOC, format_args!($($arg)+)) - } - }) -} - -/// A convenience macro for logging at the error log level. -/// -/// # Examples -/// -/// ``` -/// # #![feature(rustc_private)] -/// #[macro_use] extern crate log; -/// -/// fn main() { -/// let error = 3; -/// error!("the build has failed with error code: {}", error); -/// } -/// ``` -/// -/// Assumes the binary is `main`: -/// -/// ```{.bash} -/// $ RUST_LOG=error ./main -/// ERROR:main: the build has failed with error code: 3 -/// ``` -/// -#[macro_export] -macro_rules! error { - ($($arg:tt)*) => (log!(::log::ERROR, $($arg)*)) -} - -/// A convenience macro for logging at the warning log level. -/// -/// # Examples -/// -/// ``` -/// # #![feature(rustc_private)] -/// #[macro_use] extern crate log; -/// -/// fn main() { -/// let code = 3; -/// warn!("you may like to know that a process exited with: {}", code); -/// } -/// ``` -/// -/// Assumes the binary is `main`: -/// -/// ```{.bash} -/// $ RUST_LOG=warn ./main -/// WARN:main: you may like to know that a process exited with: 3 -/// ``` -#[macro_export] -macro_rules! warn { - ($($arg:tt)*) => (log!(::log::WARN, $($arg)*)) -} - -/// A convenience macro for logging at the info log level. -/// -/// # Examples -/// -/// ``` -/// # #![feature(rustc_private)] -/// #[macro_use] extern crate log; -/// -/// fn main() { -/// let ret = 3; -/// info!("this function is about to return: {}", ret); -/// } -/// ``` -/// -/// Assumes the binary is `main`: -/// -/// ```{.bash} -/// $ RUST_LOG=info ./main -/// INFO:main: this function is about to return: 3 -/// ``` -#[macro_export] -macro_rules! info { - ($($arg:tt)*) => (log!(::log::INFO, $($arg)*)) -} - -/// A convenience macro for logging at the debug log level. This macro will -/// be omitted at compile time in an optimized build unless `-C debug-assertions` -/// is passed to the compiler. -/// -/// # Examples -/// -/// ``` -/// # #![feature(rustc_private)] -/// #[macro_use] extern crate log; -/// -/// fn main() { -/// debug!("x = {x}, y = {y}", x=10, y=20); -/// } -/// ``` -/// -/// Assumes the binary is `main`: -/// -/// ```{.bash} -/// $ RUST_LOG=debug ./main -/// DEBUG:main: x = 10, y = 20 -/// ``` -#[macro_export] -macro_rules! debug { - ($($arg:tt)*) => (if cfg!(debug_assertions) { log!(::log::DEBUG, $($arg)*) }) -} - -/// A macro to test whether a log level is enabled for the current module. -/// -/// # Examples -/// -/// ``` -/// # #![feature(rustc_private)] -/// #[macro_use] extern crate log; -/// -/// struct Point { x: i32, y: i32 } -/// fn some_expensive_computation() -> Point { Point { x: 1, y: 2 } } -/// -/// fn main() { -/// if log_enabled!(log::DEBUG) { -/// let x = some_expensive_computation(); -/// debug!("x.x = {}, x.y = {}", x.x, x.y); -/// } -/// } -/// ``` -/// -/// Assumes the binary is `main`: -/// -/// ```{.bash} -/// $ RUST_LOG=error ./main -/// ``` -/// -/// ```{.bash} -/// $ RUST_LOG=debug ./main -/// DEBUG:main: x.x = 1, x.y = 2 -/// ``` -#[macro_export] -macro_rules! log_enabled { - ($lvl:expr) => ({ - let lvl = $lvl; - (lvl != ::log::DEBUG || cfg!(debug_assertions)) && - lvl <= ::log::log_level() && - ::log::mod_enabled(lvl, module_path!()) - }) -} diff --git a/src/librustc/Cargo.toml b/src/librustc/Cargo.toml index 5d53c60ad7f..fa217acd9f9 100644 --- a/src/librustc/Cargo.toml +++ b/src/librustc/Cargo.toml @@ -12,7 +12,7 @@ crate-type = ["dylib"] arena = { path = "../libarena" } fmt_macros = { path = "../libfmt_macros" } graphviz = { path = "../libgraphviz" } -log = { path = "../liblog" } +log = "0.3" rustc_back = { path = "../librustc_back" } rustc_bitflags = { path = "../librustc_bitflags" } rustc_const_math = { path = "../librustc_const_math" } diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs index 583b3b848f3..d7aa36b24f9 100644 --- a/src/librustc/hir/map/mod.rs +++ b/src/librustc/hir/map/mod.rs @@ -948,7 +948,7 @@ pub fn map_crate<'hir>(forest: &'hir mut Forest, intravisit::walk_crate(&mut collector, &forest.krate); let map = collector.map; - if log_enabled!(::log::DEBUG) { + if log_enabled!(::log::LogLevel::Debug) { // This only makes sense for ordered stores; note the // enumerate to count the number of entries. let (entries_less_1, _) = map.iter().filter(|&x| { diff --git a/src/librustc/ty/item_path.rs b/src/librustc/ty/item_path.rs index 874e032bc46..38699105290 100644 --- a/src/librustc/ty/item_path.rs +++ b/src/librustc/ty/item_path.rs @@ -202,7 +202,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } else { // for local crates, check whether type info is // available; typeck might not have completed yet - self.maps.impl_trait_ref.borrow().contains_key(&impl_def_id) + self.maps.impl_trait_ref.borrow().contains_key(&impl_def_id) && + self.maps.ty.borrow().contains_key(&impl_def_id) }; if !use_types { diff --git a/src/librustc_back/Cargo.toml b/src/librustc_back/Cargo.toml index 85e861b405a..730abc54568 100644 --- a/src/librustc_back/Cargo.toml +++ b/src/librustc_back/Cargo.toml @@ -11,7 +11,7 @@ crate-type = ["dylib"] [dependencies] syntax = { path = "../libsyntax" } serialize = { path = "../libserialize" } -log = { path = "../liblog" } +log = "0.3" [features] jemalloc = [] diff --git a/src/librustc_borrowck/Cargo.toml b/src/librustc_borrowck/Cargo.toml index d53318f1768..af99c0e9387 100644 --- a/src/librustc_borrowck/Cargo.toml +++ b/src/librustc_borrowck/Cargo.toml @@ -10,7 +10,7 @@ crate-type = ["dylib"] test = false [dependencies] -log = { path = "../liblog" } +log = "0.3" syntax = { path = "../libsyntax" } syntax_pos = { path = "../libsyntax_pos" } graphviz = { path = "../libgraphviz" } diff --git a/src/librustc_const_eval/Cargo.toml b/src/librustc_const_eval/Cargo.toml index 780b2c16a32..907410f74dc 100644 --- a/src/librustc_const_eval/Cargo.toml +++ b/src/librustc_const_eval/Cargo.toml @@ -10,7 +10,7 @@ crate-type = ["dylib"] [dependencies] arena = { path = "../libarena" } -log = { path = "../liblog" } +log = "0.3" rustc = { path = "../librustc" } rustc_back = { path = "../librustc_back" } rustc_const_math = { path = "../librustc_const_math" } diff --git a/src/librustc_data_structures/Cargo.toml b/src/librustc_data_structures/Cargo.toml index e2e16059d98..343b1ed68b8 100644 --- a/src/librustc_data_structures/Cargo.toml +++ b/src/librustc_data_structures/Cargo.toml @@ -9,5 +9,5 @@ path = "lib.rs" crate-type = ["dylib"] [dependencies] -log = { path = "../liblog" } +log = "0.3" serialize = { path = "../libserialize" } diff --git a/src/librustc_driver/Cargo.toml b/src/librustc_driver/Cargo.toml index caa5c8b7e00..5b5113caa8e 100644 --- a/src/librustc_driver/Cargo.toml +++ b/src/librustc_driver/Cargo.toml @@ -11,7 +11,8 @@ crate-type = ["dylib"] [dependencies] arena = { path = "../libarena" } graphviz = { path = "../libgraphviz" } -log = { path = "../liblog" } +log = { version = "0.3", features = ["release_max_level_info"] } +env_logger = { version = "0.4", default-features = false } proc_macro_plugin = { path = "../libproc_macro_plugin" } rustc = { path = "../librustc" } rustc_back = { path = "../librustc_back" } diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 5d600270626..91f9a803f4a 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -198,13 +198,13 @@ pub fn compile_input(sess: &Session, result?; - if log_enabled!(::log::INFO) { + if log_enabled!(::log::LogLevel::Info) { println!("Pre-trans"); tcx.print_debug_stats(); } let trans = phase_4_translate_to_llvm(tcx, analysis, &incremental_hashes_map); - if log_enabled!(::log::INFO) { + if log_enabled!(::log::LogLevel::Info) { println!("Post-trans"); tcx.print_debug_stats(); } diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 62d75126557..68b9f85721a 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -35,6 +35,7 @@ extern crate arena; extern crate getopts; extern crate graphviz; +extern crate env_logger; extern crate libc; extern crate rustc; extern crate rustc_back; @@ -1127,6 +1128,7 @@ pub fn diagnostics_registry() -> errors::registry::Registry { } pub fn main() { + env_logger::init().unwrap(); let result = run(|| run_compiler(&env::args().collect::>(), &mut RustcDefaultCalls, None, diff --git a/src/librustc_incremental/Cargo.toml b/src/librustc_incremental/Cargo.toml index e3ee7527545..7bf2efa4b88 100644 --- a/src/librustc_incremental/Cargo.toml +++ b/src/librustc_incremental/Cargo.toml @@ -13,6 +13,6 @@ graphviz = { path = "../libgraphviz" } rustc = { path = "../librustc" } rustc_data_structures = { path = "../librustc_data_structures" } serialize = { path = "../libserialize" } -log = { path = "../liblog" } +log = "0.3" syntax = { path = "../libsyntax" } syntax_pos = { path = "../libsyntax_pos" } diff --git a/src/librustc_lint/Cargo.toml b/src/librustc_lint/Cargo.toml index 4d5c0d7ba0a..c3c5461ff7c 100644 --- a/src/librustc_lint/Cargo.toml +++ b/src/librustc_lint/Cargo.toml @@ -10,7 +10,7 @@ crate-type = ["dylib"] test = false [dependencies] -log = { path = "../liblog" } +log = "0.3" rustc = { path = "../librustc" } rustc_back = { path = "../librustc_back" } rustc_const_eval = { path = "../librustc_const_eval" } diff --git a/src/librustc_metadata/Cargo.toml b/src/librustc_metadata/Cargo.toml index 6f7f03ca216..e8b90609273 100644 --- a/src/librustc_metadata/Cargo.toml +++ b/src/librustc_metadata/Cargo.toml @@ -10,7 +10,7 @@ crate-type = ["dylib"] [dependencies] flate = { path = "../libflate" } -log = { path = "../liblog" } +log = "0.3" proc_macro = { path = "../libproc_macro" } rustc = { path = "../librustc" } rustc_back = { path = "../librustc_back" } diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index fcdb968dc06..e1255110a83 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -1058,7 +1058,7 @@ impl<'a> middle::cstore::CrateLoader for CrateLoader<'a> { self.inject_allocator_crate(); self.inject_panic_runtime(krate); - if log_enabled!(log::INFO) { + if log_enabled!(log::LogLevel::Info) { dump_crates(&self.cstore); } diff --git a/src/librustc_mir/Cargo.toml b/src/librustc_mir/Cargo.toml index 531be0b6ae9..6e42e02d510 100644 --- a/src/librustc_mir/Cargo.toml +++ b/src/librustc_mir/Cargo.toml @@ -10,7 +10,7 @@ crate-type = ["dylib"] [dependencies] graphviz = { path = "../libgraphviz" } -log = { path = "../liblog" } +log = "0.3" rustc = { path = "../librustc" } rustc_const_eval = { path = "../librustc_const_eval" } rustc_const_math = { path = "../librustc_const_math" } diff --git a/src/librustc_passes/Cargo.toml b/src/librustc_passes/Cargo.toml index cc710e0ac35..d2560c2f820 100644 --- a/src/librustc_passes/Cargo.toml +++ b/src/librustc_passes/Cargo.toml @@ -9,10 +9,10 @@ path = "lib.rs" crate-type = ["dylib"] [dependencies] -log = { path = "../liblog" } +log = "0.3" rustc = { path = "../librustc" } rustc_const_eval = { path = "../librustc_const_eval" } rustc_const_math = { path = "../librustc_const_math" } syntax = { path = "../libsyntax" } syntax_pos = { path = "../libsyntax_pos" } -rustc_errors = { path = "../librustc_errors" } \ No newline at end of file +rustc_errors = { path = "../librustc_errors" } diff --git a/src/librustc_resolve/Cargo.toml b/src/librustc_resolve/Cargo.toml index 5ce4c74e735..0968ea31b75 100644 --- a/src/librustc_resolve/Cargo.toml +++ b/src/librustc_resolve/Cargo.toml @@ -10,7 +10,7 @@ crate-type = ["dylib"] test = false [dependencies] -log = { path = "../liblog" } +log = "0.3" syntax = { path = "../libsyntax" } rustc = { path = "../librustc" } arena = { path = "../libarena" } diff --git a/src/librustc_save_analysis/Cargo.toml b/src/librustc_save_analysis/Cargo.toml index 06c5150fd13..07a5c266fc0 100644 --- a/src/librustc_save_analysis/Cargo.toml +++ b/src/librustc_save_analysis/Cargo.toml @@ -9,7 +9,7 @@ path = "lib.rs" crate-type = ["dylib"] [dependencies] -log = { path = "../liblog" } +log = "0.3" rustc = { path = "../librustc" } syntax = { path = "../libsyntax" } syntax_pos = { path = "../libsyntax_pos" } diff --git a/src/librustc_trans/Cargo.toml b/src/librustc_trans/Cargo.toml index b5c67ad998b..07dcb2fc29d 100644 --- a/src/librustc_trans/Cargo.toml +++ b/src/librustc_trans/Cargo.toml @@ -11,7 +11,7 @@ test = false [dependencies] flate = { path = "../libflate" } -log = { path = "../liblog" } +log = "0.3" rustc = { path = "../librustc" } rustc_back = { path = "../librustc_back" } rustc_bitflags = { path = "../librustc_bitflags" } diff --git a/src/librustc_typeck/Cargo.toml b/src/librustc_typeck/Cargo.toml index f08d26373e5..07998aa4a30 100644 --- a/src/librustc_typeck/Cargo.toml +++ b/src/librustc_typeck/Cargo.toml @@ -10,7 +10,7 @@ crate-type = ["dylib"] test = false [dependencies] -log = { path = "../liblog" } +log = "0.3" syntax = { path = "../libsyntax" } arena = { path = "../libarena" } fmt_macros = { path = "../libfmt_macros" } diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml index 93c0bd6d6d8..1c479ce1d01 100644 --- a/src/librustdoc/Cargo.toml +++ b/src/librustdoc/Cargo.toml @@ -11,11 +11,13 @@ crate-type = ["dylib"] [dependencies] arena = { path = "../libarena" } +env_logger = { version = "0.4", default-features = false } +log = "0.3" rustc = { path = "../librustc" } rustc_back = { path = "../librustc_back" } rustc_const_eval = { path = "../librustc_const_eval" } -rustc_driver = { path = "../librustc_driver" } rustc_data_structures = { path = "../librustc_data_structures" } +rustc_driver = { path = "../librustc_driver" } rustc_errors = { path = "../librustc_errors" } rustc_lint = { path = "../librustc_lint" } rustc_metadata = { path = "../librustc_metadata" } @@ -24,7 +26,6 @@ rustc_trans = { path = "../librustc_trans" } serialize = { path = "../libserialize" } syntax = { path = "../libsyntax" } syntax_pos = { path = "../libsyntax_pos" } -log = { path = "../liblog" } [build-dependencies] build_helper = { path = "../build_helper" } diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 84f69cd3504..8dd03f6edc4 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -30,6 +30,7 @@ extern crate arena; extern crate getopts; +extern crate env_logger; extern crate libc; extern crate rustc; extern crate rustc_const_eval; @@ -99,6 +100,7 @@ struct Output { pub fn main() { const STACK_SIZE: usize = 32_000_000; // 32MB + env_logger::init().unwrap(); let res = std::thread::Builder::new().stack_size(STACK_SIZE).spawn(move || { let s = env::args().collect::>(); main_args(&s) diff --git a/src/libsyntax/Cargo.toml b/src/libsyntax/Cargo.toml index 0b38f5450b6..97d37266130 100644 --- a/src/libsyntax/Cargo.toml +++ b/src/libsyntax/Cargo.toml @@ -10,7 +10,7 @@ crate-type = ["dylib"] [dependencies] serialize = { path = "../libserialize" } -log = { path = "../liblog" } +log = "0.3" rustc_bitflags = { path = "../librustc_bitflags" } syntax_pos = { path = "../libsyntax_pos" } rustc_errors = { path = "../librustc_errors" } diff --git a/src/libsyntax_ext/Cargo.toml b/src/libsyntax_ext/Cargo.toml index 960db792a62..bdcec26cb83 100644 --- a/src/libsyntax_ext/Cargo.toml +++ b/src/libsyntax_ext/Cargo.toml @@ -10,7 +10,7 @@ crate-type = ["dylib"] [dependencies] fmt_macros = { path = "../libfmt_macros" } -log = { path = "../liblog" } +log = "0.3" proc_macro = { path = "../libproc_macro" } rustc_errors = { path = "../librustc_errors" } syntax = { path = "../libsyntax" } diff --git a/src/test/run-pass-fulldeps/auxiliary/logging_right_crate.rs b/src/test/run-pass-fulldeps/auxiliary/logging_right_crate.rs deleted file mode 100644 index db26b10fc67..00000000000 --- a/src/test/run-pass-fulldeps/auxiliary/logging_right_crate.rs +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![feature(rustc_private)] - -#[macro_use] extern crate log; - -pub fn foo() { - fn death() -> isize { panic!() } - debug!("{}", (||{ death() })()); -} diff --git a/src/test/run-pass-fulldeps/conditional-debug-macro-off.rs b/src/test/run-pass-fulldeps/conditional-debug-macro-off.rs deleted file mode 100644 index c6beb5ba358..00000000000 --- a/src/test/run-pass-fulldeps/conditional-debug-macro-off.rs +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2012-2014 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. - -// compile-flags: -C debug-assertions=no -// exec-env:RUST_LOG=conditional-debug-macro-off=4 - - -#![feature(rustc_private)] - -#[macro_use] -extern crate log; - -pub fn main() { - // only panics if println! evaluates its argument. - debug!("{:?}", { if true { panic!() } }); -} diff --git a/src/test/run-pass-fulldeps/logging-enabled-debug.rs b/src/test/run-pass-fulldeps/logging-enabled-debug.rs deleted file mode 100644 index 3ae4884ce47..00000000000 --- a/src/test/run-pass-fulldeps/logging-enabled-debug.rs +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright 2013-2014 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. - -// compile-flags:-C debug-assertions=no -// exec-env:RUST_LOG=logging-enabled-debug=debug - - -#![feature(rustc_private)] - -#[macro_use] -extern crate log; - -pub fn main() { - if log_enabled!(log::DEBUG) { - panic!("what?! debugging?"); - } -} diff --git a/src/test/run-pass-fulldeps/logging-enabled.rs b/src/test/run-pass-fulldeps/logging-enabled.rs deleted file mode 100644 index 26261348020..00000000000 --- a/src/test/run-pass-fulldeps/logging-enabled.rs +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright 2013-2014 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. - -// exec-env:RUST_LOG=logging_enabled=info -// ignore-emscripten: FIXME(#31622) - - -#![feature(rustc_private)] - -#[macro_use] -extern crate log; - -pub fn main() { - if log_enabled!(log::DEBUG) { - panic!("what?! debugging?"); - } - if !log_enabled!(log::INFO) { - panic!("what?! no info?"); - } -} diff --git a/src/test/run-pass-fulldeps/logging-right-crate.rs b/src/test/run-pass-fulldeps/logging-right-crate.rs deleted file mode 100644 index 7caeeb40124..00000000000 --- a/src/test/run-pass-fulldeps/logging-right-crate.rs +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright 2013-2014 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. - -// aux-build:logging_right_crate.rs -// exec-env:RUST_LOG=logging-right-crate=debug - -// This is a test for issue #3046 to make sure that when we monomorphize a -// function from one crate to another the right top-level logging name is -// preserved. -// -// It used to be the case that if logging were turned on for this crate, all -// monomorphized functions from other crates had logging turned on (their -// logging module names were all incorrect). This test ensures that this no -// longer happens by enabling logging for *this* crate and then invoking a -// function in an external crate which will panic when logging is enabled. - -// pretty-expanded FIXME #23616 - -extern crate logging_right_crate; - -pub fn main() { - // this function panicks if logging is turned on - logging_right_crate::foo::(); -} diff --git a/src/test/run-pass-fulldeps/logging-separate-lines.rs b/src/test/run-pass-fulldeps/logging-separate-lines.rs deleted file mode 100644 index 183a522bba7..00000000000 --- a/src/test/run-pass-fulldeps/logging-separate-lines.rs +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright 2013-2014 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. - -// ignore-windows -// exec-env:RUST_LOG=debug -// compile-flags:-C debug-assertions=y -// ignore-emscripten: FIXME(#31622) - -#![feature(rustc_private)] - -#[macro_use] -extern crate log; - -use std::process::Command; -use std::env; -use std::str; - -fn main() { - let args: Vec = env::args().collect(); - if args.len() > 1 && args[1] == "child" { - debug!("foo"); - debug!("bar"); - return - } - - let p = Command::new(&args[0]) - .arg("child") - .output().unwrap(); - assert!(p.status.success()); - let mut lines = str::from_utf8(&p.stderr).unwrap().lines(); - assert!(lines.next().unwrap().contains("foo")); - assert!(lines.next().unwrap().contains("bar")); -} diff --git a/src/test/run-pass-fulldeps/rust-log-filter.rs b/src/test/run-pass-fulldeps/rust-log-filter.rs deleted file mode 100644 index 306d24e3177..00000000000 --- a/src/test/run-pass-fulldeps/rust-log-filter.rs +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright 2014 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. - -// exec-env:RUST_LOG=rust_log_filter/foo -// ignore-emscripten no threads support - -#![allow(unknown_features)] -#![feature(box_syntax, std_misc, rustc_private)] - -#[macro_use] -extern crate log; - -use std::sync::mpsc::{channel, Sender, Receiver}; -use std::thread; - -pub struct ChannelLogger { - tx: Sender -} - -impl ChannelLogger { - pub fn new() -> (Box, Receiver) { - let (tx, rx) = channel(); - (box ChannelLogger { tx: tx }, rx) - } -} - -impl log::Logger for ChannelLogger { - fn log(&mut self, record: &log::LogRecord) { - self.tx.send(format!("{}", record.args)).unwrap(); - } -} - -pub fn main() { - let (logger, rx) = ChannelLogger::new(); - - let t = thread::spawn(move|| { - log::set_logger(logger); - - info!("foo"); - info!("bar"); - info!("foo bar"); - info!("bar foo"); - }); - - assert_eq!(rx.recv().unwrap(), "foo"); - assert_eq!(rx.recv().unwrap(), "foo bar"); - assert_eq!(rx.recv().unwrap(), "bar foo"); - assert!(rx.recv().is_err()); - - t.join(); -} diff --git a/src/test/run-pass/conditional-debug-macro-on.rs b/src/test/run-pass/conditional-debug-macro-on.rs index b335e20f91d..7da33be7a57 100644 --- a/src/test/run-pass/conditional-debug-macro-on.rs +++ b/src/test/run-pass/conditional-debug-macro-on.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// exec-env:RUST_LOG=conditional-debug-macro-on=4 - pub fn main() { // exits early if println! evaluates its arguments, otherwise it // will hit the panic. diff --git a/src/tools/compiletest/Cargo.toml b/src/tools/compiletest/Cargo.toml index 1fc98a78a7c..7530b65a9b7 100644 --- a/src/tools/compiletest/Cargo.toml +++ b/src/tools/compiletest/Cargo.toml @@ -5,6 +5,6 @@ version = "0.0.0" [dependencies] log = "0.3" -env_logger = { version = "0.3.5", default-features = false } +env_logger = { version = "0.4", default-features = false } rustc-serialize = "0.3" filetime = "0.1" -- cgit 1.4.1-3-g733a5 From bd52ff1cc3ff9ecce129d20ed56c61ec0b0c5653 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Fri, 24 Mar 2017 00:52:46 +0200 Subject: update LLVM with fix for PR32379 Fixes #40593. --- src/llvm | 2 +- src/rustllvm/llvm-rebuild-trigger | 2 +- src/test/run-pass/auxiliary/llvm_pr32379.rs | 15 +++++++++++++++ src/test/run-pass/llvm-pr32379.rs | 23 +++++++++++++++++++++++ 4 files changed, 40 insertions(+), 2 deletions(-) create mode 100644 src/test/run-pass/auxiliary/llvm_pr32379.rs create mode 100644 src/test/run-pass/llvm-pr32379.rs (limited to 'src/test') diff --git a/src/llvm b/src/llvm index d5ef27a7966..2e951c3ae35 160000 --- a/src/llvm +++ b/src/llvm @@ -1 +1 @@ -Subproject commit d5ef27a79661d4f0d57d7b7d2cdbe9204f790a4a +Subproject commit 2e951c3ae354bcbd2e50b30798e232949a926b75 diff --git a/src/rustllvm/llvm-rebuild-trigger b/src/rustllvm/llvm-rebuild-trigger index be6d535dc73..c8732e27b82 100644 --- a/src/rustllvm/llvm-rebuild-trigger +++ b/src/rustllvm/llvm-rebuild-trigger @@ -1,4 +1,4 @@ # If this file is modified, then llvm will be (optionally) cleaned and then rebuilt. # The actual contents of this file do not matter, but to trigger a change on the # build bots then the contents should be changed so git updates the mtime. -2017-03-19 +2017-03-23 diff --git a/src/test/run-pass/auxiliary/llvm_pr32379.rs b/src/test/run-pass/auxiliary/llvm_pr32379.rs new file mode 100644 index 00000000000..a7b15bda336 --- /dev/null +++ b/src/test/run-pass/auxiliary/llvm_pr32379.rs @@ -0,0 +1,15 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +pub fn pr32379(mut data: u64, f1: bool, f2: bool) -> u64 { + if f1 { data &= !2; } + if f2 { data |= 2; } + data +} diff --git a/src/test/run-pass/llvm-pr32379.rs b/src/test/run-pass/llvm-pr32379.rs new file mode 100644 index 00000000000..5625e81c0e6 --- /dev/null +++ b/src/test/run-pass/llvm-pr32379.rs @@ -0,0 +1,23 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:llvm_pr32379.rs + +// LLVM PR #32379 (https://bugs.llvm.org/show_bug.cgi?id=32379), which +// applies to upstream LLVM 3.9.1, is known to cause rustc itself to be +// miscompiled on ARM (Rust issue #40593). Because cross builds don't test +// our *compiler* on ARM, have a test for the miscompilation directly. + +extern crate llvm_pr32379; + +pub fn main() { + let val = llvm_pr32379::pr32379(2, false, false); + assert_eq!(val, 2); +} -- cgit 1.4.1-3-g733a5 From e6e8c919613615d2e296e5a4adbe81c57c0dbce9 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 23 Mar 2017 15:46:40 -0700 Subject: appveyor: Upgrade MinGW toolchains we use In debugging #40546 I was able to reproduce locally finally using the literal toolchain that the bots were using. I reproduced the error maybe 4 in 10 builds. I also have the 6.3.0 toolchain installed through `pacman` which has yet to have a failed build. When attempting to reproduce the bug with the toolchain that this commit switches to I was unable to reproduce anything after a few builds. I have no idea what the original problem was, but I'm hoping that it was just some random bug fixed somewhere along the way. I don't currently know of a technical reason to stick to the 4.9.2 toolchains we were previously using. Historcal 5.3.* toolchains would cause llvm to segfault (maybe a miscompile?) but this seems to have been fixed recently. To me if it passes CI then I think we're good. Closes #40546 --- appveyor.yml | 16 ++++++++-------- src/test/run-pass/issue-16671.rs | 27 +++++++-------------------- src/tools/compiletest/src/procsrv.rs | 19 ++++++++++++++++++- 3 files changed, 33 insertions(+), 29 deletions(-) (limited to 'src/test') diff --git a/appveyor.yml b/appveyor.yml index 0e7ebf12a2a..146b0ba1b3d 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -45,14 +45,14 @@ environment: - MSYS_BITS: 32 RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu --enable-ninja SCRIPT: python x.py test - MINGW_URL: https://s3.amazonaws.com/rust-lang-ci - MINGW_ARCHIVE: i686-4.9.2-release-win32-dwarf-rt_v4-rev4.7z + MINGW_URL: https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror + MINGW_ARCHIVE: i686-6.3.0-release-win32-dwarf-rt_v5-rev1.7z MINGW_DIR: mingw32 - MSYS_BITS: 64 SCRIPT: python x.py test RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu --enable-ninja - MINGW_URL: https://s3.amazonaws.com/rust-lang-ci - MINGW_ARCHIVE: x86_64-4.9.2-release-win32-seh-rt_v4-rev4.7z + MINGW_URL: https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror + MINGW_ARCHIVE: x86_64-6.3.0-release-win32-seh-rt_v5-rev1.7z MINGW_DIR: mingw64 # 32/64 bit MSVC and GNU deployment @@ -70,15 +70,15 @@ environment: - MSYS_BITS: 32 RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu --enable-extended --enable-ninja SCRIPT: python x.py dist - MINGW_URL: https://s3.amazonaws.com/rust-lang-ci - MINGW_ARCHIVE: i686-4.9.2-release-win32-dwarf-rt_v4-rev4.7z + MINGW_URL: https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror + MINGW_ARCHIVE: i686-6.3.0-release-win32-dwarf-rt_v5-rev1.7z MINGW_DIR: mingw32 DEPLOY: 1 - MSYS_BITS: 64 SCRIPT: python x.py dist RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu --enable-extended --enable-ninja - MINGW_URL: https://s3.amazonaws.com/rust-lang-ci - MINGW_ARCHIVE: x86_64-4.9.2-release-win32-seh-rt_v4-rev4.7z + MINGW_URL: https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror + MINGW_ARCHIVE: x86_64-6.3.0-release-win32-seh-rt_v5-rev1.7z MINGW_DIR: mingw64 DEPLOY: 1 diff --git a/src/test/run-pass/issue-16671.rs b/src/test/run-pass/issue-16671.rs index 2be04551cb9..71a19d98190 100644 --- a/src/test/run-pass/issue-16671.rs +++ b/src/test/run-pass/issue-16671.rs @@ -8,26 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// DON'T REENABLE THIS UNLESS YOU'VE ACTUALLY FIXED THE UNDERLYING ISSUE -// ignore-android seems to block forever +#![deny(warnings)] -// ignore-emscripten no threads support +fn foo(_f: F) { } -#![forbid(warnings)] - -// Pretty printing tests complain about `use std::predule::*` -#![allow(unused_imports)] - -// A var moved into a proc, that has a mutable loan path should -// not trigger a misleading unused_mut warning. - -use std::io::prelude::*; -use std::thread; - -pub fn main() { - let mut stdin = std::io::stdin(); - thread::spawn(move|| { - let mut v = Vec::new(); - let _ = stdin.read_to_end(&mut v); - }).join().ok().unwrap(); +fn main() { + let mut var = Vec::new();; + foo(move|| { + var.push(1); + }); } diff --git a/src/tools/compiletest/src/procsrv.rs b/src/tools/compiletest/src/procsrv.rs index 7e4f40af9ce..f55667f93c0 100644 --- a/src/tools/compiletest/src/procsrv.rs +++ b/src/tools/compiletest/src/procsrv.rs @@ -57,9 +57,26 @@ pub fn run(lib_path: &str, let mut cmd = Command::new(prog); cmd.args(args) - .stdin(Stdio::piped()) .stdout(Stdio::piped()) .stderr(Stdio::piped()); + + // Why oh why do we sometimes make a pipe and sometimes inherit the stdin + // stream, well that's an excellent question! In theory it should suffice to + // always create a pipe here and be done with it. Unfortunately though + // there's apparently something odd with the gdb that comes with gcc 6.3.0 + // on MinGW. Tracked at rust-lang/rust#40184 when stdin is piped here + // (unconditionally) then all gdb tests will fail on MinGW when using gcc + // 6.3.0. WHen using an inherited stdin though they happen to all work! + // + // As to why this fixes the issue, well, I have no idea. If you can remove + // this branch and unconditionally use `piped` and it gets past @bors please + // feel free to send a PR! + if input.is_some() || !cfg!(windows) { + cmd.stdin(Stdio::piped()); + } else { + cmd.stdin(Stdio::inherit()); + } + add_target_env(&mut cmd, lib_path, aux_path); for (key, val) in env { cmd.env(&key, &val); -- cgit 1.4.1-3-g733a5 From 64e9af47f4e517208fc1dd950340a0c046ad87b5 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Sat, 11 Mar 2017 10:58:19 +0000 Subject: Allow declarative macros 2.0 and `use` macro imports to shadow builtin macros. --- src/librustc_resolve/lib.rs | 36 ++++---- src/librustc_resolve/macros.rs | 102 +++++++++++++-------- src/librustc_resolve/resolve_imports.rs | 12 ++- .../compile-fail/imports/shadow_builtin_macros.rs | 72 +++++++++++++++ 4 files changed, 163 insertions(+), 59 deletions(-) create mode 100644 src/test/compile-fail/imports/shadow_builtin_macros.rs (limited to 'src/test') diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index f832e0f9a48..be8513c94d0 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -75,7 +75,7 @@ use std::mem::replace; use std::rc::Rc; use resolve_imports::{ImportDirective, ImportDirectiveSubclass, NameResolution, ImportResolver}; -use macros::{InvocationData, LegacyBinding, LegacyScope}; +use macros::{InvocationData, LegacyBinding, LegacyScope, MacroBinding}; // NB: This module needs to be declared first so diagnostics are // registered before they are used. @@ -2566,6 +2566,7 @@ impl<'a> Resolver<'a> { self.resolve_ident_in_module(module, ident, ns, false, record_used) } else if opt_ns == Some(MacroNS) { self.resolve_lexical_macro_path_segment(ident, ns, record_used) + .map(MacroBinding::binding) } else { match self.resolve_ident_in_lexical_scope(ident, ns, record_used) { Some(LexicalScopeBinding::Item(binding)) => Ok(binding), @@ -3223,7 +3224,7 @@ impl<'a> Resolver<'a> { }; let msg1 = format!("`{}` could refer to the name {} here", name, participle(b1)); let msg2 = format!("`{}` could also refer to the name {} here", name, participle(b2)); - let note = if !lexical && b1.is_glob_import() { + let note = if b1.expansion == Mark::root() || !lexical && b1.is_glob_import() { format!("consider adding an explicit import of `{}` to disambiguate", name) } else if let Def::Macro(..) = b1.def() { format!("macro-expanded {} do not shadow", @@ -3243,11 +3244,15 @@ impl<'a> Resolver<'a> { let msg = format!("`{}` is ambiguous", name); self.session.add_lint(lint::builtin::LEGACY_IMPORTS, id, span, msg); } else { - self.session.struct_span_err(span, &format!("`{}` is ambiguous", name)) - .span_note(b1.span, &msg1) - .span_note(b2.span, &msg2) - .note(¬e) - .emit(); + let mut err = + self.session.struct_span_err(span, &format!("`{}` is ambiguous", name)); + err.span_note(b1.span, &msg1); + match b2.def() { + Def::Macro(..) if b2.span == DUMMY_SP => + err.note(&format!("`{}` is also a builtin macro", name)), + _ => err.span_note(b2.span, &msg2), + }; + err.note(¬e).emit(); } } @@ -3361,14 +3366,13 @@ impl<'a> Resolver<'a> { if self.proc_macro_enabled { return; } for attr in attrs { - let name = unwrap_or!(attr.name(), continue); - let maybe_binding = self.builtin_macros.get(&name).cloned().or_else(|| { - let ident = Ident::with_empty_ctxt(name); - self.resolve_lexical_macro_path_segment(ident, MacroNS, None).ok() - }); - - if let Some(binding) = maybe_binding { - if let SyntaxExtension::AttrProcMacro(..) = *binding.get_macro(self) { + if attr.path.segments.len() > 1 { + continue + } + let ident = attr.path.segments[0].identifier; + let result = self.resolve_lexical_macro_path_segment(ident, MacroNS, None); + if let Ok(binding) = result { + if let SyntaxExtension::AttrProcMacro(..) = *binding.binding().get_macro(self) { attr::mark_known(attr); let msg = "attribute procedural macros are experimental"; @@ -3376,7 +3380,7 @@ impl<'a> Resolver<'a> { feature_err(&self.session.parse_sess, feature, attr.span, GateIssue::Language, msg) - .span_note(binding.span, "procedural macro imported here") + .span_note(binding.span(), "procedural macro imported here") .emit(); } } diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 99fc1c142f6..9af921a8445 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -81,11 +81,29 @@ pub struct LegacyBinding<'a> { pub span: Span, } +#[derive(Copy, Clone)] pub enum MacroBinding<'a> { Legacy(&'a LegacyBinding<'a>), + Builtin(&'a NameBinding<'a>), Modern(&'a NameBinding<'a>), } +impl<'a> MacroBinding<'a> { + pub fn span(self) -> Span { + match self { + MacroBinding::Legacy(binding) => binding.span, + MacroBinding::Builtin(binding) | MacroBinding::Modern(binding) => binding.span, + } + } + + pub fn binding(self) -> &'a NameBinding<'a> { + match self { + MacroBinding::Builtin(binding) | MacroBinding::Modern(binding) => binding, + MacroBinding::Legacy(_) => panic!("unexpected MacroBinding::Legacy"), + } + } +} + impl<'a> base::Resolver for Resolver<'a> { fn next_node_id(&mut self) -> ast::NodeId { self.session.next_node_id() @@ -378,18 +396,18 @@ impl<'a> Resolver<'a> { } let name = path[0].name; - let result = match self.resolve_legacy_scope(&invocation.legacy_scope, name, false) { - Some(MacroBinding::Legacy(binding)) => Ok(Def::Macro(binding.def_id, MacroKind::Bang)), - Some(MacroBinding::Modern(binding)) => Ok(binding.def_ignoring_ambiguity()), - None => match self.resolve_lexical_macro_path_segment(path[0], MacroNS, None) { - Ok(binding) => Ok(binding.def_ignoring_ambiguity()), - Err(Determinacy::Undetermined) if !force => - return Err(Determinacy::Undetermined), + let legacy_resolution = self.resolve_legacy_scope(&invocation.legacy_scope, name, false); + let result = if let Some(MacroBinding::Legacy(binding)) = legacy_resolution { + Ok(Def::Macro(binding.def_id, MacroKind::Bang)) + } else { + match self.resolve_lexical_macro_path_segment(path[0], MacroNS, None) { + Ok(binding) => Ok(binding.binding().def_ignoring_ambiguity()), + Err(Determinacy::Undetermined) if !force => return Err(Determinacy::Undetermined), Err(_) => { self.found_unresolved_macro = true; Err(Determinacy::Determined) } - }, + } }; self.current_module.legacy_macro_resolutions.borrow_mut() @@ -403,42 +421,56 @@ impl<'a> Resolver<'a> { ident: Ident, ns: Namespace, record_used: Option) - -> Result<&'a NameBinding<'a>, Determinacy> { - let mut module = self.current_module; - let mut potential_expanded_shadower: Option<&NameBinding> = None; + -> Result, Determinacy> { + let mut module = Some(self.current_module); + let mut potential_illegal_shadower = Err(Determinacy::Determined); + let determinacy = + if record_used.is_some() { Determinacy::Determined } else { Determinacy::Undetermined }; loop { - // Since expanded macros may not shadow the lexical scope (enforced below), - // we can ignore unresolved invocations (indicated by the penultimate argument). - match self.resolve_ident_in_module(module, ident, ns, true, record_used) { + let result = if let Some(module) = module { + // Since expanded macros may not shadow the lexical scope and + // globs may not shadow builtin macros (both enforced below), + // we resolve with restricted shadowing (indicated by the penultimate argument). + self.resolve_ident_in_module(module, ident, ns, true, record_used) + .map(MacroBinding::Modern) + } else { + self.builtin_macros.get(&ident.name).cloned().ok_or(determinacy) + .map(MacroBinding::Builtin) + }; + + match result.map(MacroBinding::binding) { Ok(binding) => { let span = match record_used { Some(span) => span, - None => return Ok(binding), + None => return result, }; - match potential_expanded_shadower { - Some(shadower) if shadower.def() != binding.def() => { + if let Ok(MacroBinding::Modern(shadower)) = potential_illegal_shadower { + if shadower.def() != binding.def() { let name = ident.name; self.ambiguity_errors.push(AmbiguityError { span: span, name: name, b1: shadower, b2: binding, lexical: true, legacy: false, }); - return Ok(shadower); + return potential_illegal_shadower; } - _ if binding.expansion == Mark::root() => return Ok(binding), - _ => potential_expanded_shadower = Some(binding), + } + if binding.expansion != Mark::root() || + (binding.is_glob_import() && module.unwrap().def().is_some()) { + potential_illegal_shadower = result; + } else { + return result; } }, Err(Determinacy::Undetermined) => return Err(Determinacy::Undetermined), Err(Determinacy::Determined) => {} } - match module.kind { - ModuleKind::Block(..) => module = module.parent.unwrap(), - ModuleKind::Def(..) => return match potential_expanded_shadower { - Some(binding) => Ok(binding), - None if record_used.is_some() => Err(Determinacy::Determined), - None => Err(Determinacy::Undetermined), + module = match module { + Some(module) => match module.kind { + ModuleKind::Block(..) => module.parent, + ModuleKind::Def(..) => None, }, + None => return potential_illegal_shadower, } } } @@ -492,7 +524,7 @@ impl<'a> Resolver<'a> { if !self.use_extern_macros { self.record_use(Ident::with_empty_ctxt(name), MacroNS, binding, DUMMY_SP); } - MacroBinding::Modern(binding) + MacroBinding::Builtin(binding) } else { return None; }; @@ -524,21 +556,15 @@ impl<'a> Resolver<'a> { let legacy_resolution = self.resolve_legacy_scope(legacy_scope, ident.name, true); let resolution = self.resolve_lexical_macro_path_segment(ident, MacroNS, Some(span)); match (legacy_resolution, resolution) { - (Some(legacy_resolution), Ok(resolution)) => { - let (legacy_span, participle) = match legacy_resolution { - MacroBinding::Modern(binding) - if binding.def() == resolution.def() => continue, - MacroBinding::Modern(binding) => (binding.span, "imported"), - MacroBinding::Legacy(binding) => (binding.span, "defined"), - }; - let msg1 = format!("`{}` could refer to the macro {} here", ident, participle); + (Some(MacroBinding::Legacy(legacy_binding)), Ok(MacroBinding::Modern(binding))) => { + let msg1 = format!("`{}` could refer to the macro defined here", ident); let msg2 = format!("`{}` could also refer to the macro imported here", ident); self.session.struct_span_err(span, &format!("`{}` is ambiguous", ident)) - .span_note(legacy_span, &msg1) - .span_note(resolution.span, &msg2) + .span_note(legacy_binding.span, &msg1) + .span_note(binding.span, &msg2) .emit(); }, - (Some(MacroBinding::Modern(binding)), Err(_)) => { + (Some(MacroBinding::Builtin(binding)), Ok(MacroBinding::Builtin(_))) => { self.record_use(ident, MacroNS, binding, span); self.err_if_macro_use_proc_macro(ident.name, span, binding); }, diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index 2f4ac12cd73..43654c8ce6f 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -145,7 +145,7 @@ impl<'a> Resolver<'a> { module: Module<'a>, ident: Ident, ns: Namespace, - ignore_unresolved_invocations: bool, + restricted_shadowing: bool, record_used: Option) -> Result<&'a NameBinding<'a>, Determinacy> { self.populate_module_if_necessary(module); @@ -158,9 +158,8 @@ impl<'a> Resolver<'a> { if let Some(binding) = resolution.binding { if let Some(shadowed_glob) = resolution.shadows_glob { let name = ident.name; - // If we ignore unresolved invocations, we must forbid - // expanded shadowing to avoid time travel. - if ignore_unresolved_invocations && + // Forbid expanded shadowing to avoid time travel. + if restricted_shadowing && binding.expansion != Mark::root() && ns != MacroNS && // In MacroNS, `try_define` always forbids this shadowing binding.def() != shadowed_glob.def() { @@ -215,7 +214,7 @@ impl<'a> Resolver<'a> { } let no_unresolved_invocations = - ignore_unresolved_invocations || module.unresolved_invocations.borrow().is_empty(); + restricted_shadowing || module.unresolved_invocations.borrow().is_empty(); match resolution.binding { // In `MacroNS`, expanded bindings do not shadow (enforced in `try_define`). Some(binding) if no_unresolved_invocations || ns == MacroNS => @@ -225,6 +224,9 @@ impl<'a> Resolver<'a> { } // Check if the globs are determined + if restricted_shadowing && module.def().is_some() { + return Err(Determined); + } for directive in module.globs.borrow().iter() { if self.is_accessible(directive.vis.get()) { if let Some(module) = directive.imported_module.get() { diff --git a/src/test/compile-fail/imports/shadow_builtin_macros.rs b/src/test/compile-fail/imports/shadow_builtin_macros.rs new file mode 100644 index 00000000000..2b3ba1b4aa7 --- /dev/null +++ b/src/test/compile-fail/imports/shadow_builtin_macros.rs @@ -0,0 +1,72 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:two_macros.rs + +#![feature(use_extern_macros)] + +mod foo { + extern crate two_macros; + pub use self::two_macros::m as panic; +} + +mod m1 { + use foo::panic; // ok + fn f() { panic!(); } +} + +mod m2 { + use foo::*; //~ NOTE `panic` could refer to the name imported here + fn f() { panic!(); } //~ ERROR ambiguous + //~| NOTE `panic` is also a builtin macro + //~| NOTE consider adding an explicit import of `panic` to disambiguate +} + +mod m3 { + ::two_macros::m!(use foo::panic;); //~ NOTE `panic` could refer to the name imported here + //~| NOTE in this expansion + fn f() { panic!(); } //~ ERROR ambiguous + //~| NOTE `panic` is also a builtin macro + //~| NOTE macro-expanded macro imports do not shadow +} + +mod m4 { + macro_rules! panic { () => {} } // ok + panic!(); +} + +mod m5 { + macro_rules! m { () => { + macro_rules! panic { () => {} } //~ ERROR `panic` is already in scope + //~| NOTE macro-expanded `macro_rules!`s may not shadow existing macros + } } + m!(); //~ NOTE in this expansion + //~| NOTE in this expansion + panic!(); +} + +#[macro_use(n)] //~ NOTE `n` could also refer to the name imported here +extern crate two_macros; +mod bar { + pub use two_macros::m as n; +} + +mod m6 { + use bar::n; // ok + n!(); +} + +mod m7 { + use bar::*; //~ NOTE `n` could refer to the name imported here + n!(); //~ ERROR ambiguous + //~| NOTE consider adding an explicit import of `n` to disambiguate +} + +fn main() {} -- cgit 1.4.1-3-g733a5 From e7949d0013bb8b45c884b173ca22c20e6899d612 Mon Sep 17 00:00:00 2001 From: Adam Ransom Date: Tue, 21 Mar 2017 21:38:32 +0900 Subject: Warn when using a `'static` lifetime bound Previously a `'static` lifetime bound would result in an `undeclared lifetime` error when compiling, even though it could be considered valid. However, it is unnecessary to use it as a lifetime bound so we present the user with a warning instead and suggest using the `'static` lifetime directly, in place of the lifetime parameter. --- src/librustc/middle/resolve_lifetime.rs | 14 ++++++++++++-- src/test/compile-fail/static-lifetime-bound.rs | 16 ++++++++++++++++ 2 files changed, 28 insertions(+), 2 deletions(-) create mode 100644 src/test/compile-fail/static-lifetime-bound.rs (limited to 'src/test') diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index 10ee760a6a6..5094e28475b 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -29,7 +29,7 @@ use syntax::ast; use syntax::attr; use syntax::ptr::P; use syntax::symbol::keywords; -use syntax_pos::Span; +use syntax_pos::{mk_sp, Span}; use errors::DiagnosticBuilder; use util::nodemap::{NodeMap, NodeSet, FxHashSet, FxHashMap, DefIdMap}; use rustc_back::slice; @@ -1464,7 +1464,17 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { self.check_lifetime_def_for_shadowing(old_scope, &lifetime_i.lifetime); for bound in &lifetime_i.bounds { - self.resolve_lifetime_ref(bound); + if !bound.is_static() { + self.resolve_lifetime_ref(bound); + } else { + self.insert_lifetime(bound, Region::Static); + let full_span = mk_sp(lifetime_i.lifetime.span.lo, bound.span.hi); + self.sess.struct_span_warn(full_span, + &format!("unnecessary lifetime parameter `{}`", lifetime_i.lifetime.name)) + .help(&format!("you can use the `'static` lifetime directly, in place \ + of `{}`", lifetime_i.lifetime.name)) + .emit(); + } } } } diff --git a/src/test/compile-fail/static-lifetime-bound.rs b/src/test/compile-fail/static-lifetime-bound.rs new file mode 100644 index 00000000000..38534ab0a36 --- /dev/null +++ b/src/test/compile-fail/static-lifetime-bound.rs @@ -0,0 +1,16 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn f<'a: 'static>(_: &'a i32) {} //~WARN unnecessary lifetime parameter `'a` + +fn main() { + let x = 0; + f(&x); //~ERROR does not live long enough +} -- cgit 1.4.1-3-g733a5 From 29a052d2d807dcb9f1d45878a3083af7a993263d Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Sat, 25 Mar 2017 04:04:13 +0000 Subject: Fix ICE with nested macros in certain situations. --- src/libsyntax/ext/placeholders.rs | 2 +- src/test/run-pass/issue-40770.rs | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 src/test/run-pass/issue-40770.rs (limited to 'src/test') diff --git a/src/libsyntax/ext/placeholders.rs b/src/libsyntax/ext/placeholders.rs index f0e328a551d..2d0994a7b78 100644 --- a/src/libsyntax/ext/placeholders.rs +++ b/src/libsyntax/ext/placeholders.rs @@ -106,8 +106,8 @@ impl<'a, 'b> PlaceholderExpander<'a, 'b> { impl<'a, 'b> Folder for PlaceholderExpander<'a, 'b> { fn fold_item(&mut self, item: P) -> SmallVector> { match item.node { - ast::ItemKind::Mac(ref mac) if !mac.node.path.segments.is_empty() => {} ast::ItemKind::Mac(_) => return self.remove(item.id).make_items(), + ast::ItemKind::MacroDef(_) => return SmallVector::one(item), _ => {} } diff --git a/src/test/run-pass/issue-40770.rs b/src/test/run-pass/issue-40770.rs new file mode 100644 index 00000000000..599d0b273e3 --- /dev/null +++ b/src/test/run-pass/issue-40770.rs @@ -0,0 +1,19 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +macro_rules! m { + ($e:expr) => { + macro_rules! n { () => { $e } } + } +} + +fn main() { + m!(foo!()); +} -- cgit 1.4.1-3-g733a5 From 6341a8b0e5155abf4bf338d3df7f6d2971f83adb Mon Sep 17 00:00:00 2001 From: Esteban Küber Date: Fri, 24 Mar 2017 23:40:24 -0700 Subject: Clarify suggetion for field used as method Instead of ``` error: no method named `src_addr` found for type `&wire::ipv4::Repr` in the current scope --> src/wire/ipv4.rs:409:34 | 409 | packet.set_src_addr(self.src_addr()); | ^^^^^^^^ | note: did you mean to write `self.src_addr`? --> src/wire/ipv4.rs:409:34 | 409 | packet.set_src_addr(self.src_addr()); | ^^^^^^^^ ``` present ``` error: no method named `src_addr` found for type `&wire::ipv4::Repr` in the current scope --> src/wire/ipv4.rs:409:34 | 409 | packet.set_src_addr(self.src_addr()); | ^^^^^^^^ `src_addr` is a field, not a method | = help: did you mean to write `self.src_addr` instead of `self.src_addr(...)`? ``` --- src/librustc_typeck/check/method/suggest.rs | 26 +++++++++++-------- src/test/compile-fail/issue-18343.rs | 6 +++-- src/test/compile-fail/issue-2392.rs | 39 +++++++++++++++++++---------- src/test/compile-fail/issue-32128.rs | 6 +++-- src/test/compile-fail/issue-33784.rs | 9 ++++--- 5 files changed, 56 insertions(+), 30 deletions(-) (limited to 'src/test') diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index 6ce50d91124..b458c1af71d 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -197,17 +197,23 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let field_ty = field.ty(tcx, substs); if self.is_fn_ty(&field_ty, span) { - err.span_note(span, - &format!("use `({0}.{1})(...)` if you \ - meant to call the function \ - stored in the `{1}` field", - expr_string, - item_name)); + err.help(&format!("use `({0}.{1})(...)` if you \ + meant to call the function \ + stored in the `{1}` field", + expr_string, + item_name)); + err.span_label(span, + &format!("`{}` is a field storing a \ + function, not a method", + item_name)); } else { - err.span_note(span, - &format!("did you mean to write `{0}.{1}`?", - expr_string, - item_name)); + err.help(&format!("did you mean to write `{0}.{1}` \ + instead of `{0}.{1}(...)`?", + expr_string, + item_name)); + err.span_label(span, + &format!("`{}` is a field, not a method", + item_name)); } break; } diff --git a/src/test/compile-fail/issue-18343.rs b/src/test/compile-fail/issue-18343.rs index 4601db9dba0..a095bb48126 100644 --- a/src/test/compile-fail/issue-18343.rs +++ b/src/test/compile-fail/issue-18343.rs @@ -14,6 +14,8 @@ struct Obj where F: FnMut() -> u32 { fn main() { let o = Obj { closure: || 42 }; - o.closure(); //~ ERROR no method named `closure` found - //~^ NOTE use `(o.closure)(...)` if you meant to call the function stored in the `closure` field + o.closure(); + //~^ ERROR no method named `closure` found + //~| HELP use `(o.closure)(...)` if you meant to call the function stored in the `closure` field + //~| NOTE `closure` is a field storing a function, not a method } diff --git a/src/test/compile-fail/issue-2392.rs b/src/test/compile-fail/issue-2392.rs index 805725dd749..12389f88536 100644 --- a/src/test/compile-fail/issue-2392.rs +++ b/src/test/compile-fail/issue-2392.rs @@ -48,45 +48,58 @@ fn main() { let o_closure = Obj { closure: || 42, not_closure: 42 }; o_closure.closure(); //~ ERROR no method named `closure` found - //~^ NOTE use `(o_closure.closure)(...)` if you meant to call the function stored + //~^ HELP use `(o_closure.closure)(...)` if you meant to call the function stored + //~| NOTE `closure` is a field storing a function, not a method - o_closure.not_closure(); //~ ERROR no method named `not_closure` found - //~^ NOTE did you mean to write `o_closure.not_closure`? + o_closure.not_closure(); + //~^ ERROR no method named `not_closure` found + //~| NOTE `not_closure` is a field, not a method + //~| HELP did you mean to write `o_closure.not_closure` instead of `o_closure.not_closure(...)`? let o_func = Obj { closure: func, not_closure: 5 }; o_func.closure(); //~ ERROR no method named `closure` found - //~^ NOTE use `(o_func.closure)(...)` if you meant to call the function stored + //~^ HELP use `(o_func.closure)(...)` if you meant to call the function stored + //~| NOTE `closure` is a field storing a function, not a method let boxed_fn = BoxedObj { boxed_closure: Box::new(func) }; boxed_fn.boxed_closure();//~ ERROR no method named `boxed_closure` found - //~^ NOTE use `(boxed_fn.boxed_closure)(...)` if you meant to call the function stored + //~^ HELP use `(boxed_fn.boxed_closure)(...)` if you meant to call the function stored + //~| NOTE `boxed_closure` is a field storing a function, not a method let boxed_closure = BoxedObj { boxed_closure: Box::new(|| 42_u32) as Box u32> }; boxed_closure.boxed_closure();//~ ERROR no method named `boxed_closure` found - //~^ NOTE use `(boxed_closure.boxed_closure)(...)` if you meant to call the function stored + //~^ HELP use `(boxed_closure.boxed_closure)(...)` if you meant to call the function stored + //~| NOTE `boxed_closure` is a field storing a function, not a method // test expression writing in the notes let w = Wrapper { wrap: o_func }; w.wrap.closure();//~ ERROR no method named `closure` found - //~^ NOTE use `(w.wrap.closure)(...)` if you meant to call the function stored + //~^ HELP use `(w.wrap.closure)(...)` if you meant to call the function stored + //~| NOTE `closure` is a field storing a function, not a method - w.wrap.not_closure();//~ ERROR no method named `not_closure` found - //~^ NOTE did you mean to write `w.wrap.not_closure`? + w.wrap.not_closure(); + //~^ ERROR no method named `not_closure` found + //~| NOTE `not_closure` is a field, not a method + //~| HELP did you mean to write `w.wrap.not_closure` instead of `w.wrap.not_closure(...)`? check_expression().closure();//~ ERROR no method named `closure` found - //~^ NOTE use `(check_expression().closure)(...)` if you meant to call the function stored + //~^ HELP use `(check_expression().closure)(...)` if you meant to call the function stored + //~| NOTE `closure` is a field storing a function, not a method } impl FuncContainerOuter { fn run(&self) { unsafe { (*self.container).f1(1); //~ ERROR no method named `f1` found - //~^ NOTE use `((*self.container).f1)(...)` + //~^ HELP use `((*self.container).f1)(...)` + //~| NOTE `f1` is a field storing a function, not a method (*self.container).f2(1); //~ ERROR no method named `f2` found - //~^ NOTE use `((*self.container).f2)(...)` + //~^ HELP use `((*self.container).f2)(...)` + //~| NOTE `f2` is a field storing a function, not a method (*self.container).f3(1); //~ ERROR no method named `f3` found - //~^ NOTE use `((*self.container).f3)(...)` + //~^ HELP use `((*self.container).f3)(...)` + //~| NOTE `f3` is a field storing a function, not a method } } } diff --git a/src/test/compile-fail/issue-32128.rs b/src/test/compile-fail/issue-32128.rs index fe7e66a2116..74fbb33296e 100644 --- a/src/test/compile-fail/issue-32128.rs +++ b/src/test/compile-fail/issue-32128.rs @@ -19,7 +19,9 @@ fn main() { }) }; - demo.example(1); //~ ERROR no method named `example` - //~^ NOTE use `(demo.example)(...)` + demo.example(1); + //~^ ERROR no method named `example` + //~| HELP use `(demo.example)(...)` + //~| NOTE `example` is a field storing a function, not a method // (demo.example)(1); } diff --git a/src/test/compile-fail/issue-33784.rs b/src/test/compile-fail/issue-33784.rs index 4229be29473..03c84fc57be 100644 --- a/src/test/compile-fail/issue-33784.rs +++ b/src/test/compile-fail/issue-33784.rs @@ -35,12 +35,15 @@ fn main() { let o = Obj { fn_ptr: empty, closure: || 42 }; let p = &o; p.closure(); //~ ERROR no method named `closure` found - //~^ NOTE use `(p.closure)(...)` if you meant to call the function stored in the `closure` field + //~^ HELP use `(p.closure)(...)` if you meant to call the function stored in the `closure` field + //~| NOTE `closure` is a field storing a function, not a method let q = &p; q.fn_ptr(); //~ ERROR no method named `fn_ptr` found - //~^ NOTE use `(q.fn_ptr)(...)` if you meant to call the function stored in the `fn_ptr` field + //~^ HELP use `(q.fn_ptr)(...)` if you meant to call the function stored in the `fn_ptr` field + //~| NOTE `fn_ptr` is a field storing a function, not a method let r = D(C { c_fn_ptr: empty }); let s = &r; s.c_fn_ptr(); //~ ERROR no method named `c_fn_ptr` found - //~^ NOTE use `(s.c_fn_ptr)(...)` if you meant to call the function stored in the `c_fn_ptr` + //~^ HELP use `(s.c_fn_ptr)(...)` if you meant to call the function stored in the `c_fn_ptr` + //~| NOTE `c_fn_ptr` is a field storing a function, not a method } -- cgit 1.4.1-3-g733a5 From 7e0f7a50ab649fb70773af35e78ca73b5123f52e Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Sun, 26 Mar 2017 14:15:47 +0300 Subject: store a copy of the Issue32230 info within TypeError The data can't be looked up from the region variable directly, because the region variable might have been destroyed at the end of a snapshot. Fixes #40000. Fixes #40743. --- src/librustc/infer/error_reporting/mod.rs | 42 ++++++++++++++----------------- src/librustc/infer/higher_ranked/mod.rs | 18 +++++++++++-- src/librustc/ty/error.rs | 14 +++++------ src/librustc/ty/structural_impls.rs | 10 +++++--- src/test/compile-fail/issue-40000.rs | 21 ++++++++++++++++ 5 files changed, 69 insertions(+), 36 deletions(-) create mode 100644 src/test/compile-fail/issue-40000.rs (limited to 'src/test') diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs index 21139c8dde2..9fa2bc8a2a7 100644 --- a/src/librustc/infer/error_reporting/mod.rs +++ b/src/librustc/infer/error_reporting/mod.rs @@ -426,30 +426,26 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { { debug!("note_issue_32330: terr={:?}", terr); match *terr { - TypeError::RegionsInsufficientlyPolymorphic(_, &Region::ReVar(vid)) | - TypeError::RegionsOverlyPolymorphic(_, &Region::ReVar(vid)) => { - match self.region_vars.var_origin(vid) { - RegionVariableOrigin::EarlyBoundRegion(_, _, Some(Issue32330 { - fn_def_id, - region_name - })) => { - diag.note( - &format!("lifetime parameter `{0}` declared on fn `{1}` \ - appears only in the return type, \ - but here is required to be higher-ranked, \ - which means that `{0}` must appear in both \ - argument and return types", - region_name, - self.tcx.item_path_str(fn_def_id))); - diag.note( - &format!("this error is the result of a recent bug fix; \ - for more information, see issue #33685 \ - ")); - } - _ => { } - } + TypeError::RegionsInsufficientlyPolymorphic(_, _, Some(box Issue32330 { + fn_def_id, region_name + })) | + TypeError::RegionsOverlyPolymorphic(_, _, Some(box Issue32330 { + fn_def_id, region_name + })) => { + diag.note( + &format!("lifetime parameter `{0}` declared on fn `{1}` \ + appears only in the return type, \ + but here is required to be higher-ranked, \ + which means that `{0}` must appear in both \ + argument and return types", + region_name, + self.tcx.item_path_str(fn_def_id))); + diag.note( + &format!("this error is the result of a recent bug fix; \ + for more information, see issue #33685 \ + ")); } - _ => { } + _ => {} } } diff --git a/src/librustc/infer/higher_ranked/mod.rs b/src/librustc/infer/higher_ranked/mod.rs index e919f025409..e3ffc99c0e9 100644 --- a/src/librustc/infer/higher_ranked/mod.rs +++ b/src/librustc/infer/higher_ranked/mod.rs @@ -15,6 +15,7 @@ use super::{CombinedSnapshot, InferCtxt, LateBoundRegion, HigherRankedType, + RegionVariableOrigin, SubregionOrigin, SkolemizationMap}; use super::combine::CombineFields; @@ -656,14 +657,27 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { skol_br, tainted_region); + let issue_32330 = if let &ty::ReVar(vid) = tainted_region { + match self.region_vars.var_origin(vid) { + RegionVariableOrigin::EarlyBoundRegion(_, _, issue_32330) => { + issue_32330.map(Box::new) + } + _ => None + } + } else { + None + }; + if overly_polymorphic { debug!("Overly polymorphic!"); return Err(TypeError::RegionsOverlyPolymorphic(skol_br, - tainted_region)); + tainted_region, + issue_32330)); } else { debug!("Not as polymorphic!"); return Err(TypeError::RegionsInsufficientlyPolymorphic(skol_br, - tainted_region)); + tainted_region, + issue_32330)); } } } diff --git a/src/librustc/ty/error.rs b/src/librustc/ty/error.rs index 5a696446b4b..73d9c8b00ae 100644 --- a/src/librustc/ty/error.rs +++ b/src/librustc/ty/error.rs @@ -39,8 +39,8 @@ pub enum TypeError<'tcx> { RegionsDoesNotOutlive(&'tcx Region, &'tcx Region), RegionsNotSame(&'tcx Region, &'tcx Region), RegionsNoOverlap(&'tcx Region, &'tcx Region), - RegionsInsufficientlyPolymorphic(BoundRegion, &'tcx Region), - RegionsOverlyPolymorphic(BoundRegion, &'tcx Region), + RegionsInsufficientlyPolymorphic(BoundRegion, &'tcx Region, Option>), + RegionsOverlyPolymorphic(BoundRegion, &'tcx Region, Option>), Sorts(ExpectedFound>), IntMismatch(ExpectedFound), FloatMismatch(ExpectedFound), @@ -116,11 +116,11 @@ impl<'tcx> fmt::Display for TypeError<'tcx> { RegionsNoOverlap(..) => { write!(f, "lifetimes do not intersect") } - RegionsInsufficientlyPolymorphic(br, _) => { + RegionsInsufficientlyPolymorphic(br, _, _) => { write!(f, "expected bound lifetime parameter {}, \ found concrete lifetime", br) } - RegionsOverlyPolymorphic(br, _) => { + RegionsOverlyPolymorphic(br, _, _) => { write!(f, "expected concrete lifetime, \ found bound lifetime parameter {}", br) } @@ -253,15 +253,15 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { self.note_and_explain_region(db, "...does not overlap ", region2, ""); } - RegionsInsufficientlyPolymorphic(_, conc_region) => { + RegionsInsufficientlyPolymorphic(_, conc_region, _) => { self.note_and_explain_region(db, "concrete lifetime that was found is ", conc_region, ""); } - RegionsOverlyPolymorphic(_, &ty::ReVar(_)) => { + RegionsOverlyPolymorphic(_, &ty::ReVar(_), _) => { // don't bother to print out the message below for // inference variables, it's not very illuminating. } - RegionsOverlyPolymorphic(_, conc_region) => { + RegionsOverlyPolymorphic(_, conc_region, _) => { self.note_and_explain_region(db, "expected concrete lifetime is ", conc_region, ""); } diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index 49824e8a738..9126600e3f6 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -293,11 +293,13 @@ impl<'a, 'tcx> Lift<'tcx> for ty::error::TypeError<'a> { RegionsNoOverlap(a, b) => { return tcx.lift(&(a, b)).map(|(a, b)| RegionsNoOverlap(a, b)) } - RegionsInsufficientlyPolymorphic(a, b) => { - return tcx.lift(&b).map(|b| RegionsInsufficientlyPolymorphic(a, b)) + RegionsInsufficientlyPolymorphic(a, b, ref c) => { + let c = c.clone(); + return tcx.lift(&b).map(|b| RegionsInsufficientlyPolymorphic(a, b, c)) } - RegionsOverlyPolymorphic(a, b) => { - return tcx.lift(&b).map(|b| RegionsOverlyPolymorphic(a, b)) + RegionsOverlyPolymorphic(a, b, ref c) => { + let c = c.clone(); + return tcx.lift(&b).map(|b| RegionsOverlyPolymorphic(a, b, c)) } IntMismatch(x) => IntMismatch(x), FloatMismatch(x) => FloatMismatch(x), diff --git a/src/test/compile-fail/issue-40000.rs b/src/test/compile-fail/issue-40000.rs new file mode 100644 index 00000000000..9be114ebcb6 --- /dev/null +++ b/src/test/compile-fail/issue-40000.rs @@ -0,0 +1,21 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(closure_to_fn_coercion)] + +fn main() { + let bar: fn(&mut u32) = |_| {}; //~ ERROR mismatched types + //~| expected concrete lifetime, found bound lifetime parameter + + fn foo(x: Box) {} + let bar = Box::new(|x: &i32| {}) as Box; + foo(bar); //~ ERROR mismatched types + //~| expected concrete lifetime, found bound lifetime parameter +} -- cgit 1.4.1-3-g733a5 From 50728e52455804143e5cc601004381e395a1e2f7 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Sun, 26 Mar 2017 19:35:46 +0300 Subject: borrowck: consolidate `mut` suggestions This converts all of borrowck's `mut` suggestions to a new `mc::ImmutabilityBlame` API instead of the current mix of various hacks. Fixes #35937. Fixes #40823. --- src/librustc/middle/mem_categorization.rs | 140 ++++++-------- src/librustc_borrowck/borrowck/gather_loans/mod.rs | 9 - src/librustc_borrowck/borrowck/mod.rs | 208 ++++++++++++--------- src/librustc_borrowck/diagnostics.rs | 6 +- src/test/compile-fail/augmented-assignments.rs | 2 +- .../compile-fail/borrowck/borrowck-issue-14498.rs | 6 +- src/test/compile-fail/issue-33819.rs | 2 +- src/test/compile-fail/mut-suggestion.rs | 4 +- .../codemap_tests/huge_multispan_highlight.stderr | 2 +- src/test/ui/did_you_mean/issue-31424.stderr | 2 + src/test/ui/did_you_mean/issue-35937.rs | 31 +++ src/test/ui/did_you_mean/issue-35937.stderr | 26 +++ src/test/ui/did_you_mean/issue-38147-2.stderr | 2 +- src/test/ui/did_you_mean/issue-38147-3.stderr | 4 +- src/test/ui/did_you_mean/issue-39544.rs | 11 +- src/test/ui/did_you_mean/issue-39544.stderr | 19 +- src/test/ui/did_you_mean/issue-40823.rs | 14 ++ src/test/ui/did_you_mean/issue-40823.stderr | 8 + ...orrowck-borrow-overloaded-auto-deref-mut.stderr | 8 +- .../borrowck-borrow-overloaded-deref-mut.stderr | 4 +- src/test/ui/span/borrowck-object-mutability.stderr | 3 + 21 files changed, 304 insertions(+), 207 deletions(-) create mode 100644 src/test/ui/did_you_mean/issue-35937.rs create mode 100644 src/test/ui/did_you_mean/issue-35937.stderr create mode 100644 src/test/ui/did_you_mean/issue-40823.rs create mode 100644 src/test/ui/did_you_mean/issue-40823.stderr (limited to 'src/test') diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 0cf53826dd4..3b52e85e08e 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -194,76 +194,75 @@ pub struct cmt_<'tcx> { pub type cmt<'tcx> = Rc>; +pub enum ImmutabilityBlame<'tcx> { + ImmLocal(ast::NodeId), + ClosureEnv(ast::NodeId), + LocalDeref(ast::NodeId), + AdtFieldDeref(&'tcx ty::AdtDef, &'tcx ty::FieldDef) +} + impl<'tcx> cmt_<'tcx> { - pub fn get_def(&self) -> Option { - match self.cat { - Categorization::Deref(ref cmt, ..) | - Categorization::Interior(ref cmt, _) | - Categorization::Downcast(ref cmt, _) => { - if let Categorization::Local(nid) = cmt.cat { - Some(nid) - } else { - None - } + fn resolve_field(&self, field_name: FieldName) -> (&'tcx ty::AdtDef, &'tcx ty::FieldDef) + { + let adt_def = self.ty.ty_adt_def().unwrap_or_else(|| { + bug!("interior cmt {:?} is not an ADT", self) + }); + let variant_def = match self.cat { + Categorization::Downcast(_, variant_did) => { + adt_def.variant_with_id(variant_did) } - _ => None - } + _ => { + assert!(adt_def.is_univariant()); + &adt_def.variants[0] + } + }; + let field_def = match field_name { + NamedField(name) => variant_def.field_named(name), + PositionalField(idx) => &variant_def.fields[idx] + }; + (adt_def, field_def) } - pub fn get_field(&self, name: ast::Name) -> Option { + pub fn immutability_blame(&self) -> Option> { match self.cat { - Categorization::Deref(ref cmt, ..) | - Categorization::Interior(ref cmt, _) | - Categorization::Downcast(ref cmt, _) => { - if let Categorization::Local(_) = cmt.cat { - if let ty::TyAdt(def, _) = self.ty.sty { - if def.is_struct() { - return def.struct_variant().find_field_named(name).map(|x| x.did); + Categorization::Deref(ref base_cmt, _, BorrowedPtr(ty::ImmBorrow, _)) | + Categorization::Deref(ref base_cmt, _, Implicit(ty::ImmBorrow, _)) => { + // try to figure out where the immutable reference came from + match base_cmt.cat { + Categorization::Local(node_id) => + Some(ImmutabilityBlame::LocalDeref(node_id)), + Categorization::Interior(ref base_cmt, InteriorField(field_name)) => { + let (adt_def, field_def) = base_cmt.resolve_field(field_name); + Some(ImmutabilityBlame::AdtFieldDeref(adt_def, field_def)) + } + Categorization::Upvar(Upvar { id, .. }) => { + if let NoteClosureEnv(..) = self.note { + Some(ImmutabilityBlame::ClosureEnv(id.closure_expr_id)) + } else { + None } } - None - } else { - cmt.get_field(name) + _ => None } } - _ => None - } - } - - pub fn get_field_name(&self) -> Option { - match self.cat { - Categorization::Interior(_, ref ik) => { - if let InteriorKind::InteriorField(FieldName::NamedField(name)) = *ik { - Some(name) - } else { - None - } + Categorization::Local(node_id) => { + Some(ImmutabilityBlame::ImmLocal(node_id)) } - Categorization::Deref(ref cmt, ..) | - Categorization::Downcast(ref cmt, _) => { - cmt.get_field_name() + Categorization::Rvalue(..) | + Categorization::Upvar(..) | + Categorization::Deref(.., UnsafePtr(..)) => { + // This should not be reachable up to inference limitations. + None } - _ => None, - } - } - - pub fn get_arg_if_immutable(&self, map: &hir_map::Map) -> Option { - match self.cat { - Categorization::Deref(ref cmt, ..) | - Categorization::Interior(ref cmt, _) | - Categorization::Downcast(ref cmt, _) => { - if let Categorization::Local(nid) = cmt.cat { - if let ty::TyAdt(_, _) = self.ty.sty { - if let ty::TyRef(_, ty::TypeAndMut{mutbl: MutImmutable, ..}) = cmt.ty.sty { - return Some(nid); - } - } - None - } else { - cmt.get_arg_if_immutable(map) - } + Categorization::Interior(ref base_cmt, _) | + Categorization::Downcast(ref base_cmt, _) | + Categorization::Deref(ref base_cmt, _, _) => { + base_cmt.immutability_blame() + } + Categorization::StaticItem => { + // Do we want to do something here? + None } - _ => None } } } @@ -1282,9 +1281,6 @@ pub enum Aliasability { #[derive(Copy, Clone, Debug)] pub enum AliasableReason { AliasableBorrowed, - AliasableClosure(ast::NodeId), // Aliasable due to capture Fn closure env - AliasableOther, - UnaliasableImmutable, // Created as needed upon seeing ImmutableUnique AliasableStatic, AliasableStaticMut, } @@ -1324,23 +1320,13 @@ impl<'tcx> cmt_<'tcx> { Categorization::Deref(ref b, _, Implicit(ty::MutBorrow, _)) | Categorization::Deref(ref b, _, BorrowedPtr(ty::UniqueImmBorrow, _)) | Categorization::Deref(ref b, _, Implicit(ty::UniqueImmBorrow, _)) | + Categorization::Deref(ref b, _, Unique) | Categorization::Downcast(ref b, _) | Categorization::Interior(ref b, _) => { // Aliasability depends on base cmt b.freely_aliasable() } - Categorization::Deref(ref b, _, Unique) => { - let sub = b.freely_aliasable(); - if b.mutbl.is_mutable() { - // Aliasability depends on base cmt alone - sub - } else { - // Do not allow mutation through an immutable box. - ImmutableUnique(Box::new(sub)) - } - } - Categorization::Rvalue(..) | Categorization::Local(..) | Categorization::Upvar(..) | @@ -1356,13 +1342,9 @@ impl<'tcx> cmt_<'tcx> { } } - Categorization::Deref(ref base, _, BorrowedPtr(ty::ImmBorrow, _)) | - Categorization::Deref(ref base, _, Implicit(ty::ImmBorrow, _)) => { - match base.cat { - Categorization::Upvar(Upvar{ id, .. }) => - FreelyAliasable(AliasableClosure(id.closure_expr_id)), - _ => FreelyAliasable(AliasableBorrowed) - } + Categorization::Deref(_, _, BorrowedPtr(ty::ImmBorrow, _)) | + Categorization::Deref(_, _, Implicit(ty::ImmBorrow, _)) => { + FreelyAliasable(AliasableBorrowed) } } } diff --git a/src/librustc_borrowck/borrowck/gather_loans/mod.rs b/src/librustc_borrowck/borrowck/gather_loans/mod.rs index 28b6c7a13f1..cedb9e1cd1c 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/mod.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/mod.rs @@ -188,14 +188,6 @@ fn check_aliasability<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, // user knows what they're doing in these cases. Ok(()) } - (mc::Aliasability::ImmutableUnique(_), ty::MutBorrow) => { - bccx.report_aliasability_violation( - borrow_span, - loan_cause, - mc::AliasableReason::UnaliasableImmutable, - cmt); - Err(()) - } (mc::Aliasability::FreelyAliasable(alias_cause), ty::UniqueImmBorrow) | (mc::Aliasability::FreelyAliasable(alias_cause), ty::MutBorrow) => { bccx.report_aliasability_violation( @@ -510,4 +502,3 @@ impl<'a, 'tcx> GatherLoanCtxt<'a, 'tcx> { self.move_error_collector.report_potential_errors(self.bccx); } } - diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index 20d495976b0..0981369ace5 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -34,6 +34,7 @@ use rustc::hir::def_id::DefId; use rustc::middle::expr_use_visitor as euv; use rustc::middle::mem_categorization as mc; use rustc::middle::mem_categorization::Categorization; +use rustc::middle::mem_categorization::ImmutabilityBlame; use rustc::middle::region; use rustc::ty::{self, TyCtxt}; @@ -41,6 +42,7 @@ use std::fmt; use std::rc::Rc; use std::hash::{Hash, Hasher}; use syntax::ast; +use syntax::symbol::keywords; use syntax_pos::{MultiSpan, Span}; use errors::DiagnosticBuilder; @@ -659,12 +661,10 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { self.tcx.sess.span_err_with_code(s, msg, code); } - pub fn bckerr_to_diag(&self, err: &BckError<'tcx>) -> DiagnosticBuilder<'a> { + fn bckerr_to_diag(&self, err: &BckError<'tcx>) -> DiagnosticBuilder<'a> { let span = err.span.clone(); - let mut immutable_field = None; - let mut local_def = None; - let msg = &match err.code { + let msg = match err.code { err_mutbl => { let descr = match err.cmt.note { mc::NoteClosureEnv(_) | mc::NoteUpvarRef(_) => { @@ -700,27 +700,6 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { BorrowViolation(euv::AutoUnsafe) | BorrowViolation(euv::ForLoop) | BorrowViolation(euv::MatchDiscriminant) => { - // Check for this field's definition to see if it is an immutable reference - // and suggest making it mutable if that is the case. - immutable_field = err.cmt.get_field_name() - .and_then(|name| err.cmt.get_field(name)) - .and_then(|did| self.tcx.hir.as_local_node_id(did)) - .and_then(|nid| { - if let hir_map::Node::NodeField(ref field) = self.tcx.hir.get(nid) { - return self.suggest_mut_for_immutable(&field.ty) - .map(|msg| (self.tcx.hir.span(nid), msg)); - } - None - }); - local_def = err.cmt.get_def() - .and_then(|nid| { - if !self.tcx.hir.is_argument(nid) { - Some(self.tcx.hir.span(nid)) - } else { - None - } - }); - format!("cannot borrow {} as mutable", descr) } BorrowViolation(euv::ClosureInvocation) => { @@ -746,16 +725,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { } }; - let mut db = self.struct_span_err(span, msg); - if let Some((span, msg)) = immutable_field { - db.span_label(span, &msg); - } - if let Some(let_span) = local_def { - if let Ok(snippet) = self.tcx.sess.codemap().span_to_snippet(let_span) { - db.span_label(let_span, &format!("consider changing this to `mut {}`", snippet)); - } - } - db + self.struct_span_err(span, &msg) } pub fn report_aliasability_violation(&self, @@ -788,55 +758,49 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { } }; - let mut err = match cause { - mc::AliasableOther => { - struct_span_err!( - self.tcx.sess, span, E0385, - "{} in an aliasable location", prefix) - } - mc::AliasableReason::UnaliasableImmutable => { - struct_span_err!( - self.tcx.sess, span, E0386, - "{} in an immutable container", prefix) + match cause { + mc::AliasableStatic | + mc::AliasableStaticMut => { + // This path cannot occur. It happens when we have an + // `&mut` or assignment to a static. But in the case + // of `static X`, we get a mutability violation first, + // and never get here. In the case of `static mut X`, + // that is unsafe and hence the aliasability error is + // ignored. + span_bug!(span, "aliasability violation for static `{}`", prefix) } - mc::AliasableClosure(id) => { + mc::AliasableBorrowed => {} + }; + let blame = cmt.immutability_blame(); + let mut err = match blame { + Some(ImmutabilityBlame::ClosureEnv(id)) => { let mut err = struct_span_err!( self.tcx.sess, span, E0387, "{} in a captured outer variable in an `Fn` closure", prefix); - if let BorrowViolation(euv::ClosureCapture(_)) = kind { + + // FIXME: the distinction between these 2 messages looks wrong. + let help = if let BorrowViolation(euv::ClosureCapture(_)) = kind { // The aliasability violation with closure captures can // happen for nested closures, so we know the enclosing // closure incorrectly accepts an `Fn` while it needs to // be `FnMut`. - span_help!(&mut err, self.tcx.hir.span(id), - "consider changing this to accept closures that implement `FnMut`"); + "consider changing this to accept closures that implement `FnMut`" + } else { - span_help!(&mut err, self.tcx.hir.span(id), - "consider changing this closure to take self by mutable reference"); - } + "consider changing this closure to take self by mutable reference" + }; + err.span_help(self.tcx.hir.span(id), help); err } - mc::AliasableStatic | - mc::AliasableStaticMut => { - // This path cannot occur. It happens when we have an - // `&mut` or assignment to a static. But in the case - // of `static X`, we get a mutability violation first, - // and never get here. In the case of `static mut X`, - // that is unsafe and hence the aliasability error is - // ignored. - span_bug!(span, "aliasability violation for static `{}`", prefix) - } - mc::AliasableBorrowed => { - let mut e = struct_span_err!( + _ => { + let mut err = struct_span_err!( self.tcx.sess, span, E0389, "{} in a `&` reference", prefix); - e.span_label(span, &"assignment into an immutable reference"); - if let Some(nid) = cmt.get_arg_if_immutable(&self.tcx.hir) { - self.immutable_argument_should_be_mut(nid, &mut e); - } - e + err.span_label(span, &"assignment into an immutable reference"); + err } }; + self.note_immutability_blame(&mut err, blame); if is_closure { err.help("closures behind references must be called via `&mut`"); @@ -873,8 +837,20 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { None } - fn immutable_argument_should_be_mut(&self, nid: ast::NodeId, db: &mut DiagnosticBuilder) { - let parent = self.tcx.hir.get_parent_node(nid); + fn local_binding_mode(&self, node_id: ast::NodeId) -> hir::BindingMode { + let pat = match self.tcx.hir.get(node_id) { + hir_map::Node::NodeLocal(pat) => pat, + node => bug!("bad node for local: {:?}", node) + }; + + match pat.node { + hir::PatKind::Binding(mode, ..) => mode, + _ => bug!("local is not a binding: {:?}", pat) + } + } + + fn local_ty(&self, node_id: ast::NodeId) -> Option<&hir::Ty> { + let parent = self.tcx.hir.get_parent_node(node_id); let parent_node = self.tcx.hir.get(parent); // The parent node is like a fn @@ -882,12 +858,72 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { // `nid`'s parent's `Body` let fn_body = self.tcx.hir.body(fn_like.body()); // Get the position of `nid` in the arguments list - let arg_pos = fn_body.arguments.iter().position(|arg| arg.pat.id == nid); + let arg_pos = fn_body.arguments.iter().position(|arg| arg.pat.id == node_id); if let Some(i) = arg_pos { // The argument's `Ty` - let arg_ty = &fn_like.decl().inputs[i]; - if let Some(msg) = self.suggest_mut_for_immutable(&arg_ty) { - db.span_label(arg_ty.span, &msg); + Some(&fn_like.decl().inputs[i]) + } else { + None + } + } else { + None + } + } + + fn note_immutability_blame(&self, + db: &mut DiagnosticBuilder, + blame: Option) { + match blame { + None => {} + Some(ImmutabilityBlame::ClosureEnv(_)) => {} + Some(ImmutabilityBlame::ImmLocal(node_id)) => { + let let_span = self.tcx.hir.span(node_id); + if let hir::BindingMode::BindByValue(..) = self.local_binding_mode(node_id) { + if let Ok(snippet) = self.tcx.sess.codemap().span_to_snippet(let_span) { + if self.tcx.hir.name(node_id) == keywords::SelfValue.name() && + snippet != "self" { + // avoid suggesting `mut &self`. + return + } + db.span_label( + let_span, + &format!("consider changing this to `mut {}`", snippet) + ); + } + } + } + Some(ImmutabilityBlame::LocalDeref(node_id)) => { + let let_span = self.tcx.hir.span(node_id); + match self.local_binding_mode(node_id) { + hir::BindingMode::BindByRef(..) => { + let snippet = self.tcx.sess.codemap().span_to_snippet(let_span); + if let Ok(snippet) = snippet { + db.span_label( + let_span, + &format!("consider changing this to `{}`", + snippet.replace("ref ", "ref mut ")) + ); + } + } + hir::BindingMode::BindByValue(..) => { + if let Some(local_ty) = self.local_ty(node_id) { + if let Some(msg) = self.suggest_mut_for_immutable(local_ty) { + db.span_label(local_ty.span, &msg); + } + } + } + } + } + Some(ImmutabilityBlame::AdtFieldDeref(_, field)) => { + let node_id = match self.tcx.hir.as_local_node_id(field.did) { + Some(node_id) => node_id, + None => return + }; + + if let hir_map::Node::NodeField(ref field) = self.tcx.hir.get(node_id) { + if let Some(msg) = self.suggest_mut_for_immutable(&field.ty) { + db.span_label(field.ty.span, &msg); + } } } } @@ -941,10 +977,13 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { } } - pub fn note_and_explain_bckerr(&self, db: &mut DiagnosticBuilder, err: BckError<'tcx>) { + fn note_and_explain_bckerr(&self, db: &mut DiagnosticBuilder, err: BckError<'tcx>) { let error_span = err.span.clone(); match err.code { - err_mutbl => self.note_and_explain_mutbl_error(db, &err, &error_span), + err_mutbl => { + self.note_and_explain_mutbl_error(db, &err, &error_span); + self.note_immutability_blame(db, err.cmt.immutability_blame()); + } err_out_of_scope(super_scope, sub_scope, cause) => { let (value_kind, value_msg) = match err.cmt.cat { mc::Categorization::Rvalue(..) => @@ -1096,13 +1135,6 @@ before rustc 1.16, this temporary lived longer - see issue #39283 \ _ => { if let Categorization::Deref(..) = err.cmt.cat { db.span_label(*error_span, &"cannot borrow as mutable"); - if let Some(local_id) = err.cmt.get_arg_if_immutable(&self.tcx.hir) { - self.immutable_argument_should_be_mut(local_id, db); - } else if let Categorization::Deref(ref inner_cmt, ..) = err.cmt.cat { - if let Categorization::Local(local_id) = inner_cmt.cat { - self.immutable_argument_should_be_mut(local_id, db); - } - } } else if let Categorization::Local(local_id) = err.cmt.cat { let span = self.tcx.hir.span(local_id); if let Ok(snippet) = self.tcx.sess.codemap().span_to_snippet(span) { @@ -1110,14 +1142,6 @@ before rustc 1.16, this temporary lived longer - see issue #39283 \ db.span_label(*error_span, &format!("cannot reborrow mutably")); db.span_label(*error_span, &format!("try removing `&mut` here")); } else { - if snippet.starts_with("ref ") { - db.span_label(span, &format!("use `{}` here to make mutable", - snippet.replace("ref ", "ref mut "))); - } else if snippet != "self" { - db.span_label(span, - &format!("use `mut {}` here to make mutable", - snippet)); - } db.span_label(*error_span, &format!("cannot borrow mutably")); } } else { diff --git a/src/librustc_borrowck/diagnostics.rs b/src/librustc_borrowck/diagnostics.rs index db4a1701e97..bfd342a9f21 100644 --- a/src/librustc_borrowck/diagnostics.rs +++ b/src/librustc_borrowck/diagnostics.rs @@ -198,7 +198,7 @@ fn main() { ``` "##, -E0386: r##" +/*E0386: r##" This error occurs when an attempt is made to mutate the target of a mutable reference stored inside an immutable container. @@ -228,7 +228,7 @@ let x: i64 = 1; let y: Box> = Box::new(Cell::new(x)); y.set(2); ``` -"##, +"##,*/ E0387: r##" This error occurs when an attempt is made to mutate or mutably reference data @@ -1117,6 +1117,6 @@ fn main() { } register_diagnostics! { - E0385, // {} in an aliasable location +// E0385, // {} in an aliasable location E0524, // two closures require unique access to `..` at the same time } diff --git a/src/test/compile-fail/augmented-assignments.rs b/src/test/compile-fail/augmented-assignments.rs index 92a8b10669c..736aa465aa7 100644 --- a/src/test/compile-fail/augmented-assignments.rs +++ b/src/test/compile-fail/augmented-assignments.rs @@ -27,7 +27,7 @@ fn main() { x; //~ value moved here let y = Int(2); - //~^use `mut y` here to make mutable + //~^ consider changing this to `mut y` y //~ error: cannot borrow immutable local variable `y` as mutable //~| cannot borrow += diff --git a/src/test/compile-fail/borrowck/borrowck-issue-14498.rs b/src/test/compile-fail/borrowck/borrowck-issue-14498.rs index 64033623fe2..8b7ccedd697 100644 --- a/src/test/compile-fail/borrowck/borrowck-issue-14498.rs +++ b/src/test/compile-fail/borrowck/borrowck-issue-14498.rs @@ -23,7 +23,7 @@ fn indirect_write_to_imm_box() { let mut x: isize = 1; let y: Box<_> = box &mut x; let p = &y; - ***p = 2; //~ ERROR cannot assign to data in an immutable container + ***p = 2; //~ ERROR cannot assign to data in a `&` reference drop(p); } @@ -43,7 +43,6 @@ fn borrow_in_var_from_var_via_imm_box() { let p = &y; let q = &***p; **y = 2; //~ ERROR cannot assign to `**y` because it is borrowed - //~^ ERROR cannot assign to data in an immutable container drop(p); drop(q); } @@ -64,7 +63,6 @@ fn borrow_in_var_from_field_via_imm_box() { let p = &y; let q = &***p; **y = 2; //~ ERROR cannot assign to `**y` because it is borrowed - //~^ ERROR cannot assign to data in an immutable container drop(p); drop(q); } @@ -85,7 +83,6 @@ fn borrow_in_field_from_var_via_imm_box() { let p = &y.a; let q = &***p; **y.a = 2; //~ ERROR cannot assign to `**y.a` because it is borrowed - //~^ ERROR cannot assign to data in an immutable container drop(p); drop(q); } @@ -106,7 +103,6 @@ fn borrow_in_field_from_field_via_imm_box() { let p = &y.a; let q = &***p; **y.a = 2; //~ ERROR cannot assign to `**y.a` because it is borrowed - //~^ ERROR cannot assign to data in an immutable container drop(p); drop(q); } diff --git a/src/test/compile-fail/issue-33819.rs b/src/test/compile-fail/issue-33819.rs index 9c9677c1e98..499e7e54947 100644 --- a/src/test/compile-fail/issue-33819.rs +++ b/src/test/compile-fail/issue-33819.rs @@ -12,7 +12,7 @@ fn main() { match op { Some(ref v) => { let a = &mut v; }, //~^ ERROR:cannot borrow immutable - //~| use `ref mut v` here to make mutable + //~| cannot borrow mutably None => {}, } } diff --git a/src/test/compile-fail/mut-suggestion.rs b/src/test/compile-fail/mut-suggestion.rs index 242ad7aee8d..0015c8e5c00 100644 --- a/src/test/compile-fail/mut-suggestion.rs +++ b/src/test/compile-fail/mut-suggestion.rs @@ -17,7 +17,7 @@ impl S { } fn func(arg: S) { - //~^ here to make mutable + //~^ consider changing this to `mut arg` arg.mutate(); //~^ ERROR cannot borrow immutable argument //~| cannot borrow mutably @@ -25,7 +25,7 @@ fn func(arg: S) { fn main() { let local = S; - //~^ here to make mutable + //~^ consider changing this to `mut local` local.mutate(); //~^ ERROR cannot borrow immutable local variable //~| cannot borrow mutably diff --git a/src/test/ui/codemap_tests/huge_multispan_highlight.stderr b/src/test/ui/codemap_tests/huge_multispan_highlight.stderr index edbfd72df61..7bb69caa102 100644 --- a/src/test/ui/codemap_tests/huge_multispan_highlight.stderr +++ b/src/test/ui/codemap_tests/huge_multispan_highlight.stderr @@ -2,7 +2,7 @@ error: cannot borrow immutable local variable `x` as mutable --> $DIR/huge_multispan_highlight.rs:100:18 | 12 | let x = "foo"; - | - use `mut x` here to make mutable + | - consider changing this to `mut x` ... 100 | let y = &mut x; | ^ cannot borrow mutably diff --git a/src/test/ui/did_you_mean/issue-31424.stderr b/src/test/ui/did_you_mean/issue-31424.stderr index 4873acf551e..60fa06d314f 100644 --- a/src/test/ui/did_you_mean/issue-31424.stderr +++ b/src/test/ui/did_you_mean/issue-31424.stderr @@ -10,6 +10,8 @@ error: cannot borrow immutable argument `self` as mutable error: cannot borrow immutable argument `self` as mutable --> $DIR/issue-31424.rs:23:15 | +22 | fn bar(self: &mut Self) { + | ---- consider changing this to `mut self` 23 | (&mut self).bar(); | ^^^^ cannot borrow mutably diff --git a/src/test/ui/did_you_mean/issue-35937.rs b/src/test/ui/did_you_mean/issue-35937.rs new file mode 100644 index 00000000000..9ec8728fd32 --- /dev/null +++ b/src/test/ui/did_you_mean/issue-35937.rs @@ -0,0 +1,31 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +struct Foo { + pub v: Vec +} + +fn main() { + let f = Foo { v: Vec::new() }; + f.v.push("cat".to_string()); +} + + +struct S { + x: i32, +} +fn foo() { + let s = S { x: 42 }; + s.x += 1; +} + +fn bar(s: S) { + s.x += 1; +} diff --git a/src/test/ui/did_you_mean/issue-35937.stderr b/src/test/ui/did_you_mean/issue-35937.stderr new file mode 100644 index 00000000000..bea3d129143 --- /dev/null +++ b/src/test/ui/did_you_mean/issue-35937.stderr @@ -0,0 +1,26 @@ +error: cannot borrow immutable field `f.v` as mutable + --> $DIR/issue-35937.rs:17:5 + | +16 | let f = Foo { v: Vec::new() }; + | - consider changing this to `mut f` +17 | f.v.push("cat".to_string()); + | ^^^ cannot mutably borrow immutable field + +error: cannot assign to immutable field `s.x` + --> $DIR/issue-35937.rs:26:5 + | +25 | let s = S { x: 42 }; + | - consider changing this to `mut s` +26 | s.x += 1; + | ^^^^^^^^ cannot mutably borrow immutable field + +error: cannot assign to immutable field `s.x` + --> $DIR/issue-35937.rs:30:5 + | +29 | fn bar(s: S) { + | - consider changing this to `mut s` +30 | s.x += 1; + | ^^^^^^^^ cannot mutably borrow immutable field + +error: aborting due to 3 previous errors + diff --git a/src/test/ui/did_you_mean/issue-38147-2.stderr b/src/test/ui/did_you_mean/issue-38147-2.stderr index fdaf0cd44d9..855feaf7d2d 100644 --- a/src/test/ui/did_you_mean/issue-38147-2.stderr +++ b/src/test/ui/did_you_mean/issue-38147-2.stderr @@ -2,7 +2,7 @@ error: cannot borrow immutable borrowed content `*self.s` as mutable --> $DIR/issue-38147-2.rs:17:9 | 12 | s: &'a String - | ------------- use `&'a mut String` here to make mutable + | ---------- use `&'a mut String` here to make mutable ... 17 | self.s.push('x'); | ^^^^^^ cannot borrow as mutable diff --git a/src/test/ui/did_you_mean/issue-38147-3.stderr b/src/test/ui/did_you_mean/issue-38147-3.stderr index d2280fa561b..d970d078df8 100644 --- a/src/test/ui/did_you_mean/issue-38147-3.stderr +++ b/src/test/ui/did_you_mean/issue-38147-3.stderr @@ -2,10 +2,8 @@ error: cannot borrow immutable borrowed content `*self.s` as mutable --> $DIR/issue-38147-3.rs:17:9 | 12 | s: &'a String - | ------------- use `&'a mut String` here to make mutable + | ---------- use `&'a mut String` here to make mutable ... -16 | fn f(&self) { - | ----- use `&mut self` here to make mutable 17 | self.s.push('x'); | ^^^^^^ cannot borrow as mutable diff --git a/src/test/ui/did_you_mean/issue-39544.rs b/src/test/ui/did_you_mean/issue-39544.rs index bcdafefa247..c98fed3c3c3 100644 --- a/src/test/ui/did_you_mean/issue-39544.rs +++ b/src/test/ui/did_you_mean/issue-39544.rs @@ -8,15 +8,20 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -enum X { +pub enum X { Y } -struct Z { +pub struct Z { x: X } -fn main() { +pub fn main() { let z = Z { x: X::Y }; let _ = &mut z.x; } + +pub fn with_arg(z: Z, w: &Z) { + let _ = &mut z.x; + let _ = &mut w.x; +} diff --git a/src/test/ui/did_you_mean/issue-39544.stderr b/src/test/ui/did_you_mean/issue-39544.stderr index 7f124e6d34d..bcd55fd744b 100644 --- a/src/test/ui/did_you_mean/issue-39544.stderr +++ b/src/test/ui/did_you_mean/issue-39544.stderr @@ -6,5 +6,22 @@ error: cannot borrow immutable field `z.x` as mutable 21 | let _ = &mut z.x; | ^^^ cannot mutably borrow immutable field -error: aborting due to previous error +error: cannot borrow immutable field `z.x` as mutable + --> $DIR/issue-39544.rs:25:18 + | +24 | pub fn with_arg(z: Z, w: &Z) { + | - consider changing this to `mut z` +25 | let _ = &mut z.x; + | ^^^ cannot mutably borrow immutable field + +error: cannot borrow immutable field `w.x` as mutable + --> $DIR/issue-39544.rs:26:18 + | +24 | pub fn with_arg(z: Z, w: &Z) { + | -- use `&mut Z` here to make mutable +25 | let _ = &mut z.x; +26 | let _ = &mut w.x; + | ^^^ cannot mutably borrow immutable field + +error: aborting due to 3 previous errors diff --git a/src/test/ui/did_you_mean/issue-40823.rs b/src/test/ui/did_you_mean/issue-40823.rs new file mode 100644 index 00000000000..f4ae3257279 --- /dev/null +++ b/src/test/ui/did_you_mean/issue-40823.rs @@ -0,0 +1,14 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main() { + let mut buf = &[1, 2, 3, 4]; + buf.iter_mut(); +} diff --git a/src/test/ui/did_you_mean/issue-40823.stderr b/src/test/ui/did_you_mean/issue-40823.stderr new file mode 100644 index 00000000000..8e77ebd9b6d --- /dev/null +++ b/src/test/ui/did_you_mean/issue-40823.stderr @@ -0,0 +1,8 @@ +error: cannot borrow immutable borrowed content `*buf` as mutable + --> $DIR/issue-40823.rs:13:5 + | +13 | buf.iter_mut(); + | ^^^ cannot borrow as mutable + +error: aborting due to previous error + diff --git a/src/test/ui/span/borrowck-borrow-overloaded-auto-deref-mut.stderr b/src/test/ui/span/borrowck-borrow-overloaded-auto-deref-mut.stderr index b83a6aaebf3..edf1635a6b8 100644 --- a/src/test/ui/span/borrowck-borrow-overloaded-auto-deref-mut.stderr +++ b/src/test/ui/span/borrowck-borrow-overloaded-auto-deref-mut.stderr @@ -2,7 +2,7 @@ error: cannot borrow immutable argument `x` as mutable --> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:63:24 | 62 | fn deref_mut_field1(x: Own) { - | - use `mut x` here to make mutable + | - consider changing this to `mut x` 63 | let __isize = &mut x.y; //~ ERROR cannot borrow | ^ cannot borrow mutably @@ -28,7 +28,7 @@ error: cannot borrow immutable argument `x` as mutable --> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:98:5 | 97 | fn assign_field1<'a>(x: Own) { - | - use `mut x` here to make mutable + | - consider changing this to `mut x` 98 | x.y = 3; //~ ERROR cannot borrow | ^ cannot borrow mutably @@ -54,7 +54,7 @@ error: cannot borrow immutable argument `x` as mutable --> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:119:5 | 118 | fn deref_mut_method1(x: Own) { - | - use `mut x` here to make mutable + | - consider changing this to `mut x` 119 | x.set(0, 0); //~ ERROR cannot borrow | ^ cannot borrow mutably @@ -70,7 +70,7 @@ error: cannot borrow immutable argument `x` as mutable --> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:139:6 | 138 | fn assign_method1<'a>(x: Own) { - | - use `mut x` here to make mutable + | - consider changing this to `mut x` 139 | *x.y_mut() = 3; //~ ERROR cannot borrow | ^ cannot borrow mutably diff --git a/src/test/ui/span/borrowck-borrow-overloaded-deref-mut.stderr b/src/test/ui/span/borrowck-borrow-overloaded-deref-mut.stderr index af954a4d792..2ec01168721 100644 --- a/src/test/ui/span/borrowck-borrow-overloaded-deref-mut.stderr +++ b/src/test/ui/span/borrowck-borrow-overloaded-deref-mut.stderr @@ -2,7 +2,7 @@ error: cannot borrow immutable argument `x` as mutable --> $DIR/borrowck-borrow-overloaded-deref-mut.rs:39:25 | 38 | fn deref_mut1(x: Own) { - | - use `mut x` here to make mutable + | - consider changing this to `mut x` 39 | let __isize = &mut *x; //~ ERROR cannot borrow | ^ cannot borrow mutably @@ -18,7 +18,7 @@ error: cannot borrow immutable argument `x` as mutable --> $DIR/borrowck-borrow-overloaded-deref-mut.rs:59:6 | 58 | fn assign1<'a>(x: Own) { - | - use `mut x` here to make mutable + | - consider changing this to `mut x` 59 | *x = 3; //~ ERROR cannot borrow | ^ cannot borrow mutably diff --git a/src/test/ui/span/borrowck-object-mutability.stderr b/src/test/ui/span/borrowck-object-mutability.stderr index 4ef1cb9c239..0abdbdc3a21 100644 --- a/src/test/ui/span/borrowck-object-mutability.stderr +++ b/src/test/ui/span/borrowck-object-mutability.stderr @@ -10,6 +10,9 @@ error: cannot borrow immutable borrowed content `*x` as mutable error: cannot borrow immutable `Box` content `*x` as mutable --> $DIR/borrowck-object-mutability.rs:29:5 | +27 | fn owned_receiver(x: Box) { + | - consider changing this to `mut x` +28 | x.borrowed(); 29 | x.borrowed_mut(); //~ ERROR cannot borrow | ^ cannot borrow as mutable -- cgit 1.4.1-3-g733a5 From 39011f8590b69d5ee9037c4ac9b863a516ae2e1e Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Mon, 27 Mar 2017 01:35:50 +0300 Subject: fix handling of `self` --- src/librustc/hir/lowering.rs | 7 +++ src/librustc/hir/mod.rs | 3 ++ src/librustc_borrowck/borrowck/mod.rs | 60 +++++++++++---------- src/test/ui/did_you_mean/issue-39544.rs | 28 +++++++++- src/test/ui/did_you_mean/issue-39544.stderr | 83 ++++++++++++++++++++++++++--- 5 files changed, 143 insertions(+), 38 deletions(-) (limited to 'src/test') diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 2ac1a036f99..726c305e903 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -907,6 +907,13 @@ impl<'a> LoweringContext<'a> { FunctionRetTy::Default(span) => hir::DefaultReturn(span), }, variadic: decl.variadic, + has_implicit_self: decl.inputs.get(0).map_or(false, |arg| { + match arg.ty.node { + TyKind::ImplicitSelf => true, + TyKind::Rptr(_, ref mt) => mt.ty.node == TyKind::ImplicitSelf, + _ => false + } + }) }) } diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 1c79a02d3da..43b7deb5b90 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -1379,6 +1379,9 @@ pub struct FnDecl { pub inputs: HirVec>, pub output: FunctionRetTy, pub variadic: bool, + /// True if this function has an `self`, `&self` or `&mut self` receiver + /// (but not a `self: Xxx` one). + pub has_implicit_self: bool, } #[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index 0981369ace5..558a835be18 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -42,7 +42,6 @@ use std::fmt; use std::rc::Rc; use std::hash::{Hash, Hasher}; use syntax::ast; -use syntax::symbol::keywords; use syntax_pos::{MultiSpan, Span}; use errors::DiagnosticBuilder; @@ -809,32 +808,33 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { } /// Given a type, if it is an immutable reference, return a suggestion to make it mutable - fn suggest_mut_for_immutable(&self, pty: &hir::Ty) -> Option { + fn suggest_mut_for_immutable(&self, pty: &hir::Ty, is_implicit_self: bool) -> Option { // Check wether the argument is an immutable reference + debug!("suggest_mut_for_immutable({:?}, {:?})", pty, is_implicit_self); if let hir::TyRptr(lifetime, hir::MutTy { mutbl: hir::Mutability::MutImmutable, ref ty }) = pty.node { // Account for existing lifetimes when generating the message - if !lifetime.is_elided() { - if let Ok(snippet) = self.tcx.sess.codemap().span_to_snippet(ty.span) { - if let Ok(lifetime_snippet) = self.tcx.sess.codemap() - .span_to_snippet(lifetime.span) { - return Some(format!("use `&{} mut {}` here to make mutable", - lifetime_snippet, - snippet)); - } - } - } else if let Ok(snippet) = self.tcx.sess.codemap().span_to_snippet(pty.span) { - if snippet.starts_with("&") { - return Some(format!("use `{}` here to make mutable", - snippet.replace("&", "&mut "))); - } + let pointee_snippet = match self.tcx.sess.codemap().span_to_snippet(ty.span) { + Ok(snippet) => snippet, + _ => return None + }; + + let lifetime_snippet = if !lifetime.is_elided() { + format!("{} ", match self.tcx.sess.codemap().span_to_snippet(lifetime.span) { + Ok(lifetime_snippet) => lifetime_snippet, + _ => return None + }) } else { - bug!("couldn't find a snippet for span: {:?}", pty.span); - } + String::new() + }; + Some(format!("use `&{}mut {}` here to make mutable", + lifetime_snippet, + if is_implicit_self { "self" } else { &*pointee_snippet })) + } else { + None } - None } fn local_binding_mode(&self, node_id: ast::NodeId) -> hir::BindingMode { @@ -849,7 +849,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { } } - fn local_ty(&self, node_id: ast::NodeId) -> Option<&hir::Ty> { + fn local_ty(&self, node_id: ast::NodeId) -> (Option<&hir::Ty>, bool) { let parent = self.tcx.hir.get_parent_node(node_id); let parent_node = self.tcx.hir.get(parent); @@ -857,16 +857,17 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { if let Some(fn_like) = FnLikeNode::from_node(parent_node) { // `nid`'s parent's `Body` let fn_body = self.tcx.hir.body(fn_like.body()); - // Get the position of `nid` in the arguments list + // Get the position of `node_id` in the arguments list let arg_pos = fn_body.arguments.iter().position(|arg| arg.pat.id == node_id); if let Some(i) = arg_pos { // The argument's `Ty` - Some(&fn_like.decl().inputs[i]) + (Some(&fn_like.decl().inputs[i]), + i == 0 && fn_like.decl().has_implicit_self) } else { - None + (None, false) } } else { - None + (None, false) } } @@ -880,8 +881,8 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { let let_span = self.tcx.hir.span(node_id); if let hir::BindingMode::BindByValue(..) = self.local_binding_mode(node_id) { if let Ok(snippet) = self.tcx.sess.codemap().span_to_snippet(let_span) { - if self.tcx.hir.name(node_id) == keywords::SelfValue.name() && - snippet != "self" { + let (_, is_implicit_self) = self.local_ty(node_id); + if is_implicit_self && snippet != "self" { // avoid suggesting `mut &self`. return } @@ -906,8 +907,9 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { } } hir::BindingMode::BindByValue(..) => { - if let Some(local_ty) = self.local_ty(node_id) { - if let Some(msg) = self.suggest_mut_for_immutable(local_ty) { + if let (Some(local_ty), is_implicit_self) = self.local_ty(node_id) { + if let Some(msg) = + self.suggest_mut_for_immutable(local_ty, is_implicit_self) { db.span_label(local_ty.span, &msg); } } @@ -921,7 +923,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { }; if let hir_map::Node::NodeField(ref field) = self.tcx.hir.get(node_id) { - if let Some(msg) = self.suggest_mut_for_immutable(&field.ty) { + if let Some(msg) = self.suggest_mut_for_immutable(&field.ty, false) { db.span_label(field.ty.span, &msg); } } diff --git a/src/test/ui/did_you_mean/issue-39544.rs b/src/test/ui/did_you_mean/issue-39544.rs index c98fed3c3c3..6331fc5771f 100644 --- a/src/test/ui/did_you_mean/issue-39544.rs +++ b/src/test/ui/did_you_mean/issue-39544.rs @@ -16,11 +16,37 @@ pub struct Z { x: X } -pub fn main() { +fn main() { let z = Z { x: X::Y }; let _ = &mut z.x; } +impl Z { + fn foo<'z>(&'z self) { + let _ = &mut self.x; + } + + fn foo1(&self, other: &Z) { + let _ = &mut self.x; + let _ = &mut other.x; + } + + fn foo2<'a>(&'a self, other: &Z) { + let _ = &mut self.x; + let _ = &mut other.x; + } + + fn foo3<'a>(self: &'a Self, other: &Z) { + let _ = &mut self.x; + let _ = &mut other.x; + } + + fn foo4(other: &Z) { + let _ = &mut other.x; + } + +} + pub fn with_arg(z: Z, w: &Z) { let _ = &mut z.x; let _ = &mut w.x; diff --git a/src/test/ui/did_you_mean/issue-39544.stderr b/src/test/ui/did_you_mean/issue-39544.stderr index bcd55fd744b..e1e229a8b05 100644 --- a/src/test/ui/did_you_mean/issue-39544.stderr +++ b/src/test/ui/did_you_mean/issue-39544.stderr @@ -6,22 +6,89 @@ error: cannot borrow immutable field `z.x` as mutable 21 | let _ = &mut z.x; | ^^^ cannot mutably borrow immutable field +error: cannot borrow immutable field `self.x` as mutable + --> $DIR/issue-39544.rs:26:22 + | +25 | fn foo<'z>(&'z self) { + | -------- use `&'z mut self` here to make mutable +26 | let _ = &mut self.x; + | ^^^^^^ cannot mutably borrow immutable field + +error: cannot borrow immutable field `self.x` as mutable + --> $DIR/issue-39544.rs:30:22 + | +29 | fn foo1(&self, other: &Z) { + | ----- use `&mut self` here to make mutable +30 | let _ = &mut self.x; + | ^^^^^^ cannot mutably borrow immutable field + +error: cannot borrow immutable field `other.x` as mutable + --> $DIR/issue-39544.rs:31:22 + | +29 | fn foo1(&self, other: &Z) { + | -- use `&mut Z` here to make mutable +30 | let _ = &mut self.x; +31 | let _ = &mut other.x; + | ^^^^^^^ cannot mutably borrow immutable field + +error: cannot borrow immutable field `self.x` as mutable + --> $DIR/issue-39544.rs:35:22 + | +34 | fn foo2<'a>(&'a self, other: &Z) { + | -------- use `&'a mut self` here to make mutable +35 | let _ = &mut self.x; + | ^^^^^^ cannot mutably borrow immutable field + +error: cannot borrow immutable field `other.x` as mutable + --> $DIR/issue-39544.rs:36:22 + | +34 | fn foo2<'a>(&'a self, other: &Z) { + | -- use `&mut Z` here to make mutable +35 | let _ = &mut self.x; +36 | let _ = &mut other.x; + | ^^^^^^^ cannot mutably borrow immutable field + +error: cannot borrow immutable field `self.x` as mutable + --> $DIR/issue-39544.rs:40:22 + | +39 | fn foo3<'a>(self: &'a Self, other: &Z) { + | -------- use `&'a mut Self` here to make mutable +40 | let _ = &mut self.x; + | ^^^^^^ cannot mutably borrow immutable field + +error: cannot borrow immutable field `other.x` as mutable + --> $DIR/issue-39544.rs:41:22 + | +39 | fn foo3<'a>(self: &'a Self, other: &Z) { + | -- use `&mut Z` here to make mutable +40 | let _ = &mut self.x; +41 | let _ = &mut other.x; + | ^^^^^^^ cannot mutably borrow immutable field + +error: cannot borrow immutable field `other.x` as mutable + --> $DIR/issue-39544.rs:45:22 + | +44 | fn foo4(other: &Z) { + | -- use `&mut Z` here to make mutable +45 | let _ = &mut other.x; + | ^^^^^^^ cannot mutably borrow immutable field + error: cannot borrow immutable field `z.x` as mutable - --> $DIR/issue-39544.rs:25:18 + --> $DIR/issue-39544.rs:51:18 | -24 | pub fn with_arg(z: Z, w: &Z) { +50 | pub fn with_arg(z: Z, w: &Z) { | - consider changing this to `mut z` -25 | let _ = &mut z.x; +51 | let _ = &mut z.x; | ^^^ cannot mutably borrow immutable field error: cannot borrow immutable field `w.x` as mutable - --> $DIR/issue-39544.rs:26:18 + --> $DIR/issue-39544.rs:52:18 | -24 | pub fn with_arg(z: Z, w: &Z) { +50 | pub fn with_arg(z: Z, w: &Z) { | -- use `&mut Z` here to make mutable -25 | let _ = &mut z.x; -26 | let _ = &mut w.x; +51 | let _ = &mut z.x; +52 | let _ = &mut w.x; | ^^^ cannot mutably borrow immutable field -error: aborting due to 3 previous errors +error: aborting due to 11 previous errors -- cgit 1.4.1-3-g733a5 From 737511ee118b16382bc7eb6a217ea370731f4821 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Mon, 27 Mar 2017 05:22:18 +0000 Subject: Ensure that macro resolutions in trait positions get finalized. --- src/librustc_resolve/lib.rs | 4 ++++ src/librustc_resolve/macros.rs | 5 ++--- src/test/compile-fail/issue-40845.rs | 16 ++++++++++++++++ 3 files changed, 22 insertions(+), 3 deletions(-) create mode 100644 src/test/compile-fail/issue-40845.rs (limited to 'src/test') diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 879d8816488..0466e76475d 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -922,6 +922,10 @@ impl<'a> ModuleData<'a> { fn is_local(&self) -> bool { self.normal_ancestor_id.is_local() } + + fn nearest_item_scope(&'a self) -> Module<'a> { + if self.is_trait() { self.parent.unwrap() } else { self } + } } impl<'a> fmt::Debug for ModuleData<'a> { diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 3d6c6896549..05f30f039c8 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -172,7 +172,6 @@ impl<'a> base::Resolver for Resolver<'a> { expansion: mark, }; expansion.visit_with(&mut visitor); - self.current_module.unresolved_invocations.borrow_mut().remove(&mark); invocation.expansion.set(visitor.legacy_scope); } @@ -390,7 +389,7 @@ impl<'a> Resolver<'a> { Err(Determinacy::Determined) }, }; - self.current_module.macro_resolutions.borrow_mut() + self.current_module.nearest_item_scope().macro_resolutions.borrow_mut() .push((path.into_boxed_slice(), span)); return def; } @@ -410,7 +409,7 @@ impl<'a> Resolver<'a> { } }; - self.current_module.legacy_macro_resolutions.borrow_mut() + self.current_module.nearest_item_scope().legacy_macro_resolutions.borrow_mut() .push((scope, path[0], span, kind)); result diff --git a/src/test/compile-fail/issue-40845.rs b/src/test/compile-fail/issue-40845.rs new file mode 100644 index 00000000000..c5604a0427b --- /dev/null +++ b/src/test/compile-fail/issue-40845.rs @@ -0,0 +1,16 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +trait T { m!(); } //~ ERROR cannot find macro `m!` in this scope + +struct S; +impl S { m!(); } //~ ERROR cannot find macro `m!` in this scope + +fn main() {} -- cgit 1.4.1-3-g733a5 From d8fc5b80b61f662dd0d63d236875ade5a3f1129c Mon Sep 17 00:00:00 2001 From: Austin Bonander Date: Tue, 28 Mar 2017 00:02:19 -0700 Subject: Rustdoc: test proper representation for `pub use` macros --- .../rustdoc/auxiliary/pub-use-extern-macros.rs | 30 +++++++++++++++++++++ src/test/rustdoc/pub-use-extern-macros.rs | 31 ++++++++++++++++++++++ 2 files changed, 61 insertions(+) create mode 100644 src/test/rustdoc/auxiliary/pub-use-extern-macros.rs create mode 100644 src/test/rustdoc/pub-use-extern-macros.rs (limited to 'src/test') diff --git a/src/test/rustdoc/auxiliary/pub-use-extern-macros.rs b/src/test/rustdoc/auxiliary/pub-use-extern-macros.rs new file mode 100644 index 00000000000..70d174a149d --- /dev/null +++ b/src/test/rustdoc/auxiliary/pub-use-extern-macros.rs @@ -0,0 +1,30 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. +#![crate_name="macros"] + +#[macro_export] +macro_rules! foo { + () => {}; +} + +#[macro_export] +macro_rules! bar { + () => {}; +} + +#[macro_export] +macro_rules! baz { + () => {}; +} + +#[macro_export] +macro_rules! quux { + () => {}; +} diff --git a/src/test/rustdoc/pub-use-extern-macros.rs b/src/test/rustdoc/pub-use-extern-macros.rs new file mode 100644 index 00000000000..3f8f6f9544e --- /dev/null +++ b/src/test/rustdoc/pub-use-extern-macros.rs @@ -0,0 +1,31 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:pub-use-extern-macros.rs + +#![feature(use_extern_macros, macro_reexport)] + +// @has pub_use_extern_macros/macro.foo.html +// @!has pub_use_extern_macros/index.html 'pub use macros::foo;' +#[macro_reexport(foo)] extern crate macros; + +// @has pub_use_extern_macros/index.html 'pub use macros::bar;' +// @!has pub_use_extern_macros/macro.bar.html +pub use macros::bar; + +// @has pub_use_extern_macros/macro.baz.html +// @!has pub_use_extern_macros/index.html 'pub use macros::baz;' +#[doc(inline)] +pub use macros::baz; + +// @!has pub_use_extern_macros/macro.quux.html +// @!has pub_use_extern_macros/index.html 'pub use macros::quux;' +#[doc(hidden)] +pub use macros::quux; -- cgit 1.4.1-3-g733a5 From ec7c0aece17c9a11bc2eca15b994355a161bf878 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Fri, 17 Mar 2017 04:04:41 +0000 Subject: Merge `ExpnId` and `SyntaxContext`. --- src/librustc/hir/lowering.rs | 7 +- src/librustc/hir/mod.rs | 5 +- src/librustc/ich/caching_codemap_view.rs | 4 - src/librustc/middle/region.rs | 2 +- src/librustc/middle/stability.rs | 2 +- src/librustc_driver/driver.rs | 4 +- src/librustc_errors/emitter.rs | 22 +- src/librustc_errors/lib.rs | 4 +- .../calculate_svh/svh_visitor.rs | 17 +- src/librustc_mir/transform/qualify_consts.rs | 4 +- src/librustc_plugin/load.rs | 4 +- src/librustc_save_analysis/lib.rs | 7 +- src/librustc_save_analysis/span_utils.rs | 3 +- src/librustc_trans/asm.rs | 4 +- src/librustc_trans/back/write.rs | 6 +- src/librustc_trans/mir/mod.rs | 18 +- src/librustc_typeck/check/mod.rs | 5 +- src/libsyntax/ast.rs | 57 +-- src/libsyntax/codemap.rs | 291 +-------------- src/libsyntax/ext/base.rs | 74 ++-- src/libsyntax/ext/derive.rs | 50 +-- src/libsyntax/ext/expand.rs | 111 +++--- src/libsyntax/ext/source_util.rs | 2 +- src/libsyntax/ext/tt/quoted.rs | 14 +- src/libsyntax/feature_gate.rs | 20 +- src/libsyntax/json.rs | 2 +- src/libsyntax/lib.rs | 2 +- src/libsyntax/parse/parser.rs | 6 +- src/libsyntax/std_inject.rs | 21 +- src/libsyntax/symbol.rs | 342 ------------------ src/libsyntax/test.rs | 21 +- src/libsyntax/test_snippet.rs | 2 +- src/libsyntax/tokenstream.rs | 16 +- src/libsyntax_ext/asm.rs | 12 +- src/libsyntax_ext/deriving/clone.rs | 2 +- src/libsyntax_ext/deriving/cmp/eq.rs | 2 +- src/libsyntax_ext/deriving/debug.rs | 4 +- src/libsyntax_ext/deriving/generic/mod.rs | 12 +- src/libsyntax_ext/deriving/mod.rs | 34 +- src/libsyntax_ext/format.rs | 3 +- src/libsyntax_ext/proc_macro_registrar.rs | 6 +- src/libsyntax_pos/hygiene.rs | 94 ++++- src/libsyntax_pos/lib.rs | 101 ++++-- src/libsyntax_pos/symbol.rs | 389 +++++++++++++++++++++ src/test/compile-fail-fulldeps/qquote.rs | 8 - src/test/run-fail-fulldeps/qquote.rs | 8 - src/test/run-pass-fulldeps/qquote.rs | 8 - 47 files changed, 793 insertions(+), 1039 deletions(-) delete mode 100644 src/libsyntax/symbol.rs create mode 100644 src/libsyntax_pos/symbol.rs (limited to 'src/test') diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 6ca0c971ea4..786145f3091 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -57,6 +57,7 @@ use std::mem; use syntax::attr; use syntax::ast::*; use syntax::errors; +use syntax::ext::hygiene::{Mark, SyntaxContext}; use syntax::ptr::P; use syntax::codemap::{self, respan, Spanned}; use syntax::std_inject; @@ -392,7 +393,8 @@ impl<'a> LoweringContext<'a> { } fn allow_internal_unstable(&self, reason: &'static str, mut span: Span) -> Span { - span.expn_id = self.sess.codemap().record_expansion(codemap::ExpnInfo { + let mark = Mark::fresh(); + mark.set_expn_info(codemap::ExpnInfo { call_site: span, callee: codemap::NameAndSpan { format: codemap::CompilerDesugaring(Symbol::intern(reason)), @@ -400,6 +402,7 @@ impl<'a> LoweringContext<'a> { allow_internal_unstable: true, }, }); + span.ctxt = SyntaxContext::empty().apply_mark(mark); span } @@ -1986,7 +1989,7 @@ impl<'a> LoweringContext<'a> { volatile: asm.volatile, alignstack: asm.alignstack, dialect: asm.dialect, - expn_id: asm.expn_id, + ctxt: asm.ctxt, }; let outputs = asm.outputs.iter().map(|out| self.lower_expr(&out.expr)).collect(); diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index f4f2f4cf921..da7e71ac07d 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -33,11 +33,12 @@ use hir::def::Def; use hir::def_id::{DefId, DefIndex, CRATE_DEF_INDEX}; use util::nodemap::{NodeMap, FxHashSet}; -use syntax_pos::{Span, ExpnId, DUMMY_SP}; +use syntax_pos::{Span, DUMMY_SP}; use syntax::codemap::{self, Spanned}; use syntax::abi::Abi; use syntax::ast::{Ident, Name, NodeId, DUMMY_NODE_ID, AsmDialect}; use syntax::ast::{Attribute, Lit, StrStyle, FloatTy, IntTy, UintTy, MetaItem}; +use syntax::ext::hygiene::SyntaxContext; use syntax::ptr::P; use syntax::symbol::{Symbol, keywords}; use syntax::tokenstream::TokenStream; @@ -1367,7 +1368,7 @@ pub struct InlineAsm { pub volatile: bool, pub alignstack: bool, pub dialect: AsmDialect, - pub expn_id: ExpnId, + pub ctxt: SyntaxContext, } /// represents an argument in a function header diff --git a/src/librustc/ich/caching_codemap_view.rs b/src/librustc/ich/caching_codemap_view.rs index a71251eedf5..1278d9f5171 100644 --- a/src/librustc/ich/caching_codemap_view.rs +++ b/src/librustc/ich/caching_codemap_view.rs @@ -47,10 +47,6 @@ impl<'tcx> CachingCodemapView<'tcx> { } } - pub fn codemap(&self) -> &'tcx CodeMap { - self.codemap - } - pub fn byte_pos_to_line_and_col(&mut self, pos: BytePos) -> Option<(Rc, usize, BytePos)> { diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index a19f15a9329..0676075930d 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -236,7 +236,7 @@ impl CodeExtent { // (This is the special case aluded to in the // doc-comment for this method) let stmt_span = blk.stmts[r.first_statement_index as usize].span; - Some(Span { lo: stmt_span.hi, hi: blk.span.hi, expn_id: stmt_span.expn_id }) + Some(Span { lo: stmt_span.hi, hi: blk.span.hi, ctxt: stmt_span.ctxt }) } } } diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs index 4354ed6817a..2b5ea61d4e8 100644 --- a/src/librustc/middle/stability.rs +++ b/src/librustc/middle/stability.rs @@ -467,7 +467,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } pub fn check_stability(self, def_id: DefId, id: NodeId, span: Span) { - if self.sess.codemap().span_allows_unstable(span) { + if span.allows_unstable() { debug!("stability: \ skipping span={:?} since it is internal", span); return; diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 4873b21c548..977382b33ad 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -580,7 +580,7 @@ pub fn phase_2_configure_and_expand(sess: &Session, krate = time(time_passes, "crate injection", || { let alt_std_name = sess.opts.alt_std_name.clone(); - syntax::std_inject::maybe_inject_crates_ref(&sess.parse_sess, krate, alt_std_name) + syntax::std_inject::maybe_inject_crates_ref(krate, alt_std_name) }); let mut addl_plugins = Some(addl_plugins); @@ -798,7 +798,7 @@ pub fn phase_2_configure_and_expand(sess: &Session, // Discard hygiene data, which isn't required after lowering to HIR. if !keep_hygiene_data(sess) { - syntax::ext::hygiene::reset_hygiene_data(); + syntax::ext::hygiene::clear_markings(); } Ok(ExpansionResult { diff --git a/src/librustc_errors/emitter.rs b/src/librustc_errors/emitter.rs index 431edb3c9bc..367b85ac726 100644 --- a/src/librustc_errors/emitter.rs +++ b/src/librustc_errors/emitter.rs @@ -10,7 +10,7 @@ use self::Destination::*; -use syntax_pos::{COMMAND_LINE_SP, DUMMY_SP, FileMap, Span, MultiSpan, CharPos}; +use syntax_pos::{DUMMY_SP, FileMap, Span, MultiSpan, CharPos}; use {Level, CodeSuggestion, DiagnosticBuilder, SubDiagnostic, CodeMapper}; use RenderSpan::*; @@ -151,7 +151,7 @@ impl EmitterWriter { if let Some(ref cm) = self.cm { for span_label in msp.span_labels() { - if span_label.span == DUMMY_SP || span_label.span == COMMAND_LINE_SP { + if span_label.span == DUMMY_SP { continue; } let lo = cm.lookup_char_pos(span_label.span.lo); @@ -615,7 +615,7 @@ impl EmitterWriter { let mut max = 0; if let Some(ref cm) = self.cm { for primary_span in msp.primary_spans() { - if primary_span != &DUMMY_SP && primary_span != &COMMAND_LINE_SP { + if primary_span != &DUMMY_SP { let hi = cm.lookup_char_pos(primary_span.hi); if hi.line > max { max = hi.line; @@ -623,7 +623,7 @@ impl EmitterWriter { } } for span_label in msp.span_labels() { - if span_label.span != DUMMY_SP && span_label.span != COMMAND_LINE_SP { + if span_label.span != DUMMY_SP { let hi = cm.lookup_char_pos(span_label.span.hi); if hi.line > max { max = hi.line; @@ -659,20 +659,20 @@ impl EmitterWriter { // First, find all the spans in <*macros> and point instead at their use site for sp in span.primary_spans() { - if (*sp == COMMAND_LINE_SP) || (*sp == DUMMY_SP) { + if *sp == DUMMY_SP { continue; } if cm.span_to_filename(sp.clone()).contains("macros>") { - let v = cm.macro_backtrace(sp.clone()); + let v = sp.macro_backtrace(); if let Some(use_site) = v.last() { before_after.push((sp.clone(), use_site.call_site.clone())); } } - for trace in cm.macro_backtrace(sp.clone()).iter().rev() { + for trace in sp.macro_backtrace().iter().rev() { // Only show macro locations that are local // and display them like a span_note if let Some(def_site) = trace.def_site_span { - if (def_site == COMMAND_LINE_SP) || (def_site == DUMMY_SP) { + if def_site == DUMMY_SP { continue; } // Check to make sure we're not in any <*macros> @@ -689,11 +689,11 @@ impl EmitterWriter { span.push_span_label(label_span, label_text); } for sp_label in span.span_labels() { - if (sp_label.span == COMMAND_LINE_SP) || (sp_label.span == DUMMY_SP) { + if sp_label.span == DUMMY_SP { continue; } if cm.span_to_filename(sp_label.span.clone()).contains("macros>") { - let v = cm.macro_backtrace(sp_label.span.clone()); + let v = sp_label.span.macro_backtrace(); if let Some(use_site) = v.last() { before_after.push((sp_label.span.clone(), use_site.call_site.clone())); } @@ -848,7 +848,7 @@ impl EmitterWriter { // Make sure our primary file comes first let primary_lo = if let (Some(ref cm), Some(ref primary_span)) = (self.cm.as_ref(), msp.primary_span().as_ref()) { - if primary_span != &&DUMMY_SP && primary_span != &&COMMAND_LINE_SP { + if primary_span != &&DUMMY_SP { cm.lookup_char_pos(primary_span.lo) } else { emit_to_destination(&buffer.render(), level, &mut self.dst)?; diff --git a/src/librustc_errors/lib.rs b/src/librustc_errors/lib.rs index 4c889dad8ca..2efdaa57fba 100644 --- a/src/librustc_errors/lib.rs +++ b/src/librustc_errors/lib.rs @@ -48,7 +48,6 @@ pub mod styled_buffer; mod lock; use syntax_pos::{BytePos, Loc, FileLinesResult, FileName, MultiSpan, Span, NO_EXPANSION}; -use syntax_pos::MacroBacktrace; #[derive(Clone, Debug, PartialEq, RustcEncodable, RustcDecodable)] pub enum RenderSpan { @@ -75,7 +74,6 @@ pub trait CodeMapper { fn span_to_lines(&self, sp: Span) -> FileLinesResult; fn span_to_string(&self, sp: Span) -> String; fn span_to_filename(&self, sp: Span) -> FileName; - fn macro_backtrace(&self, span: Span) -> Vec; fn merge_spans(&self, sp_lhs: Span, sp_rhs: Span) -> Option; } @@ -120,7 +118,7 @@ impl CodeSuggestion { let bounding_span = Span { lo: lo, hi: hi, - expn_id: NO_EXPANSION, + ctxt: NO_EXPANSION, }; let lines = cm.span_to_lines(bounding_span).unwrap(); assert!(!lines.lines.is_empty()); diff --git a/src/librustc_incremental/calculate_svh/svh_visitor.rs b/src/librustc_incremental/calculate_svh/svh_visitor.rs index 210803c3f32..5401b371888 100644 --- a/src/librustc_incremental/calculate_svh/svh_visitor.rs +++ b/src/librustc_incremental/calculate_svh/svh_visitor.rs @@ -17,9 +17,10 @@ use self::SawTraitOrImplItemComponent::*; use syntax::abi::Abi; use syntax::ast::{self, Name, NodeId}; use syntax::attr; +use syntax::ext::hygiene::SyntaxContext; use syntax::parse::token; use syntax::symbol::InternedString; -use syntax_pos::{Span, NO_EXPANSION, COMMAND_LINE_EXPN, BytePos}; +use syntax_pos::{Span, BytePos}; use syntax::tokenstream; use rustc::hir; use rustc::hir::*; @@ -92,10 +93,10 @@ impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> { span.hi }; - let expn_kind = match span.expn_id { - NO_EXPANSION => SawSpanExpnKind::NoExpansion, - COMMAND_LINE_EXPN => SawSpanExpnKind::CommandLine, - _ => SawSpanExpnKind::SomeExpansion, + let expn_kind = if span.ctxt == SyntaxContext::empty() { + SawSpanExpnKind::NoExpansion + } else { + SawSpanExpnKind::SomeExpansion }; let loc1 = self.codemap.byte_pos_to_line_and_col(span.lo); @@ -121,8 +122,7 @@ impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> { saw.hash(self.st); if expn_kind == SawSpanExpnKind::SomeExpansion { - let call_site = self.codemap.codemap().source_callsite(span); - self.hash_span(call_site); + self.hash_span(span.source_callsite()); } } @@ -483,7 +483,6 @@ fn saw_impl_item(ii: &ImplItemKind) -> SawTraitOrImplItemComponent { #[derive(Clone, Copy, Hash, Eq, PartialEq)] enum SawSpanExpnKind { NoExpansion, - CommandLine, SomeExpansion, } @@ -501,7 +500,7 @@ impl<'a> Hash for StableInlineAsm<'a> { volatile, alignstack, dialect, - expn_id: _, // This is used for error reporting + ctxt: _, // This is used for error reporting } = *self.0; asm.as_str().hash(state); diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index ba42804c926..9d236bd013c 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -223,7 +223,7 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> { } // This comes from a macro that has #[allow_internal_unstable]. - if self.tcx.sess.codemap().span_allows_unstable(self.span) { + if self.span.allows_unstable() { return; } @@ -805,7 +805,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { self.def_id.is_local() && // this doesn't come from a macro that has #[allow_internal_unstable] - !self.tcx.sess.codemap().span_allows_unstable(self.span) + !self.span.allows_unstable() { let mut err = self.tcx.sess.struct_span_err(self.span, "const fns are an unstable feature"); diff --git a/src/librustc_plugin/load.rs b/src/librustc_plugin/load.rs index efe9963cecc..e884f3bdbb1 100644 --- a/src/librustc_plugin/load.rs +++ b/src/librustc_plugin/load.rs @@ -20,7 +20,7 @@ use std::env; use std::mem; use std::path::PathBuf; use syntax::ast; -use syntax_pos::{Span, COMMAND_LINE_SP}; +use syntax_pos::{Span, DUMMY_SP}; /// Pointer to a registrar function. pub type PluginRegistrarFun = @@ -81,7 +81,7 @@ pub fn load_plugins(sess: &Session, if let Some(plugins) = addl_plugins { for plugin in plugins { - loader.load_plugin(COMMAND_LINE_SP, &plugin, vec![]); + loader.load_plugin(DUMMY_SP, &plugin, vec![]); } } diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index e5c04f6b61e..fd6803e087a 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -690,9 +690,8 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { // Note we take care to use the source callsite/callee, to handle // nested expansions and ensure we only generate data for source-visible // macro uses. - let callsite = self.tcx.sess.codemap().source_callsite(span); - let callee = self.tcx.sess.codemap().source_callee(span); - let callee = option_try!(callee); + let callsite = span.source_callsite(); + let callee = option_try!(span.source_callee()); let callee_span = option_try!(callee.span); // Ignore attribute macros, their spans are usually mangled @@ -1013,5 +1012,5 @@ fn escape(s: String) -> String { // Helper function to determine if a span came from a // macro expansion or syntax extension. pub fn generated_code(span: Span) -> bool { - span.expn_id != NO_EXPANSION || span == DUMMY_SP + span.ctxt != NO_EXPANSION || span == DUMMY_SP } diff --git a/src/librustc_save_analysis/span_utils.rs b/src/librustc_save_analysis/span_utils.rs index 34402742e6c..c19f805a285 100644 --- a/src/librustc_save_analysis/span_utils.rs +++ b/src/librustc_save_analysis/span_utils.rs @@ -462,8 +462,7 @@ impl<'a> SpanUtils<'a> { // Otherwise, a generated span is deemed invalid if it is not a sub-span of the root // callsite. This filters out macro internal variables and most malformed spans. - let span = self.sess.codemap().source_callsite(parent); - !(span.contains(parent)) + !parent.source_callsite().contains(parent) } } diff --git a/src/librustc_trans/asm.rs b/src/librustc_trans/asm.rs index b6195765b27..3e270b7928e 100644 --- a/src/librustc_trans/asm.rs +++ b/src/librustc_trans/asm.rs @@ -111,14 +111,14 @@ pub fn trans_inline_asm<'a, 'tcx>( bcx.store(v, val, None); } - // Store expn_id in a metadata node so we can map LLVM errors + // Store mark in a metadata node so we can map LLVM errors // back to source locations. See #17552. unsafe { let key = "srcloc"; let kind = llvm::LLVMGetMDKindIDInContext(bcx.ccx.llcx(), key.as_ptr() as *const c_char, key.len() as c_uint); - let val: llvm::ValueRef = C_i32(bcx.ccx, ia.expn_id.into_u32() as i32); + let val: llvm::ValueRef = C_i32(bcx.ccx, ia.ctxt.outer().as_u32() as i32); llvm::LLVMSetMetadata(r, kind, llvm::LLVMMDNodeInContext(bcx.ccx.llcx(), &val, 1)); diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs index 5a017e4fb8a..ccb3f7ac882 100644 --- a/src/librustc_trans/back/write.rs +++ b/src/librustc_trans/back/write.rs @@ -371,14 +371,14 @@ struct HandlerFreeVars<'a> { unsafe extern "C" fn report_inline_asm<'a, 'b>(cgcx: &'a CodegenContext<'a>, msg: &'b str, cookie: c_uint) { - use syntax_pos::ExpnId; + use syntax::ext::hygiene::Mark; match cgcx.lto_ctxt { Some((sess, _)) => { - sess.codemap().with_expn_info(ExpnId::from_u32(cookie), |info| match info { + match Mark::from_u32(cookie).expn_info() { Some(ei) => sess.span_err(ei.call_site, msg), None => sess.err(msg), - }); + }; } None => { diff --git a/src/librustc_trans/mir/mod.rs b/src/librustc_trans/mir/mod.rs index 6419f41f86b..21bbbea77d4 100644 --- a/src/librustc_trans/mir/mod.rs +++ b/src/librustc_trans/mir/mod.rs @@ -26,7 +26,7 @@ use monomorphize::{self, Instance}; use abi::FnType; use type_of; -use syntax_pos::{DUMMY_SP, NO_EXPANSION, COMMAND_LINE_EXPN, BytePos, Span}; +use syntax_pos::{DUMMY_SP, NO_EXPANSION, BytePos, Span}; use syntax::symbol::keywords; use std::iter; @@ -124,24 +124,18 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { // In order to have a good line stepping behavior in debugger, we overwrite debug // locations of macro expansions with that of the outermost expansion site // (unless the crate is being compiled with `-Z debug-macros`). - if source_info.span.expn_id == NO_EXPANSION || - source_info.span.expn_id == COMMAND_LINE_EXPN || - self.ccx.sess().opts.debugging_opts.debug_macros { - + if source_info.span.ctxt == NO_EXPANSION || + self.ccx.sess().opts.debugging_opts.debug_macros { let scope = self.scope_metadata_for_loc(source_info.scope, source_info.span.lo); (scope, source_info.span) } else { - let cm = self.ccx.sess().codemap(); // Walk up the macro expansion chain until we reach a non-expanded span. // We also stop at the function body level because no line stepping can occurr // at the level above that. let mut span = source_info.span; - while span.expn_id != NO_EXPANSION && - span.expn_id != COMMAND_LINE_EXPN && - span.expn_id != self.mir.span.expn_id { - if let Some(callsite_span) = cm.with_expn_info(span.expn_id, - |ei| ei.map(|ei| ei.call_site.clone())) { - span = callsite_span; + while span.ctxt != NO_EXPANSION && span.ctxt != self.mir.span.ctxt { + if let Some(info) = span.ctxt.outer().expn_info() { + span = info.call_site; } else { break; } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 9c62fd486d4..b95e01f4ff6 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -4161,12 +4161,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } if let Some(last_stmt) = extra_semi { - let original_span = original_sp(self.tcx.sess.codemap(), - last_stmt.span, blk.span); + let original_span = original_sp(last_stmt.span, blk.span); let span_semi = Span { lo: original_span.hi - BytePos(1), hi: original_span.hi, - expn_id: original_span.expn_id + ctxt: original_span.ctxt, }; err.span_help(span_semi, "consider removing this semicolon:"); } diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 7e2b225193f..a4bebd311de 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -14,10 +14,10 @@ pub use self::TyParamBound::*; pub use self::UnsafeSource::*; pub use self::ViewPath_::*; pub use self::PathParameters::*; -pub use symbol::Symbol as Name; +pub use symbol::{Ident, Symbol as Name}; pub use util::ThinVec; -use syntax_pos::{mk_sp, BytePos, Span, DUMMY_SP, ExpnId}; +use syntax_pos::{mk_sp, BytePos, Span, DUMMY_SP}; use codemap::{respan, Spanned}; use abi::Abi; use ext::hygiene::{Mark, SyntaxContext}; @@ -27,61 +27,12 @@ use rustc_data_structures::indexed_vec; use symbol::{Symbol, keywords}; use tokenstream::{ThinTokenStream, TokenStream}; +use serialize::{self, Encoder, Decoder}; use std::collections::HashSet; use std::fmt; use std::rc::Rc; use std::u32; -use serialize::{self, Encodable, Decodable, Encoder, Decoder}; - -/// An identifier contains a Name (index into the interner -/// table) and a SyntaxContext to track renaming and -/// macro expansion per Flatt et al., "Macros That Work Together" -#[derive(Clone, Copy, PartialEq, Eq, Hash)] -pub struct Ident { - pub name: Symbol, - pub ctxt: SyntaxContext -} - -impl Ident { - pub const fn with_empty_ctxt(name: Name) -> Ident { - Ident { name: name, ctxt: SyntaxContext::empty() } - } - - /// Maps a string to an identifier with an empty syntax context. - pub fn from_str(s: &str) -> Ident { - Ident::with_empty_ctxt(Symbol::intern(s)) - } - - pub fn unhygienize(&self) -> Ident { - Ident { name: self.name, ctxt: SyntaxContext::empty() } - } -} - -impl fmt::Debug for Ident { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}{:?}", self.name, self.ctxt) - } -} - -impl fmt::Display for Ident { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Display::fmt(&self.name, f) - } -} - -impl Encodable for Ident { - fn encode(&self, s: &mut S) -> Result<(), S::Error> { - self.name.encode(s) - } -} - -impl Decodable for Ident { - fn decode(d: &mut D) -> Result { - Ok(Ident::with_empty_ctxt(Name::decode(d)?)) - } -} - #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Copy)] pub struct Lifetime { pub id: NodeId, @@ -1445,7 +1396,7 @@ pub struct InlineAsm { pub volatile: bool, pub alignstack: bool, pub dialect: AsmDialect, - pub expn_id: ExpnId, + pub ctxt: SyntaxContext, } /// An argument in a function header. diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs index 388f3cb7323..ba199eacb62 100644 --- a/src/libsyntax/codemap.rs +++ b/src/libsyntax/codemap.rs @@ -17,6 +17,8 @@ //! within the CodeMap, which upon request can be converted to line and column //! information, source code snippets, etc. +pub use syntax_pos::*; +pub use syntax_pos::hygiene::{ExpnFormat, ExpnInfo, NameAndSpan}; pub use self::ExpnFormat::*; use std::cell::RefCell; @@ -26,35 +28,21 @@ use std::rc::Rc; use std::env; use std::fs; use std::io::{self, Read}; -pub use syntax_pos::*; use errors::CodeMapper; -use ast::Name; - /// Return the span itself if it doesn't come from a macro expansion, /// otherwise return the call site span up to the `enclosing_sp` by /// following the `expn_info` chain. -pub fn original_sp(cm: &CodeMap, sp: Span, enclosing_sp: Span) -> Span { - let call_site1 = cm.with_expn_info(sp.expn_id, |ei| ei.map(|ei| ei.call_site)); - let call_site2 = cm.with_expn_info(enclosing_sp.expn_id, |ei| ei.map(|ei| ei.call_site)); +pub fn original_sp(sp: Span, enclosing_sp: Span) -> Span { + let call_site1 = sp.ctxt.outer().expn_info().map(|ei| ei.call_site); + let call_site2 = enclosing_sp.ctxt.outer().expn_info().map(|ei| ei.call_site); match (call_site1, call_site2) { (None, _) => sp, (Some(call_site1), Some(call_site2)) if call_site1 == call_site2 => sp, - (Some(call_site1), _) => original_sp(cm, call_site1, enclosing_sp), + (Some(call_site1), _) => original_sp(call_site1, enclosing_sp), } } -/// The source of expansion. -#[derive(Clone, Hash, Debug, PartialEq, Eq)] -pub enum ExpnFormat { - /// e.g. #[derive(...)] - MacroAttribute(Name), - /// e.g. `format!()` - MacroBang(Name), - /// Desugaring done by the compiler during HIR lowering. - CompilerDesugaring(Name) -} - #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)] pub struct Spanned { pub node: T, @@ -73,47 +61,6 @@ pub fn dummy_spanned(t: T) -> Spanned { respan(DUMMY_SP, t) } -#[derive(Clone, Hash, Debug)] -pub struct NameAndSpan { - /// The format with which the macro was invoked. - pub format: ExpnFormat, - /// Whether the macro is allowed to use #[unstable]/feature-gated - /// features internally without forcing the whole crate to opt-in - /// to them. - pub allow_internal_unstable: bool, - /// The span of the macro definition itself. The macro may not - /// have a sensible definition span (e.g. something defined - /// completely inside libsyntax) in which case this is None. - pub span: Option -} - -impl NameAndSpan { - pub fn name(&self) -> Name { - match self.format { - ExpnFormat::MacroAttribute(s) | - ExpnFormat::MacroBang(s) | - ExpnFormat::CompilerDesugaring(s) => s, - } - } -} - -/// Extra information for tracking spans of macro and syntax sugar expansion -#[derive(Hash, Debug)] -pub struct ExpnInfo { - /// The location of the actual macro invocation or syntax sugar , e.g. - /// `let x = foo!();` or `if let Some(y) = x {}` - /// - /// This may recursively refer to other macro invocations, e.g. if - /// `foo!()` invoked `bar!()` internally, and there was an - /// expression inside `bar!`; the call_site of the expression in - /// the expansion would point to the `bar!` invocation; that - /// call_site span would have its own ExpnInfo, with the call_site - /// pointing to the `foo!` invocation. - pub call_site: Span, - /// Information about the expansion. - pub callee: NameAndSpan -} - // _____________________________________________________________________________ // FileMap, MultiByteChar, FileName, FileLines // @@ -161,7 +108,6 @@ impl FileLoader for RealFileLoader { pub struct CodeMap { pub files: RefCell>>, - expansions: RefCell>, file_loader: Box } @@ -169,7 +115,6 @@ impl CodeMap { pub fn new() -> CodeMap { CodeMap { files: RefCell::new(Vec::new()), - expansions: RefCell::new(Vec::new()), file_loader: Box::new(RealFileLoader) } } @@ -177,7 +122,6 @@ impl CodeMap { pub fn with_file_loader(file_loader: Box) -> CodeMap { CodeMap { files: RefCell::new(Vec::new()), - expansions: RefCell::new(Vec::new()), file_loader: file_loader } } @@ -353,14 +297,14 @@ impl CodeMap { /// Returns `Some(span)`, a union of the lhs and rhs span. The lhs must precede the rhs. If /// there are gaps between lhs and rhs, the resulting union will cross these gaps. /// For this to work, the spans have to be: - /// * the expn_id of both spans much match + /// * the ctxt of both spans much match /// * the lhs span needs to end on the same line the rhs span begins /// * the lhs span must start at or before the rhs span pub fn merge_spans(&self, sp_lhs: Span, sp_rhs: Span) -> Option { use std::cmp; // make sure we're at the same expansion id - if sp_lhs.expn_id != sp_rhs.expn_id { + if sp_lhs.ctxt != sp_rhs.ctxt { return None; } @@ -383,7 +327,7 @@ impl CodeMap { Some(Span { lo: cmp::min(sp_lhs.lo, sp_rhs.lo), hi: cmp::max(sp_lhs.hi, sp_rhs.hi), - expn_id: sp_lhs.expn_id, + ctxt: sp_lhs.ctxt, }) } else { None @@ -391,10 +335,6 @@ impl CodeMap { } pub fn span_to_string(&self, sp: Span) -> String { - if sp == COMMAND_LINE_SP { - return "".to_string(); - } - if self.files.borrow().is_empty() && sp.source_equal(&DUMMY_SP) { return "no-location".to_string(); } @@ -409,62 +349,6 @@ impl CodeMap { hi.col.to_usize() + 1)).to_string() } - /// Return the source span - this is either the supplied span, or the span for - /// the macro callsite that expanded to it. - pub fn source_callsite(&self, sp: Span) -> Span { - let mut span = sp; - // Special case - if a macro is parsed as an argument to another macro, the source - // callsite is the first callsite, which is also source-equivalent to the span. - let mut first = true; - while span.expn_id != NO_EXPANSION && span.expn_id != COMMAND_LINE_EXPN { - if let Some(callsite) = self.with_expn_info(span.expn_id, - |ei| ei.map(|ei| ei.call_site.clone())) { - if first && span.source_equal(&callsite) { - if self.lookup_char_pos(span.lo).file.is_real_file() { - return Span { expn_id: NO_EXPANSION, .. span }; - } - } - first = false; - span = callsite; - } - else { - break; - } - } - span - } - - /// Return the source callee. - /// - /// Returns None if the supplied span has no expansion trace, - /// else returns the NameAndSpan for the macro definition - /// corresponding to the source callsite. - pub fn source_callee(&self, sp: Span) -> Option { - let mut span = sp; - // Special case - if a macro is parsed as an argument to another macro, the source - // callsite is source-equivalent to the span, and the source callee is the first callee. - let mut first = true; - while let Some(callsite) = self.with_expn_info(span.expn_id, - |ei| ei.map(|ei| ei.call_site.clone())) { - if first && span.source_equal(&callsite) { - if self.lookup_char_pos(span.lo).file.is_real_file() { - return self.with_expn_info(span.expn_id, - |ei| ei.map(|ei| ei.callee.clone())); - } - } - first = false; - if let Some(_) = self.with_expn_info(callsite.expn_id, - |ei| ei.map(|ei| ei.call_site.clone())) { - span = callsite; - } - else { - return self.with_expn_info(span.expn_id, - |ei| ei.map(|ei| ei.callee.clone())); - } - } - None - } - pub fn span_to_filename(&self, sp: Span) -> FileName { self.lookup_char_pos(sp.lo).file.name.to_string() } @@ -628,111 +512,9 @@ impl CodeMap { return a; } - pub fn record_expansion(&self, expn_info: ExpnInfo) -> ExpnId { - let mut expansions = self.expansions.borrow_mut(); - expansions.push(expn_info); - let len = expansions.len(); - if len > u32::max_value() as usize { - panic!("too many ExpnInfo's!"); - } - ExpnId(len as u32 - 1) - } - - pub fn with_expn_info(&self, id: ExpnId, f: F) -> T where - F: FnOnce(Option<&ExpnInfo>) -> T, - { - match id { - NO_EXPANSION | COMMAND_LINE_EXPN => f(None), - ExpnId(i) => f(Some(&(*self.expansions.borrow())[i as usize])) - } - } - - /// Check if a span is "internal" to a macro in which #[unstable] - /// items can be used (that is, a macro marked with - /// `#[allow_internal_unstable]`). - pub fn span_allows_unstable(&self, span: Span) -> bool { - debug!("span_allows_unstable(span = {:?})", span); - let mut allows_unstable = false; - let mut expn_id = span.expn_id; - loop { - let quit = self.with_expn_info(expn_id, |expninfo| { - debug!("span_allows_unstable: expninfo = {:?}", expninfo); - expninfo.map_or(/* hit the top level */ true, |info| { - - let span_comes_from_this_expansion = - info.callee.span.map_or(span.source_equal(&info.call_site), |mac_span| { - mac_span.contains(span) - }); - - debug!("span_allows_unstable: span: {:?} call_site: {:?} callee: {:?}", - (span.lo, span.hi), - (info.call_site.lo, info.call_site.hi), - info.callee.span.map(|x| (x.lo, x.hi))); - debug!("span_allows_unstable: from this expansion? {}, allows unstable? {}", - span_comes_from_this_expansion, - info.callee.allow_internal_unstable); - if span_comes_from_this_expansion { - allows_unstable = info.callee.allow_internal_unstable; - // we've found the right place, stop looking - true - } else { - // not the right place, keep looking - expn_id = info.call_site.expn_id; - false - } - }) - }); - if quit { - break - } - } - debug!("span_allows_unstable? {}", allows_unstable); - allows_unstable - } - pub fn count_lines(&self) -> usize { self.files.borrow().iter().fold(0, |a, f| a + f.count_lines()) } - - pub fn macro_backtrace(&self, span: Span) -> Vec { - let mut prev_span = DUMMY_SP; - let mut span = span; - let mut result = vec![]; - loop { - let span_name_span = self.with_expn_info(span.expn_id, |expn_info| { - expn_info.map(|ei| { - let (pre, post) = match ei.callee.format { - MacroAttribute(..) => ("#[", "]"), - MacroBang(..) => ("", "!"), - CompilerDesugaring(..) => ("desugaring of `", "`"), - }; - let macro_decl_name = format!("{}{}{}", - pre, - ei.callee.name(), - post); - let def_site_span = ei.callee.span; - (ei.call_site, macro_decl_name, def_site_span) - }) - }); - - match span_name_span { - None => break, - Some((call_site, macro_decl_name, def_site_span)) => { - // Don't print recursive invocations - if !call_site.source_equal(&prev_span) { - result.push(MacroBacktrace { - call_site: call_site, - macro_decl_name: macro_decl_name, - def_site_span: def_site_span, - }); - } - prev_span = span; - span = call_site; - } - } - } - result - } } impl CodeMapper for CodeMap { @@ -748,9 +530,6 @@ impl CodeMapper for CodeMap { fn span_to_filename(&self, sp: Span) -> FileName { self.span_to_filename(sp) } - fn macro_backtrace(&self, span: Span) -> Vec { - self.macro_backtrace(span) - } fn merge_spans(&self, sp_lhs: Span, sp_rhs: Span) -> Option { self.merge_spans(sp_lhs, sp_rhs) } @@ -763,7 +542,6 @@ impl CodeMapper for CodeMap { #[cfg(test)] mod tests { use super::*; - use symbol::keywords; use std::rc::Rc; #[test] @@ -912,7 +690,7 @@ mod tests { fn t7() { // Test span_to_lines for a span ending at the end of filemap let cm = init_code_map(); - let span = Span {lo: BytePos(12), hi: BytePos(23), expn_id: NO_EXPANSION}; + let span = Span {lo: BytePos(12), hi: BytePos(23), ctxt: NO_EXPANSION}; let file_lines = cm.span_to_lines(span).unwrap(); assert_eq!(file_lines.file.name, "blork.rs"); @@ -928,7 +706,7 @@ mod tests { assert_eq!(input.len(), selection.len()); let left_index = selection.find('~').unwrap() as u32; let right_index = selection.rfind('~').map(|x|x as u32).unwrap_or(left_index); - Span { lo: BytePos(left_index), hi: BytePos(right_index + 1), expn_id: NO_EXPANSION } + Span { lo: BytePos(left_index), hi: BytePos(right_index + 1), ctxt: NO_EXPANSION } } /// Test span_to_snippet and span_to_lines for a span coverting 3 @@ -958,7 +736,7 @@ mod tests { fn t8() { // Test span_to_snippet for a span ending at the end of filemap let cm = init_code_map(); - let span = Span {lo: BytePos(12), hi: BytePos(23), expn_id: NO_EXPANSION}; + let span = Span {lo: BytePos(12), hi: BytePos(23), ctxt: NO_EXPANSION}; let snippet = cm.span_to_snippet(span); assert_eq!(snippet, Ok("second line".to_string())); @@ -968,7 +746,7 @@ mod tests { fn t9() { // Test span_to_str for a span ending at the end of filemap let cm = init_code_map(); - let span = Span {lo: BytePos(12), hi: BytePos(23), expn_id: NO_EXPANSION}; + let span = Span {lo: BytePos(12), hi: BytePos(23), ctxt: NO_EXPANSION}; let sstr = cm.span_to_string(span); assert_eq!(sstr, "blork.rs:2:1: 2:12"); @@ -1022,7 +800,7 @@ mod tests { let span = Span { lo: BytePos(lo as u32 + file.start_pos.0), hi: BytePos(hi as u32 + file.start_pos.0), - expn_id: NO_EXPANSION, + ctxt: NO_EXPANSION, }; assert_eq!(&self.span_to_snippet(span).unwrap()[..], substring); @@ -1032,45 +810,4 @@ mod tests { } } } - - fn init_expansion_chain(cm: &CodeMap) -> Span { - // Creates an expansion chain containing two recursive calls - // root -> expA -> expA -> expB -> expB -> end - let root = Span { lo: BytePos(0), hi: BytePos(11), expn_id: NO_EXPANSION }; - - let format_root = ExpnFormat::MacroBang(keywords::Invalid.name()); - let callee_root = NameAndSpan { format: format_root, - allow_internal_unstable: false, - span: Some(root) }; - - let info_a1 = ExpnInfo { call_site: root, callee: callee_root }; - let id_a1 = cm.record_expansion(info_a1); - let span_a1 = Span { lo: BytePos(12), hi: BytePos(23), expn_id: id_a1 }; - - let format_a = ExpnFormat::MacroBang(keywords::As.name()); - let callee_a = NameAndSpan { format: format_a, - allow_internal_unstable: false, - span: Some(span_a1) }; - - let info_a2 = ExpnInfo { call_site: span_a1, callee: callee_a.clone() }; - let id_a2 = cm.record_expansion(info_a2); - let span_a2 = Span { lo: BytePos(12), hi: BytePos(23), expn_id: id_a2 }; - - let info_b1 = ExpnInfo { call_site: span_a2, callee: callee_a }; - let id_b1 = cm.record_expansion(info_b1); - let span_b1 = Span { lo: BytePos(25), hi: BytePos(36), expn_id: id_b1 }; - - let format_b = ExpnFormat::MacroBang(keywords::Box.name()); - let callee_b = NameAndSpan { format: format_b, - allow_internal_unstable: false, - span: None }; - - let info_b2 = ExpnInfo { call_site: span_b1, callee: callee_b.clone() }; - let id_b2 = cm.record_expansion(info_b2); - let span_b2 = Span { lo: BytePos(25), hi: BytePos(36), expn_id: id_b2 }; - - let info_end = ExpnInfo { call_site: span_b2, callee: callee_b }; - let id_end = cm.record_expansion(info_end); - Span { lo: BytePos(37), hi: BytePos(48), expn_id: id_end } - } } diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index dc7e7673eb0..a2d54b62ec6 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -12,11 +12,11 @@ pub use self::SyntaxExtension::{MultiDecorator, MultiModifier, NormalTT, IdentTT use ast::{self, Attribute, Name, PatKind, MetaItem}; use attr::HasAttrs; -use codemap::{self, CodeMap, ExpnInfo, Spanned, respan}; -use syntax_pos::{Span, ExpnId, NO_EXPANSION}; -use errors::{DiagnosticBuilder, FatalError}; +use codemap::{self, CodeMap, Spanned, respan}; +use syntax_pos::{Span, DUMMY_SP}; +use errors::DiagnosticBuilder; use ext::expand::{self, Expansion, Invocation}; -use ext::hygiene::Mark; +use ext::hygiene::{Mark, SyntaxContext}; use fold::{self, Folder}; use parse::{self, parser, DirectoryOwnership}; use parse::token; @@ -56,6 +56,14 @@ impl HasAttrs for Annotatable { } impl Annotatable { + pub fn span(&self) -> Span { + match *self { + Annotatable::Item(ref item) => item.span, + Annotatable::TraitItem(ref trait_item) => trait_item.span, + Annotatable::ImplItem(ref impl_item) => impl_item.span, + } + } + pub fn expect_item(self) -> P { match self { Annotatable::Item(i) => i, @@ -602,7 +610,6 @@ pub struct ModuleData { pub struct ExpansionData { pub mark: Mark, pub depth: usize, - pub backtrace: ExpnId, pub module: Rc, pub directory_ownership: DirectoryOwnership, } @@ -633,7 +640,6 @@ impl<'a> ExtCtxt<'a> { current_expansion: ExpansionData { mark: Mark::root(), depth: 0, - backtrace: NO_EXPANSION, module: Rc::new(ModuleData { mod_path: Vec::new(), directory: PathBuf::new() }), directory_ownership: DirectoryOwnership::Owned, }, @@ -658,30 +664,30 @@ impl<'a> ExtCtxt<'a> { pub fn parse_sess(&self) -> &'a parse::ParseSess { self.parse_sess } pub fn cfg(&self) -> &ast::CrateConfig { &self.parse_sess.config } pub fn call_site(&self) -> Span { - self.codemap().with_expn_info(self.backtrace(), |ei| match ei { + match self.current_expansion.mark.expn_info() { Some(expn_info) => expn_info.call_site, - None => self.bug("missing top span") - }) + None => DUMMY_SP, + } + } + pub fn backtrace(&self) -> SyntaxContext { + SyntaxContext::empty().apply_mark(self.current_expansion.mark) } - pub fn backtrace(&self) -> ExpnId { self.current_expansion.backtrace } /// Returns span for the macro which originally caused the current expansion to happen. /// /// Stops backtracing at include! boundary. pub fn expansion_cause(&self) -> Span { - let mut expn_id = self.backtrace(); + let mut ctxt = self.backtrace(); let mut last_macro = None; loop { - if self.codemap().with_expn_info(expn_id, |info| { - info.map_or(None, |i| { - if i.callee.name() == "include" { - // Stop going up the backtrace once include! is encountered - return None; - } - expn_id = i.call_site.expn_id; - last_macro = Some(i.call_site); - return Some(()); - }) + if ctxt.outer().expn_info().map_or(None, |info| { + if info.callee.name() == "include" { + // Stop going up the backtrace once include! is encountered + return None; + } + ctxt = info.call_site.ctxt; + last_macro = Some(info.call_site); + return Some(()); }).is_none() { break } @@ -689,28 +695,6 @@ impl<'a> ExtCtxt<'a> { last_macro.expect("missing expansion backtrace") } - pub fn bt_push(&mut self, ei: ExpnInfo) { - if self.current_expansion.depth > self.ecfg.recursion_limit { - let suggested_limit = self.ecfg.recursion_limit * 2; - let mut err = self.struct_span_fatal(ei.call_site, - &format!("recursion limit reached while expanding the macro `{}`", - ei.callee.name())); - err.help(&format!( - "consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate", - suggested_limit)); - err.emit(); - panic!(FatalError); - } - - let mut call_site = ei.call_site; - call_site.expn_id = self.backtrace(); - self.current_expansion.backtrace = self.codemap().record_expansion(ExpnInfo { - call_site: call_site, - callee: ei.callee - }); - } - pub fn bt_pop(&mut self) {} - pub fn struct_span_warn(&self, sp: Span, msg: &str) @@ -792,9 +776,9 @@ impl<'a> ExtCtxt<'a> { /// compilation on error, merely emits a non-fatal error and returns None. pub fn expr_to_spanned_string(cx: &mut ExtCtxt, expr: P, err_msg: &str) -> Option> { - // Update `expr.span`'s expn_id now in case expr is an `include!` macro invocation. + // Update `expr.span`'s ctxt now in case expr is an `include!` macro invocation. let expr = expr.map(|mut expr| { - expr.span.expn_id = cx.backtrace(); + expr.span.ctxt = expr.span.ctxt.apply_mark(cx.current_expansion.mark); expr }); diff --git a/src/libsyntax/ext/derive.rs b/src/libsyntax/ext/derive.rs index 1569d9f540b..c79040424f6 100644 --- a/src/libsyntax/ext/derive.rs +++ b/src/libsyntax/ext/derive.rs @@ -9,13 +9,16 @@ // except according to those terms. use attr::HasAttrs; -use {ast, codemap}; +use ast; +use codemap::{ExpnInfo, NameAndSpan, ExpnFormat}; use ext::base::ExtCtxt; use ext::build::AstBuilder; use parse::parser::PathStyle; use symbol::Symbol; use syntax_pos::Span; +use std::collections::HashSet; + pub fn collect_derives(cx: &mut ExtCtxt, attrs: &mut Vec) -> Vec { let mut result = Vec::new(); attrs.retain(|attr| { @@ -41,36 +44,35 @@ pub fn collect_derives(cx: &mut ExtCtxt, attrs: &mut Vec) -> Vec result } -fn allow_unstable(cx: &mut ExtCtxt, span: Span, attr_name: &str) -> Span { - Span { - expn_id: cx.codemap().record_expansion(codemap::ExpnInfo { - call_site: span, - callee: codemap::NameAndSpan { - format: codemap::MacroAttribute(Symbol::intern(attr_name)), - span: Some(span), - allow_internal_unstable: true, - }, - }), - ..span +pub fn add_derived_markers(cx: &mut ExtCtxt, span: Span, traits: &[ast::Path], item: T) -> T + where T: HasAttrs, +{ + let (mut names, mut pretty_name) = (HashSet::new(), "derive(".to_owned()); + for (i, path) in traits.iter().enumerate() { + if i > 0 { + pretty_name.push_str(", "); + } + pretty_name.push_str(&path.to_string()); + names.insert(unwrap_or!(path.segments.get(0), continue).identifier.name); } -} + pretty_name.push(')'); -pub fn add_derived_markers(cx: &mut ExtCtxt, traits: &[ast::Path], item: T) -> T { - let span = match traits.get(0) { - Some(path) => path.span, - None => return item, - }; + cx.current_expansion.mark.set_expn_info(ExpnInfo { + call_site: span, + callee: NameAndSpan { + format: ExpnFormat::MacroAttribute(Symbol::intern(&pretty_name)), + span: None, + allow_internal_unstable: true, + }, + }); + let span = Span { ctxt: cx.backtrace(), ..span }; item.map_attrs(|mut attrs| { - if traits.iter().any(|path| *path == "PartialEq") && - traits.iter().any(|path| *path == "Eq") { - let span = allow_unstable(cx, span, "derive(PartialEq, Eq)"); + if names.contains(&Symbol::intern("Eq")) && names.contains(&Symbol::intern("PartialEq")) { let meta = cx.meta_word(span, Symbol::intern("structural_match")); attrs.push(cx.attribute(span, meta)); } - if traits.iter().any(|path| *path == "Copy") && - traits.iter().any(|path| *path == "Clone") { - let span = allow_unstable(cx, span, "derive(Copy, Clone)"); + if names.contains(&Symbol::intern("Copy")) && names.contains(&Symbol::intern("Clone")) { let meta = cx.meta_word(span, Symbol::intern("rustc_copy_clone_marker")); attrs.push(cx.attribute(span, meta)); } diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index e258c51a329..1b3352f73ad 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -13,6 +13,7 @@ use ast::{MacStmtStyle, StmtKind, ItemKind}; use attr::{self, HasAttrs}; use codemap::{ExpnInfo, NameAndSpan, MacroBang, MacroAttribute}; use config::{is_test_or_bench, StripUnconfigured}; +use errors::FatalError; use ext::base::*; use ext::derive::{add_derived_markers, collect_derives}; use ext::hygiene::Mark; @@ -27,7 +28,7 @@ use ptr::P; use std_inject; use symbol::Symbol; use symbol::keywords; -use syntax_pos::{Span, ExpnId, DUMMY_SP}; +use syntax_pos::{Span, DUMMY_SP}; use tokenstream::TokenStream; use util::small_vector::SmallVector; use visit::Visitor; @@ -273,7 +274,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { let item = item .map_attrs(|mut attrs| { attrs.retain(|a| a.path != "derive"); attrs }); let item_with_markers = - add_derived_markers(&mut self.cx, &traits, item.clone()); + add_derived_markers(&mut self.cx, item.span(), &traits, item.clone()); let derives = derives.entry(invoc.expansion_data.mark).or_insert_with(Vec::new); for path in &traits { @@ -363,11 +364,26 @@ impl<'a, 'b> MacroExpander<'a, 'b> { } fn expand_invoc(&mut self, invoc: Invocation, ext: Rc) -> Expansion { - match invoc.kind { + let result = match invoc.kind { InvocationKind::Bang { .. } => self.expand_bang_invoc(invoc, ext), InvocationKind::Attr { .. } => self.expand_attr_invoc(invoc, ext), InvocationKind::Derive { .. } => self.expand_derive_invoc(invoc, ext), + }; + + if self.cx.current_expansion.depth > self.cx.ecfg.recursion_limit { + let info = self.cx.current_expansion.mark.expn_info().unwrap(); + let suggested_limit = self.cx.ecfg.recursion_limit * 2; + let mut err = self.cx.struct_span_fatal(info.call_site, + &format!("recursion limit reached while expanding the macro `{}`", + info.callee.name())); + err.help(&format!( + "consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate", + suggested_limit)); + err.emit(); + panic!(FatalError); } + + result } fn expand_attr_invoc(&mut self, invoc: Invocation, ext: Rc) -> Expansion { @@ -378,11 +394,11 @@ impl<'a, 'b> MacroExpander<'a, 'b> { }; attr::mark_used(&attr); - self.cx.bt_push(ExpnInfo { + invoc.expansion_data.mark.set_expn_info(ExpnInfo { call_site: attr.span, callee: NameAndSpan { format: MacroAttribute(Symbol::intern(&format!("{}", attr.path))), - span: Some(attr.span), + span: None, allow_internal_unstable: false, } }); @@ -403,19 +419,8 @@ impl<'a, 'b> MacroExpander<'a, 'b> { SyntaxExtension::AttrProcMacro(ref mac) => { let item_toks = stream_for_item(&item, &self.cx.parse_sess); - let span = Span { - expn_id: self.cx.codemap().record_expansion(ExpnInfo { - call_site: attr.span, - callee: NameAndSpan { - format: MacroAttribute(Symbol::intern(&format!("{}", attr.path))), - span: None, - allow_internal_unstable: false, - }, - }), - ..attr.span - }; - - let tok_result = mac.expand(self.cx, attr.span, attr.tokens.clone(), item_toks); + let span = Span { ctxt: self.cx.backtrace(), ..attr.span }; + let tok_result = mac.expand(self.cx, attr.span, attr.tokens, item_toks); self.parse_expansion(tok_result, kind, &attr.path, span) } SyntaxExtension::ProcMacroDerive(..) | SyntaxExtension::BuiltinDerive(..) => { @@ -440,8 +445,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { let path = &mac.node.path; let ident = ident.unwrap_or(keywords::Invalid.ident()); - let marked_tts = - noop_fold_tts(mac.node.stream(), &mut Marker { mark: mark, expn_id: None }); + let marked_tts = noop_fold_tts(mac.node.stream(), &mut Marker(mark)); let opt_expanded = match *ext { NormalTT(ref expandfun, exp_span, allow_internal_unstable) => { if ident.name != keywords::Invalid.name() { @@ -451,7 +455,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { return kind.dummy(span); } - self.cx.bt_push(ExpnInfo { + invoc.expansion_data.mark.set_expn_info(ExpnInfo { call_site: span, callee: NameAndSpan { format: MacroBang(Symbol::intern(&format!("{}", path))), @@ -470,7 +474,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { return kind.dummy(span); }; - self.cx.bt_push(ExpnInfo { + invoc.expansion_data.mark.set_expn_info(ExpnInfo { call_site: span, callee: NameAndSpan { format: MacroBang(Symbol::intern(&format!("{}", path))), @@ -502,7 +506,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { return kind.dummy(span); } - self.cx.bt_push(ExpnInfo { + invoc.expansion_data.mark.set_expn_info(ExpnInfo { call_site: span, callee: NameAndSpan { format: MacroBang(Symbol::intern(&format!("{}", path))), @@ -528,10 +532,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { return kind.dummy(span); }; - expanded.fold_with(&mut Marker { - mark: mark, - expn_id: Some(self.cx.backtrace()), - }) + expanded.fold_with(&mut Marker(mark)) } /// Expand a derive invocation. Returns the result of expansion. @@ -550,50 +551,33 @@ impl<'a, 'b> MacroExpander<'a, 'b> { id: ast::AttrId(0), style: ast::AttrStyle::Outer, is_sugared_doc: false, }; - self.cx.bt_push(ExpnInfo { + let mut expn_info = ExpnInfo { call_site: span, callee: NameAndSpan { format: MacroAttribute(pretty_name), span: None, allow_internal_unstable: false, } - }); + }; match *ext { SyntaxExtension::ProcMacroDerive(ref ext, _) => { - let span = Span { - expn_id: self.cx.codemap().record_expansion(ExpnInfo { - call_site: span, - callee: NameAndSpan { - format: MacroAttribute(pretty_name), - span: None, - allow_internal_unstable: false, - }, - }), - ..span - }; + invoc.expansion_data.mark.set_expn_info(expn_info); + let span = Span { ctxt: self.cx.backtrace(), ..span }; let dummy = ast::MetaItem { // FIXME(jseyfried) avoid this name: keywords::Invalid.name(), span: DUMMY_SP, node: ast::MetaItemKind::Word, }; - return kind.expect_from_annotatables(ext.expand(self.cx, span, &dummy, item)); + kind.expect_from_annotatables(ext.expand(self.cx, span, &dummy, item)) } SyntaxExtension::BuiltinDerive(func) => { - let span = Span { - expn_id: self.cx.codemap().record_expansion(ExpnInfo { - call_site: span, - callee: NameAndSpan { - format: MacroAttribute(pretty_name), - span: None, - allow_internal_unstable: true, - }, - }), - ..span - }; + expn_info.callee.allow_internal_unstable = true; + invoc.expansion_data.mark.set_expn_info(expn_info); + let span = Span { ctxt: self.cx.backtrace(), ..span }; let mut items = Vec::new(); func(self.cx, span, &attr.meta().unwrap(), &item, &mut |a| items.push(a)); - return kind.expect_from_annotatables(items); + kind.expect_from_annotatables(items) } _ => { let msg = &format!("macro `{}` may not be used for derive attributes", attr.path); @@ -753,10 +737,9 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { // Detect use of feature-gated or invalid attributes on macro invocations // since they will not be detected after macro expansion. fn check_attributes(&mut self, attrs: &[ast::Attribute]) { - let codemap = &self.cx.parse_sess.codemap(); let features = self.cx.ecfg.features.unwrap(); for attr in attrs.iter() { - feature_gate::check_attribute(&attr, &self.cx.parse_sess, codemap, features); + feature_gate::check_attribute(&attr, &self.cx.parse_sess, features); } } } @@ -1065,23 +1048,21 @@ impl<'feat> ExpansionConfig<'feat> { } } -// A Marker adds the given mark to the syntax context and -// sets spans' `expn_id` to the given expn_id (unless it is `None`). -struct Marker { mark: Mark, expn_id: Option } +// A Marker adds the given mark to the syntax context. +struct Marker(Mark); impl Folder for Marker { fn fold_ident(&mut self, mut ident: Ident) -> Ident { - ident.ctxt = ident.ctxt.apply_mark(self.mark); + ident.ctxt = ident.ctxt.apply_mark(self.0); ident } - fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac { - noop_fold_mac(mac, self) - } fn new_span(&mut self, mut span: Span) -> Span { - if let Some(expn_id) = self.expn_id { - span.expn_id = expn_id; - } + span.ctxt = span.ctxt.apply_mark(self.0); span } + + fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac { + noop_fold_mac(mac, self) + } } diff --git a/src/libsyntax/ext/source_util.rs b/src/libsyntax/ext/source_util.rs index 39b92c7d007..0103d6ea959 100644 --- a/src/libsyntax/ext/source_util.rs +++ b/src/libsyntax/ext/source_util.rs @@ -185,7 +185,7 @@ pub fn expand_include_bytes(cx: &mut ExtCtxt, sp: Span, tts: &[tokenstream::Toke fn res_rel_file(cx: &mut ExtCtxt, sp: syntax_pos::Span, arg: &Path) -> PathBuf { // NB: relative paths are resolved relative to the compilation unit if !arg.is_absolute() { - let callsite = cx.codemap().source_callsite(sp); + let callsite = sp.source_callsite(); let mut cu = PathBuf::from(&cx.codemap().span_to_filename(callsite)); cu.pop(); cu.push(arg); diff --git a/src/libsyntax/ext/tt/quoted.rs b/src/libsyntax/ext/tt/quoted.rs index d56859d805c..12e746e024d 100644 --- a/src/libsyntax/ext/tt/quoted.rs +++ b/src/libsyntax/ext/tt/quoted.rs @@ -34,17 +34,19 @@ impl Delimited { } pub fn open_tt(&self, span: Span) -> TokenTree { - let open_span = match span { - DUMMY_SP => DUMMY_SP, - _ => Span { hi: span.lo + BytePos(self.delim.len() as u32), ..span }, + let open_span = if span == DUMMY_SP { + DUMMY_SP + } else { + Span { hi: span.lo + BytePos(self.delim.len() as u32), ..span } }; TokenTree::Token(open_span, self.open_token()) } pub fn close_tt(&self, span: Span) -> TokenTree { - let close_span = match span { - DUMMY_SP => DUMMY_SP, - _ => Span { lo: span.hi - BytePos(self.delim.len() as u32), ..span }, + let close_span = if span == DUMMY_SP { + DUMMY_SP + } else { + Span { lo: span.hi - BytePos(self.delim.len() as u32), ..span } }; TokenTree::Token(close_span, self.close_token()) } diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 9d280a413e6..12d25ca4274 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -28,7 +28,7 @@ use self::AttributeGate::*; use abi::Abi; use ast::{self, NodeId, PatKind, RangeEnd}; use attr; -use codemap::{CodeMap, Spanned}; +use codemap::Spanned; use syntax_pos::Span; use errors::{DiagnosticBuilder, Handler, FatalError}; use visit::{self, FnKind, Visitor}; @@ -831,7 +831,7 @@ impl GatedCfg { pub fn check_and_emit(&self, sess: &ParseSess, features: &Features) { let (cfg, feature, has_feature) = GATED_CFGS[self.index]; - if !has_feature(features) && !sess.codemap().span_allows_unstable(self.span) { + if !has_feature(features) && !self.span.allows_unstable() { let explain = format!("`cfg({})` is experimental and subject to change", cfg); emit_feature_err(sess, feature, self.span, GateIssue::Language, &explain); } @@ -841,7 +841,6 @@ impl GatedCfg { struct Context<'a> { features: &'a Features, parse_sess: &'a ParseSess, - cm: &'a CodeMap, plugin_attributes: &'a [(String, AttributeType)], } @@ -850,7 +849,7 @@ macro_rules! gate_feature_fn { let (cx, has_feature, span, name, explain) = ($cx, $has_feature, $span, $name, $explain); let has_feature: bool = has_feature(&$cx.features); debug!("gate_feature(feature = {:?}, span = {:?}); has? {}", name, span, has_feature); - if !has_feature && !cx.cm.span_allows_unstable(span) { + if !has_feature && !span.allows_unstable() { emit_feature_err(cx.parse_sess, name, span, GateIssue::Language, explain); } }} @@ -908,12 +907,8 @@ impl<'a> Context<'a> { } } -pub fn check_attribute(attr: &ast::Attribute, parse_sess: &ParseSess, - cm: &CodeMap, features: &Features) { - let cx = Context { - features: features, parse_sess: parse_sess, - cm: cm, plugin_attributes: &[] - }; +pub fn check_attribute(attr: &ast::Attribute, parse_sess: &ParseSess, features: &Features) { + let cx = Context { features: features, parse_sess: parse_sess, plugin_attributes: &[] }; cx.check_attribute(attr, true); } @@ -1016,7 +1011,7 @@ struct PostExpansionVisitor<'a> { macro_rules! gate_feature_post { ($cx: expr, $feature: ident, $span: expr, $explain: expr) => {{ let (cx, span) = ($cx, $span); - if !cx.context.cm.span_allows_unstable(span) { + if !span.allows_unstable() { gate_feature!(cx.context, $feature, span, $explain) } }} @@ -1096,7 +1091,7 @@ fn starts_with_digit(s: &str) -> bool { impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { fn visit_attribute(&mut self, attr: &ast::Attribute) { - if !self.context.cm.span_allows_unstable(attr.span) { + if !attr.span.allows_unstable() { // check for gated attributes self.context.check_attribute(attr, false); } @@ -1530,7 +1525,6 @@ pub fn check_crate(krate: &ast::Crate, let ctx = Context { features: features, parse_sess: sess, - cm: sess.codemap(), plugin_attributes: plugin_attributes, }; visit::walk_crate(&mut PostExpansionVisitor { context: &ctx }, krate); diff --git a/src/libsyntax/json.rs b/src/libsyntax/json.rs index fd762552248..dec1b7d1d87 100644 --- a/src/libsyntax/json.rs +++ b/src/libsyntax/json.rs @@ -202,7 +202,7 @@ impl DiagnosticSpan { // backtrace ourselves, but the `macro_backtrace` helper makes // some decision, such as dropping some frames, and I don't // want to duplicate that logic here. - let backtrace = je.cm.macro_backtrace(span).into_iter(); + let backtrace = span.macro_backtrace().into_iter(); DiagnosticSpan::from_span_full(span, is_primary, label, diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index 6c975f3fc40..86ee1c5336d 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -125,7 +125,7 @@ pub mod ptr; pub mod show_span; pub mod std_inject; pub mod str; -pub mod symbol; +pub use syntax_pos::symbol; pub mod test; pub mod tokenstream; pub mod visit; diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 43a9d8c5f78..e9eb4fbcc91 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -5036,11 +5036,7 @@ impl<'a> Parser<'a> { the path:", path); self.expect(&token::CloseDelim(token::Paren))?; // `)` - let sp = Span { - lo: start_span.lo, - hi: self.prev_span.hi, - expn_id: start_span.expn_id, - }; + let sp = start_span.to(self.prev_span); let mut err = self.span_fatal_help(sp, &msg, &suggestion); err.span_suggestion(path_span, &help_msg, format!("in {}", path)); err.emit(); // emit diagnostic, but continue with public visibility diff --git a/src/libsyntax/std_inject.rs b/src/libsyntax/std_inject.rs index c541df9230a..c7820a15fb3 100644 --- a/src/libsyntax/std_inject.rs +++ b/src/libsyntax/std_inject.rs @@ -10,29 +10,27 @@ use ast; use attr; +use ext::hygiene::{Mark, SyntaxContext}; use symbol::{Symbol, keywords}; use syntax_pos::{DUMMY_SP, Span}; use codemap::{self, ExpnInfo, NameAndSpan, MacroAttribute}; -use parse::ParseSess; use ptr::P; use tokenstream::TokenStream; /// Craft a span that will be ignored by the stability lint's /// call to codemap's is_internal check. /// The expanded code uses the unstable `#[prelude_import]` attribute. -fn ignored_span(sess: &ParseSess, sp: Span) -> Span { - let info = ExpnInfo { +fn ignored_span(sp: Span) -> Span { + let mark = Mark::fresh(); + mark.set_expn_info(ExpnInfo { call_site: DUMMY_SP, callee: NameAndSpan { format: MacroAttribute(Symbol::intern("std_inject")), span: None, allow_internal_unstable: true, } - }; - let expn_id = sess.codemap().record_expansion(info); - let mut sp = sp; - sp.expn_id = expn_id; - return sp; + }); + Span { ctxt: SyntaxContext::empty().apply_mark(mark), ..sp } } pub fn injected_crate_name(krate: &ast::Crate) -> Option<&'static str> { @@ -45,10 +43,7 @@ pub fn injected_crate_name(krate: &ast::Crate) -> Option<&'static str> { } } -pub fn maybe_inject_crates_ref(sess: &ParseSess, - mut krate: ast::Crate, - alt_std_name: Option) - -> ast::Crate { +pub fn maybe_inject_crates_ref(mut krate: ast::Crate, alt_std_name: Option) -> ast::Crate { let name = match injected_crate_name(&krate) { Some(name) => name, None => return krate, @@ -67,7 +62,7 @@ pub fn maybe_inject_crates_ref(sess: &ParseSess, span: DUMMY_SP, })); - let span = ignored_span(sess, DUMMY_SP); + let span = ignored_span(DUMMY_SP); krate.module.items.insert(0, P(ast::Item { attrs: vec![ast::Attribute { style: ast::AttrStyle::Outer, diff --git a/src/libsyntax/symbol.rs b/src/libsyntax/symbol.rs deleted file mode 100644 index 2acbeee426b..00000000000 --- a/src/libsyntax/symbol.rs +++ /dev/null @@ -1,342 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! An "interner" is a data structure that associates values with usize tags and -//! allows bidirectional lookup; i.e. given a value, one can easily find the -//! type, and vice versa. - -use serialize::{Decodable, Decoder, Encodable, Encoder}; -use std::cell::RefCell; -use std::collections::HashMap; -use std::fmt; - -/// A symbol is an interned or gensymed string. -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct Symbol(u32); - -// The interner in thread-local, so `Symbol` shouldn't move between threads. -impl !Send for Symbol { } - -impl Symbol { - /// Maps a string to its interned representation. - pub fn intern(string: &str) -> Self { - with_interner(|interner| interner.intern(string)) - } - - /// gensym's a new usize, using the current interner. - pub fn gensym(string: &str) -> Self { - with_interner(|interner| interner.gensym(string)) - } - - pub fn as_str(self) -> InternedString { - with_interner(|interner| unsafe { - InternedString { - string: ::std::mem::transmute::<&str, &str>(interner.get(self)) - } - }) - } - - pub fn as_u32(self) -> u32 { - self.0 - } -} - -impl fmt::Debug for Symbol { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}({})", self, self.0) - } -} - -impl fmt::Display for Symbol { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Display::fmt(&self.as_str(), f) - } -} - -impl Encodable for Symbol { - fn encode(&self, s: &mut S) -> Result<(), S::Error> { - s.emit_str(&self.as_str()) - } -} - -impl Decodable for Symbol { - fn decode(d: &mut D) -> Result { - Ok(Symbol::intern(&d.read_str()?)) - } -} - -impl> PartialEq for Symbol { - fn eq(&self, other: &T) -> bool { - self.as_str() == other.deref() - } -} - -#[derive(Default)] -pub struct Interner { - names: HashMap, Symbol>, - strings: Vec>, -} - -impl Interner { - pub fn new() -> Self { - Interner::default() - } - - fn prefill(init: &[&str]) -> Self { - let mut this = Interner::new(); - for &string in init { - this.intern(string); - } - this - } - - pub fn intern(&mut self, string: &str) -> Symbol { - if let Some(&name) = self.names.get(string) { - return name; - } - - let name = Symbol(self.strings.len() as u32); - let string = string.to_string().into_boxed_str(); - self.strings.push(string.clone()); - self.names.insert(string, name); - name - } - - fn gensym(&mut self, string: &str) -> Symbol { - let gensym = Symbol(self.strings.len() as u32); - // leave out of `names` to avoid colliding - self.strings.push(string.to_string().into_boxed_str()); - gensym - } - - pub fn get(&self, name: Symbol) -> &str { - &self.strings[name.0 as usize] - } -} - -// In this macro, there is the requirement that the name (the number) must be monotonically -// increasing by one in the special identifiers, starting at 0; the same holds for the keywords, -// except starting from the next number instead of zero. -macro_rules! declare_keywords {( - $( ($index: expr, $konst: ident, $string: expr) )* -) => { - pub mod keywords { - use ast; - #[derive(Clone, Copy, PartialEq, Eq)] - pub struct Keyword { - ident: ast::Ident, - } - impl Keyword { - #[inline] pub fn ident(self) -> ast::Ident { self.ident } - #[inline] pub fn name(self) -> ast::Name { self.ident.name } - } - $( - #[allow(non_upper_case_globals)] - pub const $konst: Keyword = Keyword { - ident: ast::Ident::with_empty_ctxt(super::Symbol($index)) - }; - )* - } - - impl Interner { - fn fresh() -> Self { - Interner::prefill(&[$($string,)*]) - } - } -}} - -// NB: leaving holes in the ident table is bad! a different ident will get -// interned with the id from the hole, but it will be between the min and max -// of the reserved words, and thus tagged as "reserved". -// After modifying this list adjust `is_strict_keyword`/`is_reserved_keyword`, -// this should be rarely necessary though if the keywords are kept in alphabetic order. -declare_keywords! { - // Invalid identifier - (0, Invalid, "") - - // Strict keywords used in the language. - (1, As, "as") - (2, Box, "box") - (3, Break, "break") - (4, Const, "const") - (5, Continue, "continue") - (6, Crate, "crate") - (7, Else, "else") - (8, Enum, "enum") - (9, Extern, "extern") - (10, False, "false") - (11, Fn, "fn") - (12, For, "for") - (13, If, "if") - (14, Impl, "impl") - (15, In, "in") - (16, Let, "let") - (17, Loop, "loop") - (18, Match, "match") - (19, Mod, "mod") - (20, Move, "move") - (21, Mut, "mut") - (22, Pub, "pub") - (23, Ref, "ref") - (24, Return, "return") - (25, SelfValue, "self") - (26, SelfType, "Self") - (27, Static, "static") - (28, Struct, "struct") - (29, Super, "super") - (30, Trait, "trait") - (31, True, "true") - (32, Type, "type") - (33, Unsafe, "unsafe") - (34, Use, "use") - (35, Where, "where") - (36, While, "while") - - // Keywords reserved for future use. - (37, Abstract, "abstract") - (38, Alignof, "alignof") - (39, Become, "become") - (40, Do, "do") - (41, Final, "final") - (42, Macro, "macro") - (43, Offsetof, "offsetof") - (44, Override, "override") - (45, Priv, "priv") - (46, Proc, "proc") - (47, Pure, "pure") - (48, Sizeof, "sizeof") - (49, Typeof, "typeof") - (50, Unsized, "unsized") - (51, Virtual, "virtual") - (52, Yield, "yield") - - // Weak keywords, have special meaning only in specific contexts. - (53, Default, "default") - (54, StaticLifetime, "'static") - (55, Union, "union") - (56, Catch, "catch") - - // A virtual keyword that resolves to the crate root when used in a lexical scope. - (57, CrateRoot, "{{root}}") -} - -// If an interner exists in TLS, return it. Otherwise, prepare a fresh one. -fn with_interner T>(f: F) -> T { - thread_local!(static INTERNER: RefCell = { - RefCell::new(Interner::fresh()) - }); - INTERNER.with(|interner| f(&mut *interner.borrow_mut())) -} - -/// Represents a string stored in the thread-local interner. Because the -/// interner lives for the life of the thread, this can be safely treated as an -/// immortal string, as long as it never crosses between threads. -/// -/// FIXME(pcwalton): You must be careful about what you do in the destructors -/// of objects stored in TLS, because they may run after the interner is -/// destroyed. In particular, they must not access string contents. This can -/// be fixed in the future by just leaking all strings until thread death -/// somehow. -#[derive(Clone, Hash, PartialOrd, Eq, Ord)] -pub struct InternedString { - string: &'static str, -} - -impl ::std::convert::AsRef for InternedString where str: ::std::convert::AsRef { - fn as_ref(&self) -> &U { - self.string.as_ref() - } -} - -impl> ::std::cmp::PartialEq for InternedString { - fn eq(&self, other: &T) -> bool { - self.string == other.deref() - } -} - -impl ::std::cmp::PartialEq for str { - fn eq(&self, other: &InternedString) -> bool { - self == other.string - } -} - -impl<'a> ::std::cmp::PartialEq for &'a str { - fn eq(&self, other: &InternedString) -> bool { - *self == other.string - } -} - -impl ::std::cmp::PartialEq for String { - fn eq(&self, other: &InternedString) -> bool { - self == other.string - } -} - -impl<'a> ::std::cmp::PartialEq for &'a String { - fn eq(&self, other: &InternedString) -> bool { - *self == other.string - } -} - -impl !Send for InternedString { } - -impl ::std::ops::Deref for InternedString { - type Target = str; - fn deref(&self) -> &str { self.string } -} - -impl fmt::Debug for InternedString { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Debug::fmt(self.string, f) - } -} - -impl fmt::Display for InternedString { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Display::fmt(self.string, f) - } -} - -impl Decodable for InternedString { - fn decode(d: &mut D) -> Result { - Ok(Symbol::intern(&d.read_str()?).as_str()) - } -} - -impl Encodable for InternedString { - fn encode(&self, s: &mut S) -> Result<(), S::Error> { - s.emit_str(self.string) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn interner_tests() { - let mut i: Interner = Interner::new(); - // first one is zero: - assert_eq!(i.intern("dog"), Symbol(0)); - // re-use gets the same entry: - assert_eq!(i.intern ("dog"), Symbol(0)); - // different string gets a different #: - assert_eq!(i.intern("cat"), Symbol(1)); - assert_eq!(i.intern("cat"), Symbol(1)); - // dog is still at zero - assert_eq!(i.intern("dog"), Symbol(0)); - // gensym gets 3 - assert_eq!(i.gensym("zebra"), Symbol(2)); - // gensym of same string gets new number : - assert_eq!(i.gensym("zebra"), Symbol(3)); - // gensym of *existing* string gets new number: - assert_eq!(i.gensym("dog"), Symbol(4)); - } -} diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs index 6fb6db9ca02..50380626d7f 100644 --- a/src/libsyntax/test.rs +++ b/src/libsyntax/test.rs @@ -31,6 +31,7 @@ use entry::{self, EntryPointType}; use ext::base::{ExtCtxt, Resolver}; use ext::build::AstBuilder; use ext::expand::ExpansionConfig; +use ext::hygiene::{Mark, SyntaxContext}; use fold::Folder; use util::move_map::MoveMap; use fold; @@ -62,6 +63,7 @@ struct TestCtxt<'a> { testfns: Vec, reexport_test_harness_main: Option, is_test_crate: bool, + ctxt: SyntaxContext, // top-level re-export submodule, filled out after folding is finished toplevel_reexport: Option, @@ -275,6 +277,7 @@ fn generate_test_harness(sess: &ParseSess, let mut cleaner = EntryPointCleaner { depth: 0 }; let krate = cleaner.fold_crate(krate); + let mark = Mark::fresh(); let mut cx: TestCtxt = TestCtxt { sess: sess, span_diagnostic: sd, @@ -284,15 +287,16 @@ fn generate_test_harness(sess: &ParseSess, reexport_test_harness_main: reexport_test_harness_main, is_test_crate: is_test_crate(&krate), toplevel_reexport: None, + ctxt: SyntaxContext::empty().apply_mark(mark), }; cx.ext_cx.crate_root = Some("std"); - cx.ext_cx.bt_push(ExpnInfo { + mark.set_expn_info(ExpnInfo { call_site: DUMMY_SP, callee: NameAndSpan { format: MacroAttribute(Symbol::intern("test")), span: None, - allow_internal_unstable: false, + allow_internal_unstable: true, } }); @@ -307,18 +311,7 @@ fn generate_test_harness(sess: &ParseSess, /// call to codemap's is_internal check. /// The expanded code calls some unstable functions in the test crate. fn ignored_span(cx: &TestCtxt, sp: Span) -> Span { - let info = ExpnInfo { - call_site: sp, - callee: NameAndSpan { - format: MacroAttribute(Symbol::intern("test")), - span: None, - allow_internal_unstable: true, - } - }; - let expn_id = cx.sess.codemap().record_expansion(info); - let mut sp = sp; - sp.expn_id = expn_id; - return sp; + Span { ctxt: cx.ctxt, ..sp } } #[derive(PartialEq)] diff --git a/src/libsyntax/test_snippet.rs b/src/libsyntax/test_snippet.rs index c6d6e6237f2..c537a0ee166 100644 --- a/src/libsyntax/test_snippet.rs +++ b/src/libsyntax/test_snippet.rs @@ -83,7 +83,7 @@ fn make_span(file_text: &str, start: &Position, end: &Position) -> Span { Span { lo: BytePos(start as u32), hi: BytePos(end as u32), - expn_id: NO_EXPANSION, + ctxt: NO_EXPANSION, } } diff --git a/src/libsyntax/tokenstream.rs b/src/libsyntax/tokenstream.rs index b75b3efda36..86bfdebe42b 100644 --- a/src/libsyntax/tokenstream.rs +++ b/src/libsyntax/tokenstream.rs @@ -56,18 +56,20 @@ impl Delimited { /// Returns the opening delimiter as a token tree. pub fn open_tt(&self, span: Span) -> TokenTree { - let open_span = match span { - DUMMY_SP => DUMMY_SP, - _ => Span { hi: span.lo + BytePos(self.delim.len() as u32), ..span }, + let open_span = if span == DUMMY_SP { + DUMMY_SP + } else { + Span { hi: span.lo + BytePos(self.delim.len() as u32), ..span } }; TokenTree::Token(open_span, self.open_token()) } /// Returns the closing delimiter as a token tree. pub fn close_tt(&self, span: Span) -> TokenTree { - let close_span = match span { - DUMMY_SP => DUMMY_SP, - _ => Span { lo: span.hi - BytePos(self.delim.len() as u32), ..span }, + let close_span = if span == DUMMY_SP { + DUMMY_SP + } else { + Span { lo: span.hi - BytePos(self.delim.len() as u32), ..span } }; TokenTree::Token(close_span, self.close_token()) } @@ -425,7 +427,7 @@ mod tests { Span { lo: BytePos(a), hi: BytePos(b), - expn_id: NO_EXPANSION, + ctxt: NO_EXPANSION, } } diff --git a/src/libsyntax_ext/asm.rs b/src/libsyntax_ext/asm.rs index 767ec94a0ce..923e8072f43 100644 --- a/src/libsyntax_ext/asm.rs +++ b/src/libsyntax_ext/asm.rs @@ -13,7 +13,6 @@ use self::State::*; use syntax::ast; -use syntax::codemap; use syntax::ext::base; use syntax::ext::base::*; use syntax::feature_gate; @@ -240,15 +239,6 @@ pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt, } } - let expn_id = cx.codemap().record_expansion(codemap::ExpnInfo { - call_site: sp, - callee: codemap::NameAndSpan { - format: codemap::MacroBang(Symbol::intern("asm")), - span: None, - allow_internal_unstable: false, - }, - }); - MacEager::expr(P(ast::Expr { id: ast::DUMMY_NODE_ID, node: ast::ExprKind::InlineAsm(P(ast::InlineAsm { @@ -260,7 +250,7 @@ pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt, volatile: volatile, alignstack: alignstack, dialect: dialect, - expn_id: expn_id, + ctxt: cx.backtrace(), })), span: sp, attrs: ast::ThinVec::new(), diff --git a/src/libsyntax_ext/deriving/clone.rs b/src/libsyntax_ext/deriving/clone.rs index d14b59d6c70..1993d6ebe5b 100644 --- a/src/libsyntax_ext/deriving/clone.rs +++ b/src/libsyntax_ext/deriving/clone.rs @@ -111,7 +111,7 @@ fn cs_clone_shallow(name: &str, ty: P, span: Span, helper_name: &str) { // Generate statement `let _: helper_name;`, // set the expn ID so we can use the unstable struct. - let span = super::allow_unstable(cx, span, "derive(Clone)"); + let span = Span { ctxt: cx.backtrace(), ..span}; let assert_path = cx.path_all(span, true, cx.std_path(&["clone", helper_name]), vec![], vec![ty], vec![]); diff --git a/src/libsyntax_ext/deriving/cmp/eq.rs b/src/libsyntax_ext/deriving/cmp/eq.rs index 6ab5987a159..eef21492deb 100644 --- a/src/libsyntax_ext/deriving/cmp/eq.rs +++ b/src/libsyntax_ext/deriving/cmp/eq.rs @@ -58,7 +58,7 @@ fn cs_total_eq_assert(cx: &mut ExtCtxt, trait_span: Span, substr: &Substructure) ty: P, span: Span, helper_name: &str) { // Generate statement `let _: helper_name;`, // set the expn ID so we can use the unstable struct. - let span = super::allow_unstable(cx, span, "derive(Eq)"); + let span = Span { ctxt: cx.backtrace(), ..span }; let assert_path = cx.path_all(span, true, cx.std_path(&["cmp", helper_name]), vec![], vec![ty], vec![]); diff --git a/src/libsyntax_ext/deriving/debug.rs b/src/libsyntax_ext/deriving/debug.rs index a767716466c..ec4cb815960 100644 --- a/src/libsyntax_ext/deriving/debug.rs +++ b/src/libsyntax_ext/deriving/debug.rs @@ -66,8 +66,8 @@ fn show_substructure(cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> P cx.span_bug(span, "nonsensical .fields in `#[derive(Debug)]`"), }; - // We want to make sure we have the expn_id set so that we can use unstable methods - let span = Span { expn_id: cx.backtrace(), ..span }; + // We want to make sure we have the ctxt set so that we can use unstable methods + let span = Span { ctxt: cx.backtrace(), ..span }; let name = cx.expr_lit(span, ast::LitKind::Str(ident.name, ast::StrStyle::Cooked)); let builder = Ident::from_str("builder"); let builder_expr = cx.expr_ident(span, builder.clone()); diff --git a/src/libsyntax_ext/deriving/generic/mod.rs b/src/libsyntax_ext/deriving/generic/mod.rs index 48e7ff0d243..1ff0fec1c96 100644 --- a/src/libsyntax_ext/deriving/generic/mod.rs +++ b/src/libsyntax_ext/deriving/generic/mod.rs @@ -375,7 +375,7 @@ fn find_type_parameters(ty: &ast::Ty, } fn visit_mac(&mut self, mac: &ast::Mac) { - let span = Span { expn_id: self.span.expn_id, ..mac.span }; + let span = Span { ctxt: self.span.ctxt, ..mac.span }; self.cx.span_err(span, "`derive` cannot be used on items with type macros"); } } @@ -1458,7 +1458,7 @@ impl<'a> MethodDef<'a> { .iter() .map(|v| { let ident = v.node.name; - let sp = Span { expn_id: trait_.span.expn_id, ..v.span }; + let sp = Span { ctxt: trait_.span.ctxt, ..v.span }; let summary = trait_.summarise_struct(cx, &v.node.data); (ident, sp, summary) }) @@ -1478,7 +1478,7 @@ impl<'a> TraitDef<'a> { let mut named_idents = Vec::new(); let mut just_spans = Vec::new(); for field in struct_def.fields() { - let sp = Span { expn_id: self.span.expn_id, ..field.span }; + let sp = Span { ctxt: self.span.ctxt, ..field.span }; match field.ident { Some(ident) => named_idents.push((ident, sp)), _ => just_spans.push(sp), @@ -1523,7 +1523,7 @@ impl<'a> TraitDef<'a> { let mut paths = Vec::new(); let mut ident_exprs = Vec::new(); for (i, struct_field) in struct_def.fields().iter().enumerate() { - let sp = Span { expn_id: self.span.expn_id, ..struct_field.span }; + let sp = Span { ctxt: self.span.ctxt, ..struct_field.span }; let ident = cx.ident_of(&format!("{}_{}", prefix, i)); paths.push(codemap::Spanned { span: sp, @@ -1544,7 +1544,7 @@ impl<'a> TraitDef<'a> { cx.span_bug(sp, "a braced struct with unnamed fields in `derive`"); } codemap::Spanned { - span: Span { expn_id: self.span.expn_id, ..pat.span }, + span: Span { ctxt: self.span.ctxt, ..pat.span }, node: ast::FieldPat { ident: ident.unwrap(), pat: pat, @@ -1576,7 +1576,7 @@ impl<'a> TraitDef<'a> { mutbl: ast::Mutability) -> (P, Vec<(Span, Option, P, &'a [ast::Attribute])>) { let variant_ident = variant.node.name; - let sp = Span { expn_id: self.span.expn_id, ..variant.span }; + let sp = Span { ctxt: self.span.ctxt, ..variant.span }; let variant_path = cx.path(sp, vec![enum_ident, variant_ident]); self.create_struct_pattern(cx, variant_path, &variant.node.data, prefix, mutbl) } diff --git a/src/libsyntax_ext/deriving/mod.rs b/src/libsyntax_ext/deriving/mod.rs index b51591bf89d..b2bb43e41ed 100644 --- a/src/libsyntax_ext/deriving/mod.rs +++ b/src/libsyntax_ext/deriving/mod.rs @@ -12,9 +12,9 @@ use std::rc::Rc; use syntax::ast; -use syntax::codemap; use syntax::ext::base::{Annotatable, ExtCtxt, SyntaxExtension, Resolver}; use syntax::ext::build::AstBuilder; +use syntax::ext::hygiene::{Mark, SyntaxContext}; use syntax::ptr::P; use syntax::symbol::Symbol; use syntax_pos::Span; @@ -74,20 +74,6 @@ pub mod ord; pub mod generic; -fn allow_unstable(cx: &mut ExtCtxt, span: Span, attr_name: &str) -> Span { - Span { - expn_id: cx.codemap().record_expansion(codemap::ExpnInfo { - call_site: span, - callee: codemap::NameAndSpan { - format: codemap::MacroAttribute(Symbol::intern(attr_name)), - span: Some(span), - allow_internal_unstable: true, - }, - }), - ..span - } -} - macro_rules! derive_traits { ($( $name:expr => $func:path, )+) => { pub fn is_builtin_trait(name: ast::Name) -> bool { @@ -177,15 +163,15 @@ fn call_intrinsic(cx: &ExtCtxt, intrinsic: &str, args: Vec>) -> P { - span.expn_id = cx.codemap().record_expansion(codemap::ExpnInfo { - call_site: span, - callee: codemap::NameAndSpan { - format: codemap::MacroAttribute(Symbol::intern("derive")), - span: Some(span), - allow_internal_unstable: true, - }, - }); - + if cx.current_expansion.mark.expn_info().unwrap().callee.allow_internal_unstable { + span.ctxt = cx.backtrace(); + } else { // Avoid instability errors with user defined curstom derives, cc #36316 + let mut info = cx.current_expansion.mark.expn_info().unwrap(); + info.callee.allow_internal_unstable = true; + let mark = Mark::fresh(); + mark.set_expn_info(info); + span.ctxt = SyntaxContext::empty().apply_mark(mark); + } let path = cx.std_path(&["intrinsics", intrinsic]); let call = cx.expr_call_global(span, path, args); diff --git a/src/libsyntax_ext/format.rs b/src/libsyntax_ext/format.rs index d2afa08cada..aeb5b1e0a53 100644 --- a/src/libsyntax_ext/format.rs +++ b/src/libsyntax_ext/format.rs @@ -641,10 +641,11 @@ impl<'a, 'b> Context<'a, 'b> { fn format_arg(ecx: &ExtCtxt, macsp: Span, - sp: Span, + mut sp: Span, ty: &ArgumentType, arg: P) -> P { + sp.ctxt = sp.ctxt.apply_mark(ecx.current_expansion.mark); let trait_ = match *ty { Placeholder(ref tyname) => { match &tyname[..] { diff --git a/src/libsyntax_ext/proc_macro_registrar.rs b/src/libsyntax_ext/proc_macro_registrar.rs index 2d815b3f1bb..bb89caab709 100644 --- a/src/libsyntax_ext/proc_macro_registrar.rs +++ b/src/libsyntax_ext/proc_macro_registrar.rs @@ -17,6 +17,7 @@ use syntax::codemap::{ExpnInfo, NameAndSpan, MacroAttribute}; use syntax::ext::base::ExtCtxt; use syntax::ext::build::AstBuilder; use syntax::ext::expand::ExpansionConfig; +use syntax::ext::hygiene::{Mark, SyntaxContext}; use syntax::fold::Folder; use syntax::parse::ParseSess; use syntax::ptr::P; @@ -360,7 +361,8 @@ fn mk_registrar(cx: &mut ExtCtxt, custom_derives: &[ProcMacroDerive], custom_attrs: &[ProcMacroDef], custom_macros: &[ProcMacroDef]) -> P { - let eid = cx.codemap().record_expansion(ExpnInfo { + let mark = Mark::fresh(); + mark.set_expn_info(ExpnInfo { call_site: DUMMY_SP, callee: NameAndSpan { format: MacroAttribute(Symbol::intern("proc_macro")), @@ -368,7 +370,7 @@ fn mk_registrar(cx: &mut ExtCtxt, allow_internal_unstable: true, } }); - let span = Span { expn_id: eid, ..DUMMY_SP }; + let span = Span { ctxt: SyntaxContext::empty().apply_mark(mark), ..DUMMY_SP }; let proc_macro = Ident::from_str("proc_macro"); let krate = cx.item(span, diff --git a/src/libsyntax_pos/hygiene.rs b/src/libsyntax_pos/hygiene.rs index feebbcd6f03..8a9ff647b3e 100644 --- a/src/libsyntax_pos/hygiene.rs +++ b/src/libsyntax_pos/hygiene.rs @@ -15,12 +15,16 @@ //! and definition contexts*. J. Funct. Program. 22, 2 (March 2012), 181-216. //! DOI=10.1017/S0956796812000093 http://dx.doi.org/10.1017/S0956796812000093 +use Span; +use symbol::Symbol; + +use serialize::{Encodable, Decodable, Encoder, Decoder}; use std::cell::RefCell; use std::collections::HashMap; use std::fmt; /// A SyntaxContext represents a chain of macro expansions (represented by marks). -#[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, Default)] +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct SyntaxContext(u32); #[derive(Copy, Clone)] @@ -36,8 +40,8 @@ pub struct Mark(u32); impl Mark { pub fn fresh() -> Self { HygieneData::with(|data| { - let next_mark = Mark(data.next_mark.0 + 1); - ::std::mem::replace(&mut data.next_mark, next_mark) + data.marks.push(None); + Mark(data.marks.len() as u32 - 1) }) } @@ -53,23 +57,31 @@ impl Mark { pub fn from_u32(raw: u32) -> Mark { Mark(raw) } + + pub fn expn_info(self) -> Option { + HygieneData::with(|data| data.marks[self.0 as usize].clone()) + } + + pub fn set_expn_info(self, info: ExpnInfo) { + HygieneData::with(|data| data.marks[self.0 as usize] = Some(info)) + } } struct HygieneData { + marks: Vec>, syntax_contexts: Vec, markings: HashMap<(SyntaxContext, Mark), SyntaxContext>, - next_mark: Mark, } impl HygieneData { fn new() -> Self { HygieneData { + marks: vec![None], syntax_contexts: vec![SyntaxContextData { outer_mark: Mark::root(), prev_ctxt: SyntaxContext::empty(), }], markings: HashMap::new(), - next_mark: Mark(1), } } @@ -81,8 +93,8 @@ impl HygieneData { } } -pub fn reset_hygiene_data() { - HygieneData::with(|data| *data = HygieneData::new()) +pub fn clear_markings() { + HygieneData::with(|data| data.markings = HashMap::new()); } impl SyntaxContext { @@ -113,6 +125,10 @@ impl SyntaxContext { }) }) } + + pub fn outer(self) -> Mark { + HygieneData::with(|data| data.syntax_contexts[self.0 as usize].outer_mark) + } } impl fmt::Debug for SyntaxContext { @@ -120,3 +136,67 @@ impl fmt::Debug for SyntaxContext { write!(f, "#{}", self.0) } } + +/// Extra information for tracking spans of macro and syntax sugar expansion +#[derive(Clone, Hash, Debug)] +pub struct ExpnInfo { + /// The location of the actual macro invocation or syntax sugar , e.g. + /// `let x = foo!();` or `if let Some(y) = x {}` + /// + /// This may recursively refer to other macro invocations, e.g. if + /// `foo!()` invoked `bar!()` internally, and there was an + /// expression inside `bar!`; the call_site of the expression in + /// the expansion would point to the `bar!` invocation; that + /// call_site span would have its own ExpnInfo, with the call_site + /// pointing to the `foo!` invocation. + pub call_site: Span, + /// Information about the expansion. + pub callee: NameAndSpan +} + +#[derive(Clone, Hash, Debug)] +pub struct NameAndSpan { + /// The format with which the macro was invoked. + pub format: ExpnFormat, + /// Whether the macro is allowed to use #[unstable]/feature-gated + /// features internally without forcing the whole crate to opt-in + /// to them. + pub allow_internal_unstable: bool, + /// The span of the macro definition itself. The macro may not + /// have a sensible definition span (e.g. something defined + /// completely inside libsyntax) in which case this is None. + pub span: Option +} + +impl NameAndSpan { + pub fn name(&self) -> Symbol { + match self.format { + ExpnFormat::MacroAttribute(s) | + ExpnFormat::MacroBang(s) | + ExpnFormat::CompilerDesugaring(s) => s, + } + } +} + +/// The source of expansion. +#[derive(Clone, Hash, Debug, PartialEq, Eq)] +pub enum ExpnFormat { + /// e.g. #[derive(...)] + MacroAttribute(Symbol), + /// e.g. `format!()` + MacroBang(Symbol), + /// Desugaring done by the compiler during HIR lowering. + CompilerDesugaring(Symbol) +} + +impl Encodable for SyntaxContext { + fn encode(&self, _: &mut E) -> Result<(), E::Error> { + Ok(()) // FIXME(jseyfried) intercrate hygiene + } +} + +impl Decodable for SyntaxContext { + fn decode(_: &mut D) -> Result { + Ok(SyntaxContext::empty()) // FIXME(jseyfried) intercrate hygiene + } +} diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs index 1b62d62348b..9b45e364ecf 100644 --- a/src/libsyntax_pos/lib.rs +++ b/src/libsyntax_pos/lib.rs @@ -25,6 +25,7 @@ #![feature(const_fn)] #![feature(custom_attribute)] +#![feature(optin_builtin_traits)] #![allow(unused_attributes)] #![feature(rustc_private)] #![feature(staged_api)] @@ -43,6 +44,9 @@ extern crate serialize; extern crate serialize as rustc_serialize; // used by deriving pub mod hygiene; +pub use hygiene::{SyntaxContext, ExpnInfo, ExpnFormat, NameAndSpan}; + +pub mod symbol; pub type FileName = String; @@ -60,7 +64,7 @@ pub struct Span { pub hi: BytePos, /// Information about where the macro came from, if this piece of /// code was created by a macro expansion. - pub expn_id: ExpnId + pub ctxt: SyntaxContext, } /// A collection of spans. Spans have two orthogonal attributes: @@ -79,7 +83,7 @@ impl Span { /// Returns a new span representing just the end-point of this span pub fn end_point(self) -> Span { let lo = cmp::max(self.hi.0 - 1, self.lo.0); - Span { lo: BytePos(lo), hi: self.hi, expn_id: self.expn_id} + Span { lo: BytePos(lo), hi: self.hi, ctxt: self.ctxt } } /// Returns `self` if `self` is not the dummy span, and `other` otherwise. @@ -107,6 +111,69 @@ impl Span { None } } + + /// Return the source span - this is either the supplied span, or the span for + /// the macro callsite that expanded to it. + pub fn source_callsite(self) -> Span { + self.ctxt.outer().expn_info().map(|info| info.call_site.source_callsite()).unwrap_or(self) + } + + /// Return the source callee. + /// + /// Returns None if the supplied span has no expansion trace, + /// else returns the NameAndSpan for the macro definition + /// corresponding to the source callsite. + pub fn source_callee(self) -> Option { + fn source_callee(info: ExpnInfo) -> NameAndSpan { + match info.call_site.ctxt.outer().expn_info() { + Some(info) => source_callee(info), + None => info.callee, + } + } + self.ctxt.outer().expn_info().map(source_callee) + } + + /// Check if a span is "internal" to a macro in which #[unstable] + /// items can be used (that is, a macro marked with + /// `#[allow_internal_unstable]`). + pub fn allows_unstable(&self) -> bool { + match self.ctxt.outer().expn_info() { + Some(info) => info.callee.allow_internal_unstable, + None => false, + } + } + + pub fn macro_backtrace(mut self) -> Vec { + let mut prev_span = DUMMY_SP; + let mut result = vec![]; + loop { + let info = match self.ctxt.outer().expn_info() { + Some(info) => info, + None => break, + }; + + let (pre, post) = match info.callee.format { + ExpnFormat::MacroAttribute(..) => ("#[", "]"), + ExpnFormat::MacroBang(..) => ("", "!"), + ExpnFormat::CompilerDesugaring(..) => ("desugaring of `", "`"), + }; + let macro_decl_name = format!("{}{}{}", pre, info.callee.name(), post); + let def_site_span = info.callee.span; + + // Don't print recursive invocations + if !info.call_site.source_equal(&prev_span) { + result.push(MacroBacktrace { + call_site: info.call_site, + macro_decl_name: macro_decl_name, + def_site_span: def_site_span, + }); + } + + prev_span = self; + self = info.call_site; + } + result + } } #[derive(Clone, Debug)] @@ -147,8 +214,8 @@ impl serialize::UseSpecializedDecodable for Span { } fn default_span_debug(span: Span, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "Span {{ lo: {:?}, hi: {:?}, expn_id: {:?} }}", - span.lo, span.hi, span.expn_id) + write!(f, "Span {{ lo: {:?}, hi: {:?}, ctxt: {:?} }}", + span.lo, span.hi, span.ctxt) } impl fmt::Debug for Span { @@ -157,12 +224,7 @@ impl fmt::Debug for Span { } } -pub const DUMMY_SP: Span = Span { lo: BytePos(0), hi: BytePos(0), expn_id: NO_EXPANSION }; - -// Generic span to be used for code originating from the command line -pub const COMMAND_LINE_SP: Span = Span { lo: BytePos(0), - hi: BytePos(0), - expn_id: COMMAND_LINE_EXPN }; +pub const DUMMY_SP: Span = Span { lo: BytePos(0), hi: BytePos(0), ctxt: NO_EXPANSION }; impl MultiSpan { pub fn new() -> MultiSpan { @@ -256,22 +318,7 @@ impl From for MultiSpan { } } -#[derive(PartialEq, Eq, Clone, Debug, Hash, RustcEncodable, RustcDecodable, Copy, Ord, PartialOrd)] -pub struct ExpnId(pub u32); - -pub const NO_EXPANSION: ExpnId = ExpnId(!0); -// For code appearing from the command line -pub const COMMAND_LINE_EXPN: ExpnId = ExpnId(!1); - -impl ExpnId { - pub fn from_u32(id: u32) -> ExpnId { - ExpnId(id) - } - - pub fn into_u32(self) -> u32 { - self.0 - } -} +pub const NO_EXPANSION: SyntaxContext = SyntaxContext::empty(); /// Identifies an offset of a multi-byte character in a FileMap #[derive(Copy, Clone, RustcEncodable, RustcDecodable, Eq, PartialEq)] @@ -651,7 +698,7 @@ thread_local!(pub static SPAN_DEBUG: Cell fmt:: /* assuming that we're not in macro expansion */ pub fn mk_sp(lo: BytePos, hi: BytePos) -> Span { - Span {lo: lo, hi: hi, expn_id: NO_EXPANSION} + Span {lo: lo, hi: hi, ctxt: NO_EXPANSION} } pub struct MacroBacktrace { diff --git a/src/libsyntax_pos/symbol.rs b/src/libsyntax_pos/symbol.rs new file mode 100644 index 00000000000..b866652c49f --- /dev/null +++ b/src/libsyntax_pos/symbol.rs @@ -0,0 +1,389 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! An "interner" is a data structure that associates values with usize tags and +//! allows bidirectional lookup; i.e. given a value, one can easily find the +//! type, and vice versa. + +use hygiene::SyntaxContext; + +use serialize::{Decodable, Decoder, Encodable, Encoder}; +use std::cell::RefCell; +use std::collections::HashMap; +use std::fmt; + +#[derive(Copy, Clone, PartialEq, Eq, Hash)] +pub struct Ident { + pub name: Symbol, + pub ctxt: SyntaxContext, +} + +impl Ident { + pub const fn with_empty_ctxt(name: Symbol) -> Ident { + Ident { name: name, ctxt: SyntaxContext::empty() } + } + + /// Maps a string to an identifier with an empty syntax context. + pub fn from_str(string: &str) -> Ident { + Ident::with_empty_ctxt(Symbol::intern(string)) + } + + pub fn unhygienize(self) -> Ident { + Ident { name: self.name, ctxt: SyntaxContext::empty() } + } +} + +impl fmt::Debug for Ident { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}{:?}", self.name, self.ctxt) + } +} + +impl fmt::Display for Ident { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(&self.name, f) + } +} + +impl Encodable for Ident { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { + self.name.encode(s) + } +} + +impl Decodable for Ident { + fn decode(d: &mut D) -> Result { + Ok(Ident::with_empty_ctxt(Symbol::decode(d)?)) + } +} + +/// A symbol is an interned or gensymed string. +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct Symbol(u32); + +// The interner in thread-local, so `Symbol` shouldn't move between threads. +impl !Send for Symbol { } + +impl Symbol { + /// Maps a string to its interned representation. + pub fn intern(string: &str) -> Self { + with_interner(|interner| interner.intern(string)) + } + + /// gensym's a new usize, using the current interner. + pub fn gensym(string: &str) -> Self { + with_interner(|interner| interner.gensym(string)) + } + + pub fn as_str(self) -> InternedString { + with_interner(|interner| unsafe { + InternedString { + string: ::std::mem::transmute::<&str, &str>(interner.get(self)) + } + }) + } + + pub fn as_u32(self) -> u32 { + self.0 + } +} + +impl fmt::Debug for Symbol { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}({})", self, self.0) + } +} + +impl fmt::Display for Symbol { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(&self.as_str(), f) + } +} + +impl Encodable for Symbol { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { + s.emit_str(&self.as_str()) + } +} + +impl Decodable for Symbol { + fn decode(d: &mut D) -> Result { + Ok(Symbol::intern(&d.read_str()?)) + } +} + +impl> PartialEq for Symbol { + fn eq(&self, other: &T) -> bool { + self.as_str() == other.deref() + } +} + +#[derive(Default)] +pub struct Interner { + names: HashMap, Symbol>, + strings: Vec>, +} + +impl Interner { + pub fn new() -> Self { + Interner::default() + } + + fn prefill(init: &[&str]) -> Self { + let mut this = Interner::new(); + for &string in init { + this.intern(string); + } + this + } + + pub fn intern(&mut self, string: &str) -> Symbol { + if let Some(&name) = self.names.get(string) { + return name; + } + + let name = Symbol(self.strings.len() as u32); + let string = string.to_string().into_boxed_str(); + self.strings.push(string.clone()); + self.names.insert(string, name); + name + } + + fn gensym(&mut self, string: &str) -> Symbol { + let gensym = Symbol(self.strings.len() as u32); + // leave out of `names` to avoid colliding + self.strings.push(string.to_string().into_boxed_str()); + gensym + } + + pub fn get(&self, name: Symbol) -> &str { + &self.strings[name.0 as usize] + } +} + +// In this macro, there is the requirement that the name (the number) must be monotonically +// increasing by one in the special identifiers, starting at 0; the same holds for the keywords, +// except starting from the next number instead of zero. +macro_rules! declare_keywords {( + $( ($index: expr, $konst: ident, $string: expr) )* +) => { + pub mod keywords { + use super::{Symbol, Ident}; + #[derive(Clone, Copy, PartialEq, Eq)] + pub struct Keyword { + ident: Ident, + } + impl Keyword { + #[inline] pub fn ident(self) -> Ident { self.ident } + #[inline] pub fn name(self) -> Symbol { self.ident.name } + } + $( + #[allow(non_upper_case_globals)] + pub const $konst: Keyword = Keyword { + ident: Ident::with_empty_ctxt(super::Symbol($index)) + }; + )* + } + + impl Interner { + fn fresh() -> Self { + Interner::prefill(&[$($string,)*]) + } + } +}} + +// NB: leaving holes in the ident table is bad! a different ident will get +// interned with the id from the hole, but it will be between the min and max +// of the reserved words, and thus tagged as "reserved". +// After modifying this list adjust `is_strict_keyword`/`is_reserved_keyword`, +// this should be rarely necessary though if the keywords are kept in alphabetic order. +declare_keywords! { + // Invalid identifier + (0, Invalid, "") + + // Strict keywords used in the language. + (1, As, "as") + (2, Box, "box") + (3, Break, "break") + (4, Const, "const") + (5, Continue, "continue") + (6, Crate, "crate") + (7, Else, "else") + (8, Enum, "enum") + (9, Extern, "extern") + (10, False, "false") + (11, Fn, "fn") + (12, For, "for") + (13, If, "if") + (14, Impl, "impl") + (15, In, "in") + (16, Let, "let") + (17, Loop, "loop") + (18, Match, "match") + (19, Mod, "mod") + (20, Move, "move") + (21, Mut, "mut") + (22, Pub, "pub") + (23, Ref, "ref") + (24, Return, "return") + (25, SelfValue, "self") + (26, SelfType, "Self") + (27, Static, "static") + (28, Struct, "struct") + (29, Super, "super") + (30, Trait, "trait") + (31, True, "true") + (32, Type, "type") + (33, Unsafe, "unsafe") + (34, Use, "use") + (35, Where, "where") + (36, While, "while") + + // Keywords reserved for future use. + (37, Abstract, "abstract") + (38, Alignof, "alignof") + (39, Become, "become") + (40, Do, "do") + (41, Final, "final") + (42, Macro, "macro") + (43, Offsetof, "offsetof") + (44, Override, "override") + (45, Priv, "priv") + (46, Proc, "proc") + (47, Pure, "pure") + (48, Sizeof, "sizeof") + (49, Typeof, "typeof") + (50, Unsized, "unsized") + (51, Virtual, "virtual") + (52, Yield, "yield") + + // Weak keywords, have special meaning only in specific contexts. + (53, Default, "default") + (54, StaticLifetime, "'static") + (55, Union, "union") + (56, Catch, "catch") + + // A virtual keyword that resolves to the crate root when used in a lexical scope. + (57, CrateRoot, "{{root}}") +} + +// If an interner exists in TLS, return it. Otherwise, prepare a fresh one. +fn with_interner T>(f: F) -> T { + thread_local!(static INTERNER: RefCell = { + RefCell::new(Interner::fresh()) + }); + INTERNER.with(|interner| f(&mut *interner.borrow_mut())) +} + +/// Represents a string stored in the thread-local interner. Because the +/// interner lives for the life of the thread, this can be safely treated as an +/// immortal string, as long as it never crosses between threads. +/// +/// FIXME(pcwalton): You must be careful about what you do in the destructors +/// of objects stored in TLS, because they may run after the interner is +/// destroyed. In particular, they must not access string contents. This can +/// be fixed in the future by just leaking all strings until thread death +/// somehow. +#[derive(Clone, Hash, PartialOrd, Eq, Ord)] +pub struct InternedString { + string: &'static str, +} + +impl ::std::convert::AsRef for InternedString where str: ::std::convert::AsRef { + fn as_ref(&self) -> &U { + self.string.as_ref() + } +} + +impl> ::std::cmp::PartialEq for InternedString { + fn eq(&self, other: &T) -> bool { + self.string == other.deref() + } +} + +impl ::std::cmp::PartialEq for str { + fn eq(&self, other: &InternedString) -> bool { + self == other.string + } +} + +impl<'a> ::std::cmp::PartialEq for &'a str { + fn eq(&self, other: &InternedString) -> bool { + *self == other.string + } +} + +impl ::std::cmp::PartialEq for String { + fn eq(&self, other: &InternedString) -> bool { + self == other.string + } +} + +impl<'a> ::std::cmp::PartialEq for &'a String { + fn eq(&self, other: &InternedString) -> bool { + *self == other.string + } +} + +impl !Send for InternedString { } + +impl ::std::ops::Deref for InternedString { + type Target = str; + fn deref(&self) -> &str { self.string } +} + +impl fmt::Debug for InternedString { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Debug::fmt(self.string, f) + } +} + +impl fmt::Display for InternedString { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(self.string, f) + } +} + +impl Decodable for InternedString { + fn decode(d: &mut D) -> Result { + Ok(Symbol::intern(&d.read_str()?).as_str()) + } +} + +impl Encodable for InternedString { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { + s.emit_str(self.string) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn interner_tests() { + let mut i: Interner = Interner::new(); + // first one is zero: + assert_eq!(i.intern("dog"), Symbol(0)); + // re-use gets the same entry: + assert_eq!(i.intern ("dog"), Symbol(0)); + // different string gets a different #: + assert_eq!(i.intern("cat"), Symbol(1)); + assert_eq!(i.intern("cat"), Symbol(1)); + // dog is still at zero + assert_eq!(i.intern("dog"), Symbol(0)); + // gensym gets 3 + assert_eq!(i.gensym("zebra"), Symbol(2)); + // gensym of same string gets new number : + assert_eq!(i.gensym("zebra"), Symbol(3)); + // gensym of *existing* string gets new number: + assert_eq!(i.gensym("dog"), Symbol(4)); + } +} diff --git a/src/test/compile-fail-fulldeps/qquote.rs b/src/test/compile-fail-fulldeps/qquote.rs index bd25561065b..272bf1150ca 100644 --- a/src/test/compile-fail-fulldeps/qquote.rs +++ b/src/test/compile-fail-fulldeps/qquote.rs @@ -27,14 +27,6 @@ fn main() { &ps, syntax::ext::expand::ExpansionConfig::default("qquote".to_string()), &mut resolver); - cx.bt_push(syntax::codemap::ExpnInfo { - call_site: DUMMY_SP, - callee: syntax::codemap::NameAndSpan { - format: syntax::codemap::MacroBang(Symbol::intern("")), - allow_internal_unstable: false, - span: None, - } - }); let cx = &mut cx; assert_eq!(pprust::expr_to_string(&*quote_expr!(&cx, 23)), "23"); diff --git a/src/test/run-fail-fulldeps/qquote.rs b/src/test/run-fail-fulldeps/qquote.rs index d692bb519c1..5518ab47c2b 100644 --- a/src/test/run-fail-fulldeps/qquote.rs +++ b/src/test/run-fail-fulldeps/qquote.rs @@ -30,14 +30,6 @@ fn main() { &ps, syntax::ext::expand::ExpansionConfig::default("qquote".to_string()), &mut resolver); - cx.bt_push(syntax::codemap::ExpnInfo { - call_site: DUMMY_SP, - callee: syntax::codemap::NameAndSpan { - format: syntax::codemap::MacroBang(Symbol::intern("")), - allow_internal_unstable: false, - span: None, - } - }); let cx = &mut cx; println!("{}", pprust::expr_to_string(&*quote_expr!(&cx, 23))); diff --git a/src/test/run-pass-fulldeps/qquote.rs b/src/test/run-pass-fulldeps/qquote.rs index b4ed57192cc..4a8246ec429 100644 --- a/src/test/run-pass-fulldeps/qquote.rs +++ b/src/test/run-pass-fulldeps/qquote.rs @@ -26,14 +26,6 @@ fn main() { &ps, syntax::ext::expand::ExpansionConfig::default("qquote".to_string()), &mut resolver); - cx.bt_push(syntax::codemap::ExpnInfo { - call_site: DUMMY_SP, - callee: syntax::codemap::NameAndSpan { - format: syntax::codemap::MacroBang(Symbol::intern("")), - allow_internal_unstable: false, - span: None, - } - }); let cx = &mut cx; macro_rules! check { -- cgit 1.4.1-3-g733a5 From 872d3bc0d713a85f2050f99d0cf33dd060318411 Mon Sep 17 00:00:00 2001 From: Esteban Küber Date: Mon, 27 Mar 2017 14:54:15 -0700 Subject: Simplify labels and move tests to ui --- src/librustc_typeck/check/method/suggest.rs | 8 +- src/test/compile-fail/issue-18343.rs | 21 ----- src/test/compile-fail/issue-2392.rs | 105 --------------------- src/test/compile-fail/issue-32128.rs | 27 ------ src/test/compile-fail/issue-33784.rs | 49 ---------- .../confuse-field-and-method/issue-18343.rs | 21 +++++ .../confuse-field-and-method/issue-18343.stderr | 10 ++ .../confuse-field-and-method/issue-2392.rs | 105 +++++++++++++++++++++ .../confuse-field-and-method/issue-2392.stderr | 90 ++++++++++++++++++ .../confuse-field-and-method/issue-32128.rs | 27 ++++++ .../confuse-field-and-method/issue-32128.stderr | 10 ++ .../confuse-field-and-method/issue-33784.rs | 49 ++++++++++ .../confuse-field-and-method/issue-33784.stderr | 26 +++++ 13 files changed, 339 insertions(+), 209 deletions(-) delete mode 100644 src/test/compile-fail/issue-18343.rs delete mode 100644 src/test/compile-fail/issue-2392.rs delete mode 100644 src/test/compile-fail/issue-32128.rs delete mode 100644 src/test/compile-fail/issue-33784.rs create mode 100644 src/test/ui/suggestions/confuse-field-and-method/issue-18343.rs create mode 100644 src/test/ui/suggestions/confuse-field-and-method/issue-18343.stderr create mode 100644 src/test/ui/suggestions/confuse-field-and-method/issue-2392.rs create mode 100644 src/test/ui/suggestions/confuse-field-and-method/issue-2392.stderr create mode 100644 src/test/ui/suggestions/confuse-field-and-method/issue-32128.rs create mode 100644 src/test/ui/suggestions/confuse-field-and-method/issue-32128.stderr create mode 100644 src/test/ui/suggestions/confuse-field-and-method/issue-33784.rs create mode 100644 src/test/ui/suggestions/confuse-field-and-method/issue-33784.stderr (limited to 'src/test') diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index b458c1af71d..67ee7ef5865 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -202,19 +202,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { stored in the `{1}` field", expr_string, item_name)); - err.span_label(span, - &format!("`{}` is a field storing a \ - function, not a method", - item_name)); } else { err.help(&format!("did you mean to write `{0}.{1}` \ instead of `{0}.{1}(...)`?", expr_string, item_name)); - err.span_label(span, - &format!("`{}` is a field, not a method", - item_name)); } + err.span_label(span, &"field, not a method"); break; } } diff --git a/src/test/compile-fail/issue-18343.rs b/src/test/compile-fail/issue-18343.rs deleted file mode 100644 index a095bb48126..00000000000 --- a/src/test/compile-fail/issue-18343.rs +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright 2014 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. - -struct Obj where F: FnMut() -> u32 { - closure: F, -} - -fn main() { - let o = Obj { closure: || 42 }; - o.closure(); - //~^ ERROR no method named `closure` found - //~| HELP use `(o.closure)(...)` if you meant to call the function stored in the `closure` field - //~| NOTE `closure` is a field storing a function, not a method -} diff --git a/src/test/compile-fail/issue-2392.rs b/src/test/compile-fail/issue-2392.rs deleted file mode 100644 index 12389f88536..00000000000 --- a/src/test/compile-fail/issue-2392.rs +++ /dev/null @@ -1,105 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![feature(core, fnbox)] - -use std::boxed::FnBox; - -struct FuncContainer { - f1: fn(data: u8), - f2: extern "C" fn(data: u8), - f3: unsafe fn(data: u8), -} - -struct FuncContainerOuter { - container: Box -} - -struct Obj where F: FnOnce() -> u32 { - closure: F, - not_closure: usize, -} - -struct BoxedObj { - boxed_closure: Box u32>, -} - -struct Wrapper where F: FnMut() -> u32 { - wrap: Obj, -} - -fn func() -> u32 { - 0 -} - -fn check_expression() -> Obj u32>> { - Obj { closure: Box::new(|| 42_u32) as Box u32>, not_closure: 42 } -} - -fn main() { - // test variations of function - - let o_closure = Obj { closure: || 42, not_closure: 42 }; - o_closure.closure(); //~ ERROR no method named `closure` found - //~^ HELP use `(o_closure.closure)(...)` if you meant to call the function stored - //~| NOTE `closure` is a field storing a function, not a method - - o_closure.not_closure(); - //~^ ERROR no method named `not_closure` found - //~| NOTE `not_closure` is a field, not a method - //~| HELP did you mean to write `o_closure.not_closure` instead of `o_closure.not_closure(...)`? - - let o_func = Obj { closure: func, not_closure: 5 }; - o_func.closure(); //~ ERROR no method named `closure` found - //~^ HELP use `(o_func.closure)(...)` if you meant to call the function stored - //~| NOTE `closure` is a field storing a function, not a method - - let boxed_fn = BoxedObj { boxed_closure: Box::new(func) }; - boxed_fn.boxed_closure();//~ ERROR no method named `boxed_closure` found - //~^ HELP use `(boxed_fn.boxed_closure)(...)` if you meant to call the function stored - //~| NOTE `boxed_closure` is a field storing a function, not a method - - let boxed_closure = BoxedObj { boxed_closure: Box::new(|| 42_u32) as Box u32> }; - boxed_closure.boxed_closure();//~ ERROR no method named `boxed_closure` found - //~^ HELP use `(boxed_closure.boxed_closure)(...)` if you meant to call the function stored - //~| NOTE `boxed_closure` is a field storing a function, not a method - - // test expression writing in the notes - - let w = Wrapper { wrap: o_func }; - w.wrap.closure();//~ ERROR no method named `closure` found - //~^ HELP use `(w.wrap.closure)(...)` if you meant to call the function stored - //~| NOTE `closure` is a field storing a function, not a method - - w.wrap.not_closure(); - //~^ ERROR no method named `not_closure` found - //~| NOTE `not_closure` is a field, not a method - //~| HELP did you mean to write `w.wrap.not_closure` instead of `w.wrap.not_closure(...)`? - - check_expression().closure();//~ ERROR no method named `closure` found - //~^ HELP use `(check_expression().closure)(...)` if you meant to call the function stored - //~| NOTE `closure` is a field storing a function, not a method -} - -impl FuncContainerOuter { - fn run(&self) { - unsafe { - (*self.container).f1(1); //~ ERROR no method named `f1` found - //~^ HELP use `((*self.container).f1)(...)` - //~| NOTE `f1` is a field storing a function, not a method - (*self.container).f2(1); //~ ERROR no method named `f2` found - //~^ HELP use `((*self.container).f2)(...)` - //~| NOTE `f2` is a field storing a function, not a method - (*self.container).f3(1); //~ ERROR no method named `f3` found - //~^ HELP use `((*self.container).f3)(...)` - //~| NOTE `f3` is a field storing a function, not a method - } - } -} diff --git a/src/test/compile-fail/issue-32128.rs b/src/test/compile-fail/issue-32128.rs deleted file mode 100644 index 74fbb33296e..00000000000 --- a/src/test/compile-fail/issue-32128.rs +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -struct Example { - example: Box i32> -} - -fn main() { - let demo = Example { - example: Box::new(|x| { - x + 1 - }) - }; - - demo.example(1); - //~^ ERROR no method named `example` - //~| HELP use `(demo.example)(...)` - //~| NOTE `example` is a field storing a function, not a method - // (demo.example)(1); -} diff --git a/src/test/compile-fail/issue-33784.rs b/src/test/compile-fail/issue-33784.rs deleted file mode 100644 index 03c84fc57be..00000000000 --- a/src/test/compile-fail/issue-33784.rs +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use std::ops::Deref; - -struct Obj where F: FnMut() -> u32 { - fn_ptr: fn() -> (), - closure: F, -} - -struct C { - c_fn_ptr: fn() -> (), -} - -struct D(C); - -impl Deref for D { - type Target = C; - fn deref(&self) -> &C { - &self.0 - } -} - - -fn empty() {} - -fn main() { - let o = Obj { fn_ptr: empty, closure: || 42 }; - let p = &o; - p.closure(); //~ ERROR no method named `closure` found - //~^ HELP use `(p.closure)(...)` if you meant to call the function stored in the `closure` field - //~| NOTE `closure` is a field storing a function, not a method - let q = &p; - q.fn_ptr(); //~ ERROR no method named `fn_ptr` found - //~^ HELP use `(q.fn_ptr)(...)` if you meant to call the function stored in the `fn_ptr` field - //~| NOTE `fn_ptr` is a field storing a function, not a method - let r = D(C { c_fn_ptr: empty }); - let s = &r; - s.c_fn_ptr(); //~ ERROR no method named `c_fn_ptr` found - //~^ HELP use `(s.c_fn_ptr)(...)` if you meant to call the function stored in the `c_fn_ptr` - //~| NOTE `c_fn_ptr` is a field storing a function, not a method -} diff --git a/src/test/ui/suggestions/confuse-field-and-method/issue-18343.rs b/src/test/ui/suggestions/confuse-field-and-method/issue-18343.rs new file mode 100644 index 00000000000..fc3c58e5223 --- /dev/null +++ b/src/test/ui/suggestions/confuse-field-and-method/issue-18343.rs @@ -0,0 +1,21 @@ +// Copyright 2014 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. + +struct Obj where F: FnMut() -> u32 { + closure: F, +} + +fn main() { + let o = Obj { closure: || 42 }; + o.closure(); + //~^ ERROR no method named `closure` found + //~| HELP use `(o.closure)(...)` if you meant to call the function stored in the `closure` field + //~| NOTE field, not a method +} diff --git a/src/test/ui/suggestions/confuse-field-and-method/issue-18343.stderr b/src/test/ui/suggestions/confuse-field-and-method/issue-18343.stderr new file mode 100644 index 00000000000..9e5e4adb180 --- /dev/null +++ b/src/test/ui/suggestions/confuse-field-and-method/issue-18343.stderr @@ -0,0 +1,10 @@ +error: no method named `closure` found for type `Obj<[closure@$DIR/issue-18343.rs:16:28: 16:33]>` in the current scope + --> $DIR/issue-18343.rs:17:7 + | +17 | o.closure(); + | ^^^^^^^ field, not a method + | + = help: use `(o.closure)(...)` if you meant to call the function stored in the `closure` field + +error: aborting due to previous error + diff --git a/src/test/ui/suggestions/confuse-field-and-method/issue-2392.rs b/src/test/ui/suggestions/confuse-field-and-method/issue-2392.rs new file mode 100644 index 00000000000..f84f35ce84b --- /dev/null +++ b/src/test/ui/suggestions/confuse-field-and-method/issue-2392.rs @@ -0,0 +1,105 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(core, fnbox)] + +use std::boxed::FnBox; + +struct FuncContainer { + f1: fn(data: u8), + f2: extern "C" fn(data: u8), + f3: unsafe fn(data: u8), +} + +struct FuncContainerOuter { + container: Box +} + +struct Obj where F: FnOnce() -> u32 { + closure: F, + not_closure: usize, +} + +struct BoxedObj { + boxed_closure: Box u32>, +} + +struct Wrapper where F: FnMut() -> u32 { + wrap: Obj, +} + +fn func() -> u32 { + 0 +} + +fn check_expression() -> Obj u32>> { + Obj { closure: Box::new(|| 42_u32) as Box u32>, not_closure: 42 } +} + +fn main() { + // test variations of function + + let o_closure = Obj { closure: || 42, not_closure: 42 }; + o_closure.closure(); //~ ERROR no method named `closure` found + //~^ HELP use `(o_closure.closure)(...)` if you meant to call the function stored + //~| NOTE field, not a method + + o_closure.not_closure(); + //~^ ERROR no method named `not_closure` found + //~| NOTE field, not a method + //~| HELP did you mean to write `o_closure.not_closure` instead of `o_closure.not_closure(...)`? + + let o_func = Obj { closure: func, not_closure: 5 }; + o_func.closure(); //~ ERROR no method named `closure` found + //~^ HELP use `(o_func.closure)(...)` if you meant to call the function stored + //~| NOTE field, not a method + + let boxed_fn = BoxedObj { boxed_closure: Box::new(func) }; + boxed_fn.boxed_closure();//~ ERROR no method named `boxed_closure` found + //~^ HELP use `(boxed_fn.boxed_closure)(...)` if you meant to call the function stored + //~| NOTE field, not a method + + let boxed_closure = BoxedObj { boxed_closure: Box::new(|| 42_u32) as Box u32> }; + boxed_closure.boxed_closure();//~ ERROR no method named `boxed_closure` found + //~^ HELP use `(boxed_closure.boxed_closure)(...)` if you meant to call the function stored + //~| NOTE field, not a method + + // test expression writing in the notes + + let w = Wrapper { wrap: o_func }; + w.wrap.closure();//~ ERROR no method named `closure` found + //~^ HELP use `(w.wrap.closure)(...)` if you meant to call the function stored + //~| NOTE field, not a method + + w.wrap.not_closure(); + //~^ ERROR no method named `not_closure` found + //~| NOTE field, not a method + //~| HELP did you mean to write `w.wrap.not_closure` instead of `w.wrap.not_closure(...)`? + + check_expression().closure();//~ ERROR no method named `closure` found + //~^ HELP use `(check_expression().closure)(...)` if you meant to call the function stored + //~| NOTE field, not a method +} + +impl FuncContainerOuter { + fn run(&self) { + unsafe { + (*self.container).f1(1); //~ ERROR no method named `f1` found + //~^ HELP use `((*self.container).f1)(...)` + //~| NOTE field, not a method + (*self.container).f2(1); //~ ERROR no method named `f2` found + //~^ HELP use `((*self.container).f2)(...)` + //~| NOTE field, not a method + (*self.container).f3(1); //~ ERROR no method named `f3` found + //~^ HELP use `((*self.container).f3)(...)` + //~| NOTE field, not a method + } + } +} diff --git a/src/test/ui/suggestions/confuse-field-and-method/issue-2392.stderr b/src/test/ui/suggestions/confuse-field-and-method/issue-2392.stderr new file mode 100644 index 00000000000..56e1060bdb9 --- /dev/null +++ b/src/test/ui/suggestions/confuse-field-and-method/issue-2392.stderr @@ -0,0 +1,90 @@ +error: no method named `closure` found for type `Obj<[closure@$DIR/issue-2392.rs:49:36: 49:41]>` in the current scope + --> $DIR/issue-2392.rs:50:15 + | +50 | o_closure.closure(); //~ ERROR no method named `closure` found + | ^^^^^^^ field, not a method + | + = help: use `(o_closure.closure)(...)` if you meant to call the function stored in the `closure` field + +error: no method named `not_closure` found for type `Obj<[closure@$DIR/issue-2392.rs:49:36: 49:41]>` in the current scope + --> $DIR/issue-2392.rs:54:15 + | +54 | o_closure.not_closure(); + | ^^^^^^^^^^^ field, not a method + | + = help: did you mean to write `o_closure.not_closure` instead of `o_closure.not_closure(...)`? + +error: no method named `closure` found for type `Obj u32 {func}>` in the current scope + --> $DIR/issue-2392.rs:60:12 + | +60 | o_func.closure(); //~ ERROR no method named `closure` found + | ^^^^^^^ field, not a method + | + = help: use `(o_func.closure)(...)` if you meant to call the function stored in the `closure` field + +error: no method named `boxed_closure` found for type `BoxedObj` in the current scope + --> $DIR/issue-2392.rs:65:14 + | +65 | boxed_fn.boxed_closure();//~ ERROR no method named `boxed_closure` found + | ^^^^^^^^^^^^^ field, not a method + | + = help: use `(boxed_fn.boxed_closure)(...)` if you meant to call the function stored in the `boxed_closure` field + +error: no method named `boxed_closure` found for type `BoxedObj` in the current scope + --> $DIR/issue-2392.rs:70:19 + | +70 | boxed_closure.boxed_closure();//~ ERROR no method named `boxed_closure` found + | ^^^^^^^^^^^^^ field, not a method + | + = help: use `(boxed_closure.boxed_closure)(...)` if you meant to call the function stored in the `boxed_closure` field + +error: no method named `closure` found for type `Obj u32 {func}>` in the current scope + --> $DIR/issue-2392.rs:77:12 + | +77 | w.wrap.closure();//~ ERROR no method named `closure` found + | ^^^^^^^ field, not a method + | + = help: use `(w.wrap.closure)(...)` if you meant to call the function stored in the `closure` field + +error: no method named `not_closure` found for type `Obj u32 {func}>` in the current scope + --> $DIR/issue-2392.rs:81:12 + | +81 | w.wrap.not_closure(); + | ^^^^^^^^^^^ field, not a method + | + = help: did you mean to write `w.wrap.not_closure` instead of `w.wrap.not_closure(...)`? + +error: no method named `closure` found for type `Obj + 'static>>` in the current scope + --> $DIR/issue-2392.rs:86:24 + | +86 | check_expression().closure();//~ ERROR no method named `closure` found + | ^^^^^^^ field, not a method + | + = help: use `(check_expression().closure)(...)` if you meant to call the function stored in the `closure` field + +error: no method named `f1` found for type `FuncContainer` in the current scope + --> $DIR/issue-2392.rs:94:31 + | +94 | (*self.container).f1(1); //~ ERROR no method named `f1` found + | ^^ field, not a method + | + = help: use `((*self.container).f1)(...)` if you meant to call the function stored in the `f1` field + +error: no method named `f2` found for type `FuncContainer` in the current scope + --> $DIR/issue-2392.rs:97:31 + | +97 | (*self.container).f2(1); //~ ERROR no method named `f2` found + | ^^ field, not a method + | + = help: use `((*self.container).f2)(...)` if you meant to call the function stored in the `f2` field + +error: no method named `f3` found for type `FuncContainer` in the current scope + --> $DIR/issue-2392.rs:100:31 + | +100 | (*self.container).f3(1); //~ ERROR no method named `f3` found + | ^^ field, not a method + | + = help: use `((*self.container).f3)(...)` if you meant to call the function stored in the `f3` field + +error: aborting due to 11 previous errors + diff --git a/src/test/ui/suggestions/confuse-field-and-method/issue-32128.rs b/src/test/ui/suggestions/confuse-field-and-method/issue-32128.rs new file mode 100644 index 00000000000..2fd7dc246c2 --- /dev/null +++ b/src/test/ui/suggestions/confuse-field-and-method/issue-32128.rs @@ -0,0 +1,27 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +struct Example { + example: Box i32> +} + +fn main() { + let demo = Example { + example: Box::new(|x| { + x + 1 + }) + }; + + demo.example(1); + //~^ ERROR no method named `example` + //~| HELP use `(demo.example)(...)` + //~| NOTE field, not a method + // (demo.example)(1); +} diff --git a/src/test/ui/suggestions/confuse-field-and-method/issue-32128.stderr b/src/test/ui/suggestions/confuse-field-and-method/issue-32128.stderr new file mode 100644 index 00000000000..0d2a895bad1 --- /dev/null +++ b/src/test/ui/suggestions/confuse-field-and-method/issue-32128.stderr @@ -0,0 +1,10 @@ +error: no method named `example` found for type `Example` in the current scope + --> $DIR/issue-32128.rs:22:10 + | +22 | demo.example(1); + | ^^^^^^^ field, not a method + | + = help: use `(demo.example)(...)` if you meant to call the function stored in the `example` field + +error: aborting due to previous error + diff --git a/src/test/ui/suggestions/confuse-field-and-method/issue-33784.rs b/src/test/ui/suggestions/confuse-field-and-method/issue-33784.rs new file mode 100644 index 00000000000..03c84fc57be --- /dev/null +++ b/src/test/ui/suggestions/confuse-field-and-method/issue-33784.rs @@ -0,0 +1,49 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::ops::Deref; + +struct Obj where F: FnMut() -> u32 { + fn_ptr: fn() -> (), + closure: F, +} + +struct C { + c_fn_ptr: fn() -> (), +} + +struct D(C); + +impl Deref for D { + type Target = C; + fn deref(&self) -> &C { + &self.0 + } +} + + +fn empty() {} + +fn main() { + let o = Obj { fn_ptr: empty, closure: || 42 }; + let p = &o; + p.closure(); //~ ERROR no method named `closure` found + //~^ HELP use `(p.closure)(...)` if you meant to call the function stored in the `closure` field + //~| NOTE `closure` is a field storing a function, not a method + let q = &p; + q.fn_ptr(); //~ ERROR no method named `fn_ptr` found + //~^ HELP use `(q.fn_ptr)(...)` if you meant to call the function stored in the `fn_ptr` field + //~| NOTE `fn_ptr` is a field storing a function, not a method + let r = D(C { c_fn_ptr: empty }); + let s = &r; + s.c_fn_ptr(); //~ ERROR no method named `c_fn_ptr` found + //~^ HELP use `(s.c_fn_ptr)(...)` if you meant to call the function stored in the `c_fn_ptr` + //~| NOTE `c_fn_ptr` is a field storing a function, not a method +} diff --git a/src/test/ui/suggestions/confuse-field-and-method/issue-33784.stderr b/src/test/ui/suggestions/confuse-field-and-method/issue-33784.stderr new file mode 100644 index 00000000000..70d64e3ffa3 --- /dev/null +++ b/src/test/ui/suggestions/confuse-field-and-method/issue-33784.stderr @@ -0,0 +1,26 @@ +error: no method named `closure` found for type `&Obj<[closure@$DIR/issue-33784.rs:35:43: 35:48]>` in the current scope + --> $DIR/issue-33784.rs:37:7 + | +37 | p.closure(); //~ ERROR no method named `closure` found + | ^^^^^^^ field, not a method + | + = help: use `(p.closure)(...)` if you meant to call the function stored in the `closure` field + +error: no method named `fn_ptr` found for type `&&Obj<[closure@$DIR/issue-33784.rs:35:43: 35:48]>` in the current scope + --> $DIR/issue-33784.rs:41:7 + | +41 | q.fn_ptr(); //~ ERROR no method named `fn_ptr` found + | ^^^^^^ field, not a method + | + = help: use `(q.fn_ptr)(...)` if you meant to call the function stored in the `fn_ptr` field + +error: no method named `c_fn_ptr` found for type `&D` in the current scope + --> $DIR/issue-33784.rs:46:7 + | +46 | s.c_fn_ptr(); //~ ERROR no method named `c_fn_ptr` found + | ^^^^^^^^ field, not a method + | + = help: use `(s.c_fn_ptr)(...)` if you meant to call the function stored in the `c_fn_ptr` field + +error: aborting due to 3 previous errors + -- cgit 1.4.1-3-g733a5 From 11ce5b72a21718f6d49b5f40b71ea0f53b8ea4bc Mon Sep 17 00:00:00 2001 From: topecongiro Date: Wed, 22 Mar 2017 16:17:15 +0900 Subject: Make overlapping_inherent_impls lint a hard error --- src/librustc_lint/lib.rs | 5 +---- src/librustc_typeck/coherence/inherent_impls.rs | 1 - src/librustc_typeck/diagnostics.rs | 1 + src/test/compile-fail/coherence-overlapping-inherent-impl-trait.rs | 2 -- src/test/compile-fail/inherent-overlap.rs | 3 --- 5 files changed, 2 insertions(+), 10 deletions(-) (limited to 'src/test') diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index 05dbbc09870..8d759d89135 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -196,10 +196,6 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) { id: LintId::of(SUPER_OR_SELF_IN_GLOBAL_PATH), reference: "issue #36888 ", }, - FutureIncompatibleInfo { - id: LintId::of(OVERLAPPING_INHERENT_IMPLS), - reference: "issue #36889 ", - }, FutureIncompatibleInfo { id: LintId::of(ILLEGAL_FLOATING_POINT_CONSTANT_PATTERN), reference: "issue #36890 ", @@ -263,4 +259,5 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) { store.register_removed("drop_with_repr_extern", "drop flags have been removed"); store.register_removed("transmute_from_fn_item_types", "always cast functions before transmuting them"); + store.register_removed("overlapping_inherent_impls", "converted into hard error, see #36889"); } diff --git a/src/librustc_typeck/coherence/inherent_impls.rs b/src/librustc_typeck/coherence/inherent_impls.rs index 3a39df505eb..dc4bd7733fc 100644 --- a/src/librustc_typeck/coherence/inherent_impls.rs +++ b/src/librustc_typeck/coherence/inherent_impls.rs @@ -322,4 +322,3 @@ impl<'a, 'tcx> InherentCollect<'a, 'tcx> { } } } - diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index bd6129eb5be..fb951fd20e5 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -4212,4 +4212,5 @@ register_diagnostics! { // but `{}` was found in the type `{}` E0567, // auto traits can not have type parameters E0568, // auto-traits can not have predicates, + E0592, // duplicate definitions with name `{}` } diff --git a/src/test/compile-fail/coherence-overlapping-inherent-impl-trait.rs b/src/test/compile-fail/coherence-overlapping-inherent-impl-trait.rs index 08e8605e917..158d3606104 100644 --- a/src/test/compile-fail/coherence-overlapping-inherent-impl-trait.rs +++ b/src/test/compile-fail/coherence-overlapping-inherent-impl-trait.rs @@ -9,10 +9,8 @@ // except according to those terms. #![allow(dead_code)] -#![deny(overlapping_inherent_impls)] trait C {} impl C { fn f() {} } //~ ERROR duplicate definitions with name `f` -//~^ WARN: this was previously accepted impl C { fn f() {} } fn main() { } diff --git a/src/test/compile-fail/inherent-overlap.rs b/src/test/compile-fail/inherent-overlap.rs index 00d41244639..18e77ddfd2c 100644 --- a/src/test/compile-fail/inherent-overlap.rs +++ b/src/test/compile-fail/inherent-overlap.rs @@ -17,7 +17,6 @@ struct Foo; impl Foo { fn id() {} //~ ERROR duplicate definitions - //~^ WARN previously accepted } impl Foo { @@ -28,7 +27,6 @@ struct Bar(T); impl Bar { fn bar(&self) {} //~ ERROR duplicate definitions - //~^ WARN previously accepted } impl Bar { @@ -39,7 +37,6 @@ struct Baz(T); impl Baz { fn baz(&self) {} //~ ERROR duplicate definitions - //~^ WARN previously accepted } impl Baz> { -- cgit 1.4.1-3-g733a5 From f08d5ad4c59ca5fc1c961a94c53807d70959c375 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Wed, 15 Mar 2017 00:22:48 +0000 Subject: Refactor how spans are combined in the parser. --- src/librustc/middle/resolve_lifetime.rs | 5 +- src/librustc_metadata/cstore_impl.rs | 4 +- src/librustc_metadata/decoder.rs | 6 +- src/librustc_save_analysis/lib.rs | 2 +- src/librustc_save_analysis/span_utils.rs | 4 +- src/libsyntax/ast.rs | 10 +- src/libsyntax/attr.rs | 15 +- src/libsyntax/codemap.rs | 4 - src/libsyntax/ext/tt/macro_parser.rs | 9 +- src/libsyntax/parse/attr.rs | 29 +- src/libsyntax/parse/lexer/mod.rs | 42 +- src/libsyntax/parse/lexer/unicode_chars.rs | 4 +- src/libsyntax/parse/mod.rs | 6 +- src/libsyntax/parse/parser.rs | 617 ++++++++++----------- src/libsyntax_ext/format.rs | 15 +- src/libsyntax_pos/lib.rs | 16 +- src/test/compile-fail/imports/macro-paths.rs | 2 - src/test/compile-fail/imports/macros.rs | 2 - .../compile-fail/imports/shadow_builtin_macros.rs | 1 - src/test/compile-fail/issue-25385.rs | 1 - src/test/run-pass/syntax-extension-source-utils.rs | 2 +- .../ui/macros/macro_path_as_generic_bound.stderr | 5 +- 22 files changed, 363 insertions(+), 438 deletions(-) (limited to 'src/test') diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index 5094e28475b..8037570d24a 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -29,7 +29,7 @@ use syntax::ast; use syntax::attr; use syntax::ptr::P; use syntax::symbol::keywords; -use syntax_pos::{mk_sp, Span}; +use syntax_pos::Span; use errors::DiagnosticBuilder; use util::nodemap::{NodeMap, NodeSet, FxHashSet, FxHashMap, DefIdMap}; use rustc_back::slice; @@ -1468,8 +1468,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { self.resolve_lifetime_ref(bound); } else { self.insert_lifetime(bound, Region::Static); - let full_span = mk_sp(lifetime_i.lifetime.span.lo, bound.span.hi); - self.sess.struct_span_warn(full_span, + self.sess.struct_span_warn(lifetime_i.lifetime.span.to(bound.span), &format!("unnecessary lifetime parameter `{}`", lifetime_i.lifetime.name)) .help(&format!("you can use the `'static` lifetime directly, in place \ of `{}`", lifetime_i.lifetime.name)) diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index 3e9b6a6226a..41a2e8a8d55 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -36,7 +36,7 @@ use syntax::ast; use syntax::attr; use syntax::parse::filemap_to_stream; use syntax::symbol::Symbol; -use syntax_pos::{mk_sp, Span}; +use syntax_pos::{Span, NO_EXPANSION}; use rustc::hir::svh::Svh; use rustc_back::target::Target; use rustc::hir; @@ -395,7 +395,7 @@ impl CrateStore for cstore::CStore { let source_name = format!("<{} macros>", name); let filemap = sess.parse_sess.codemap().new_filemap(source_name, None, def.body); - let local_span = mk_sp(filemap.start_pos, filemap.end_pos); + let local_span = Span { lo: filemap.start_pos, hi: filemap.end_pos, ctxt: NO_EXPANSION }; let body = filemap_to_stream(&sess.parse_sess, filemap); // Mark the attrs as used diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 3de1e3442c6..43e076e799b 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -39,7 +39,7 @@ use syntax::attr; use syntax::ast; use syntax::codemap; use syntax::ext::base::MacroKind; -use syntax_pos::{self, Span, BytePos, Pos, DUMMY_SP}; +use syntax_pos::{self, Span, BytePos, Pos, DUMMY_SP, NO_EXPANSION}; pub struct DecodeContext<'a, 'tcx: 'a> { opaque: opaque::Decoder<'a>, @@ -243,7 +243,7 @@ impl<'a, 'tcx> SpecializedDecoder for DecodeContext<'a, 'tcx> { let sess = if let Some(sess) = self.sess { sess } else { - return Ok(syntax_pos::mk_sp(lo, hi)); + return Ok(Span { lo: lo, hi: hi, ctxt: NO_EXPANSION }); }; let (lo, hi) = if lo > hi { @@ -290,7 +290,7 @@ impl<'a, 'tcx> SpecializedDecoder for DecodeContext<'a, 'tcx> { let lo = (lo - filemap.original_start_pos) + filemap.translated_filemap.start_pos; let hi = (hi - filemap.original_start_pos) + filemap.translated_filemap.start_pos; - Ok(syntax_pos::mk_sp(lo, hi)) + Ok(Span { lo: lo, hi: hi, ctxt: NO_EXPANSION }) } } diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index fd6803e087a..1de9fbc8e49 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -742,7 +742,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { let ident_start = text.find(&name).expect("Name not in signature?"); let ident_end = ident_start + name.len(); Signature { - span: mk_sp(item.span.lo, item.span.lo + BytePos(text.len() as u32)), + span: Span { hi: item.span.lo + BytePos(text.len() as u32), ..item.span }, text: text, ident_start: ident_start, ident_end: ident_end, diff --git a/src/librustc_save_analysis/span_utils.rs b/src/librustc_save_analysis/span_utils.rs index c19f805a285..af3efb48090 100644 --- a/src/librustc_save_analysis/span_utils.rs +++ b/src/librustc_save_analysis/span_utils.rs @@ -305,10 +305,10 @@ impl<'a> SpanUtils<'a> { continue; } if let TokenTree::Token(_, token::Semi) = tok { - return self.snippet(mk_sp(first_span.lo, prev.span().hi)); + return self.snippet(first_span.to(prev.span())); } else if let TokenTree::Delimited(_, ref d) = tok { if d.delim == token::Brace { - return self.snippet(mk_sp(first_span.lo, prev.span().hi)); + return self.snippet(first_span.to(prev.span())); } } prev = tok; diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index a4bebd311de..9eb86aa006d 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -17,7 +17,7 @@ pub use self::PathParameters::*; pub use symbol::{Ident, Symbol as Name}; pub use util::ThinVec; -use syntax_pos::{mk_sp, BytePos, Span, DUMMY_SP}; +use syntax_pos::{Span, DUMMY_SP}; use codemap::{respan, Spanned}; use abi::Abi; use ext::hygiene::{Mark, SyntaxContext}; @@ -1433,7 +1433,7 @@ impl Arg { TyKind::Rptr(lt, MutTy{ref ty, mutbl}) if ty.node == TyKind::ImplicitSelf => { Some(respan(self.pat.span, SelfKind::Region(lt, mutbl))) } - _ => Some(respan(mk_sp(self.pat.span.lo, self.ty.span.hi), + _ => Some(respan(self.pat.span.to(self.ty.span), SelfKind::Explicit(self.ty.clone(), mutbl))), } } @@ -1450,7 +1450,7 @@ impl Arg { } pub fn from_self(eself: ExplicitSelf, eself_ident: SpannedIdent) -> Arg { - let span = mk_sp(eself.span.lo, eself_ident.span.hi); + let span = eself.span.to(eself_ident.span); let infer_ty = P(Ty { id: DUMMY_NODE_ID, node: TyKind::ImplicitSelf, @@ -1687,11 +1687,11 @@ pub struct PolyTraitRef { } impl PolyTraitRef { - pub fn new(lifetimes: Vec, path: Path, lo: BytePos, hi: BytePos) -> Self { + pub fn new(lifetimes: Vec, path: Path, span: Span) -> Self { PolyTraitRef { bound_lifetimes: lifetimes, trait_ref: TraitRef { path: path, ref_id: DUMMY_NODE_ID }, - span: mk_sp(lo, hi), + span: span, } } } diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs index 2f1efd6ad00..5dcce2572af 100644 --- a/src/libsyntax/attr.rs +++ b/src/libsyntax/attr.rs @@ -18,8 +18,8 @@ use ast; use ast::{AttrId, Attribute, Name, Ident}; use ast::{MetaItem, MetaItemKind, NestedMetaItem, NestedMetaItemKind}; use ast::{Lit, LitKind, Expr, ExprKind, Item, Local, Stmt, StmtKind}; -use codemap::{Spanned, spanned, dummy_spanned, mk_sp}; -use syntax_pos::{Span, BytePos, DUMMY_SP}; +use codemap::{Spanned, respan, dummy_spanned}; +use syntax_pos::{Span, DUMMY_SP}; use errors::Handler; use feature_gate::{Features, GatedCfg}; use parse::lexer::comments::{doc_comment_style, strip_doc_comment_decoration}; @@ -447,17 +447,16 @@ pub fn mk_spanned_attr_outer(sp: Span, id: AttrId, item: MetaItem) -> Attribute } } -pub fn mk_sugared_doc_attr(id: AttrId, text: Symbol, lo: BytePos, hi: BytePos) - -> Attribute { +pub fn mk_sugared_doc_attr(id: AttrId, text: Symbol, span: Span) -> Attribute { let style = doc_comment_style(&text.as_str()); - let lit = spanned(lo, hi, LitKind::Str(text, ast::StrStyle::Cooked)); + let lit = respan(span, LitKind::Str(text, ast::StrStyle::Cooked)); Attribute { id: id, style: style, - path: ast::Path::from_ident(mk_sp(lo, hi), ast::Ident::from_str("doc")), - tokens: MetaItemKind::NameValue(lit).tokens(mk_sp(lo, hi)), + path: ast::Path::from_ident(span, ast::Ident::from_str("doc")), + tokens: MetaItemKind::NameValue(lit).tokens(span), is_sugared_doc: true, - span: mk_sp(lo, hi), + span: span, } } diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs index ba199eacb62..4d67390d442 100644 --- a/src/libsyntax/codemap.rs +++ b/src/libsyntax/codemap.rs @@ -49,10 +49,6 @@ pub struct Spanned { pub span: Span, } -pub fn spanned(lo: BytePos, hi: BytePos, t: T) -> Spanned { - respan(mk_sp(lo, hi), t) -} - pub fn respan(sp: Span, t: T) -> Spanned { Spanned {node: t, span: sp} } diff --git a/src/libsyntax/ext/tt/macro_parser.rs b/src/libsyntax/ext/tt/macro_parser.rs index ed17f0f956c..9ee427eed35 100644 --- a/src/libsyntax/ext/tt/macro_parser.rs +++ b/src/libsyntax/ext/tt/macro_parser.rs @@ -79,7 +79,7 @@ pub use self::ParseResult::*; use self::TokenTreeOrTokenTreeVec::*; use ast::Ident; -use syntax_pos::{self, BytePos, mk_sp, Span}; +use syntax_pos::{self, BytePos, Span}; use codemap::Spanned; use errors::FatalError; use ext::tt::quoted::{self, TokenTree}; @@ -285,7 +285,7 @@ fn inner_parse_loop(sess: &ParseSess, eof_eis: &mut SmallVector>, bb_eis: &mut SmallVector>, token: &Token, - span: &syntax_pos::Span) + span: syntax_pos::Span) -> ParseResult<()> { while let Some(mut ei) = cur_eis.pop() { // When unzipped trees end, remove them @@ -323,8 +323,7 @@ fn inner_parse_loop(sess: &ParseSess, for idx in ei.match_lo..ei.match_hi { let sub = ei.matches[idx].clone(); new_pos.matches[idx] - .push(Rc::new(MatchedSeq(sub, mk_sp(ei.sp_lo, - span.hi)))); + .push(Rc::new(MatchedSeq(sub, Span { lo: ei.sp_lo, ..span }))); } new_pos.match_cur = ei.match_hi; @@ -426,7 +425,7 @@ pub fn parse(sess: &ParseSess, tts: TokenStream, ms: &[TokenTree], directory: Op assert!(next_eis.is_empty()); match inner_parse_loop(sess, &mut cur_eis, &mut next_eis, &mut eof_eis, &mut bb_eis, - &parser.token, &parser.span) { + &parser.token, parser.span) { Success(_) => {}, Failure(sp, tok) => return Failure(sp, tok), Error(sp, msg) => return Error(sp, msg), diff --git a/src/libsyntax/parse/attr.rs b/src/libsyntax/parse/attr.rs index 53106214fa3..92cec462ffb 100644 --- a/src/libsyntax/parse/attr.rs +++ b/src/libsyntax/parse/attr.rs @@ -10,8 +10,7 @@ use attr; use ast; -use syntax_pos::{mk_sp, Span}; -use codemap::spanned; +use codemap::respan; use parse::common::SeqSep; use parse::PResult; use parse::token::{self, Nonterminal}; @@ -49,8 +48,7 @@ impl<'a> Parser<'a> { just_parsed_doc_comment = false; } token::DocComment(s) => { - let Span { lo, hi, .. } = self.span; - let attr = attr::mk_sugared_doc_attr(attr::mk_attr_id(), s, lo, hi); + let attr = attr::mk_sugared_doc_attr(attr::mk_attr_id(), s, self.span); if attr.style != ast::AttrStyle::Outer { let mut err = self.fatal("expected outer doc comment"); err.note("inner doc comments like this (starting with \ @@ -94,7 +92,7 @@ impl<'a> Parser<'a> { self.token); let (span, path, tokens, mut style) = match self.token { token::Pound => { - let lo = self.span.lo; + let lo = self.span; self.bump(); if inner_parse_policy == InnerAttributeParsePolicy::Permitted { @@ -122,9 +120,9 @@ impl<'a> Parser<'a> { self.expect(&token::OpenDelim(token::Bracket))?; let (path, tokens) = self.parse_path_and_tokens()?; self.expect(&token::CloseDelim(token::Bracket))?; - let hi = self.prev_span.hi; + let hi = self.prev_span; - (mk_sp(lo, hi), path, tokens, style) + (lo.to(hi), path, tokens, style) } _ => { let token_str = self.this_token_to_string(); @@ -189,8 +187,7 @@ impl<'a> Parser<'a> { } token::DocComment(s) => { // we need to get the position of this token before we bump. - let Span { lo, hi, .. } = self.span; - let attr = attr::mk_sugared_doc_attr(attr::mk_attr_id(), s, lo, hi); + let attr = attr::mk_sugared_doc_attr(attr::mk_attr_id(), s, self.span); if attr.style == ast::AttrStyle::Inner { attrs.push(attr); self.bump(); @@ -238,11 +235,10 @@ impl<'a> Parser<'a> { return Ok(meta); } - let lo = self.span.lo; + let lo = self.span; let ident = self.parse_ident()?; let node = self.parse_meta_item_kind()?; - let hi = self.prev_span.hi; - Ok(ast::MetaItem { name: ident.name, node: node, span: mk_sp(lo, hi) }) + Ok(ast::MetaItem { name: ident.name, node: node, span: lo.to(self.prev_span) }) } pub fn parse_meta_item_kind(&mut self) -> PResult<'a, ast::MetaItemKind> { @@ -258,26 +254,25 @@ impl<'a> Parser<'a> { /// matches meta_item_inner : (meta_item | UNSUFFIXED_LIT) ; fn parse_meta_item_inner(&mut self) -> PResult<'a, ast::NestedMetaItem> { - let sp = self.span; - let lo = self.span.lo; + let lo = self.span; match self.parse_unsuffixed_lit() { Ok(lit) => { - return Ok(spanned(lo, self.prev_span.hi, ast::NestedMetaItemKind::Literal(lit))) + return Ok(respan(lo.to(self.prev_span), ast::NestedMetaItemKind::Literal(lit))) } Err(ref mut err) => self.diagnostic().cancel(err) } match self.parse_meta_item() { Ok(mi) => { - return Ok(spanned(lo, self.prev_span.hi, ast::NestedMetaItemKind::MetaItem(mi))) + return Ok(respan(lo.to(self.prev_span), ast::NestedMetaItemKind::MetaItem(mi))) } Err(ref mut err) => self.diagnostic().cancel(err) } let found = self.this_token_to_string(); let msg = format!("expected unsuffixed literal or identifier, found {}", found); - Err(self.diagnostic().struct_span_err(sp, &msg)) + Err(self.diagnostic().struct_span_err(lo, &msg)) } /// matches meta_seq = ( COMMASEP(meta_item_inner) ) diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs index d48cf6911ed..920b2c401e2 100644 --- a/src/libsyntax/parse/lexer/mod.rs +++ b/src/libsyntax/parse/lexer/mod.rs @@ -9,7 +9,7 @@ // except according to those terms. use ast::{self, Ident}; -use syntax_pos::{self, BytePos, CharPos, Pos, Span}; +use syntax_pos::{self, BytePos, CharPos, Pos, Span, NO_EXPANSION}; use codemap::CodeMap; use errors::{FatalError, DiagnosticBuilder}; use parse::{token, ParseSess}; @@ -68,6 +68,10 @@ pub struct StringReader<'a> { open_braces: Vec<(token::DelimToken, Span)>, } +fn mk_sp(lo: BytePos, hi: BytePos) -> Span { + Span { lo: lo, hi: hi, ctxt: NO_EXPANSION } +} + impl<'a> StringReader<'a> { fn next_token(&mut self) -> TokenAndSpan where Self: Sized { let res = self.try_next_token(); @@ -225,12 +229,12 @@ impl<'a> StringReader<'a> { /// Report a fatal error spanning [`from_pos`, `to_pos`). fn fatal_span_(&self, from_pos: BytePos, to_pos: BytePos, m: &str) -> FatalError { - self.fatal_span(syntax_pos::mk_sp(from_pos, to_pos), m) + self.fatal_span(mk_sp(from_pos, to_pos), m) } /// Report a lexical error spanning [`from_pos`, `to_pos`). fn err_span_(&self, from_pos: BytePos, to_pos: BytePos, m: &str) { - self.err_span(syntax_pos::mk_sp(from_pos, to_pos), m) + self.err_span(mk_sp(from_pos, to_pos), m) } /// Report a lexical error spanning [`from_pos`, `to_pos`), appending an @@ -254,7 +258,7 @@ impl<'a> StringReader<'a> { for c in c.escape_default() { m.push(c) } - self.sess.span_diagnostic.struct_span_fatal(syntax_pos::mk_sp(from_pos, to_pos), &m[..]) + self.sess.span_diagnostic.struct_span_fatal(mk_sp(from_pos, to_pos), &m[..]) } /// Report a lexical error spanning [`from_pos`, `to_pos`), appending an @@ -278,7 +282,7 @@ impl<'a> StringReader<'a> { for c in c.escape_default() { m.push(c) } - self.sess.span_diagnostic.struct_span_err(syntax_pos::mk_sp(from_pos, to_pos), &m[..]) + self.sess.span_diagnostic.struct_span_err(mk_sp(from_pos, to_pos), &m[..]) } /// Report a lexical error spanning [`from_pos`, `to_pos`), appending the @@ -302,11 +306,11 @@ impl<'a> StringReader<'a> { None => { if self.is_eof() { self.peek_tok = token::Eof; - self.peek_span = syntax_pos::mk_sp(self.filemap.end_pos, self.filemap.end_pos); + self.peek_span = mk_sp(self.filemap.end_pos, self.filemap.end_pos); } else { let start_bytepos = self.pos; self.peek_tok = self.next_token_inner()?; - self.peek_span = syntax_pos::mk_sp(start_bytepos, self.pos); + self.peek_span = mk_sp(start_bytepos, self.pos); }; } } @@ -489,7 +493,7 @@ impl<'a> StringReader<'a> { if let Some(c) = self.ch { if c.is_whitespace() { let msg = "called consume_any_line_comment, but there was whitespace"; - self.sess.span_diagnostic.span_err(syntax_pos::mk_sp(self.pos, self.pos), msg); + self.sess.span_diagnostic.span_err(mk_sp(self.pos, self.pos), msg); } } @@ -532,13 +536,13 @@ impl<'a> StringReader<'a> { Some(TokenAndSpan { tok: tok, - sp: syntax_pos::mk_sp(start_bpos, self.pos), + sp: mk_sp(start_bpos, self.pos), }) }) } else { Some(TokenAndSpan { tok: token::Comment, - sp: syntax_pos::mk_sp(start_bpos, self.pos), + sp: mk_sp(start_bpos, self.pos), }) }; } @@ -571,7 +575,7 @@ impl<'a> StringReader<'a> { } return Some(TokenAndSpan { tok: token::Shebang(self.name_from(start)), - sp: syntax_pos::mk_sp(start, self.pos), + sp: mk_sp(start, self.pos), }); } } @@ -599,7 +603,7 @@ impl<'a> StringReader<'a> { } let c = Some(TokenAndSpan { tok: token::Whitespace, - sp: syntax_pos::mk_sp(start_bpos, self.pos), + sp: mk_sp(start_bpos, self.pos), }); debug!("scanning whitespace: {:?}", c); c @@ -661,7 +665,7 @@ impl<'a> StringReader<'a> { Some(TokenAndSpan { tok: tok, - sp: syntax_pos::mk_sp(start_bpos, self.pos), + sp: mk_sp(start_bpos, self.pos), }) }) } @@ -858,7 +862,7 @@ impl<'a> StringReader<'a> { let valid = if self.ch_is('{') { self.scan_unicode_escape(delim) && !ascii_only } else { - let span = syntax_pos::mk_sp(start, self.pos); + let span = mk_sp(start, self.pos); self.sess.span_diagnostic .struct_span_err(span, "incorrect unicode escape sequence") .span_help(span, @@ -896,13 +900,13 @@ impl<'a> StringReader<'a> { }, c); if e == '\r' { - err.span_help(syntax_pos::mk_sp(escaped_pos, pos), + err.span_help(mk_sp(escaped_pos, pos), "this is an isolated carriage return; consider \ checking your editor and version control \ settings"); } if (e == '{' || e == '}') && !ascii_only { - err.span_help(syntax_pos::mk_sp(escaped_pos, pos), + err.span_help(mk_sp(escaped_pos, pos), "if used in a formatting string, curly braces \ are escaped with `{{` and `}}`"); } @@ -1735,7 +1739,7 @@ mod tests { sp: Span { lo: BytePos(21), hi: BytePos(23), - expn_id: NO_EXPANSION, + ctxt: NO_EXPANSION, }, }; assert_eq!(tok1, tok2); @@ -1749,7 +1753,7 @@ mod tests { sp: Span { lo: BytePos(24), hi: BytePos(28), - expn_id: NO_EXPANSION, + ctxt: NO_EXPANSION, }, }; assert_eq!(tok3, tok4); @@ -1908,7 +1912,7 @@ mod tests { let mut lexer = setup(&cm, &sh, "// test\r\n/// test\r\n".to_string()); let comment = lexer.next_token(); assert_eq!(comment.tok, token::Comment); - assert_eq!(comment.sp, ::syntax_pos::mk_sp(BytePos(0), BytePos(7))); + assert_eq!((comment.sp.lo, comment.sp.hi), (BytePos(0), BytePos(7))); assert_eq!(lexer.next_token().tok, token::Whitespace); assert_eq!(lexer.next_token().tok, token::DocComment(Symbol::intern("/// test"))); diff --git a/src/libsyntax/parse/lexer/unicode_chars.rs b/src/libsyntax/parse/lexer/unicode_chars.rs index 6da3e5de75c..4df23da3c9c 100644 --- a/src/libsyntax/parse/lexer/unicode_chars.rs +++ b/src/libsyntax/parse/lexer/unicode_chars.rs @@ -11,7 +11,7 @@ // Characters and their corresponding confusables were collected from // http://www.unicode.org/Public/security/revision-06/confusables.txt -use syntax_pos::mk_sp as make_span; +use syntax_pos::{Span, NO_EXPANSION}; use errors::DiagnosticBuilder; use super::StringReader; @@ -234,7 +234,7 @@ pub fn check_for_substitution<'a>(reader: &StringReader<'a>, .iter() .find(|&&(c, _, _)| c == ch) .map(|&(_, u_name, ascii_char)| { - let span = make_span(reader.pos, reader.next_pos); + let span = Span { lo: reader.pos, hi: reader.next_pos, ctxt: NO_EXPANSION }; match ASCII_ARRAY.iter().find(|&&(c, _)| c == ascii_char) { Some(&(ascii_char, ascii_name)) => { let msg = diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index e188bcaf105..b5d0a46de49 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -12,7 +12,7 @@ use ast::{self, CrateConfig}; use codemap::CodeMap; -use syntax_pos::{self, Span, FileMap}; +use syntax_pos::{self, Span, FileMap, NO_EXPANSION}; use errors::{Handler, ColorConfig, DiagnosticBuilder}; use feature_gate::UnstableFeatures; use parse::parser::Parser; @@ -178,7 +178,7 @@ pub fn filemap_to_parser<'a>(sess: &'a ParseSess, filemap: Rc, ) -> Par let mut parser = stream_to_parser(sess, filemap_to_stream(sess, filemap)); if parser.token == token::Eof && parser.span == syntax_pos::DUMMY_SP { - parser.span = syntax_pos::mk_sp(end_pos, end_pos); + parser.span = Span { lo: end_pos, hi: end_pos, ctxt: NO_EXPANSION }; } parser @@ -665,7 +665,7 @@ mod tests { // produce a syntax_pos::span fn sp(a: u32, b: u32) -> Span { - Span {lo: BytePos(a), hi: BytePos(b), expn_id: NO_EXPANSION} + Span {lo: BytePos(a), hi: BytePos(b), ctxt: NO_EXPANSION} } fn str2seg(s: &str, lo: u32, hi: u32) -> ast::PathSegment { diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index e9eb4fbcc91..b0611d75290 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -40,8 +40,8 @@ use ast::{Visibility, WhereClause}; use ast::{BinOpKind, UnOp}; use ast::RangeEnd; use {ast, attr}; -use codemap::{self, CodeMap, Spanned, spanned, respan}; -use syntax_pos::{self, Span, BytePos, mk_sp}; +use codemap::{self, CodeMap, Spanned, respan}; +use syntax_pos::{self, Span, BytePos}; use errors::{self, DiagnosticBuilder}; use parse::{self, classify, token}; use parse::common::SeqSep; @@ -108,13 +108,13 @@ macro_rules! maybe_whole_expr { $p.bump(); let span = $p.span; let kind = ExprKind::Path(None, (*path).clone()); - return Ok($p.mk_expr(span.lo, span.hi, kind, ThinVec::new())); + return Ok($p.mk_expr(span, kind, ThinVec::new())); } token::NtBlock(ref block) => { $p.bump(); let span = $p.span; let kind = ExprKind::Block((*block).clone()); - return Ok($p.mk_expr(span.lo, span.hi, kind, ThinVec::new())); + return Ok($p.mk_expr(span, kind, ThinVec::new())); } _ => {}, }; @@ -731,7 +731,7 @@ impl<'a> Parser<'a> { token::AndAnd => { let span = self.span; let lo = span.lo + BytePos(1); - Ok(self.bump_with(token::BinOp(token::And), lo, span.hi)) + Ok(self.bump_with(token::BinOp(token::And), Span { lo: lo, ..span })) } _ => self.unexpected() } @@ -765,7 +765,7 @@ impl<'a> Parser<'a> { token::BinOp(token::Shl) => { let span = self.span; let lo = span.lo + BytePos(1); - self.bump_with(token::Lt, lo, span.hi); + self.bump_with(token::Lt, Span { lo: lo, ..span }); true } _ => false, @@ -793,17 +793,17 @@ impl<'a> Parser<'a> { token::BinOp(token::Shr) => { let span = self.span; let lo = span.lo + BytePos(1); - Ok(self.bump_with(token::Gt, lo, span.hi)) + Ok(self.bump_with(token::Gt, Span { lo: lo, ..span })) } token::BinOpEq(token::Shr) => { let span = self.span; let lo = span.lo + BytePos(1); - Ok(self.bump_with(token::Ge, lo, span.hi)) + Ok(self.bump_with(token::Ge, Span { lo: lo, ..span })) } token::Ge => { let span = self.span; let lo = span.lo + BytePos(1); - Ok(self.bump_with(token::Eq, lo, span.hi)) + Ok(self.bump_with(token::Eq, Span { lo: lo, ..span })) } _ => self.unexpected() } @@ -997,12 +997,12 @@ impl<'a> Parser<'a> { -> PResult<'a, Spanned>> where F: FnMut(&mut Parser<'a>) -> PResult<'a, T>, { - let lo = self.span.lo; + let lo = self.span; self.expect(bra)?; let result = self.parse_seq_to_before_end(ket, sep, f); - let hi = self.span.hi; + let hi = self.span; self.bump(); - Ok(spanned(lo, hi, result)) + Ok(respan(lo.to(hi), result)) } /// Advance the parser by one token @@ -1033,16 +1033,13 @@ impl<'a> Parser<'a> { /// Advance the parser using provided token as a next one. Use this when /// consuming a part of a token. For example a single `<` from `<<`. - pub fn bump_with(&mut self, - next: token::Token, - lo: BytePos, - hi: BytePos) { - self.prev_span = mk_sp(self.span.lo, lo); + pub fn bump_with(&mut self, next: token::Token, span: Span) { + self.prev_span = Span { hi: span.lo, ..self.span }; // It would be incorrect to record the kind of the current token, but // fortunately for tokens currently using `bump_with`, the // prev_token_kind will be of no use anyway. self.prev_token_kind = PrevTokenKind::Other; - self.span = mk_sp(lo, hi); + self.span = span; self.token = next; self.expected_tokens.clear(); } @@ -1173,7 +1170,7 @@ impl<'a> Parser<'a> { pub fn parse_trait_item(&mut self) -> PResult<'a, TraitItem> { maybe_whole!(self, NtTraitItem, |x| x); let mut attrs = self.parse_outer_attributes()?; - let lo = self.span.lo; + let lo = self.span; let (name, node) = if self.eat_keyword(keywords::Type) { let TyParam {ident, bounds, default, ..} = self.parse_ty_param(vec![])?; @@ -1197,7 +1194,7 @@ impl<'a> Parser<'a> { } else if self.token.is_path_start() { // trait item macro. // code copied from parse_macro_use_or_failure... abstraction! - let lo = self.span.lo; + let lo = self.span; let pth = self.parse_path(PathStyle::Mod)?; self.expect(&token::Not)?; @@ -1207,7 +1204,7 @@ impl<'a> Parser<'a> { self.expect(&token::Semi)? } - let mac = spanned(lo, self.prev_span.hi, Mac_ { path: pth, tts: tts }); + let mac = respan(lo.to(self.prev_span), Mac_ { path: pth, tts: tts }); (keywords::Invalid.ident(), ast::TraitItemKind::Macro(mac)) } else { let (constness, unsafety, abi) = match self.parse_fn_front_matter() { @@ -1277,7 +1274,7 @@ impl<'a> Parser<'a> { ident: name, attrs: attrs, node: node, - span: mk_sp(lo, self.prev_span.hi), + span: lo.to(self.prev_span), }) } @@ -1298,8 +1295,7 @@ impl<'a> Parser<'a> { if self.eat(&token::RArrow) { Ok(FunctionRetTy::Ty(self.parse_ty_no_plus()?)) } else { - let pos = self.span.lo; - Ok(FunctionRetTy::Default(mk_sp(pos, pos))) + Ok(FunctionRetTy::Default(Span { hi: self.span.lo, ..self.span })) } } @@ -1320,7 +1316,7 @@ impl<'a> Parser<'a> { fn parse_ty_common(&mut self, allow_plus: bool) -> PResult<'a, P> { maybe_whole!(self, NtTy, |x| x); - let lo = self.span.lo; + let lo = self.span; let node = if self.eat(&token::OpenDelim(token::Paren)) { // `(TYPE)` is a parenthesized type. // `(TYPE,)` is a tuple with a single field of type TYPE. @@ -1344,7 +1340,7 @@ impl<'a> Parser<'a> { TyKind::Path(None, ref path) if allow_plus && self.token == token::BinOp(token::Plus) => { self.bump(); // `+` - let pt = PolyTraitRef::new(Vec::new(), path.clone(), lo, self.prev_span.hi); + let pt = PolyTraitRef::new(Vec::new(), path.clone(), lo.to(self.prev_span)); let mut bounds = vec![TraitTyParamBound(pt, TraitBoundModifier::None)]; bounds.append(&mut self.parse_ty_param_bounds()?); TyKind::TraitObject(bounds) @@ -1394,13 +1390,13 @@ impl<'a> Parser<'a> { if self.eat(&token::Not) { // Macro invocation in type position let (_, tts) = self.expect_delimited_token_tree()?; - TyKind::Mac(spanned(lo, self.span.hi, Mac_ { path: path, tts: tts })) + TyKind::Mac(respan(lo.to(self.span), Mac_ { path: path, tts: tts })) } else { // Just a type path or bound list (trait object type) starting with a trait. // `Type` // `Trait1 + Trait2 + 'a` if allow_plus && self.eat(&token::BinOp(token::Plus)) { - let poly_trait = PolyTraitRef::new(Vec::new(), path, lo, self.prev_span.hi); + let poly_trait = PolyTraitRef::new(Vec::new(), path, lo.to(self.prev_span)); let mut bounds = vec![TraitTyParamBound(poly_trait, TraitBoundModifier::None)]; bounds.append(&mut self.parse_ty_param_bounds()?); TyKind::TraitObject(bounds) @@ -1415,13 +1411,13 @@ impl<'a> Parser<'a> { // Function pointer type or bound list (trait object type) starting with a poly-trait. // `for<'lt> [unsafe] [extern "ABI"] fn (&'lt S) -> T` // `for<'lt> Trait1<'lt> + Trait2 + 'a` - let lo = self.span.lo; + let lo = self.span; let lifetime_defs = self.parse_late_bound_lifetime_defs()?; if self.token_is_bare_fn_keyword() { self.parse_ty_bare_fn(lifetime_defs)? } else { let path = self.parse_path(PathStyle::Type)?; - let poly_trait = PolyTraitRef::new(lifetime_defs, path, lo, self.prev_span.hi); + let poly_trait = PolyTraitRef::new(lifetime_defs, path, lo.to(self.prev_span)); let mut bounds = vec![TraitTyParamBound(poly_trait, TraitBoundModifier::None)]; if allow_plus && self.eat(&token::BinOp(token::Plus)) { bounds.append(&mut self.parse_ty_param_bounds()?) @@ -1440,7 +1436,7 @@ impl<'a> Parser<'a> { return Err(self.fatal(&msg)); }; - let span = mk_sp(lo, self.prev_span.hi); + let span = lo.to(self.prev_span); let ty = Ty { node: node, span: span, id: ast::DUMMY_NODE_ID }; // Try to recover from use of `+` with incorrect priority. @@ -1457,7 +1453,7 @@ impl<'a> Parser<'a> { self.bump(); // `+` let bounds = self.parse_ty_param_bounds()?; - let sum_span = mk_sp(ty.span.lo, self.prev_span.hi); + let sum_span = ty.span.to(self.prev_span); let mut err = struct_span_err!(self.sess.span_diagnostic, ty.span, E0178, "expected a path on the left-hand side of `+`, not `{}`", pprust::ty_to_string(&ty)); @@ -1577,7 +1573,7 @@ impl<'a> Parser<'a> { P(Ty { id: ast::DUMMY_NODE_ID, node: TyKind::Infer, - span: mk_sp(self.span.lo, self.span.hi), + span: self.span, }) }; Ok(Arg { @@ -1625,7 +1621,7 @@ impl<'a> Parser<'a> { /// Matches lit = true | false | token_lit pub fn parse_lit(&mut self) -> PResult<'a, Lit> { - let lo = self.span.lo; + let lo = self.span; let lit = if self.eat_keyword(keywords::True) { LitKind::Bool(true) } else if self.eat_keyword(keywords::False) { @@ -1634,22 +1630,22 @@ impl<'a> Parser<'a> { let lit = self.parse_lit_token()?; lit }; - Ok(codemap::Spanned { node: lit, span: mk_sp(lo, self.prev_span.hi) }) + Ok(codemap::Spanned { node: lit, span: lo.to(self.prev_span) }) } /// matches '-' lit | lit pub fn parse_pat_literal_maybe_minus(&mut self) -> PResult<'a, P> { - let minus_lo = self.span.lo; + let minus_lo = self.span; let minus_present = self.eat(&token::BinOp(token::Minus)); - let lo = self.span.lo; + let lo = self.span; let literal = P(self.parse_lit()?); - let hi = self.prev_span.hi; - let expr = self.mk_expr(lo, hi, ExprKind::Lit(literal), ThinVec::new()); + let hi = self.prev_span; + let expr = self.mk_expr(lo.to(hi), ExprKind::Lit(literal), ThinVec::new()); if minus_present { - let minus_hi = self.prev_span.hi; + let minus_hi = self.prev_span; let unary = self.mk_unary(UnOp::Neg, expr); - Ok(self.mk_expr(minus_lo, minus_hi, unary, ThinVec::new())) + Ok(self.mk_expr(minus_lo.to(minus_hi), unary, ThinVec::new())) } else { Ok(expr) } @@ -1726,7 +1722,7 @@ impl<'a> Parser<'a> { pub fn parse_path(&mut self, mode: PathStyle) -> PResult<'a, ast::Path> { maybe_whole!(self, NtPath, |x| x); - let lo = self.span.lo; + let lo = self.span; let is_global = self.eat(&token::ModSep); // Parse any number of segments and bound sets. A segment is an @@ -1750,7 +1746,7 @@ impl<'a> Parser<'a> { // Assemble the span. // FIXME(#39450) This is bogus if part of the path is macro generated. - let span = mk_sp(lo, self.prev_span.hi); + let span = lo.to(self.prev_span); // Assemble the result. Ok(ast::Path { @@ -1791,7 +1787,7 @@ impl<'a> Parser<'a> { bindings: bindings, }.into() } else if self.eat(&token::OpenDelim(token::Paren)) { - let lo = self.prev_span.lo; + let lo = self.prev_span; let inputs = self.parse_seq_to_end( &token::CloseDelim(token::Paren), @@ -1804,10 +1800,10 @@ impl<'a> Parser<'a> { None }; - let hi = self.prev_span.hi; + let hi = self.prev_span; Some(P(ast::PathParameters::Parenthesized(ast::ParenthesizedParameterData { - span: mk_sp(lo, hi), + span: lo.to(hi), inputs: inputs, output: output_ty, }))) @@ -1928,38 +1924,37 @@ impl<'a> Parser<'a> { /// Parse ident (COLON expr)? pub fn parse_field(&mut self) -> PResult<'a, Field> { let attrs = self.parse_outer_attributes()?; - let lo = self.span.lo; + let lo = self.span; let hi; // Check if a colon exists one ahead. This means we're parsing a fieldname. let (fieldname, expr, is_shorthand) = if self.look_ahead(1, |t| t == &token::Colon) { let fieldname = self.parse_field_name()?; self.bump(); - hi = self.prev_span.hi; + hi = self.prev_span; (fieldname, self.parse_expr()?, false) } else { let fieldname = self.parse_ident()?; - hi = self.prev_span.hi; + hi = self.prev_span; // Mimic `x: x` for the `x` field shorthand. - let path = ast::Path::from_ident(mk_sp(lo, hi), fieldname); - (fieldname, self.mk_expr(lo, hi, ExprKind::Path(None, path), ThinVec::new()), true) + let path = ast::Path::from_ident(lo.to(hi), fieldname); + (fieldname, self.mk_expr(lo.to(hi), ExprKind::Path(None, path), ThinVec::new()), true) }; Ok(ast::Field { - ident: spanned(lo, hi, fieldname), - span: mk_sp(lo, expr.span.hi), + ident: respan(lo.to(hi), fieldname), + span: lo.to(expr.span), expr: expr, is_shorthand: is_shorthand, attrs: attrs.into(), }) } - pub fn mk_expr(&mut self, lo: BytePos, hi: BytePos, node: ExprKind, attrs: ThinVec) - -> P { + pub fn mk_expr(&mut self, span: Span, node: ExprKind, attrs: ThinVec) -> P { P(Expr { id: ast::DUMMY_NODE_ID, node: node, - span: mk_sp(lo, hi), + span: span, attrs: attrs.into(), }) } @@ -2013,12 +2008,11 @@ impl<'a> Parser<'a> { ExprKind::AssignOp(binop, lhs, rhs) } - pub fn mk_mac_expr(&mut self, lo: BytePos, hi: BytePos, - m: Mac_, attrs: ThinVec) -> P { + pub fn mk_mac_expr(&mut self, span: Span, m: Mac_, attrs: ThinVec) -> P { P(Expr { id: ast::DUMMY_NODE_ID, - node: ExprKind::Mac(codemap::Spanned {node: m, span: mk_sp(lo, hi)}), - span: mk_sp(lo, hi), + node: ExprKind::Mac(codemap::Spanned {node: m, span: span}), + span: span, attrs: attrs, }) } @@ -2065,8 +2059,8 @@ impl<'a> Parser<'a> { // attributes by giving them a empty "already parsed" list. let mut attrs = ThinVec::new(); - let lo = self.span.lo; - let mut hi = self.span.hi; + let lo = self.span; + let mut hi = self.span; let ex: ExprKind; @@ -2095,18 +2089,19 @@ impl<'a> Parser<'a> { } self.bump(); - hi = self.prev_span.hi; + hi = self.prev_span; + let span = lo.to(hi); return if es.len() == 1 && !trailing_comma { - Ok(self.mk_expr(lo, hi, ExprKind::Paren(es.into_iter().nth(0).unwrap()), attrs)) + Ok(self.mk_expr(span, ExprKind::Paren(es.into_iter().nth(0).unwrap()), attrs)) } else { - Ok(self.mk_expr(lo, hi, ExprKind::Tup(es), attrs)) + Ok(self.mk_expr(span, ExprKind::Tup(es), attrs)) } }, token::OpenDelim(token::Brace) => { return self.parse_block_expr(lo, BlockCheckMode::Default, attrs); }, token::BinOp(token::Or) | token::OrOr => { - let lo = self.span.lo; + let lo = self.span; return self.parse_lambda_expr(lo, CaptureBy::Ref, attrs); }, token::OpenDelim(token::Bracket) => { @@ -2144,34 +2139,34 @@ impl<'a> Parser<'a> { ex = ExprKind::Array(vec![first_expr]); } } - hi = self.prev_span.hi; + hi = self.prev_span; } _ => { if self.eat_lt() { let (qself, path) = self.parse_qualified_path(PathStyle::Expr)?; - hi = path.span.hi; - return Ok(self.mk_expr(lo, hi, ExprKind::Path(Some(qself), path), attrs)); + hi = path.span; + return Ok(self.mk_expr(lo.to(hi), ExprKind::Path(Some(qself), path), attrs)); } if self.eat_keyword(keywords::Move) { - let lo = self.prev_span.lo; + let lo = self.prev_span; return self.parse_lambda_expr(lo, CaptureBy::Value, attrs); } if self.eat_keyword(keywords::If) { return self.parse_if_expr(attrs); } if self.eat_keyword(keywords::For) { - let lo = self.prev_span.lo; + let lo = self.prev_span; return self.parse_for_expr(None, lo, attrs); } if self.eat_keyword(keywords::While) { - let lo = self.prev_span.lo; + let lo = self.prev_span; return self.parse_while_expr(None, lo, attrs); } if self.token.is_lifetime() { let label = Spanned { node: self.get_label(), span: self.span }; - let lo = self.span.lo; + let lo = self.span; self.bump(); self.expect(&token::Colon)?; if self.eat_keyword(keywords::While) { @@ -2186,7 +2181,7 @@ impl<'a> Parser<'a> { return Err(self.fatal("expected `while`, `for`, or `loop` after a label")) } if self.eat_keyword(keywords::Loop) { - let lo = self.prev_span.lo; + let lo = self.prev_span; return self.parse_loop_expr(None, lo, attrs); } if self.eat_keyword(keywords::Continue) { @@ -2200,8 +2195,8 @@ impl<'a> Parser<'a> { } else { ExprKind::Continue(None) }; - let hi = self.prev_span.hi; - return Ok(self.mk_expr(lo, hi, ex, attrs)); + let hi = self.prev_span; + return Ok(self.mk_expr(lo.to(hi), ex, attrs)); } if self.eat_keyword(keywords::Match) { return self.parse_match_expr(attrs); @@ -2215,13 +2210,13 @@ impl<'a> Parser<'a> { if self.is_catch_expr() { assert!(self.eat_keyword(keywords::Do)); assert!(self.eat_keyword(keywords::Catch)); - let lo = self.prev_span.lo; + let lo = self.prev_span; return self.parse_catch_expr(lo, attrs); } if self.eat_keyword(keywords::Return) { if self.token.can_begin_expr() { let e = self.parse_expr()?; - hi = e.span.hi; + hi = e.span; ex = ExprKind::Ret(Some(e)); } else { ex = ExprKind::Ret(None); @@ -2246,7 +2241,7 @@ impl<'a> Parser<'a> { None }; ex = ExprKind::Break(lt, e); - hi = self.prev_span.hi; + hi = self.prev_span; } else if self.token.is_keyword(keywords::Let) { // Catch this syntax error here, instead of in `check_strict_keywords`, so // that we can explicitly mention that let is not to be used as an expression @@ -2260,8 +2255,8 @@ impl<'a> Parser<'a> { if self.eat(&token::Not) { // MACRO INVOCATION expression let (_, tts) = self.expect_delimited_token_tree()?; - let hi = self.prev_span.hi; - return Ok(self.mk_mac_expr(lo, hi, Mac_ { path: pth, tts: tts }, attrs)); + let hi = self.prev_span; + return Ok(self.mk_mac_expr(lo.to(hi), Mac_ { path: pth, tts: tts }, attrs)); } if self.check(&token::OpenDelim(token::Brace)) { // This is a struct literal, unless we're prohibited @@ -2274,12 +2269,12 @@ impl<'a> Parser<'a> { } } - hi = pth.span.hi; + hi = pth.span; ex = ExprKind::Path(None, pth); } else { match self.parse_lit() { Ok(lit) => { - hi = lit.span.hi; + hi = lit.span; ex = ExprKind::Lit(P(lit)); } Err(mut err) => { @@ -2293,10 +2288,10 @@ impl<'a> Parser<'a> { } } - return Ok(self.mk_expr(lo, hi, ex, attrs)); + return Ok(self.mk_expr(lo.to(hi), ex, attrs)); } - fn parse_struct_expr(&mut self, lo: BytePos, pth: ast::Path, mut attrs: ThinVec) + fn parse_struct_expr(&mut self, lo: Span, pth: ast::Path, mut attrs: ThinVec) -> PResult<'a, P> { self.bump(); let mut fields = Vec::new(); @@ -2338,9 +2333,9 @@ impl<'a> Parser<'a> { } } - let hi = self.span.hi; + let span = lo.to(self.span); self.expect(&token::CloseDelim(token::Brace))?; - return Ok(self.mk_expr(lo, hi, ExprKind::Struct(pth, fields, base), attrs)); + return Ok(self.mk_expr(span, ExprKind::Struct(pth, fields, base), attrs)); } fn parse_or_use_outer_attributes(&mut self, @@ -2354,7 +2349,7 @@ impl<'a> Parser<'a> { } /// Parse a block or unsafe block - pub fn parse_block_expr(&mut self, lo: BytePos, blk_mode: BlockCheckMode, + pub fn parse_block_expr(&mut self, lo: Span, blk_mode: BlockCheckMode, outer_attrs: ThinVec) -> PResult<'a, P> { @@ -2364,7 +2359,7 @@ impl<'a> Parser<'a> { attrs.extend(self.parse_inner_attributes()?); let blk = self.parse_block_tail(lo, blk_mode)?; - return Ok(self.mk_expr(blk.span.lo, blk.span.hi, ExprKind::Block(blk), attrs)); + return Ok(self.mk_expr(blk.span, ExprKind::Block(blk), attrs)); } /// parse a.b or a(13) or a[4] or just a @@ -2375,12 +2370,12 @@ impl<'a> Parser<'a> { let b = self.parse_bottom_expr(); let (span, b) = self.interpolated_or_expr_span(b)?; - self.parse_dot_or_call_expr_with(b, span.lo, attrs) + self.parse_dot_or_call_expr_with(b, span, attrs) } pub fn parse_dot_or_call_expr_with(&mut self, e0: P, - lo: BytePos, + lo: Span, mut attrs: ThinVec) -> PResult<'a, P> { // Stitch the list of outer attributes onto the return value. @@ -2411,11 +2406,7 @@ impl<'a> Parser<'a> { // Assuming we have just parsed `.foo` (i.e., a dot and an ident), continue // parsing into an expression. - fn parse_dot_suffix(&mut self, - ident: Ident, - ident_span: Span, - self_value: P, - lo: BytePos) + fn parse_dot_suffix(&mut self, ident: Ident, ident_span: Span, self_value: P, lo: Span) -> PResult<'a, P> { let (_, tys, bindings) = if self.eat(&token::ModSep) { self.expect_lt()?; @@ -2440,12 +2431,12 @@ impl<'a> Parser<'a> { SeqSep::trailing_allowed(token::Comma), |p| Ok(p.parse_expr()?) )?; - let hi = self.prev_span.hi; + let hi = self.prev_span; es.insert(0, self_value); - let id = spanned(ident_span.lo, ident_span.hi, ident); + let id = respan(ident_span.to(ident_span), ident); let nd = self.mk_method_call(id, tys, es); - self.mk_expr(lo, hi, nd, ThinVec::new()) + self.mk_expr(lo.to(hi), nd, ThinVec::new()) } // Field access. _ => { @@ -2456,32 +2447,30 @@ impl<'a> Parser<'a> { have type parameters"); } - let id = spanned(ident_span.lo, ident_span.hi, ident); + let id = respan(ident_span.to(ident_span), ident); let field = self.mk_field(self_value, id); - self.mk_expr(lo, ident_span.hi, field, ThinVec::new()) + self.mk_expr(lo.to(ident_span), field, ThinVec::new()) } }) } - fn parse_dot_or_call_expr_with_(&mut self, e0: P, lo: BytePos) -> PResult<'a, P> { + fn parse_dot_or_call_expr_with_(&mut self, e0: P, lo: Span) -> PResult<'a, P> { let mut e = e0; let mut hi; loop { // expr? while self.eat(&token::Question) { - let hi = self.prev_span.hi; - e = self.mk_expr(lo, hi, ExprKind::Try(e), ThinVec::new()); + let hi = self.prev_span; + e = self.mk_expr(lo.to(hi), ExprKind::Try(e), ThinVec::new()); } // expr.f if self.eat(&token::Dot) { match self.token { token::Ident(i) => { - let dot_pos = self.prev_span.hi; - hi = self.span.hi; + let ident_span = self.span; self.bump(); - - e = self.parse_dot_suffix(i, mk_sp(dot_pos, hi), e, lo)?; + e = self.parse_dot_suffix(i, ident_span, e, lo)?; } token::Literal(token::Integer(n), suf) => { let sp = self.span; @@ -2489,16 +2478,16 @@ impl<'a> Parser<'a> { // A tuple index may not have a suffix self.expect_no_suffix(sp, "tuple index", suf); - let dot = self.prev_span.hi; - hi = self.span.hi; + let dot_span = self.prev_span; + hi = self.span; self.bump(); let index = n.as_str().parse::().ok(); match index { Some(n) => { - let id = spanned(dot, hi, n); + let id = respan(dot_span.to(hi), n); let field = self.mk_tup_field(e, id); - e = self.mk_expr(lo, hi, field, ThinVec::new()); + e = self.mk_expr(lo.to(hi), field, ThinVec::new()); } None => { let prev_span = self.prev_span; @@ -2541,10 +2530,8 @@ impl<'a> Parser<'a> { let actual = self.this_token_to_string(); self.span_err(self.span, &format!("unexpected token: `{}`", actual)); - let dot_pos = self.prev_span.hi; - e = self.parse_dot_suffix(keywords::Invalid.ident(), - mk_sp(dot_pos, dot_pos), - e, lo)?; + let dot_span = self.prev_span; + e = self.parse_dot_suffix(keywords::Invalid.ident(), dot_span, e, lo)?; } } continue; @@ -2559,10 +2546,10 @@ impl<'a> Parser<'a> { SeqSep::trailing_allowed(token::Comma), |p| Ok(p.parse_expr()?) )?; - hi = self.prev_span.hi; + hi = self.prev_span; let nd = self.mk_call(e, es); - e = self.mk_expr(lo, hi, nd, ThinVec::new()); + e = self.mk_expr(lo.to(hi), nd, ThinVec::new()); } // expr[...] @@ -2570,10 +2557,10 @@ impl<'a> Parser<'a> { token::OpenDelim(token::Bracket) => { self.bump(); let ix = self.parse_expr()?; - hi = self.span.hi; + hi = self.span; self.expect(&token::CloseDelim(token::Bracket))?; let index = self.mk_index(e, ix); - e = self.mk_expr(lo, hi, index, ThinVec::new()) + e = self.mk_expr(lo.to(hi), index, ThinVec::new()) } _ => return Ok(e) } @@ -2635,38 +2622,33 @@ impl<'a> Parser<'a> { already_parsed_attrs: Option>) -> PResult<'a, P> { let attrs = self.parse_or_use_outer_attributes(already_parsed_attrs)?; - let lo = self.span.lo; - let hi; + let lo = self.span; // Note: when adding new unary operators, don't forget to adjust Token::can_begin_expr() - let ex = match self.token { + let (hi, ex) = match self.token { token::Not => { self.bump(); let e = self.parse_prefix_expr(None); let (span, e) = self.interpolated_or_expr_span(e)?; - hi = span.hi; - self.mk_unary(UnOp::Not, e) + (span, self.mk_unary(UnOp::Not, e)) } token::BinOp(token::Minus) => { self.bump(); let e = self.parse_prefix_expr(None); let (span, e) = self.interpolated_or_expr_span(e)?; - hi = span.hi; - self.mk_unary(UnOp::Neg, e) + (span, self.mk_unary(UnOp::Neg, e)) } token::BinOp(token::Star) => { self.bump(); let e = self.parse_prefix_expr(None); let (span, e) = self.interpolated_or_expr_span(e)?; - hi = span.hi; - self.mk_unary(UnOp::Deref, e) + (span, self.mk_unary(UnOp::Deref, e)) } token::BinOp(token::And) | token::AndAnd => { self.expect_and()?; let m = self.parse_mutability(); let e = self.parse_prefix_expr(None); let (span, e) = self.interpolated_or_expr_span(e)?; - hi = span.hi; - ExprKind::AddrOf(m, e) + (span, ExprKind::AddrOf(m, e)) } token::Ident(..) if self.token.is_keyword(keywords::In) => { self.bump(); @@ -2676,20 +2658,18 @@ impl<'a> Parser<'a> { )?; let blk = self.parse_block()?; let span = blk.span; - hi = span.hi; - let blk_expr = self.mk_expr(span.lo, hi, ExprKind::Block(blk), ThinVec::new()); - ExprKind::InPlace(place, blk_expr) + let blk_expr = self.mk_expr(span, ExprKind::Block(blk), ThinVec::new()); + (span, ExprKind::InPlace(place, blk_expr)) } token::Ident(..) if self.token.is_keyword(keywords::Box) => { self.bump(); let e = self.parse_prefix_expr(None); let (span, e) = self.interpolated_or_expr_span(e)?; - hi = span.hi; - ExprKind::Box(e) + (span, ExprKind::Box(e)) } _ => return self.parse_dot_or_call_expr(Some(attrs)) }; - return Ok(self.mk_expr(lo, hi, ex, attrs)); + return Ok(self.mk_expr(lo.to(hi), ex, attrs)); } /// Parse an associative expression @@ -2750,13 +2730,11 @@ impl<'a> Parser<'a> { // Special cases: if op == AssocOp::As { let rhs = self.parse_ty_no_plus()?; - let (lo, hi) = (lhs_span.lo, rhs.span.hi); - lhs = self.mk_expr(lo, hi, ExprKind::Cast(lhs, rhs), ThinVec::new()); + lhs = self.mk_expr(lhs_span.to(rhs.span), ExprKind::Cast(lhs, rhs), ThinVec::new()); continue } else if op == AssocOp::Colon { let rhs = self.parse_ty_no_plus()?; - let (lo, hi) = (lhs_span.lo, rhs.span.hi); - lhs = self.mk_expr(lo, hi, ExprKind::Type(lhs, rhs), ThinVec::new()); + lhs = self.mk_expr(lhs_span.to(rhs.span), ExprKind::Type(lhs, rhs), ThinVec::new()); continue } else if op == AssocOp::DotDot || op == AssocOp::DotDotDot { // If we didn’t have to handle `x..`/`x...`, it would be pretty easy to @@ -2782,7 +2760,7 @@ impl<'a> Parser<'a> { }; let r = try!(self.mk_range(Some(lhs), rhs, limits)); - lhs = self.mk_expr(lhs_span.lo, rhs_span.hi, r, ThinVec::new()); + lhs = self.mk_expr(lhs_span.to(rhs_span), r, ThinVec::new()); break } @@ -2809,7 +2787,7 @@ impl<'a> Parser<'a> { }), }?; - let (lo, hi) = (lhs_span.lo, rhs.span.hi); + let span = lhs_span.to(rhs.span); lhs = match op { AssocOp::Add | AssocOp::Subtract | AssocOp::Multiply | AssocOp::Divide | AssocOp::Modulus | AssocOp::LAnd | AssocOp::LOr | AssocOp::BitXor | @@ -2818,12 +2796,12 @@ impl<'a> Parser<'a> { AssocOp::Greater | AssocOp::GreaterEqual => { let ast_op = op.to_ast_binop().unwrap(); let binary = self.mk_binary(codemap::respan(cur_op_span, ast_op), lhs, rhs); - self.mk_expr(lo, hi, binary, ThinVec::new()) + self.mk_expr(span, binary, ThinVec::new()) } AssocOp::Assign => - self.mk_expr(lo, hi, ExprKind::Assign(lhs, rhs), ThinVec::new()), + self.mk_expr(span, ExprKind::Assign(lhs, rhs), ThinVec::new()), AssocOp::Inplace => - self.mk_expr(lo, hi, ExprKind::InPlace(lhs, rhs), ThinVec::new()), + self.mk_expr(span, ExprKind::InPlace(lhs, rhs), ThinVec::new()), AssocOp::AssignOp(k) => { let aop = match k { token::Plus => BinOpKind::Add, @@ -2838,7 +2816,7 @@ impl<'a> Parser<'a> { token::Shr => BinOpKind::Shr, }; let aopexpr = self.mk_assign_op(codemap::respan(cur_op_span, aop), lhs, rhs); - self.mk_expr(lo, hi, aopexpr, ThinVec::new()) + self.mk_expr(span, aopexpr, ThinVec::new()) } AssocOp::As | AssocOp::Colon | AssocOp::DotDot | AssocOp::DotDotDot => { self.bug("As, Colon, DotDot or DotDotDot branch reached") @@ -2858,7 +2836,7 @@ impl<'a> Parser<'a> { match lhs.node { ExprKind::Binary(op, _, _) if op.node.is_comparison() => { // respan to include both operators - let op_span = mk_sp(op.span.lo, self.span.hi); + let op_span = op.span.to(self.span); let mut err = self.diagnostic().struct_span_err(op_span, "chained comparison operators require parentheses"); if op.node == BinOpKind::Lt && @@ -2881,8 +2859,8 @@ impl<'a> Parser<'a> { debug_assert!(self.token == token::DotDot || self.token == token::DotDotDot); let tok = self.token.clone(); let attrs = self.parse_or_use_outer_attributes(already_parsed_attrs)?; - let lo = self.span.lo; - let mut hi = self.span.hi; + let lo = self.span; + let mut hi = self.span; self.bump(); let opt_end = if self.is_at_start_of_range_notation_rhs() { // RHS must be parsed with more associativity than the dots. @@ -2890,7 +2868,7 @@ impl<'a> Parser<'a> { Some(self.parse_assoc_expr_with(next_prec, LhsExpr::NotYetParsed) .map(|x|{ - hi = x.span.hi; + hi = x.span; x })?) } else { @@ -2905,7 +2883,7 @@ impl<'a> Parser<'a> { let r = try!(self.mk_range(None, opt_end, limits)); - Ok(self.mk_expr(lo, hi, r, attrs)) + Ok(self.mk_expr(lo.to(hi), r, attrs)) } fn is_at_start_of_range_notation_rhs(&self) -> bool { @@ -2925,23 +2903,23 @@ impl<'a> Parser<'a> { if self.check_keyword(keywords::Let) { return self.parse_if_let_expr(attrs); } - let lo = self.prev_span.lo; + let lo = self.prev_span; let cond = self.parse_expr_res(Restrictions::RESTRICTION_NO_STRUCT_LITERAL, None)?; let thn = self.parse_block()?; let mut els: Option> = None; - let mut hi = thn.span.hi; + let mut hi = thn.span; if self.eat_keyword(keywords::Else) { let elexpr = self.parse_else_expr()?; - hi = elexpr.span.hi; + hi = elexpr.span; els = Some(elexpr); } - Ok(self.mk_expr(lo, hi, ExprKind::If(cond, thn, els), attrs)) + Ok(self.mk_expr(lo.to(hi), ExprKind::If(cond, thn, els), attrs)) } /// Parse an 'if let' expression ('if' token already eaten) pub fn parse_if_let_expr(&mut self, attrs: ThinVec) -> PResult<'a, P> { - let lo = self.prev_span.lo; + let lo = self.prev_span; self.expect_keyword(keywords::Let)?; let pat = self.parse_pat()?; self.expect(&token::Eq)?; @@ -2949,36 +2927,35 @@ impl<'a> Parser<'a> { let thn = self.parse_block()?; let (hi, els) = if self.eat_keyword(keywords::Else) { let expr = self.parse_else_expr()?; - (expr.span.hi, Some(expr)) + (expr.span, Some(expr)) } else { - (thn.span.hi, None) + (thn.span, None) }; - Ok(self.mk_expr(lo, hi, ExprKind::IfLet(pat, expr, thn, els), attrs)) + Ok(self.mk_expr(lo.to(hi), ExprKind::IfLet(pat, expr, thn, els), attrs)) } // `move |args| expr` pub fn parse_lambda_expr(&mut self, - lo: BytePos, + lo: Span, capture_clause: CaptureBy, attrs: ThinVec) -> PResult<'a, P> { let decl = self.parse_fn_block_decl()?; - let decl_hi = self.prev_span.hi; + let decl_hi = self.prev_span; let body = match decl.output { FunctionRetTy::Default(_) => self.parse_expr()?, _ => { // If an explicit return type is given, require a // block to appear (RFC 968). - let body_lo = self.span.lo; + let body_lo = self.span; self.parse_block_expr(body_lo, BlockCheckMode::Default, ThinVec::new())? } }; Ok(self.mk_expr( - lo, - body.span.hi, - ExprKind::Closure(capture_clause, decl, body, mk_sp(lo, decl_hi)), + lo.to(body.span), + ExprKind::Closure(capture_clause, decl, body, lo.to(decl_hi)), attrs)) } @@ -2988,13 +2965,13 @@ impl<'a> Parser<'a> { return self.parse_if_expr(ThinVec::new()); } else { let blk = self.parse_block()?; - return Ok(self.mk_expr(blk.span.lo, blk.span.hi, ExprKind::Block(blk), ThinVec::new())); + return Ok(self.mk_expr(blk.span, ExprKind::Block(blk), ThinVec::new())); } } /// Parse a 'for' .. 'in' expression ('for' token already eaten) pub fn parse_for_expr(&mut self, opt_ident: Option, - span_lo: BytePos, + span_lo: Span, mut attrs: ThinVec) -> PResult<'a, P> { // Parse: `for in ` @@ -3004,16 +2981,13 @@ impl<'a> Parser<'a> { let (iattrs, loop_block) = self.parse_inner_attrs_and_block()?; attrs.extend(iattrs); - let hi = self.prev_span.hi; - - Ok(self.mk_expr(span_lo, hi, - ExprKind::ForLoop(pat, expr, loop_block, opt_ident), - attrs)) + let hi = self.prev_span; + Ok(self.mk_expr(span_lo.to(hi), ExprKind::ForLoop(pat, expr, loop_block, opt_ident), attrs)) } /// Parse a 'while' or 'while let' expression ('while' token already eaten) pub fn parse_while_expr(&mut self, opt_ident: Option, - span_lo: BytePos, + span_lo: Span, mut attrs: ThinVec) -> PResult<'a, P> { if self.token.is_keyword(keywords::Let) { return self.parse_while_let_expr(opt_ident, span_lo, attrs); @@ -3021,14 +2995,13 @@ impl<'a> Parser<'a> { let cond = self.parse_expr_res(Restrictions::RESTRICTION_NO_STRUCT_LITERAL, None)?; let (iattrs, body) = self.parse_inner_attrs_and_block()?; attrs.extend(iattrs); - let hi = body.span.hi; - return Ok(self.mk_expr(span_lo, hi, ExprKind::While(cond, body, opt_ident), - attrs)); + let span = span_lo.to(body.span); + return Ok(self.mk_expr(span, ExprKind::While(cond, body, opt_ident), attrs)); } /// Parse a 'while let' expression ('while' token already eaten) pub fn parse_while_let_expr(&mut self, opt_ident: Option, - span_lo: BytePos, + span_lo: Span, mut attrs: ThinVec) -> PResult<'a, P> { self.expect_keyword(keywords::Let)?; let pat = self.parse_pat()?; @@ -3036,34 +3009,33 @@ impl<'a> Parser<'a> { let expr = self.parse_expr_res(Restrictions::RESTRICTION_NO_STRUCT_LITERAL, None)?; let (iattrs, body) = self.parse_inner_attrs_and_block()?; attrs.extend(iattrs); - let hi = body.span.hi; - return Ok(self.mk_expr(span_lo, hi, ExprKind::WhileLet(pat, expr, body, opt_ident), attrs)); + let span = span_lo.to(body.span); + return Ok(self.mk_expr(span, ExprKind::WhileLet(pat, expr, body, opt_ident), attrs)); } // parse `loop {...}`, `loop` token already eaten pub fn parse_loop_expr(&mut self, opt_ident: Option, - span_lo: BytePos, + span_lo: Span, mut attrs: ThinVec) -> PResult<'a, P> { let (iattrs, body) = self.parse_inner_attrs_and_block()?; attrs.extend(iattrs); - let hi = body.span.hi; - Ok(self.mk_expr(span_lo, hi, ExprKind::Loop(body, opt_ident), attrs)) + let span = span_lo.to(body.span); + Ok(self.mk_expr(span, ExprKind::Loop(body, opt_ident), attrs)) } /// Parse a `do catch {...}` expression (`do catch` token already eaten) - pub fn parse_catch_expr(&mut self, span_lo: BytePos, mut attrs: ThinVec) + pub fn parse_catch_expr(&mut self, span_lo: Span, mut attrs: ThinVec) -> PResult<'a, P> { let (iattrs, body) = self.parse_inner_attrs_and_block()?; attrs.extend(iattrs); - let hi = body.span.hi; - Ok(self.mk_expr(span_lo, hi, ExprKind::Catch(body), attrs)) + Ok(self.mk_expr(span_lo.to(body.span), ExprKind::Catch(body), attrs)) } // `match` token already eaten fn parse_match_expr(&mut self, mut attrs: ThinVec) -> PResult<'a, P> { let match_span = self.prev_span; - let lo = self.prev_span.lo; + let lo = self.prev_span; let discriminant = self.parse_expr_res(Restrictions::RESTRICTION_NO_STRUCT_LITERAL, None)?; if let Err(mut e) = self.expect(&token::OpenDelim(token::Brace)) { @@ -3082,17 +3054,17 @@ impl<'a> Parser<'a> { // Recover by skipping to the end of the block. e.emit(); self.recover_stmt(); - let hi = self.span.hi; + let span = lo.to(self.span); if self.token == token::CloseDelim(token::Brace) { self.bump(); } - return Ok(self.mk_expr(lo, hi, ExprKind::Match(discriminant, arms), attrs)); + return Ok(self.mk_expr(span, ExprKind::Match(discriminant, arms), attrs)); } } } - let hi = self.span.hi; + let hi = self.span; self.bump(); - return Ok(self.mk_expr(lo, hi, ExprKind::Match(discriminant, arms), attrs)); + return Ok(self.mk_expr(lo.to(hi), ExprKind::Match(discriminant, arms), attrs)); } pub fn parse_arm(&mut self) -> PResult<'a, Arm> { @@ -3266,7 +3238,7 @@ impl<'a> Parser<'a> { } let attrs = self.parse_outer_attributes()?; - let lo = self.span.lo; + let lo = self.span; let hi; if self.check(&token::DotDot) { @@ -3286,16 +3258,16 @@ impl<'a> Parser<'a> { let fieldname = self.parse_field_name()?; self.bump(); let pat = self.parse_pat()?; - hi = pat.span.hi; + hi = pat.span; (pat, fieldname, false) } else { // Parsing a pattern of the form "(box) (ref) (mut) fieldname" let is_box = self.eat_keyword(keywords::Box); - let boxed_span_lo = self.span.lo; + let boxed_span = self.span; let is_ref = self.eat_keyword(keywords::Ref); let is_mut = self.eat_keyword(keywords::Mut); let fieldname = self.parse_ident()?; - hi = self.prev_span.hi; + hi = self.prev_span; let bind_type = match (is_ref, is_mut) { (true, true) => BindingMode::ByRef(Mutability::Mutable), @@ -3307,14 +3279,14 @@ impl<'a> Parser<'a> { let fieldpat = P(ast::Pat{ id: ast::DUMMY_NODE_ID, node: PatKind::Ident(bind_type, fieldpath, None), - span: mk_sp(boxed_span_lo, hi), + span: boxed_span.to(hi), }); let subpat = if is_box { P(ast::Pat{ id: ast::DUMMY_NODE_ID, node: PatKind::Box(fieldpat), - span: mk_sp(lo, hi), + span: lo.to(hi), }) } else { fieldpat @@ -3322,7 +3294,7 @@ impl<'a> Parser<'a> { (subpat, fieldname, true) }; - fields.push(codemap::Spanned { span: mk_sp(lo, hi), + fields.push(codemap::Spanned { span: lo.to(hi), node: ast::FieldPat { ident: fieldname, pat: subpat, @@ -3336,7 +3308,7 @@ impl<'a> Parser<'a> { fn parse_pat_range_end(&mut self) -> PResult<'a, P> { if self.token.is_path_start() { - let lo = self.span.lo; + let lo = self.span; let (qself, path) = if self.eat_lt() { // Parse a qualified path let (qself, path) = @@ -3346,8 +3318,8 @@ impl<'a> Parser<'a> { // Parse an unqualified path (None, self.parse_path(PathStyle::Expr)?) }; - let hi = self.prev_span.hi; - Ok(self.mk_expr(lo, hi, ExprKind::Path(qself, path), ThinVec::new())) + let hi = self.prev_span; + Ok(self.mk_expr(lo.to(hi), ExprKind::Path(qself, path), ThinVec::new())) } else { self.parse_pat_literal_maybe_minus() } @@ -3373,7 +3345,7 @@ impl<'a> Parser<'a> { pub fn parse_pat(&mut self) -> PResult<'a, P> { maybe_whole!(self, NtPat, |x| x); - let lo = self.span.lo; + let lo = self.span; let pat; match self.token { token::Underscore => { @@ -3439,7 +3411,7 @@ impl<'a> Parser<'a> { // Parse macro invocation self.bump(); let (_, tts) = self.expect_delimited_token_tree()?; - let mac = spanned(lo, self.prev_span.hi, Mac_ { path: path, tts: tts }); + let mac = respan(lo.to(self.prev_span), Mac_ { path: path, tts: tts }); pat = PatKind::Mac(mac); } token::DotDotDot | token::DotDot => { @@ -3449,9 +3421,8 @@ impl<'a> Parser<'a> { _ => panic!("can only parse `..` or `...` for ranges (checked above)"), }; // Parse range - let hi = self.prev_span.hi; - let begin = - self.mk_expr(lo, hi, ExprKind::Path(qself, path), ThinVec::new()); + let span = lo.to(self.prev_span); + let begin = self.mk_expr(span, ExprKind::Path(qself, path), ThinVec::new()); self.bump(); let end = self.parse_pat_range_end()?; pat = PatKind::Range(begin, end, end_kind); @@ -3505,11 +3476,10 @@ impl<'a> Parser<'a> { } } - let hi = self.prev_span.hi; Ok(P(ast::Pat { id: ast::DUMMY_NODE_ID, node: pat, - span: mk_sp(lo, hi), + span: lo.to(self.prev_span), })) } @@ -3545,7 +3515,7 @@ impl<'a> Parser<'a> { /// Parse a local variable declaration fn parse_local(&mut self, attrs: ThinVec) -> PResult<'a, P> { - let lo = self.span.lo; + let lo = self.span; let pat = self.parse_pat()?; let mut ty = None; @@ -3558,14 +3528,14 @@ impl<'a> Parser<'a> { pat: pat, init: init, id: ast::DUMMY_NODE_ID, - span: mk_sp(lo, self.prev_span.hi), + span: lo.to(self.prev_span), attrs: attrs, })) } /// Parse a structure field fn parse_name_and_ty(&mut self, - lo: BytePos, + lo: Span, vis: Visibility, attrs: Vec) -> PResult<'a, StructField> { @@ -3573,7 +3543,7 @@ impl<'a> Parser<'a> { self.expect(&token::Colon)?; let ty = self.parse_ty()?; Ok(StructField { - span: mk_sp(lo, self.prev_span.hi), + span: lo.to(self.prev_span), ident: Some(name), vis: vis, id: ast::DUMMY_NODE_ID, @@ -3683,7 +3653,7 @@ impl<'a> Parser<'a> { fn eat_macro_def(&mut self, attrs: &[Attribute], vis: &Visibility) -> PResult<'a, Option>> { - let lo = self.span.lo; + let lo = self.span; match self.token { token::Ident(ident) if ident.name == "macro_rules" => { if self.look_ahead(1, |t| *t == token::Not) { @@ -3706,9 +3676,9 @@ impl<'a> Parser<'a> { } } - let hi = self.prev_span.hi; + let span = lo.to(self.prev_span); let kind = ItemKind::MacroDef(tts); - Ok(Some(self.mk_item(lo, hi, id, kind, Visibility::Inherited, attrs.to_owned()))) + Ok(Some(self.mk_item(span, id, kind, Visibility::Inherited, attrs.to_owned()))) } fn parse_stmt_without_recovery(&mut self, @@ -3717,19 +3687,19 @@ impl<'a> Parser<'a> { maybe_whole!(self, NtStmt, |x| Some(x)); let attrs = self.parse_outer_attributes()?; - let lo = self.span.lo; + let lo = self.span; Ok(Some(if self.eat_keyword(keywords::Let) { Stmt { id: ast::DUMMY_NODE_ID, node: StmtKind::Local(self.parse_local(attrs.into())?), - span: mk_sp(lo, self.prev_span.hi), + span: lo.to(self.prev_span), } } else if let Some(macro_def) = self.eat_macro_def(&attrs, &Visibility::Inherited)? { Stmt { id: ast::DUMMY_NODE_ID, node: StmtKind::Item(macro_def), - span: mk_sp(lo, self.prev_span.hi), + span: lo.to(self.prev_span), } // Starts like a simple path, but not a union item. } else if self.token.is_path_start() && @@ -3741,8 +3711,8 @@ impl<'a> Parser<'a> { let expr = if self.check(&token::OpenDelim(token::Brace)) { self.parse_struct_expr(lo, pth, ThinVec::new())? } else { - let hi = self.prev_span.hi; - self.mk_expr(lo, hi, ExprKind::Path(None, pth), ThinVec::new()) + let hi = self.prev_span; + self.mk_expr(lo.to(hi), ExprKind::Path(None, pth), ThinVec::new()) }; let expr = self.with_res(Restrictions::RESTRICTION_STMT_EXPR, |this| { @@ -3753,7 +3723,7 @@ impl<'a> Parser<'a> { return Ok(Some(Stmt { id: ast::DUMMY_NODE_ID, node: StmtKind::Expr(expr), - span: mk_sp(lo, self.prev_span.hi), + span: lo.to(self.prev_span), })); } @@ -3784,7 +3754,7 @@ impl<'a> Parser<'a> { }; let (_, tts) = self.expect_delimited_token_tree()?; - let hi = self.prev_span.hi; + let hi = self.prev_span; let style = if delim == token::Brace { MacStmtStyle::Braces @@ -3793,7 +3763,7 @@ impl<'a> Parser<'a> { }; if id.name == keywords::Invalid.name() { - let mac = spanned(lo, hi, Mac_ { path: pth, tts: tts }); + let mac = respan(lo.to(hi), Mac_ { path: pth, tts: tts }); let node = if delim == token::Brace || self.token == token::Semi || self.token == token::Eof { StmtKind::Mac(P((mac, style, attrs.into()))) @@ -3813,14 +3783,14 @@ impl<'a> Parser<'a> { self.warn_missing_semicolon(); StmtKind::Mac(P((mac, style, attrs.into()))) } else { - let e = self.mk_mac_expr(lo, hi, mac.node, ThinVec::new()); + let e = self.mk_mac_expr(lo.to(hi), mac.node, ThinVec::new()); let e = self.parse_dot_or_call_expr_with(e, lo, attrs.into())?; let e = self.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(e))?; StmtKind::Expr(e) }; Stmt { id: ast::DUMMY_NODE_ID, - span: mk_sp(lo, hi), + span: lo.to(hi), node: node, } } else { @@ -3835,13 +3805,14 @@ impl<'a> Parser<'a> { followed by a semicolon"); } } + let span = lo.to(hi); Stmt { id: ast::DUMMY_NODE_ID, - span: mk_sp(lo, hi), + span: span, node: StmtKind::Item({ self.mk_item( - lo, hi, id /*id is good here*/, - ItemKind::Mac(spanned(lo, hi, Mac_ { path: pth, tts: tts })), + span, id /*id is good here*/, + ItemKind::Mac(respan(span, Mac_ { path: pth, tts: tts })), Visibility::Inherited, attrs) }), @@ -3856,7 +3827,7 @@ impl<'a> Parser<'a> { match item { Some(i) => Stmt { id: ast::DUMMY_NODE_ID, - span: mk_sp(lo, i.span.hi), + span: lo.to(i.span), node: StmtKind::Item(i), }, None => { @@ -3887,7 +3858,7 @@ impl<'a> Parser<'a> { Restrictions::RESTRICTION_STMT_EXPR, Some(attrs.into()))?; Stmt { id: ast::DUMMY_NODE_ID, - span: mk_sp(lo, e.span.hi), + span: lo.to(e.span), node: StmtKind::Expr(e), } } @@ -3905,7 +3876,7 @@ impl<'a> Parser<'a> { pub fn parse_block(&mut self) -> PResult<'a, P> { maybe_whole!(self, NtBlock, |x| x); - let lo = self.span.lo; + let lo = self.span; if !self.eat(&token::OpenDelim(token::Brace)) { let sp = self.span; @@ -3950,7 +3921,7 @@ impl<'a> Parser<'a> { fn parse_inner_attrs_and_block(&mut self) -> PResult<'a, (Vec, P)> { maybe_whole!(self, NtBlock, |x| (Vec::new(), x)); - let lo = self.span.lo; + let lo = self.span; self.expect(&token::OpenDelim(token::Brace))?; Ok((self.parse_inner_attributes()?, self.parse_block_tail(lo, BlockCheckMode::Default)?)) @@ -3958,7 +3929,7 @@ impl<'a> Parser<'a> { /// Parse the rest of a block expression or function body /// Precondition: already parsed the '{'. - fn parse_block_tail(&mut self, lo: BytePos, s: BlockCheckMode) -> PResult<'a, P> { + fn parse_block_tail(&mut self, lo: Span, s: BlockCheckMode) -> PResult<'a, P> { let mut stmts = vec![]; while !self.eat(&token::CloseDelim(token::Brace)) { @@ -3976,7 +3947,7 @@ impl<'a> Parser<'a> { stmts: stmts, id: ast::DUMMY_NODE_ID, rules: s, - span: mk_sp(lo, self.prev_span.hi), + span: lo.to(self.prev_span), })) } @@ -4042,10 +4013,10 @@ impl<'a> Parser<'a> { } bounds.push(RegionTyParamBound(self.expect_lifetime())); } else if self.check_keyword(keywords::For) || self.check_path() { - let lo = self.span.lo; + let lo = self.span; let lifetime_defs = self.parse_late_bound_lifetime_defs()?; let path = self.parse_path(PathStyle::Type)?; - let poly_trait = PolyTraitRef::new(lifetime_defs, path, lo, self.prev_span.hi); + let poly_trait = PolyTraitRef::new(lifetime_defs, path, lo.to(self.prev_span)); let modifier = if question.is_some() { TraitBoundModifier::Maybe } else { @@ -4166,7 +4137,7 @@ impl<'a> Parser<'a> { pub fn parse_generics(&mut self) -> PResult<'a, ast::Generics> { maybe_whole!(self, NtGenerics, |x| x); - let span_lo = self.span.lo; + let span_lo = self.span; if self.eat_lt() { let (lifetime_defs, ty_params) = self.parse_generic_params()?; self.expect_gt()?; @@ -4177,7 +4148,7 @@ impl<'a> Parser<'a> { id: ast::DUMMY_NODE_ID, predicates: Vec::new(), }, - span: mk_sp(span_lo, self.prev_span.hi), + span: span_lo.to(self.prev_span), }) } else { Ok(ast::Generics::default()) @@ -4202,7 +4173,7 @@ impl<'a> Parser<'a> { } } else if self.check_ident() && self.look_ahead(1, |t| t == &token::Eq) { // Parse associated type binding. - let lo = self.span.lo; + let lo = self.span; let ident = self.parse_ident()?; self.bump(); let ty = self.parse_ty()?; @@ -4210,7 +4181,7 @@ impl<'a> Parser<'a> { id: ast::DUMMY_NODE_ID, ident: ident, ty: ty, - span: mk_sp(lo, self.prev_span.hi), + span: lo.to(self.prev_span), }); seen_binding = true; } else if self.check_type() { @@ -4267,7 +4238,7 @@ impl<'a> Parser<'a> { } loop { - let lo = self.span.lo; + let lo = self.span; if self.check_lifetime() && self.look_ahead(1, |t| t != &token::BinOp(token::Plus)) { let lifetime = self.expect_lifetime(); // Bounds starting with a colon are mandatory, but possibly empty. @@ -4275,7 +4246,7 @@ impl<'a> Parser<'a> { let bounds = self.parse_lt_param_bounds(); where_clause.predicates.push(ast::WherePredicate::RegionPredicate( ast::WhereRegionPredicate { - span: mk_sp(lo, self.prev_span.hi), + span: lo.to(self.prev_span), lifetime: lifetime, bounds: bounds, } @@ -4296,7 +4267,7 @@ impl<'a> Parser<'a> { let bounds = self.parse_ty_param_bounds()?; where_clause.predicates.push(ast::WherePredicate::BoundPredicate( ast::WhereBoundPredicate { - span: mk_sp(lo, self.prev_span.hi), + span: lo.to(self.prev_span), bound_lifetimes: lifetime_defs, bounded_ty: ty, bounds: bounds, @@ -4307,7 +4278,7 @@ impl<'a> Parser<'a> { let rhs_ty = self.parse_ty()?; where_clause.predicates.push(ast::WherePredicate::EqPredicate( ast::WhereEqPredicate { - span: mk_sp(lo, self.prev_span.hi), + span: lo.to(self.prev_span), lhs_ty: ty, rhs_ty: rhs_ty, id: ast::DUMMY_NODE_ID, @@ -4404,7 +4375,7 @@ impl<'a> Parser<'a> { // Parse optional self parameter of a method. // Only a limited set of initial token sequences is considered self parameters, anything // else is parsed as a normal function parameter list, so some lookahead is required. - let eself_lo = self.span.lo; + let eself_lo = self.span; let (eself, eself_ident) = match self.token { token::BinOp(token::And) => { // &self @@ -4486,7 +4457,7 @@ impl<'a> Parser<'a> { _ => return Ok(None), }; - let eself = codemap::respan(mk_sp(eself_lo, self.prev_span.hi), eself); + let eself = codemap::respan(eself_lo.to(self.prev_span), eself); Ok(Some(Arg::from_self(eself, eself_ident))) } @@ -4558,8 +4529,7 @@ impl<'a> Parser<'a> { Ok((id, generics)) } - fn mk_item(&mut self, lo: BytePos, hi: BytePos, ident: Ident, - node: ItemKind, vis: Visibility, + fn mk_item(&mut self, span: Span, ident: Ident, node: ItemKind, vis: Visibility, attrs: Vec) -> P { P(Item { ident: ident, @@ -4567,7 +4537,7 @@ impl<'a> Parser<'a> { id: ast::DUMMY_NODE_ID, node: node, vis: vis, - span: mk_sp(lo, hi) + span: span, }) } @@ -4625,7 +4595,7 @@ impl<'a> Parser<'a> { maybe_whole!(self, NtImplItem, |x| x); let mut attrs = self.parse_outer_attributes()?; - let lo = self.span.lo; + let lo = self.span; let vis = self.parse_visibility(false)?; let defaultness = self.parse_defaultness()?; let (name, node) = if self.eat_keyword(keywords::Type) { @@ -4651,7 +4621,7 @@ impl<'a> Parser<'a> { Ok(ImplItem { id: ast::DUMMY_NODE_ID, - span: mk_sp(lo, self.prev_span.hi), + span: lo.to(self.prev_span), ident: name, vis: vis, defaultness: defaultness, @@ -4694,7 +4664,7 @@ impl<'a> Parser<'a> { let prev_span = self.prev_span; self.complain_if_pub_macro(&vis, prev_span); - let lo = self.span.lo; + let lo = self.span; let pth = self.parse_path(PathStyle::Mod)?; self.expect(&token::Not)?; @@ -4704,7 +4674,7 @@ impl<'a> Parser<'a> { self.expect(&token::Semi)? } - let mac = spanned(lo, self.prev_span.hi, Mac_ { path: pth, tts: tts }); + let mac = respan(lo.to(self.prev_span), Mac_ { path: pth, tts: tts }); Ok((keywords::Invalid.ident(), vec![], ast::ImplItemKind::Macro(mac))) } else { let (constness, unsafety, abi) = self.parse_fn_front_matter()?; @@ -4938,11 +4908,11 @@ impl<'a> Parser<'a> { SeqSep::trailing_allowed(token::Comma), |p| { let attrs = p.parse_outer_attributes()?; - let lo = p.span.lo; + let lo = p.span; let vis = p.parse_visibility(true)?; let ty = p.parse_ty()?; Ok(StructField { - span: mk_sp(lo, p.span.hi), + span: lo.to(p.span), vis: vis, ident: None, id: ast::DUMMY_NODE_ID, @@ -4956,7 +4926,7 @@ impl<'a> Parser<'a> { /// Parse a structure field declaration pub fn parse_single_struct_field(&mut self, - lo: BytePos, + lo: Span, vis: Visibility, attrs: Vec ) -> PResult<'a, StructField> { @@ -4978,7 +4948,7 @@ impl<'a> Parser<'a> { /// Parse an element of a struct definition fn parse_struct_decl_field(&mut self) -> PResult<'a, StructField> { let attrs = self.parse_outer_attributes()?; - let lo = self.span.lo; + let lo = self.span; let vis = self.parse_visibility(false)?; self.parse_single_struct_field(lo, vis, attrs) } @@ -5056,7 +5026,7 @@ impl<'a> Parser<'a> { } /// Given a termination token, parse all of the items in a module - fn parse_mod_items(&mut self, term: &token::Token, inner_lo: BytePos) -> PResult<'a, Mod> { + fn parse_mod_items(&mut self, term: &token::Token, inner_lo: Span) -> PResult<'a, Mod> { let mut items = vec![]; while let Some(item) = self.parse_item()? { items.push(item); @@ -5070,11 +5040,11 @@ impl<'a> Parser<'a> { let hi = if self.span == syntax_pos::DUMMY_SP { inner_lo } else { - self.prev_span.hi + self.prev_span }; Ok(ast::Mod { - inner: mk_sp(inner_lo, hi), + inner: inner_lo.to(hi), items: items }) } @@ -5137,7 +5107,7 @@ impl<'a> Parser<'a> { let old_directory = self.directory.clone(); self.push_directory(id, &outer_attrs); self.expect(&token::OpenDelim(token::Brace))?; - let mod_inner_lo = self.span.lo; + let mod_inner_lo = self.span; let attrs = self.parse_inner_attributes()?; let module = self.parse_mod_items(&token::CloseDelim(token::Brace), mod_inner_lo)?; self.directory = old_directory; @@ -5280,7 +5250,7 @@ impl<'a> Parser<'a> { let mut p0 = new_sub_parser_from_file(self.sess, &path, directory_ownership, Some(name), id_sp); p0.cfg_mods = self.cfg_mods; - let mod_inner_lo = p0.span.lo; + let mod_inner_lo = p0.span; let mod_attrs = p0.parse_inner_attributes()?; let m0 = p0.parse_mod_items(&token::Eof, mod_inner_lo)?; self.sess.included_mod_stack.borrow_mut().pop(); @@ -5288,42 +5258,42 @@ impl<'a> Parser<'a> { } /// Parse a function declaration from a foreign module - fn parse_item_foreign_fn(&mut self, vis: ast::Visibility, lo: BytePos, - attrs: Vec) -> PResult<'a, ForeignItem> { + fn parse_item_foreign_fn(&mut self, vis: ast::Visibility, lo: Span, attrs: Vec) + -> PResult<'a, ForeignItem> { self.expect_keyword(keywords::Fn)?; let (ident, mut generics) = self.parse_fn_header()?; let decl = self.parse_fn_decl(true)?; generics.where_clause = self.parse_where_clause()?; - let hi = self.span.hi; + let hi = self.span; self.expect(&token::Semi)?; Ok(ast::ForeignItem { ident: ident, attrs: attrs, node: ForeignItemKind::Fn(decl, generics), id: ast::DUMMY_NODE_ID, - span: mk_sp(lo, hi), + span: lo.to(hi), vis: vis }) } /// Parse a static item from a foreign module - fn parse_item_foreign_static(&mut self, vis: ast::Visibility, lo: BytePos, - attrs: Vec) -> PResult<'a, ForeignItem> { + fn parse_item_foreign_static(&mut self, vis: ast::Visibility, lo: Span, attrs: Vec) + -> PResult<'a, ForeignItem> { self.expect_keyword(keywords::Static)?; let mutbl = self.eat_keyword(keywords::Mut); let ident = self.parse_ident()?; self.expect(&token::Colon)?; let ty = self.parse_ty()?; - let hi = self.span.hi; + let hi = self.span; self.expect(&token::Semi)?; Ok(ForeignItem { ident: ident, attrs: attrs, node: ForeignItemKind::Static(ty, mutbl), id: ast::DUMMY_NODE_ID, - span: mk_sp(lo, hi), + span: lo.to(hi), vis: vis }) } @@ -5335,7 +5305,7 @@ impl<'a> Parser<'a> { /// extern crate foo; /// extern crate bar as foo; fn parse_item_extern_crate(&mut self, - lo: BytePos, + lo: Span, visibility: Visibility, attrs: Vec) -> PResult<'a, P> { @@ -5349,8 +5319,7 @@ impl<'a> Parser<'a> { self.expect(&token::Semi)?; let prev_span = self.prev_span; - Ok(self.mk_item(lo, - prev_span.hi, + Ok(self.mk_item(lo.to(prev_span), ident, ItemKind::ExternCrate(maybe_path), visibility, @@ -5368,7 +5337,7 @@ impl<'a> Parser<'a> { /// extern "C" {} /// extern {} fn parse_item_foreign_mod(&mut self, - lo: BytePos, + lo: Span, opt_abi: Option, visibility: Visibility, mut attrs: Vec) @@ -5390,12 +5359,8 @@ impl<'a> Parser<'a> { abi: abi, items: foreign_items }; - Ok(self.mk_item(lo, - prev_span.hi, - keywords::Invalid.ident(), - ItemKind::ForeignMod(m), - visibility, - attrs)) + let invalid = keywords::Invalid.ident(); + Ok(self.mk_item(lo.to(prev_span), invalid, ItemKind::ForeignMod(m), visibility, attrs)) } /// Parse type Foo = Bar; @@ -5416,7 +5381,7 @@ impl<'a> Parser<'a> { let mut any_disr = None; while self.token != token::CloseDelim(token::Brace) { let variant_attrs = self.parse_outer_attributes()?; - let vlo = self.span.lo; + let vlo = self.span; let struct_def; let mut disr_expr = None; @@ -5444,7 +5409,7 @@ impl<'a> Parser<'a> { data: struct_def, disr_expr: disr_expr, }; - variants.push(spanned(vlo, self.prev_span.hi, vr)); + variants.push(respan(vlo.to(self.prev_span), vr)); if !self.eat(&token::Comma) { break; } } @@ -5514,7 +5479,7 @@ impl<'a> Parser<'a> { Some(P(item)) }); - let lo = self.span.lo; + let lo = self.span; let visibility = self.parse_visibility(false)?; @@ -5524,12 +5489,8 @@ impl<'a> Parser<'a> { self.expect(&token::Semi)?; let prev_span = self.prev_span; - let item = self.mk_item(lo, - prev_span.hi, - keywords::Invalid.ident(), - item_, - visibility, - attrs); + let invalid = keywords::Invalid.ident(); + let item = self.mk_item(lo.to(prev_span), invalid, item_, visibility, attrs); return Ok(Some(item)); } @@ -5549,8 +5510,7 @@ impl<'a> Parser<'a> { respan(fn_span, Constness::NotConst), abi)?; let prev_span = self.prev_span; - let item = self.mk_item(lo, - prev_span.hi, + let item = self.mk_item(lo.to(prev_span), ident, item_, visibility, @@ -5572,8 +5532,7 @@ impl<'a> Parser<'a> { }; let (ident, item_, extra_attrs) = self.parse_item_const(Some(m))?; let prev_span = self.prev_span; - let item = self.mk_item(lo, - prev_span.hi, + let item = self.mk_item(lo.to(prev_span), ident, item_, visibility, @@ -5597,8 +5556,7 @@ impl<'a> Parser<'a> { respan(const_span, Constness::Const), Abi::Rust)?; let prev_span = self.prev_span; - let item = self.mk_item(lo, - prev_span.hi, + let item = self.mk_item(lo.to(prev_span), ident, item_, visibility, @@ -5615,8 +5573,7 @@ impl<'a> Parser<'a> { } let (ident, item_, extra_attrs) = self.parse_item_const(None)?; let prev_span = self.prev_span; - let item = self.mk_item(lo, - prev_span.hi, + let item = self.mk_item(lo.to(prev_span), ident, item_, visibility, @@ -5632,8 +5589,7 @@ impl<'a> Parser<'a> { let (ident, item_, extra_attrs) = self.parse_item_trait(ast::Unsafety::Unsafe)?; let prev_span = self.prev_span; - let item = self.mk_item(lo, - prev_span.hi, + let item = self.mk_item(lo.to(prev_span), ident, item_, visibility, @@ -5648,8 +5604,7 @@ impl<'a> Parser<'a> { self.expect_keyword(keywords::Impl)?; let (ident, item_, extra_attrs) = self.parse_item_impl(ast::Unsafety::Unsafe)?; let prev_span = self.prev_span; - let item = self.mk_item(lo, - prev_span.hi, + let item = self.mk_item(lo.to(prev_span), ident, item_, visibility, @@ -5665,8 +5620,7 @@ impl<'a> Parser<'a> { respan(fn_span, Constness::NotConst), Abi::Rust)?; let prev_span = self.prev_span; - let item = self.mk_item(lo, - prev_span.hi, + let item = self.mk_item(lo.to(prev_span), ident, item_, visibility, @@ -5689,8 +5643,7 @@ impl<'a> Parser<'a> { respan(fn_span, Constness::NotConst), abi)?; let prev_span = self.prev_span; - let item = self.mk_item(lo, - prev_span.hi, + let item = self.mk_item(lo.to(prev_span), ident, item_, visibility, @@ -5702,8 +5655,7 @@ impl<'a> Parser<'a> { let (ident, item_, extra_attrs) = self.parse_item_mod(&attrs[..])?; let prev_span = self.prev_span; - let item = self.mk_item(lo, - prev_span.hi, + let item = self.mk_item(lo.to(prev_span), ident, item_, visibility, @@ -5714,8 +5666,7 @@ impl<'a> Parser<'a> { // TYPE ITEM let (ident, item_, extra_attrs) = self.parse_item_type()?; let prev_span = self.prev_span; - let item = self.mk_item(lo, - prev_span.hi, + let item = self.mk_item(lo.to(prev_span), ident, item_, visibility, @@ -5726,8 +5677,7 @@ impl<'a> Parser<'a> { // ENUM ITEM let (ident, item_, extra_attrs) = self.parse_item_enum()?; let prev_span = self.prev_span; - let item = self.mk_item(lo, - prev_span.hi, + let item = self.mk_item(lo.to(prev_span), ident, item_, visibility, @@ -5739,8 +5689,7 @@ impl<'a> Parser<'a> { let (ident, item_, extra_attrs) = self.parse_item_trait(ast::Unsafety::Normal)?; let prev_span = self.prev_span; - let item = self.mk_item(lo, - prev_span.hi, + let item = self.mk_item(lo.to(prev_span), ident, item_, visibility, @@ -5751,8 +5700,7 @@ impl<'a> Parser<'a> { // IMPL ITEM let (ident, item_, extra_attrs) = self.parse_item_impl(ast::Unsafety::Normal)?; let prev_span = self.prev_span; - let item = self.mk_item(lo, - prev_span.hi, + let item = self.mk_item(lo.to(prev_span), ident, item_, visibility, @@ -5763,8 +5711,7 @@ impl<'a> Parser<'a> { // STRUCT ITEM let (ident, item_, extra_attrs) = self.parse_item_struct()?; let prev_span = self.prev_span; - let item = self.mk_item(lo, - prev_span.hi, + let item = self.mk_item(lo.to(prev_span), ident, item_, visibility, @@ -5776,8 +5723,7 @@ impl<'a> Parser<'a> { self.bump(); let (ident, item_, extra_attrs) = self.parse_item_union()?; let prev_span = self.prev_span; - let item = self.mk_item(lo, - prev_span.hi, + let item = self.mk_item(lo.to(prev_span), ident, item_, visibility, @@ -5794,7 +5740,7 @@ impl<'a> Parser<'a> { /// Parse a foreign item. fn parse_foreign_item(&mut self) -> PResult<'a, Option> { let attrs = self.parse_outer_attributes()?; - let lo = self.span.lo; + let lo = self.span; let visibility = self.parse_visibility(false)?; if self.check_keyword(keywords::Static) { @@ -5821,7 +5767,7 @@ impl<'a> Parser<'a> { attrs: Vec , macros_allowed: bool, attributes_allowed: bool, - lo: BytePos, + lo: Span, visibility: Visibility ) -> PResult<'a, Option>> { if macros_allowed && self.token.is_path_start() { @@ -5830,7 +5776,7 @@ impl<'a> Parser<'a> { let prev_span = self.prev_span; self.complain_if_pub_macro(&visibility, prev_span); - let mac_lo = self.span.lo; + let mac_lo = self.span; // item macro. let pth = self.parse_path(PathStyle::Mod)?; @@ -5856,9 +5802,9 @@ impl<'a> Parser<'a> { } } - let hi = self.prev_span.hi; - let mac = spanned(mac_lo, hi, Mac_ { path: pth, tts: tts }); - let item = self.mk_item(lo, hi, id, ItemKind::Mac(mac), visibility, attrs); + let hi = self.prev_span; + let mac = respan(mac_lo.to(hi), Mac_ { path: pth, tts: tts }); + let item = self.mk_item(lo.to(hi), id, ItemKind::Mac(mac), visibility, attrs); return Ok(Some(item)); } @@ -5886,7 +5832,7 @@ impl<'a> Parser<'a> { self.parse_unspanned_seq(&token::OpenDelim(token::Brace), &token::CloseDelim(token::Brace), SeqSep::trailing_allowed(token::Comma), |this| { - let lo = this.span.lo; + let lo = this.span; let ident = if this.eat_keyword(keywords::SelfValue) { keywords::SelfValue.ident() } else { @@ -5898,8 +5844,7 @@ impl<'a> Parser<'a> { rename: rename, id: ast::DUMMY_NODE_ID }; - let hi = this.prev_span.hi; - Ok(spanned(lo, hi, node)) + Ok(respan(lo.to(this.prev_span), node)) }) } @@ -5917,21 +5862,21 @@ impl<'a> Parser<'a> { /// MOD_SEP? non_global_path MOD_SEP LBRACE item_seq RBRACE /// MOD_SEP? LBRACE item_seq RBRACE fn parse_view_path(&mut self) -> PResult<'a, P> { - let lo = self.span.lo; + let lo = self.span; if self.check(&token::OpenDelim(token::Brace)) || self.check(&token::BinOp(token::Star)) || self.is_import_coupler() { // `{foo, bar}`, `::{foo, bar}`, `*`, or `::*`. self.eat(&token::ModSep); let prefix = ast::Path { segments: vec![PathSegment::crate_root()], - span: mk_sp(lo, self.span.hi), + span: lo.to(self.span), }; let view_path_kind = if self.eat(&token::BinOp(token::Star)) { ViewPathGlob(prefix) } else { ViewPathList(prefix, self.parse_path_list_items()?) }; - Ok(P(spanned(lo, self.span.hi, view_path_kind))) + Ok(P(respan(lo.to(self.span), view_path_kind))) } else { let prefix = self.parse_path(PathStyle::Mod)?.default_to_global(); if self.is_import_coupler() { @@ -5939,16 +5884,16 @@ impl<'a> Parser<'a> { self.bump(); if self.check(&token::BinOp(token::Star)) { self.bump(); - Ok(P(spanned(lo, self.span.hi, ViewPathGlob(prefix)))) + Ok(P(respan(lo.to(self.span), ViewPathGlob(prefix)))) } else { let items = self.parse_path_list_items()?; - Ok(P(spanned(lo, self.span.hi, ViewPathList(prefix, items)))) + Ok(P(respan(lo.to(self.span), ViewPathList(prefix, items)))) } } else { // `foo::bar` or `foo::bar as baz` let rename = self.parse_rename()?. unwrap_or(prefix.segments.last().unwrap().identifier); - Ok(P(spanned(lo, self.prev_span.hi, ViewPathSimple(rename, prefix)))) + Ok(P(respan(lo.to(self.prev_span), ViewPathSimple(rename, prefix)))) } } } @@ -5964,11 +5909,11 @@ impl<'a> Parser<'a> { /// Parses a source module as a crate. This is the main /// entry point for the parser. pub fn parse_crate_mod(&mut self) -> PResult<'a, Crate> { - let lo = self.span.lo; + let lo = self.span; Ok(ast::Crate { attrs: self.parse_inner_attributes()?, module: self.parse_mod_items(&token::Eof, lo)?, - span: mk_sp(lo, self.span.lo), + span: lo.to(self.span), }) } diff --git a/src/libsyntax_ext/format.rs b/src/libsyntax_ext/format.rs index aeb5b1e0a53..6f5ab50b2fe 100644 --- a/src/libsyntax_ext/format.rs +++ b/src/libsyntax_ext/format.rs @@ -559,11 +559,7 @@ impl<'a, 'b> Context<'a, 'b> { let name = self.ecx.ident_of(&format!("__arg{}", i)); pats.push(self.ecx.pat_ident(DUMMY_SP, name)); for ref arg_ty in self.arg_unique_types[i].iter() { - locals.push(Context::format_arg(self.ecx, - self.macsp, - e.span, - arg_ty, - self.ecx.expr_ident(e.span, name))); + locals.push(Context::format_arg(self.ecx, self.macsp, e.span, arg_ty, name)); } heads.push(self.ecx.expr_addr_of(e.span, e)); } @@ -576,11 +572,7 @@ impl<'a, 'b> Context<'a, 'b> { Exact(i) => spans_pos[i], _ => panic!("should never happen"), }; - counts.push(Context::format_arg(self.ecx, - self.macsp, - span, - &Count, - self.ecx.expr_ident(span, name))); + counts.push(Context::format_arg(self.ecx, self.macsp, span, &Count, name)); } // Now create a vector containing all the arguments @@ -643,9 +635,10 @@ impl<'a, 'b> Context<'a, 'b> { macsp: Span, mut sp: Span, ty: &ArgumentType, - arg: P) + arg: ast::Ident) -> P { sp.ctxt = sp.ctxt.apply_mark(ecx.current_expansion.mark); + let arg = ecx.expr_ident(sp, arg); let trait_ = match *ty { Placeholder(ref tyname) => { match &tyname[..] { diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs index 9b45e364ecf..947192a0a23 100644 --- a/src/libsyntax_pos/lib.rs +++ b/src/libsyntax_pos/lib.rs @@ -174,6 +174,15 @@ impl Span { } result } + + pub fn to(self, end: Span) -> Span { + // FIXME(jseyfried): self.ctxt should always equal end.ctxt here (c.f. issue #23480) + if end.ctxt == SyntaxContext::empty() { + Span { lo: self.lo, ..end } + } else { + Span { hi: end.hi, ..self } + } + } } #[derive(Clone, Debug)] @@ -208,7 +217,7 @@ impl serialize::UseSpecializedDecodable for Span { d.read_struct("Span", 2, |d| { let lo = d.read_struct_field("lo", 0, Decodable::decode)?; let hi = d.read_struct_field("hi", 1, Decodable::decode)?; - Ok(mk_sp(lo, hi)) + Ok(Span { lo: lo, hi: hi, ctxt: NO_EXPANSION }) }) } } @@ -696,11 +705,6 @@ pub struct FileLines { thread_local!(pub static SPAN_DEBUG: Cell fmt::Result> = Cell::new(default_span_debug)); -/* assuming that we're not in macro expansion */ -pub fn mk_sp(lo: BytePos, hi: BytePos) -> Span { - Span {lo: lo, hi: hi, ctxt: NO_EXPANSION} -} - pub struct MacroBacktrace { /// span where macro was applied to generate this code pub call_site: Span, diff --git a/src/test/compile-fail/imports/macro-paths.rs b/src/test/compile-fail/imports/macro-paths.rs index 48e7ca0eee4..7c19917acc4 100644 --- a/src/test/compile-fail/imports/macro-paths.rs +++ b/src/test/compile-fail/imports/macro-paths.rs @@ -25,7 +25,6 @@ fn f() { bar::m! { //~ ERROR ambiguous //~| NOTE macro-expanded items do not shadow when used in a macro invocation path mod bar { pub use two_macros::m; } //~ NOTE could refer to the name defined here - //~^^^ NOTE in this expansion } } @@ -37,6 +36,5 @@ fn g() { baz::m! { //~ ERROR ambiguous //~| NOTE macro-expanded items do not shadow when used in a macro invocation path mod baz { pub use two_macros::m; } //~ NOTE could refer to the name defined here - //~^^^ NOTE in this expansion } } diff --git a/src/test/compile-fail/imports/macros.rs b/src/test/compile-fail/imports/macros.rs index cfa7681dc22..06b0964a3b1 100644 --- a/src/test/compile-fail/imports/macros.rs +++ b/src/test/compile-fail/imports/macros.rs @@ -28,7 +28,6 @@ mod m2 { m! { //~ ERROR ambiguous //~| NOTE macro-expanded macro imports do not shadow use foo::m; //~ NOTE could refer to the name imported here - //~^^^ NOTE in this expansion } } @@ -43,7 +42,6 @@ mod m3 { m! { //~ ERROR ambiguous //~| NOTE macro-expanded macro imports do not shadow use two_macros::n as m; //~ NOTE could refer to the name imported here - //~^^^ NOTE in this expansion } } } diff --git a/src/test/compile-fail/imports/shadow_builtin_macros.rs b/src/test/compile-fail/imports/shadow_builtin_macros.rs index 2b3ba1b4aa7..a7f1cf3c9d3 100644 --- a/src/test/compile-fail/imports/shadow_builtin_macros.rs +++ b/src/test/compile-fail/imports/shadow_builtin_macros.rs @@ -31,7 +31,6 @@ mod m2 { mod m3 { ::two_macros::m!(use foo::panic;); //~ NOTE `panic` could refer to the name imported here - //~| NOTE in this expansion fn f() { panic!(); } //~ ERROR ambiguous //~| NOTE `panic` is also a builtin macro //~| NOTE macro-expanded macro imports do not shadow diff --git a/src/test/compile-fail/issue-25385.rs b/src/test/compile-fail/issue-25385.rs index 51d7baaf3e9..4aacb6840e9 100644 --- a/src/test/compile-fail/issue-25385.rs +++ b/src/test/compile-fail/issue-25385.rs @@ -21,5 +21,4 @@ fn main() { foo!(1i32.foo()); //~^ ERROR no method named `foo` found for type `i32` in the current scope - //~^^ NOTE in this expansion of foo! } diff --git a/src/test/run-pass/syntax-extension-source-utils.rs b/src/test/run-pass/syntax-extension-source-utils.rs index 3b5f033d07b..25c7417f7eb 100644 --- a/src/test/run-pass/syntax-extension-source-utils.rs +++ b/src/test/run-pass/syntax-extension-source-utils.rs @@ -22,7 +22,7 @@ macro_rules! indirect_line { () => ( line!() ) } pub fn main() { assert_eq!(line!(), 24); - assert_eq!(column!(), 4); + assert_eq!(column!(), 15); assert_eq!(indirect_line!(), 26); assert!((file!().ends_with("syntax-extension-source-utils.rs"))); assert_eq!(stringify!((2*3) + 5).to_string(), "( 2 * 3 ) + 5".to_string()); diff --git a/src/test/ui/macros/macro_path_as_generic_bound.stderr b/src/test/ui/macros/macro_path_as_generic_bound.stderr index 96635032105..e4044f5aaf2 100644 --- a/src/test/ui/macros/macro_path_as_generic_bound.stderr +++ b/src/test/ui/macros/macro_path_as_generic_bound.stderr @@ -2,10 +2,7 @@ error[E0433]: failed to resolve. Use of undeclared type or module `m` --> $DIR/macro_path_as_generic_bound.rs:17:6 | 17 | foo!(m::m2::A); - | -----^^^^^^^^-- - | | | - | | Use of undeclared type or module `m` - | in this macro invocation + | ^^^^^^^^ Use of undeclared type or module `m` error: cannot continue compilation due to previous error -- cgit 1.4.1-3-g733a5 From e3acebff66c89e2a50c8bfcd08fbe221265b30b0 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Thu, 30 Mar 2017 12:14:04 +1300 Subject: save-analysis: track associated types --- src/librustc_save_analysis/dump_visitor.rs | 30 +++++++++++++++++++++++++++--- src/test/run-make/save-analysis/foo.rs | 17 +++++++++++++++++ 2 files changed, 44 insertions(+), 3 deletions(-) (limited to 'src/test') diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index f2aa89ba4b6..7a7fa4eda05 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -1149,8 +1149,32 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { &trait_item.attrs, trait_item.span); } - ast::TraitItemKind::Const(_, None) | - ast::TraitItemKind::Type(..) | + ast::TraitItemKind::Type(ref _bounds, ref default_ty) => { + // FIXME do something with _bounds (for type refs) + let name = trait_item.ident.name.to_string(); + let qualname = format!("::{}", self.tcx.node_path_str(trait_item.id)); + let sub_span = self.span.sub_span_after_keyword(trait_item.span, keywords::Type); + + if !self.span.filter_generated(sub_span, trait_item.span) { + self.dumper.typedef(TypeDefData { + span: sub_span.expect("No span found for assoc type"), + name: name, + id: trait_item.id, + qualname: qualname, + value: self.span.snippet(trait_item.span), + visibility: Visibility::Public, + parent: Some(trait_id), + docs: docs_for_attrs(&trait_item.attrs), + sig: None, + attributes: trait_item.attrs.clone(), + }.lower(self.tcx)); + } + + if let &Some(ref default_ty) = default_ty { + self.visit_ty(default_ty) + } + } + ast::TraitItemKind::Const(ref ty, None) => self.visit_ty(ty), ast::TraitItemKind::Macro(_) => {} } } @@ -1177,7 +1201,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { &impl_item.attrs, impl_item.span); } - ast::ImplItemKind::Type(_) | + ast::ImplItemKind::Type(ref ty) => self.visit_ty(ty), ast::ImplItemKind::Macro(_) => {} } } diff --git a/src/test/run-make/save-analysis/foo.rs b/src/test/run-make/save-analysis/foo.rs index e8b69729af6..3fe1479f5f2 100644 --- a/src/test/run-make/save-analysis/foo.rs +++ b/src/test/run-make/save-analysis/foo.rs @@ -11,6 +11,7 @@ #![ crate_name = "test" ] #![feature(box_syntax)] #![feature(rustc_private)] +#![feature(associated_type_defaults)] extern crate graphviz; // A simple rust project @@ -441,3 +442,19 @@ fn test_format_args() { print!("{0} + {} = {}", x, y); print!("x is {}, y is {1}, name is {n}", x, y, n = name); } + +struct FrameBuffer; + +struct SilenceGenerator; + +impl Iterator for SilenceGenerator { + type Item = FrameBuffer; + + fn next(&mut self) -> Option { + panic!(); + } +} + +trait Foo { + type Bar = FrameBuffer; +} -- cgit 1.4.1-3-g733a5 From 08a741eabf3c223650bb29c5df30c8fd414cd86a Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 29 Mar 2017 19:48:06 -0600 Subject: Add support for image, rules and footnotes --- src/librustdoc/html/markdown.rs | 139 ++++++++++++++++++++------ src/test/rustdoc/check-rule-image-footnote.rs | 35 +++++++ 2 files changed, 146 insertions(+), 28 deletions(-) create mode 100644 src/test/rustdoc/check-rule-image-footnote.rs (limited to 'src/test') diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 117cfbabb52..6c82dab94bc 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -133,11 +133,37 @@ macro_rules! event_loop_break { }} } +struct ParserWrapper<'a> { + parser: Parser<'a>, + footnotes: Vec, + current_footnote_id: u16, +} + +impl<'a> ParserWrapper<'a> { + pub fn new(s: &'a str) -> ParserWrapper<'a> { + ParserWrapper { + parser: Parser::new_ext(s, pulldown_cmark::OPTION_ENABLE_TABLES | + pulldown_cmark::OPTION_ENABLE_FOOTNOTES), + footnotes: Vec::new(), + current_footnote_id: 1, + } + } + pub fn next(&mut self) -> Option> { + self.parser.next() + } + + pub fn get_next_footnote_id(&mut self) -> u16 { + let tmp = self.current_footnote_id; + self.current_footnote_id += 1; + tmp + } +} + pub fn render(w: &mut fmt::Formatter, s: &str, print_toc: bool, shorter: MarkdownOutputStyle) -> fmt::Result { - fn code_block(parser: &mut Parser, buffer: &mut String, lang: &str) { + fn code_block(parser: &mut ParserWrapper, buffer: &mut String, lang: &str) { let mut origtext = String::new(); while let Some(event) = parser.next() { match event { @@ -215,8 +241,8 @@ pub fn render(w: &mut fmt::Formatter, }); } - fn heading(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, - shorter: MarkdownOutputStyle, level: i32) { + fn heading(parser: &mut ParserWrapper, buffer: &mut String, + toc_builder: &mut Option, shorter: MarkdownOutputStyle, level: i32) { let mut ret = String::new(); let mut id = String::new(); event_loop_break!(parser, toc_builder, shorter, ret, true, &mut Some(&mut id), @@ -249,32 +275,48 @@ pub fn render(w: &mut fmt::Formatter, ret, lvl = level, id = id, sec = sec)); } - fn inline_code(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, - shorter: MarkdownOutputStyle, id: &mut Option<&mut String>) { + fn inline_code(parser: &mut ParserWrapper, buffer: &mut String, + toc_builder: &mut Option, shorter: MarkdownOutputStyle, + id: &mut Option<&mut String>) { let mut content = String::new(); event_loop_break!(parser, toc_builder, shorter, content, false, id, Event::End(Tag::Code)); buffer.push_str(&format!("{}", Escape(&collapse_whitespace(content.trim_right())))); } - fn link(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, + fn link(parser: &mut ParserWrapper, buffer: &mut String, toc_builder: &mut Option, + shorter: MarkdownOutputStyle, url: &str, title: &str, + id: &mut Option<&mut String>) { + let mut content = String::new(); + event_loop_break!(parser, toc_builder, shorter, content, true, id, + Event::End(Tag::Link(_, _))); + if title.is_empty() { + buffer.push_str(&format!("{}", url, content)); + } else { + buffer.push_str(&format!("{}", + url, Escape(title), content)); + } + } + + fn image(parser: &mut ParserWrapper, buffer: &mut String, toc_builder: &mut Option, shorter: MarkdownOutputStyle, url: &str, mut title: String, id: &mut Option<&mut String>) { event_loop_break!(parser, toc_builder, shorter, title, true, id, - Event::End(Tag::Link(_, _))); - buffer.push_str(&format!("{}", url, title)); + Event::End(Tag::Image(_, _))); + buffer.push_str(&format!("\"{}\"", url, title)); } - fn paragraph(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, - shorter: MarkdownOutputStyle, id: &mut Option<&mut String>) { + fn paragraph(parser: &mut ParserWrapper, buffer: &mut String, + toc_builder: &mut Option, shorter: MarkdownOutputStyle, + id: &mut Option<&mut String>) { let mut content = String::new(); event_loop_break!(parser, toc_builder, shorter, content, true, id, Event::End(Tag::Paragraph)); buffer.push_str(&format!("

{}

", content.trim_right())); } - fn table_cell(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, - shorter: MarkdownOutputStyle) { + fn table_cell(parser: &mut ParserWrapper, buffer: &mut String, + toc_builder: &mut Option, shorter: MarkdownOutputStyle) { let mut content = String::new(); event_loop_break!(parser, toc_builder, shorter, content, true, &mut None, Event::End(Tag::TableHead) | @@ -284,8 +326,8 @@ pub fn render(w: &mut fmt::Formatter, buffer.push_str(&format!("{}", content.trim())); } - fn table_row(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, - shorter: MarkdownOutputStyle) { + fn table_row(parser: &mut ParserWrapper, buffer: &mut String, + toc_builder: &mut Option, shorter: MarkdownOutputStyle) { let mut content = String::new(); while let Some(event) = parser.next() { match event { @@ -303,8 +345,8 @@ pub fn render(w: &mut fmt::Formatter, buffer.push_str(&format!("{}", content)); } - fn table_head(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, - shorter: MarkdownOutputStyle) { + fn table_head(parser: &mut ParserWrapper, buffer: &mut String, + toc_builder: &mut Option, shorter: MarkdownOutputStyle) { let mut content = String::new(); while let Some(event) = parser.next() { match event { @@ -322,7 +364,7 @@ pub fn render(w: &mut fmt::Formatter, } } - fn table(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, + fn table(parser: &mut ParserWrapper, buffer: &mut String, toc_builder: &mut Option, shorter: MarkdownOutputStyle) { let mut content = String::new(); let mut rows = String::new(); @@ -347,16 +389,16 @@ pub fn render(w: &mut fmt::Formatter, })); } - fn blockquote(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, - shorter: MarkdownOutputStyle) { + fn blockquote(parser: &mut ParserWrapper, buffer: &mut String, + toc_builder: &mut Option, shorter: MarkdownOutputStyle) { let mut content = String::new(); event_loop_break!(parser, toc_builder, shorter, content, true, &mut None, Event::End(Tag::BlockQuote)); buffer.push_str(&format!("
{}
", content.trim_right())); } - fn list_item(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, - shorter: MarkdownOutputStyle) { + fn list_item(parser: &mut ParserWrapper, buffer: &mut String, + toc_builder: &mut Option, shorter: MarkdownOutputStyle) { let mut content = String::new(); while let Some(event) = parser.next() { match event { @@ -372,7 +414,7 @@ pub fn render(w: &mut fmt::Formatter, buffer.push_str(&format!("
  • {}
  • ", content)); } - fn list(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, + fn list(parser: &mut ParserWrapper, buffer: &mut String, toc_builder: &mut Option, shorter: MarkdownOutputStyle) { let mut content = String::new(); while let Some(event) = parser.next() { @@ -389,15 +431,16 @@ pub fn render(w: &mut fmt::Formatter, buffer.push_str(&format!("
      {}
    ", content)); } - fn emphasis(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, - shorter: MarkdownOutputStyle, id: &mut Option<&mut String>) { + fn emphasis(parser: &mut ParserWrapper, buffer: &mut String, + toc_builder: &mut Option, shorter: MarkdownOutputStyle, + id: &mut Option<&mut String>) { let mut content = String::new(); event_loop_break!(parser, toc_builder, shorter, content, false, id, Event::End(Tag::Emphasis)); buffer.push_str(&format!("{}", content)); } - fn strong(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, + fn strong(parser: &mut ParserWrapper, buffer: &mut String, toc_builder: &mut Option, shorter: MarkdownOutputStyle, id: &mut Option<&mut String>) { let mut content = String::new(); event_loop_break!(parser, toc_builder, shorter, content, false, id, @@ -405,7 +448,23 @@ pub fn render(w: &mut fmt::Formatter, buffer.push_str(&format!("{}", content)); } - fn looper<'a>(parser: &'a mut Parser, buffer: &mut String, next_event: Option>, + fn footnote(parser: &mut ParserWrapper, buffer: &mut String, + toc_builder: &mut Option, shorter: MarkdownOutputStyle, + mut definition: String, id: &mut Option<&mut String>) { + event_loop_break!(parser, toc_builder, shorter, definition, true, id, + Event::End(Tag::FootnoteDefinition(_))); + buffer.push_str(&definition); + } + + fn rule(parser: &mut ParserWrapper, buffer: &mut String, toc_builder: &mut Option, + shorter: MarkdownOutputStyle, id: &mut Option<&mut String>) { + let mut content = String::new(); + event_loop_break!(parser, toc_builder, shorter, content, true, id, + Event::End(Tag::Rule)); + buffer.push_str("
    "); + } + + fn looper<'a>(parser: &'a mut ParserWrapper, buffer: &mut String, next_event: Option>, toc_builder: &mut Option, shorter: MarkdownOutputStyle, id: &mut Option<&mut String>) -> bool { if let Some(event) = next_event { @@ -423,7 +482,10 @@ pub fn render(w: &mut fmt::Formatter, paragraph(parser, buffer, toc_builder, shorter, id); } Event::Start(Tag::Link(ref url, ref t)) => { - link(parser, buffer, toc_builder, shorter, url, t.as_ref().to_owned(), id); + link(parser, buffer, toc_builder, shorter, url, t.as_ref(), id); + } + Event::Start(Tag::Image(ref url, ref t)) => { + image(parser, buffer, toc_builder, shorter, url, t.as_ref().to_owned(), id); } Event::Start(Tag::Table(_)) => { table(parser, buffer, toc_builder, shorter); @@ -440,6 +502,23 @@ pub fn render(w: &mut fmt::Formatter, Event::Start(Tag::Strong) => { strong(parser, buffer, toc_builder, shorter, id); } + Event::Start(Tag::Rule) => { + rule(parser, buffer, toc_builder, shorter, id); + } + Event::Start(Tag::FootnoteDefinition(ref def)) => { + let mut content = String::new(); + footnote(parser, &mut content, toc_builder, shorter, def.as_ref().to_owned(), + id); + let cur_len = parser.footnotes.len() + 1; + parser.footnotes.push(format!("
  • {}
  • ", + cur_len, content)); + } + Event::FootnoteReference(_) => { + buffer.push_str(&format!("{0}\ + ", + parser.get_next_footnote_id())); + } Event::Html(h) | Event::InlineHtml(h) => { buffer.push_str(&*h); } @@ -457,13 +536,17 @@ pub fn render(w: &mut fmt::Formatter, None }; let mut buffer = String::new(); - let mut parser = Parser::new_ext(s, pulldown_cmark::OPTION_ENABLE_TABLES); + let mut parser = ParserWrapper::new(s); loop { let next_event = parser.next(); if !looper(&mut parser, &mut buffer, next_event, &mut toc_builder, shorter, &mut None) { break } } + if !parser.footnotes.is_empty() { + buffer.push_str(&format!("

      {}
    ", + parser.footnotes.join(""))); + } let mut ret = toc_builder.map_or(Ok(()), |builder| { write!(w, "", builder.into_toc()) }); diff --git a/src/test/rustdoc/check-rule-image-footnote.rs b/src/test/rustdoc/check-rule-image-footnote.rs new file mode 100644 index 00000000000..629e1a64e6f --- /dev/null +++ b/src/test/rustdoc/check-rule-image-footnote.rs @@ -0,0 +1,35 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![crate_name = "foo"] + +// @has foo/fn.f.html +// @has - '

    hard break: after hard break


    ' +// @has - 'Rust' +// @has - '
  • ' +// @has - '1' +/// markdown test +/// +/// this is a [link]. +/// +/// [link]: https://example.com "this is a title" +/// +/// hard break: +/// after hard break +/// +/// ----------- +/// +/// a footnote[^footnote]. +/// +/// [^footnote]: Thing +/// +/// ![Rust](https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png) +#[deprecated(note = "Struct")] +pub fn f() {} -- cgit 1.4.1-3-g733a5 From b3763862280946cab09cbedc4ad5626ebd95a5b2 Mon Sep 17 00:00:00 2001 From: Thomas Jespersen Date: Fri, 17 Mar 2017 23:11:27 +0100 Subject: Replace hardcoded forward slash with path::MAIN_SEPARATOR Fixes #40149 --- src/libstd/sys_common/backtrace.rs | 4 +-- src/libsyntax/parse/parser.rs | 9 ++++--- src/test/parse-fail/mod_file_not_exist.rs | 2 ++ src/test/parse-fail/mod_file_not_exist_windows.rs | 32 +++++++++++++++++++++++ 4 files changed, 41 insertions(+), 6 deletions(-) create mode 100644 src/test/parse-fail/mod_file_not_exist_windows.rs (limited to 'src/test') diff --git a/src/libstd/sys_common/backtrace.rs b/src/libstd/sys_common/backtrace.rs index 99297b781e4..f5c188f7a75 100644 --- a/src/libstd/sys_common/backtrace.rs +++ b/src/libstd/sys_common/backtrace.rs @@ -19,7 +19,7 @@ use io; use libc; use str; use sync::atomic::{self, Ordering}; -use path::Path; +use path::{self, Path}; use sys::mutex::Mutex; use ptr; @@ -262,7 +262,7 @@ fn output_fileline(w: &mut Write, file: &[u8], line: libc::c_int, if let Ok(cwd) = env::current_dir() { if let Ok(stripped) = file_path.strip_prefix(&cwd) { if let Some(s) = stripped.to_str() { - write!(w, " at ./{}:{}", s, line)?; + write!(w, " at .{}{}:{}", path::MAIN_SEPARATOR, s, line)?; already_printed = true; } } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index db2878c6b1e..c2c3e5a6855 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -59,7 +59,7 @@ use util::ThinVec; use std::collections::HashSet; use std::{cmp, mem, slice}; -use std::path::{Path, PathBuf}; +use std::path::{self, Path, PathBuf}; bitflags! { flags Restrictions: u8 { @@ -5146,7 +5146,7 @@ impl<'a> Parser<'a> { pub fn default_submod_path(id: ast::Ident, dir_path: &Path, codemap: &CodeMap) -> ModulePath { let mod_name = id.to_string(); let default_path_str = format!("{}.rs", mod_name); - let secondary_path_str = format!("{}/mod.rs", mod_name); + let secondary_path_str = format!("{}{}mod.rs", mod_name, path::MAIN_SEPARATOR); let default_path = dir_path.join(&default_path_str); let secondary_path = dir_path.join(&secondary_path_str); let default_exists = codemap.file_exists(&default_path); @@ -5224,8 +5224,9 @@ impl<'a> Parser<'a> { }; err.span_note(id_sp, &format!("maybe move this module `{0}` to its own directory \ - via `{0}/mod.rs`", - this_module)); + via `{0}{1}mod.rs`", + this_module, + path::MAIN_SEPARATOR)); if paths.path_exists { err.span_note(id_sp, &format!("... or maybe `use` the module `{}` instead \ diff --git a/src/test/parse-fail/mod_file_not_exist.rs b/src/test/parse-fail/mod_file_not_exist.rs index 7736394a6f5..4bc6e706d42 100644 --- a/src/test/parse-fail/mod_file_not_exist.rs +++ b/src/test/parse-fail/mod_file_not_exist.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-windows + // compile-flags: -Z parse-only mod not_a_real_file; //~ ERROR file not found for module `not_a_real_file` diff --git a/src/test/parse-fail/mod_file_not_exist_windows.rs b/src/test/parse-fail/mod_file_not_exist_windows.rs new file mode 100644 index 00000000000..c58603b4398 --- /dev/null +++ b/src/test/parse-fail/mod_file_not_exist_windows.rs @@ -0,0 +1,32 @@ +// Copyright 2012 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. + +// ignore-gnu +// ignore-android +// ignore-bitrig +// ignore-macos +// ignore-dragonfly +// ignore-freebsd +// ignore-haiku +// ignore-ios +// ignore-linux +// ignore-netbsd +// ignore-openbsd +// ignore-solaris +// ignore-emscripten + +// compile-flags: -Z parse-only + +mod not_a_real_file; //~ ERROR file not found for module `not_a_real_file` +//~^ HELP name the file either not_a_real_file.rs or not_a_real_file\mod.rs inside the directory + +fn main() { + assert_eq!(mod_file_aux::bar(), 10); +} -- cgit 1.4.1-3-g733a5 From 4c6c26eba1ca315677b024026a54001a5ab96cd0 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 2 Mar 2017 21:15:26 -0500 Subject: change the strategy for diverging types The new strategy is as follows. First, the `!` type is assigned in two cases: - a block with a diverging statement and no tail expression (e.g., `{return;}`); - any expression with the type `!` is considered diverging. Second, we track when we are in a diverging state, and we permit a value of any type to be coerced **into** `!` if the expression that produced it is diverging. This means that `fn foo() -> ! { panic!(); 22 }` type-checks, even though the block has a type of `usize`. Finally, coercions **from** the `!` type to any other are always permitted. Fixes #39808. --- src/librustc_typeck/check/demand.rs | 24 ++++++++++++++++++++- src/librustc_typeck/check/mod.rs | 24 +++++++++++---------- .../compile-fail/diverging-tuple-parts-39485.rs | 25 ++++++++++++++++++++++ src/test/compile-fail/never-assign-wrong-type.rs | 1 + src/test/run-pass/issue-39808.rs | 21 ++++++++++++++++++ 5 files changed, 83 insertions(+), 12 deletions(-) create mode 100644 src/test/compile-fail/diverging-tuple-parts-39485.rs create mode 100644 src/test/run-pass/issue-39808.rs (limited to 'src/test') diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs index 232c4c4db7c..25d689b3c2c 100644 --- a/src/librustc_typeck/check/demand.rs +++ b/src/librustc_typeck/check/demand.rs @@ -67,8 +67,30 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } // Checks that the type of `expr` can be coerced to `expected`. - pub fn demand_coerce(&self, expr: &hir::Expr, checked_ty: Ty<'tcx>, expected: Ty<'tcx>) { + // + // NB: This code relies on `self.diverges` to be accurate. In + // particular, assignments to `!` will be permitted if the + // diverges flag is currently "always". + pub fn demand_coerce(&self, + expr: &hir::Expr, + checked_ty: Ty<'tcx>, + expected: Ty<'tcx>) { let expected = self.resolve_type_vars_with_obligations(expected); + + // If we are "assigning" to a `!` location, then we can permit + // any type to be assigned there, so long as we are in + // dead-code. This applies to e.g. `fn foo() -> ! { return; 22 + // }` but also `fn foo() { let x: ! = { return; 22 }; }`. + // + // You might imagine that we could just *always* bail if we + // are in dead-code, but we don't want to do that, because + // that leaves a lot of type variables unconstrained. See + // e.g. #39808 and #39984. + let in_dead_code = self.diverges.get().always(); + if expected.is_never() && in_dead_code { + return; + } + if let Err(e) = self.try_coerce(expr, checked_ty, expected) { let cause = self.misc(expr.span); let expr_ty = self.resolve_type_vars_with_obligations(checked_ty); diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 000398a4bce..5d002dba78c 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1533,18 +1533,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { #[inline] pub fn write_ty(&self, node_id: ast::NodeId, ty: Ty<'tcx>) { debug!("write_ty({}, {:?}) in fcx {}", - node_id, ty, self.tag()); + node_id, self.resolve_type_vars_if_possible(&ty), self.tag()); self.tables.borrow_mut().node_types.insert(node_id, ty); if ty.references_error() { self.has_errors.set(true); self.set_tainted_by_errors(); } - - // FIXME(canndrew): This is_never should probably be an is_uninhabited - if ty.is_never() || self.type_var_diverges(ty) { - self.diverges.set(self.diverges.get() | Diverges::Always); - } } pub fn write_substs(&self, node_id: ast::NodeId, substs: ty::ItemSubsts<'tcx>) { @@ -3282,6 +3277,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { _ => self.warn_if_unreachable(expr.id, expr.span, "expression") } + // Any expression that produces a value of type `!` must have diverged + if ty.is_never() { + self.diverges.set(self.diverges.get() | Diverges::Always); + } + // Record the type, which applies it effects. // We need to do this after the warning above, so that // we don't warn for the diverging expression itself. @@ -3967,7 +3967,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.diverges.set(Diverges::Maybe); self.has_errors.set(false); - let (node_id, span) = match stmt.node { + let (node_id, _span) = match stmt.node { hir::StmtDecl(ref decl, id) => { let span = match decl.node { hir::DeclLocal(ref l) => { @@ -3993,9 +3993,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if self.has_errors.get() { self.write_error(node_id); - } else if self.diverges.get().always() { - self.write_ty(node_id, self.next_diverging_ty_var( - TypeVariableOrigin::DivergingStmt(span))); } else { self.write_nil(node_id); } @@ -4046,7 +4043,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { cause = self.misc(e.span); }, None => { - e_ty = self.tcx.mk_nil(); + e_ty = if self.diverges.get().always() { + self.next_diverging_ty_var(TypeVariableOrigin::DivergingBlockExpr(blk.span)) + } else { + self.tcx.mk_nil() + }; cause = self.misc(blk.span); } }; @@ -4054,6 +4055,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { (e_ty, cause) }); + if let ExpectHasType(ety) = expected { if let Some(ref e) = blk.expr { let result = if !ctxt.may_break { self.try_coerce(e, e_ty, ctxt.coerce_to) diff --git a/src/test/compile-fail/diverging-tuple-parts-39485.rs b/src/test/compile-fail/diverging-tuple-parts-39485.rs new file mode 100644 index 00000000000..eedad08ab55 --- /dev/null +++ b/src/test/compile-fail/diverging-tuple-parts-39485.rs @@ -0,0 +1,25 @@ +// Copyright 2014 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. + +// After #39485, this test used to pass, but that change was reverted +// due to numerous inference failures like #39808, so it now fails +// again. #39485 made it so that diverging types never propagate +// upward; but we now do propagate such types upward in many more +// cases. + +fn g() { + &panic!() //~ ERROR mismatched types +} + +fn f() -> isize { + (return 1, return 2) //~ ERROR mismatched types +} + +fn main() {} diff --git a/src/test/compile-fail/never-assign-wrong-type.rs b/src/test/compile-fail/never-assign-wrong-type.rs index 53d96aaf4fe..d854e6eb203 100644 --- a/src/test/compile-fail/never-assign-wrong-type.rs +++ b/src/test/compile-fail/never-assign-wrong-type.rs @@ -11,6 +11,7 @@ // Test that we can't use another type in place of ! #![feature(never_type)] +#![deny(warnings)] fn main() { let x: ! = "hello"; //~ ERROR mismatched types diff --git a/src/test/run-pass/issue-39808.rs b/src/test/run-pass/issue-39808.rs new file mode 100644 index 00000000000..f83e9328e58 --- /dev/null +++ b/src/test/run-pass/issue-39808.rs @@ -0,0 +1,21 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Regression test: even though `Ok` is dead-code, its type needs to +// be influenced by the result of `Err` or else we get a "type +// variable unconstrained" error. + +fn main() { + let _ = if false { + Ok(return) + } else { + Err("") + }; +} -- cgit 1.4.1-3-g733a5 From 56847af9163284f928d5632a3d0d29399716414f Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 17 Mar 2017 09:51:31 -0400 Subject: port the match code to use `CoerceMany` `match { }` now (correctly?) indicates divergence, which results in more unreachable warnings. We also avoid fallback to `!` if there is just one arm (see new test: `match-unresolved-one-arm.rs`). --- src/librustc_typeck/check/_match.rs | 90 ++++++++++------------ src/libsyntax/parse/obsolete.rs | 1 + .../match-no-arms-unreachable-after.rs | 22 ++++++ ...h-unreachable-warning-with-diverging-discrim.rs | 16 ++++ src/test/compile-fail/match-unresolved-one-arm.rs | 17 ++++ 5 files changed, 95 insertions(+), 51 deletions(-) create mode 100644 src/test/compile-fail/match-no-arms-unreachable-after.rs create mode 100644 src/test/compile-fail/match-unreachable-warning-with-diverging-discrim.rs create mode 100644 src/test/compile-fail/match-unresolved-one-arm.rs (limited to 'src/test') diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index feed5752cf8..f0d2598a0fb 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -16,6 +16,7 @@ use rustc::infer::type_variable::TypeVariableOrigin; use rustc::traits::ObligationCauseCode; use rustc::ty::{self, Ty, TypeFoldable, LvaluePreference}; use check::{FnCtxt, Expectation, Diverges}; +use check::coercion::CoerceMany; use util::nodemap::FxHashMap; use std::collections::hash_map::Entry::{Occupied, Vacant}; @@ -414,6 +415,20 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { discrim_ty = self.next_ty_var(TypeVariableOrigin::TypeInference(discrim.span)); self.check_expr_has_type(discrim, discrim_ty); }; + + // If the discriminant diverges, the match is pointless (e.g., + // `match (return) { }`). + self.warn_if_unreachable(expr.id, expr.span, "expression"); + + // If there are no arms, that is a diverging match; a special case. + if arms.is_empty() { + self.diverges.set(self.diverges.get() | Diverges::Always); + return tcx.types.never; + } + + // Otherwise, we have to union together the types that the + // arms produce and so forth. + let discrim_diverges = self.diverges.get(); self.diverges.set(Diverges::Maybe); @@ -426,6 +441,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.check_pat(&p, discrim_ty); all_pats_diverge &= self.diverges.get(); } + // As discussed with @eddyb, this is for disabling unreachable_code // warnings on patterns (they're now subsumed by unreachable_patterns // warnings). @@ -444,20 +460,21 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // on any empty type and is therefore unreachable; should the flow // of execution reach it, we will panic, so bottom is an appropriate // type in that case) - let expected = expected.adjust_for_branches(self); - let mut result_ty = self.next_diverging_ty_var( - TypeVariableOrigin::DivergingBlockExpr(expr.span)); let mut all_arms_diverge = Diverges::WarnedAlways; - let coerce_first = match expected { - // We don't coerce to `()` so that if the match expression is a - // statement it's branches can have any consistent type. That allows - // us to give better error messages (pointing to a usually better - // arm for inconsistent arms or to the whole match when a `()` type - // is required). - Expectation::ExpectHasType(ety) if ety != self.tcx.mk_nil() => { - ety - } - _ => result_ty + + let expected = expected.adjust_for_branches(self); + + let mut coercion = { + let coerce_first = match expected { + // We don't coerce to `()` so that if the match expression is a + // statement it's branches can have any consistent type. That allows + // us to give better error messages (pointing to a usually better + // arm for inconsistent arms or to the whole match when a `()` type + // is required). + Expectation::ExpectHasType(ety) if ety != self.tcx.mk_nil() => ety, + _ => self.next_ty_var(TypeVariableOrigin::MiscVariable(expr.span)), + }; + CoerceMany::new(coerce_first) }; for (i, (arm, pats_diverge)) in arms.iter().zip(all_arm_pats_diverge).enumerate() { @@ -470,11 +487,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let arm_ty = self.check_expr_with_expectation(&arm.body, expected); all_arms_diverge &= self.diverges.get(); - if result_ty.references_error() || arm_ty.references_error() { - result_ty = tcx.types.err; - continue; - } - // Handle the fallback arm of a desugared if-let like a missing else. let is_if_let_fallback = match match_src { hir::MatchSource::IfLetDesugar { contains_else_clause: false } => { @@ -483,47 +495,23 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { _ => false }; - let cause = if is_if_let_fallback { - self.cause(expr.span, ObligationCauseCode::IfExpressionWithNoElse) + if is_if_let_fallback { + let cause = self.cause(expr.span, ObligationCauseCode::IfExpressionWithNoElse); + assert!(arm_ty.is_nil()); + coercion.coerce_forced_unit(self, &cause); } else { - self.cause(expr.span, ObligationCauseCode::MatchExpressionArm { + let cause = self.cause(expr.span, ObligationCauseCode::MatchExpressionArm { arm_span: arm.body.span, source: match_src - }) - }; - - let result = if is_if_let_fallback { - self.eq_types(true, &cause, arm_ty, result_ty) - .map(|infer_ok| { - self.register_infer_ok_obligations(infer_ok); - arm_ty - }) - } else if i == 0 { - // Special-case the first arm, as it has no "previous expressions". - self.try_coerce(&arm.body, arm_ty, coerce_first) - } else { - let prev_arms = || arms[..i].iter().map(|arm| &*arm.body); - self.try_find_coercion_lub(&cause, prev_arms, result_ty, &arm.body, arm_ty) - }; - - result_ty = match result { - Ok(ty) => ty, - Err(e) => { - let (expected, found) = if is_if_let_fallback { - (arm_ty, result_ty) - } else { - (result_ty, arm_ty) - }; - self.report_mismatched_types(&cause, expected, found, e).emit(); - self.tcx.types.err - } - }; + }); + coercion.coerce(self, &cause, &arm.body, arm_ty); + } } // We won't diverge unless the discriminant or all arms diverge. self.diverges.set(discrim_diverges | all_arms_diverge); - result_ty + coercion.complete(self) } fn check_pat_struct(&self, diff --git a/src/libsyntax/parse/obsolete.rs b/src/libsyntax/parse/obsolete.rs index a46a788ca08..d5baec675e4 100644 --- a/src/libsyntax/parse/obsolete.rs +++ b/src/libsyntax/parse/obsolete.rs @@ -36,6 +36,7 @@ pub trait ParserObsoleteMethods { impl<'a> ParserObsoleteMethods for parser::Parser<'a> { /// Reports an obsolete syntax non-fatal error. #[allow(unused_variables)] + #[allow(unreachable_code)] fn obsolete(&mut self, sp: Span, kind: ObsoleteSyntax) { let (kind_str, desc, error) = match kind { // Nothing here at the moment diff --git a/src/test/compile-fail/match-no-arms-unreachable-after.rs b/src/test/compile-fail/match-no-arms-unreachable-after.rs new file mode 100644 index 00000000000..db08f5e5e66 --- /dev/null +++ b/src/test/compile-fail/match-no-arms-unreachable-after.rs @@ -0,0 +1,22 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![allow(warnings)] +#![deny(unreachable_code)] + +enum Void { } + +fn foo(v: Void) { + match v { } + let x = 2; //~ ERROR unreachable +} + +fn main() { +} diff --git a/src/test/compile-fail/match-unreachable-warning-with-diverging-discrim.rs b/src/test/compile-fail/match-unreachable-warning-with-diverging-discrim.rs new file mode 100644 index 00000000000..aae0f3135d8 --- /dev/null +++ b/src/test/compile-fail/match-unreachable-warning-with-diverging-discrim.rs @@ -0,0 +1,16 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![allow(unused_parens)] +#![deny(unreachable_code)] + +fn main() { + match (return) { } //~ ERROR unreachable expression +} diff --git a/src/test/compile-fail/match-unresolved-one-arm.rs b/src/test/compile-fail/match-unresolved-one-arm.rs new file mode 100644 index 00000000000..ea0f8db99e8 --- /dev/null +++ b/src/test/compile-fail/match-unresolved-one-arm.rs @@ -0,0 +1,17 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn foo() -> T { panic!("Rocks for my pillow") } + +fn main() { + let x = match () { //~ ERROR type annotations needed + () => foo() // T here should be unresolved + }; +} -- cgit 1.4.1-3-g733a5 From a6e6be5f88bc773f50016cc1cf1baaa7b3e6cd11 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 17 Mar 2017 09:54:26 -0400 Subject: port `return` expressions to use `CoerceMany` This slightly affects the error messages in one particular compile-fail test. --- src/librustc_typeck/check/compare_method.rs | 2 +- src/librustc_typeck/check/mod.rs | 85 +++++++++++++++++++++-------- src/librustc_typeck/check/wfcheck.rs | 2 +- src/test/compile-fail/regions-bounds.rs | 10 +--- 4 files changed, 66 insertions(+), 33 deletions(-) (limited to 'src/test') diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index 0e9abaf1cf9..905d8688ea1 100644 --- a/src/librustc_typeck/check/compare_method.rs +++ b/src/librustc_typeck/check/compare_method.rs @@ -362,7 +362,7 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, &infcx.parameter_environment.caller_bounds); infcx.resolve_regions_and_report_errors(&free_regions, impl_m_body_id); } else { - let fcx = FnCtxt::new(&inh, Some(tcx.types.err), impl_m_body_id); + let fcx = FnCtxt::new(&inh, impl_m_body_id); fcx.regionck_item(impl_m_body_id, impl_m_span, &[]); } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 69f1466c475..619f4fb10c5 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -448,7 +448,7 @@ pub struct FnCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { // expects the types within the function to be consistent. err_count_on_creation: usize, - ret_ty: Option>, + ret_coercion: Option>>, ps: RefCell, @@ -679,7 +679,7 @@ fn typeck_tables<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, check_fn(&inh, fn_sig, decl, id, body) } else { - let fcx = FnCtxt::new(&inh, None, body.value.id); + let fcx = FnCtxt::new(&inh, body.value.id); let expected_type = tcx.item_type(def_id); let expected_type = fcx.normalize_associated_types_in(body.value.span, &expected_type); fcx.require_type_is_sized(expected_type, body.value.span, traits::ConstSized); @@ -800,15 +800,16 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>, // Create the function context. This is either derived from scratch or, // in the case of function expressions, based on the outer context. - let mut fcx = FnCtxt::new(inherited, None, body.value.id); - let ret_ty = fn_sig.output(); + let mut fcx = FnCtxt::new(inherited, body.value.id); *fcx.ps.borrow_mut() = UnsafetyState::function(fn_sig.unsafety, fn_id); + let ret_ty = fn_sig.output(); fcx.require_type_is_sized(ret_ty, decl.output.span(), traits::ReturnType); - fcx.ret_ty = fcx.instantiate_anon_types(&Some(ret_ty)); + let ret_ty = fcx.instantiate_anon_types(&ret_ty); + fcx.ret_coercion = Some(RefCell::new(CoerceMany::new(ret_ty))); fn_sig = fcx.tcx.mk_fn_sig( fn_sig.inputs().iter().cloned(), - fcx.ret_ty.unwrap(), + ret_ty, fn_sig.variadic, fn_sig.unsafety, fn_sig.abi @@ -833,7 +834,38 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>, inherited.tables.borrow_mut().liberated_fn_sigs.insert(fn_id, fn_sig); - fcx.check_expr_coercable_to_type(&body.value, fcx.ret_ty.unwrap()); + fcx.check_return_expr(&body.value); + + // Finalize the return check by taking the LUB of the return types + // we saw and assigning it to the expected return type. This isn't + // really expected to fail, since the coercions would have failed + // earlier when trying to find a LUB. + // + // However, the behavior around `!` is sort of complex. In the + // event that the `actual_return_ty` comes back as `!`, that + // indicates that the fn either does not return or "returns" only + // values of type `!`. In this case, if there is an expected + // return type that is *not* `!`, that should be ok. But if the + // return type is being inferred, we want to "fallback" to `!`: + // + // let x = move || panic!(); + // + // To allow for that, I am creating a type variable with diverging + // fallback. This was deemed ever so slightly better than unifying + // the return value with `!` because it allows for the caller to + // make more assumptions about the return type (e.g., they could do + // + // let y: Option = Some(x()); + // + // which would then cause this return type to become `u32`, not + // `!`). + let coercion = fcx.ret_coercion.take().unwrap().into_inner(); + let mut actual_return_ty = coercion.complete(&fcx); + if actual_return_ty.is_never() { + actual_return_ty = fcx.next_diverging_ty_var( + TypeVariableOrigin::DivergingFn(body.value.span)); + } + fcx.demand_suptype(body.value.span, ret_ty, actual_return_ty); fcx } @@ -1429,14 +1461,13 @@ enum TupleArgumentsFlag { impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { pub fn new(inh: &'a Inherited<'a, 'gcx, 'tcx>, - rty: Option>, body_id: ast::NodeId) -> FnCtxt<'a, 'gcx, 'tcx> { FnCtxt { ast_ty_to_ty_cache: RefCell::new(NodeMap()), body_id: body_id, err_count_on_creation: inh.tcx.sess.err_count(), - ret_ty: rty, + ret_coercion: None, ps: RefCell::new(UnsafetyState::function(hir::Unsafety::Normal, ast::CRATE_NODE_ID)), diverges: Cell::new(Diverges::Maybe), @@ -2738,6 +2769,23 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { ret_ty } + fn check_return_expr(&self, return_expr: &'gcx hir::Expr) { + let ret_coercion = + self.ret_coercion + .as_ref() + .unwrap_or_else(|| span_bug!(return_expr.span, + "check_return_expr called outside fn body")); + + let ret_ty = ret_coercion.borrow().expected_ty(); + let return_expr_ty = self.check_expr_with_hint(return_expr, ret_ty); + ret_coercion.borrow_mut() + .coerce(self, + &self.misc(return_expr.span), + return_expr, + return_expr_ty); + } + + // A generic function for checking the then and else in an if // or if-else. fn check_then_else(&self, @@ -3522,24 +3570,15 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } hir::ExprAgain(_) => { tcx.types.never } hir::ExprRet(ref expr_opt) => { - if self.ret_ty.is_none() { + if self.ret_coercion.is_none() { struct_span_err!(self.tcx.sess, expr.span, E0572, "return statement outside of function body").emit(); } else if let Some(ref e) = *expr_opt { - self.check_expr_coercable_to_type(&e, self.ret_ty.unwrap()); + self.check_return_expr(e); } else { - match self.eq_types(false, - &self.misc(expr.span), - self.ret_ty.unwrap(), - tcx.mk_nil()) { - Ok(ok) => self.register_infer_ok_obligations(ok), - Err(_) => { - struct_span_err!(tcx.sess, expr.span, E0069, - "`return;` in a function whose return type is not `()`") - .span_label(expr.span, &format!("return type is not ()")) - .emit(); - } - } + let mut coercion = self.ret_coercion.as_ref().unwrap().borrow_mut(); + let cause = self.cause(expr.span, ObligationCauseCode::ReturnNoExpression); + coercion.coerce_forced_unit(self, &cause); } tcx.types.never } diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index a4cb4071b4d..85c87adf9be 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -50,7 +50,7 @@ impl<'a, 'gcx, 'tcx> CheckWfFcxBuilder<'a, 'gcx, 'tcx> { let id = self.id; let span = self.span; self.inherited.enter(|inh| { - let fcx = FnCtxt::new(&inh, None, id); + let fcx = FnCtxt::new(&inh, id); let wf_tys = f(&fcx, &mut CheckTypeWellFormedVisitor { tcx: fcx.tcx.global_tcx(), code: code diff --git a/src/test/compile-fail/regions-bounds.rs b/src/test/compile-fail/regions-bounds.rs index 64dbf27b78e..810a8671c53 100644 --- a/src/test/compile-fail/regions-bounds.rs +++ b/src/test/compile-fail/regions-bounds.rs @@ -16,17 +16,11 @@ struct an_enum<'a>(&'a isize); struct a_class<'a> { x:&'a isize } fn a_fn1<'a,'b>(e: an_enum<'a>) -> an_enum<'b> { - return e; //~ ERROR mismatched types - //~| expected type `an_enum<'b>` - //~| found type `an_enum<'a>` - //~| lifetime mismatch + return e; //~^ ERROR mismatched types } fn a_fn3<'a,'b>(e: a_class<'a>) -> a_class<'b> { - return e; //~ ERROR mismatched types - //~| expected type `a_class<'b>` - //~| found type `a_class<'a>` - //~| lifetime mismatch + return e; //~^ ERROR mismatched types } fn main() { } -- cgit 1.4.1-3-g733a5 From 1ae620bbebadbe4362a28b37bcecd41cfed66cea Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 17 Mar 2017 11:48:18 -0400 Subject: do not eagerly convert `!` to a diverging variable Instead, wait until coercion time. This has some small effects on a few tests (one less temporary, generally better errors when trying to call methods or otherwise "force" the type). --- src/librustc_typeck/check/coercion.rs | 26 +++++++++--- src/librustc_typeck/check/mod.rs | 79 ++++++++++++++++++++--------------- src/test/compile-fail/index-bot.rs | 2 +- src/test/compile-fail/issue-13847.rs | 2 +- src/test/compile-fail/issue-15207.rs | 2 +- src/test/compile-fail/issue-15965.rs | 2 +- src/test/compile-fail/issue-17373.rs | 2 +- src/test/compile-fail/issue-18532.rs | 3 +- 8 files changed, 71 insertions(+), 47 deletions(-) (limited to 'src/test') diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index 40ae169a94e..a08faf2610e 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -169,7 +169,23 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { } if a.is_never() { - return success(Adjust::NeverToAny, b, vec![]); + // Subtle: If we are coercing from `!` to `?T`, where `?T` is an unbound + // type variable, we want `?T` to fallback to `!` if not + // otherwise constrained. An example where this arises: + // + // let _: Option = Some({ return; }); + // + // here, we would coerce from `!` to `?T`. + let b = self.shallow_resolve(b); + return if self.shallow_resolve(b).is_ty_var() { + // micro-optimization: no need for this if `b` is + // already resolved in some way. + let diverging_ty = self.next_diverging_ty_var( + TypeVariableOrigin::AdjustmentType(self.cause.span)); + self.unify_and(&b, &diverging_ty, Adjust::NeverToAny) + } else { + success(Adjust::NeverToAny, b, vec![]) + }; } // Consider coercing the subtype to a DST @@ -687,11 +703,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let adjustment = self.register_infer_ok_obligations(ok); if !adjustment.is_identity() { debug!("Success, coerced with {:?}", adjustment); - match self.tables.borrow().adjustments.get(&expr.id) { - None | - Some(&Adjustment { kind: Adjust::NeverToAny, .. }) => (), - _ => bug!("expr already has an adjustment on it!"), - }; + if self.tables.borrow().adjustments.get(&expr.id).is_some() { + bug!("expr already has an adjustment on it!"); + } self.write_adjustment(expr.id, adjustment); } Ok(adjustment.target) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index e186daf9f40..ae0ed81ac77 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -2664,7 +2664,22 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { pub fn check_expr_has_type(&self, expr: &'gcx hir::Expr, expected: Ty<'tcx>) -> Ty<'tcx> { - let ty = self.check_expr_with_hint(expr, expected); + let mut ty = self.check_expr_with_hint(expr, expected); + + // While we don't allow *arbitrary* coercions here, we *do* allow + // coercions from ! to `expected`. + if ty.is_never() { + assert!(!self.tables.borrow().adjustments.contains_key(&expr.id), + "expression with never type wound up being adjusted"); + let adj_ty = self.next_diverging_ty_var( + TypeVariableOrigin::AdjustmentType(expr.span)); + self.write_adjustment(expr.id, adjustment::Adjustment { + kind: adjustment::Adjust::NeverToAny, + target: adj_ty + }); + ty = adj_ty; + } + self.demand_suptype(expr.span, expected, ty); ty } @@ -3370,18 +3385,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { debug!("type of {} is...", self.tcx.hir.node_to_string(expr.id)); debug!("... {:?}, expected is {:?}", ty, expected); - // Add adjustments to !-expressions - if ty.is_never() { - if let Some(hir::map::NodeExpr(node_expr)) = self.tcx.hir.find(expr.id) { - let adj_ty = self.next_diverging_ty_var( - TypeVariableOrigin::AdjustmentType(node_expr.span)); - self.write_adjustment(expr.id, adjustment::Adjustment { - kind: adjustment::Adjust::NeverToAny, - target: adj_ty - }); - return adj_ty; - } - } ty } @@ -4072,7 +4075,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { pub fn check_block_no_value(&self, blk: &'gcx hir::Block) { let unit = self.tcx.mk_nil(); let ty = self.check_block_with_expected(blk, ExpectHasType(unit)); - self.demand_suptype(blk.span, unit, ty); + + // if the block produces a `!` value, that can always be + // (effectively) coerced to unit. + if !ty.is_never() { + self.demand_suptype(blk.span, unit, ty); + } } fn check_block_with_expected(&self, @@ -4111,7 +4119,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }, None => { e_ty = if self.diverges.get().always() { - self.next_diverging_ty_var(TypeVariableOrigin::DivergingBlockExpr(blk.span)) + self.tcx.types.never } else { self.tcx.mk_nil() }; @@ -4135,6 +4143,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { Err(err) => self.report_mismatched_types(&cause, ctxt.unified, e_ty, err).emit(), } + } else if self.diverges.get().always() { + // No tail expression and the body diverges; ignore + // the expected type, and keep `!` as the type of the + // block. } else { self.check_block_no_expr(blk, self.tcx.mk_nil(), e_ty); }; @@ -4147,33 +4159,32 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let mut ty = match blk.expr { Some(ref e) => self.check_expr_with_expectation(e, expected), - None => self.tcx.mk_nil() + None => if self.diverges.get().always() { + self.tcx.types.never + } else { + self.tcx.mk_nil() + }, }; - if self.diverges.get().always() { - if let ExpectHasType(ety) = expected { - // Avoid forcing a type (only `!` for now) in unreachable code. - // FIXME(aburka) do we need this special case? and should it be is_uninhabited? - if !ety.is_never() { - if let Some(ref e) = blk.expr { - // Coerce the tail expression to the right type. - self.demand_coerce(e, ty, ety); - } - } - } - - ty = self.next_diverging_ty_var(TypeVariableOrigin::DivergingBlockExpr(blk.span)); - } else if let ExpectHasType(ety) = expected { + if let ExpectHasType(ety) = expected { if let Some(ref e) = blk.expr { // Coerce the tail expression to the right type. self.demand_coerce(e, ty, ety); + + // We already applied the type (and potentially errored), + // use the expected type to avoid further errors out. + ty = ety; + } else if self.diverges.get().always() { + // No tail expression and the body diverges; ignore + // the expected type, and keep `!` as the type of the + // block. } else { self.check_block_no_expr(blk, ty, ety); - } - // We already applied the type (and potentially errored), - // use the expected type to avoid further errors out. - ty = ety; + // We already applied the type (and potentially errored), + // use the expected type to avoid further errors out. + ty = ety; + } } ty }; diff --git a/src/test/compile-fail/index-bot.rs b/src/test/compile-fail/index-bot.rs index 70c362303ae..05b04723300 100644 --- a/src/test/compile-fail/index-bot.rs +++ b/src/test/compile-fail/index-bot.rs @@ -9,5 +9,5 @@ // except according to those terms. fn main() { - (return)[0]; //~ ERROR the type of this value must be known in this context + (return)[0]; //~ ERROR cannot index a value of type `!` } diff --git a/src/test/compile-fail/issue-13847.rs b/src/test/compile-fail/issue-13847.rs index aa823d9a70e..0314f109a7c 100644 --- a/src/test/compile-fail/issue-13847.rs +++ b/src/test/compile-fail/issue-13847.rs @@ -9,5 +9,5 @@ // except according to those terms. fn main() { - return.is_failure //~ ERROR the type of this value must be known in this context + return.is_failure //~ ERROR no field `is_failure` on type `!` } diff --git a/src/test/compile-fail/issue-15207.rs b/src/test/compile-fail/issue-15207.rs index 61877775269..70da8cf4169 100644 --- a/src/test/compile-fail/issue-15207.rs +++ b/src/test/compile-fail/issue-15207.rs @@ -10,7 +10,7 @@ fn main() { loop { - break.push(1) //~ ERROR the type of this value must be known in this context + break.push(1) //~ ERROR no method named `push` found for type `!` ; } } diff --git a/src/test/compile-fail/issue-15965.rs b/src/test/compile-fail/issue-15965.rs index 08b896f387b..d5d597c190e 100644 --- a/src/test/compile-fail/issue-15965.rs +++ b/src/test/compile-fail/issue-15965.rs @@ -11,7 +11,7 @@ fn main() { return { return () } -//~^ ERROR the type of this value must be known in this context +//~^ ERROR expected function, found `!` () ; } diff --git a/src/test/compile-fail/issue-17373.rs b/src/test/compile-fail/issue-17373.rs index 6895893adc4..f6e6a8a0852 100644 --- a/src/test/compile-fail/issue-17373.rs +++ b/src/test/compile-fail/issue-17373.rs @@ -9,6 +9,6 @@ // except according to those terms. fn main() { - *return //~ ERROR the type of this value must be known in this context + *return //~ ERROR type `!` cannot be dereferenced ; } diff --git a/src/test/compile-fail/issue-18532.rs b/src/test/compile-fail/issue-18532.rs index 94eab97c42a..2be5fdcac4e 100644 --- a/src/test/compile-fail/issue-18532.rs +++ b/src/test/compile-fail/issue-18532.rs @@ -13,6 +13,5 @@ // into it. fn main() { - (return)((),()); - //~^ ERROR the type of this value must be known + (return)((),()); //~ ERROR expected function, found `!` } -- cgit 1.4.1-3-g733a5 From 16a71cce514f29cb8c532248cf749e26972afb01 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 17 Mar 2017 11:49:53 -0400 Subject: rework how we handle the type of loops First, we keep a `CoerceMany` now to find the LUB of all the break expressions. Second, this `CoerceMany` is actually an `Option`, and we store `None` for loops where "break with an expression" is disallowed. This avoids silly duplicate errors about a type mismatch, since the loops pass already reports an error that the break cannot have an expression. Finally, since we now detect an invalid break target during HIR lowering, refactor `find_loop` to be infallible. Adjust tests as needed: - some spans from breaks are slightly different - break up a single loop into multiple since `CoerceMany` silences redundant and derived errors - add a ui test that we only give on error for loop-break-value --- src/librustc_typeck/check/mod.rs | 207 ++++++++++++++------------ src/test/compile-fail/issue-27042.rs | 8 +- src/test/compile-fail/loop-break-value.rs | 23 +-- src/test/ui/loop-break-value-no-repeat.rs | 25 ++++ src/test/ui/loop-break-value-no-repeat.stderr | 8 + 5 files changed, 161 insertions(+), 110 deletions(-) create mode 100644 src/test/ui/loop-break-value-no-repeat.rs create mode 100644 src/test/ui/loop-break-value-no-repeat.stderr (limited to 'src/test') diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index ae0ed81ac77..59f3ac739e0 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -415,15 +415,16 @@ impl Diverges { } #[derive(Clone)] -pub struct BreakableCtxt<'gcx, 'tcx> { - unified: Ty<'tcx>, - coerce_to: Ty<'tcx>, - break_exprs: Vec<&'gcx hir::Expr>, +pub struct BreakableCtxt<'gcx: 'tcx, 'tcx> { may_break: bool, + + // this is `null` for loops where break with a value is illegal, + // such as `while`, `for`, and `while let` + coerce: Option>, } #[derive(Clone)] -pub struct EnclosingBreakables<'gcx, 'tcx> { +pub struct EnclosingBreakables<'gcx: 'tcx, 'tcx> { stack: Vec>, by_id: NodeMap, } @@ -3547,60 +3548,66 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { tcx.mk_nil() } hir::ExprBreak(destination, ref expr_opt) => { - if let Some(target_id) = destination.target_id.opt_id() { - let coerce_to = { - let mut enclosing_breakables = self.enclosing_breakables.borrow_mut(); - enclosing_breakables.find_breakable(target_id).coerce_to - }; - - let e_ty; - let cause; - if let Some(ref e) = *expr_opt { - // Recurse without `enclosing_loops` borrowed. - e_ty = self.check_expr_with_hint(e, coerce_to); - cause = self.misc(e.span); - // Notably, the recursive call may alter coerce_to - must not keep using it! - } else { - // `break` without argument acts like `break ()`. - e_ty = tcx.mk_nil(); - cause = self.misc(expr.span); - } - - let mut enclosing_breakables = self.enclosing_breakables.borrow_mut(); - let ctxt = enclosing_breakables.find_breakable(target_id); + if let Some(target_id) = destination.target_id.opt_id() { + let (e_ty, cause); + if let Some(ref e) = *expr_opt { + // If this is a break with a value, we need to type-check + // the expression. Get an expected type from the loop context. + let opt_coerce_to = { + let mut enclosing_breakables = self.enclosing_breakables.borrow_mut(); + enclosing_breakables.find_breakable(target_id) + .coerce + .as_ref() + .map(|coerce| coerce.expected_ty()) + }; + + // If the loop context is not a `loop { }`, then break with + // a value is illegal, and `opt_coerce_to` will be `None`. + // Just set expectation to error in that case. + let coerce_to = opt_coerce_to.unwrap_or(tcx.types.err); + + // Recurse without `enclosing_breakables` borrowed. + e_ty = self.check_expr_with_hint(e, coerce_to); + cause = self.misc(e.span); + } else { + // Otherwise, this is a break *without* a value. That's + // always legal, and is equivalent to `break ()`. + e_ty = tcx.mk_nil(); + cause = self.misc(expr.span); + } - let result = if let Some(ref e) = *expr_opt { - // Special-case the first element, as it has no "previous expressions". - let result = if !ctxt.may_break { - self.try_coerce(e, e_ty, ctxt.coerce_to) - } else { - self.try_find_coercion_lub(&cause, || ctxt.break_exprs.iter().cloned(), - ctxt.unified, e, e_ty) - }; + // Now that we have type-checked `expr_opt`, borrow + // the `enclosing_loops` field and let's coerce the + // type of `expr_opt` into what is expected. + let mut enclosing_breakables = self.enclosing_breakables.borrow_mut(); + let ctxt = enclosing_breakables.find_breakable(target_id); + if let Some(ref mut coerce) = ctxt.coerce { + if let Some(ref e) = *expr_opt { + coerce.coerce(self, &cause, e, e_ty); + } else { + assert!(e_ty.is_nil()); + coerce.coerce_forced_unit(self, &cause); + } + } else { + // If `ctxt.coerce` is `None`, we can just ignore + // the type of the expresison. This is because + // either this was a break *without* a value, in + // which case it is always a legal type (`()`), or + // else an error would have been flagged by the + // `loops` pass for using break with an expression + // where you are not supposed to. + assert!(expr_opt.is_none() || self.tcx.sess.err_count() > 0); + } - ctxt.break_exprs.push(e); - result - } else { - self.eq_types(true, &cause, e_ty, ctxt.unified) - .map(|InferOk { obligations, .. }| { - // FIXME(#32730) propagate obligations - assert!(obligations.is_empty()); - e_ty - }) - }; - match result { - Ok(ty) => ctxt.unified = ty, - Err(err) => { - self.report_mismatched_types(&cause, ctxt.unified, e_ty, err).emit(); - } - } + ctxt.may_break = true; + } else { + // Otherwise, we failed to find the enclosing loop; this can only happen if the + // `break` was not inside a loop at all, which is caught by the loop-checking pass. + assert!(self.tcx.sess.err_count() > 0); + } - ctxt.may_break = true; - } - // Otherwise, we failed to find the enclosing breakable; this can only happen if the - // `break` target was not found, which is caught in HIR lowering and reported by the - // loop-checking pass. - tcx.types.never + // the type of a `break` is always `!`, since it diverges + tcx.types.never } hir::ExprAgain(_) => { tcx.types.never } hir::ExprRet(ref expr_opt) => { @@ -3645,51 +3652,59 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { expr.span, expected) } hir::ExprWhile(ref cond, ref body, _) => { - let unified = self.tcx.mk_nil(); - let coerce_to = unified; - let ctxt = BreakableCtxt { - unified: unified, - coerce_to: coerce_to, - break_exprs: vec![], - may_break: true, - }; - self.with_breakable_ctxt(expr.id, ctxt, || { - self.check_expr_has_type(&cond, tcx.types.bool); - let cond_diverging = self.diverges.get(); - self.check_block_no_value(&body); + let ctxt = BreakableCtxt { + // cannot use break with a value from a while loop + coerce: None, + may_break: true, + }; - // We may never reach the body so it diverging means nothing. - self.diverges.set(cond_diverging); - }); + self.with_breakable_ctxt(expr.id, ctxt, || { + self.check_expr_has_type(&cond, tcx.types.bool); + let cond_diverging = self.diverges.get(); + self.check_block_no_value(&body); - if self.has_errors.get() { - tcx.types.err - } else { - tcx.mk_nil() - } + // We may never reach the body so it diverging means nothing. + self.diverges.set(cond_diverging); + }); + + self.tcx.mk_nil() } - hir::ExprLoop(ref body, _, _) => { - let unified = self.next_ty_var(TypeVariableOrigin::TypeInference(body.span)); - let coerce_to = expected.only_has_type(self).unwrap_or(unified); - let ctxt = BreakableCtxt { - unified: unified, - coerce_to: coerce_to, - break_exprs: vec![], - may_break: false, - }; + hir::ExprLoop(ref body, _, source) => { + let coerce = match source { + // you can only use break with a value from a normal `loop { }` + hir::LoopSource::Loop => { + let coerce_to = expected.only_has_type_or_fresh_var(self, body.span); + Some(CoerceMany::new(coerce_to)) + } - let (ctxt, ()) = self.with_breakable_ctxt(expr.id, ctxt, || { - self.check_block_no_value(&body); - }); - if ctxt.may_break { - // No way to know whether it's diverging because - // of a `break` or an outer `break` or `return. - self.diverges.set(Diverges::Maybe); + hir::LoopSource::WhileLet | + hir::LoopSource::ForLoop => { + None + } + }; - ctxt.unified - } else { - tcx.types.never - } + let ctxt = BreakableCtxt { + coerce: coerce, + may_break: false, // will get updated if/when we find a `break` + }; + + let (ctxt, ()) = self.with_breakable_ctxt(expr.id, ctxt, || { + self.check_block_no_value(&body); + }); + + if ctxt.may_break { + // No way to know whether it's diverging because + // of a `break` or an outer `break` or `return. + self.diverges.set(Diverges::Maybe); + } + + // If we permit break with a value, then result type is + // the LUB of the breaks (possibly ! if none); else, it + // is nil. This makes sense because infinite loops + // (which would have type !) are only possible iff we + // permit break with a value [1]. + assert!(ctxt.coerce.is_some() || ctxt.may_break); // [1] + ctxt.coerce.map(|c| c.complete(self)).unwrap_or(self.tcx.mk_nil()) } hir::ExprMatch(ref discrim, ref arms, match_src) => { self.check_match(expr, &discrim, arms, expected, match_src) diff --git a/src/test/compile-fail/issue-27042.rs b/src/test/compile-fail/issue-27042.rs index f31389f1337..23afa4b6296 100644 --- a/src/test/compile-fail/issue-27042.rs +++ b/src/test/compile-fail/issue-27042.rs @@ -12,14 +12,14 @@ fn main() { let _: i32 = - 'a: //~ ERROR mismatched types - loop { break }; + 'a: // in this case, the citation is just the `break`: + loop { break }; //~ ERROR mismatched types let _: i32 = 'b: //~ ERROR mismatched types - while true { break }; + while true { break }; // but here we cite the whole loop let _: i32 = 'c: //~ ERROR mismatched types - for _ in None { break }; + for _ in None { break }; // but here we cite the whole loop let _: i32 = 'd: //~ ERROR mismatched types while let Some(_) = None { break }; diff --git a/src/test/compile-fail/loop-break-value.rs b/src/test/compile-fail/loop-break-value.rs index d4f29597486..a4143218992 100644 --- a/src/test/compile-fail/loop-break-value.rs +++ b/src/test/compile-fail/loop-break-value.rs @@ -40,37 +40,40 @@ fn main() { loop { break 'while_loop 123; //~^ ERROR `break` with value from a `while` loop - //~| ERROR mismatched types break 456; break 789; }; } - 'while_let_loop: while let Some(_) = Some(()) { + while let Some(_) = Some(()) { if break () { //~ ERROR `break` with value from a `while let` loop - break; - break None; - //~^ ERROR `break` with value from a `while let` loop - //~| ERROR mismatched types } + } + + while let Some(_) = Some(()) { + break None; + //~^ ERROR `break` with value from a `while let` loop + } + + 'while_let_loop: while let Some(_) = Some(()) { loop { break 'while_let_loop "nope"; //~^ ERROR `break` with value from a `while let` loop - //~| ERROR mismatched types break 33; }; } - 'for_loop: for _ in &[1,2,3] { + for _ in &[1,2,3] { break (); //~ ERROR `break` with value from a `for` loop break [()]; //~^ ERROR `break` with value from a `for` loop - //~| ERROR mismatched types + } + + 'for_loop: for _ in &[1,2,3] { loop { break Some(3); break 'for_loop Some(17); //~^ ERROR `break` with value from a `for` loop - //~| ERROR mismatched types }; } diff --git a/src/test/ui/loop-break-value-no-repeat.rs b/src/test/ui/loop-break-value-no-repeat.rs new file mode 100644 index 00000000000..790f796fae0 --- /dev/null +++ b/src/test/ui/loop-break-value-no-repeat.rs @@ -0,0 +1,25 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(loop_break_value)] +#![allow(unused_variables)] + +use std::ptr; + +// Test that we only report **one** error here and that is that +// `break` with an expression is illegal in this context. In +// particular, we don't report any mismatched types error, which is +// besides the point. + +fn main() { + for _ in &[1,2,3] { + break 22 + } +} diff --git a/src/test/ui/loop-break-value-no-repeat.stderr b/src/test/ui/loop-break-value-no-repeat.stderr new file mode 100644 index 00000000000..0d99abd3907 --- /dev/null +++ b/src/test/ui/loop-break-value-no-repeat.stderr @@ -0,0 +1,8 @@ +error[E0571]: `break` with value from a `for` loop + --> $DIR/loop-break-value-no-repeat.rs:23:9 + | +23 | break 22 + | ^^^^^^^^ can only break with a value inside `loop` + +error: aborting due to previous error + -- cgit 1.4.1-3-g733a5 From 5cd99aa1677075baecbd5224861b36a7719e0f25 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 17 Mar 2017 14:10:00 -0400 Subject: more detailed tests around diverging type variables --- src/test/compile-fail/defaulted-unit-warning.rs | 12 +-- src/test/compile-fail/never-fallback.rs | 41 -------- .../run-pass/diverging-fallback-control-flow.rs | 106 +++++++++++++++++++++ .../run-pass/diverging-fallback-method-chain.rs | 27 ++++++ src/test/run-pass/diverging-fallback-option.rs | 22 +++++ src/test/run-pass/unit-fallback.rs | 38 -------- 6 files changed, 156 insertions(+), 90 deletions(-) delete mode 100644 src/test/compile-fail/never-fallback.rs create mode 100644 src/test/run-pass/diverging-fallback-control-flow.rs create mode 100644 src/test/run-pass/diverging-fallback-method-chain.rs create mode 100644 src/test/run-pass/diverging-fallback-option.rs delete mode 100644 src/test/run-pass/unit-fallback.rs (limited to 'src/test') diff --git a/src/test/compile-fail/defaulted-unit-warning.rs b/src/test/compile-fail/defaulted-unit-warning.rs index 5213a189714..ed6263d0fdb 100644 --- a/src/test/compile-fail/defaulted-unit-warning.rs +++ b/src/test/compile-fail/defaulted-unit-warning.rs @@ -22,16 +22,6 @@ impl Deserialize for () { } } -fn doit() -> Result<(), String> { - let _ = match Deserialize::deserialize() { - //~^ ERROR code relies on type - //~| WARNING previously accepted - Ok(x) => x, - Err(e) => return Err(e), - }; - Ok(()) -} - trait ImplementedForUnitButNotNever {} impl ImplementedForUnitButNotNever for () {} @@ -46,6 +36,6 @@ fn smeg() { } fn main() { - let _ = doit(); + smeg(); } diff --git a/src/test/compile-fail/never-fallback.rs b/src/test/compile-fail/never-fallback.rs deleted file mode 100644 index a43b1a45fe9..00000000000 --- a/src/test/compile-fail/never-fallback.rs +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright 2015 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 diverging types default to ! when feature(never_type) is enabled. This test is the -// same as run-pass/unit-fallback.rs except that ! is enabled. - -#![feature(never_type)] - -trait Balls: Sized { - fn smeg() -> Result; -} - -impl Balls for () { - fn smeg() -> Result<(), ()> { Ok(()) } -} - -struct Flah; - -impl Flah { - fn flah(&self) -> Result { - T::smeg() - } -} - -fn doit() -> Result<(), ()> { - // The type of _ is unconstrained here and should default to ! - let _ = try!(Flah.flah()); //~ ERROR the trait bound - Ok(()) -} - -fn main() { - let _ = doit(); -} - diff --git a/src/test/run-pass/diverging-fallback-control-flow.rs b/src/test/run-pass/diverging-fallback-control-flow.rs new file mode 100644 index 00000000000..656e90d2d52 --- /dev/null +++ b/src/test/run-pass/diverging-fallback-control-flow.rs @@ -0,0 +1,106 @@ +// Copyright 2015 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 various cases where we permit an unconstrained variable +// to fallback based on control-flow. +// +// These represent current behavior, but are pretty dubious. I would +// like to revisit these and potentially change them. --nmatsakis + +#![feature(never_type)] +#![feature(loop_break_value)] + +trait BadDefault { + fn default() -> Self; +} + +impl BadDefault for u32 { + fn default() -> Self { + 0 + } +} + +impl BadDefault for ! { + fn default() -> ! { + panic!() + } +} + +fn assignment() { + let x; + + if true { + x = BadDefault::default(); + } else { + x = return; + } +} + +fn assignment_rev() { + let x; + + if true { + x = return; + } else { + x = BadDefault::default(); + } +} + +fn if_then_else() { + let _x = if true { + BadDefault::default() + } else { + return; + }; +} + +fn if_then_else_rev() { + let _x = if true { + return; + } else { + BadDefault::default() + }; +} + +fn match_arm() { + let _x = match Ok(BadDefault::default()) { + Ok(v) => v, + Err(()) => return, + }; +} + +fn match_arm_rev() { + let _x = match Ok(BadDefault::default()) { + Err(()) => return, + Ok(v) => v, + }; +} + +fn loop_break() { + let _x = loop { + if false { + break return; + } else { + break BadDefault::default(); + } + }; +} + +fn loop_break_rev() { + let _x = loop { + if false { + break return; + } else { + break BadDefault::default(); + } + }; +} + +fn main() { } diff --git a/src/test/run-pass/diverging-fallback-method-chain.rs b/src/test/run-pass/diverging-fallback-method-chain.rs new file mode 100644 index 00000000000..664a329c228 --- /dev/null +++ b/src/test/run-pass/diverging-fallback-method-chain.rs @@ -0,0 +1,27 @@ +// Copyright 2015 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 a regression found when building compiler. The `produce()` +// error type `T` winds up getting unified with result of `x.parse()`; +// the type of the closure given to `unwrap_or_else` needs to be +// inferred to `usize`. + +use std::num::ParseIntError; + +fn produce() -> Result<&'static str, T> { + Ok("22") +} + +fn main() { + let x: usize = produce() + .and_then(|x| x.parse()) + .unwrap_or_else(|_| panic!()); + println!("{}", x); +} diff --git a/src/test/run-pass/diverging-fallback-option.rs b/src/test/run-pass/diverging-fallback-option.rs new file mode 100644 index 00000000000..49f90e7c91f --- /dev/null +++ b/src/test/run-pass/diverging-fallback-option.rs @@ -0,0 +1,22 @@ +// Copyright 2012 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. + +#![allow(warnings)] + +// Here the type of `c` is `Option`, where `?T` is unconstrained. +// Because there is data-flow from the `{ return; }` block, which +// diverges and hence has type `!`, into `c`, we will default `?T` to +// `!`, and hence this code compiles rather than failing and requiring +// a type annotation. + +fn main() { + let c = Some({ return; }); + c.unwrap(); +} diff --git a/src/test/run-pass/unit-fallback.rs b/src/test/run-pass/unit-fallback.rs deleted file mode 100644 index 2babc6348e1..00000000000 --- a/src/test/run-pass/unit-fallback.rs +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2015 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 diverging types default to () (with feature(never_type) disabled). - -trait Balls: Sized { - fn smeg() -> Result; -} - -impl Balls for () { - fn smeg() -> Result<(), ()> { Ok(()) } -} - -struct Flah; - -impl Flah { - fn flah(&self) -> Result { - T::smeg() - } -} - -fn doit() -> Result<(), ()> { - // The type of _ is unconstrained here and should default to () - let _ = try!(Flah.flah()); - Ok(()) -} - -fn main() { - let _ = doit(); -} - -- cgit 1.4.1-3-g733a5 From 2f526cc89773d3b14c3d909152697678bc8fa7a1 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 17 Mar 2017 11:54:23 -0400 Subject: we now get an extra unreachable code warning in this test --- src/test/compile-fail/never-assign-dead-code.rs | 1 + 1 file changed, 1 insertion(+) (limited to 'src/test') diff --git a/src/test/compile-fail/never-assign-dead-code.rs b/src/test/compile-fail/never-assign-dead-code.rs index 57e0bca6a6d..d8752e1c050 100644 --- a/src/test/compile-fail/never-assign-dead-code.rs +++ b/src/test/compile-fail/never-assign-dead-code.rs @@ -16,5 +16,6 @@ fn main() { let x: ! = panic!("aah"); //~ ERROR unused drop(x); //~ ERROR unreachable + //~^ ERROR unreachable } -- cgit 1.4.1-3-g733a5 From f11b7d33bb71a78beb6a4671d53d2e89a2afc0ef Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sat, 18 Mar 2017 15:22:48 -0400 Subject: add regression test for #39808 Fixes #39808 --- src/test/run-pass/issue-39808.rs | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'src/test') diff --git a/src/test/run-pass/issue-39808.rs b/src/test/run-pass/issue-39808.rs index f83e9328e58..00c2bdc8cc9 100644 --- a/src/test/run-pass/issue-39808.rs +++ b/src/test/run-pass/issue-39808.rs @@ -8,14 +8,19 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// Regression test: even though `Ok` is dead-code, its type needs to -// be influenced by the result of `Err` or else we get a "type -// variable unconstrained" error. +#![allow(unreachable_code)] + +// Regression test for #39808. The type parameter of `Owned` was +// considered to be "unconstrained" because the type resulting from +// `format!` (`String`) was not being propagated upward, owing to the +// fact that the expression diverges. + +use std::borrow::Cow; fn main() { let _ = if false { - Ok(return) + Cow::Owned(format!("{:?}", panic!())) /* as Cow */ // uncomment to fix } else { - Err("") + Cow::Borrowed("") }; } -- cgit 1.4.1-3-g733a5 From 609bfe82fd1c1207ab59f6c08bbadf45e587bd4a Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 21 Mar 2017 09:41:41 -0400 Subject: cherry-pick over the tests I wrote for the reachability code For the most part, the current code performs similarly, although it differs in some particulars. I'll be nice to have these tests for judging future changes, as well. --- src/test/ui/reachable/README.md | 7 +++++ src/test/ui/reachable/expr_add.rs | 28 +++++++++++++++++ src/test/ui/reachable/expr_add.stderr | 14 +++++++++ src/test/ui/reachable/expr_again.rs | 20 ++++++++++++ src/test/ui/reachable/expr_again.stderr | 15 +++++++++ src/test/ui/reachable/expr_andand.rs | 21 +++++++++++++ src/test/ui/reachable/expr_andand.stderr | 0 src/test/ui/reachable/expr_array.rs | 28 +++++++++++++++++ src/test/ui/reachable/expr_array.stderr | 20 ++++++++++++ src/test/ui/reachable/expr_assign.rs | 39 +++++++++++++++++++++++ src/test/ui/reachable/expr_assign.stderr | 26 +++++++++++++++ src/test/ui/reachable/expr_block.rs | 41 ++++++++++++++++++++++++ src/test/ui/reachable/expr_block.stderr | 22 +++++++++++++ src/test/ui/reachable/expr_box.rs | 18 +++++++++++ src/test/ui/reachable/expr_box.stderr | 14 +++++++++ src/test/ui/reachable/expr_call.rs | 31 ++++++++++++++++++ src/test/ui/reachable/expr_call.stderr | 20 ++++++++++++ src/test/ui/reachable/expr_cast.rs | 23 ++++++++++++++ src/test/ui/reachable/expr_cast.stderr | 14 +++++++++ src/test/ui/reachable/expr_if.rs | 41 ++++++++++++++++++++++++ src/test/ui/reachable/expr_if.stderr | 15 +++++++++ src/test/ui/reachable/expr_loop.rs | 44 ++++++++++++++++++++++++++ src/test/ui/reachable/expr_loop.stderr | 31 ++++++++++++++++++ src/test/ui/reachable/expr_match.rs | 54 ++++++++++++++++++++++++++++++++ src/test/ui/reachable/expr_match.stderr | 30 ++++++++++++++++++ src/test/ui/reachable/expr_method.rs | 34 ++++++++++++++++++++ src/test/ui/reachable/expr_method.stderr | 20 ++++++++++++ src/test/ui/reachable/expr_oror.rs | 20 ++++++++++++ src/test/ui/reachable/expr_oror.stderr | 0 src/test/ui/reachable/expr_repeat.rs | 23 ++++++++++++++ src/test/ui/reachable/expr_repeat.stderr | 14 +++++++++ src/test/ui/reachable/expr_return.rs | 24 ++++++++++++++ src/test/ui/reachable/expr_return.stderr | 14 +++++++++ src/test/ui/reachable/expr_struct.rs | 43 +++++++++++++++++++++++++ src/test/ui/reachable/expr_struct.stderr | 32 +++++++++++++++++++ src/test/ui/reachable/expr_tup.rs | 28 +++++++++++++++++ src/test/ui/reachable/expr_tup.stderr | 20 ++++++++++++ src/test/ui/reachable/expr_type.rs | 23 ++++++++++++++ src/test/ui/reachable/expr_type.stderr | 14 +++++++++ src/test/ui/reachable/expr_unary.rs | 21 +++++++++++++ src/test/ui/reachable/expr_unary.stderr | 8 +++++ src/test/ui/reachable/expr_while.rs | 38 ++++++++++++++++++++++ src/test/ui/reachable/expr_while.stderr | 31 ++++++++++++++++++ 43 files changed, 1023 insertions(+) create mode 100644 src/test/ui/reachable/README.md create mode 100644 src/test/ui/reachable/expr_add.rs create mode 100644 src/test/ui/reachable/expr_add.stderr create mode 100644 src/test/ui/reachable/expr_again.rs create mode 100644 src/test/ui/reachable/expr_again.stderr create mode 100644 src/test/ui/reachable/expr_andand.rs create mode 100644 src/test/ui/reachable/expr_andand.stderr create mode 100644 src/test/ui/reachable/expr_array.rs create mode 100644 src/test/ui/reachable/expr_array.stderr create mode 100644 src/test/ui/reachable/expr_assign.rs create mode 100644 src/test/ui/reachable/expr_assign.stderr create mode 100644 src/test/ui/reachable/expr_block.rs create mode 100644 src/test/ui/reachable/expr_block.stderr create mode 100644 src/test/ui/reachable/expr_box.rs create mode 100644 src/test/ui/reachable/expr_box.stderr create mode 100644 src/test/ui/reachable/expr_call.rs create mode 100644 src/test/ui/reachable/expr_call.stderr create mode 100644 src/test/ui/reachable/expr_cast.rs create mode 100644 src/test/ui/reachable/expr_cast.stderr create mode 100644 src/test/ui/reachable/expr_if.rs create mode 100644 src/test/ui/reachable/expr_if.stderr create mode 100644 src/test/ui/reachable/expr_loop.rs create mode 100644 src/test/ui/reachable/expr_loop.stderr create mode 100644 src/test/ui/reachable/expr_match.rs create mode 100644 src/test/ui/reachable/expr_match.stderr create mode 100644 src/test/ui/reachable/expr_method.rs create mode 100644 src/test/ui/reachable/expr_method.stderr create mode 100644 src/test/ui/reachable/expr_oror.rs create mode 100644 src/test/ui/reachable/expr_oror.stderr create mode 100644 src/test/ui/reachable/expr_repeat.rs create mode 100644 src/test/ui/reachable/expr_repeat.stderr create mode 100644 src/test/ui/reachable/expr_return.rs create mode 100644 src/test/ui/reachable/expr_return.stderr create mode 100644 src/test/ui/reachable/expr_struct.rs create mode 100644 src/test/ui/reachable/expr_struct.stderr create mode 100644 src/test/ui/reachable/expr_tup.rs create mode 100644 src/test/ui/reachable/expr_tup.stderr create mode 100644 src/test/ui/reachable/expr_type.rs create mode 100644 src/test/ui/reachable/expr_type.stderr create mode 100644 src/test/ui/reachable/expr_unary.rs create mode 100644 src/test/ui/reachable/expr_unary.stderr create mode 100644 src/test/ui/reachable/expr_while.rs create mode 100644 src/test/ui/reachable/expr_while.stderr (limited to 'src/test') diff --git a/src/test/ui/reachable/README.md b/src/test/ui/reachable/README.md new file mode 100644 index 00000000000..8bed5fba7a2 --- /dev/null +++ b/src/test/ui/reachable/README.md @@ -0,0 +1,7 @@ +A variety of tests around reachability. These tests in general check +two things: + +- that we get unreachable code warnings in reasonable locations; +- that we permit coercions **into** `!` from expressions which + diverge, where an expression "diverges" if it must execute some + subexpression of type `!`, or it has type `!` itself. diff --git a/src/test/ui/reachable/expr_add.rs b/src/test/ui/reachable/expr_add.rs new file mode 100644 index 00000000000..87d017adf68 --- /dev/null +++ b/src/test/ui/reachable/expr_add.rs @@ -0,0 +1,28 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(never_type)] +#![allow(unused_variables)] +#![deny(unreachable_code)] + +use std::ops; + +struct Foo; + +impl ops::Add for Foo { + type Output = !; + fn add(self, rhs: !) -> ! { + unimplemented!() + } +} + +fn main() { + let x = Foo + return; +} diff --git a/src/test/ui/reachable/expr_add.stderr b/src/test/ui/reachable/expr_add.stderr new file mode 100644 index 00000000000..1a2cc252051 --- /dev/null +++ b/src/test/ui/reachable/expr_add.stderr @@ -0,0 +1,14 @@ +error: unreachable expression + --> $DIR/expr_add.rs:27:13 + | +27 | let x = Foo + return; + | ^^^^^^^^^^^^ + | +note: lint level defined here + --> $DIR/expr_add.rs:13:9 + | +13 | #![deny(unreachable_code)] + | ^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/reachable/expr_again.rs b/src/test/ui/reachable/expr_again.rs new file mode 100644 index 00000000000..cdbdb8dc0db --- /dev/null +++ b/src/test/ui/reachable/expr_again.rs @@ -0,0 +1,20 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(box_syntax)] +#![allow(unused_variables)] +#![deny(unreachable_code)] + +fn main() { + let x = loop { + continue; + println!("hi"); + }; +} diff --git a/src/test/ui/reachable/expr_again.stderr b/src/test/ui/reachable/expr_again.stderr new file mode 100644 index 00000000000..bf4e4dc4711 --- /dev/null +++ b/src/test/ui/reachable/expr_again.stderr @@ -0,0 +1,15 @@ +error: unreachable statement + --> $DIR/expr_again.rs:18:9 + | +18 | println!("hi"); + | ^^^^^^^^^^^^^^^ + | +note: lint level defined here + --> $DIR/expr_again.rs:13:9 + | +13 | #![deny(unreachable_code)] + | ^^^^^^^^^^^^^^^^ + = note: this error originates in a macro outside of the current crate + +error: aborting due to previous error + diff --git a/src/test/ui/reachable/expr_andand.rs b/src/test/ui/reachable/expr_andand.rs new file mode 100644 index 00000000000..af404d03097 --- /dev/null +++ b/src/test/ui/reachable/expr_andand.rs @@ -0,0 +1,21 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![allow(unused_variables)] +#![allow(dead_code)] +#![deny(unreachable_code)] + +fn foo() { + // No error here. + let x = false && (return); + println!("I am not dead."); +} + +fn main() { } diff --git a/src/test/ui/reachable/expr_andand.stderr b/src/test/ui/reachable/expr_andand.stderr new file mode 100644 index 00000000000..e69de29bb2d diff --git a/src/test/ui/reachable/expr_array.rs b/src/test/ui/reachable/expr_array.rs new file mode 100644 index 00000000000..00e8be07725 --- /dev/null +++ b/src/test/ui/reachable/expr_array.rs @@ -0,0 +1,28 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![allow(unused_variables)] +#![allow(unused_assignments)] +#![allow(dead_code)] +#![deny(unreachable_code)] +#![feature(never_type)] +#![feature(type_ascription)] + +fn a() { + // the `22` is unreachable: + let x: [usize; 2] = [return, 22]; +} + +fn b() { + // the `array is unreachable: + let x: [usize; 2] = [22, return]; +} + +fn main() { } diff --git a/src/test/ui/reachable/expr_array.stderr b/src/test/ui/reachable/expr_array.stderr new file mode 100644 index 00000000000..f8dbdb5f8bb --- /dev/null +++ b/src/test/ui/reachable/expr_array.stderr @@ -0,0 +1,20 @@ +error: unreachable expression + --> $DIR/expr_array.rs:20:34 + | +20 | let x: [usize; 2] = [return, 22]; + | ^^ + | +note: lint level defined here + --> $DIR/expr_array.rs:14:9 + | +14 | #![deny(unreachable_code)] + | ^^^^^^^^^^^^^^^^ + +error: unreachable expression + --> $DIR/expr_array.rs:25:25 + | +25 | let x: [usize; 2] = [22, return]; + | ^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/reachable/expr_assign.rs b/src/test/ui/reachable/expr_assign.rs new file mode 100644 index 00000000000..1b9357013d2 --- /dev/null +++ b/src/test/ui/reachable/expr_assign.rs @@ -0,0 +1,39 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![allow(unused_variables)] +#![allow(unused_assignments)] +#![allow(dead_code)] +#![deny(unreachable_code)] +#![feature(never_type)] + +fn foo() { + // No error here. + let x; + x = return; +} + +fn bar() { + use std::ptr; + let p: *mut ! = ptr::null_mut::(); + unsafe { + // Here we consider the `return` unreachable because + // "evaluating" the `*p` has type `!`. This is somewhat + // dubious, I suppose. + *p = return; + } +} + +fn baz() { + let mut i = 0; + *{return; &mut i} = 22; +} + +fn main() { } diff --git a/src/test/ui/reachable/expr_assign.stderr b/src/test/ui/reachable/expr_assign.stderr new file mode 100644 index 00000000000..807f6a1c1d5 --- /dev/null +++ b/src/test/ui/reachable/expr_assign.stderr @@ -0,0 +1,26 @@ +error: unreachable expression + --> $DIR/expr_assign.rs:20:5 + | +20 | x = return; + | ^^^^^^^^^^ + | +note: lint level defined here + --> $DIR/expr_assign.rs:14:9 + | +14 | #![deny(unreachable_code)] + | ^^^^^^^^^^^^^^^^ + +error: unreachable expression + --> $DIR/expr_assign.rs:30:14 + | +30 | *p = return; + | ^^^^^^ + +error: unreachable expression + --> $DIR/expr_assign.rs:36:15 + | +36 | *{return; &mut i} = 22; + | ^^^^^^ + +error: aborting due to 3 previous errors + diff --git a/src/test/ui/reachable/expr_block.rs b/src/test/ui/reachable/expr_block.rs new file mode 100644 index 00000000000..093589b4dc8 --- /dev/null +++ b/src/test/ui/reachable/expr_block.rs @@ -0,0 +1,41 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![allow(unused_variables)] +#![allow(unused_assignments)] +#![allow(dead_code)] +#![deny(unreachable_code)] +#![feature(never_type)] + +fn a() { + // Here the tail expression is considered unreachable: + let x = { + return; + 22 + }; +} + +fn b() { + // Here the `x` assignment is considered unreachable, not the block: + let x = { + return; + }; +} + +fn c() { + // Here the `println!` is unreachable: + let x = { + return; + println!("foo"); + 22 + }; +} + +fn main() { } diff --git a/src/test/ui/reachable/expr_block.stderr b/src/test/ui/reachable/expr_block.stderr new file mode 100644 index 00000000000..542ce1c3fd9 --- /dev/null +++ b/src/test/ui/reachable/expr_block.stderr @@ -0,0 +1,22 @@ +error: unreachable expression + --> $DIR/expr_block.rs:21:9 + | +21 | 22 + | ^^ + | +note: lint level defined here + --> $DIR/expr_block.rs:14:9 + | +14 | #![deny(unreachable_code)] + | ^^^^^^^^^^^^^^^^ + +error: unreachable statement + --> $DIR/expr_block.rs:36:9 + | +36 | println!("foo"); + | ^^^^^^^^^^^^^^^^ + | + = note: this error originates in a macro outside of the current crate + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/reachable/expr_box.rs b/src/test/ui/reachable/expr_box.rs new file mode 100644 index 00000000000..6509b608335 --- /dev/null +++ b/src/test/ui/reachable/expr_box.rs @@ -0,0 +1,18 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(box_syntax)] +#![allow(unused_variables)] +#![deny(unreachable_code)] + +fn main() { + let x = box return; + println!("hi"); +} diff --git a/src/test/ui/reachable/expr_box.stderr b/src/test/ui/reachable/expr_box.stderr new file mode 100644 index 00000000000..78ba231cef9 --- /dev/null +++ b/src/test/ui/reachable/expr_box.stderr @@ -0,0 +1,14 @@ +error: unreachable expression + --> $DIR/expr_box.rs:16:13 + | +16 | let x = box return; + | ^^^^^^^^^^ + | +note: lint level defined here + --> $DIR/expr_box.rs:13:9 + | +13 | #![deny(unreachable_code)] + | ^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/reachable/expr_call.rs b/src/test/ui/reachable/expr_call.rs new file mode 100644 index 00000000000..8d9f303df7f --- /dev/null +++ b/src/test/ui/reachable/expr_call.rs @@ -0,0 +1,31 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![allow(unused_variables)] +#![allow(unused_assignments)] +#![allow(dead_code)] +#![deny(unreachable_code)] +#![feature(never_type)] + +fn foo(x: !, y: usize) { } + +fn bar(x: !) { } + +fn a() { + // the `22` is unreachable: + foo(return, 22); +} + +fn b() { + // the call is unreachable: + bar(return); +} + +fn main() { } diff --git a/src/test/ui/reachable/expr_call.stderr b/src/test/ui/reachable/expr_call.stderr new file mode 100644 index 00000000000..5526827f59f --- /dev/null +++ b/src/test/ui/reachable/expr_call.stderr @@ -0,0 +1,20 @@ +error: unreachable expression + --> $DIR/expr_call.rs:23:17 + | +23 | foo(return, 22); + | ^^ + | +note: lint level defined here + --> $DIR/expr_call.rs:14:9 + | +14 | #![deny(unreachable_code)] + | ^^^^^^^^^^^^^^^^ + +error: unreachable expression + --> $DIR/expr_call.rs:28:5 + | +28 | bar(return); + | ^^^^^^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/reachable/expr_cast.rs b/src/test/ui/reachable/expr_cast.rs new file mode 100644 index 00000000000..926ef864ebf --- /dev/null +++ b/src/test/ui/reachable/expr_cast.rs @@ -0,0 +1,23 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![allow(unused_variables)] +#![allow(unused_assignments)] +#![allow(dead_code)] +#![deny(unreachable_code)] +#![feature(never_type)] +#![feature(type_ascription)] + +fn a() { + // the cast is unreachable: + let x = {return} as !; +} + +fn main() { } diff --git a/src/test/ui/reachable/expr_cast.stderr b/src/test/ui/reachable/expr_cast.stderr new file mode 100644 index 00000000000..a22300dcc13 --- /dev/null +++ b/src/test/ui/reachable/expr_cast.stderr @@ -0,0 +1,14 @@ +error: unreachable expression + --> $DIR/expr_cast.rs:20:13 + | +20 | let x = {return} as !; + | ^^^^^^^^^^^^^ + | +note: lint level defined here + --> $DIR/expr_cast.rs:14:9 + | +14 | #![deny(unreachable_code)] + | ^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/reachable/expr_if.rs b/src/test/ui/reachable/expr_if.rs new file mode 100644 index 00000000000..2a265e772f3 --- /dev/null +++ b/src/test/ui/reachable/expr_if.rs @@ -0,0 +1,41 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![allow(unused_variables)] +#![allow(unused_assignments)] +#![allow(dead_code)] +#![deny(unreachable_code)] +#![feature(never_type)] + +fn foo() { + if {return} { + println!("Hello, world!"); + } +} + +fn bar() { + if {true} { + return; + } + println!("I am not dead."); +} + +fn baz() { + if {true} { + return; + } else { + return; + } + // As the next action to be taken after the if arms, we should + // report the `println!` as unreachable: + println!("But I am."); +} + +fn main() { } diff --git a/src/test/ui/reachable/expr_if.stderr b/src/test/ui/reachable/expr_if.stderr new file mode 100644 index 00000000000..2cf17474f6e --- /dev/null +++ b/src/test/ui/reachable/expr_if.stderr @@ -0,0 +1,15 @@ +error: unreachable statement + --> $DIR/expr_if.rs:38:5 + | +38 | println!("But I am."); + | ^^^^^^^^^^^^^^^^^^^^^^ + | +note: lint level defined here + --> $DIR/expr_if.rs:14:9 + | +14 | #![deny(unreachable_code)] + | ^^^^^^^^^^^^^^^^ + = note: this error originates in a macro outside of the current crate + +error: aborting due to previous error + diff --git a/src/test/ui/reachable/expr_loop.rs b/src/test/ui/reachable/expr_loop.rs new file mode 100644 index 00000000000..3ed4b2dcf0c --- /dev/null +++ b/src/test/ui/reachable/expr_loop.rs @@ -0,0 +1,44 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![allow(unused_variables)] +#![allow(unused_assignments)] +#![allow(dead_code)] +#![deny(unreachable_code)] +#![feature(never_type)] + +fn a() { + loop { return; } + println!("I am dead."); +} + +fn b() { + loop { + break; + } + println!("I am not dead."); +} + +fn c() { + loop { return; } + println!("I am dead."); +} + +fn d() { + 'outer: loop { loop { break 'outer; } } + println!("I am not dead."); +} + +fn e() { + loop { 'middle: loop { loop { break 'middle; } } } + println!("I am dead."); +} + +fn main() { } diff --git a/src/test/ui/reachable/expr_loop.stderr b/src/test/ui/reachable/expr_loop.stderr new file mode 100644 index 00000000000..6e98e754c54 --- /dev/null +++ b/src/test/ui/reachable/expr_loop.stderr @@ -0,0 +1,31 @@ +error: unreachable statement + --> $DIR/expr_loop.rs:19:5 + | +19 | println!("I am dead."); + | ^^^^^^^^^^^^^^^^^^^^^^^ + | +note: lint level defined here + --> $DIR/expr_loop.rs:14:9 + | +14 | #![deny(unreachable_code)] + | ^^^^^^^^^^^^^^^^ + = note: this error originates in a macro outside of the current crate + +error: unreachable statement + --> $DIR/expr_loop.rs:31:5 + | +31 | println!("I am dead."); + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this error originates in a macro outside of the current crate + +error: unreachable statement + --> $DIR/expr_loop.rs:41:5 + | +41 | println!("I am dead."); + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this error originates in a macro outside of the current crate + +error: aborting due to 3 previous errors + diff --git a/src/test/ui/reachable/expr_match.rs b/src/test/ui/reachable/expr_match.rs new file mode 100644 index 00000000000..23bdcc035b2 --- /dev/null +++ b/src/test/ui/reachable/expr_match.rs @@ -0,0 +1,54 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![allow(unused_variables)] +#![allow(unused_assignments)] +#![allow(dead_code)] +#![deny(unreachable_code)] +#![feature(never_type)] + +fn a() { + // The match is considered unreachable here, because the `return` + // diverges: + match {return} { } +} + +fn b() { + match () { () => return } + println!("I am dead"); +} + +fn c() { + match () { () if false => return, () => () } + println!("I am not dead"); +} + +fn d() { + match () { () if false => return, () => return } + println!("I am dead"); +} + +fn e() { + // Here the compiler fails to figure out that the `println` is dead. + match () { () if return => (), () => return } + println!("I am dead"); +} + +fn f() { + match Some(()) { None => (), Some(()) => return } + println!("I am not dead"); +} + +fn g() { + match Some(()) { None => return, Some(()) => () } + println!("I am not dead"); +} + +fn main() { } diff --git a/src/test/ui/reachable/expr_match.stderr b/src/test/ui/reachable/expr_match.stderr new file mode 100644 index 00000000000..f5857a5b345 --- /dev/null +++ b/src/test/ui/reachable/expr_match.stderr @@ -0,0 +1,30 @@ +error: unreachable expression + --> $DIR/expr_match.rs:20:5 + | +20 | match {return} { } + | ^^^^^^^^^^^^^^^^^^ + | +note: lint level defined here + --> $DIR/expr_match.rs:14:9 + | +14 | #![deny(unreachable_code)] + | ^^^^^^^^^^^^^^^^ + +error: unreachable statement + --> $DIR/expr_match.rs:25:5 + | +25 | println!("I am dead"); + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this error originates in a macro outside of the current crate + +error: unreachable statement + --> $DIR/expr_match.rs:35:5 + | +35 | println!("I am dead"); + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this error originates in a macro outside of the current crate + +error: aborting due to 3 previous errors + diff --git a/src/test/ui/reachable/expr_method.rs b/src/test/ui/reachable/expr_method.rs new file mode 100644 index 00000000000..f1d979d7df7 --- /dev/null +++ b/src/test/ui/reachable/expr_method.rs @@ -0,0 +1,34 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![allow(unused_variables)] +#![allow(unused_assignments)] +#![allow(dead_code)] +#![deny(unreachable_code)] +#![feature(never_type)] + +struct Foo; + +impl Foo { + fn foo(&self, x: !, y: usize) { } + fn bar(&self, x: !) { } +} + +fn a() { + // the `22` is unreachable: + Foo.foo(return, 22); +} + +fn b() { + // the call is unreachable: + Foo.bar(return); +} + +fn main() { } diff --git a/src/test/ui/reachable/expr_method.stderr b/src/test/ui/reachable/expr_method.stderr new file mode 100644 index 00000000000..177d4352a37 --- /dev/null +++ b/src/test/ui/reachable/expr_method.stderr @@ -0,0 +1,20 @@ +error: unreachable expression + --> $DIR/expr_method.rs:26:21 + | +26 | Foo.foo(return, 22); + | ^^ + | +note: lint level defined here + --> $DIR/expr_method.rs:14:9 + | +14 | #![deny(unreachable_code)] + | ^^^^^^^^^^^^^^^^ + +error: unreachable expression + --> $DIR/expr_method.rs:31:5 + | +31 | Foo.bar(return); + | ^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/reachable/expr_oror.rs b/src/test/ui/reachable/expr_oror.rs new file mode 100644 index 00000000000..d01304d4034 --- /dev/null +++ b/src/test/ui/reachable/expr_oror.rs @@ -0,0 +1,20 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![allow(unused_variables)] +#![allow(dead_code)] +#![deny(unreachable_code)] + +fn foo() { + let x = false || (return); + println!("I am not dead."); +} + +fn main() { } diff --git a/src/test/ui/reachable/expr_oror.stderr b/src/test/ui/reachable/expr_oror.stderr new file mode 100644 index 00000000000..e69de29bb2d diff --git a/src/test/ui/reachable/expr_repeat.rs b/src/test/ui/reachable/expr_repeat.rs new file mode 100644 index 00000000000..6078d6d5bde --- /dev/null +++ b/src/test/ui/reachable/expr_repeat.rs @@ -0,0 +1,23 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![allow(unused_variables)] +#![allow(unused_assignments)] +#![allow(dead_code)] +#![deny(unreachable_code)] +#![feature(never_type)] +#![feature(type_ascription)] + +fn a() { + // the repeat is unreachable: + let x: [usize; 2] = [return; 2]; +} + +fn main() { } diff --git a/src/test/ui/reachable/expr_repeat.stderr b/src/test/ui/reachable/expr_repeat.stderr new file mode 100644 index 00000000000..19afc5dd7b5 --- /dev/null +++ b/src/test/ui/reachable/expr_repeat.stderr @@ -0,0 +1,14 @@ +error: unreachable expression + --> $DIR/expr_repeat.rs:20:25 + | +20 | let x: [usize; 2] = [return; 2]; + | ^^^^^^^^^^^ + | +note: lint level defined here + --> $DIR/expr_repeat.rs:14:9 + | +14 | #![deny(unreachable_code)] + | ^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/reachable/expr_return.rs b/src/test/ui/reachable/expr_return.rs new file mode 100644 index 00000000000..c640ca06630 --- /dev/null +++ b/src/test/ui/reachable/expr_return.rs @@ -0,0 +1,24 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![allow(unused_variables)] +#![allow(unused_assignments)] +#![allow(dead_code)] +#![deny(unreachable_code)] +#![feature(never_type)] +#![feature(type_ascription)] + +fn a() { + // Here we issue that the "2nd-innermost" return is unreachable, + // but we stop there. + let x = {return {return {return;}}}; +} + +fn main() { } diff --git a/src/test/ui/reachable/expr_return.stderr b/src/test/ui/reachable/expr_return.stderr new file mode 100644 index 00000000000..3eb70a4dd7c --- /dev/null +++ b/src/test/ui/reachable/expr_return.stderr @@ -0,0 +1,14 @@ +error: unreachable expression + --> $DIR/expr_return.rs:21:22 + | +21 | let x = {return {return {return;}}}; + | ^^^^^^^^^^^^^^^^ + | +note: lint level defined here + --> $DIR/expr_return.rs:14:9 + | +14 | #![deny(unreachable_code)] + | ^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/reachable/expr_struct.rs b/src/test/ui/reachable/expr_struct.rs new file mode 100644 index 00000000000..09e31819279 --- /dev/null +++ b/src/test/ui/reachable/expr_struct.rs @@ -0,0 +1,43 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![allow(unused_variables)] +#![allow(unused_assignments)] +#![allow(dead_code)] +#![deny(unreachable_code)] +#![feature(never_type)] +#![feature(type_ascription)] + +struct Foo { + a: usize, + b: usize, +} + +fn a() { + // struct expr is unreachable: + let x = Foo { a: 22, b: 33, ..return }; +} + +fn b() { + // the `33` is unreachable: + let x = Foo { a: return, b: 33, ..return }; +} + +fn c() { + // the `..return` is unreachable: + let x = Foo { a: 22, b: return, ..return }; +} + +fn d() { + // the struct expr is unreachable: + let x = Foo { a: 22, b: return }; +} + +fn main() { } diff --git a/src/test/ui/reachable/expr_struct.stderr b/src/test/ui/reachable/expr_struct.stderr new file mode 100644 index 00000000000..4b7ac660413 --- /dev/null +++ b/src/test/ui/reachable/expr_struct.stderr @@ -0,0 +1,32 @@ +error: unreachable expression + --> $DIR/expr_struct.rs:25:13 + | +25 | let x = Foo { a: 22, b: 33, ..return }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: lint level defined here + --> $DIR/expr_struct.rs:14:9 + | +14 | #![deny(unreachable_code)] + | ^^^^^^^^^^^^^^^^ + +error: unreachable expression + --> $DIR/expr_struct.rs:30:33 + | +30 | let x = Foo { a: return, b: 33, ..return }; + | ^^ + +error: unreachable expression + --> $DIR/expr_struct.rs:35:39 + | +35 | let x = Foo { a: 22, b: return, ..return }; + | ^^^^^^ + +error: unreachable expression + --> $DIR/expr_struct.rs:40:13 + | +40 | let x = Foo { a: 22, b: return }; + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 4 previous errors + diff --git a/src/test/ui/reachable/expr_tup.rs b/src/test/ui/reachable/expr_tup.rs new file mode 100644 index 00000000000..7c75296de6c --- /dev/null +++ b/src/test/ui/reachable/expr_tup.rs @@ -0,0 +1,28 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![allow(unused_variables)] +#![allow(unused_assignments)] +#![allow(dead_code)] +#![deny(unreachable_code)] +#![feature(never_type)] +#![feature(type_ascription)] + +fn a() { + // the `2` is unreachable: + let x: (usize, usize) = (return, 2); +} + +fn b() { + // the tuple is unreachable: + let x: (usize, usize) = (2, return); +} + +fn main() { } diff --git a/src/test/ui/reachable/expr_tup.stderr b/src/test/ui/reachable/expr_tup.stderr new file mode 100644 index 00000000000..63f477fd0c3 --- /dev/null +++ b/src/test/ui/reachable/expr_tup.stderr @@ -0,0 +1,20 @@ +error: unreachable expression + --> $DIR/expr_tup.rs:20:38 + | +20 | let x: (usize, usize) = (return, 2); + | ^ + | +note: lint level defined here + --> $DIR/expr_tup.rs:14:9 + | +14 | #![deny(unreachable_code)] + | ^^^^^^^^^^^^^^^^ + +error: unreachable expression + --> $DIR/expr_tup.rs:25:29 + | +25 | let x: (usize, usize) = (2, return); + | ^^^^^^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/reachable/expr_type.rs b/src/test/ui/reachable/expr_type.rs new file mode 100644 index 00000000000..2fa277c382e --- /dev/null +++ b/src/test/ui/reachable/expr_type.rs @@ -0,0 +1,23 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![allow(unused_variables)] +#![allow(unused_assignments)] +#![allow(dead_code)] +#![deny(unreachable_code)] +#![feature(never_type)] +#![feature(type_ascription)] + +fn a() { + // the cast is unreachable: + let x = {return}: !; +} + +fn main() { } diff --git a/src/test/ui/reachable/expr_type.stderr b/src/test/ui/reachable/expr_type.stderr new file mode 100644 index 00000000000..6ed79974ccb --- /dev/null +++ b/src/test/ui/reachable/expr_type.stderr @@ -0,0 +1,14 @@ +error: unreachable expression + --> $DIR/expr_type.rs:20:13 + | +20 | let x = {return}: !; + | ^^^^^^^^^^^ + | +note: lint level defined here + --> $DIR/expr_type.rs:14:9 + | +14 | #![deny(unreachable_code)] + | ^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/reachable/expr_unary.rs b/src/test/ui/reachable/expr_unary.rs new file mode 100644 index 00000000000..57901fbaa7c --- /dev/null +++ b/src/test/ui/reachable/expr_unary.rs @@ -0,0 +1,21 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![allow(unused_variables)] +#![allow(unused_assignments)] +#![allow(dead_code)] +#![deny(unreachable_code)] +#![feature(never_type)] + +fn foo() { + let x: ! = ! { return; 22 }; +} + +fn main() { } diff --git a/src/test/ui/reachable/expr_unary.stderr b/src/test/ui/reachable/expr_unary.stderr new file mode 100644 index 00000000000..11172652d84 --- /dev/null +++ b/src/test/ui/reachable/expr_unary.stderr @@ -0,0 +1,8 @@ +error: cannot apply unary operator `!` to type `!` + --> $DIR/expr_unary.rs:18:16 + | +18 | let x: ! = ! { return; 22 }; + | ^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/reachable/expr_while.rs b/src/test/ui/reachable/expr_while.rs new file mode 100644 index 00000000000..7dcd609fbc8 --- /dev/null +++ b/src/test/ui/reachable/expr_while.rs @@ -0,0 +1,38 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![allow(unused_variables)] +#![allow(unused_assignments)] +#![allow(dead_code)] +#![deny(unreachable_code)] +#![feature(never_type)] + +fn foo() { + while {return} { + println!("Hello, world!"); + } +} + +fn bar() { + while {true} { + return; + } + println!("I am not dead."); +} + +fn baz() { + // Here, we cite the `while` loop as dead. + while {return} { + println!("I am dead."); + } + println!("I am, too."); +} + +fn main() { } diff --git a/src/test/ui/reachable/expr_while.stderr b/src/test/ui/reachable/expr_while.stderr new file mode 100644 index 00000000000..066cfc86c64 --- /dev/null +++ b/src/test/ui/reachable/expr_while.stderr @@ -0,0 +1,31 @@ +error: unreachable statement + --> $DIR/expr_while.rs:19:9 + | +19 | println!("Hello, world!"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: lint level defined here + --> $DIR/expr_while.rs:14:9 + | +14 | #![deny(unreachable_code)] + | ^^^^^^^^^^^^^^^^ + = note: this error originates in a macro outside of the current crate + +error: unreachable statement + --> $DIR/expr_while.rs:33:9 + | +33 | println!("I am dead."); + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this error originates in a macro outside of the current crate + +error: unreachable statement + --> $DIR/expr_while.rs:35:5 + | +35 | println!("I am, too."); + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this error originates in a macro outside of the current crate + +error: aborting due to 3 previous errors + -- cgit 1.4.1-3-g733a5 From 8c6156e1d1f7e46c59fd21c878dccbc4526d7e0c Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 22 Mar 2017 21:07:02 -0400 Subject: have coercion supply back the target type The `try_coerce` method coerces from a source to a target type, possibly inserting adjustments. It should guarantee that the post-adjustment type is a subtype of the target type (or else that some side-constraint has been registered which will lead to an error). However, it used to return the (possibly adjusted) source as the type of the expression rather than the target. This led to less good downstream errors. To work around this, the code around blocks -- and particular tail expressions in blocks -- had some special case manipulation. However, since that code is now using the more general `CoerceMany` construct (to account for breaks), it can no longer take advantage of that. This lead to some regressions in compile-fail tests were errors were reported at "less good" locations than before. This change modifies coercions to return the target type when successful rather the source type. This extends the behavior from blocks to all coercions. Typically this has limited effect but on a few tests yielded better errors results (and avoided regressions, of course). This change also restores the hint about removing semicolons which went missing (by giving 'force-unit' coercions a chance to add notes etc). --- src/librustc_typeck/check/_match.rs | 2 +- src/librustc_typeck/check/coercion.rs | 40 ++++++--- src/librustc_typeck/check/mod.rs | 99 +++++++++++++--------- src/test/compile-fail/issue-15965.rs | 2 +- src/test/compile-fail/issue-2149.rs | 2 +- .../region-invariant-static-error-reporting.rs | 3 - src/test/compile-fail/regions-bounds.rs | 4 +- 7 files changed, 91 insertions(+), 61 deletions(-) (limited to 'src/test') diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index e83b786b9a8..4a044642444 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -498,7 +498,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if is_if_let_fallback { let cause = self.cause(expr.span, ObligationCauseCode::IfExpressionWithNoElse); assert!(arm_ty.is_nil()); - coercion.coerce_forced_unit(self, &cause); + coercion.coerce_forced_unit(self, &cause, &mut |_| ()); } else { let cause = self.cause(expr.span, ObligationCauseCode::MatchExpressionArm { arm_span: arm.body.span, diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index 37d442f1d05..a5acd0c7e53 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -74,6 +74,7 @@ use rustc::ty::fold::TypeFoldable; use rustc::ty::error::TypeError; use rustc::ty::relate::RelateResult; use rustc::ty::subst::Subst; +use errors::DiagnosticBuilder; use syntax::abi; use syntax::feature_gate; use syntax::ptr::P; @@ -718,7 +719,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } self.write_adjustment(expr.id, adjustment); } - Ok(adjustment.target) + + // We should now have added sufficient adjustments etc to + // ensure that the type of expression, post-adjustment, is + // a subtype of target. + Ok(target) }) } @@ -1000,7 +1005,7 @@ impl<'gcx, 'tcx, 'exprs, E> CoerceMany<'gcx, 'tcx, 'exprs, E> expression_ty: Ty<'tcx>, expression_diverges: Diverges) { - self.coerce_inner(fcx, cause, Some(expression), expression_ty, expression_diverges) + self.coerce_inner(fcx, cause, Some(expression), expression_ty, expression_diverges, None) } /// Indicates that one of the inputs is a "forced unit". This @@ -1011,15 +1016,21 @@ impl<'gcx, 'tcx, 'exprs, E> CoerceMany<'gcx, 'tcx, 'exprs, E> /// purposes. Note that these tend to correspond to cases where /// the `()` expression is implicit in the source, and hence we do /// not take an expression argument. + /// + /// The `augment_error` gives you a chance to extend the error + /// message, in case any results (e.g., we use this to suggest + /// removing a `;`). pub fn coerce_forced_unit<'a>(&mut self, fcx: &FnCtxt<'a, 'gcx, 'tcx>, - cause: &ObligationCause<'tcx>) + cause: &ObligationCause<'tcx>, + augment_error: &mut FnMut(&mut DiagnosticBuilder)) { self.coerce_inner(fcx, cause, None, fcx.tcx.mk_nil(), - Diverges::Maybe) + Diverges::Maybe, + Some(augment_error)) } /// The inner coercion "engine". If `expression` is `None`, this @@ -1030,7 +1041,8 @@ impl<'gcx, 'tcx, 'exprs, E> CoerceMany<'gcx, 'tcx, 'exprs, E> cause: &ObligationCause<'tcx>, expression: Option<&'gcx hir::Expr>, mut expression_ty: Ty<'tcx>, - expression_diverges: Diverges) + expression_diverges: Diverges, + augment_error: Option<&mut FnMut(&mut DiagnosticBuilder)>) { // Incorporate whatever type inference information we have // until now; in principle we might also want to process @@ -1126,19 +1138,25 @@ impl<'gcx, 'tcx, 'exprs, E> CoerceMany<'gcx, 'tcx, 'exprs, E> (self.final_ty.unwrap_or(self.expected_ty), expression_ty) }; + let mut db; match cause.code { ObligationCauseCode::ReturnNoExpression => { - struct_span_err!(fcx.tcx.sess, cause.span, E0069, - "`return;` in a function whose return type is not `()`") - .span_label(cause.span, &format!("return type is not ()")) - .emit(); + db = struct_span_err!( + fcx.tcx.sess, cause.span, E0069, + "`return;` in a function whose return type is not `()`"); + db.span_label(cause.span, &format!("return type is not ()")); } _ => { - fcx.report_mismatched_types(cause, expected, found, err) - .emit(); + db = fcx.report_mismatched_types(cause, expected, found, err); } } + if let Some(mut augment_error) = augment_error { + augment_error(&mut db); + } + + db.emit(); + self.final_ty = Some(fcx.tcx.types.err); } } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 9eaa8404bde..29b83523aed 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -87,7 +87,7 @@ use fmt_macros::{Parser, Piece, Position}; use hir::def::{Def, CtorKind}; use hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; use rustc_back::slice::ref_slice; -use rustc::infer::{self, InferCtxt, InferOk, RegionVariableOrigin, TypeTrace}; +use rustc::infer::{self, InferCtxt, InferOk, RegionVariableOrigin}; use rustc::infer::type_variable::{self, TypeVariableOrigin}; use rustc::ty::subst::{Kind, Subst, Substs}; use rustc::traits::{self, ObligationCause, ObligationCauseCode, Reveal}; @@ -99,6 +99,7 @@ use rustc::ty::adjustment; use rustc::ty::fold::{BottomUpFolder, TypeFoldable}; use rustc::ty::maps::Providers; use rustc::ty::util::{Representability, IntTypeExt}; +use errors::DiagnosticBuilder; use require_c_abi_if_variadic; use session::{Session, CompileResult}; use TypeAndSubsts; @@ -2875,7 +2876,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.diverges.set(cond_diverges | then_diverges & else_diverges); } else { let else_cause = self.cause(sp, ObligationCauseCode::IfExpressionWithNoElse); - coerce.coerce_forced_unit(self, &else_cause); + coerce.coerce_forced_unit(self, &else_cause, &mut |_| ()); // If the condition is false we can't diverge. self.diverges.set(cond_diverges); @@ -3591,7 +3592,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { coerce.coerce(self, &cause, e, e_ty, e_diverges); } else { assert!(e_ty.is_nil()); - coerce.coerce_forced_unit(self, &cause); + coerce.coerce_forced_unit(self, &cause, &mut |_| ()); } } else { // If `ctxt.coerce` is `None`, we can just ignore @@ -3626,7 +3627,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } else { let mut coercion = self.ret_coercion.as_ref().unwrap().borrow_mut(); let cause = self.cause(expr.span, ObligationCauseCode::ReturnNoExpression); - coercion.coerce_forced_unit(self, &cause); + coercion.coerce_forced_unit(self, &cause, &mut |_| ()); } tcx.types.never } @@ -4158,8 +4159,23 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { tail_expr, tail_expr_ty, self.diverges.get()); // TODO - } else if !self.diverges.get().always() { - coerce.coerce_forced_unit(self, &self.misc(blk.span)); + } else { + // Subtle: if there is no explicit tail expression, + // that is typically equivalent to a tail expression + // of `()` -- except if the block diverges. In that + // case, there is no value supplied from the tail + // expression (assuming there are no other breaks, + // this implies that the type of the block will be + // `!`). + if !self.diverges.get().always() { + coerce.coerce_forced_unit(self, &self.misc(blk.span), &mut |err| { + if let Some(expected_ty) = expected.only_has_type(self) { + self.consider_hint_about_removing_semicolon(blk, + expected_ty, + err); + } + }); + } } }); @@ -4175,43 +4191,42 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { ty } - pub fn check_block_no_expr(&self, blk: &'gcx hir::Block, ty: Ty<'tcx>, ety: Ty<'tcx>) { - // We're not diverging and there's an expected type, which, - // in case it's not `()`, could result in an error higher-up. - // We have a chance to error here early and be more helpful. - let cause = self.misc(blk.span); - let trace = TypeTrace::types(&cause, false, ty, ety); - match self.sub_types(false, &cause, ty, ety) { - Ok(InferOk { obligations, .. }) => { - // FIXME(#32730) propagate obligations - assert!(obligations.is_empty()); - }, - Err(err) => { - let mut err = self.report_and_explain_type_error(trace, &err); - - // Be helpful when the user wrote `{... expr;}` and - // taking the `;` off is enough to fix the error. - let mut extra_semi = None; - if let Some(stmt) = blk.stmts.last() { - if let hir::StmtSemi(ref e, _) = stmt.node { - if self.can_sub_types(self.node_ty(e.id), ety).is_ok() { - extra_semi = Some(stmt); - } - } - } - if let Some(last_stmt) = extra_semi { - let original_span = original_sp(last_stmt.span, blk.span); - let span_semi = Span { - lo: original_span.hi - BytePos(1), - hi: original_span.hi, - ctxt: original_span.ctxt, - }; - err.span_help(span_semi, "consider removing this semicolon:"); - } - - err.emit(); - } + /// A common error is to add an extra semicolon: + /// + /// ``` + /// fn foo() -> usize { + /// 22; + /// } + /// ``` + /// + /// This routine checks if the final statement in a block is an + /// expression with an explicit semicolon whose type is compatible + /// with `expected_ty`. If so, it suggests removing the semicolon. + fn consider_hint_about_removing_semicolon(&self, + blk: &'gcx hir::Block, + expected_ty: Ty<'tcx>, + err: &mut DiagnosticBuilder) { + // Be helpful when the user wrote `{... expr;}` and + // taking the `;` off is enough to fix the error. + let last_stmt = match blk.stmts.last() { + Some(s) => s, + None => return, + }; + let last_expr = match last_stmt.node { + hir::StmtSemi(ref e, _) => e, + _ => return, + }; + let last_expr_ty = self.expr_ty(last_expr); + if self.can_sub_types(last_expr_ty, expected_ty).is_err() { + return; } + let original_span = original_sp(last_stmt.span, blk.span); + let span_semi = Span { + lo: original_span.hi - BytePos(1), + hi: original_span.hi, + ctxt: original_span.ctxt, + }; + err.span_help(span_semi, "consider removing this semicolon:"); } // Instantiates the given path, which must refer to an item with the given diff --git a/src/test/compile-fail/issue-15965.rs b/src/test/compile-fail/issue-15965.rs index d5d597c190e..08b896f387b 100644 --- a/src/test/compile-fail/issue-15965.rs +++ b/src/test/compile-fail/issue-15965.rs @@ -11,7 +11,7 @@ fn main() { return { return () } -//~^ ERROR expected function, found `!` +//~^ ERROR the type of this value must be known in this context () ; } diff --git a/src/test/compile-fail/issue-2149.rs b/src/test/compile-fail/issue-2149.rs index 9143a226a24..256c5d8e6f7 100644 --- a/src/test/compile-fail/issue-2149.rs +++ b/src/test/compile-fail/issue-2149.rs @@ -21,5 +21,5 @@ impl vec_monad for Vec { } fn main() { ["hi"].bind(|x| [x] ); - //~^ ERROR no method named `bind` found for type `[&'static str; 1]` in the current scope + //~^ ERROR no method named `bind` found for type `[&str; 1]` in the current scope } diff --git a/src/test/compile-fail/region-invariant-static-error-reporting.rs b/src/test/compile-fail/region-invariant-static-error-reporting.rs index ac0167e08bd..d25674a74b1 100644 --- a/src/test/compile-fail/region-invariant-static-error-reporting.rs +++ b/src/test/compile-fail/region-invariant-static-error-reporting.rs @@ -13,9 +13,6 @@ // over time, but this test used to exhibit some pretty bogus messages // that were not remotely helpful. -// error-pattern:cannot infer -// error-pattern:cannot outlive the lifetime 'a -// error-pattern:must be valid for the static lifetime // error-pattern:cannot infer // error-pattern:cannot outlive the lifetime 'a // error-pattern:must be valid for the static lifetime diff --git a/src/test/compile-fail/regions-bounds.rs b/src/test/compile-fail/regions-bounds.rs index 810a8671c53..5ce80be98d9 100644 --- a/src/test/compile-fail/regions-bounds.rs +++ b/src/test/compile-fail/regions-bounds.rs @@ -16,11 +16,11 @@ struct an_enum<'a>(&'a isize); struct a_class<'a> { x:&'a isize } fn a_fn1<'a,'b>(e: an_enum<'a>) -> an_enum<'b> { - return e; //~^ ERROR mismatched types + return e; //~ ERROR mismatched types } fn a_fn3<'a,'b>(e: a_class<'a>) -> a_class<'b> { - return e; //~^ ERROR mismatched types + return e; //~ ERROR mismatched types } fn main() { } -- cgit 1.4.1-3-g733a5 From 7eeddb409364fdeecbec8611f08a6ccea134971f Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 24 Mar 2017 13:21:50 -0400 Subject: add test illustrating current "coerce to `!`" behavior --- src/test/compile-fail/coerce-to-bang.rs | 90 +++++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 src/test/compile-fail/coerce-to-bang.rs (limited to 'src/test') diff --git a/src/test/compile-fail/coerce-to-bang.rs b/src/test/compile-fail/coerce-to-bang.rs new file mode 100644 index 00000000000..870665bb49e --- /dev/null +++ b/src/test/compile-fail/coerce-to-bang.rs @@ -0,0 +1,90 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(never_type)] + +fn foo(x: usize, y: !, z: usize) { } + +fn call_foo_a() { + // FIXME(#40800) -- accepted beacuse divergence happens **before** + // the coercion to `!`, but within same expression. Not clear that + // these are the rules we want. + foo(return, 22, 44); +} + +fn call_foo_b() { + // Divergence happens in the argument itself, definitely ok. + foo(22, return, 44); +} + +fn call_foo_c() { + // This test fails because the divergence happens **after** the + // coercion to `!`: + foo(22, 44, return); //~ ERROR mismatched types +} + +fn call_foo_d() { + // This test passes because `a` has type `!`: + let a: ! = return; + let b = 22; + let c = 44; + foo(a, b, c); // ... and hence a reference to `a` is expected to diverge. +} + +fn call_foo_e() { + // This test probably could pass but we don't *know* that `a` + // has type `!` so we don't let it work. + let a = return; + let b = 22; + let c = 44; + foo(a, b, c); //~ ERROR mismatched types +} + +fn call_foo_f() { + // This fn fails because `a` has type `usize`, and hence a + // reference to is it **not** considered to diverge. + let a: usize = return; + let b = 22; + let c = 44; + foo(a, b, c); //~ ERROR mismatched types +} + +fn array_a() { + // Accepted: return is coerced to `!` just fine, and then `22` can be + // because we already diverged. + let x: [!; 2] = [return, 22]; +} + +fn array_b() { + // Error: divergence has not yet occurred. + let x: [!; 2] = [22, return]; //~ ERROR mismatched types +} + +fn tuple_a() { + // No divergence at all. + let x: (usize, !, usize) = (22, 44, 66); //~ ERROR mismatched types +} + +fn tuple_b() { + // Divergence happens before coercion: OK + let x: (usize, !, usize) = (return, 44, 66); +} + +fn tuple_c() { + // Divergence happens before coercion: OK + let x: (usize, !, usize) = (22, return, 66); +} + +fn tuple_d() { + // Error: divergence happens too late + let x: (usize, !, usize) = (22, 44, return); //~ ERROR mismatched types +} + +fn main() { } -- cgit 1.4.1-3-g733a5 From 8450add8bede7bc5119457e37bbbcc95a5e8b121 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 24 Mar 2017 13:35:49 -0400 Subject: fix `X as !` behavior --- src/librustc_typeck/check/cast.rs | 8 +++++--- src/librustc_typeck/check/mod.rs | 5 +++-- src/test/compile-fail/coerce-to-bang-cast.rs | 23 +++++++++++++++++++++++ 3 files changed, 31 insertions(+), 5 deletions(-) create mode 100644 src/test/compile-fail/coerce-to-bang-cast.rs (limited to 'src/test') diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs index ea0aad007dd..32b363ed755 100644 --- a/src/librustc_typeck/check/cast.rs +++ b/src/librustc_typeck/check/cast.rs @@ -56,6 +56,7 @@ use util::common::ErrorReported; pub struct CastCheck<'tcx> { expr: &'tcx hir::Expr, expr_ty: Ty<'tcx>, + expr_diverges: Diverges, cast_ty: Ty<'tcx>, cast_span: Span, span: Span, @@ -115,6 +116,7 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { pub fn new(fcx: &FnCtxt<'a, 'gcx, 'tcx>, expr: &'tcx hir::Expr, expr_ty: Ty<'tcx>, + expr_diverges: Diverges, cast_ty: Ty<'tcx>, cast_span: Span, span: Span) @@ -122,6 +124,7 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { let check = CastCheck { expr: expr, expr_ty: expr_ty, + expr_diverges: expr_diverges, cast_ty: cast_ty, cast_span: cast_span, span: span, @@ -378,7 +381,7 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { // Attempt a coercion to a fn pointer type. let res = fcx.try_coerce(self.expr, self.expr_ty, - Diverges::Maybe, // TODO + self.expr_diverges, fcx.tcx.mk_fn_ptr(f)); if !res.is_ok() { return Err(CastError::NonScalar); @@ -545,8 +548,7 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { } fn try_coercion_cast(&self, fcx: &FnCtxt<'a, 'gcx, 'tcx>) -> bool { - // TODO - fcx.try_coerce(self.expr, self.expr_ty, Diverges::Maybe, self.cast_ty).is_ok() + fcx.try_coerce(self.expr, self.expr_ty, self.expr_diverges, self.cast_ty).is_ok() } } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 29b83523aed..da15c8f766e 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -3736,6 +3736,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let t_cast = self.resolve_type_vars_if_possible(&t_cast); let t_expr = self.check_expr_with_expectation(e, ExpectCastableToType(t_cast)); let t_cast = self.resolve_type_vars_if_possible(&t_cast); + let diverges = self.diverges.get(); // Eagerly check for some obvious errors. if t_expr.references_error() || t_cast.references_error() { @@ -3743,7 +3744,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } else { // Defer other checks until we're done type checking. let mut deferred_cast_checks = self.deferred_cast_checks.borrow_mut(); - match cast::CastCheck::new(self, e, t_expr, t_cast, t.span, expr.span) { + match cast::CastCheck::new(self, e, t_expr, diverges, t_cast, t.span, expr.span) { Ok(cast_check) => { deferred_cast_checks.push(cast_check); t_cast @@ -4158,7 +4159,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { &self.misc(tail_expr.span), tail_expr, tail_expr_ty, - self.diverges.get()); // TODO + self.diverges.get()); } else { // Subtle: if there is no explicit tail expression, // that is typically equivalent to a tail expression diff --git a/src/test/compile-fail/coerce-to-bang-cast.rs b/src/test/compile-fail/coerce-to-bang-cast.rs new file mode 100644 index 00000000000..57d2192e635 --- /dev/null +++ b/src/test/compile-fail/coerce-to-bang-cast.rs @@ -0,0 +1,23 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(never_type)] + +fn foo(x: usize, y: !, z: usize) { } + +fn cast_a() { + let y = {return; 22} as !; +} + +fn cast_b() { + let y = 22 as !; //~ ERROR non-scalar cast +} + +fn main() { } -- cgit 1.4.1-3-g733a5 From e97fc5247a1d3e3e223febbbcda15e3439b61c30 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 24 Mar 2017 18:47:58 -0400 Subject: kill the graphviz-flowgraph tests They are so annoying to update, and haven't caught any bugs afaik. --- src/test/run-make/graphviz-flowgraph/Makefile | 38 ----- .../graphviz-flowgraph/f00.dot-expected.dot | 9 -- src/test/run-make/graphviz-flowgraph/f00.rs | 13 -- .../graphviz-flowgraph/f01.dot-expected.dot | 13 -- src/test/run-make/graphviz-flowgraph/f01.rs | 13 -- .../graphviz-flowgraph/f02.dot-expected.dot | 13 -- src/test/run-make/graphviz-flowgraph/f02.rs | 13 -- .../graphviz-flowgraph/f03.dot-expected.dot | 17 --- src/test/run-make/graphviz-flowgraph/f03.rs | 13 -- .../graphviz-flowgraph/f04.dot-expected.dot | 15 -- src/test/run-make/graphviz-flowgraph/f04.rs | 13 -- .../graphviz-flowgraph/f05.dot-expected.dot | 23 --- src/test/run-make/graphviz-flowgraph/f05.rs | 13 -- .../graphviz-flowgraph/f06.dot-expected.dot | 19 --- src/test/run-make/graphviz-flowgraph/f06.rs | 14 -- .../graphviz-flowgraph/f07.dot-expected.dot | 39 ----- src/test/run-make/graphviz-flowgraph/f07.rs | 17 --- .../graphviz-flowgraph/f08.dot-expected.dot | 38 ----- src/test/run-make/graphviz-flowgraph/f08.rs | 16 -- .../graphviz-flowgraph/f09.dot-expected.dot | 54 ------- src/test/run-make/graphviz-flowgraph/f09.rs | 18 --- .../graphviz-flowgraph/f10.dot-expected.dot | 36 ----- src/test/run-make/graphviz-flowgraph/f10.rs | 16 -- .../graphviz-flowgraph/f11.dot-expected.dot | 35 ----- src/test/run-make/graphviz-flowgraph/f11.rs | 18 --- .../graphviz-flowgraph/f12.dot-expected.dot | 50 ------- src/test/run-make/graphviz-flowgraph/f12.rs | 18 --- .../graphviz-flowgraph/f13.dot-expected.dot | 54 ------- src/test/run-make/graphviz-flowgraph/f13.rs | 18 --- .../graphviz-flowgraph/f14.dot-expected.dot | 36 ----- src/test/run-make/graphviz-flowgraph/f14.rs | 18 --- .../graphviz-flowgraph/f15.dot-expected.dot | 105 -------------- src/test/run-make/graphviz-flowgraph/f15.rs | 30 ---- .../graphviz-flowgraph/f16.dot-expected.dot | 111 -------------- src/test/run-make/graphviz-flowgraph/f16.rs | 31 ---- .../graphviz-flowgraph/f17.dot-expected.dot | 21 --- src/test/run-make/graphviz-flowgraph/f17.rs | 13 -- .../graphviz-flowgraph/f18.dot-expected.dot | 23 --- src/test/run-make/graphviz-flowgraph/f18.rs | 14 -- .../graphviz-flowgraph/f19.dot-expected.dot | 29 ---- src/test/run-make/graphviz-flowgraph/f19.rs | 16 -- .../graphviz-flowgraph/f20.dot-expected.dot | 29 ---- src/test/run-make/graphviz-flowgraph/f20.rs | 14 -- .../graphviz-flowgraph/f21.dot-expected.dot | 101 ------------- src/test/run-make/graphviz-flowgraph/f21.rs | 30 ---- .../graphviz-flowgraph/f22.dot-expected.dot | 107 -------------- src/test/run-make/graphviz-flowgraph/f22.rs | 31 ---- .../graphviz-flowgraph/f23.dot-expected.dot | 113 --------------- src/test/run-make/graphviz-flowgraph/f23.rs | 31 ---- .../graphviz-flowgraph/f24.dot-expected.dot | 161 --------------------- src/test/run-make/graphviz-flowgraph/f24.rs | 36 ----- .../graphviz-flowgraph/f25.dot-expected.dot | 161 --------------------- src/test/run-make/graphviz-flowgraph/f25.rs | 36 ----- 53 files changed, 1963 deletions(-) delete mode 100644 src/test/run-make/graphviz-flowgraph/Makefile delete mode 100644 src/test/run-make/graphviz-flowgraph/f00.dot-expected.dot delete mode 100644 src/test/run-make/graphviz-flowgraph/f00.rs delete mode 100644 src/test/run-make/graphviz-flowgraph/f01.dot-expected.dot delete mode 100644 src/test/run-make/graphviz-flowgraph/f01.rs delete mode 100644 src/test/run-make/graphviz-flowgraph/f02.dot-expected.dot delete mode 100644 src/test/run-make/graphviz-flowgraph/f02.rs delete mode 100644 src/test/run-make/graphviz-flowgraph/f03.dot-expected.dot delete mode 100644 src/test/run-make/graphviz-flowgraph/f03.rs delete mode 100644 src/test/run-make/graphviz-flowgraph/f04.dot-expected.dot delete mode 100644 src/test/run-make/graphviz-flowgraph/f04.rs delete mode 100644 src/test/run-make/graphviz-flowgraph/f05.dot-expected.dot delete mode 100644 src/test/run-make/graphviz-flowgraph/f05.rs delete mode 100644 src/test/run-make/graphviz-flowgraph/f06.dot-expected.dot delete mode 100644 src/test/run-make/graphviz-flowgraph/f06.rs delete mode 100644 src/test/run-make/graphviz-flowgraph/f07.dot-expected.dot delete mode 100644 src/test/run-make/graphviz-flowgraph/f07.rs delete mode 100644 src/test/run-make/graphviz-flowgraph/f08.dot-expected.dot delete mode 100644 src/test/run-make/graphviz-flowgraph/f08.rs delete mode 100644 src/test/run-make/graphviz-flowgraph/f09.dot-expected.dot delete mode 100644 src/test/run-make/graphviz-flowgraph/f09.rs delete mode 100644 src/test/run-make/graphviz-flowgraph/f10.dot-expected.dot delete mode 100644 src/test/run-make/graphviz-flowgraph/f10.rs delete mode 100644 src/test/run-make/graphviz-flowgraph/f11.dot-expected.dot delete mode 100644 src/test/run-make/graphviz-flowgraph/f11.rs delete mode 100644 src/test/run-make/graphviz-flowgraph/f12.dot-expected.dot delete mode 100644 src/test/run-make/graphviz-flowgraph/f12.rs delete mode 100644 src/test/run-make/graphviz-flowgraph/f13.dot-expected.dot delete mode 100644 src/test/run-make/graphviz-flowgraph/f13.rs delete mode 100644 src/test/run-make/graphviz-flowgraph/f14.dot-expected.dot delete mode 100644 src/test/run-make/graphviz-flowgraph/f14.rs delete mode 100644 src/test/run-make/graphviz-flowgraph/f15.dot-expected.dot delete mode 100644 src/test/run-make/graphviz-flowgraph/f15.rs delete mode 100644 src/test/run-make/graphviz-flowgraph/f16.dot-expected.dot delete mode 100644 src/test/run-make/graphviz-flowgraph/f16.rs delete mode 100644 src/test/run-make/graphviz-flowgraph/f17.dot-expected.dot delete mode 100644 src/test/run-make/graphviz-flowgraph/f17.rs delete mode 100644 src/test/run-make/graphviz-flowgraph/f18.dot-expected.dot delete mode 100644 src/test/run-make/graphviz-flowgraph/f18.rs delete mode 100644 src/test/run-make/graphviz-flowgraph/f19.dot-expected.dot delete mode 100644 src/test/run-make/graphviz-flowgraph/f19.rs delete mode 100644 src/test/run-make/graphviz-flowgraph/f20.dot-expected.dot delete mode 100644 src/test/run-make/graphviz-flowgraph/f20.rs delete mode 100644 src/test/run-make/graphviz-flowgraph/f21.dot-expected.dot delete mode 100644 src/test/run-make/graphviz-flowgraph/f21.rs delete mode 100644 src/test/run-make/graphviz-flowgraph/f22.dot-expected.dot delete mode 100644 src/test/run-make/graphviz-flowgraph/f22.rs delete mode 100644 src/test/run-make/graphviz-flowgraph/f23.dot-expected.dot delete mode 100644 src/test/run-make/graphviz-flowgraph/f23.rs delete mode 100644 src/test/run-make/graphviz-flowgraph/f24.dot-expected.dot delete mode 100644 src/test/run-make/graphviz-flowgraph/f24.rs delete mode 100644 src/test/run-make/graphviz-flowgraph/f25.dot-expected.dot delete mode 100644 src/test/run-make/graphviz-flowgraph/f25.rs (limited to 'src/test') diff --git a/src/test/run-make/graphviz-flowgraph/Makefile b/src/test/run-make/graphviz-flowgraph/Makefile deleted file mode 100644 index 5740a36359c..00000000000 --- a/src/test/run-make/graphviz-flowgraph/Makefile +++ /dev/null @@ -1,38 +0,0 @@ --include ../tools.mk - -FILES=f00.rs f01.rs f02.rs f03.rs f04.rs f05.rs f06.rs f07.rs \ - f08.rs f09.rs f10.rs f11.rs f12.rs f13.rs f14.rs f15.rs \ - f16.rs f17.rs f18.rs f19.rs f20.rs f21.rs f22.rs f23.rs \ - f24.rs f25.rs - - -# all: $(patsubst %.rs,$(TMPDIR)/%.dot,$(FILES)) $(patsubst %.rs,$(TMPDIR)/%.pp,$(FILES)) -all: $(patsubst %.rs,$(TMPDIR)/%.check,$(FILES)) - - -RUSTC_LIB=$(RUSTC) --crate-type=lib - -define FIND_LAST_BLOCK -LASTBLOCKNUM_$(1) := $(shell $(RUSTC_LIB) -Z unstable-options --pretty=expanded,identified $(1) \ - | grep block - | tail -1 - | sed -e 's@.*/\* block \([0-9]*\) \*/.*@\1@') -endef - -ifeq ($(findstring rustc,$(RUSTC)),) -$(error Must set RUSTC) -endif - -$(TMPDIR)/%.pp: %.rs - $(RUSTC_LIB) --pretty=expanded,identified $< -o $@ - -$(TMPDIR)/%.dot: %.rs - $(eval $(call FIND_LAST_BLOCK,$<)) - $(RUSTC_LIB) -Z unstable-options --unpretty flowgraph,unlabelled=$(LASTBLOCKNUM_$<) $< -o $@.tmp - cat $@.tmp | sed -e 's@ (id=[0-9]*)@@g' \ - -e 's@\[label=""\]@@' \ - -e 's@digraph [a-zA-Z0-9_]* @digraph block @' \ - > $@ - -$(TMPDIR)/%.check: %.rs $(TMPDIR)/%.dot - diff -u $(patsubst %.rs,$(TMPDIR)/%.dot,$<) $(patsubst %.rs,%.dot-expected.dot,$<) diff --git a/src/test/run-make/graphviz-flowgraph/f00.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f00.dot-expected.dot deleted file mode 100644 index 8ea8370ab23..00000000000 --- a/src/test/run-make/graphviz-flowgraph/f00.dot-expected.dot +++ /dev/null @@ -1,9 +0,0 @@ -digraph block { - N0[label="entry"]; - N1[label="exit"]; - N2[label="block { }"]; - N3[label="expr { }"]; - N0 -> N2; - N2 -> N3; - N3 -> N1; -} diff --git a/src/test/run-make/graphviz-flowgraph/f00.rs b/src/test/run-make/graphviz-flowgraph/f00.rs deleted file mode 100644 index 4e7fc7ea9b0..00000000000 --- a/src/test/run-make/graphviz-flowgraph/f00.rs +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2014 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. - -pub fn empty_0() { - -} diff --git a/src/test/run-make/graphviz-flowgraph/f01.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f01.dot-expected.dot deleted file mode 100644 index 5982fbea769..00000000000 --- a/src/test/run-make/graphviz-flowgraph/f01.dot-expected.dot +++ /dev/null @@ -1,13 +0,0 @@ -digraph block { - N0[label="entry"]; - N1[label="exit"]; - N2[label="expr 1"]; - N3[label="stmt 1;"]; - N4[label="block { 1; }"]; - N5[label="expr { 1; }"]; - N0 -> N2; - N2 -> N3; - N3 -> N4; - N4 -> N5; - N5 -> N1; -} diff --git a/src/test/run-make/graphviz-flowgraph/f01.rs b/src/test/run-make/graphviz-flowgraph/f01.rs deleted file mode 100644 index 231aab69e50..00000000000 --- a/src/test/run-make/graphviz-flowgraph/f01.rs +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2014 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. - -pub fn lit_1() { - 1; -} diff --git a/src/test/run-make/graphviz-flowgraph/f02.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f02.dot-expected.dot deleted file mode 100644 index 1639785bd68..00000000000 --- a/src/test/run-make/graphviz-flowgraph/f02.dot-expected.dot +++ /dev/null @@ -1,13 +0,0 @@ -digraph block { - N0[label="entry"]; - N1[label="exit"]; - N2[label="local _x"]; - N3[label="stmt let _x: isize;"]; - N4[label="block { let _x: isize; }"]; - N5[label="expr { let _x: isize; }"]; - N0 -> N2; - N2 -> N3; - N3 -> N4; - N4 -> N5; - N5 -> N1; -} diff --git a/src/test/run-make/graphviz-flowgraph/f02.rs b/src/test/run-make/graphviz-flowgraph/f02.rs deleted file mode 100644 index f7fe1266198..00000000000 --- a/src/test/run-make/graphviz-flowgraph/f02.rs +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2014 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. - -pub fn decl_x_2() { - let _x : isize; -} diff --git a/src/test/run-make/graphviz-flowgraph/f03.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f03.dot-expected.dot deleted file mode 100644 index b0ae00d8167..00000000000 --- a/src/test/run-make/graphviz-flowgraph/f03.dot-expected.dot +++ /dev/null @@ -1,17 +0,0 @@ -digraph block { - N0[label="entry"]; - N1[label="exit"]; - N2[label="expr 3"]; - N3[label="expr 4"]; - N4[label="expr 3 + 4"]; - N5[label="stmt 3 + 4;"]; - N6[label="block { 3 + 4; }"]; - N7[label="expr { 3 + 4; }"]; - N0 -> N2; - N2 -> N3; - N3 -> N4; - N4 -> N5; - N5 -> N6; - N6 -> N7; - N7 -> N1; -} diff --git a/src/test/run-make/graphviz-flowgraph/f03.rs b/src/test/run-make/graphviz-flowgraph/f03.rs deleted file mode 100644 index 2dd71b623c2..00000000000 --- a/src/test/run-make/graphviz-flowgraph/f03.rs +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2014 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. - -pub fn expr_add_3() { - 3 + 4; -} diff --git a/src/test/run-make/graphviz-flowgraph/f04.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f04.dot-expected.dot deleted file mode 100644 index 41ace15a4c6..00000000000 --- a/src/test/run-make/graphviz-flowgraph/f04.dot-expected.dot +++ /dev/null @@ -1,15 +0,0 @@ -digraph block { - N0[label="entry"]; - N1[label="exit"]; - N2[label="expr 4"]; - N3[label="local _x"]; - N4[label="stmt let _x = 4;"]; - N5[label="block { let _x = 4; }"]; - N6[label="expr { let _x = 4; }"]; - N0 -> N2; - N2 -> N3; - N3 -> N4; - N4 -> N5; - N5 -> N6; - N6 -> N1; -} diff --git a/src/test/run-make/graphviz-flowgraph/f04.rs b/src/test/run-make/graphviz-flowgraph/f04.rs deleted file mode 100644 index 2a0ac8ac9e5..00000000000 --- a/src/test/run-make/graphviz-flowgraph/f04.rs +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2014 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. - -pub fn pat_id_4() { - let _x = 4; -} diff --git a/src/test/run-make/graphviz-flowgraph/f05.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f05.dot-expected.dot deleted file mode 100644 index 72b8ae71751..00000000000 --- a/src/test/run-make/graphviz-flowgraph/f05.dot-expected.dot +++ /dev/null @@ -1,23 +0,0 @@ -digraph block { - N0[label="entry"]; - N1[label="exit"]; - N2[label="expr 5"]; - N3[label="expr 55"]; - N4[label="expr (5, 55)"]; - N5[label="local _x"]; - N6[label="local _y"]; - N7[label="pat (_x, _y)"]; - N8[label="stmt let (_x, _y) = (5, 55);"]; - N9[label="block { let (_x, _y) = (5, 55); }"]; - N10[label="expr { let (_x, _y) = (5, 55); }"]; - N0 -> N2; - N2 -> N3; - N3 -> N4; - N4 -> N5; - N5 -> N6; - N6 -> N7; - N7 -> N8; - N8 -> N9; - N9 -> N10; - N10 -> N1; -} diff --git a/src/test/run-make/graphviz-flowgraph/f05.rs b/src/test/run-make/graphviz-flowgraph/f05.rs deleted file mode 100644 index 616d822bed0..00000000000 --- a/src/test/run-make/graphviz-flowgraph/f05.rs +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2014 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. - -pub fn pat_tup_5() { - let (_x, _y) = (5, 55); -} diff --git a/src/test/run-make/graphviz-flowgraph/f06.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f06.dot-expected.dot deleted file mode 100644 index acba71ef625..00000000000 --- a/src/test/run-make/graphviz-flowgraph/f06.dot-expected.dot +++ /dev/null @@ -1,19 +0,0 @@ -digraph block { - N0[label="entry"]; - N1[label="exit"]; - N2[label="expr 6"]; - N3[label="expr S6{val: 6,}"]; - N4[label="local _x"]; - N5[label="pat S6 { val: _x }"]; - N6[label="stmt let S6 { val: _x } = S6{val: 6,};"]; - N7[label="block { let S6 { val: _x } = S6{val: 6,}; }"]; - N8[label="expr { let S6 { val: _x } = S6{val: 6,}; }"]; - N0 -> N2; - N2 -> N3; - N3 -> N4; - N4 -> N5; - N5 -> N6; - N6 -> N7; - N7 -> N8; - N8 -> N1; -} diff --git a/src/test/run-make/graphviz-flowgraph/f06.rs b/src/test/run-make/graphviz-flowgraph/f06.rs deleted file mode 100644 index 538ef2af898..00000000000 --- a/src/test/run-make/graphviz-flowgraph/f06.rs +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright 2014 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. - -struct S6 { val: isize } -pub fn pat_struct_6() { - let S6 { val: _x } = S6{ val: 6 }; -} diff --git a/src/test/run-make/graphviz-flowgraph/f07.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f07.dot-expected.dot deleted file mode 100644 index 251e2b39f14..00000000000 --- a/src/test/run-make/graphviz-flowgraph/f07.dot-expected.dot +++ /dev/null @@ -1,39 +0,0 @@ -digraph block { - N0[label="entry"]; - N1[label="exit"]; - N2[label="expr 7"]; - N3[label="expr 77"]; - N4[label="expr 777"]; - N5[label="expr 7777"]; - N6[label="expr [7, 77, 777, 7777]"]; - N7[label="expr match [7, 77, 777, 7777] { [x, y, ..] => x + y, }"]; - N8[label="(dummy_node)"]; - N9[label="local x"]; - N10[label="local y"]; - N11[label="pat _"]; - N12[label="pat [x, y, ..]"]; - N13[label="expr x"]; - N14[label="expr y"]; - N15[label="expr x + y"]; - N16[label="stmt match [7, 77, 777, 7777] { [x, y, ..] => x + y, };"]; - N17[label="block { match [7, 77, 777, 7777] { [x, y, ..] => x + y, }; }"]; - N18[label="expr { match [7, 77, 777, 7777] { [x, y, ..] => x + y, }; }"]; - N0 -> N2; - N2 -> N3; - N3 -> N4; - N4 -> N5; - N5 -> N6; - N6 -> N9; - N9 -> N10; - N10 -> N11; - N11 -> N12; - N12 -> N8; - N8 -> N13; - N13 -> N14; - N14 -> N15; - N15 -> N7; - N7 -> N16; - N16 -> N17; - N17 -> N18; - N18 -> N1; -} diff --git a/src/test/run-make/graphviz-flowgraph/f07.rs b/src/test/run-make/graphviz-flowgraph/f07.rs deleted file mode 100644 index f36b8d0abc7..00000000000 --- a/src/test/run-make/graphviz-flowgraph/f07.rs +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![feature(slice_patterns)] - -pub fn pat_vec_7() { - match [7, 77, 777, 7777] { - [x, y, ..] => x + y - }; -} diff --git a/src/test/run-make/graphviz-flowgraph/f08.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f08.dot-expected.dot deleted file mode 100644 index e2779c9414a..00000000000 --- a/src/test/run-make/graphviz-flowgraph/f08.dot-expected.dot +++ /dev/null @@ -1,38 +0,0 @@ -digraph block { - N0[label="entry"]; - N1[label="exit"]; - N2[label="expr 8"]; - N3[label="local x"]; - N4[label="stmt let x = 8;"]; - N5[label="local _y"]; - N6[label="stmt let _y;"]; - N7[label="expr x"]; - N8[label="expr 88"]; - N9[label="expr x > 88"]; - N10[label="expr 888"]; - N11[label="expr _y"]; - N12[label="expr _y = 888"]; - N13[label="stmt _y = 888;"]; - N14[label="block { _y = 888; }"]; - N15[label="expr if x > 88 { _y = 888; }"]; - N16[label="block { let x = 8; let _y; if x > 88 { _y = 888; } }"]; - N17[label="expr { let x = 8; let _y; if x > 88 { _y = 888; } }"]; - N0 -> N2; - N2 -> N3; - N3 -> N4; - N4 -> N5; - N5 -> N6; - N6 -> N7; - N7 -> N8; - N8 -> N9; - N9 -> N10; - N10 -> N11; - N11 -> N12; - N12 -> N13; - N13 -> N14; - N9 -> N15; - N14 -> N15; - N15 -> N16; - N16 -> N17; - N17 -> N1; -} diff --git a/src/test/run-make/graphviz-flowgraph/f08.rs b/src/test/run-make/graphviz-flowgraph/f08.rs deleted file mode 100644 index 6ba7b03d54d..00000000000 --- a/src/test/run-make/graphviz-flowgraph/f08.rs +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2014 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. - -pub fn expr_if_onearm_8() { - let x = 8; let _y; - if x > 88 { - _y = 888; - } -} diff --git a/src/test/run-make/graphviz-flowgraph/f09.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f09.dot-expected.dot deleted file mode 100644 index 536abde91e8..00000000000 --- a/src/test/run-make/graphviz-flowgraph/f09.dot-expected.dot +++ /dev/null @@ -1,54 +0,0 @@ -digraph block { - N0[label="entry"]; - N1[label="exit"]; - N2[label="expr 91"]; - N3[label="local x"]; - N4[label="stmt let x = 91;"]; - N5[label="local _y"]; - N6[label="stmt let _y;"]; - N7[label="expr x"]; - N8[label="expr 92"]; - N9[label="expr x > 92"]; - N10[label="expr 93"]; - N11[label="expr _y"]; - N12[label="expr _y = 93"]; - N13[label="stmt _y = 93;"]; - N14[label="block { _y = 93; }"]; - N15[label="expr 94"]; - N16[label="expr 95"]; - N17[label="expr 94 + 95"]; - N18[label="expr _y"]; - N19[label="expr _y = 94 + 95"]; - N20[label="stmt _y = 94 + 95;"]; - N21[label="block { _y = 94 + 95; }"]; - N22[label="expr { _y = 94 + 95; }"]; - N23[label="expr if x > 92 { _y = 93; } else { _y = 94 + 95; }"]; - N24[label="block { let x = 91; let _y; if x > 92 { _y = 93; } else { _y = 94 + 95; } }"]; - N25[label="expr { let x = 91; let _y; if x > 92 { _y = 93; } else { _y = 94 + 95; } }"]; - N0 -> N2; - N2 -> N3; - N3 -> N4; - N4 -> N5; - N5 -> N6; - N6 -> N7; - N7 -> N8; - N8 -> N9; - N9 -> N10; - N10 -> N11; - N11 -> N12; - N12 -> N13; - N13 -> N14; - N9 -> N15; - N15 -> N16; - N16 -> N17; - N17 -> N18; - N18 -> N19; - N19 -> N20; - N20 -> N21; - N21 -> N22; - N14 -> N23; - N22 -> N23; - N23 -> N24; - N24 -> N25; - N25 -> N1; -} diff --git a/src/test/run-make/graphviz-flowgraph/f09.rs b/src/test/run-make/graphviz-flowgraph/f09.rs deleted file mode 100644 index a78ccb8a937..00000000000 --- a/src/test/run-make/graphviz-flowgraph/f09.rs +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2014 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. - -pub fn expr_if_twoarm_9() { - let x = 91; let _y; - if x > 92 { - _y = 93; - } else { - _y = 94+95; - } -} diff --git a/src/test/run-make/graphviz-flowgraph/f10.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f10.dot-expected.dot deleted file mode 100644 index 07b9c744a71..00000000000 --- a/src/test/run-make/graphviz-flowgraph/f10.dot-expected.dot +++ /dev/null @@ -1,36 +0,0 @@ -digraph block { - N0[label="entry"]; - N1[label="exit"]; - N2[label="expr 10"]; - N3[label="local mut x"]; - N4[label="stmt let mut x = 10;"]; - N5[label="(dummy_node)"]; - N6[label="expr while x > 0 { x -= 1; }"]; - N7[label="expr x"]; - N8[label="expr 0"]; - N9[label="expr x > 0"]; - N10[label="expr 1"]; - N11[label="expr x"]; - N12[label="expr x -= 1"]; - N13[label="stmt x -= 1;"]; - N14[label="block { x -= 1; }"]; - N15[label="block { let mut x = 10; while x > 0 { x -= 1; } }"]; - N16[label="expr { let mut x = 10; while x > 0 { x -= 1; } }"]; - N0 -> N2; - N2 -> N3; - N3 -> N4; - N4 -> N5; - N5 -> N7; - N7 -> N8; - N8 -> N9; - N9 -> N6; - N9 -> N10; - N10 -> N11; - N11 -> N12; - N12 -> N13; - N13 -> N14; - N14 -> N5; - N6 -> N15; - N15 -> N16; - N16 -> N1; -} diff --git a/src/test/run-make/graphviz-flowgraph/f10.rs b/src/test/run-make/graphviz-flowgraph/f10.rs deleted file mode 100644 index 0ca7cc5ee86..00000000000 --- a/src/test/run-make/graphviz-flowgraph/f10.rs +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2014 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. - -pub fn expr_while_10() { - let mut x = 10; - while x > 0 { - x -= 1; - } -} diff --git a/src/test/run-make/graphviz-flowgraph/f11.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f11.dot-expected.dot deleted file mode 100644 index 70034d299ba..00000000000 --- a/src/test/run-make/graphviz-flowgraph/f11.dot-expected.dot +++ /dev/null @@ -1,35 +0,0 @@ -digraph block { - N0[label="entry"]; - N1[label="exit"]; - N2[label="expr 11"]; - N3[label="local mut _x"]; - N4[label="stmt let mut _x = 11;"]; - N5[label="(dummy_node)"]; - N6[label="expr loop { _x -= 1; }"]; - N7[label="expr 1"]; - N8[label="expr _x"]; - N9[label="expr _x -= 1"]; - N10[label="stmt _x -= 1;"]; - N11[label="block { _x -= 1; }"]; - N12[label="stmt loop { _x -= 1; }"]; - N13[label="expr \"unreachable\""]; - N14[label="stmt \"unreachable\";"]; - N15[label="block { let mut _x = 11; loop { _x -= 1; } \"unreachable\"; }"]; - N16[label="expr { let mut _x = 11; loop { _x -= 1; } \"unreachable\"; }"]; - N0 -> N2; - N2 -> N3; - N3 -> N4; - N4 -> N5; - N5 -> N7; - N7 -> N8; - N8 -> N9; - N9 -> N10; - N10 -> N11; - N11 -> N5; - N6 -> N12; - N12 -> N13; - N13 -> N14; - N14 -> N15; - N15 -> N16; - N16 -> N1; -} diff --git a/src/test/run-make/graphviz-flowgraph/f11.rs b/src/test/run-make/graphviz-flowgraph/f11.rs deleted file mode 100644 index d0f3452119e..00000000000 --- a/src/test/run-make/graphviz-flowgraph/f11.rs +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2014 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. - -#[allow(unreachable_code)] -pub fn expr_loop_11() { - let mut _x = 11; - loop { - _x -= 1; - } - "unreachable"; -} diff --git a/src/test/run-make/graphviz-flowgraph/f12.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f12.dot-expected.dot deleted file mode 100644 index 245afc43504..00000000000 --- a/src/test/run-make/graphviz-flowgraph/f12.dot-expected.dot +++ /dev/null @@ -1,50 +0,0 @@ -digraph block { - N0[label="entry"]; - N1[label="exit"]; - N2[label="expr 12"]; - N3[label="local mut x"]; - N4[label="stmt let mut x = 12;"]; - N5[label="(dummy_node)"]; - N6[label="expr loop { x -= 1; if x == 2 { break ; \"unreachable\"; } }"]; - N7[label="expr 1"]; - N8[label="expr x"]; - N9[label="expr x -= 1"]; - N10[label="stmt x -= 1;"]; - N11[label="expr x"]; - N12[label="expr 2"]; - N13[label="expr x == 2"]; - N14[label="expr break"]; - N15[label="(dummy_node)"]; - N16[label="stmt break ;"]; - N17[label="expr \"unreachable\""]; - N18[label="stmt \"unreachable\";"]; - N19[label="block { break ; \"unreachable\"; }"]; - N20[label="expr if x == 2 { break ; \"unreachable\"; }"]; - N21[label="block { x -= 1; if x == 2 { break ; \"unreachable\"; } }"]; - N22[label="block { let mut x = 12; loop { x -= 1; if x == 2 { break ; \"unreachable\"; } } }"]; - N23[label="expr { let mut x = 12; loop { x -= 1; if x == 2 { break ; \"unreachable\"; } } }"]; - N0 -> N2; - N2 -> N3; - N3 -> N4; - N4 -> N5; - N5 -> N7; - N7 -> N8; - N8 -> N9; - N9 -> N10; - N10 -> N11; - N11 -> N12; - N12 -> N13; - N13 -> N14; - N14 -> N6; - N15 -> N16; - N16 -> N17; - N17 -> N18; - N18 -> N19; - N13 -> N20; - N19 -> N20; - N20 -> N21; - N21 -> N5; - N6 -> N22; - N22 -> N23; - N23 -> N1; -} diff --git a/src/test/run-make/graphviz-flowgraph/f12.rs b/src/test/run-make/graphviz-flowgraph/f12.rs deleted file mode 100644 index 90b146340b6..00000000000 --- a/src/test/run-make/graphviz-flowgraph/f12.rs +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2014 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. - -#[allow(unreachable_code)] -pub fn expr_loop_12() { - let mut x = 12; - loop { - x -= 1; - if x == 2 { break; "unreachable"; } - } -} diff --git a/src/test/run-make/graphviz-flowgraph/f13.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f13.dot-expected.dot deleted file mode 100644 index 0f268bd0f2a..00000000000 --- a/src/test/run-make/graphviz-flowgraph/f13.dot-expected.dot +++ /dev/null @@ -1,54 +0,0 @@ -digraph block { - N0[label="entry"]; - N1[label="exit"]; - N2[label="expr E13::E13b"]; - N3[label="expr 13"]; - N4[label="expr E13::E13b(13)"]; - N5[label="local x"]; - N6[label="stmt let x = E13::E13b(13);"]; - N7[label="local _y"]; - N8[label="stmt let _y;"]; - N9[label="expr x"]; - N10[label="expr match x { E13::E13a => _y = 1, E13::E13b(v) => _y = v + 1, }"]; - N11[label="(dummy_node)"]; - N12[label="pat E13::E13a"]; - N13[label="expr 1"]; - N14[label="expr _y"]; - N15[label="expr _y = 1"]; - N16[label="(dummy_node)"]; - N17[label="local v"]; - N18[label="pat E13::E13b(v)"]; - N19[label="expr v"]; - N20[label="expr 1"]; - N21[label="expr v + 1"]; - N22[label="expr _y"]; - N23[label="expr _y = v + 1"]; - N24[label="block {\l let x = E13::E13b(13);\l let _y;\l match x { E13::E13a => _y = 1, E13::E13b(v) => _y = v + 1, }\l}\l"]; - N25[label="expr {\l let x = E13::E13b(13);\l let _y;\l match x { E13::E13a => _y = 1, E13::E13b(v) => _y = v + 1, }\l}\l"]; - N0 -> N2; - N2 -> N3; - N3 -> N4; - N4 -> N5; - N5 -> N6; - N6 -> N7; - N7 -> N8; - N8 -> N9; - N9 -> N12; - N12 -> N11; - N11 -> N13; - N13 -> N14; - N14 -> N15; - N15 -> N10; - N9 -> N17; - N17 -> N18; - N18 -> N16; - N16 -> N19; - N19 -> N20; - N20 -> N21; - N21 -> N22; - N22 -> N23; - N23 -> N10; - N10 -> N24; - N24 -> N25; - N25 -> N1; -} diff --git a/src/test/run-make/graphviz-flowgraph/f13.rs b/src/test/run-make/graphviz-flowgraph/f13.rs deleted file mode 100644 index babb283c734..00000000000 --- a/src/test/run-make/graphviz-flowgraph/f13.rs +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2014 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. - -enum E13 { E13a, E13b(isize) } -pub fn expr_match_13() { - let x = E13::E13b(13); let _y; - match x { - E13::E13a => _y = 1, - E13::E13b(v) => _y = v + 1, - } -} diff --git a/src/test/run-make/graphviz-flowgraph/f14.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f14.dot-expected.dot deleted file mode 100644 index 719a6cf2619..00000000000 --- a/src/test/run-make/graphviz-flowgraph/f14.dot-expected.dot +++ /dev/null @@ -1,36 +0,0 @@ -digraph block { - N0[label="entry"]; - N1[label="exit"]; - N2[label="expr 14"]; - N3[label="local x"]; - N4[label="stmt let x = 14;"]; - N5[label="expr x"]; - N6[label="expr 1"]; - N7[label="expr x > 1"]; - N8[label="expr return"]; - N9[label="(dummy_node)"]; - N10[label="stmt return;"]; - N11[label="expr \"unreachable\""]; - N12[label="stmt \"unreachable\";"]; - N13[label="block { return; \"unreachable\"; }"]; - N14[label="expr if x > 1 { return; \"unreachable\"; }"]; - N15[label="block { let x = 14; if x > 1 { return; \"unreachable\"; } }"]; - N16[label="expr { let x = 14; if x > 1 { return; \"unreachable\"; } }"]; - N0 -> N2; - N2 -> N3; - N3 -> N4; - N4 -> N5; - N5 -> N6; - N6 -> N7; - N7 -> N8; - N8 -> N1; - N9 -> N10; - N10 -> N11; - N11 -> N12; - N12 -> N13; - N7 -> N14; - N13 -> N14; - N14 -> N15; - N15 -> N16; - N16 -> N1; -} diff --git a/src/test/run-make/graphviz-flowgraph/f14.rs b/src/test/run-make/graphviz-flowgraph/f14.rs deleted file mode 100644 index 98ff095c831..00000000000 --- a/src/test/run-make/graphviz-flowgraph/f14.rs +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2014 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. - -#[allow(unreachable_code)] -pub fn expr_ret_14() { - let x = 14; - if x > 1 { - return; - "unreachable"; - } -} diff --git a/src/test/run-make/graphviz-flowgraph/f15.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f15.dot-expected.dot deleted file mode 100644 index d8cbd8411e2..00000000000 --- a/src/test/run-make/graphviz-flowgraph/f15.dot-expected.dot +++ /dev/null @@ -1,105 +0,0 @@ -digraph block { - N0[label="entry"]; - N1[label="exit"]; - N2[label="expr 15"]; - N3[label="local mut x"]; - N4[label="stmt let mut x = 15;"]; - N5[label="expr 151"]; - N6[label="local mut y"]; - N7[label="stmt let mut y = 151;"]; - N8[label="(dummy_node)"]; - N9[label="expr \'outer:\l loop {\l \'inner:\l loop {\l if x == 1 { break \'outer ; \"unreachable\"; }\l if y >= 2 { break ; \"unreachable\"; }\l y -= 3;\l }\l y -= 4;\l x -= 5;\l }\l"]; - N10[label="(dummy_node)"]; - N11[label="expr \'inner:\l loop {\l if x == 1 { break \'outer ; \"unreachable\"; }\l if y >= 2 { break ; \"unreachable\"; }\l y -= 3;\l }\l"]; - N12[label="expr x"]; - N13[label="expr 1"]; - N14[label="expr x == 1"]; - N15[label="expr break \'outer"]; - N16[label="(dummy_node)"]; - N17[label="stmt break \'outer ;"]; - N18[label="expr \"unreachable\""]; - N19[label="stmt \"unreachable\";"]; - N20[label="block { break \'outer ; \"unreachable\"; }"]; - N21[label="expr if x == 1 { break \'outer ; \"unreachable\"; }"]; - N22[label="stmt if x == 1 { break \'outer ; \"unreachable\"; }"]; - N23[label="expr y"]; - N24[label="expr 2"]; - N25[label="expr y >= 2"]; - N26[label="expr break"]; - N27[label="(dummy_node)"]; - N28[label="stmt break ;"]; - N29[label="expr \"unreachable\""]; - N30[label="stmt \"unreachable\";"]; - N31[label="block { break ; \"unreachable\"; }"]; - N32[label="expr if y >= 2 { break ; \"unreachable\"; }"]; - N33[label="stmt if y >= 2 { break ; \"unreachable\"; }"]; - N34[label="expr 3"]; - N35[label="expr y"]; - N36[label="expr y -= 3"]; - N37[label="stmt y -= 3;"]; - N38[label="block {\l if x == 1 { break \'outer ; \"unreachable\"; }\l if y >= 2 { break ; \"unreachable\"; }\l y -= 3;\l}\l"]; - N39[label="stmt \'inner:\l loop {\l if x == 1 { break \'outer ; \"unreachable\"; }\l if y >= 2 { break ; \"unreachable\"; }\l y -= 3;\l }\l"]; - N40[label="expr 4"]; - N41[label="expr y"]; - N42[label="expr y -= 4"]; - N43[label="stmt y -= 4;"]; - N44[label="expr 5"]; - N45[label="expr x"]; - N46[label="expr x -= 5"]; - N47[label="stmt x -= 5;"]; - N48[label="block {\l \'inner:\l loop {\l if x == 1 { break \'outer ; \"unreachable\"; }\l if y >= 2 { break ; \"unreachable\"; }\l y -= 3;\l }\l y -= 4;\l x -= 5;\l}\l"]; - N49[label="block {\l let mut x = 15;\l let mut y = 151;\l \'outer:\l loop {\l \'inner:\l loop {\l if x == 1 { break \'outer ; \"unreachable\"; }\l if y >= 2 { break ; \"unreachable\"; }\l y -= 3;\l }\l y -= 4;\l x -= 5;\l }\l}\l"]; - N50[label="expr {\l let mut x = 15;\l let mut y = 151;\l \'outer:\l loop {\l \'inner:\l loop {\l if x == 1 { break \'outer ; \"unreachable\"; }\l if y >= 2 { break ; \"unreachable\"; }\l y -= 3;\l }\l y -= 4;\l x -= 5;\l }\l}\l"]; - N0 -> N2; - N2 -> N3; - N3 -> N4; - N4 -> N5; - N5 -> N6; - N6 -> N7; - N7 -> N8; - N8 -> N10; - N10 -> N12; - N12 -> N13; - N13 -> N14; - N14 -> N15; - N15 -> N9; - N16 -> N17; - N17 -> N18; - N18 -> N19; - N19 -> N20; - N14 -> N21; - N20 -> N21; - N21 -> N22; - N22 -> N23; - N23 -> N24; - N24 -> N25; - N25 -> N26; - N26 -> N11; - N27 -> N28; - N28 -> N29; - N29 -> N30; - N30 -> N31; - N25 -> N32; - N31 -> N32; - N32 -> N33; - N33 -> N34; - N34 -> N35; - N35 -> N36; - N36 -> N37; - N37 -> N38; - N38 -> N10; - N11 -> N39; - N39 -> N40; - N40 -> N41; - N41 -> N42; - N42 -> N43; - N43 -> N44; - N44 -> N45; - N45 -> N46; - N46 -> N47; - N47 -> N48; - N48 -> N8; - N9 -> N49; - N49 -> N50; - N50 -> N1; -} diff --git a/src/test/run-make/graphviz-flowgraph/f15.rs b/src/test/run-make/graphviz-flowgraph/f15.rs deleted file mode 100644 index 056458e5558..00000000000 --- a/src/test/run-make/graphviz-flowgraph/f15.rs +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright 2014 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. - -#[allow(unreachable_code)] -pub fn expr_break_label_15() { - let mut x = 15; - let mut y = 151; - 'outer: loop { - 'inner: loop { - if x == 1 { - break 'outer; - "unreachable"; - } - if y >= 2 { - break; - "unreachable"; - } - y -= 3; - } - y -= 4; - x -= 5; - } -} diff --git a/src/test/run-make/graphviz-flowgraph/f16.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f16.dot-expected.dot deleted file mode 100644 index b11881247fb..00000000000 --- a/src/test/run-make/graphviz-flowgraph/f16.dot-expected.dot +++ /dev/null @@ -1,111 +0,0 @@ -digraph block { - N0[label="entry"]; - N1[label="exit"]; - N2[label="expr 16"]; - N3[label="local mut x"]; - N4[label="stmt let mut x = 16;"]; - N5[label="expr 16"]; - N6[label="local mut y"]; - N7[label="stmt let mut y = 16;"]; - N8[label="(dummy_node)"]; - N9[label="expr \'outer:\l loop {\l \'inner:\l loop {\l if x == 1 { continue \'outer ; \"unreachable\"; }\l if y >= 1 { break ; \"unreachable\"; }\l y -= 1;\l }\l y -= 1;\l x -= 1;\l }\l"]; - N10[label="(dummy_node)"]; - N11[label="expr \'inner:\l loop {\l if x == 1 { continue \'outer ; \"unreachable\"; }\l if y >= 1 { break ; \"unreachable\"; }\l y -= 1;\l }\l"]; - N12[label="expr x"]; - N13[label="expr 1"]; - N14[label="expr x == 1"]; - N15[label="expr continue \'outer"]; - N16[label="(dummy_node)"]; - N17[label="stmt continue \'outer ;"]; - N18[label="expr \"unreachable\""]; - N19[label="stmt \"unreachable\";"]; - N20[label="block { continue \'outer ; \"unreachable\"; }"]; - N21[label="expr if x == 1 { continue \'outer ; \"unreachable\"; }"]; - N22[label="stmt if x == 1 { continue \'outer ; \"unreachable\"; }"]; - N23[label="expr y"]; - N24[label="expr 1"]; - N25[label="expr y >= 1"]; - N26[label="expr break"]; - N27[label="(dummy_node)"]; - N28[label="stmt break ;"]; - N29[label="expr \"unreachable\""]; - N30[label="stmt \"unreachable\";"]; - N31[label="block { break ; \"unreachable\"; }"]; - N32[label="expr if y >= 1 { break ; \"unreachable\"; }"]; - N33[label="stmt if y >= 1 { break ; \"unreachable\"; }"]; - N34[label="expr 1"]; - N35[label="expr y"]; - N36[label="expr y -= 1"]; - N37[label="stmt y -= 1;"]; - N38[label="block {\l if x == 1 { continue \'outer ; \"unreachable\"; }\l if y >= 1 { break ; \"unreachable\"; }\l y -= 1;\l}\l"]; - N39[label="stmt \'inner:\l loop {\l if x == 1 { continue \'outer ; \"unreachable\"; }\l if y >= 1 { break ; \"unreachable\"; }\l y -= 1;\l }\l"]; - N40[label="expr 1"]; - N41[label="expr y"]; - N42[label="expr y -= 1"]; - N43[label="stmt y -= 1;"]; - N44[label="expr 1"]; - N45[label="expr x"]; - N46[label="expr x -= 1"]; - N47[label="stmt x -= 1;"]; - N48[label="block {\l \'inner:\l loop {\l if x == 1 { continue \'outer ; \"unreachable\"; }\l if y >= 1 { break ; \"unreachable\"; }\l y -= 1;\l }\l y -= 1;\l x -= 1;\l}\l"]; - N49[label="stmt \'outer:\l loop {\l \'inner:\l loop {\l if x == 1 { continue \'outer ; \"unreachable\"; }\l if y >= 1 { break ; \"unreachable\"; }\l y -= 1;\l }\l y -= 1;\l x -= 1;\l }\l"]; - N50[label="expr \"unreachable\""]; - N51[label="stmt \"unreachable\";"]; - N52[label="block {\l let mut x = 16;\l let mut y = 16;\l \'outer:\l loop {\l \'inner:\l loop {\l if x == 1 { continue \'outer ; \"unreachable\"; }\l if y >= 1 { break ; \"unreachable\"; }\l y -= 1;\l }\l y -= 1;\l x -= 1;\l }\l \"unreachable\";\l}\l"]; - N53[label="expr {\l let mut x = 16;\l let mut y = 16;\l \'outer:\l loop {\l \'inner:\l loop {\l if x == 1 { continue \'outer ; \"unreachable\"; }\l if y >= 1 { break ; \"unreachable\"; }\l y -= 1;\l }\l y -= 1;\l x -= 1;\l }\l \"unreachable\";\l}\l"]; - N0 -> N2; - N2 -> N3; - N3 -> N4; - N4 -> N5; - N5 -> N6; - N6 -> N7; - N7 -> N8; - N8 -> N10; - N10 -> N12; - N12 -> N13; - N13 -> N14; - N14 -> N15; - N15 -> N8; - N16 -> N17; - N17 -> N18; - N18 -> N19; - N19 -> N20; - N14 -> N21; - N20 -> N21; - N21 -> N22; - N22 -> N23; - N23 -> N24; - N24 -> N25; - N25 -> N26; - N26 -> N11; - N27 -> N28; - N28 -> N29; - N29 -> N30; - N30 -> N31; - N25 -> N32; - N31 -> N32; - N32 -> N33; - N33 -> N34; - N34 -> N35; - N35 -> N36; - N36 -> N37; - N37 -> N38; - N38 -> N10; - N11 -> N39; - N39 -> N40; - N40 -> N41; - N41 -> N42; - N42 -> N43; - N43 -> N44; - N44 -> N45; - N45 -> N46; - N46 -> N47; - N47 -> N48; - N48 -> N8; - N9 -> N49; - N49 -> N50; - N50 -> N51; - N51 -> N52; - N52 -> N53; - N53 -> N1; -} diff --git a/src/test/run-make/graphviz-flowgraph/f16.rs b/src/test/run-make/graphviz-flowgraph/f16.rs deleted file mode 100644 index e225b0080e5..00000000000 --- a/src/test/run-make/graphviz-flowgraph/f16.rs +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright 2014 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. - -#[allow(unreachable_code)] -pub fn expr_continue_label_16() { - let mut x = 16; - let mut y = 16; - 'outer: loop { - 'inner: loop { - if x == 1 { - continue 'outer; - "unreachable"; - } - if y >= 1 { - break; - "unreachable"; - } - y -= 1; - } - y -= 1; - x -= 1; - } - "unreachable"; -} diff --git a/src/test/run-make/graphviz-flowgraph/f17.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f17.dot-expected.dot deleted file mode 100644 index 705eece7755..00000000000 --- a/src/test/run-make/graphviz-flowgraph/f17.dot-expected.dot +++ /dev/null @@ -1,21 +0,0 @@ -digraph block { - N0[label="entry"]; - N1[label="exit"]; - N2[label="expr 1"]; - N3[label="expr 7"]; - N4[label="expr 17"]; - N5[label="expr [1, 7, 17]"]; - N6[label="local _v"]; - N7[label="stmt let _v = [1, 7, 17];"]; - N8[label="block { let _v = [1, 7, 17]; }"]; - N9[label="expr { let _v = [1, 7, 17]; }"]; - N0 -> N2; - N2 -> N3; - N3 -> N4; - N4 -> N5; - N5 -> N6; - N6 -> N7; - N7 -> N8; - N8 -> N9; - N9 -> N1; -} diff --git a/src/test/run-make/graphviz-flowgraph/f17.rs b/src/test/run-make/graphviz-flowgraph/f17.rs deleted file mode 100644 index 23f5bb8a1eb..00000000000 --- a/src/test/run-make/graphviz-flowgraph/f17.rs +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2014 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. - -pub fn expr_vec_17() { - let _v = [1, 7, 17]; -} diff --git a/src/test/run-make/graphviz-flowgraph/f18.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f18.dot-expected.dot deleted file mode 100644 index b0491fe6e27..00000000000 --- a/src/test/run-make/graphviz-flowgraph/f18.dot-expected.dot +++ /dev/null @@ -1,23 +0,0 @@ -digraph block { - N0[label="entry"]; - N1[label="exit"]; - N2[label="stmt fn inner(x: isize) -> isize { x + x }"]; - N3[label="expr inner"]; - N4[label="expr inner"]; - N5[label="expr 18"]; - N6[label="expr inner(18)"]; - N7[label="expr inner(inner(18))"]; - N8[label="stmt inner(inner(18));"]; - N9[label="block {\l fn inner(x: isize) -> isize { x + x }\l inner(inner(18));\l}\l"]; - N10[label="expr {\l fn inner(x: isize) -> isize { x + x }\l inner(inner(18));\l}\l"]; - N0 -> N2; - N2 -> N3; - N3 -> N4; - N4 -> N5; - N5 -> N6; - N6 -> N7; - N7 -> N8; - N8 -> N9; - N9 -> N10; - N10 -> N1; -} diff --git a/src/test/run-make/graphviz-flowgraph/f18.rs b/src/test/run-make/graphviz-flowgraph/f18.rs deleted file mode 100644 index cbf8aa5db43..00000000000 --- a/src/test/run-make/graphviz-flowgraph/f18.rs +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright 2014 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. - -pub fn expr_call_18() { - fn inner(x:isize) -> isize { x + x } - inner(inner(18)); -} diff --git a/src/test/run-make/graphviz-flowgraph/f19.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f19.dot-expected.dot deleted file mode 100644 index 223978c3d76..00000000000 --- a/src/test/run-make/graphviz-flowgraph/f19.dot-expected.dot +++ /dev/null @@ -1,29 +0,0 @@ -digraph block { - N0[label="entry"]; - N1[label="exit"]; - N2[label="stmt struct S19 {\l x: isize,\l}\l"]; - N3[label="stmt impl S19 {\l fn inner(self: Self) -> S19 { S19{x: self.x + self.x,} }\l}\l"]; - N4[label="expr 19"]; - N5[label="expr S19{x: 19,}"]; - N6[label="local s"]; - N7[label="stmt let s = S19{x: 19,};"]; - N8[label="expr s"]; - N9[label="expr s.inner()"]; - N10[label="expr s.inner().inner()"]; - N11[label="stmt s.inner().inner();"]; - N12[label="block {\l struct S19 {\l x: isize,\l }\l impl S19 {\l fn inner(self: Self) -> S19 { S19{x: self.x + self.x,} }\l }\l let s = S19{x: 19,};\l s.inner().inner();\l}\l"]; - N13[label="expr {\l struct S19 {\l x: isize,\l }\l impl S19 {\l fn inner(self: Self) -> S19 { S19{x: self.x + self.x,} }\l }\l let s = S19{x: 19,};\l s.inner().inner();\l}\l"]; - N0 -> N2; - N2 -> N3; - N3 -> N4; - N4 -> N5; - N5 -> N6; - N6 -> N7; - N7 -> N8; - N8 -> N9; - N9 -> N10; - N10 -> N11; - N11 -> N12; - N12 -> N13; - N13 -> N1; -} diff --git a/src/test/run-make/graphviz-flowgraph/f19.rs b/src/test/run-make/graphviz-flowgraph/f19.rs deleted file mode 100644 index 78c15dd64ad..00000000000 --- a/src/test/run-make/graphviz-flowgraph/f19.rs +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2014 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. - -pub fn expr_method_call_19() { - struct S19 { x: isize } - impl S19 { fn inner(self) -> S19 { S19 { x: self.x + self.x } } } - let s = S19 { x: 19 }; - s.inner().inner(); -} diff --git a/src/test/run-make/graphviz-flowgraph/f20.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f20.dot-expected.dot deleted file mode 100644 index 120eab4dac9..00000000000 --- a/src/test/run-make/graphviz-flowgraph/f20.dot-expected.dot +++ /dev/null @@ -1,29 +0,0 @@ -digraph block { - N0[label="entry"]; - N1[label="exit"]; - N2[label="expr 2"]; - N3[label="expr 0"]; - N4[label="expr 20"]; - N5[label="expr [2, 0, 20]"]; - N6[label="local v"]; - N7[label="stmt let v = [2, 0, 20];"]; - N8[label="expr v"]; - N9[label="expr 20"]; - N10[label="expr v[20]"]; - N11[label="stmt v[20];"]; - N12[label="block { let v = [2, 0, 20]; v[20]; }"]; - N13[label="expr { let v = [2, 0, 20]; v[20]; }"]; - N0 -> N2; - N2 -> N3; - N3 -> N4; - N4 -> N5; - N5 -> N6; - N6 -> N7; - N7 -> N8; - N8 -> N9; - N9 -> N10; - N10 -> N11; - N11 -> N12; - N12 -> N13; - N13 -> N1; -} diff --git a/src/test/run-make/graphviz-flowgraph/f20.rs b/src/test/run-make/graphviz-flowgraph/f20.rs deleted file mode 100644 index d7349932355..00000000000 --- a/src/test/run-make/graphviz-flowgraph/f20.rs +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright 2014 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. - -pub fn expr_index_20() { - let v = [2, 0, 20]; - v[20]; -} diff --git a/src/test/run-make/graphviz-flowgraph/f21.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f21.dot-expected.dot deleted file mode 100644 index 370dcdd8554..00000000000 --- a/src/test/run-make/graphviz-flowgraph/f21.dot-expected.dot +++ /dev/null @@ -1,101 +0,0 @@ -digraph block { - N0[label="entry"]; - N1[label="exit"]; - N2[label="expr 15"]; - N3[label="local mut x"]; - N4[label="stmt let mut x = 15;"]; - N5[label="expr 151"]; - N6[label="local mut y"]; - N7[label="stmt let mut y = 151;"]; - N8[label="(dummy_node)"]; - N9[label="expr \'outer:\l loop {\l \'inner:\l loop {\l if x == 1 { break \'outer ; \"unreachable\"; }\l if y >= 2 { return; \"unreachable\"; }\l y -= 3;\l x -= 5;\l }\l \"unreachable\";\l }\l"]; - N10[label="(dummy_node)"]; - N11[label="expr \'inner:\l loop {\l if x == 1 { break \'outer ; \"unreachable\"; }\l if y >= 2 { return; \"unreachable\"; }\l y -= 3;\l x -= 5;\l }\l"]; - N12[label="expr x"]; - N13[label="expr 1"]; - N14[label="expr x == 1"]; - N15[label="expr break \'outer"]; - N16[label="(dummy_node)"]; - N17[label="stmt break \'outer ;"]; - N18[label="expr \"unreachable\""]; - N19[label="stmt \"unreachable\";"]; - N20[label="block { break \'outer ; \"unreachable\"; }"]; - N21[label="expr if x == 1 { break \'outer ; \"unreachable\"; }"]; - N22[label="stmt if x == 1 { break \'outer ; \"unreachable\"; }"]; - N23[label="expr y"]; - N24[label="expr 2"]; - N25[label="expr y >= 2"]; - N26[label="expr return"]; - N27[label="(dummy_node)"]; - N28[label="stmt return;"]; - N29[label="expr \"unreachable\""]; - N30[label="stmt \"unreachable\";"]; - N31[label="block { return; \"unreachable\"; }"]; - N32[label="expr if y >= 2 { return; \"unreachable\"; }"]; - N33[label="stmt if y >= 2 { return; \"unreachable\"; }"]; - N34[label="expr 3"]; - N35[label="expr y"]; - N36[label="expr y -= 3"]; - N37[label="stmt y -= 3;"]; - N38[label="expr 5"]; - N39[label="expr x"]; - N40[label="expr x -= 5"]; - N41[label="stmt x -= 5;"]; - N42[label="block {\l if x == 1 { break \'outer ; \"unreachable\"; }\l if y >= 2 { return; \"unreachable\"; }\l y -= 3;\l x -= 5;\l}\l"]; - N43[label="stmt \'inner:\l loop {\l if x == 1 { break \'outer ; \"unreachable\"; }\l if y >= 2 { return; \"unreachable\"; }\l y -= 3;\l x -= 5;\l }\l"]; - N44[label="expr \"unreachable\""]; - N45[label="stmt \"unreachable\";"]; - N46[label="block {\l \'inner:\l loop {\l if x == 1 { break \'outer ; \"unreachable\"; }\l if y >= 2 { return; \"unreachable\"; }\l y -= 3;\l x -= 5;\l }\l \"unreachable\";\l}\l"]; - N47[label="block {\l let mut x = 15;\l let mut y = 151;\l \'outer:\l loop {\l \'inner:\l loop {\l if x == 1 { break \'outer ; \"unreachable\"; }\l if y >= 2 { return; \"unreachable\"; }\l y -= 3;\l x -= 5;\l }\l \"unreachable\";\l }\l}\l"]; - N48[label="expr {\l let mut x = 15;\l let mut y = 151;\l \'outer:\l loop {\l \'inner:\l loop {\l if x == 1 { break \'outer ; \"unreachable\"; }\l if y >= 2 { return; \"unreachable\"; }\l y -= 3;\l x -= 5;\l }\l \"unreachable\";\l }\l}\l"]; - N0 -> N2; - N2 -> N3; - N3 -> N4; - N4 -> N5; - N5 -> N6; - N6 -> N7; - N7 -> N8; - N8 -> N10; - N10 -> N12; - N12 -> N13; - N13 -> N14; - N14 -> N15; - N15 -> N9; - N16 -> N17; - N17 -> N18; - N18 -> N19; - N19 -> N20; - N14 -> N21; - N20 -> N21; - N21 -> N22; - N22 -> N23; - N23 -> N24; - N24 -> N25; - N25 -> N26; - N26 -> N1; - N27 -> N28; - N28 -> N29; - N29 -> N30; - N30 -> N31; - N25 -> N32; - N31 -> N32; - N32 -> N33; - N33 -> N34; - N34 -> N35; - N35 -> N36; - N36 -> N37; - N37 -> N38; - N38 -> N39; - N39 -> N40; - N40 -> N41; - N41 -> N42; - N42 -> N10; - N11 -> N43; - N43 -> N44; - N44 -> N45; - N45 -> N46; - N46 -> N8; - N9 -> N47; - N47 -> N48; - N48 -> N1; -} diff --git a/src/test/run-make/graphviz-flowgraph/f21.rs b/src/test/run-make/graphviz-flowgraph/f21.rs deleted file mode 100644 index 70083ed8312..00000000000 --- a/src/test/run-make/graphviz-flowgraph/f21.rs +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright 2014 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. - -#[allow(unreachable_code)] -pub fn expr_break_label_21() { - let mut x = 15; - let mut y = 151; - 'outer: loop { - 'inner: loop { - if x == 1 { - break 'outer; - "unreachable"; - } - if y >= 2 { - return; - "unreachable"; - } - y -= 3; - x -= 5; - } - "unreachable"; - } -} diff --git a/src/test/run-make/graphviz-flowgraph/f22.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f22.dot-expected.dot deleted file mode 100644 index 9d3bc22831a..00000000000 --- a/src/test/run-make/graphviz-flowgraph/f22.dot-expected.dot +++ /dev/null @@ -1,107 +0,0 @@ -digraph block { - N0[label="entry"]; - N1[label="exit"]; - N2[label="expr 15"]; - N3[label="local mut x"]; - N4[label="stmt let mut x = 15;"]; - N5[label="expr 151"]; - N6[label="local mut y"]; - N7[label="stmt let mut y = 151;"]; - N8[label="(dummy_node)"]; - N9[label="expr \'outer:\l loop {\l \'inner:\l loop {\l if x == 1 { continue \'outer ; \"unreachable\"; }\l if y >= 2 { return; \"unreachable\"; }\l x -= 1;\l y -= 3;\l }\l \"unreachable\";\l }\l"]; - N10[label="(dummy_node)"]; - N11[label="expr \'inner:\l loop {\l if x == 1 { continue \'outer ; \"unreachable\"; }\l if y >= 2 { return; \"unreachable\"; }\l x -= 1;\l y -= 3;\l }\l"]; - N12[label="expr x"]; - N13[label="expr 1"]; - N14[label="expr x == 1"]; - N15[label="expr continue \'outer"]; - N16[label="(dummy_node)"]; - N17[label="stmt continue \'outer ;"]; - N18[label="expr \"unreachable\""]; - N19[label="stmt \"unreachable\";"]; - N20[label="block { continue \'outer ; \"unreachable\"; }"]; - N21[label="expr if x == 1 { continue \'outer ; \"unreachable\"; }"]; - N22[label="stmt if x == 1 { continue \'outer ; \"unreachable\"; }"]; - N23[label="expr y"]; - N24[label="expr 2"]; - N25[label="expr y >= 2"]; - N26[label="expr return"]; - N27[label="(dummy_node)"]; - N28[label="stmt return;"]; - N29[label="expr \"unreachable\""]; - N30[label="stmt \"unreachable\";"]; - N31[label="block { return; \"unreachable\"; }"]; - N32[label="expr if y >= 2 { return; \"unreachable\"; }"]; - N33[label="stmt if y >= 2 { return; \"unreachable\"; }"]; - N34[label="expr 1"]; - N35[label="expr x"]; - N36[label="expr x -= 1"]; - N37[label="stmt x -= 1;"]; - N38[label="expr 3"]; - N39[label="expr y"]; - N40[label="expr y -= 3"]; - N41[label="stmt y -= 3;"]; - N42[label="block {\l if x == 1 { continue \'outer ; \"unreachable\"; }\l if y >= 2 { return; \"unreachable\"; }\l x -= 1;\l y -= 3;\l}\l"]; - N43[label="stmt \'inner:\l loop {\l if x == 1 { continue \'outer ; \"unreachable\"; }\l if y >= 2 { return; \"unreachable\"; }\l x -= 1;\l y -= 3;\l }\l"]; - N44[label="expr \"unreachable\""]; - N45[label="stmt \"unreachable\";"]; - N46[label="block {\l \'inner:\l loop {\l if x == 1 { continue \'outer ; \"unreachable\"; }\l if y >= 2 { return; \"unreachable\"; }\l x -= 1;\l y -= 3;\l }\l \"unreachable\";\l}\l"]; - N47[label="stmt \'outer:\l loop {\l \'inner:\l loop {\l if x == 1 { continue \'outer ; \"unreachable\"; }\l if y >= 2 { return; \"unreachable\"; }\l x -= 1;\l y -= 3;\l }\l \"unreachable\";\l }\l"]; - N48[label="expr \"unreachable\""]; - N49[label="stmt \"unreachable\";"]; - N50[label="block {\l let mut x = 15;\l let mut y = 151;\l \'outer:\l loop {\l \'inner:\l loop {\l if x == 1 { continue \'outer ; \"unreachable\"; }\l if y >= 2 { return; \"unreachable\"; }\l x -= 1;\l y -= 3;\l }\l \"unreachable\";\l }\l \"unreachable\";\l}\l"]; - N51[label="expr {\l let mut x = 15;\l let mut y = 151;\l \'outer:\l loop {\l \'inner:\l loop {\l if x == 1 { continue \'outer ; \"unreachable\"; }\l if y >= 2 { return; \"unreachable\"; }\l x -= 1;\l y -= 3;\l }\l \"unreachable\";\l }\l \"unreachable\";\l}\l"]; - N0 -> N2; - N2 -> N3; - N3 -> N4; - N4 -> N5; - N5 -> N6; - N6 -> N7; - N7 -> N8; - N8 -> N10; - N10 -> N12; - N12 -> N13; - N13 -> N14; - N14 -> N15; - N15 -> N8; - N16 -> N17; - N17 -> N18; - N18 -> N19; - N19 -> N20; - N14 -> N21; - N20 -> N21; - N21 -> N22; - N22 -> N23; - N23 -> N24; - N24 -> N25; - N25 -> N26; - N26 -> N1; - N27 -> N28; - N28 -> N29; - N29 -> N30; - N30 -> N31; - N25 -> N32; - N31 -> N32; - N32 -> N33; - N33 -> N34; - N34 -> N35; - N35 -> N36; - N36 -> N37; - N37 -> N38; - N38 -> N39; - N39 -> N40; - N40 -> N41; - N41 -> N42; - N42 -> N10; - N11 -> N43; - N43 -> N44; - N44 -> N45; - N45 -> N46; - N46 -> N8; - N9 -> N47; - N47 -> N48; - N48 -> N49; - N49 -> N50; - N50 -> N51; - N51 -> N1; -} diff --git a/src/test/run-make/graphviz-flowgraph/f22.rs b/src/test/run-make/graphviz-flowgraph/f22.rs deleted file mode 100644 index b35aac9ec42..00000000000 --- a/src/test/run-make/graphviz-flowgraph/f22.rs +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright 2014 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. - -#[allow(unreachable_code)] -pub fn expr_break_label_21() { - let mut x = 15; - let mut y = 151; - 'outer: loop { - 'inner: loop { - if x == 1 { - continue 'outer; - "unreachable"; - } - if y >= 2 { - return; - "unreachable"; - } - x -= 1; - y -= 3; - } - "unreachable"; - } - "unreachable"; -} diff --git a/src/test/run-make/graphviz-flowgraph/f23.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f23.dot-expected.dot deleted file mode 100644 index c8bfcd6510b..00000000000 --- a/src/test/run-make/graphviz-flowgraph/f23.dot-expected.dot +++ /dev/null @@ -1,113 +0,0 @@ -digraph block { - N0[label="entry"]; - N1[label="exit"]; - N2[label="expr 23"]; - N3[label="local mut x"]; - N4[label="stmt let mut x = 23;"]; - N5[label="expr 23"]; - N6[label="local mut y"]; - N7[label="stmt let mut y = 23;"]; - N8[label="expr 23"]; - N9[label="local mut z"]; - N10[label="stmt let mut z = 23;"]; - N11[label="(dummy_node)"]; - N12[label="expr while x > 0 {\l x -= 1;\l while y > 0 {\l y -= 1;\l while z > 0 { z -= 1; }\l if x > 10 { return; \"unreachable\"; }\l }\l}\l"]; - N13[label="expr x"]; - N14[label="expr 0"]; - N15[label="expr x > 0"]; - N16[label="expr 1"]; - N17[label="expr x"]; - N18[label="expr x -= 1"]; - N19[label="stmt x -= 1;"]; - N20[label="(dummy_node)"]; - N21[label="expr while y > 0 {\l y -= 1;\l while z > 0 { z -= 1; }\l if x > 10 { return; \"unreachable\"; }\l}\l"]; - N22[label="expr y"]; - N23[label="expr 0"]; - N24[label="expr y > 0"]; - N25[label="expr 1"]; - N26[label="expr y"]; - N27[label="expr y -= 1"]; - N28[label="stmt y -= 1;"]; - N29[label="(dummy_node)"]; - N30[label="expr while z > 0 { z -= 1; }"]; - N31[label="expr z"]; - N32[label="expr 0"]; - N33[label="expr z > 0"]; - N34[label="expr 1"]; - N35[label="expr z"]; - N36[label="expr z -= 1"]; - N37[label="stmt z -= 1;"]; - N38[label="block { z -= 1; }"]; - N39[label="stmt while z > 0 { z -= 1; }"]; - N40[label="expr x"]; - N41[label="expr 10"]; - N42[label="expr x > 10"]; - N43[label="expr return"]; - N44[label="(dummy_node)"]; - N45[label="stmt return;"]; - N46[label="expr \"unreachable\""]; - N47[label="stmt \"unreachable\";"]; - N48[label="block { return; \"unreachable\"; }"]; - N49[label="expr if x > 10 { return; \"unreachable\"; }"]; - N50[label="block { y -= 1; while z > 0 { z -= 1; } if x > 10 { return; \"unreachable\"; } }"]; - N51[label="block {\l x -= 1;\l while y > 0 {\l y -= 1;\l while z > 0 { z -= 1; }\l if x > 10 { return; \"unreachable\"; }\l }\l}\l"]; - N52[label="block {\l let mut x = 23;\l let mut y = 23;\l let mut z = 23;\l while x > 0 {\l x -= 1;\l while y > 0 {\l y -= 1;\l while z > 0 { z -= 1; }\l if x > 10 { return; \"unreachable\"; }\l }\l }\l}\l"]; - N53[label="expr {\l let mut x = 23;\l let mut y = 23;\l let mut z = 23;\l while x > 0 {\l x -= 1;\l while y > 0 {\l y -= 1;\l while z > 0 { z -= 1; }\l if x > 10 { return; \"unreachable\"; }\l }\l }\l}\l"]; - N0 -> N2; - N2 -> N3; - N3 -> N4; - N4 -> N5; - N5 -> N6; - N6 -> N7; - N7 -> N8; - N8 -> N9; - N9 -> N10; - N10 -> N11; - N11 -> N13; - N13 -> N14; - N14 -> N15; - N15 -> N12; - N15 -> N16; - N16 -> N17; - N17 -> N18; - N18 -> N19; - N19 -> N20; - N20 -> N22; - N22 -> N23; - N23 -> N24; - N24 -> N21; - N24 -> N25; - N25 -> N26; - N26 -> N27; - N27 -> N28; - N28 -> N29; - N29 -> N31; - N31 -> N32; - N32 -> N33; - N33 -> N30; - N33 -> N34; - N34 -> N35; - N35 -> N36; - N36 -> N37; - N37 -> N38; - N38 -> N29; - N30 -> N39; - N39 -> N40; - N40 -> N41; - N41 -> N42; - N42 -> N43; - N43 -> N1; - N44 -> N45; - N45 -> N46; - N46 -> N47; - N47 -> N48; - N42 -> N49; - N48 -> N49; - N49 -> N50; - N50 -> N20; - N21 -> N51; - N51 -> N11; - N12 -> N52; - N52 -> N53; - N53 -> N1; -} diff --git a/src/test/run-make/graphviz-flowgraph/f23.rs b/src/test/run-make/graphviz-flowgraph/f23.rs deleted file mode 100644 index 52341a3fbd4..00000000000 --- a/src/test/run-make/graphviz-flowgraph/f23.rs +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright 2014 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. - -#[allow(unreachable_code)] -pub fn expr_while_23() { - let mut x = 23; - let mut y = 23; - let mut z = 23; - - while x > 0 { - x -= 1; - - while y > 0 { - y -= 1; - - while z > 0 { z -= 1; } - - if x > 10 { - return; - "unreachable"; - } - } - } -} diff --git a/src/test/run-make/graphviz-flowgraph/f24.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f24.dot-expected.dot deleted file mode 100644 index e40dd014f0a..00000000000 --- a/src/test/run-make/graphviz-flowgraph/f24.dot-expected.dot +++ /dev/null @@ -1,161 +0,0 @@ -digraph block { - N0[label="entry"]; - N1[label="exit"]; - N2[label="expr 24"]; - N3[label="local mut x"]; - N4[label="stmt let mut x = 24;"]; - N5[label="expr 24"]; - N6[label="local mut y"]; - N7[label="stmt let mut y = 24;"]; - N8[label="expr 24"]; - N9[label="local mut z"]; - N10[label="stmt let mut z = 24;"]; - N11[label="(dummy_node)"]; - N12[label="expr loop {\l if x == 0 { break ; \"unreachable\"; }\l x -= 1;\l loop {\l if y == 0 { break ; \"unreachable\"; }\l y -= 1;\l loop { if z == 0 { break ; \"unreachable\"; } z -= 1; }\l if x > 10 { return; \"unreachable\"; }\l }\l}\l"]; - N13[label="expr x"]; - N14[label="expr 0"]; - N15[label="expr x == 0"]; - N16[label="expr break"]; - N17[label="(dummy_node)"]; - N18[label="stmt break ;"]; - N19[label="expr \"unreachable\""]; - N20[label="stmt \"unreachable\";"]; - N21[label="block { break ; \"unreachable\"; }"]; - N22[label="expr if x == 0 { break ; \"unreachable\"; }"]; - N23[label="stmt if x == 0 { break ; \"unreachable\"; }"]; - N24[label="expr 1"]; - N25[label="expr x"]; - N26[label="expr x -= 1"]; - N27[label="stmt x -= 1;"]; - N28[label="(dummy_node)"]; - N29[label="expr loop {\l if y == 0 { break ; \"unreachable\"; }\l y -= 1;\l loop { if z == 0 { break ; \"unreachable\"; } z -= 1; }\l if x > 10 { return; \"unreachable\"; }\l}\l"]; - N30[label="expr y"]; - N31[label="expr 0"]; - N32[label="expr y == 0"]; - N33[label="expr break"]; - N34[label="(dummy_node)"]; - N35[label="stmt break ;"]; - N36[label="expr \"unreachable\""]; - N37[label="stmt \"unreachable\";"]; - N38[label="block { break ; \"unreachable\"; }"]; - N39[label="expr if y == 0 { break ; \"unreachable\"; }"]; - N40[label="stmt if y == 0 { break ; \"unreachable\"; }"]; - N41[label="expr 1"]; - N42[label="expr y"]; - N43[label="expr y -= 1"]; - N44[label="stmt y -= 1;"]; - N45[label="(dummy_node)"]; - N46[label="expr loop { if z == 0 { break ; \"unreachable\"; } z -= 1; }"]; - N47[label="expr z"]; - N48[label="expr 0"]; - N49[label="expr z == 0"]; - N50[label="expr break"]; - N51[label="(dummy_node)"]; - N52[label="stmt break ;"]; - N53[label="expr \"unreachable\""]; - N54[label="stmt \"unreachable\";"]; - N55[label="block { break ; \"unreachable\"; }"]; - N56[label="expr if z == 0 { break ; \"unreachable\"; }"]; - N57[label="stmt if z == 0 { break ; \"unreachable\"; }"]; - N58[label="expr 1"]; - N59[label="expr z"]; - N60[label="expr z -= 1"]; - N61[label="stmt z -= 1;"]; - N62[label="block { if z == 0 { break ; \"unreachable\"; } z -= 1; }"]; - N63[label="stmt loop { if z == 0 { break ; \"unreachable\"; } z -= 1; }"]; - N64[label="expr x"]; - N65[label="expr 10"]; - N66[label="expr x > 10"]; - N67[label="expr return"]; - N68[label="(dummy_node)"]; - N69[label="stmt return;"]; - N70[label="expr \"unreachable\""]; - N71[label="stmt \"unreachable\";"]; - N72[label="block { return; \"unreachable\"; }"]; - N73[label="expr if x > 10 { return; \"unreachable\"; }"]; - N74[label="block {\l if y == 0 { break ; \"unreachable\"; }\l y -= 1;\l loop { if z == 0 { break ; \"unreachable\"; } z -= 1; }\l if x > 10 { return; \"unreachable\"; }\l}\l"]; - N75[label="block {\l if x == 0 { break ; \"unreachable\"; }\l x -= 1;\l loop {\l if y == 0 { break ; \"unreachable\"; }\l y -= 1;\l loop { if z == 0 { break ; \"unreachable\"; } z -= 1; }\l if x > 10 { return; \"unreachable\"; }\l }\l}\l"]; - N76[label="block {\l let mut x = 24;\l let mut y = 24;\l let mut z = 24;\l loop {\l if x == 0 { break ; \"unreachable\"; }\l x -= 1;\l loop {\l if y == 0 { break ; \"unreachable\"; }\l y -= 1;\l loop { if z == 0 { break ; \"unreachable\"; } z -= 1; }\l if x > 10 { return; \"unreachable\"; }\l }\l }\l}\l"]; - N77[label="expr {\l let mut x = 24;\l let mut y = 24;\l let mut z = 24;\l loop {\l if x == 0 { break ; \"unreachable\"; }\l x -= 1;\l loop {\l if y == 0 { break ; \"unreachable\"; }\l y -= 1;\l loop { if z == 0 { break ; \"unreachable\"; } z -= 1; }\l if x > 10 { return; \"unreachable\"; }\l }\l }\l}\l"]; - N0 -> N2; - N2 -> N3; - N3 -> N4; - N4 -> N5; - N5 -> N6; - N6 -> N7; - N7 -> N8; - N8 -> N9; - N9 -> N10; - N10 -> N11; - N11 -> N13; - N13 -> N14; - N14 -> N15; - N15 -> N16; - N16 -> N12; - N17 -> N18; - N18 -> N19; - N19 -> N20; - N20 -> N21; - N15 -> N22; - N21 -> N22; - N22 -> N23; - N23 -> N24; - N24 -> N25; - N25 -> N26; - N26 -> N27; - N27 -> N28; - N28 -> N30; - N30 -> N31; - N31 -> N32; - N32 -> N33; - N33 -> N29; - N34 -> N35; - N35 -> N36; - N36 -> N37; - N37 -> N38; - N32 -> N39; - N38 -> N39; - N39 -> N40; - N40 -> N41; - N41 -> N42; - N42 -> N43; - N43 -> N44; - N44 -> N45; - N45 -> N47; - N47 -> N48; - N48 -> N49; - N49 -> N50; - N50 -> N46; - N51 -> N52; - N52 -> N53; - N53 -> N54; - N54 -> N55; - N49 -> N56; - N55 -> N56; - N56 -> N57; - N57 -> N58; - N58 -> N59; - N59 -> N60; - N60 -> N61; - N61 -> N62; - N62 -> N45; - N46 -> N63; - N63 -> N64; - N64 -> N65; - N65 -> N66; - N66 -> N67; - N67 -> N1; - N68 -> N69; - N69 -> N70; - N70 -> N71; - N71 -> N72; - N66 -> N73; - N72 -> N73; - N73 -> N74; - N74 -> N28; - N29 -> N75; - N75 -> N11; - N12 -> N76; - N76 -> N77; - N77 -> N1; -} diff --git a/src/test/run-make/graphviz-flowgraph/f24.rs b/src/test/run-make/graphviz-flowgraph/f24.rs deleted file mode 100644 index f796d660a18..00000000000 --- a/src/test/run-make/graphviz-flowgraph/f24.rs +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2014 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. - -#[allow(unreachable_code)] -pub fn expr_while_24() { - let mut x = 24; - let mut y = 24; - let mut z = 24; - - loop { - if x == 0 { break; "unreachable"; } - x -= 1; - - loop { - if y == 0 { break; "unreachable"; } - y -= 1; - - loop { - if z == 0 { break; "unreachable"; } - z -= 1; - } - - if x > 10 { - return; - "unreachable"; - } - } - } -} diff --git a/src/test/run-make/graphviz-flowgraph/f25.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f25.dot-expected.dot deleted file mode 100644 index 1e2df1ab5e7..00000000000 --- a/src/test/run-make/graphviz-flowgraph/f25.dot-expected.dot +++ /dev/null @@ -1,161 +0,0 @@ -digraph block { - N0[label="entry"]; - N1[label="exit"]; - N2[label="expr 25"]; - N3[label="local mut x"]; - N4[label="stmt let mut x = 25;"]; - N5[label="expr 25"]; - N6[label="local mut y"]; - N7[label="stmt let mut y = 25;"]; - N8[label="expr 25"]; - N9[label="local mut z"]; - N10[label="stmt let mut z = 25;"]; - N11[label="(dummy_node)"]; - N12[label="expr \'a:\l loop {\l if x == 0 { break ; \"unreachable\"; }\l x -= 1;\l \'a:\l loop {\l if y == 0 { break ; \"unreachable\"; }\l y -= 1;\l \'a: loop { if z == 0 { break ; \"unreachable\"; } z -= 1; }\l if x > 10 { continue \'a ; \"unreachable\"; }\l }\l }\l"]; - N13[label="expr x"]; - N14[label="expr 0"]; - N15[label="expr x == 0"]; - N16[label="expr break"]; - N17[label="(dummy_node)"]; - N18[label="stmt break ;"]; - N19[label="expr \"unreachable\""]; - N20[label="stmt \"unreachable\";"]; - N21[label="block { break ; \"unreachable\"; }"]; - N22[label="expr if x == 0 { break ; \"unreachable\"; }"]; - N23[label="stmt if x == 0 { break ; \"unreachable\"; }"]; - N24[label="expr 1"]; - N25[label="expr x"]; - N26[label="expr x -= 1"]; - N27[label="stmt x -= 1;"]; - N28[label="(dummy_node)"]; - N29[label="expr \'a:\l loop {\l if y == 0 { break ; \"unreachable\"; }\l y -= 1;\l \'a: loop { if z == 0 { break ; \"unreachable\"; } z -= 1; }\l if x > 10 { continue \'a ; \"unreachable\"; }\l }\l"]; - N30[label="expr y"]; - N31[label="expr 0"]; - N32[label="expr y == 0"]; - N33[label="expr break"]; - N34[label="(dummy_node)"]; - N35[label="stmt break ;"]; - N36[label="expr \"unreachable\""]; - N37[label="stmt \"unreachable\";"]; - N38[label="block { break ; \"unreachable\"; }"]; - N39[label="expr if y == 0 { break ; \"unreachable\"; }"]; - N40[label="stmt if y == 0 { break ; \"unreachable\"; }"]; - N41[label="expr 1"]; - N42[label="expr y"]; - N43[label="expr y -= 1"]; - N44[label="stmt y -= 1;"]; - N45[label="(dummy_node)"]; - N46[label="expr \'a: loop { if z == 0 { break ; \"unreachable\"; } z -= 1; }"]; - N47[label="expr z"]; - N48[label="expr 0"]; - N49[label="expr z == 0"]; - N50[label="expr break"]; - N51[label="(dummy_node)"]; - N52[label="stmt break ;"]; - N53[label="expr \"unreachable\""]; - N54[label="stmt \"unreachable\";"]; - N55[label="block { break ; \"unreachable\"; }"]; - N56[label="expr if z == 0 { break ; \"unreachable\"; }"]; - N57[label="stmt if z == 0 { break ; \"unreachable\"; }"]; - N58[label="expr 1"]; - N59[label="expr z"]; - N60[label="expr z -= 1"]; - N61[label="stmt z -= 1;"]; - N62[label="block { if z == 0 { break ; \"unreachable\"; } z -= 1; }"]; - N63[label="stmt \'a: loop { if z == 0 { break ; \"unreachable\"; } z -= 1; }"]; - N64[label="expr x"]; - N65[label="expr 10"]; - N66[label="expr x > 10"]; - N67[label="expr continue \'a"]; - N68[label="(dummy_node)"]; - N69[label="stmt continue \'a ;"]; - N70[label="expr \"unreachable\""]; - N71[label="stmt \"unreachable\";"]; - N72[label="block { continue \'a ; \"unreachable\"; }"]; - N73[label="expr if x > 10 { continue \'a ; \"unreachable\"; }"]; - N74[label="block {\l if y == 0 { break ; \"unreachable\"; }\l y -= 1;\l \'a: loop { if z == 0 { break ; \"unreachable\"; } z -= 1; }\l if x > 10 { continue \'a ; \"unreachable\"; }\l}\l"]; - N75[label="block {\l if x == 0 { break ; \"unreachable\"; }\l x -= 1;\l \'a:\l loop {\l if y == 0 { break ; \"unreachable\"; }\l y -= 1;\l \'a: loop { if z == 0 { break ; \"unreachable\"; } z -= 1; }\l if x > 10 { continue \'a ; \"unreachable\"; }\l }\l}\l"]; - N76[label="block {\l let mut x = 25;\l let mut y = 25;\l let mut z = 25;\l \'a:\l loop {\l if x == 0 { break ; \"unreachable\"; }\l x -= 1;\l \'a:\l loop {\l if y == 0 { break ; \"unreachable\"; }\l y -= 1;\l \'a: loop { if z == 0 { break ; \"unreachable\"; } z -= 1; }\l if x > 10 { continue \'a ; \"unreachable\"; }\l }\l }\l}\l"]; - N77[label="expr {\l let mut x = 25;\l let mut y = 25;\l let mut z = 25;\l \'a:\l loop {\l if x == 0 { break ; \"unreachable\"; }\l x -= 1;\l \'a:\l loop {\l if y == 0 { break ; \"unreachable\"; }\l y -= 1;\l \'a: loop { if z == 0 { break ; \"unreachable\"; } z -= 1; }\l if x > 10 { continue \'a ; \"unreachable\"; }\l }\l }\l}\l"]; - N0 -> N2; - N2 -> N3; - N3 -> N4; - N4 -> N5; - N5 -> N6; - N6 -> N7; - N7 -> N8; - N8 -> N9; - N9 -> N10; - N10 -> N11; - N11 -> N13; - N13 -> N14; - N14 -> N15; - N15 -> N16; - N16 -> N12; - N17 -> N18; - N18 -> N19; - N19 -> N20; - N20 -> N21; - N15 -> N22; - N21 -> N22; - N22 -> N23; - N23 -> N24; - N24 -> N25; - N25 -> N26; - N26 -> N27; - N27 -> N28; - N28 -> N30; - N30 -> N31; - N31 -> N32; - N32 -> N33; - N33 -> N29; - N34 -> N35; - N35 -> N36; - N36 -> N37; - N37 -> N38; - N32 -> N39; - N38 -> N39; - N39 -> N40; - N40 -> N41; - N41 -> N42; - N42 -> N43; - N43 -> N44; - N44 -> N45; - N45 -> N47; - N47 -> N48; - N48 -> N49; - N49 -> N50; - N50 -> N46; - N51 -> N52; - N52 -> N53; - N53 -> N54; - N54 -> N55; - N49 -> N56; - N55 -> N56; - N56 -> N57; - N57 -> N58; - N58 -> N59; - N59 -> N60; - N60 -> N61; - N61 -> N62; - N62 -> N45; - N46 -> N63; - N63 -> N64; - N64 -> N65; - N65 -> N66; - N66 -> N67; - N67 -> N28; - N68 -> N69; - N69 -> N70; - N70 -> N71; - N71 -> N72; - N66 -> N73; - N72 -> N73; - N73 -> N74; - N74 -> N28; - N29 -> N75; - N75 -> N11; - N12 -> N76; - N76 -> N77; - N77 -> N1; -} diff --git a/src/test/run-make/graphviz-flowgraph/f25.rs b/src/test/run-make/graphviz-flowgraph/f25.rs deleted file mode 100644 index 2ee2e48fd10..00000000000 --- a/src/test/run-make/graphviz-flowgraph/f25.rs +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2014 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. - -#[allow(unreachable_code)] -pub fn expr_while_25() { - let mut x = 25; - let mut y = 25; - let mut z = 25; - - 'a: loop { - if x == 0 { break; "unreachable"; } - x -= 1; - - 'a: loop { - if y == 0 { break; "unreachable"; } - y -= 1; - - 'a: loop { - if z == 0 { break; "unreachable"; } - z -= 1; - } - - if x > 10 { - continue 'a; - "unreachable"; - } - } - } -} -- cgit 1.4.1-3-g733a5 From fb99d87c460c8f35ae8ab9e3694aa34d983dbd9c Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sat, 25 Mar 2017 05:30:39 -0400 Subject: update UI test We no longer give suggestions; this is presumably related to the changes I made in coercion. However, those suggestions appear to be wrong anyhow! --- src/test/ui/resolve/token-error-correct-3.stderr | 4 ---- 1 file changed, 4 deletions(-) (limited to 'src/test') diff --git a/src/test/ui/resolve/token-error-correct-3.stderr b/src/test/ui/resolve/token-error-correct-3.stderr index 56e36889575..5be23d8ca48 100644 --- a/src/test/ui/resolve/token-error-correct-3.stderr +++ b/src/test/ui/resolve/token-error-correct-3.stderr @@ -36,10 +36,6 @@ error[E0308]: mismatched types | = note: expected type `()` found type `std::result::Result` - = help: here are some functions which might fulfill your needs: - - .unwrap() - - .unwrap_err() - - .unwrap_or_default() error: aborting due to previous error -- cgit 1.4.1-3-g733a5 From 744f666445348d505f42b3fb77217e31d8eb786b Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sun, 26 Mar 2017 07:02:39 -0400 Subject: fix error message for issue-10176.rs --- src/test/compile-fail/issue-10176.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/test') diff --git a/src/test/compile-fail/issue-10176.rs b/src/test/compile-fail/issue-10176.rs index 434b795ff31..c968844ae21 100644 --- a/src/test/compile-fail/issue-10176.rs +++ b/src/test/compile-fail/issue-10176.rs @@ -12,7 +12,7 @@ fn f() -> isize { (return 1, return 2) //~^ ERROR mismatched types //~| expected type `isize` -//~| found type `(_, _)` +//~| found type `(!, !)` //~| expected isize, found tuple } -- cgit 1.4.1-3-g733a5 From 2414222b17f45e33d68582dd5ebe0083ed27b8cc Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 27 Mar 2017 19:48:55 -0400 Subject: remove comments that were tripping up pretty printer --- src/test/run-pass/issue-39808.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/test') diff --git a/src/test/run-pass/issue-39808.rs b/src/test/run-pass/issue-39808.rs index 00c2bdc8cc9..91c70d76eef 100644 --- a/src/test/run-pass/issue-39808.rs +++ b/src/test/run-pass/issue-39808.rs @@ -19,7 +19,7 @@ use std::borrow::Cow; fn main() { let _ = if false { - Cow::Owned(format!("{:?}", panic!())) /* as Cow */ // uncomment to fix + Cow::Owned(format!("{:?}", panic!())) } else { Cow::Borrowed("") }; -- cgit 1.4.1-3-g733a5 From 36b15f0409fae948b3de7dee1d6b2cb995c5784d Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 30 Mar 2017 17:29:54 -0600 Subject: Fix multiple footnotes and improve testing --- src/librustdoc/html/markdown.rs | 54 ++++++++++++++++----------- src/test/rustdoc/check-rule-image-footnote.rs | 13 +++++-- 2 files changed, 42 insertions(+), 25 deletions(-) (limited to 'src/test') diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 6c82dab94bc..e8acabde408 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -27,6 +27,7 @@ use std::ascii::AsciiExt; use std::cell::RefCell; +use std::collections::HashMap; use std::default::Default; use std::fmt::{self, Write}; use std::str; @@ -135,8 +136,8 @@ macro_rules! event_loop_break { struct ParserWrapper<'a> { parser: Parser<'a>, - footnotes: Vec, - current_footnote_id: u16, + // The key is the footnote reference. The value is the footnote definition and the id. + footnotes: HashMap, } impl<'a> ParserWrapper<'a> { @@ -144,18 +145,18 @@ impl<'a> ParserWrapper<'a> { ParserWrapper { parser: Parser::new_ext(s, pulldown_cmark::OPTION_ENABLE_TABLES | pulldown_cmark::OPTION_ENABLE_FOOTNOTES), - footnotes: Vec::new(), - current_footnote_id: 1, + footnotes: HashMap::new(), } } + pub fn next(&mut self) -> Option> { self.parser.next() } - pub fn get_next_footnote_id(&mut self) -> u16 { - let tmp = self.current_footnote_id; - self.current_footnote_id += 1; - tmp + pub fn get_entry(&mut self, key: &str) -> &mut (String, u16) { + let new_id = self.footnotes.keys().count() + 1; + let key = key.to_owned(); + self.footnotes.entry(key).or_insert((String::new(), new_id as u16)) } } @@ -450,10 +451,11 @@ pub fn render(w: &mut fmt::Formatter, fn footnote(parser: &mut ParserWrapper, buffer: &mut String, toc_builder: &mut Option, shorter: MarkdownOutputStyle, - mut definition: String, id: &mut Option<&mut String>) { - event_loop_break!(parser, toc_builder, shorter, definition, true, id, + id: &mut Option<&mut String>) { + let mut content = String::new(); + event_loop_break!(parser, toc_builder, shorter, content, true, id, Event::End(Tag::FootnoteDefinition(_))); - buffer.push_str(&definition); + buffer.push_str(&content); } fn rule(parser: &mut ParserWrapper, buffer: &mut String, toc_builder: &mut Option, @@ -507,17 +509,24 @@ pub fn render(w: &mut fmt::Formatter, } Event::Start(Tag::FootnoteDefinition(ref def)) => { let mut content = String::new(); - footnote(parser, &mut content, toc_builder, shorter, def.as_ref().to_owned(), - id); - let cur_len = parser.footnotes.len() + 1; - parser.footnotes.push(format!("
  • {}
  • ", - cur_len, content)); - } - Event::FootnoteReference(_) => { + let def = def.as_ref(); + footnote(parser, &mut content, toc_builder, shorter, id); + let entry = parser.get_entry(def); + let cur_id = (*entry).1; + (*entry).0.push_str(&format!("
  • {} 

  • ", + cur_id, + if content.ends_with("

    ") { + &content[..content.len() - 4] + } else { + &content + })); + } + Event::FootnoteReference(ref reference) => { + let entry = parser.get_entry(reference.as_ref()); buffer.push_str(&format!("{0}\ ", - parser.get_next_footnote_id())); + (*entry).1)); } Event::Html(h) | Event::InlineHtml(h) => { buffer.push_str(&*h); @@ -545,7 +554,10 @@ pub fn render(w: &mut fmt::Formatter, } if !parser.footnotes.is_empty() { buffer.push_str(&format!("

      {}
    ", - parser.footnotes.join(""))); + parser.footnotes.values() + .map(|&(ref s, _)| s.as_str()) + .collect::>() + .join(""))); } let mut ret = toc_builder.map_or(Ok(()), |builder| { write!(w, "", builder.into_toc()) diff --git a/src/test/rustdoc/check-rule-image-footnote.rs b/src/test/rustdoc/check-rule-image-footnote.rs index 629e1a64e6f..4d3bea20ba8 100644 --- a/src/test/rustdoc/check-rule-image-footnote.rs +++ b/src/test/rustdoc/check-rule-image-footnote.rs @@ -10,11 +10,10 @@ #![crate_name = "foo"] +// ignore-tidy-linelength + // @has foo/fn.f.html -// @has - '

    hard break: after hard break


    ' -// @has - 'Rust' -// @has - '
  • ' -// @has - '1' +// @has - '

    markdown test

    this is a link.

    hard break: after hard break


    a footnote1.

    another footnote2.

    Rust


    1. Thing 

    2. Another Thing 

    ' /// markdown test /// /// this is a [link]. @@ -28,8 +27,14 @@ /// /// a footnote[^footnote]. /// +/// another footnote[^footnotebis]. +/// /// [^footnote]: Thing /// +/// +/// [^footnotebis]: Another Thing +/// +/// /// ![Rust](https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png) #[deprecated(note = "Struct")] pub fn f() {} -- cgit 1.4.1-3-g733a5 From 51d3cec38794beb644f67e80b1e7718ee14facf0 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 31 Mar 2017 11:02:46 -0600 Subject: Fix hard break issue --- src/librustdoc/html/markdown.rs | 36 ++++++++++++++++++++++++++++-- src/librustdoc/passes/unindent_comments.rs | 13 ++++++++++- src/test/rustdoc/check-hard-break.rs | 19 ++++++++++++++++ 3 files changed, 65 insertions(+), 3 deletions(-) create mode 100644 src/test/rustdoc/check-hard-break.rs (limited to 'src/test') diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index e8acabde408..d1f2948bc25 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -116,6 +116,7 @@ macro_rules! event_loop_break { match event { $($end_event)|* => break, Event::Text(ref s) => { + debug!("Text"); inner($id, s); if $escape { $buf.push_str(&format!("{}", Escape(s))); @@ -123,8 +124,11 @@ macro_rules! event_loop_break { $buf.push_str(s); } } - Event::SoftBreak | Event::HardBreak if !$buf.is_empty() => { - $buf.push(' '); + Event::SoftBreak => { + debug!("SoftBreak"); + if !$buf.is_empty() { + $buf.push(' '); + } } x => { looper($parser, &mut $buf, Some(x), $toc_builder, $shorter, $id); @@ -165,6 +169,7 @@ pub fn render(w: &mut fmt::Formatter, print_toc: bool, shorter: MarkdownOutputStyle) -> fmt::Result { fn code_block(parser: &mut ParserWrapper, buffer: &mut String, lang: &str) { + debug!("CodeBlock"); let mut origtext = String::new(); while let Some(event) = parser.next() { match event { @@ -244,6 +249,7 @@ pub fn render(w: &mut fmt::Formatter, fn heading(parser: &mut ParserWrapper, buffer: &mut String, toc_builder: &mut Option, shorter: MarkdownOutputStyle, level: i32) { + debug!("Heading"); let mut ret = String::new(); let mut id = String::new(); event_loop_break!(parser, toc_builder, shorter, ret, true, &mut Some(&mut id), @@ -279,6 +285,7 @@ pub fn render(w: &mut fmt::Formatter, fn inline_code(parser: &mut ParserWrapper, buffer: &mut String, toc_builder: &mut Option, shorter: MarkdownOutputStyle, id: &mut Option<&mut String>) { + debug!("InlineCode"); let mut content = String::new(); event_loop_break!(parser, toc_builder, shorter, content, false, id, Event::End(Tag::Code)); buffer.push_str(&format!("{}", @@ -288,6 +295,7 @@ pub fn render(w: &mut fmt::Formatter, fn link(parser: &mut ParserWrapper, buffer: &mut String, toc_builder: &mut Option, shorter: MarkdownOutputStyle, url: &str, title: &str, id: &mut Option<&mut String>) { + debug!("Link"); let mut content = String::new(); event_loop_break!(parser, toc_builder, shorter, content, true, id, Event::End(Tag::Link(_, _))); @@ -302,6 +310,7 @@ pub fn render(w: &mut fmt::Formatter, fn image(parser: &mut ParserWrapper, buffer: &mut String, toc_builder: &mut Option, shorter: MarkdownOutputStyle, url: &str, mut title: String, id: &mut Option<&mut String>) { + debug!("Image"); event_loop_break!(parser, toc_builder, shorter, title, true, id, Event::End(Tag::Image(_, _))); buffer.push_str(&format!("\"{}\"", url, title)); @@ -310,6 +319,7 @@ pub fn render(w: &mut fmt::Formatter, fn paragraph(parser: &mut ParserWrapper, buffer: &mut String, toc_builder: &mut Option, shorter: MarkdownOutputStyle, id: &mut Option<&mut String>) { + debug!("Paragraph"); let mut content = String::new(); event_loop_break!(parser, toc_builder, shorter, content, true, id, Event::End(Tag::Paragraph)); @@ -318,6 +328,7 @@ pub fn render(w: &mut fmt::Formatter, fn table_cell(parser: &mut ParserWrapper, buffer: &mut String, toc_builder: &mut Option, shorter: MarkdownOutputStyle) { + debug!("TableCell"); let mut content = String::new(); event_loop_break!(parser, toc_builder, shorter, content, true, &mut None, Event::End(Tag::TableHead) | @@ -329,6 +340,7 @@ pub fn render(w: &mut fmt::Formatter, fn table_row(parser: &mut ParserWrapper, buffer: &mut String, toc_builder: &mut Option, shorter: MarkdownOutputStyle) { + debug!("TableRow"); let mut content = String::new(); while let Some(event) = parser.next() { match event { @@ -348,6 +360,7 @@ pub fn render(w: &mut fmt::Formatter, fn table_head(parser: &mut ParserWrapper, buffer: &mut String, toc_builder: &mut Option, shorter: MarkdownOutputStyle) { + debug!("TableHead"); let mut content = String::new(); while let Some(event) = parser.next() { match event { @@ -367,6 +380,7 @@ pub fn render(w: &mut fmt::Formatter, fn table(parser: &mut ParserWrapper, buffer: &mut String, toc_builder: &mut Option, shorter: MarkdownOutputStyle) { + debug!("Table"); let mut content = String::new(); let mut rows = String::new(); while let Some(event) = parser.next() { @@ -392,6 +406,7 @@ pub fn render(w: &mut fmt::Formatter, fn blockquote(parser: &mut ParserWrapper, buffer: &mut String, toc_builder: &mut Option, shorter: MarkdownOutputStyle) { + debug!("BlockQuote"); let mut content = String::new(); event_loop_break!(parser, toc_builder, shorter, content, true, &mut None, Event::End(Tag::BlockQuote)); @@ -400,6 +415,7 @@ pub fn render(w: &mut fmt::Formatter, fn list_item(parser: &mut ParserWrapper, buffer: &mut String, toc_builder: &mut Option, shorter: MarkdownOutputStyle) { + debug!("ListItem"); let mut content = String::new(); while let Some(event) = parser.next() { match event { @@ -417,6 +433,7 @@ pub fn render(w: &mut fmt::Formatter, fn list(parser: &mut ParserWrapper, buffer: &mut String, toc_builder: &mut Option, shorter: MarkdownOutputStyle) { + debug!("List"); let mut content = String::new(); while let Some(event) = parser.next() { match event { @@ -435,6 +452,7 @@ pub fn render(w: &mut fmt::Formatter, fn emphasis(parser: &mut ParserWrapper, buffer: &mut String, toc_builder: &mut Option, shorter: MarkdownOutputStyle, id: &mut Option<&mut String>) { + debug!("Emphasis"); let mut content = String::new(); event_loop_break!(parser, toc_builder, shorter, content, false, id, Event::End(Tag::Emphasis)); @@ -443,6 +461,7 @@ pub fn render(w: &mut fmt::Formatter, fn strong(parser: &mut ParserWrapper, buffer: &mut String, toc_builder: &mut Option, shorter: MarkdownOutputStyle, id: &mut Option<&mut String>) { + debug!("Strong"); let mut content = String::new(); event_loop_break!(parser, toc_builder, shorter, content, false, id, Event::End(Tag::Strong)); @@ -452,6 +471,7 @@ pub fn render(w: &mut fmt::Formatter, fn footnote(parser: &mut ParserWrapper, buffer: &mut String, toc_builder: &mut Option, shorter: MarkdownOutputStyle, id: &mut Option<&mut String>) { + debug!("FootnoteDefinition"); let mut content = String::new(); event_loop_break!(parser, toc_builder, shorter, content, true, id, Event::End(Tag::FootnoteDefinition(_))); @@ -460,6 +480,7 @@ pub fn render(w: &mut fmt::Formatter, fn rule(parser: &mut ParserWrapper, buffer: &mut String, toc_builder: &mut Option, shorter: MarkdownOutputStyle, id: &mut Option<&mut String>) { + debug!("Rule"); let mut content = String::new(); event_loop_break!(parser, toc_builder, shorter, content, true, id, Event::End(Tag::Rule)); @@ -508,6 +529,7 @@ pub fn render(w: &mut fmt::Formatter, rule(parser, buffer, toc_builder, shorter, id); } Event::Start(Tag::FootnoteDefinition(ref def)) => { + debug!("FootnoteDefinition"); let mut content = String::new(); let def = def.as_ref(); footnote(parser, &mut content, toc_builder, shorter, id); @@ -523,12 +545,22 @@ pub fn render(w: &mut fmt::Formatter, })); } Event::FootnoteReference(ref reference) => { + debug!("FootnoteReference"); let entry = parser.get_entry(reference.as_ref()); buffer.push_str(&format!("{0}\ ", (*entry).1)); } + Event::HardBreak => { + debug!("HardBreak"); + if shorter.is_fancy() { + buffer.push_str("
    "); + } else if !buffer.is_empty() { + buffer.push(' '); + } + } Event::Html(h) | Event::InlineHtml(h) => { + debug!("Html/InlineHtml"); buffer.push_str(&*h); } _ => {} diff --git a/src/librustdoc/passes/unindent_comments.rs b/src/librustdoc/passes/unindent_comments.rs index 4d94c308478..59fef8d2027 100644 --- a/src/librustdoc/passes/unindent_comments.rs +++ b/src/librustdoc/passes/unindent_comments.rs @@ -82,7 +82,7 @@ fn unindent(s: &str) -> String { }); if !lines.is_empty() { - let mut unindented = vec![ lines[0].trim().to_string() ]; + let mut unindented = vec![ lines[0].trim_left().to_string() ]; unindented.extend_from_slice(&lines[1..].iter().map(|&line| { if line.chars().all(|c| c.is_whitespace()) { line.to_string() @@ -160,4 +160,15 @@ mod unindent_tests { let r = unindent(&s); assert_eq!(r, "line1\nline2"); } + + #[test] + fn should_not_trim() { + let s = "\t line1 \n\t line2".to_string(); + let r = unindent(&s); + assert_eq!(r, "line1 \nline2"); + + let s = " \tline1 \n \tline2".to_string(); + let r = unindent(&s); + assert_eq!(r, "line1 \nline2"); + } } diff --git a/src/test/rustdoc/check-hard-break.rs b/src/test/rustdoc/check-hard-break.rs new file mode 100644 index 00000000000..4604639c3c8 --- /dev/null +++ b/src/test/rustdoc/check-hard-break.rs @@ -0,0 +1,19 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![crate_name = "foo"] + +// ignore-tidy-linelength + +// @has foo/fn.f.html +// @has - '

    hard break:
    after hard break

    ' +/// hard break: +/// after hard break +pub fn f() {} -- cgit 1.4.1-3-g733a5 From 4de4a955052febfbcd28fd156a7585b90b5dd184 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 31 Mar 2017 12:08:31 -0600 Subject: Add end whitespace ignore flag for tidy --- src/test/rustdoc/check-hard-break.rs | 2 +- src/tools/tidy/src/style.rs | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'src/test') diff --git a/src/test/rustdoc/check-hard-break.rs b/src/test/rustdoc/check-hard-break.rs index 4604639c3c8..5c5e3f8136c 100644 --- a/src/test/rustdoc/check-hard-break.rs +++ b/src/test/rustdoc/check-hard-break.rs @@ -10,7 +10,7 @@ #![crate_name = "foo"] -// ignore-tidy-linelength +// ignore-tidy-end-whitespace // @has foo/fn.f.html // @has - '

    hard break:
    after hard break

    ' diff --git a/src/tools/tidy/src/style.rs b/src/tools/tidy/src/style.rs index 2233f8c3529..012301299e0 100644 --- a/src/tools/tidy/src/style.rs +++ b/src/tools/tidy/src/style.rs @@ -110,6 +110,7 @@ pub fn check(path: &Path, bad: &mut bool) { let skip_cr = contents.contains("ignore-tidy-cr"); let skip_tab = contents.contains("ignore-tidy-tab"); let skip_length = contents.contains("ignore-tidy-linelength"); + let skip_end_whitespace = contents.contains("ignore-tidy-end-whitespace"); for (i, line) in contents.split("\n").enumerate() { let mut err = |msg: &str| { println!("{}:{}: {}", file.display(), i + 1, msg); @@ -122,7 +123,7 @@ pub fn check(path: &Path, bad: &mut bool) { if line.contains("\t") && !skip_tab { err("tab character"); } - if line.ends_with(" ") || line.ends_with("\t") { + if !skip_end_whitespace && (line.ends_with(" ") || line.ends_with("\t")) { err("trailing whitespace"); } if line.contains("\r") && !skip_cr { -- cgit 1.4.1-3-g733a5