From ae46434b7936d1f1d71cb92c45ddcf936ec0eb24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Sat, 3 Feb 2018 21:15:00 +0100 Subject: [PATCH 01/34] Remove "static item recursion checking" in favor of relying on cycle checks in the query engine --- src/librustc_driver/driver.rs | 6 +- src/librustc_passes/diagnostics.rs | 16 - src/librustc_passes/lib.rs | 1 - src/librustc_passes/static_recursion.rs | 280 ------------------ src/test/compile-fail/issue-17252.rs | 4 +- .../ui/{issue-23302.rs => issue-23302-1.rs} | 13 +- src/test/ui/issue-23302-1.stderr | 15 + .../issue-23302-2.rs} | 12 +- src/test/ui/issue-23302-2.stderr | 15 + .../issue-23302-3.rs} | 10 +- src/test/ui/issue-23302-3.stderr | 20 ++ src/test/ui/issue-23302.stderr | 26 -- src/test/ui/issue-36163.rs | 10 +- src/test/ui/issue-36163.stderr | 30 +- 14 files changed, 84 insertions(+), 374 deletions(-) delete mode 100644 src/librustc_passes/static_recursion.rs rename src/test/ui/{issue-23302.rs => issue-23302-1.rs} (71%) create mode 100644 src/test/ui/issue-23302-1.stderr rename src/test/{compile-fail/issue-17718-recursive.rs => ui/issue-23302-2.rs} (64%) create mode 100644 src/test/ui/issue-23302-2.stderr rename src/test/{compile-fail/const-recursive.rs => ui/issue-23302-3.rs} (69%) create mode 100644 src/test/ui/issue-23302-3.stderr delete mode 100644 src/test/ui/issue-23302.stderr diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 50c19b5a99a54..0c0c946cd4c51 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -36,7 +36,7 @@ use rustc_typeck as typeck; use rustc_privacy; use rustc_plugin::registry::Registry; use rustc_plugin as plugin; -use rustc_passes::{self, ast_validation, loops, consts, static_recursion, hir_stats}; +use rustc_passes::{self, ast_validation, loops, consts, hir_stats}; use rustc_const_eval::{self, check_match}; use super::Compilation; @@ -972,10 +972,6 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(trans: &TransCrate, "loop checking", || loops::check_crate(sess, &hir_map)); - time(time_passes, - "static item recursion checking", - || static_recursion::check_crate(sess, &hir_map))?; - let mut local_providers = ty::maps::Providers::default(); default_provide(&mut local_providers); trans.provide(&mut local_providers); diff --git a/src/librustc_passes/diagnostics.rs b/src/librustc_passes/diagnostics.rs index 743f7b7326e9e..8a19615c1adcb 100644 --- a/src/librustc_passes/diagnostics.rs +++ b/src/librustc_passes/diagnostics.rs @@ -128,22 +128,6 @@ impl !Enterprise for Foo { } Please note that negative impls are only allowed for auto traits. "##, -E0265: r##" -This error indicates that a static or constant references itself. -All statics and constants need to resolve to a value in an acyclic manner. - -For example, neither of the following can be sensibly compiled: - -```compile_fail,E0265 -const X: u32 = X; -``` - -```compile_fail,E0265 -const X: u32 = Y; -const Y: u32 = X; -``` -"##, - E0267: r##" This error indicates the use of a loop keyword (`break` or `continue`) inside a closure but outside of any loop. Erroneous code example: diff --git a/src/librustc_passes/lib.rs b/src/librustc_passes/lib.rs index 73c71ec0b2f00..bfcf68908bc8c 100644 --- a/src/librustc_passes/lib.rs +++ b/src/librustc_passes/lib.rs @@ -42,7 +42,6 @@ pub mod consts; pub mod hir_stats; pub mod loops; mod mir_stats; -pub mod static_recursion; #[cfg(not(stage0))] // remove after the next snapshot __build_diagnostic_array! { librustc_passes, DIAGNOSTICS } diff --git a/src/librustc_passes/static_recursion.rs b/src/librustc_passes/static_recursion.rs deleted file mode 100644 index 987243b523473..0000000000000 --- a/src/librustc_passes/static_recursion.rs +++ /dev/null @@ -1,280 +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. - -// This compiler pass detects constants that refer to themselves -// recursively. - -use rustc::hir::map as hir_map; -use rustc::session::Session; -use rustc::hir::def::{Def, CtorKind}; -use rustc::util::common::ErrorReported; -use rustc::util::nodemap::{NodeMap, NodeSet}; - -use syntax::ast; -use syntax_pos::Span; -use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap}; -use rustc::hir; - -struct CheckCrateVisitor<'a, 'hir: 'a> { - sess: &'a Session, - hir_map: &'a hir_map::Map<'hir>, - // `discriminant_map` is a cache that associates the `NodeId`s of local - // variant definitions with the discriminant expression that applies to - // each one. If the variant uses the default values (starting from `0`), - // then `None` is stored. - discriminant_map: NodeMap>, - detected_recursive_ids: NodeSet, -} - -impl<'a, 'hir: 'a> Visitor<'hir> for CheckCrateVisitor<'a, 'hir> { - fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'hir> { - NestedVisitorMap::None - } - - fn visit_item(&mut self, it: &'hir hir::Item) { - match it.node { - hir::ItemStatic(..) | - hir::ItemConst(..) => { - let mut recursion_visitor = CheckItemRecursionVisitor::new(self); - recursion_visitor.visit_item(it); - } - hir::ItemEnum(ref enum_def, ref generics) => { - // We could process the whole enum, but handling the variants - // with discriminant expressions one by one gives more specific, - // less redundant output. - for variant in &enum_def.variants { - if let Some(_) = variant.node.disr_expr { - let mut recursion_visitor = CheckItemRecursionVisitor::new(self); - recursion_visitor.populate_enum_discriminants(enum_def); - recursion_visitor.visit_variant(variant, generics, it.id); - } - } - } - _ => {} - } - intravisit::walk_item(self, it) - } - - fn visit_trait_item(&mut self, ti: &'hir hir::TraitItem) { - match ti.node { - hir::TraitItemKind::Const(_, ref default) => { - if let Some(_) = *default { - let mut recursion_visitor = CheckItemRecursionVisitor::new(self); - recursion_visitor.visit_trait_item(ti); - } - } - _ => {} - } - intravisit::walk_trait_item(self, ti) - } - - fn visit_impl_item(&mut self, ii: &'hir hir::ImplItem) { - match ii.node { - hir::ImplItemKind::Const(..) => { - let mut recursion_visitor = CheckItemRecursionVisitor::new(self); - recursion_visitor.visit_impl_item(ii); - } - _ => {} - } - intravisit::walk_impl_item(self, ii) - } -} - -pub fn check_crate<'hir>(sess: &Session, hir_map: &hir_map::Map<'hir>) - -> Result<(), ErrorReported> -{ - let mut visitor = CheckCrateVisitor { - sess, - hir_map, - discriminant_map: NodeMap(), - detected_recursive_ids: NodeSet(), - }; - sess.track_errors(|| { - // FIXME(#37712) could use ItemLikeVisitor if trait items were item-like - hir_map.krate().visit_all_item_likes(&mut visitor.as_deep_visitor()); - }) -} - -struct CheckItemRecursionVisitor<'a, 'b: 'a, 'hir: 'b> { - sess: &'b Session, - hir_map: &'b hir_map::Map<'hir>, - discriminant_map: &'a mut NodeMap>, - idstack: Vec, - detected_recursive_ids: &'a mut NodeSet, -} - -impl<'a, 'b: 'a, 'hir: 'b> CheckItemRecursionVisitor<'a, 'b, 'hir> { - fn new(v: &'a mut CheckCrateVisitor<'b, 'hir>) -> Self { - CheckItemRecursionVisitor { - sess: v.sess, - hir_map: v.hir_map, - discriminant_map: &mut v.discriminant_map, - idstack: Vec::new(), - detected_recursive_ids: &mut v.detected_recursive_ids, - } - } - fn with_item_id_pushed(&mut self, id: ast::NodeId, f: F, span: Span) - where F: Fn(&mut Self) - { - if self.idstack.iter().any(|&x| x == id) { - if self.detected_recursive_ids.contains(&id) { - return; - } - self.detected_recursive_ids.insert(id); - let any_static = self.idstack.iter().any(|&x| { - if let hir_map::NodeItem(item) = self.hir_map.get(x) { - if let hir::ItemStatic(..) = item.node { - true - } else { - false - } - } else { - false - } - }); - if !any_static { - struct_span_err!(self.sess, span, E0265, "recursive constant") - .span_label(span, "recursion not allowed in constant") - .emit(); - } - return; - } - self.idstack.push(id); - f(self); - self.idstack.pop(); - } - // If a variant has an expression specifying its discriminant, then it needs - // to be checked just like a static or constant. However, if there are more - // variants with no explicitly specified discriminant, those variants will - // increment the same expression to get their values. - // - // So for every variant, we need to track whether there is an expression - // somewhere in the enum definition that controls its discriminant. We do - // this by starting from the end and searching backward. - fn populate_enum_discriminants(&mut self, enum_definition: &'hir hir::EnumDef) { - // Get the map, and return if we already processed this enum or if it - // has no variants. - match enum_definition.variants.first() { - None => { - return; - } - Some(variant) if self.discriminant_map.contains_key(&variant.node.data.id()) => { - return; - } - _ => {} - } - - // Go through all the variants. - let mut variant_stack: Vec = Vec::new(); - for variant in enum_definition.variants.iter().rev() { - variant_stack.push(variant.node.data.id()); - // When we find an expression, every variant currently on the stack - // is affected by that expression. - if let Some(expr) = variant.node.disr_expr { - for id in &variant_stack { - self.discriminant_map.insert(*id, Some(expr)); - } - variant_stack.clear() - } - } - // If we are at the top, that always starts at 0, so any variant on the - // stack has a default value and does not need to be checked. - for id in &variant_stack { - self.discriminant_map.insert(*id, None); - } - } -} - -impl<'a, 'b: 'a, 'hir: 'b> Visitor<'hir> for CheckItemRecursionVisitor<'a, 'b, 'hir> { - fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'hir> { - NestedVisitorMap::OnlyBodies(&self.hir_map) - } - fn visit_item(&mut self, it: &'hir hir::Item) { - self.with_item_id_pushed(it.id, |v| intravisit::walk_item(v, it), it.span); - } - - fn visit_enum_def(&mut self, - enum_definition: &'hir hir::EnumDef, - generics: &'hir hir::Generics, - item_id: ast::NodeId, - _: Span) { - self.populate_enum_discriminants(enum_definition); - intravisit::walk_enum_def(self, enum_definition, generics, item_id); - } - - fn visit_variant(&mut self, - variant: &'hir hir::Variant, - _: &'hir hir::Generics, - _: ast::NodeId) { - let variant_id = variant.node.data.id(); - let maybe_expr = *self.discriminant_map.get(&variant_id).unwrap_or_else(|| { - span_bug!(variant.span, - "`check_static_recursion` attempted to visit \ - variant with unknown discriminant") - }); - // If `maybe_expr` is `None`, that's because no discriminant is - // specified that affects this variant. Thus, no risk of recursion. - if let Some(expr) = maybe_expr { - let expr = &self.hir_map.body(expr).value; - self.with_item_id_pushed(expr.id, |v| intravisit::walk_expr(v, expr), expr.span); - } - } - - fn visit_trait_item(&mut self, ti: &'hir hir::TraitItem) { - self.with_item_id_pushed(ti.id, |v| intravisit::walk_trait_item(v, ti), ti.span); - } - - fn visit_impl_item(&mut self, ii: &'hir hir::ImplItem) { - self.with_item_id_pushed(ii.id, |v| intravisit::walk_impl_item(v, ii), ii.span); - } - - fn visit_path(&mut self, path: &'hir hir::Path, _: ast::NodeId) { - match path.def { - Def::Static(def_id, _) | - Def::AssociatedConst(def_id) | - Def::Const(def_id) => { - if let Some(node_id) = self.hir_map.as_local_node_id(def_id) { - match self.hir_map.get(node_id) { - hir_map::NodeItem(item) => self.visit_item(item), - hir_map::NodeTraitItem(item) => self.visit_trait_item(item), - hir_map::NodeImplItem(item) => self.visit_impl_item(item), - hir_map::NodeForeignItem(_) => {} - _ => { - span_bug!(path.span, - "expected item, found {}", - self.hir_map.node_to_string(node_id)); - } - } - } - } - // For variants, we only want to check expressions that - // affect the specific variant used, but we need to check - // the whole enum definition to see what expression that - // might be (if any). - Def::VariantCtor(variant_id, CtorKind::Const) => { - if let Some(variant_id) = self.hir_map.as_local_node_id(variant_id) { - let variant = self.hir_map.expect_variant(variant_id); - let enum_id = self.hir_map.get_parent(variant_id); - let enum_item = self.hir_map.expect_item(enum_id); - if let hir::ItemEnum(ref enum_def, ref generics) = enum_item.node { - self.populate_enum_discriminants(enum_def); - self.visit_variant(variant, generics, enum_id); - } else { - span_bug!(path.span, - "`check_static_recursion` found \ - non-enum in Def::VariantCtor"); - } - } - } - _ => (), - } - intravisit::walk_path(self, path); - } -} diff --git a/src/test/compile-fail/issue-17252.rs b/src/test/compile-fail/issue-17252.rs index 0c04e295e1458..1c3e6890c8e2e 100644 --- a/src/test/compile-fail/issue-17252.rs +++ b/src/test/compile-fail/issue-17252.rs @@ -8,12 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -const FOO: usize = FOO; //~ ERROR recursive constant +const FOO: usize = FOO; //~ ERROR E0391 fn main() { let _x: [u8; FOO]; // caused stack overflow prior to fix let _y: usize = 1 + { - const BAR: usize = BAR; //~ ERROR recursive constant + const BAR: usize = BAR; let _z: [u8; BAR]; // caused stack overflow prior to fix 1 }; diff --git a/src/test/ui/issue-23302.rs b/src/test/ui/issue-23302-1.rs similarity index 71% rename from src/test/ui/issue-23302.rs rename to src/test/ui/issue-23302-1.rs index 2d93ab0c30c8f..10a538301162c 100644 --- a/src/test/ui/issue-23302.rs +++ b/src/test/ui/issue-23302-1.rs @@ -11,18 +11,7 @@ // Check that an enum with recursion in the discriminant throws // the appropriate error (rather than, say, blowing the stack). enum X { - A = X::A as isize, //~ ERROR E0265 + A = X::A as isize, //~ ERROR E0391 } -// Since `Y::B` here defaults to `Y::A+1`, this is also a -// recursive definition. -enum Y { - A = Y::B as isize, //~ ERROR E0265 - B, -} - -const A: i32 = B; //~ ERROR E0265 - -const B: i32 = A; //~ ERROR E0265 - fn main() { } diff --git a/src/test/ui/issue-23302-1.stderr b/src/test/ui/issue-23302-1.stderr new file mode 100644 index 0000000000000..4fbd0e72bf2c8 --- /dev/null +++ b/src/test/ui/issue-23302-1.stderr @@ -0,0 +1,15 @@ +error[E0391]: unsupported cyclic reference between types/traits detected + --> $DIR/issue-23302-1.rs:14:9 + | +14 | A = X::A as isize, //~ ERROR E0391 + | ^^^^^^^^^^^^^ cyclic reference + | +note: the cycle begins when const-evaluating `X::A::{{initializer}}`... + --> $DIR/issue-23302-1.rs:14:5 + | +14 | A = X::A as isize, //~ ERROR E0391 + | ^^^^^^^^^^^^^^^^^ + = note: ...which then again requires const-evaluating `X::A::{{initializer}}`, completing the cycle. + +error: aborting due to previous error + diff --git a/src/test/compile-fail/issue-17718-recursive.rs b/src/test/ui/issue-23302-2.rs similarity index 64% rename from src/test/compile-fail/issue-17718-recursive.rs rename to src/test/ui/issue-23302-2.rs index 9959b0c6fc523..d1af19eb579f5 100644 --- a/src/test/compile-fail/issue-17718-recursive.rs +++ b/src/test/ui/issue-23302-2.rs @@ -1,4 +1,4 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// 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. // @@ -8,7 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -const A: usize = B; //~ ERROR: recursive constant -const B: usize = A; //~ ERROR: recursive constant +// Since `Y::B` here defaults to `Y::A+1`, this is also a +// recursive definition. +enum Y { + A = Y::B as isize, //~ ERROR E0391 + B, +} -fn main() {} +fn main() { } diff --git a/src/test/ui/issue-23302-2.stderr b/src/test/ui/issue-23302-2.stderr new file mode 100644 index 0000000000000..90d828621e937 --- /dev/null +++ b/src/test/ui/issue-23302-2.stderr @@ -0,0 +1,15 @@ +error[E0391]: unsupported cyclic reference between types/traits detected + --> $DIR/issue-23302-2.rs:14:9 + | +14 | A = Y::B as isize, //~ ERROR E0391 + | ^^^^^^^^^^^^^ cyclic reference + | +note: the cycle begins when const-evaluating `Y::A::{{initializer}}`... + --> $DIR/issue-23302-2.rs:14:5 + | +14 | A = Y::B as isize, //~ ERROR E0391 + | ^^^^^^^^^^^^^^^^^ + = note: ...which then again requires const-evaluating `Y::A::{{initializer}}`, completing the cycle. + +error: aborting due to previous error + diff --git a/src/test/compile-fail/const-recursive.rs b/src/test/ui/issue-23302-3.rs similarity index 69% rename from src/test/compile-fail/const-recursive.rs rename to src/test/ui/issue-23302-3.rs index 7c05a817243b4..1d750b09025b9 100644 --- a/src/test/compile-fail/const-recursive.rs +++ b/src/test/ui/issue-23302-3.rs @@ -1,4 +1,4 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// 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. // @@ -8,8 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -const a: isize = b; //~ ERROR recursive constant -const b: isize = a; //~ ERROR recursive constant +const A: i32 = B; //~ ERROR E0391 -fn main() { -} +const B: i32 = A; + +fn main() { } diff --git a/src/test/ui/issue-23302-3.stderr b/src/test/ui/issue-23302-3.stderr new file mode 100644 index 0000000000000..a72010c2c797f --- /dev/null +++ b/src/test/ui/issue-23302-3.stderr @@ -0,0 +1,20 @@ +error[E0391]: unsupported cyclic reference between types/traits detected + --> $DIR/issue-23302-3.rs:11:16 + | +11 | const A: i32 = B; //~ ERROR E0391 + | ^ cyclic reference + | +note: the cycle begins when processing `B`... + --> $DIR/issue-23302-3.rs:13:1 + | +13 | const B: i32 = A; + | ^^^^^^^^^^^^^^^^^ +note: ...which then requires processing `A`... + --> $DIR/issue-23302-3.rs:13:16 + | +13 | const B: i32 = A; + | ^ + = note: ...which then again requires processing `B`, completing the cycle. + +error: aborting due to previous error + diff --git a/src/test/ui/issue-23302.stderr b/src/test/ui/issue-23302.stderr deleted file mode 100644 index 4e93809fac374..0000000000000 --- a/src/test/ui/issue-23302.stderr +++ /dev/null @@ -1,26 +0,0 @@ -error[E0265]: recursive constant - --> $DIR/issue-23302.rs:14:9 - | -14 | A = X::A as isize, //~ ERROR E0265 - | ^^^^^^^^^^^^^ recursion not allowed in constant - -error[E0265]: recursive constant - --> $DIR/issue-23302.rs:20:9 - | -20 | A = Y::B as isize, //~ ERROR E0265 - | ^^^^^^^^^^^^^ recursion not allowed in constant - -error[E0265]: recursive constant - --> $DIR/issue-23302.rs:24:1 - | -24 | const A: i32 = B; //~ ERROR E0265 - | ^^^^^^^^^^^^^^^^^ recursion not allowed in constant - -error[E0265]: recursive constant - --> $DIR/issue-23302.rs:26:1 - | -26 | const B: i32 = A; //~ ERROR E0265 - | ^^^^^^^^^^^^^^^^^ recursion not allowed in constant - -error: aborting due to 4 previous errors - diff --git a/src/test/ui/issue-36163.rs b/src/test/ui/issue-36163.rs index 2337f82afa49f..4c74d9d9173d8 100644 --- a/src/test/ui/issue-36163.rs +++ b/src/test/ui/issue-36163.rs @@ -8,16 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -const A: i32 = Foo::B; //~ ERROR E0265 +const A: isize = Foo::B as isize; enum Foo { - B = A, //~ ERROR E0265 + B = A, //~ ERROR E0391 } -enum Bar { - C = Bar::C, //~ ERROR E0265 -} - -const D: i32 = A; - fn main() {} diff --git a/src/test/ui/issue-36163.stderr b/src/test/ui/issue-36163.stderr index 5a107d88f2e4f..3868d58e7f7ae 100644 --- a/src/test/ui/issue-36163.stderr +++ b/src/test/ui/issue-36163.stderr @@ -1,20 +1,20 @@ -error[E0265]: recursive constant - --> $DIR/issue-36163.rs:11:1 - | -11 | const A: i32 = Foo::B; //~ ERROR E0265 - | ^^^^^^^^^^^^^^^^^^^^^^ recursion not allowed in constant - -error[E0265]: recursive constant +error[E0391]: unsupported cyclic reference between types/traits detected --> $DIR/issue-36163.rs:14:9 | -14 | B = A, //~ ERROR E0265 - | ^ recursion not allowed in constant - -error[E0265]: recursive constant - --> $DIR/issue-36163.rs:18:9 +14 | B = A, //~ ERROR E0391 + | ^ cyclic reference + | +note: the cycle begins when const-evaluating `Foo::B::{{initializer}}`... + --> $DIR/issue-36163.rs:14:5 + | +14 | B = A, //~ ERROR E0391 + | ^^^^^ +note: ...which then requires const-evaluating `A`... + --> $DIR/issue-36163.rs:14:9 | -18 | C = Bar::C, //~ ERROR E0265 - | ^^^^^^ recursion not allowed in constant +14 | B = A, //~ ERROR E0391 + | ^ + = note: ...which then again requires const-evaluating `Foo::B::{{initializer}}`, completing the cycle. -error: aborting due to 3 previous errors +error: aborting due to previous error From 46a3f2fa188a8b8c68a2941afb43182691662493 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Sat, 10 Feb 2018 00:28:23 +0100 Subject: [PATCH 02/34] Change error message for E0391 to "cyclic dependency detected" --- src/librustc/ty/maps/plumbing.rs | 2 +- .../coherence-inherited-assoc-ty-cycle-err.rs | 2 +- src/test/compile-fail/const-size_of-cycle.rs | 2 +- .../cycle-projection-based-on-where-clause.rs | 2 +- .../compile-fail/cycle-trait-default-type-trait.rs | 2 +- src/test/compile-fail/cycle-trait-supertrait-direct.rs | 2 +- src/test/compile-fail/infinite-vec-type-recursion.rs | 2 +- src/test/compile-fail/issue-20772.rs | 2 +- src/test/compile-fail/issue-20825.rs | 2 +- src/test/compile-fail/issue-21177.rs | 2 +- src/test/compile-fail/issue-22673.rs | 2 +- src/test/compile-fail/issue-26548.rs | 2 +- src/test/compile-fail/issue-34373.rs | 2 +- src/test/compile-fail/issue-44415.rs | 2 +- src/test/compile-fail/resolve-self-in-impl.rs | 10 +++++----- src/test/ui/cycle-trait-supertrait-indirect.rs | 2 +- src/test/ui/cycle-trait-supertrait-indirect.stderr | 2 +- src/test/ui/impl-trait/auto-trait-leak.rs | 2 +- src/test/ui/impl-trait/auto-trait-leak.stderr | 2 +- src/test/ui/issue-12511.rs | 2 +- src/test/ui/issue-12511.stderr | 2 +- src/test/ui/issue-23302-1.stderr | 2 +- src/test/ui/issue-23302-2.stderr | 2 +- src/test/ui/issue-23302-3.stderr | 2 +- src/test/ui/issue-36163.stderr | 2 +- src/test/ui/resolve/issue-23305.rs | 2 +- src/test/ui/resolve/issue-23305.stderr | 2 +- 27 files changed, 31 insertions(+), 31 deletions(-) diff --git a/src/librustc/ty/maps/plumbing.rs b/src/librustc/ty/maps/plumbing.rs index 0ab6ee1a54a9b..1a2b80626fe47 100644 --- a/src/librustc/ty/maps/plumbing.rs +++ b/src/librustc/ty/maps/plumbing.rs @@ -84,7 +84,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { let span = self.sess.codemap().def_span(span); let mut err = struct_span_err!(self.sess, span, E0391, - "unsupported cyclic reference between types/traits detected"); + "cyclic dependency detected"); err.span_label(span, "cyclic reference"); err.span_note(self.sess.codemap().def_span(stack[0].0), diff --git a/src/test/compile-fail/coherence-inherited-assoc-ty-cycle-err.rs b/src/test/compile-fail/coherence-inherited-assoc-ty-cycle-err.rs index 5d7f33967402c..2f4d82e2ef514 100644 --- a/src/test/compile-fail/coherence-inherited-assoc-ty-cycle-err.rs +++ b/src/test/compile-fail/coherence-inherited-assoc-ty-cycle-err.rs @@ -17,7 +17,7 @@ #![feature(specialization)] trait Trait { type Assoc; } -//~^ unsupported cyclic reference between types/traits detected [E0391] +//~^ cyclic dependency detected [E0391] impl Trait for Vec { type Assoc = (); diff --git a/src/test/compile-fail/const-size_of-cycle.rs b/src/test/compile-fail/const-size_of-cycle.rs index cbeafdfe6acc9..6218dcbf5f2c5 100644 --- a/src/test/compile-fail/const-size_of-cycle.rs +++ b/src/test/compile-fail/const-size_of-cycle.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// error-pattern: unsupported cyclic reference between types/traits detected +// error-pattern: cyclic dependency detected #![feature(const_fn)] diff --git a/src/test/compile-fail/cycle-projection-based-on-where-clause.rs b/src/test/compile-fail/cycle-projection-based-on-where-clause.rs index 7af2f11bd2815..ee4722c010f16 100644 --- a/src/test/compile-fail/cycle-projection-based-on-where-clause.rs +++ b/src/test/compile-fail/cycle-projection-based-on-where-clause.rs @@ -25,7 +25,7 @@ trait Trait { type Item; } struct A where T : Trait, T : Add - //~^ ERROR unsupported cyclic reference between types/traits detected + //~^ ERROR cyclic dependency detected //~| ERROR associated type `Item` not found for `T` { data: T diff --git a/src/test/compile-fail/cycle-trait-default-type-trait.rs b/src/test/compile-fail/cycle-trait-default-type-trait.rs index e6caeb34a8c8f..88672088bcb4c 100644 --- a/src/test/compile-fail/cycle-trait-default-type-trait.rs +++ b/src/test/compile-fail/cycle-trait-default-type-trait.rs @@ -12,7 +12,7 @@ // again references the trait. trait Foo> { - //~^ ERROR unsupported cyclic reference + //~^ ERROR cyclic dependency detected } fn main() { } diff --git a/src/test/compile-fail/cycle-trait-supertrait-direct.rs b/src/test/compile-fail/cycle-trait-supertrait-direct.rs index ef3fead18f6aa..626567ccc0ead 100644 --- a/src/test/compile-fail/cycle-trait-supertrait-direct.rs +++ b/src/test/compile-fail/cycle-trait-supertrait-direct.rs @@ -11,7 +11,7 @@ // Test a supertrait cycle where a trait extends itself. trait Chromosome: Chromosome { - //~^ ERROR unsupported cyclic reference + //~^ ERROR cyclic dependency detected } fn main() { } diff --git a/src/test/compile-fail/infinite-vec-type-recursion.rs b/src/test/compile-fail/infinite-vec-type-recursion.rs index e5120840f7672..25d0590db1b75 100644 --- a/src/test/compile-fail/infinite-vec-type-recursion.rs +++ b/src/test/compile-fail/infinite-vec-type-recursion.rs @@ -9,6 +9,6 @@ // except according to those terms. type x = Vec; -//~^ ERROR unsupported cyclic reference +//~^ ERROR cyclic dependency detected fn main() { let b: x = Vec::new(); } diff --git a/src/test/compile-fail/issue-20772.rs b/src/test/compile-fail/issue-20772.rs index 7ae4250d4203b..88395e5f1eafa 100644 --- a/src/test/compile-fail/issue-20772.rs +++ b/src/test/compile-fail/issue-20772.rs @@ -9,7 +9,7 @@ // except according to those terms. trait T : Iterator -//~^ ERROR unsupported cyclic reference between types/traits detected +//~^ ERROR cyclic dependency detected //~| ERROR associated type `Item` not found for `Self` {} diff --git a/src/test/compile-fail/issue-20825.rs b/src/test/compile-fail/issue-20825.rs index 7d082a3148f76..aeb798b382875 100644 --- a/src/test/compile-fail/issue-20825.rs +++ b/src/test/compile-fail/issue-20825.rs @@ -13,7 +13,7 @@ pub trait Subscriber { } pub trait Processor: Subscriber { - //~^ ERROR unsupported cyclic reference between types/traits detected [E0391] + //~^ ERROR cyclic dependency detected [E0391] type Input; } diff --git a/src/test/compile-fail/issue-21177.rs b/src/test/compile-fail/issue-21177.rs index f49b71953835b..40c95b98f1264 100644 --- a/src/test/compile-fail/issue-21177.rs +++ b/src/test/compile-fail/issue-21177.rs @@ -14,7 +14,7 @@ trait Trait { } fn foo>() { } -//~^ ERROR unsupported cyclic reference between types/traits detected +//~^ ERROR cyclic dependency detected //~| ERROR associated type `B` not found for `T` fn main() { } diff --git a/src/test/compile-fail/issue-22673.rs b/src/test/compile-fail/issue-22673.rs index 442e6bcda5a09..fde2d001542b8 100644 --- a/src/test/compile-fail/issue-22673.rs +++ b/src/test/compile-fail/issue-22673.rs @@ -9,7 +9,7 @@ // except according to those terms. trait Expr : PartialEq { - //~^ ERROR: unsupported cyclic reference between types/traits detected + //~^ ERROR: cyclic dependency detected type Item; } diff --git a/src/test/compile-fail/issue-26548.rs b/src/test/compile-fail/issue-26548.rs index 39c6e97268f98..16a650cc6d886 100644 --- a/src/test/compile-fail/issue-26548.rs +++ b/src/test/compile-fail/issue-26548.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// error-pattern: unsupported cyclic reference between types/traits detected +// error-pattern: cyclic dependency detected // note-pattern: the cycle begins when computing layout of // note-pattern: ...which then requires computing layout of // note-pattern: ...which then again requires computing layout of diff --git a/src/test/compile-fail/issue-34373.rs b/src/test/compile-fail/issue-34373.rs index 7bbc680197e84..b18e05af47c97 100644 --- a/src/test/compile-fail/issue-34373.rs +++ b/src/test/compile-fail/issue-34373.rs @@ -15,7 +15,7 @@ trait Trait { } pub struct Foo>>; -type DefaultFoo = Foo; //~ ERROR unsupported cyclic reference +type DefaultFoo = Foo; //~ ERROR cyclic dependency detected fn main() { } diff --git a/src/test/compile-fail/issue-44415.rs b/src/test/compile-fail/issue-44415.rs index 3b7089f497526..930a427e9a5e0 100644 --- a/src/test/compile-fail/issue-44415.rs +++ b/src/test/compile-fail/issue-44415.rs @@ -15,7 +15,7 @@ use std::intrinsics; struct Foo { bytes: [u8; unsafe { intrinsics::size_of::() }], - //~^ ERROR unsupported cyclic reference between types/traits detected + //~^ ERROR cyclic dependency detected x: usize, } diff --git a/src/test/compile-fail/resolve-self-in-impl.rs b/src/test/compile-fail/resolve-self-in-impl.rs index 55ae37404a9fa..7210c857125d6 100644 --- a/src/test/compile-fail/resolve-self-in-impl.rs +++ b/src/test/compile-fail/resolve-self-in-impl.rs @@ -21,10 +21,10 @@ impl Tr for S where Self: Copy {} // OK impl Tr for S where S: Copy {} // OK impl Tr for S where Self::A: Copy {} // OK -impl Tr for Self {} //~ ERROR unsupported cyclic reference between types/traits detected -impl Tr for S {} //~ ERROR unsupported cyclic reference between types/traits detected -impl Self {} //~ ERROR unsupported cyclic reference between types/traits detected -impl S {} //~ ERROR unsupported cyclic reference between types/traits detected -impl Tr for S {} //~ ERROR unsupported cyclic reference between types/traits detected +impl Tr for Self {} //~ ERROR cyclic dependency detected +impl Tr for S {} //~ ERROR cyclic dependency detected +impl Self {} //~ ERROR cyclic dependency detected +impl S {} //~ ERROR cyclic dependency detected +impl Tr for S {} //~ ERROR cyclic dependency detected fn main() {} diff --git a/src/test/ui/cycle-trait-supertrait-indirect.rs b/src/test/ui/cycle-trait-supertrait-indirect.rs index c3b0276bcf9cb..447505e886f81 100644 --- a/src/test/ui/cycle-trait-supertrait-indirect.rs +++ b/src/test/ui/cycle-trait-supertrait-indirect.rs @@ -18,7 +18,7 @@ trait B: C { } trait C: B { } - //~^ ERROR unsupported cyclic reference + //~^ ERROR cyclic dependency detected //~| cyclic reference fn main() { } diff --git a/src/test/ui/cycle-trait-supertrait-indirect.stderr b/src/test/ui/cycle-trait-supertrait-indirect.stderr index 107644037a9ca..a01565546462d 100644 --- a/src/test/ui/cycle-trait-supertrait-indirect.stderr +++ b/src/test/ui/cycle-trait-supertrait-indirect.stderr @@ -1,4 +1,4 @@ -error[E0391]: unsupported cyclic reference between types/traits detected +error[E0391]: cyclic dependency detected --> $DIR/cycle-trait-supertrait-indirect.rs:20:1 | 20 | trait C: B { } diff --git a/src/test/ui/impl-trait/auto-trait-leak.rs b/src/test/ui/impl-trait/auto-trait-leak.rs index 705390e3b969c..5a6aac43ec770 100644 --- a/src/test/ui/impl-trait/auto-trait-leak.rs +++ b/src/test/ui/impl-trait/auto-trait-leak.rs @@ -42,7 +42,7 @@ fn after() -> impl Fn(i32) { // independently resolved and only require the concrete // return type, which can't depend on the obligation. fn cycle1() -> impl Clone { - //~^ ERROR unsupported cyclic reference between types/traits detected + //~^ ERROR cyclic dependency detected //~| cyclic reference send(cycle2().clone()); diff --git a/src/test/ui/impl-trait/auto-trait-leak.stderr b/src/test/ui/impl-trait/auto-trait-leak.stderr index 838a3002e3aa7..d6e31ba1e1f9c 100644 --- a/src/test/ui/impl-trait/auto-trait-leak.stderr +++ b/src/test/ui/impl-trait/auto-trait-leak.stderr @@ -28,7 +28,7 @@ note: required by `send` 24 | fn send(_: T) {} | ^^^^^^^^^^^^^^^^^^^^^^ -error[E0391]: unsupported cyclic reference between types/traits detected +error[E0391]: cyclic dependency detected --> $DIR/auto-trait-leak.rs:44:1 | 44 | fn cycle1() -> impl Clone { diff --git a/src/test/ui/issue-12511.rs b/src/test/ui/issue-12511.rs index e1335c7d558e1..e4d6076868717 100644 --- a/src/test/ui/issue-12511.rs +++ b/src/test/ui/issue-12511.rs @@ -12,7 +12,7 @@ trait t1 : t2 { } trait t2 : t1 { -//~^ ERROR unsupported cyclic reference between types/traits detected +//~^ ERROR cyclic dependency detected //~| cyclic reference } diff --git a/src/test/ui/issue-12511.stderr b/src/test/ui/issue-12511.stderr index cbf005a70b028..aec828a90d1a7 100644 --- a/src/test/ui/issue-12511.stderr +++ b/src/test/ui/issue-12511.stderr @@ -1,4 +1,4 @@ -error[E0391]: unsupported cyclic reference between types/traits detected +error[E0391]: cyclic dependency detected --> $DIR/issue-12511.rs:14:1 | 14 | trait t2 : t1 { diff --git a/src/test/ui/issue-23302-1.stderr b/src/test/ui/issue-23302-1.stderr index 4fbd0e72bf2c8..0658c07fb1dbe 100644 --- a/src/test/ui/issue-23302-1.stderr +++ b/src/test/ui/issue-23302-1.stderr @@ -1,4 +1,4 @@ -error[E0391]: unsupported cyclic reference between types/traits detected +error[E0391]: cyclic dependency detected --> $DIR/issue-23302-1.rs:14:9 | 14 | A = X::A as isize, //~ ERROR E0391 diff --git a/src/test/ui/issue-23302-2.stderr b/src/test/ui/issue-23302-2.stderr index 90d828621e937..c4a1c4f80c82c 100644 --- a/src/test/ui/issue-23302-2.stderr +++ b/src/test/ui/issue-23302-2.stderr @@ -1,4 +1,4 @@ -error[E0391]: unsupported cyclic reference between types/traits detected +error[E0391]: cyclic dependency detected --> $DIR/issue-23302-2.rs:14:9 | 14 | A = Y::B as isize, //~ ERROR E0391 diff --git a/src/test/ui/issue-23302-3.stderr b/src/test/ui/issue-23302-3.stderr index a72010c2c797f..76f543cff7913 100644 --- a/src/test/ui/issue-23302-3.stderr +++ b/src/test/ui/issue-23302-3.stderr @@ -1,4 +1,4 @@ -error[E0391]: unsupported cyclic reference between types/traits detected +error[E0391]: cyclic dependency detected --> $DIR/issue-23302-3.rs:11:16 | 11 | const A: i32 = B; //~ ERROR E0391 diff --git a/src/test/ui/issue-36163.stderr b/src/test/ui/issue-36163.stderr index 3868d58e7f7ae..d0337fc32b03e 100644 --- a/src/test/ui/issue-36163.stderr +++ b/src/test/ui/issue-36163.stderr @@ -1,4 +1,4 @@ -error[E0391]: unsupported cyclic reference between types/traits detected +error[E0391]: cyclic dependency detected --> $DIR/issue-36163.rs:14:9 | 14 | B = A, //~ ERROR E0391 diff --git a/src/test/ui/resolve/issue-23305.rs b/src/test/ui/resolve/issue-23305.rs index f249e0e1127ee..34f8a0a48431c 100644 --- a/src/test/ui/resolve/issue-23305.rs +++ b/src/test/ui/resolve/issue-23305.rs @@ -13,6 +13,6 @@ pub trait ToNbt { } impl ToNbt {} -//~^ ERROR unsupported cyclic reference +//~^ ERROR cyclic dependency detected fn main() {} diff --git a/src/test/ui/resolve/issue-23305.stderr b/src/test/ui/resolve/issue-23305.stderr index 5bba9fc41e276..a0b4d424ec968 100644 --- a/src/test/ui/resolve/issue-23305.stderr +++ b/src/test/ui/resolve/issue-23305.stderr @@ -1,4 +1,4 @@ -error[E0391]: unsupported cyclic reference between types/traits detected +error[E0391]: cyclic dependency detected --> $DIR/issue-23305.rs:15:12 | 15 | impl ToNbt {} From 335e25fd79e57c4cd7453c0af25e5c6bd0406602 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Tue, 13 Feb 2018 15:50:37 +0100 Subject: [PATCH 03/34] incr.comp.: Don't keep RefCells in on-disk-cache borrowed in order to allow for recursive invocations. --- src/librustc/ty/maps/on_disk_cache.rs | 34 +++++++++++++++------------ 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/src/librustc/ty/maps/on_disk_cache.rs b/src/librustc/ty/maps/on_disk_cache.rs index 56ed0f9106f30..17b44f6959f2f 100644 --- a/src/librustc/ty/maps/on_disk_cache.rs +++ b/src/librustc/ty/maps/on_disk_cache.rs @@ -347,22 +347,21 @@ impl<'sess> OnDiskCache<'sess> { return None }; - let mut cnum_map = self.cnum_map.borrow_mut(); - if cnum_map.is_none() { + // Initialize the cnum_map if it is not initialized yet. + if self.cnum_map.borrow().is_none() { + let mut cnum_map = self.cnum_map.borrow_mut(); *cnum_map = Some(Self::compute_cnum_map(tcx, &self.prev_cnums[..])); } - - let mut synthetic_expansion_infos = self.synthetic_expansion_infos.borrow_mut(); - let mut file_index_to_file = self.file_index_to_file.borrow_mut(); + let cnum_map = self.cnum_map.borrow(); let mut decoder = CacheDecoder { tcx, opaque: opaque::Decoder::new(&self.serialized_data[..], pos.to_usize()), codemap: self.codemap, cnum_map: cnum_map.as_ref().unwrap(), - file_index_to_file: &mut file_index_to_file, + file_index_to_file: &self.file_index_to_file, file_index_to_stable_id: &self.file_index_to_stable_id, - synthetic_expansion_infos: &mut synthetic_expansion_infos, + synthetic_expansion_infos: &self.synthetic_expansion_infos, }; match decode_tagged(&mut decoder, dep_node_index) { @@ -421,21 +420,21 @@ struct CacheDecoder<'a, 'tcx: 'a, 'x> { opaque: opaque::Decoder<'x>, codemap: &'x CodeMap, cnum_map: &'x IndexVec>, - synthetic_expansion_infos: &'x mut FxHashMap, - file_index_to_file: &'x mut FxHashMap>, + synthetic_expansion_infos: &'x RefCell>, + file_index_to_file: &'x RefCell>>, file_index_to_stable_id: &'x FxHashMap, } impl<'a, 'tcx, 'x> CacheDecoder<'a, 'tcx, 'x> { - fn file_index_to_file(&mut self, index: FileMapIndex) -> Rc { + fn file_index_to_file(&self, index: FileMapIndex) -> Rc { let CacheDecoder { - ref mut file_index_to_file, + ref file_index_to_file, ref file_index_to_stable_id, ref codemap, .. } = *self; - file_index_to_file.entry(index).or_insert_with(|| { + file_index_to_file.borrow_mut().entry(index).or_insert_with(|| { let stable_id = file_index_to_stable_id[&index]; codemap.filemap_by_stable_id(stable_id) .expect("Failed to lookup FileMap in new context.") @@ -572,19 +571,24 @@ impl<'a, 'tcx, 'x> SpecializedDecoder for CacheDecoder<'a, 'tcx, 'x> { let pos = AbsoluteBytePos::new(self.opaque.position()); let expn_info: ExpnInfo = Decodable::decode(self)?; let ctxt = SyntaxContext::allocate_directly(expn_info); - self.synthetic_expansion_infos.insert(pos, ctxt); + self.synthetic_expansion_infos.borrow_mut().insert(pos, ctxt); ctxt } TAG_EXPANSION_INFO_SHORTHAND => { let pos = AbsoluteBytePos::decode(self)?; - if let Some(ctxt) = self.synthetic_expansion_infos.get(&pos).cloned() { + let cached_ctxt = self.synthetic_expansion_infos + .borrow() + .get(&pos) + .cloned(); + + if let Some(ctxt) = cached_ctxt { ctxt } else { let expn_info = self.with_position(pos.to_usize(), |this| { ExpnInfo::decode(this) })?; let ctxt = SyntaxContext::allocate_directly(expn_info); - self.synthetic_expansion_infos.insert(pos, ctxt); + self.synthetic_expansion_infos.borrow_mut().insert(pos, ctxt); ctxt } } From 75f72c0de141573eef56f13fd48a3af12deaee4f Mon Sep 17 00:00:00 2001 From: Taylor Cramer Date: Thu, 8 Feb 2018 15:40:27 -0800 Subject: [PATCH 04/34] Make nested impl Trait a hard error --- src/librustc_passes/ast_validation.rs | 69 ++++++++++++++++++ src/librustc_passes/diagnostics.rs | 1 + src/libsyntax/feature_gate.rs | 70 +------------------ .../compile-fail/impl-trait/where-allowed.rs | 4 +- src/test/run-pass/impl-trait/lifetimes.rs | 11 ++- src/test/ui/error-codes/E0657.rs | 6 +- .../nested_impl_trait.rs} | 10 +-- src/test/ui/nested_impl_trait.stderr | 50 +++++++++++++ 8 files changed, 138 insertions(+), 83 deletions(-) rename src/test/{compile-fail/feature-gate-nested_impl_trait.rs => ui/nested_impl_trait.rs} (80%) create mode 100644 src/test/ui/nested_impl_trait.stderr diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs index 6971033c8994b..826f27c2ddbf4 100644 --- a/src/librustc_passes/ast_validation.rs +++ b/src/librustc_passes/ast_validation.rs @@ -420,6 +420,75 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } } +// Bans nested `impl Trait`, e.g. `impl Into`. +// Nested `impl Trait` _is_ allowed in associated type position, +// e.g `impl Iterator` +struct NestedImplTraitVisitor<'a> { + session: &'a Session, + outer_impl_trait: Option, +} + +impl<'a> NestedImplTraitVisitor<'a> { + fn with_impl_trait(&mut self, outer_impl_trait: Option, f: F) + where F: FnOnce(&mut NestedImplTraitVisitor<'a>) + { + let old_outer_impl_trait = self.outer_impl_trait; + self.outer_impl_trait = outer_impl_trait; + f(self); + self.outer_impl_trait = old_outer_impl_trait; + } +} + + +impl<'a> Visitor<'a> for NestedImplTraitVisitor<'a> { + fn visit_ty(&mut self, t: &'a Ty) { + if let TyKind::ImplTrait(_) = t.node { + if let Some(outer_impl_trait) = self.outer_impl_trait { + struct_span_err!(self.session, t.span, E0666, + "nested `impl Trait` is not allowed") + .span_label(outer_impl_trait, "outer `impl Trait`") + .span_label(t.span, "devilishly nested `impl Trait` here") + .emit(); + + } + self.with_impl_trait(Some(t.span), |this| visit::walk_ty(this, t)); + } else { + visit::walk_ty(self, t); + } + } + fn visit_path_parameters(&mut self, _: Span, path_parameters: &'a PathParameters) { + match *path_parameters { + PathParameters::AngleBracketed(ref params) => { + for type_ in ¶ms.types { + self.visit_ty(type_); + } + for type_binding in ¶ms.bindings { + // Type bindings such as `Item=impl Debug` in `Iterator` + // are allowed to contain nested `impl Trait`. + self.with_impl_trait(None, |this| visit::walk_ty(this, &type_binding.ty)); + } + } + PathParameters::Parenthesized(ref params) => { + for type_ in ¶ms.inputs { + self.visit_ty(type_); + } + if let Some(ref type_) = params.output { + // `-> Foo` syntax is essentially an associated type binding, + // so it is also allowed to contain nested `impl Trait`. + self.with_impl_trait(None, |this| visit::walk_ty(this, type_)); + } + } + } + } +} + + pub fn check_crate(session: &Session, krate: &Crate) { + visit::walk_crate( + &mut NestedImplTraitVisitor { + session, + outer_impl_trait: None, + }, krate); + visit::walk_crate(&mut AstValidator { session: session }, krate) } diff --git a/src/librustc_passes/diagnostics.rs b/src/librustc_passes/diagnostics.rs index 743f7b7326e9e..6dfc52f842e16 100644 --- a/src/librustc_passes/diagnostics.rs +++ b/src/librustc_passes/diagnostics.rs @@ -320,4 +320,5 @@ register_diagnostics! { E0567, // auto traits can not have generic parameters E0568, // auto traits can not have super traits E0642, // patterns aren't allowed in methods without bodies + E0666, // nested `impl Trait` is illegal } diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index ea916d5168c33..a3eba63706cb0 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -432,9 +432,6 @@ declare_features! ( // `foo.rs` as an alternative to `foo/mod.rs` (active, non_modrs_mods, "1.24.0", Some(44660)), - // Nested `impl Trait` - (active, nested_impl_trait, "1.24.0", Some(34511)), - // Termination trait in main (RFC 1937) (active, termination_trait, "1.24.0", Some(43301)), @@ -1352,73 +1349,8 @@ fn contains_novel_literal(item: &ast::MetaItem) -> bool { } } -// Bans nested `impl Trait`, e.g. `impl Into`. -// Nested `impl Trait` _is_ allowed in associated type position, -// e.g `impl Iterator` -struct NestedImplTraitVisitor<'a> { - context: &'a Context<'a>, - is_in_impl_trait: bool, -} - -impl<'a> NestedImplTraitVisitor<'a> { - fn with_impl_trait(&mut self, is_in_impl_trait: bool, f: F) - where F: FnOnce(&mut NestedImplTraitVisitor<'a>) - { - let old_is_in_impl_trait = self.is_in_impl_trait; - self.is_in_impl_trait = is_in_impl_trait; - f(self); - self.is_in_impl_trait = old_is_in_impl_trait; - } -} - - -impl<'a> Visitor<'a> for NestedImplTraitVisitor<'a> { - fn visit_ty(&mut self, t: &'a ast::Ty) { - if let ast::TyKind::ImplTrait(_) = t.node { - if self.is_in_impl_trait { - gate_feature_post!(&self, nested_impl_trait, t.span, - "nested `impl Trait` is experimental" - ); - } - self.with_impl_trait(true, |this| visit::walk_ty(this, t)); - } else { - visit::walk_ty(self, t); - } - } - fn visit_path_parameters(&mut self, _: Span, path_parameters: &'a ast::PathParameters) { - match *path_parameters { - ast::PathParameters::AngleBracketed(ref params) => { - for type_ in ¶ms.types { - self.visit_ty(type_); - } - for type_binding in ¶ms.bindings { - // Type bindings such as `Item=impl Debug` in `Iterator` - // are allowed to contain nested `impl Trait`. - self.with_impl_trait(false, |this| visit::walk_ty(this, &type_binding.ty)); - } - } - ast::PathParameters::Parenthesized(ref params) => { - for type_ in ¶ms.inputs { - self.visit_ty(type_); - } - if let Some(ref type_) = params.output { - // `-> Foo` syntax is essentially an associated type binding, - // so it is also allowed to contain nested `impl Trait`. - self.with_impl_trait(false, |this| visit::walk_ty(this, type_)); - } - } - } - } -} - impl<'a> PostExpansionVisitor<'a> { - fn whole_crate_feature_gates(&mut self, krate: &ast::Crate) { - visit::walk_crate( - &mut NestedImplTraitVisitor { - context: self.context, - is_in_impl_trait: false, - }, krate); - + fn whole_crate_feature_gates(&mut self, _krate: &ast::Crate) { for &(ident, span) in &*self.context.parse_sess.non_modrs_mods.borrow() { if !span.allows_unstable() { let cx = &self.context; diff --git a/src/test/compile-fail/impl-trait/where-allowed.rs b/src/test/compile-fail/impl-trait/where-allowed.rs index a9fe1e04664e9..52c5471681df3 100644 --- a/src/test/compile-fail/impl-trait/where-allowed.rs +++ b/src/test/compile-fail/impl-trait/where-allowed.rs @@ -10,7 +10,7 @@ //! A simple test for testing many permutations of allowedness of //! impl Trait -#![feature(conservative_impl_trait, nested_impl_trait, universal_impl_trait, dyn_trait)] +#![feature(conservative_impl_trait, universal_impl_trait, dyn_trait)] use std::fmt::Debug; // Allowed @@ -60,6 +60,7 @@ fn in_dyn_Fn_return_in_return() -> &'static dyn Fn() -> impl Debug { panic!() } // Disallowed fn in_impl_Fn_parameter_in_parameters(_: &impl Fn(impl Debug)) { panic!() } //~^ ERROR `impl Trait` not allowed outside of function and inherent method return types +//~^^ ERROR nested `impl Trait` is not allowed // Disallowed fn in_impl_Fn_return_in_parameters(_: &impl Fn() -> impl Debug) { panic!() } @@ -68,6 +69,7 @@ fn in_impl_Fn_return_in_parameters(_: &impl Fn() -> impl Debug) { panic!() } // Disallowed fn in_impl_Fn_parameter_in_return() -> &'static impl Fn(impl Debug) { panic!() } //~^ ERROR `impl Trait` not allowed outside of function and inherent method return types +//~^^ ERROR nested `impl Trait` is not allowed // Disallowed fn in_impl_Fn_return_in_return() -> &'static impl Fn() -> impl Debug { panic!() } diff --git a/src/test/run-pass/impl-trait/lifetimes.rs b/src/test/run-pass/impl-trait/lifetimes.rs index 1f2d76f289472..4d40e707ddcb9 100644 --- a/src/test/run-pass/impl-trait/lifetimes.rs +++ b/src/test/run-pass/impl-trait/lifetimes.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(conservative_impl_trait, underscore_lifetimes, universal_impl_trait, nested_impl_trait)] +#![feature(conservative_impl_trait, underscore_lifetimes, universal_impl_trait)] #![allow(warnings)] use std::fmt::Debug; @@ -55,12 +55,11 @@ fn pass_through_elision_with_fn_ptr(x: &fn(&u32) -> &u32) -> impl Into<&fn(&u32) fn pass_through_elision_with_fn_path &u32>( x: &T -) -> impl Into<&impl Fn(&u32) -> &u32> { x } +) -> &impl Fn(&u32) -> &u32 { x } -fn foo(x: &impl Debug) -> impl Into<&impl Debug> { x } -fn foo_explicit_lifetime<'a>(x: &'a impl Debug) -> impl Into<&'a impl Debug> { x } -fn foo_no_outer_impl(x: &impl Debug) -> &impl Debug { x } -fn foo_explicit_arg(x: &T) -> impl Into<&impl Debug> { x } +fn foo(x: &impl Debug) -> &impl Debug { x } +fn foo_explicit_lifetime<'a>(x: &'a impl Debug) -> &'a impl Debug { x } +fn foo_explicit_arg(x: &T) -> &impl Debug { x } fn mixed_lifetimes<'a>() -> impl for<'b: 'a> Fn(&'b u32) { |_| () } fn mixed_as_static() -> impl Fn(&'static u32) { mixed_lifetimes() } diff --git a/src/test/ui/error-codes/E0657.rs b/src/test/ui/error-codes/E0657.rs index 4595e413081a5..31b3acd86ef55 100644 --- a/src/test/ui/error-codes/E0657.rs +++ b/src/test/ui/error-codes/E0657.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. #![allow(warnings)] -#![feature(conservative_impl_trait, nested_impl_trait)] +#![feature(conservative_impl_trait)] trait Id {} trait Lt<'a> {} @@ -17,7 +17,7 @@ impl<'a> Lt<'a> for () {} impl Id for T {} fn free_fn_capture_hrtb_in_impl_trait() - -> impl for<'a> Id> + -> Box Id>> //~^ ERROR `impl Trait` can only capture lifetimes bound at the fn or impl level [E0657] { () @@ -26,7 +26,7 @@ fn free_fn_capture_hrtb_in_impl_trait() struct Foo; impl Foo { fn impl_fn_capture_hrtb_in_impl_trait() - -> impl for<'a> Id> + -> Box Id>> //~^ ERROR `impl Trait` can only capture lifetimes bound at the fn or impl level { () diff --git a/src/test/compile-fail/feature-gate-nested_impl_trait.rs b/src/test/ui/nested_impl_trait.rs similarity index 80% rename from src/test/compile-fail/feature-gate-nested_impl_trait.rs rename to src/test/ui/nested_impl_trait.rs index 7c35263d05dd7..f6302c0f3b3e2 100644 --- a/src/test/compile-fail/feature-gate-nested_impl_trait.rs +++ b/src/test/ui/nested_impl_trait.rs @@ -14,18 +14,19 @@ use std::fmt::Debug; fn fine(x: impl Into) -> impl Into { x } fn bad_in_ret_position(x: impl Into) -> impl Into { x } -//~^ ERROR nested `impl Trait` is experimental +//~^ ERROR nested `impl Trait` is not allowed fn bad_in_fn_syntax(x: fn() -> impl Into) {} -//~^ ERROR nested `impl Trait` is experimental +//~^ ERROR nested `impl Trait` is not allowed +//~^^ `impl Trait` not allowed fn bad_in_arg_position(_: impl Into) { } -//~^ ERROR nested `impl Trait` is experimental +//~^ ERROR nested `impl Trait` is not allowed struct X; impl X { fn bad(x: impl Into) -> impl Into { x } - //~^ ERROR nested `impl Trait` is experimental + //~^ ERROR nested `impl Trait` is not allowed } fn allowed_in_assoc_type() -> impl Iterator { @@ -33,6 +34,7 @@ fn allowed_in_assoc_type() -> impl Iterator { } fn allowed_in_ret_type() -> impl Fn() -> impl Into { +//~^ `impl Trait` not allowed || 5 } diff --git a/src/test/ui/nested_impl_trait.stderr b/src/test/ui/nested_impl_trait.stderr new file mode 100644 index 0000000000000..6649f9ab99cc1 --- /dev/null +++ b/src/test/ui/nested_impl_trait.stderr @@ -0,0 +1,50 @@ +error[E0666]: nested `impl Trait` is not allowed + --> $DIR/nested_impl_trait.rs:16:56 + | +16 | fn bad_in_ret_position(x: impl Into) -> impl Into { x } + | ----------^^^^^^^^^^- + | | | + | | devilishly nested `impl Trait` here + | outer `impl Trait` + +error[E0666]: nested `impl Trait` is not allowed + --> $DIR/nested_impl_trait.rs:19:42 + | +19 | fn bad_in_fn_syntax(x: fn() -> impl Into) {} + | ----------^^^^^^^^^^- + | | | + | | devilishly nested `impl Trait` here + | outer `impl Trait` + +error[E0666]: nested `impl Trait` is not allowed + --> $DIR/nested_impl_trait.rs:23:37 + | +23 | fn bad_in_arg_position(_: impl Into) { } + | ----------^^^^^^^^^^- + | | | + | | devilishly nested `impl Trait` here + | outer `impl Trait` + +error[E0666]: nested `impl Trait` is not allowed + --> $DIR/nested_impl_trait.rs:28:44 + | +28 | fn bad(x: impl Into) -> impl Into { x } + | ----------^^^^^^^^^^- + | | | + | | devilishly nested `impl Trait` here + | outer `impl Trait` + +error[E0562]: `impl Trait` not allowed outside of function and inherent method return types + --> $DIR/nested_impl_trait.rs:19:32 + | +19 | fn bad_in_fn_syntax(x: fn() -> impl Into) {} + | ^^^^^^^^^^^^^^^^^^^^^ + +error[E0562]: `impl Trait` not allowed outside of function and inherent method return types + --> $DIR/nested_impl_trait.rs:36:42 + | +36 | fn allowed_in_ret_type() -> impl Fn() -> impl Into { + | ^^^^^^^^^^^^^^ + +error: aborting due to 6 previous errors + From 70e1f4fc6d951dfc0547ff5acb3d8780d16635e6 Mon Sep 17 00:00:00 2001 From: Taylor Cramer Date: Thu, 8 Feb 2018 16:50:14 -0800 Subject: [PATCH 05/34] Disallow projections from impl Trait types --- src/librustc_passes/ast_validation.rs | 68 ++++++++++++++++++++++- src/librustc_passes/diagnostics.rs | 1 + src/test/ui/impl_trait_projections.rs | 43 ++++++++++++++ src/test/ui/impl_trait_projections.stderr | 28 ++++++++++ 4 files changed, 139 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/impl_trait_projections.rs create mode 100644 src/test/ui/impl_trait_projections.stderr diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs index 826f27c2ddbf4..14ea5c0ce7982 100644 --- a/src/librustc_passes/ast_validation.rs +++ b/src/librustc_passes/ast_validation.rs @@ -447,7 +447,7 @@ impl<'a> Visitor<'a> for NestedImplTraitVisitor<'a> { struct_span_err!(self.session, t.span, E0666, "nested `impl Trait` is not allowed") .span_label(outer_impl_trait, "outer `impl Trait`") - .span_label(t.span, "devilishly nested `impl Trait` here") + .span_label(t.span, "nested `impl Trait` here") .emit(); } @@ -482,6 +482,66 @@ impl<'a> Visitor<'a> for NestedImplTraitVisitor<'a> { } } +// Bans `impl Trait` in path projections like `::Item` or `Foo::Bar`. +struct ImplTraitProjectionVisitor<'a> { + session: &'a Session, + is_banned: bool, +} + +impl<'a> ImplTraitProjectionVisitor<'a> { + fn with_ban(&mut self, f: F) + where F: FnOnce(&mut ImplTraitProjectionVisitor<'a>) + { + let old_is_banned = self.is_banned; + self.is_banned = true; + f(self); + self.is_banned = old_is_banned; + } +} + +impl<'a> Visitor<'a> for ImplTraitProjectionVisitor<'a> { + fn visit_ty(&mut self, t: &'a Ty) { + match t.node { + TyKind::ImplTrait(_) => { + if self.is_banned { + struct_span_err!(self.session, t.span, E0667, + "`impl Trait` is not allowed in path parameters") + .emit(); + } + } + TyKind::Path(ref qself, ref path) => { + // We allow these: + // - `Option` + // - `option::Option` + // - `option::Option::Foo + // + // But not these: + // - `::Foo` + // - `option::Option::Foo`. + // + // To implement this, we disallow `impl Trait` from `qself` + // (for cases like `::Foo>`) + // but we allow `impl Trait` in `PathParameters` + // iff there are no more PathSegments. + if let Some(ref qself) = *qself { + // `impl Trait` in `qself` is always illegal + self.with_ban(|this| this.visit_ty(&qself.ty)); + } + + for (i, segment) in path.segments.iter().enumerate() { + // Allow `impl Trait` iff we're on the final path segment + if i == (path.segments.len() - 1) { + visit::walk_path_segment(self, path.span, segment); + } else { + self.with_ban(|this| + visit::walk_path_segment(this, path.span, segment)); + } + } + } + _ => visit::walk_ty(self, t), + } + } +} pub fn check_crate(session: &Session, krate: &Crate) { visit::walk_crate( @@ -490,5 +550,11 @@ pub fn check_crate(session: &Session, krate: &Crate) { outer_impl_trait: None, }, krate); + visit::walk_crate( + &mut ImplTraitProjectionVisitor { + session, + is_banned: false, + }, krate); + visit::walk_crate(&mut AstValidator { session: session }, krate) } diff --git a/src/librustc_passes/diagnostics.rs b/src/librustc_passes/diagnostics.rs index 6dfc52f842e16..980808a6905c1 100644 --- a/src/librustc_passes/diagnostics.rs +++ b/src/librustc_passes/diagnostics.rs @@ -321,4 +321,5 @@ register_diagnostics! { E0568, // auto traits can not have super traits E0642, // patterns aren't allowed in methods without bodies E0666, // nested `impl Trait` is illegal + E0667, // `impl Trait` in projections } diff --git a/src/test/ui/impl_trait_projections.rs b/src/test/ui/impl_trait_projections.rs new file mode 100644 index 0000000000000..e34b7799fb724 --- /dev/null +++ b/src/test/ui/impl_trait_projections.rs @@ -0,0 +1,43 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. +#![feature(conservative_impl_trait, universal_impl_trait)] + +use std::fmt::Debug; +use std::option; + +fn parametrized_type_is_allowed() -> Option { + Some(5i32) +} + +fn path_parametrized_type_is_allowed() -> option::Option { + Some(5i32) +} + +fn projection_is_disallowed(x: impl Iterator) -> ::Item { +//~^ ERROR `impl Trait` is not allowed in path parameters +//~^^ ERROR ambiguous associated type + x.next().unwrap() +} + +fn projection_with_named_trait_is_disallowed(x: impl Iterator) + -> ::Item +//~^ ERROR `impl Trait` is not allowed in path parameters +{ + x.next().unwrap() +} + +fn projection_with_named_trait_inside_path_is_disallowed() + -> <::std::ops::Range as Iterator>::Item +//~^ ERROR `impl Trait` is not allowed in path parameters +{ + (1i32..100).next().unwrap() +} + +fn main() {} diff --git a/src/test/ui/impl_trait_projections.stderr b/src/test/ui/impl_trait_projections.stderr new file mode 100644 index 0000000000000..2e8bfc931f82e --- /dev/null +++ b/src/test/ui/impl_trait_projections.stderr @@ -0,0 +1,28 @@ +error[E0667]: `impl Trait` is not allowed in path parameters + --> $DIR/impl_trait_projections.rs:23:51 + | +23 | fn projection_is_disallowed(x: impl Iterator) -> ::Item { + | ^^^^^^^^^^^^^ + +error[E0667]: `impl Trait` is not allowed in path parameters + --> $DIR/impl_trait_projections.rs:30:9 + | +30 | -> ::Item + | ^^^^^^^^^^^^^ + +error[E0667]: `impl Trait` is not allowed in path parameters + --> $DIR/impl_trait_projections.rs:37:27 + | +37 | -> <::std::ops::Range as Iterator>::Item + | ^^^^^^^^^^ + +error[E0223]: ambiguous associated type + --> $DIR/impl_trait_projections.rs:23:50 + | +23 | fn projection_is_disallowed(x: impl Iterator) -> ::Item { + | ^^^^^^^^^^^^^^^^^^^^^ ambiguous associated type + | + = note: specify the type using the syntax `::Item` + +error: aborting due to 4 previous errors + From f1fbf79223aca762c42c6674d125c4c5223f9949 Mon Sep 17 00:00:00 2001 From: Taylor Cramer Date: Tue, 13 Feb 2018 17:46:33 -0800 Subject: [PATCH 06/34] Amend nested impl Trait error message --- src/test/ui/nested_impl_trait.stderr | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/test/ui/nested_impl_trait.stderr b/src/test/ui/nested_impl_trait.stderr index 6649f9ab99cc1..094926120cdee 100644 --- a/src/test/ui/nested_impl_trait.stderr +++ b/src/test/ui/nested_impl_trait.stderr @@ -4,7 +4,7 @@ error[E0666]: nested `impl Trait` is not allowed 16 | fn bad_in_ret_position(x: impl Into) -> impl Into { x } | ----------^^^^^^^^^^- | | | - | | devilishly nested `impl Trait` here + | | nested `impl Trait` here | outer `impl Trait` error[E0666]: nested `impl Trait` is not allowed @@ -13,7 +13,7 @@ error[E0666]: nested `impl Trait` is not allowed 19 | fn bad_in_fn_syntax(x: fn() -> impl Into) {} | ----------^^^^^^^^^^- | | | - | | devilishly nested `impl Trait` here + | | nested `impl Trait` here | outer `impl Trait` error[E0666]: nested `impl Trait` is not allowed @@ -22,7 +22,7 @@ error[E0666]: nested `impl Trait` is not allowed 23 | fn bad_in_arg_position(_: impl Into) { } | ----------^^^^^^^^^^- | | | - | | devilishly nested `impl Trait` here + | | nested `impl Trait` here | outer `impl Trait` error[E0666]: nested `impl Trait` is not allowed @@ -31,7 +31,7 @@ error[E0666]: nested `impl Trait` is not allowed 28 | fn bad(x: impl Into) -> impl Into { x } | ----------^^^^^^^^^^- | | | - | | devilishly nested `impl Trait` here + | | nested `impl Trait` here | outer `impl Trait` error[E0562]: `impl Trait` not allowed outside of function and inherent method return types From dbacf0c56ba2bd5ed38fc2a2e4bc20150271e7f2 Mon Sep 17 00:00:00 2001 From: Taylor Cramer Date: Tue, 13 Feb 2018 17:52:22 -0800 Subject: [PATCH 07/34] Test err on impl Trait projection within dyn Trait --- src/test/ui/impl_trait_projections.rs | 9 ++++++++- src/test/ui/impl_trait_projections.stderr | 8 +++++++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/test/ui/impl_trait_projections.rs b/src/test/ui/impl_trait_projections.rs index e34b7799fb724..f69a78b1450f1 100644 --- a/src/test/ui/impl_trait_projections.rs +++ b/src/test/ui/impl_trait_projections.rs @@ -7,7 +7,7 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(conservative_impl_trait, universal_impl_trait)] +#![feature(dyn_trait, conservative_impl_trait, universal_impl_trait)] use std::fmt::Debug; use std::option; @@ -40,4 +40,11 @@ fn projection_with_named_trait_inside_path_is_disallowed() (1i32..100).next().unwrap() } +fn projection_from_impl_trait_inside_dyn_trait_is_disallowed() + -> as Iterator>::Item +//~^ ERROR `impl Trait` is not allowed in path parameters +{ + panic!() +} + fn main() {} diff --git a/src/test/ui/impl_trait_projections.stderr b/src/test/ui/impl_trait_projections.stderr index 2e8bfc931f82e..08de0eb99a307 100644 --- a/src/test/ui/impl_trait_projections.stderr +++ b/src/test/ui/impl_trait_projections.stderr @@ -16,6 +16,12 @@ error[E0667]: `impl Trait` is not allowed in path parameters 37 | -> <::std::ops::Range as Iterator>::Item | ^^^^^^^^^^ +error[E0667]: `impl Trait` is not allowed in path parameters + --> $DIR/impl_trait_projections.rs:44:29 + | +44 | -> as Iterator>::Item + | ^^^^^^^^^^ + error[E0223]: ambiguous associated type --> $DIR/impl_trait_projections.rs:23:50 | @@ -24,5 +30,5 @@ error[E0223]: ambiguous associated type | = note: specify the type using the syntax `::Item` -error: aborting due to 4 previous errors +error: aborting due to 5 previous errors From d4b847504c2ecf32637486987ac299f91a3d1c54 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Tue, 13 Feb 2018 17:40:46 +0100 Subject: [PATCH 08/34] incr.comp.: Store DepNode colors in a dense array instead of a hashmap. --- src/librustc/dep_graph/graph.rs | 148 ++++++++++++++++++++++--------- src/librustc/dep_graph/prev.rs | 5 ++ src/librustc/ty/maps/plumbing.rs | 6 +- 3 files changed, 112 insertions(+), 47 deletions(-) diff --git a/src/librustc/dep_graph/graph.rs b/src/librustc/dep_graph/graph.rs index 55ec8adb5fbf3..b77431e806a6d 100644 --- a/src/librustc/dep_graph/graph.rs +++ b/src/librustc/dep_graph/graph.rs @@ -74,7 +74,7 @@ struct DepGraphData { /// nodes and edges as well as all fingerprints of nodes that have them. previous: PreviousDepGraph, - colors: RefCell>, + colors: RefCell, /// When we load, there may be `.o` files, cached mir, or other such /// things available to us. If we find that they are not dirty, we @@ -97,8 +97,10 @@ impl DepGraph { // Pre-allocate the fingerprints array. We over-allocate a little so // that we hopefully don't have to re-allocate during this compilation // session. + let prev_graph_node_count = prev_graph.node_count(); + let fingerprints = IndexVec::from_elem_n(Fingerprint::ZERO, - (prev_graph.node_count() * 115) / 100); + (prev_graph_node_count * 115) / 100); DepGraph { data: Some(Rc::new(DepGraphData { previous_work_products: RefCell::new(FxHashMap()), @@ -106,7 +108,7 @@ impl DepGraph { dep_node_debug: RefCell::new(FxHashMap()), current: RefCell::new(CurrentDepGraph::new()), previous: prev_graph, - colors: RefCell::new(FxHashMap()), + colors: RefCell::new(DepNodeColorMap::new(prev_graph_node_count)), loaded_from_cache: RefCell::new(FxHashMap()), })), fingerprints: Rc::new(RefCell::new(fingerprints)), @@ -213,8 +215,6 @@ impl DepGraph { R: HashStable, { if let Some(ref data) = self.data { - debug_assert!(!data.colors.borrow().contains_key(&key)); - push(&data.current, key); if cfg!(debug_assertions) { profq_msg(ProfileQueriesMsg::TaskBegin(key.clone())) @@ -254,19 +254,21 @@ impl DepGraph { } // Determine the color of the new DepNode. - { - let prev_fingerprint = data.previous.fingerprint_of(&key); + if let Some(prev_index) = data.previous.node_to_index_opt(&key) { + let prev_fingerprint = data.previous.fingerprint_by_index(prev_index); - let color = if Some(current_fingerprint) == prev_fingerprint { + let color = if current_fingerprint == prev_fingerprint { DepNodeColor::Green(dep_node_index) } else { DepNodeColor::Red }; - let old_value = data.colors.borrow_mut().insert(key, color); - debug_assert!(old_value.is_none(), + let mut colors = data.colors.borrow_mut(); + debug_assert!(colors.get(prev_index).is_none(), "DepGraph::with_task() - Duplicate DepNodeColor \ insertion for {:?}", key); + + colors.insert(prev_index, color); } (result, dep_node_index) @@ -281,9 +283,11 @@ impl DepGraph { let mut fingerprints = self.fingerprints.borrow_mut(); let dep_node_index = DepNodeIndex::new(fingerprints.len()); fingerprints.push(fingerprint); + debug_assert!(fingerprints[dep_node_index] == fingerprint, "DepGraph::with_task() - Assigned fingerprint to \ unexpected index for {:?}", key); + (result, dep_node_index) } else { (task(cx, arg), DepNodeIndex::INVALID) @@ -356,6 +360,15 @@ impl DepGraph { .unwrap() } + #[inline] + pub fn dep_node_exists(&self, dep_node: &DepNode) -> bool { + if let Some(ref data) = self.data { + data.current.borrow_mut().node_to_node_index.contains_key(dep_node) + } else { + false + } + } + #[inline] pub fn fingerprint_of(&self, dep_node_index: DepNodeIndex) -> Fingerprint { match self.fingerprints.borrow().get(dep_node_index) { @@ -495,7 +508,17 @@ impl DepGraph { } pub fn node_color(&self, dep_node: &DepNode) -> Option { - self.data.as_ref().and_then(|data| data.colors.borrow().get(dep_node).cloned()) + if let Some(ref data) = self.data { + if let Some(prev_index) = data.previous.node_to_index_opt(dep_node) { + return data.colors.borrow().get(prev_index) + } else { + // This is a node that did not exist in the previous compilation + // session, so we consider it to be red. + return Some(DepNodeColor::Red) + } + } + + None } pub fn try_mark_green<'tcx>(&self, @@ -505,7 +528,6 @@ impl DepGraph { debug!("try_mark_green({:?}) - BEGIN", dep_node); let data = self.data.as_ref().unwrap(); - debug_assert!(!data.colors.borrow().contains_key(dep_node)); debug_assert!(!data.current.borrow().node_to_node_index.contains_key(dep_node)); if dep_node.kind.is_input() { @@ -535,19 +557,22 @@ impl DepGraph { } }; + debug_assert!(data.colors.borrow().get(prev_dep_node_index).is_none()); + let mut current_deps = Vec::new(); for &dep_dep_node_index in prev_deps { - let dep_dep_node = &data.previous.index_to_node(dep_dep_node_index); + let dep_dep_node_color = data.colors.borrow().get(dep_dep_node_index); - let dep_dep_node_color = data.colors.borrow().get(dep_dep_node).cloned(); match dep_dep_node_color { Some(DepNodeColor::Green(node_index)) => { // This dependency has been marked as green before, we are // still fine and can continue with checking the other // dependencies. debug!("try_mark_green({:?}) --- found dependency {:?} to \ - be immediately green", dep_node, dep_dep_node); + be immediately green", + dep_node, + data.previous.index_to_node(dep_dep_node_index)); current_deps.push(node_index); } Some(DepNodeColor::Red) => { @@ -556,10 +581,14 @@ impl DepGraph { // mark the DepNode as green and also don't need to bother // with checking any of the other dependencies. debug!("try_mark_green({:?}) - END - dependency {:?} was \ - immediately red", dep_node, dep_dep_node); + immediately red", + dep_node, + data.previous.index_to_node(dep_dep_node_index)); return None } None => { + let dep_dep_node = &data.previous.index_to_node(dep_dep_node_index); + // We don't know the state of this dependency. If it isn't // an input node, let's try to mark it green recursively. if !dep_dep_node.kind.is_input() { @@ -601,10 +630,8 @@ impl DepGraph { debug!("try_mark_green({:?}) --- trying to force \ dependency {:?}", dep_node, dep_dep_node); if ::ty::maps::force_from_dep_node(tcx, dep_dep_node) { - let dep_dep_node_color = data.colors - .borrow() - .get(dep_dep_node) - .cloned(); + let dep_dep_node_color = data.colors.borrow().get(dep_dep_node_index); + match dep_dep_node_color { Some(DepNodeColor::Green(node_index)) => { debug!("try_mark_green({:?}) --- managed to \ @@ -681,26 +708,21 @@ impl DepGraph { } // ... and finally storing a "Green" entry in the color map. - let old_color = data.colors - .borrow_mut() - .insert(*dep_node, DepNodeColor::Green(dep_node_index)); - debug_assert!(old_color.is_none(), + let mut colors = data.colors.borrow_mut(); + debug_assert!(colors.get(prev_dep_node_index).is_none(), "DepGraph::try_mark_green() - Duplicate DepNodeColor \ insertion for {:?}", dep_node); + colors.insert(prev_dep_node_index, DepNodeColor::Green(dep_node_index)); + debug!("try_mark_green({:?}) - END - successfully marked as green", dep_node); Some(dep_node_index) } - // Used in various assertions - pub fn is_green(&self, dep_node_index: DepNodeIndex) -> bool { - let dep_node = self.data.as_ref().unwrap().current.borrow().nodes[dep_node_index]; - self.data.as_ref().unwrap().colors.borrow().get(&dep_node).map(|&color| { - match color { - DepNodeColor::Red => false, - DepNodeColor::Green(_) => true, - } - }).unwrap_or(false) + // Returns true if the given node has been marked as green during the + // current compilation session. Used in various assertions + pub fn is_green(&self, dep_node: &DepNode) -> bool { + self.node_color(dep_node).map(|c| c.is_green()).unwrap_or(false) } // This method loads all on-disk cacheable query results into memory, so @@ -714,20 +736,25 @@ impl DepGraph { pub fn exec_cache_promotions<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) { let green_nodes: Vec = { let data = self.data.as_ref().unwrap(); - data.colors.borrow().iter().filter_map(|(dep_node, color)| match color { - DepNodeColor::Green(_) => { - if dep_node.cache_on_disk(tcx) { - Some(*dep_node) - } else { + let colors = data.colors.borrow(); + colors.values.indices().filter_map(|prev_index| { + match colors.get(prev_index) { + Some(DepNodeColor::Green(_)) => { + let dep_node = data.previous.index_to_node(prev_index); + if dep_node.cache_on_disk(tcx) { + Some(dep_node) + } else { + None + } + } + None | + Some(DepNodeColor::Red) => { + // We can skip red nodes because a node can only be marked + // as red if the query result was recomputed and thus is + // already in memory. None } } - DepNodeColor::Red => { - // We can skip red nodes because a node can only be marked - // as red if the query result was recomputed and thus is - // already in memory. - None - } }).collect() }; @@ -1052,3 +1079,36 @@ enum OpenTask { node: DepNode, }, } + +// A data structure that stores Option values as a contiguous +// array, using one u32 per entry. +struct DepNodeColorMap { + values: IndexVec, +} + +const COMPRESSED_NONE: u32 = 0; +const COMPRESSED_RED: u32 = 1; +const COMPRESSED_FIRST_GREEN: u32 = 2; + +impl DepNodeColorMap { + fn new(size: usize) -> DepNodeColorMap { + DepNodeColorMap { + values: IndexVec::from_elem_n(COMPRESSED_NONE, size) + } + } + + fn get(&self, index: SerializedDepNodeIndex) -> Option { + match self.values[index] { + COMPRESSED_NONE => None, + COMPRESSED_RED => Some(DepNodeColor::Red), + value => Some(DepNodeColor::Green(DepNodeIndex(value - COMPRESSED_FIRST_GREEN))) + } + } + + fn insert(&mut self, index: SerializedDepNodeIndex, color: DepNodeColor) { + self.values[index] = match color { + DepNodeColor::Red => COMPRESSED_RED, + DepNodeColor::Green(index) => index.0 + COMPRESSED_FIRST_GREEN, + } + } +} diff --git a/src/librustc/dep_graph/prev.rs b/src/librustc/dep_graph/prev.rs index 50e1ee88a4614..504b60e763e23 100644 --- a/src/librustc/dep_graph/prev.rs +++ b/src/librustc/dep_graph/prev.rs @@ -49,6 +49,11 @@ impl PreviousDepGraph { self.index[dep_node] } + #[inline] + pub fn node_to_index_opt(&self, dep_node: &DepNode) -> Option { + self.index.get(dep_node).cloned() + } + #[inline] pub fn fingerprint_of(&self, dep_node: &DepNode) -> Option { self.index diff --git a/src/librustc/ty/maps/plumbing.rs b/src/librustc/ty/maps/plumbing.rs index 0ab6ee1a54a9b..956348edcce65 100644 --- a/src/librustc/ty/maps/plumbing.rs +++ b/src/librustc/ty/maps/plumbing.rs @@ -147,7 +147,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } match self.dep_graph.try_mark_green(self.global_tcx(), &dep_node) { Some(dep_node_index) => { - debug_assert!(self.dep_graph.is_green(dep_node_index)); + debug_assert!(self.dep_graph.is_green(&dep_node)); self.dep_graph.read_index(dep_node_index); Some(dep_node_index) } @@ -390,7 +390,7 @@ macro_rules! define_maps { dep_node: &DepNode) -> Result<$V, CycleError<'a, $tcx>> { - debug_assert!(tcx.dep_graph.is_green(dep_node_index)); + debug_assert!(tcx.dep_graph.is_green(dep_node)); // First we try to load the result from the on-disk cache let result = if Self::cache_on_disk(key) && @@ -478,7 +478,7 @@ macro_rules! define_maps { span: Span, dep_node: DepNode) -> Result<($V, DepNodeIndex), CycleError<'a, $tcx>> { - debug_assert!(tcx.dep_graph.node_color(&dep_node).is_none()); + debug_assert!(!tcx.dep_graph.dep_node_exists(&dep_node)); profq_msg!(tcx, ProfileQueriesMsg::ProviderBegin); let res = tcx.cycle_check(span, Query::$name(key), || { From 9e9c55f8fd064335cadc28bd9a0152538dcc9fa0 Mon Sep 17 00:00:00 2001 From: Taylor Cramer Date: Wed, 14 Feb 2018 10:22:12 -0800 Subject: [PATCH 09/34] Update E0657 stderr to match changed test --- src/test/ui/error-codes/E0657.stderr | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/test/ui/error-codes/E0657.stderr b/src/test/ui/error-codes/E0657.stderr index d3b53d37a30a0..e039d645fa6db 100644 --- a/src/test/ui/error-codes/E0657.stderr +++ b/src/test/ui/error-codes/E0657.stderr @@ -1,14 +1,14 @@ error[E0657]: `impl Trait` can only capture lifetimes bound at the fn or impl level - --> $DIR/E0657.rs:20:32 + --> $DIR/E0657.rs:20:31 | -20 | -> impl for<'a> Id> - | ^^ +20 | -> Box Id>> + | ^^ error[E0657]: `impl Trait` can only capture lifetimes bound at the fn or impl level - --> $DIR/E0657.rs:29:36 + --> $DIR/E0657.rs:29:35 | -29 | -> impl for<'a> Id> - | ^^ +29 | -> Box Id>> + | ^^ error: aborting due to 2 previous errors From fe0260fbf892d5b49e79ee310b5e198c72c3d576 Mon Sep 17 00:00:00 2001 From: Federico Poli Date: Thu, 15 Feb 2018 15:04:43 +0100 Subject: [PATCH 10/34] mir: Gather move at SwitchInt, Assert terminators Previously, "_1" was not marked as "definitely uninitialized" after a "switchInt(move _1)" terminator. Related discussion: https://internals.rust-lang.org/t/why-is-2-definitely-initialized-after-switchint-move-2/6760 --- src/librustc_mir/dataflow/move_paths/builder.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/librustc_mir/dataflow/move_paths/builder.rs b/src/librustc_mir/dataflow/move_paths/builder.rs index 635d99e7737a9..d6f419f6cfb41 100644 --- a/src/librustc_mir/dataflow/move_paths/builder.rs +++ b/src/librustc_mir/dataflow/move_paths/builder.rs @@ -353,9 +353,12 @@ impl<'b, 'a, 'gcx, 'tcx> Gatherer<'b, 'a, 'gcx, 'tcx> { self.gather_move(&Place::Local(RETURN_PLACE)); } - TerminatorKind::Assert { .. } | - TerminatorKind::SwitchInt { .. } => { - // branching terminators - these don't move anything + TerminatorKind::Assert { ref cond, .. } => { + self.gather_operand(cond); + } + + TerminatorKind::SwitchInt { ref discr, .. } => { + self.gather_operand(discr); } TerminatorKind::Yield { ref value, .. } => { From b9fa2dac25786e67d8332dfa3fe7524ba4c196b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 15 Feb 2018 14:42:22 -0800 Subject: [PATCH 11/34] Avoid ICE in arg mistmatch error for tuple variants --- src/librustc/traits/error_reporting.rs | 15 ++++++++++++++- src/test/ui/issue-47706.rs | 15 +++++++++++++++ src/test/ui/issue-47706.stderr | 21 +++++++++++++++++++-- 3 files changed, 48 insertions(+), 3 deletions(-) diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index a290839425ebe..43a3269fa52d5 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -756,7 +756,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { }).collect(), ref sty => vec![ArgKind::Arg("_".to_owned(), format!("{}", sty))], }; - if found.len()== expected.len() { + if found.len() == expected.len() { self.report_closure_arg_mismatch(span, found_span, found_trait_ref, @@ -870,6 +870,19 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { _ => ArgKind::Arg("_".to_owned(), "_".to_owned()) }).collect::>()) } + hir::map::NodeVariant(&hir::Variant { + span, + node: hir::Variant_ { + data: hir::VariantData::Tuple(ref fields, _), + .. + }, + .. + }) => { + (self.tcx.sess.codemap().def_span(span), + fields.iter().map(|field| { + ArgKind::Arg(format!("{}", field.name), "_".to_string()) + }).collect::>()) + } _ => panic!("non-FnLike node found: {:?}", node), } } diff --git a/src/test/ui/issue-47706.rs b/src/test/ui/issue-47706.rs index 24a0f66f5b1c4..9c521dd647963 100644 --- a/src/test/ui/issue-47706.rs +++ b/src/test/ui/issue-47706.rs @@ -22,3 +22,18 @@ impl Foo { } //~^^ ERROR function is expected to take 1 argument, but it takes 2 arguments [E0593] } + +enum Qux { + Bar(i32), +} + +fn foo(f: F) +where + F: Fn(), +{ +} + +fn main() { + foo(Qux::Bar); +} +//~^^ ERROR function is expected to take 0 arguments, but it takes 1 argument [E0593] diff --git a/src/test/ui/issue-47706.stderr b/src/test/ui/issue-47706.stderr index 0916dc64292e3..e197c09062d1c 100644 --- a/src/test/ui/issue-47706.stderr +++ b/src/test/ui/issue-47706.stderr @@ -1,5 +1,3 @@ -error[E0601]: main function not found - error[E0593]: function is expected to take 1 argument, but it takes 2 arguments --> $DIR/issue-47706.rs:21:18 | @@ -9,5 +7,24 @@ error[E0593]: function is expected to take 1 argument, but it takes 2 arguments 21 | self.foo.map(Foo::new) | ^^^ expected function that takes 1 argument +error[E0593]: function is expected to take 0 arguments, but it takes 1 argument + --> $DIR/issue-47706.rs:37:5 + | +27 | Bar(i32), + | -------- takes 1 argument +... +37 | foo(Qux::Bar); + | ^^^ expected function that takes 0 arguments + | +note: required by `foo` + --> $DIR/issue-47706.rs:30:1 + | +30 | / fn foo(f: F) +31 | | where +32 | | F: Fn(), +33 | | { +34 | | } + | |_^ + error: aborting due to 2 previous errors From 10fbdb832b2ad5807b89a005f9d4bccaec231fb1 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Fri, 16 Feb 2018 16:45:37 +1300 Subject: [PATCH 12/34] save-analysis: power through bracket mis-counts Closes #47981 This is pretty unsatisfying since it is working around a span bug. However, I can't track down the span bug and it could be in the parser, proc macro expansion, the user macro, or Syn (or any other library that can manipulate spans). Given that user code can cause this error, I think we need to be more robust here. --- src/librustc_save_analysis/span_utils.rs | 26 +++++++++++++----------- 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/src/librustc_save_analysis/span_utils.rs b/src/librustc_save_analysis/span_utils.rs index 25e81e6f326e1..d5a58c08cbe5a 100644 --- a/src/librustc_save_analysis/span_utils.rs +++ b/src/librustc_save_analysis/span_utils.rs @@ -115,7 +115,7 @@ impl<'a> SpanUtils<'a> { // We keep track of the following two counts - the depth of nesting of // angle brackets, and the depth of nesting of square brackets. For the // angle bracket count, we only count tokens which occur outside of any - // square brackets (i.e. bracket_count == 0). The intutition here is + // square brackets (i.e. bracket_count == 0). The intuition here is // that we want to count angle brackets in the type, but not any which // could be in expression context (because these could mean 'less than', // etc.). @@ -151,18 +151,20 @@ impl<'a> SpanUtils<'a> { } prev = next; } - if angle_count != 0 || bracket_count != 0 { - let loc = self.sess.codemap().lookup_char_pos(span.lo()); - span_bug!( - span, - "Mis-counted brackets when breaking path? Parsing '{}' \ - in {}, line {}", - self.snippet(span), - loc.file.name, - loc.line - ); + #[cfg(debug_assertions)] { + if angle_count != 0 || bracket_count != 0 { + let loc = self.sess.codemap().lookup_char_pos(span.lo()); + span_bug!( + span, + "Mis-counted brackets when breaking path? Parsing '{}' \ + in {}, line {}", + self.snippet(span), + loc.file.name, + loc.line + ); + } } - if result.is_none() && prev.tok.is_ident() && angle_count == 0 { + if result.is_none() && prev.tok.is_ident() { return Some(prev.sp); } result From 42df8c56cc6f1b94a9c0e8e55462dff57d95e4ac Mon Sep 17 00:00:00 2001 From: Michael Lamparski Date: Sat, 17 Feb 2018 22:31:14 -0500 Subject: [PATCH 13/34] unused_unsafe: don't label irrelevant fns --- src/librustc_mir/transform/check_unsafety.rs | 7 +++- src/test/compile-fail/issue-48131.rs | 39 ++++++++++++++++++++ 2 files changed, 44 insertions(+), 2 deletions(-) create mode 100644 src/test/compile-fail/issue-48131.rs diff --git a/src/librustc_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs index bbc7803b84d8e..3524255e03772 100644 --- a/src/librustc_mir/transform/check_unsafety.rs +++ b/src/librustc_mir/transform/check_unsafety.rs @@ -386,10 +386,13 @@ fn is_enclosed(tcx: TyCtxt, if used_unsafe.contains(&parent_id) { Some(("block".to_string(), parent_id)) } else if let Some(hir::map::NodeItem(&hir::Item { - node: hir::ItemFn(_, hir::Unsafety::Unsafe, _, _, _, _), + node: hir::ItemFn(_, fn_unsafety, _, _, _, _), .. })) = tcx.hir.find(parent_id) { - Some(("fn".to_string(), parent_id)) + match fn_unsafety { + hir::Unsafety::Unsafe => Some(("fn".to_string(), parent_id)), + hir::Unsafety::Normal => None, + } } else { is_enclosed(tcx, used_unsafe, parent_id) } diff --git a/src/test/compile-fail/issue-48131.rs b/src/test/compile-fail/issue-48131.rs new file mode 100644 index 0000000000000..9eb567a5d3eb0 --- /dev/null +++ b/src/test/compile-fail/issue-48131.rs @@ -0,0 +1,39 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// This note is annotated because the purpose of the test +// is to ensure that certain other notes are not generated. +#![deny(unused_unsafe)] //~ NOTE + +// (test that no note is generated on this unsafe fn) +pub unsafe fn a() { + fn inner() { + unsafe { /* unnecessary */ } //~ ERROR unnecessary `unsafe` + //~^ NOTE + } + + inner() +} + +pub fn b() { + // (test that no note is generated on this unsafe block) + unsafe { + fn inner() { + unsafe { /* unnecessary */ } //~ ERROR unnecessary `unsafe` + //~^ NOTE + } + + let () = ::std::mem::uninitialized(); + + inner() + } +} + +fn main() {} From d5ed655a0824b2d525e6fad4f3b23f77432ebf98 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Mon, 19 Feb 2018 12:41:10 +0100 Subject: [PATCH 14/34] Use DefId instead of NodeId while generating debuginfo for statics. --- src/librustc_trans/consts.rs | 2 +- src/librustc_trans/debuginfo/metadata.rs | 19 +++++++++---------- src/librustc_trans/debuginfo/mod.rs | 6 +++--- src/librustc_trans/debuginfo/namespace.rs | 11 ----------- src/librustc_trans/debuginfo/utils.rs | 4 +--- 5 files changed, 14 insertions(+), 28 deletions(-) diff --git a/src/librustc_trans/consts.rs b/src/librustc_trans/consts.rs index d5b33d837c5bd..82e59bf4f5d16 100644 --- a/src/librustc_trans/consts.rs +++ b/src/librustc_trans/consts.rs @@ -304,7 +304,7 @@ pub fn trans_static<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, } } - debuginfo::create_global_var_metadata(cx, id, g); + debuginfo::create_global_var_metadata(cx, def_id, g); if attr::contains_name(attrs, "thread_local") { llvm::set_thread_local_mode(g, cx.tls_model); diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs index 62ba91840d95e..2c430d03c968e 100644 --- a/src/librustc_trans/debuginfo/metadata.rs +++ b/src/librustc_trans/debuginfo/metadata.rs @@ -14,7 +14,7 @@ use self::EnumDiscriminantInfo::*; use super::utils::{debug_context, DIB, span_start, get_namespace_for_item, create_DIArray, is_node_local_to_unit}; -use super::namespace::mangled_name_of_item; +use super::namespace::mangled_name_of_instance; use super::type_names::compute_debuginfo_type_name; use super::{CrateDebugContext}; use abi; @@ -1634,19 +1634,18 @@ fn create_union_stub<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, /// /// Adds the created metadata nodes directly to the crate's IR. pub fn create_global_var_metadata(cx: &CodegenCx, - node_id: ast::NodeId, + def_id: DefId, global: ValueRef) { if cx.dbg_cx.is_none() { return; } let tcx = cx.tcx; - let node_def_id = tcx.hir.local_def_id(node_id); - let no_mangle = attr::contains_name(&tcx.get_attrs(node_def_id), "no_mangle"); + let no_mangle = attr::contains_name(&tcx.get_attrs(def_id), "no_mangle"); // We may want to remove the namespace scope if we're in an extern block, see: // https://github.com/rust-lang/rust/pull/46457#issuecomment-351750952 - let var_scope = get_namespace_for_item(cx, node_def_id); - let span = cx.tcx.def_span(node_def_id); + let var_scope = get_namespace_for_item(cx, def_id); + let span = cx.tcx.def_span(def_id); let (file_metadata, line_number) = if span != syntax_pos::DUMMY_SP { let loc = span_start(cx, span); @@ -1655,15 +1654,15 @@ pub fn create_global_var_metadata(cx: &CodegenCx, (unknown_file_metadata(cx), UNKNOWN_LINE_NUMBER) }; - let is_local_to_unit = is_node_local_to_unit(cx, node_id); - let variable_type = Instance::mono(cx.tcx, node_def_id).ty(cx.tcx); + let is_local_to_unit = is_node_local_to_unit(cx, def_id); + let variable_type = Instance::mono(cx.tcx, def_id).ty(cx.tcx); let type_metadata = type_metadata(cx, variable_type, span); - let var_name = tcx.item_name(node_def_id).to_string(); + let var_name = tcx.item_name(def_id).to_string(); let var_name = CString::new(var_name).unwrap(); let linkage_name = if no_mangle { None } else { - let linkage_name = mangled_name_of_item(cx, node_id); + let linkage_name = mangled_name_of_instance(cx, Instance::mono(tcx, def_id)); Some(CString::new(linkage_name.to_string()).unwrap()) }; diff --git a/src/librustc_trans/debuginfo/mod.rs b/src/librustc_trans/debuginfo/mod.rs index 9071eb776d529..16279f31836a9 100644 --- a/src/librustc_trans/debuginfo/mod.rs +++ b/src/librustc_trans/debuginfo/mod.rs @@ -254,14 +254,14 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, let linkage_name = mangled_name_of_instance(cx, instance); let scope_line = span_start(cx, span).line; - - let local_id = cx.tcx.hir.as_local_node_id(instance.def_id()); - let is_local_to_unit = local_id.map_or(false, |id| is_node_local_to_unit(cx, id)); + let is_local_to_unit = is_node_local_to_unit(cx, def_id); let function_name = CString::new(name).unwrap(); let linkage_name = CString::new(linkage_name.to_string()).unwrap(); let mut flags = DIFlags::FlagPrototyped; + + let local_id = cx.tcx.hir.as_local_node_id(def_id); match *cx.sess().entry_fn.borrow() { Some((id, _)) => { if local_id == Some(id) { diff --git a/src/librustc_trans/debuginfo/namespace.rs b/src/librustc_trans/debuginfo/namespace.rs index 46067a4330396..891bf649c388a 100644 --- a/src/librustc_trans/debuginfo/namespace.rs +++ b/src/librustc_trans/debuginfo/namespace.rs @@ -14,7 +14,6 @@ use super::metadata::{unknown_file_metadata, UNKNOWN_LINE_NUMBER}; use super::utils::{DIB, debug_context}; use monomorphize::Instance; use rustc::ty; -use syntax::ast; use llvm; use llvm::debuginfo::DIScope; @@ -33,16 +32,6 @@ pub fn mangled_name_of_instance<'a, 'tcx>( tcx.symbol_name(instance) } -pub fn mangled_name_of_item<'a, 'tcx>( - cx: &CodegenCx<'a, 'tcx>, - node_id: ast::NodeId, -) -> ty::SymbolName { - let tcx = cx.tcx; - let node_def_id = tcx.hir.local_def_id(node_id); - let instance = Instance::mono(tcx, node_def_id); - tcx.symbol_name(instance) -} - pub fn item_namespace(cx: &CodegenCx, def_id: DefId) -> DIScope { if let Some(&scope) = debug_context(cx).namespace_map.borrow().get(&def_id) { return scope; diff --git a/src/librustc_trans/debuginfo/utils.rs b/src/librustc_trans/debuginfo/utils.rs index c571b84b8e9ed..9559cd4d9ea2d 100644 --- a/src/librustc_trans/debuginfo/utils.rs +++ b/src/librustc_trans/debuginfo/utils.rs @@ -21,9 +21,8 @@ use llvm::debuginfo::{DIScope, DIBuilderRef, DIDescriptor, DIArray}; use common::{CodegenCx}; use syntax_pos::{self, Span}; -use syntax::ast; -pub fn is_node_local_to_unit(cx: &CodegenCx, node_id: ast::NodeId) -> bool +pub fn is_node_local_to_unit(cx: &CodegenCx, def_id: DefId) -> bool { // The is_local_to_unit flag indicates whether a function is local to the // current compilation unit (i.e. if it is *static* in the C-sense). The @@ -33,7 +32,6 @@ pub fn is_node_local_to_unit(cx: &CodegenCx, node_id: ast::NodeId) -> bool // visible). It might better to use the `exported_items` set from // `driver::CrateAnalysis` in the future, but (atm) this set is not // available in the translation pass. - let def_id = cx.tcx.hir.local_def_id(node_id); !cx.tcx.is_exported_symbol(def_id) } From 15ff0adcde77776e2947d147a756d4289aa42e59 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Mon, 19 Feb 2018 13:29:22 +0100 Subject: [PATCH 15/34] Use DefId instead of NodeId in MonoItem::Static. --- src/librustc/mir/mono.rs | 7 +++-- src/librustc_mir/monomorphize/collector.rs | 12 ++++---- src/librustc_mir/monomorphize/item.rs | 16 +++++------ src/librustc_mir/monomorphize/partitioning.rs | 16 +++++++++-- src/librustc_trans/consts.rs | 26 ++++++++--------- src/librustc_trans/trans_item.rs | 28 ++++++++++++++----- 6 files changed, 64 insertions(+), 41 deletions(-) diff --git a/src/librustc/mir/mono.rs b/src/librustc/mir/mono.rs index 49e5c0dc21f9e..7f8f2e9b90603 100644 --- a/src/librustc/mir/mono.rs +++ b/src/librustc/mir/mono.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use hir::def_id::DefId; use syntax::ast::NodeId; use syntax::symbol::InternedString; use ty::{Instance, TyCtxt}; @@ -21,7 +22,7 @@ use std::hash::Hash; #[derive(PartialEq, Eq, Clone, Copy, Debug, Hash)] pub enum MonoItem<'tcx> { Fn(Instance<'tcx>), - Static(NodeId), + Static(DefId), GlobalAsm(NodeId), } @@ -50,7 +51,9 @@ impl<'tcx> HashStable> for MonoItem<'tcx> { MonoItem::Fn(ref instance) => { instance.hash_stable(hcx, hasher); } - MonoItem::Static(node_id) | + MonoItem::Static(def_id) => { + def_id.hash_stable(hcx, hasher); + } MonoItem::GlobalAsm(node_id) => { hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| { node_id.hash_stable(hcx, hasher); diff --git a/src/librustc_mir/monomorphize/collector.rs b/src/librustc_mir/monomorphize/collector.rs index a80dfaef0dab1..eb4ba21489c3d 100644 --- a/src/librustc_mir/monomorphize/collector.rs +++ b/src/librustc_mir/monomorphize/collector.rs @@ -368,8 +368,7 @@ fn collect_items_rec<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let recursion_depth_reset; match starting_point { - MonoItem::Static(node_id) => { - let def_id = tcx.hir.local_def_id(node_id); + MonoItem::Static(def_id) => { let instance = Instance::mono(tcx, def_id); // Sanity check whether this ended up being collected accidentally @@ -652,8 +651,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { let tcx = self.tcx; let instance = Instance::mono(tcx, static_.def_id); if should_monomorphize_locally(tcx, &instance) { - let node_id = tcx.hir.as_local_node_id(static_.def_id).unwrap(); - self.output.push(MonoItem::Static(node_id)); + self.output.push(MonoItem::Static(static_.def_id)); } self.super_static(static_, context, location); @@ -946,10 +944,10 @@ impl<'b, 'a, 'v> ItemLikeVisitor<'v> for RootCollector<'b, 'a, 'v> { self.output.push(MonoItem::GlobalAsm(item.id)); } hir::ItemStatic(..) => { + let def_id = self.tcx.hir.local_def_id(item.id); debug!("RootCollector: ItemStatic({})", - def_id_to_string(self.tcx, - self.tcx.hir.local_def_id(item.id))); - self.output.push(MonoItem::Static(item.id)); + def_id_to_string(self.tcx, def_id)); + self.output.push(MonoItem::Static(def_id)); } hir::ItemConst(..) => { // const items only generate mono items if they are diff --git a/src/librustc_mir/monomorphize/item.rs b/src/librustc_mir/monomorphize/item.rs index a5078187a57e3..549919a2c8919 100644 --- a/src/librustc_mir/monomorphize/item.rs +++ b/src/librustc_mir/monomorphize/item.rs @@ -97,8 +97,7 @@ pub trait MonoItemExt<'a, 'tcx>: fmt::Debug { fn symbol_name(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> ty::SymbolName { match *self.as_mono_item() { MonoItem::Fn(instance) => tcx.symbol_name(instance), - MonoItem::Static(node_id) => { - let def_id = tcx.hir.local_def_id(node_id); + MonoItem::Static(def_id) => { tcx.symbol_name(Instance::mono(tcx, def_id)) } MonoItem::GlobalAsm(node_id) => { @@ -159,7 +158,7 @@ pub trait MonoItemExt<'a, 'tcx>: fmt::Debug { fn explicit_linkage(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Option { let def_id = match *self.as_mono_item() { MonoItem::Fn(ref instance) => instance.def_id(), - MonoItem::Static(node_id) => tcx.hir.local_def_id(node_id), + MonoItem::Static(def_id) => def_id, MonoItem::GlobalAsm(..) => return None, }; @@ -209,7 +208,7 @@ pub trait MonoItemExt<'a, 'tcx>: fmt::Debug { debug!("is_instantiable({:?})", self); let (def_id, substs) = match *self.as_mono_item() { MonoItem::Fn(ref instance) => (instance.def_id(), instance.substs), - MonoItem::Static(node_id) => (tcx.hir.local_def_id(node_id), Substs::empty()), + MonoItem::Static(def_id) => (def_id, Substs::empty()), // global asm never has predicates MonoItem::GlobalAsm(..) => return true }; @@ -218,14 +217,11 @@ pub trait MonoItemExt<'a, 'tcx>: fmt::Debug { } fn to_string(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> String { - let hir_map = &tcx.hir; - return match *self.as_mono_item() { MonoItem::Fn(instance) => { to_string_internal(tcx, "fn ", instance) }, - MonoItem::Static(node_id) => { - let def_id = hir_map.local_def_id(node_id); + MonoItem::Static(def_id) => { let instance = Instance::new(def_id, tcx.intern_substs(&[])); to_string_internal(tcx, "static ", instance) }, @@ -251,7 +247,9 @@ pub trait MonoItemExt<'a, 'tcx>: fmt::Debug { MonoItem::Fn(Instance { def, .. }) => { tcx.hir.as_local_node_id(def.def_id()) } - MonoItem::Static(node_id) | + MonoItem::Static(def_id) => { + tcx.hir.as_local_node_id(def_id) + } MonoItem::GlobalAsm(node_id) => { Some(node_id) } diff --git a/src/librustc_mir/monomorphize/partitioning.rs b/src/librustc_mir/monomorphize/partitioning.rs index e9471cdb4f949..2b558e71483c6 100644 --- a/src/librustc_mir/monomorphize/partitioning.rs +++ b/src/librustc_mir/monomorphize/partitioning.rs @@ -180,7 +180,9 @@ pub trait CodegenUnitExt<'tcx> { } } } - MonoItem::Static(node_id) | + MonoItem::Static(def_id) => { + tcx.hir.as_local_node_id(def_id) + } MonoItem::GlobalAsm(node_id) => { Some(node_id) } @@ -382,7 +384,15 @@ fn place_root_translation_items<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, }; (Linkage::External, visibility) } - MonoItem::Static(node_id) | + MonoItem::Static(def_id) => { + let visibility = if tcx.is_exported_symbol(def_id) { + can_be_internalized = false; + default_visibility(def_id) + } else { + Visibility::Hidden + }; + (Linkage::External, visibility) + } MonoItem::GlobalAsm(node_id) => { let def_id = tcx.hir.local_def_id(node_id); let visibility = if tcx.is_exported_symbol(def_id) { @@ -643,7 +653,7 @@ fn characteristic_def_id_of_trans_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, Some(def_id) } - MonoItem::Static(node_id) | + MonoItem::Static(def_id) => Some(def_id), MonoItem::GlobalAsm(node_id) => Some(tcx.hir.local_def_id(node_id)), } } diff --git a/src/librustc_trans/consts.rs b/src/librustc_trans/consts.rs index 82e59bf4f5d16..f9f185dfa5161 100644 --- a/src/librustc_trans/consts.rs +++ b/src/librustc_trans/consts.rs @@ -16,7 +16,7 @@ use rustc::hir::map as hir_map; use rustc::middle::const_val::ConstEvalErr; use debuginfo; use base; -use monomorphize::{MonoItem, MonoItemExt}; +use monomorphize::MonoItem; use common::{CodegenCx, val_ty}; use declare; use monomorphize::Instance; @@ -110,7 +110,17 @@ pub fn get_static(cx: &CodegenCx, def_id: DefId) -> ValueRef { return g; } + let defined_in_current_codegen_unit = cx.codegen_unit + .items() + .contains_key(&MonoItem::Static(def_id)); + assert!(!defined_in_current_codegen_unit, + "consts::get_static() should always hit the cache for \ + statics defined in the same CGU, but did not for `{:?}`", + def_id); + let ty = instance.ty(cx.tcx); + let sym = cx.tcx.symbol_name(instance); + let g = if let Some(id) = cx.tcx.hir.as_local_node_id(def_id) { let llty = cx.layout_of(ty).llvm_type(cx); @@ -118,13 +128,6 @@ pub fn get_static(cx: &CodegenCx, def_id: DefId) -> ValueRef { hir_map::NodeItem(&hir::Item { ref attrs, span, node: hir::ItemStatic(..), .. }) => { - let sym = MonoItem::Static(id).symbol_name(cx.tcx); - - let defined_in_current_codegen_unit = cx.codegen_unit - .items() - .contains_key(&MonoItem::Static(id)); - assert!(!defined_in_current_codegen_unit); - if declare::get_declared_value(cx, &sym[..]).is_some() { span_bug!(span, "trans: Conflicting symbol names for static?"); } @@ -143,7 +146,7 @@ pub fn get_static(cx: &CodegenCx, def_id: DefId) -> ValueRef { hir_map::NodeForeignItem(&hir::ForeignItem { ref attrs, span, node: hir::ForeignItemStatic(..), .. }) => { - let sym = cx.tcx.symbol_name(instance); + let g = if let Some(name) = attr::first_attr_value_str_by_name(&attrs, "linkage") { // If this is a static with a linkage specified, then we need to handle @@ -203,8 +206,6 @@ pub fn get_static(cx: &CodegenCx, def_id: DefId) -> ValueRef { g } else { - let sym = cx.tcx.symbol_name(instance); - // FIXME(nagisa): perhaps the map of externs could be offloaded to llvm somehow? // FIXME(nagisa): investigate whether it can be changed into define_global let g = declare::declare_global(cx, &sym, cx.layout_of(ty).llvm_type(cx)); @@ -246,11 +247,10 @@ pub fn get_static(cx: &CodegenCx, def_id: DefId) -> ValueRef { pub fn trans_static<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, m: hir::Mutability, - id: ast::NodeId, + def_id: DefId, attrs: &[ast::Attribute]) -> Result> { unsafe { - let def_id = cx.tcx.hir.local_def_id(id); let g = get_static(cx, def_id); let v = ::mir::trans_static_initializer(cx, def_id)?; diff --git a/src/librustc_trans/trans_item.rs b/src/librustc_trans/trans_item.rs index 5eb6679fe252c..2751e32925931 100644 --- a/src/librustc_trans/trans_item.rs +++ b/src/librustc_trans/trans_item.rs @@ -24,10 +24,10 @@ use llvm; use monomorphize::Instance; use type_of::LayoutLlvmExt; use rustc::hir; +use rustc::hir::def_id::DefId; use rustc::mir::mono::{Linkage, Visibility}; use rustc::ty::TypeFoldable; use rustc::ty::layout::LayoutOf; -use syntax::ast; use syntax::attr; use std::fmt; @@ -44,11 +44,18 @@ pub trait MonoItemExt<'a, 'tcx>: fmt::Debug + BaseMonoItemExt<'a, 'tcx> { cx.codegen_unit.name()); match *self.as_mono_item() { - MonoItem::Static(node_id) => { + MonoItem::Static(def_id) => { let tcx = cx.tcx; + let node_id = match tcx.hir.as_local_node_id(def_id) { + Some(node_id) => node_id, + None => { + bug!("MonoItemExt::define() called for non-local \ + static `{:?}`.", def_id) + } + }; let item = tcx.hir.expect_item(node_id); if let hir::ItemStatic(_, m, _) = item.node { - match consts::trans_static(&cx, m, item.id, &item.attrs) { + match consts::trans_static(&cx, m, def_id, &item.attrs) { Ok(_) => { /* Cool, everything's alright. */ }, Err(err) => { err.report(tcx, item.span, "static"); @@ -91,8 +98,8 @@ pub trait MonoItemExt<'a, 'tcx>: fmt::Debug + BaseMonoItemExt<'a, 'tcx> { debug!("symbol {}", &symbol_name); match *self.as_mono_item() { - MonoItem::Static(node_id) => { - predefine_static(cx, node_id, linkage, visibility, &symbol_name); + MonoItem::Static(def_id) => { + predefine_static(cx, def_id, linkage, visibility, &symbol_name); } MonoItem::Fn(instance) => { predefine_fn(cx, instance, linkage, visibility, &symbol_name); @@ -126,11 +133,18 @@ pub trait MonoItemExt<'a, 'tcx>: fmt::Debug + BaseMonoItemExt<'a, 'tcx> { impl<'a, 'tcx> MonoItemExt<'a, 'tcx> for MonoItem<'tcx> {} fn predefine_static<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, - node_id: ast::NodeId, + def_id: DefId, linkage: Linkage, visibility: Visibility, symbol_name: &str) { - let def_id = cx.tcx.hir.local_def_id(node_id); + let node_id = match cx.tcx.hir.as_local_node_id(def_id) { + Some(node_id) => node_id, + None => { + bug!("MonoItemExt::predefine() called for non-local static `{:?}`.", + def_id) + } + }; + let instance = Instance::mono(cx.tcx, def_id); let ty = instance.ty(cx.tcx); let llty = cx.layout_of(ty).llvm_type(cx); From 8ff633cc3b85933e76c84b43d2c19250c397e9cb Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Mon, 19 Feb 2018 16:46:40 +0100 Subject: [PATCH 16/34] Implement describe_def query for LOCAL_CRATE --- src/librustc/hir/map/mod.rs | 98 +++++++++++++++++++++++++++++++++++ src/librustc/hir/mod.rs | 6 +++ src/librustc_driver/driver.rs | 1 + 3 files changed, 105 insertions(+) diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs index b6b3e8955351c..3799bdada888e 100644 --- a/src/librustc/hir/map/mod.rs +++ b/src/librustc/hir/map/mod.rs @@ -22,6 +22,7 @@ use hir::def_id::{CRATE_DEF_INDEX, DefId, LocalDefId, DefIndexAddressSpace}; use syntax::abi::Abi; use syntax::ast::{self, Name, NodeId, CRATE_NODE_ID}; use syntax::codemap::Spanned; +use syntax::ext::base::MacroKind; use syntax_pos::Span; use hir::*; @@ -32,6 +33,7 @@ use util::nodemap::{DefIdMap, FxHashMap}; use arena::TypedArena; use std::cell::RefCell; use std::io; +use ty::TyCtxt; pub mod blocks; mod collector; @@ -39,6 +41,7 @@ mod def_collector; pub mod definitions; mod hir_id_validator; + pub const ITEM_LIKE_SPACE: DefIndexAddressSpace = DefIndexAddressSpace::Low; pub const REGULAR_SPACE: DefIndexAddressSpace = DefIndexAddressSpace::High; @@ -373,6 +376,92 @@ impl<'hir> Map<'hir> { self.definitions.as_local_node_id(def_id.to_def_id()).unwrap() } + pub fn describe_def(&self, node_id: NodeId) -> Option { + let node = if let Some(node) = self.find(node_id) { + node + } else { + return None + }; + + match node { + NodeItem(item) => { + let def_id = || { + self.local_def_id(item.id) + }; + + match item.node { + ItemStatic(_, m, _) => Some(Def::Static(def_id(), + m == MutMutable)), + ItemConst(..) => Some(Def::Const(def_id())), + ItemFn(..) => Some(Def::Fn(def_id())), + ItemMod(..) => Some(Def::Mod(def_id())), + ItemGlobalAsm(..) => Some(Def::GlobalAsm(def_id())), + ItemTy(..) => Some(Def::TyAlias(def_id())), + ItemEnum(..) => Some(Def::Enum(def_id())), + ItemStruct(..) => Some(Def::Struct(def_id())), + ItemUnion(..) => Some(Def::Union(def_id())), + ItemTrait(..) => Some(Def::Trait(def_id())), + ItemTraitAlias(..) => { + bug!("trait aliases are not yet implemented (see issue #41517)") + }, + ItemExternCrate(_) | + ItemUse(..) | + ItemForeignMod(..) | + ItemImpl(..) => None, + } + } + NodeForeignItem(item) => { + let def_id = self.local_def_id(item.id); + match item.node { + ForeignItemFn(..) => Some(Def::Fn(def_id)), + ForeignItemStatic(_, m) => Some(Def::Static(def_id, m)), + ForeignItemType => Some(Def::TyForeign(def_id)), + } + } + NodeTraitItem(item) => { + let def_id = self.local_def_id(item.id); + match item.node { + TraitItemKind::Const(..) => Some(Def::AssociatedConst(def_id)), + TraitItemKind::Method(..) => Some(Def::Method(def_id)), + TraitItemKind::Type(..) => Some(Def::AssociatedTy(def_id)), + } + } + NodeImplItem(item) => { + let def_id = self.local_def_id(item.id); + match item.node { + ImplItemKind::Const(..) => Some(Def::AssociatedConst(def_id)), + ImplItemKind::Method(..) => Some(Def::Method(def_id)), + ImplItemKind::Type(..) => Some(Def::AssociatedTy(def_id)), + } + } + NodeVariant(variant) => { + let def_id = self.local_def_id(variant.node.data.id()); + Some(Def::Variant(def_id)) + } + NodeField(_) | + NodeExpr(_) | + NodeStmt(_) | + NodeTy(_) | + NodeTraitRef(_) | + NodePat(_) | + NodeBinding(_) | + NodeStructCtor(_) | + NodeLifetime(_) | + NodeVisibility(_) | + NodeBlock(_) => None, + NodeLocal(local) => { + Some(Def::Local(local.id)) + } + NodeMacroDef(macro_def) => { + Some(Def::Macro(self.local_def_id(macro_def.id), + MacroKind::Bang)) + } + NodeTyParam(param) => { + Some(Def::TyParam(self.local_def_id(param.id))) + } + } + } + fn entry_count(&self) -> usize { self.map.len() } @@ -1275,3 +1364,12 @@ fn node_id_to_string(map: &Map, id: NodeId, include_id: bool) -> String { } } } + +pub fn describe_def(tcx: TyCtxt, def_id: DefId) -> Option { + if let Some(node_id) = tcx.hir.as_local_node_id(def_id) { + tcx.hir.describe_def(node_id) + } else { + bug!("Calling local describe_def query provider for upstream DefId: {:?}", + def_id) + } +} diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index bc03f7ead8187..0fa1b95d8e777 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -43,6 +43,7 @@ use syntax::tokenstream::TokenStream; use syntax::util::ThinVec; use syntax::util::parser::ExprPrecedence; use ty::AdtKind; +use ty::maps::Providers; use rustc_data_structures::indexed_vec; @@ -2204,3 +2205,8 @@ pub type TraitMap = NodeMap>; // Map from the NodeId of a glob import to a list of items which are actually // imported. pub type GlobMap = NodeMap>; + + +pub fn provide(providers: &mut Providers) { + providers.describe_def = map::describe_def; +} diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index b8a1fe9910540..d283e13c95823 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -929,6 +929,7 @@ pub fn phase_2_configure_and_expand_inner<'a, F>(sess: &'a Session, } pub fn default_provide(providers: &mut ty::maps::Providers) { + hir::provide(providers); borrowck::provide(providers); mir::provide(providers); reachable::provide(providers); From 1be7f966e03f41eb299c184a3c0ad98018fb8fc4 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Mon, 19 Feb 2018 16:47:59 +0100 Subject: [PATCH 17/34] Rename is_translated_fn query to is_translated_item and make it support statics. --- src/librustc/dep_graph/dep_node.rs | 2 +- src/librustc/ty/maps/mod.rs | 2 +- src/librustc/ty/maps/plumbing.rs | 2 +- src/librustc_trans/base.rs | 5 +++-- src/librustc_trans/callee.rs | 2 +- 5 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index 4034055d04155..aa678ba788a5b 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -625,7 +625,7 @@ define_dep_nodes!( <'tcx> [eval_always] CollectAndPartitionTranslationItems, [] ExportName(DefId), [] ContainsExternIndicator(DefId), - [] IsTranslatedFunction(DefId), + [] IsTranslatedItem(DefId), [] CodegenUnit(InternedString), [] CompileCodegenUnit(InternedString), [input] OutputFilenames, diff --git a/src/librustc/ty/maps/mod.rs b/src/librustc/ty/maps/mod.rs index 21ffe6b895e72..be1d255afa191 100644 --- a/src/librustc/ty/maps/mod.rs +++ b/src/librustc/ty/maps/mod.rs @@ -349,7 +349,7 @@ define_maps! { <'tcx> [] fn export_name: ExportName(DefId) -> Option, [] fn contains_extern_indicator: ContainsExternIndicator(DefId) -> bool, [] fn symbol_export_level: GetSymbolExportLevel(DefId) -> SymbolExportLevel, - [] fn is_translated_function: IsTranslatedFunction(DefId) -> bool, + [] fn is_translated_item: IsTranslatedItem(DefId) -> bool, [] fn codegen_unit: CodegenUnit(InternedString) -> Arc>, [] fn compile_codegen_unit: CompileCodegenUnit(InternedString) -> Stats, [] fn output_filenames: output_filenames_node(CrateNum) diff --git a/src/librustc/ty/maps/plumbing.rs b/src/librustc/ty/maps/plumbing.rs index f02c7cbd0ea3e..146b3c859e933 100644 --- a/src/librustc/ty/maps/plumbing.rs +++ b/src/librustc/ty/maps/plumbing.rs @@ -929,7 +929,7 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>, DepKind::ContainsExternIndicator => { force!(contains_extern_indicator, def_id!()); } - DepKind::IsTranslatedFunction => { force!(is_translated_function, def_id!()); } + DepKind::IsTranslatedItem => { force!(is_translated_item, def_id!()); } DepKind::OutputFilenames => { force!(output_filenames, LOCAL_CRATE); } DepKind::TargetFeaturesWhitelist => { force!(target_features_whitelist, LOCAL_CRATE); } diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index 466a86e7ea558..c0785f5393716 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -1004,6 +1004,7 @@ fn collect_and_partition_translation_items<'a, 'tcx>( let translation_items: DefIdSet = items.iter().filter_map(|trans_item| { match *trans_item { MonoItem::Fn(ref instance) => Some(instance.def_id()), + MonoItem::Static(def_id) => Some(def_id), _ => None, } }).collect(); @@ -1107,7 +1108,7 @@ impl CrateInfo { } } -fn is_translated_function(tcx: TyCtxt, id: DefId) -> bool { +fn is_translated_item(tcx: TyCtxt, id: DefId) -> bool { let (all_trans_items, _) = tcx.collect_and_partition_translation_items(LOCAL_CRATE); all_trans_items.contains(&id) @@ -1222,7 +1223,7 @@ pub fn provide(providers: &mut Providers) { providers.collect_and_partition_translation_items = collect_and_partition_translation_items; - providers.is_translated_function = is_translated_function; + providers.is_translated_item = is_translated_item; providers.codegen_unit = |tcx, name| { let (_, all) = tcx.collect_and_partition_translation_items(LOCAL_CRATE); diff --git a/src/librustc_trans/callee.rs b/src/librustc_trans/callee.rs index c3d5e08c73e7e..8c40aa6a2acba 100644 --- a/src/librustc_trans/callee.rs +++ b/src/librustc_trans/callee.rs @@ -149,7 +149,7 @@ pub fn get_fn<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, unsafe { llvm::LLVMRustSetLinkage(llfn, llvm::Linkage::ExternalLinkage); - if cx.tcx.is_translated_function(instance_def_id) { + if cx.tcx.is_translated_item(instance_def_id) { if instance_def_id.is_local() { if !cx.tcx.is_exported_symbol(instance_def_id) { llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden); From 89b3ef3e8eae1a9cf119888341509e10fd7e1b9a Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Mon, 19 Feb 2018 16:49:20 +0100 Subject: [PATCH 18/34] Allow for instantiating statics from upstream crates. --- src/librustc_trans/consts.rs | 15 ++++++++---- src/librustc_trans/trans_item.rs | 40 +++++++++++++------------------- 2 files changed, 27 insertions(+), 28 deletions(-) diff --git a/src/librustc_trans/consts.rs b/src/librustc_trans/consts.rs index f9f185dfa5161..1608c4a87bf5c 100644 --- a/src/librustc_trans/consts.rs +++ b/src/librustc_trans/consts.rs @@ -226,8 +226,15 @@ pub fn get_static(cx: &CodegenCx, def_id: DefId) -> ValueRef { // statically in the final application, we always mark such symbols as 'dllimport'. // If final linkage happens to be static, we rely on compiler-emitted __imp_ stubs to // make things work. - unsafe { - llvm::LLVMSetDLLStorageClass(g, llvm::DLLStorageClass::DllImport); + // + // However, in some scenarios we defer emission of statics to downstream + // crates, so there are cases where a static with an upstream DefId + // is actually present in the current crate. We can find out via the + // is_translated_item query. + if !cx.tcx.is_translated_item(def_id) { + unsafe { + llvm::LLVMSetDLLStorageClass(g, llvm::DLLStorageClass::DllImport); + } } } g @@ -246,8 +253,8 @@ pub fn get_static(cx: &CodegenCx, def_id: DefId) -> ValueRef { } pub fn trans_static<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, - m: hir::Mutability, def_id: DefId, + is_mutable: bool, attrs: &[ast::Attribute]) -> Result> { unsafe { @@ -298,7 +305,7 @@ pub fn trans_static<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, // As an optimization, all shared statics which do not have interior // mutability are placed into read-only memory. - if m != hir::MutMutable { + if !is_mutable { if cx.type_is_freeze(ty) { llvm::LLVMSetGlobalConstant(g, llvm::True); } diff --git a/src/librustc_trans/trans_item.rs b/src/librustc_trans/trans_item.rs index 2751e32925931..91c1097fc7f8a 100644 --- a/src/librustc_trans/trans_item.rs +++ b/src/librustc_trans/trans_item.rs @@ -24,6 +24,7 @@ use llvm; use monomorphize::Instance; use type_of::LayoutLlvmExt; use rustc::hir; +use rustc::hir::def::Def; use rustc::hir::def_id::DefId; use rustc::mir::mono::{Linkage, Visibility}; use rustc::ty::TypeFoldable; @@ -46,24 +47,23 @@ pub trait MonoItemExt<'a, 'tcx>: fmt::Debug + BaseMonoItemExt<'a, 'tcx> { match *self.as_mono_item() { MonoItem::Static(def_id) => { let tcx = cx.tcx; - let node_id = match tcx.hir.as_local_node_id(def_id) { - Some(node_id) => node_id, + let is_mutable = match tcx.describe_def(def_id) { + Some(Def::Static(_, is_mutable)) => is_mutable, + Some(other) => { + bug!("Expected Def::Static, found {:?}", other) + } None => { - bug!("MonoItemExt::define() called for non-local \ - static `{:?}`.", def_id) + bug!("Expected Def::Static for {:?}, found nothing", def_id) + } + }; + let attrs = tcx.get_attrs(def_id); + + match consts::trans_static(&cx, def_id, is_mutable, &attrs) { + Ok(_) => { /* Cool, everything's alright. */ }, + Err(err) => { + err.report(tcx, tcx.def_span(def_id), "static"); } }; - let item = tcx.hir.expect_item(node_id); - if let hir::ItemStatic(_, m, _) = item.node { - match consts::trans_static(&cx, m, def_id, &item.attrs) { - Ok(_) => { /* Cool, everything's alright. */ }, - Err(err) => { - err.report(tcx, item.span, "static"); - } - }; - } else { - span_bug!(item.span, "Mismatch between hir::Item type and TransItem type") - } } MonoItem::GlobalAsm(node_id) => { let item = cx.tcx.hir.expect_item(node_id); @@ -137,20 +137,12 @@ fn predefine_static<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, linkage: Linkage, visibility: Visibility, symbol_name: &str) { - let node_id = match cx.tcx.hir.as_local_node_id(def_id) { - Some(node_id) => node_id, - None => { - bug!("MonoItemExt::predefine() called for non-local static `{:?}`.", - def_id) - } - }; - let instance = Instance::mono(cx.tcx, def_id); let ty = instance.ty(cx.tcx); let llty = cx.layout_of(ty).llvm_type(cx); let g = declare::define_global(cx, symbol_name, llty).unwrap_or_else(|| { - cx.sess().span_fatal(cx.tcx.hir.span(node_id), + cx.sess().span_fatal(cx.tcx.def_span(def_id), &format!("symbol `{}` is already defined", symbol_name)) }); From 1aad320974786f3abbe6e82a9d96d5594238046b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Mon, 19 Feb 2018 10:07:45 -0800 Subject: [PATCH 19/34] When encountering invalid token after `unsafe`, mention `{` --- src/libsyntax/parse/parser.rs | 2 ++ src/test/ui/unsafe-block-without-braces.rs | 16 ++++++++++++++++ src/test/ui/unsafe-block-without-braces.stderr | 10 ++++++++++ 3 files changed, 28 insertions(+) create mode 100644 src/test/ui/unsafe-block-without-braces.rs create mode 100644 src/test/ui/unsafe-block-without-braces.stderr diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index ac582627f88fd..fed7d25811aab 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -6469,6 +6469,8 @@ impl<'a> Parser<'a> { && self.look_ahead(1, |t| *t != token::OpenDelim(token::Brace)) { // UNSAFE FUNCTION ITEM self.bump(); // `unsafe` + // `{` is also expected after `unsafe`, in case of error, include it in the diagnostic + self.check(&token::OpenDelim(token::Brace)); let abi = if self.eat_keyword(keywords::Extern) { self.parse_opt_abi()?.unwrap_or(Abi::C) } else { diff --git a/src/test/ui/unsafe-block-without-braces.rs b/src/test/ui/unsafe-block-without-braces.rs new file mode 100644 index 0000000000000..b6fb3ec5c44cf --- /dev/null +++ b/src/test/ui/unsafe-block-without-braces.rs @@ -0,0 +1,16 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main() { + unsafe //{ + std::mem::transmute::(1.0); + //} +} +//~^^^ ERROR expected one of `extern`, `fn`, or `{`, found `std` diff --git a/src/test/ui/unsafe-block-without-braces.stderr b/src/test/ui/unsafe-block-without-braces.stderr new file mode 100644 index 0000000000000..fc6ddba382395 --- /dev/null +++ b/src/test/ui/unsafe-block-without-braces.stderr @@ -0,0 +1,10 @@ +error: expected one of `extern`, `fn`, or `{`, found `std` + --> $DIR/unsafe-block-without-braces.rs:13:9 + | +12 | unsafe //{ + | - expected one of `extern`, `fn`, or `{` here +13 | std::mem::transmute::(1.0); + | ^^^ unexpected token + +error: aborting due to previous error + From 713b05f0726b7ee4c45728c01ddb0c40d8ccf0f3 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Wed, 21 Feb 2018 19:20:09 +0200 Subject: [PATCH 20/34] rustc_data_structures: add missing #[inline]. --- src/librustc_data_structures/bitslice.rs | 3 +++ src/librustc_data_structures/indexed_vec.rs | 6 ++++++ 2 files changed, 9 insertions(+) diff --git a/src/librustc_data_structures/bitslice.rs b/src/librustc_data_structures/bitslice.rs index 7665bfd5b1117..2678861be0634 100644 --- a/src/librustc_data_structures/bitslice.rs +++ b/src/librustc_data_structures/bitslice.rs @@ -24,6 +24,7 @@ pub trait BitSlice { impl BitSlice for [Word] { /// Clears bit at `idx` to 0; returns true iff this changed `self.` + #[inline] fn clear_bit(&mut self, idx: usize) -> bool { let words = self; debug!("clear_bit: words={} idx={}", @@ -37,6 +38,7 @@ impl BitSlice for [Word] { } /// Sets bit at `idx` to 1; returns true iff this changed `self.` + #[inline] fn set_bit(&mut self, idx: usize) -> bool { let words = self; debug!("set_bit: words={} idx={}", @@ -50,6 +52,7 @@ impl BitSlice for [Word] { } /// Extracts value of bit at `idx` in `self`. + #[inline] fn get_bit(&self, idx: usize) -> bool { let words = self; let BitLookup { word, bit_mask, .. } = bit_lookup(idx); diff --git a/src/librustc_data_structures/indexed_vec.rs b/src/librustc_data_structures/indexed_vec.rs index b11ca107af7dd..14626f9d5a0fd 100644 --- a/src/librustc_data_structures/indexed_vec.rs +++ b/src/librustc_data_structures/indexed_vec.rs @@ -29,12 +29,16 @@ pub trait Idx: Copy + 'static + Eq + Debug { } impl Idx for usize { + #[inline] fn new(idx: usize) -> Self { idx } + #[inline] fn index(self) -> usize { self } } impl Idx for u32 { + #[inline] fn new(idx: usize) -> Self { assert!(idx <= u32::MAX as usize); idx as u32 } + #[inline] fn index(self) -> usize { self as usize } } @@ -73,11 +77,13 @@ macro_rules! newtype_index { pub struct $type($($pub)* u32); impl Idx for $type { + #[inline] fn new(value: usize) -> Self { assert!(value < ($max) as usize); $type(value as u32) } + #[inline] fn index(self) -> usize { self.0 as usize } From 1eab1b19a39f54a825c9107086f0c1752b81224d Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 8 Feb 2018 17:16:39 -0500 Subject: [PATCH 21/34] support unit tests with return values that implement `Terminaton` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Extend `Termination` trait with a method to determine what happens with a unit test. This commit incorporates work by Bastian Köcher . --- src/librustc_driver/driver.rs | 3 +- src/libstd/termination.rs | 7 + src/libsyntax/lib.rs | 1 + src/libsyntax/test.rs | 170 +++++++++++++----- .../run-pass/termination-trait-in-test.rs | 28 +++ 5 files changed, 166 insertions(+), 43 deletions(-) create mode 100644 src/test/run-pass/termination-trait-in-test.rs diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index b8a1fe9910540..e4600f25ea70c 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -816,7 +816,8 @@ pub fn phase_2_configure_and_expand_inner<'a, F>(sess: &'a Session, &mut resolver, sess.opts.test, krate, - sess.diagnostic()) + sess.diagnostic(), + &sess.features.borrow()) }); // If we're actually rustdoc then there's no need to actually compile diff --git a/src/libstd/termination.rs b/src/libstd/termination.rs index dc7fa53aab632..f02fad009d8a5 100644 --- a/src/libstd/termination.rs +++ b/src/libstd/termination.rs @@ -37,6 +37,13 @@ pub trait Termination { /// Is called to get the representation of the value as status code. /// This status code is returned to the operating system. fn report(self) -> i32; + + /// Invoked when unit tests terminate. Should panic if the unit + /// test is considered a failure. By default, invokes `report()` + /// and checks for a `0` result. + fn assert_unit_test_successful(self) where Self: Sized { + assert_eq!(self.report(), 0); + } } #[unstable(feature = "termination_trait", issue = "43301")] diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index 9181cca215c84..53ff3ccd48ad9 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -105,6 +105,7 @@ pub mod syntax { pub use ext; pub use parse; pub use ast; + pub use tokenstream; } pub mod abi; diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs index e73550d0719a4..094de6868a500 100644 --- a/src/libsyntax/test.rs +++ b/src/libsyntax/test.rs @@ -32,6 +32,7 @@ use ext::build::AstBuilder; use ext::expand::ExpansionConfig; use ext::hygiene::{Mark, SyntaxContext}; use fold::Folder; +use feature_gate::Features; use util::move_map::MoveMap; use fold; use parse::{token, ParseSess}; @@ -63,6 +64,7 @@ struct TestCtxt<'a> { reexport_test_harness_main: Option, is_libtest: bool, ctxt: SyntaxContext, + features: &'a Features, // top-level re-export submodule, filled out after folding is finished toplevel_reexport: Option, @@ -74,7 +76,8 @@ pub fn modify_for_testing(sess: &ParseSess, resolver: &mut Resolver, should_test: bool, krate: ast::Crate, - span_diagnostic: &errors::Handler) -> ast::Crate { + span_diagnostic: &errors::Handler, + features: &Features) -> ast::Crate { // Check for #[reexport_test_harness_main = "some_name"] which // creates a `use some_name = __test::main;`. This needs to be // unconditional, so that the attribute is still marked as used in @@ -84,7 +87,8 @@ pub fn modify_for_testing(sess: &ParseSess, "reexport_test_harness_main"); if should_test { - generate_test_harness(sess, resolver, reexport_test_harness_main, krate, span_diagnostic) + generate_test_harness(sess, resolver, reexport_test_harness_main, + krate, span_diagnostic, features) } else { krate } @@ -265,16 +269,20 @@ fn generate_test_harness(sess: &ParseSess, resolver: &mut Resolver, reexport_test_harness_main: Option, krate: ast::Crate, - sd: &errors::Handler) -> ast::Crate { + sd: &errors::Handler, + features: &Features) -> ast::Crate { // Remove the entry points let mut cleaner = EntryPointCleaner { depth: 0 }; let krate = cleaner.fold_crate(krate); let mark = Mark::fresh(Mark::root()); + let mut econfig = ExpansionConfig::default("test".to_string()); + econfig.features = Some(features); + let cx = TestCtxt { span_diagnostic: sd, - ext_cx: ExtCtxt::new(sess, ExpansionConfig::default("test".to_string()), resolver), + ext_cx: ExtCtxt::new(sess, econfig, resolver), path: Vec::new(), testfns: Vec::new(), reexport_test_harness_main, @@ -282,6 +290,7 @@ fn generate_test_harness(sess: &ParseSess, is_libtest: attr::find_crate_name(&krate.attrs).map(|s| s == "test").unwrap_or(false), toplevel_reexport: None, ctxt: SyntaxContext::empty().apply_mark(mark), + features, }; mark.set_expn_info(ExpnInfo { @@ -318,71 +327,105 @@ enum HasTestSignature { fn is_test_fn(cx: &TestCtxt, i: &ast::Item) -> bool { let has_test_attr = attr::contains_name(&i.attrs, "test"); - fn has_test_signature(i: &ast::Item) -> HasTestSignature { + fn has_test_signature(cx: &TestCtxt, i: &ast::Item) -> HasTestSignature { match i.node { - ast::ItemKind::Fn(ref decl, _, _, _, ref generics, _) => { - let no_output = match decl.output { - ast::FunctionRetTy::Default(..) => true, - ast::FunctionRetTy::Ty(ref t) if t.node == ast::TyKind::Tup(vec![]) => true, - _ => false - }; - if decl.inputs.is_empty() - && no_output - && !generics.is_parameterized() { - Yes - } else { - No + ast::ItemKind::Fn(ref decl, _, _, _, ref generics, _) => { + // If the termination trait is active, the compiler will check that the output + // type implements the `Termination` trait as `libtest` enforces that. + let output_matches = if cx.features.termination_trait { + true + } else { + let no_output = match decl.output { + ast::FunctionRetTy::Default(..) => true, + ast::FunctionRetTy::Ty(ref t) if t.node == ast::TyKind::Tup(vec![]) => true, + _ => false + }; + + no_output && !generics.is_parameterized() + }; + + if decl.inputs.is_empty() && output_matches { + Yes + } else { + No + } } - } - _ => NotEvenAFunction, + _ => NotEvenAFunction, } } - if has_test_attr { + let has_test_signature = if has_test_attr { let diag = cx.span_diagnostic; - match has_test_signature(i) { - Yes => {}, - No => diag.span_err(i.span, "functions used as tests must have signature fn() -> ()"), - NotEvenAFunction => diag.span_err(i.span, - "only functions may be used as tests"), + match has_test_signature(cx, i) { + Yes => true, + No => { + if cx.features.termination_trait { + diag.span_err(i.span, "functions used as tests can not have any arguments"); + } else { + diag.span_err(i.span, "functions used as tests must have signature fn() -> ()"); + } + false + }, + NotEvenAFunction => { + diag.span_err(i.span, "only functions may be used as tests"); + false + }, } - } + } else { + false + }; - has_test_attr && has_test_signature(i) == Yes + has_test_attr && has_test_signature } fn is_bench_fn(cx: &TestCtxt, i: &ast::Item) -> bool { let has_bench_attr = attr::contains_name(&i.attrs, "bench"); - fn has_test_signature(i: &ast::Item) -> bool { + fn has_bench_signature(cx: &TestCtxt, i: &ast::Item) -> bool { match i.node { ast::ItemKind::Fn(ref decl, _, _, _, ref generics, _) => { let input_cnt = decl.inputs.len(); - let no_output = match decl.output { - ast::FunctionRetTy::Default(..) => true, - ast::FunctionRetTy::Ty(ref t) if t.node == ast::TyKind::Tup(vec![]) => true, - _ => false + + // If the termination trait is active, the compiler will check that the output + // type implements the `Termination` trait as `libtest` enforces that. + let output_matches = if cx.features.termination_trait { + true + } else { + let no_output = match decl.output { + ast::FunctionRetTy::Default(..) => true, + ast::FunctionRetTy::Ty(ref t) if t.node == ast::TyKind::Tup(vec![]) => true, + _ => false + }; + let tparm_cnt = generics.params.iter() + .filter(|param| param.is_type_param()) + .count(); + + no_output && tparm_cnt == 0 }; - let tparm_cnt = generics.params.iter() - .filter(|param| param.is_type_param()) - .count(); // NB: inadequate check, but we're running // well before resolve, can't get too deep. - input_cnt == 1 - && no_output && tparm_cnt == 0 + input_cnt == 1 && output_matches } _ => false } } - if has_bench_attr && !has_test_signature(i) { + let has_bench_signature = has_bench_signature(cx, i); + + if has_bench_attr && !has_bench_signature { let diag = cx.span_diagnostic; - diag.span_err(i.span, "functions used as benches must have signature \ - `fn(&mut Bencher) -> ()`"); + + if cx.features.termination_trait { + diag.span_err(i.span, "functions used as benches must have signature \ + `fn(&mut Bencher) -> impl Termination`"); + } else { + diag.span_err(i.span, "functions used as benches must have signature \ + `fn(&mut Bencher) -> ()`"); + } } - has_bench_attr && has_test_signature(i) + has_bench_attr && has_bench_signature } fn is_ignored(i: &ast::Item) -> bool { @@ -700,9 +743,52 @@ fn mk_test_desc_and_fn_rec(cx: &TestCtxt, test: &Test) -> P { }; visible_path.extend(path); - let fn_expr = ecx.expr_path(ecx.path_global(span, visible_path)); + // If termination feature is enabled, create a wrapper that invokes the fn + // like this: + // + // fn wrapper() { + // assert_eq!(0, real_function().report()); + // } + // + // and then put a reference to `wrapper` into the test descriptor. Otherwise, + // just put a direct reference to `real_function`. + let fn_expr = { + let base_fn_expr = ecx.expr_path(ecx.path_global(span, visible_path)); + if cx.features.termination_trait { + // ::std::Termination::assert_unit_test_successful + let assert_unit_test_successful = ecx.path_global( + span, + vec![ + ecx.ident_of("std"), + ecx.ident_of("Termination"), + ecx.ident_of("assert_unit_test_successful"), + ], + ); + // || {..} + ecx.lambda( + span, + vec![], + // ::std::Termination::assert_unit_test_successful(..) + ecx.expr_call( + span, + ecx.expr_path(assert_unit_test_successful), + vec![ + // $base_fn_expr() + ecx.expr_call( + span, + base_fn_expr, + vec![], + ) + ], + ), + ) + } else { + base_fn_expr + } + }; let variant_name = if test.bench { "StaticBenchFn" } else { "StaticTestFn" }; + // self::test::$variant_name($fn_expr) let testfn_expr = ecx.expr_call(span, ecx.expr_path(test_path(variant_name)), vec![fn_expr]); diff --git a/src/test/run-pass/termination-trait-in-test.rs b/src/test/run-pass/termination-trait-in-test.rs new file mode 100644 index 0000000000000..e67e0de5c318b --- /dev/null +++ b/src/test/run-pass/termination-trait-in-test.rs @@ -0,0 +1,28 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: --test + +#![feature(termination_trait)] + +use std::num::ParseIntError; + +#[test] +fn is_a_num() -> Result<(), ParseIntError> { + let _: u32 = "22".parse()?; + Ok(()) +} + +#[test] +#[should_panic] +fn not_a_num() -> Result<(), ParseIntError> { + let _: u32 = "abc".parse()?; + Ok(()) +} From 0625d4c282a9fa2a5ba3c6448017898baccfcf9a Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sun, 11 Feb 2018 09:28:47 -0500 Subject: [PATCH 22/34] begin crate-relative paths with `crate` --- src/libsyntax/ext/build.rs | 10 +++------ src/libsyntax/test.rs | 9 +++++--- .../rfc-2126-extern-absolute-paths/test.rs | 21 +++++++++++++++++++ 3 files changed, 30 insertions(+), 10 deletions(-) create mode 100644 src/test/run-pass/rfc-2126-extern-absolute-paths/test.rs diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index 2e6de96d65a6d..57978ca9c80a5 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -319,14 +319,8 @@ impl<'a> AstBuilder for ExtCtxt<'a> { types: Vec>, bindings: Vec ) -> ast::Path { - use syntax::parse::token; - let last_identifier = idents.pop().unwrap(); let mut segments: Vec = Vec::new(); - if global && - !idents.first().map_or(false, |&ident| token::Ident(ident).is_path_segment_keyword()) { - segments.push(ast::PathSegment::crate_root(span)); - } segments.extend(idents.into_iter().map(|i| ast::PathSegment::from_ident(i, span))); let parameters = if !lifetimes.is_empty() || !types.is_empty() || !bindings.is_empty() { @@ -335,7 +329,9 @@ impl<'a> AstBuilder for ExtCtxt<'a> { None }; segments.push(ast::PathSegment { identifier: last_identifier, span, parameters }); - ast::Path { span, segments } + let path = ast::Path { span, segments }; + + if global { path.default_to_global() } else { path } } /// Constructs a qualified path. diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs index 094de6868a500..6cbb7ab393fae 100644 --- a/src/libsyntax/test.rs +++ b/src/libsyntax/test.rs @@ -733,9 +733,12 @@ fn mk_test_desc_and_fn_rec(cx: &TestCtxt, test: &Test) -> P { field("should_panic", fail_expr), field("allow_fail", allow_fail_expr)]); - - let mut visible_path = match cx.toplevel_reexport { - Some(id) => vec![id], + let mut visible_path = vec![]; + if cx.features.extern_absolute_paths { + visible_path.push(keywords::Crate.ident()); + } + match cx.toplevel_reexport { + Some(id) => visible_path.push(id), None => { let diag = cx.span_diagnostic; diag.bug("expected to find top-level re-export name, but found None"); diff --git a/src/test/run-pass/rfc-2126-extern-absolute-paths/test.rs b/src/test/run-pass/rfc-2126-extern-absolute-paths/test.rs new file mode 100644 index 0000000000000..796f652d6b57b --- /dev/null +++ b/src/test/run-pass/rfc-2126-extern-absolute-paths/test.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. + +// Check that `#[test]` works with extern-absolute-paths enabled. +// +// Regression test for #47075. + +// compile-flags: --test + +#![feature(extern_absolute_paths)] + +#[test] +fn test() { +} From e446f706a89e3d5c26c01318bd70904d492ab8b2 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 14 Feb 2018 10:06:12 -0500 Subject: [PATCH 23/34] put the "unit test" logic into libtest Also make `std::termination` module public and rename feature. The lib feature needs a different name from the language feature. --- src/libstd/lib.rs | 5 +- src/libstd/termination.rs | 23 ++++--- src/libsyntax/test.rs | 60 ++++++++----------- src/libtest/lib.rs | 9 +++ .../termination-trait-main-wrong-type.rs | 2 +- .../termination-trait-not-satisfied.rs | 2 +- 6 files changed, 47 insertions(+), 54 deletions(-) diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 3c9004cdd19bc..b247d121648f6 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -501,11 +501,10 @@ mod memchr; // The runtime entry point and a few unstable public functions used by the // compiler pub mod rt; -// The trait to support returning arbitrary types in the main function -mod termination; +// The trait to support returning arbitrary types in the main function #[unstable(feature = "termination_trait", issue = "43301")] -pub use self::termination::Termination; +pub mod termination; // Include a number of private modules that exist solely to provide // the rustdoc documentation for primitive types. Using `include!` diff --git a/src/libstd/termination.rs b/src/libstd/termination.rs index f02fad009d8a5..203870766a9ab 100644 --- a/src/libstd/termination.rs +++ b/src/libstd/termination.rs @@ -8,7 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +//! Defines the meaning of the return value from `main`, and hence +//! controls what happens in a Rust program after `main` returns. + use fmt::Debug; + #[cfg(target_arch = "wasm32")] mod exit { pub const SUCCESS: i32 = 0; @@ -30,28 +34,21 @@ mod exit { /// The default implementations are returning `libc::EXIT_SUCCESS` to indicate /// a successful execution. In case of a failure, `libc::EXIT_FAILURE` is returned. #[cfg_attr(not(test), lang = "termination")] -#[unstable(feature = "termination_trait", issue = "43301")] +#[unstable(feature = "termination_trait_lib", issue = "43301")] #[rustc_on_unimplemented = "`main` can only return types that implement {Termination}, not `{Self}`"] pub trait Termination { /// Is called to get the representation of the value as status code. /// This status code is returned to the operating system. fn report(self) -> i32; - - /// Invoked when unit tests terminate. Should panic if the unit - /// test is considered a failure. By default, invokes `report()` - /// and checks for a `0` result. - fn assert_unit_test_successful(self) where Self: Sized { - assert_eq!(self.report(), 0); - } } -#[unstable(feature = "termination_trait", issue = "43301")] +#[unstable(feature = "termination_trait_lib", issue = "43301")] impl Termination for () { fn report(self) -> i32 { exit::SUCCESS } } -#[unstable(feature = "termination_trait", issue = "43301")] +#[unstable(feature = "termination_trait_lib", issue = "43301")] impl Termination for Result { fn report(self) -> i32 { match self { @@ -64,19 +61,19 @@ impl Termination for Result { } } -#[unstable(feature = "termination_trait", issue = "43301")] +#[unstable(feature = "termination_trait_lib", issue = "43301")] impl Termination for ! { fn report(self) -> i32 { unreachable!(); } } -#[unstable(feature = "termination_trait", issue = "43301")] +#[unstable(feature = "termination_trait_lib", issue = "43301")] impl Termination for bool { fn report(self) -> i32 { if self { exit::SUCCESS } else { exit::FAILURE } } } -#[unstable(feature = "termination_trait", issue = "43301")] +#[unstable(feature = "termination_trait_lib", issue = "43301")] impl Termination for i32 { fn report(self) -> i32 { self diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs index 6cbb7ab393fae..b48713fcf7aa1 100644 --- a/src/libsyntax/test.rs +++ b/src/libsyntax/test.rs @@ -746,48 +746,36 @@ fn mk_test_desc_and_fn_rec(cx: &TestCtxt, test: &Test) -> P { }; visible_path.extend(path); - // If termination feature is enabled, create a wrapper that invokes the fn - // like this: + // Rather than directly give the test function to the test + // harness, we create a wrapper like this: // - // fn wrapper() { - // assert_eq!(0, real_function().report()); - // } + // || test::assert_test_result(real_function()) // - // and then put a reference to `wrapper` into the test descriptor. Otherwise, - // just put a direct reference to `real_function`. + // this will coerce into a fn pointer that is specialized to the + // actual return type of `real_function` (Typically `()`, but not always). let fn_expr = { - let base_fn_expr = ecx.expr_path(ecx.path_global(span, visible_path)); - if cx.features.termination_trait { - // ::std::Termination::assert_unit_test_successful - let assert_unit_test_successful = ecx.path_global( + // construct `real_function()` (this will be inserted into the overall expr) + let real_function_expr = ecx.expr_path(ecx.path_global(span, visible_path)); + // construct path `test::assert_test_result` + let assert_test_result = test_path("assert_test_result"); + // construct `|| {..}` + ecx.lambda( + span, + vec![], + // construct `assert_test_result(..)` + ecx.expr_call( span, + ecx.expr_path(assert_test_result), vec![ - ecx.ident_of("std"), - ecx.ident_of("Termination"), - ecx.ident_of("assert_unit_test_successful"), + // construct `real_function()` + ecx.expr_call( + span, + real_function_expr, + vec![], + ) ], - ); - // || {..} - ecx.lambda( - span, - vec![], - // ::std::Termination::assert_unit_test_successful(..) - ecx.expr_call( - span, - ecx.expr_path(assert_unit_test_successful), - vec![ - // $base_fn_expr() - ecx.expr_call( - span, - base_fn_expr, - vec![], - ) - ], - ), - ) - } else { - base_fn_expr - } + ), + ) }; let variant_name = if test.bench { "StaticBenchFn" } else { "StaticTestFn" }; diff --git a/src/libtest/lib.rs b/src/libtest/lib.rs index 9ea5f39b71fee..932952d649bdf 100644 --- a/src/libtest/lib.rs +++ b/src/libtest/lib.rs @@ -40,6 +40,7 @@ #![feature(set_stdio)] #![feature(panic_unwind)] #![feature(staged_api)] +#![feature(termination_trait_lib)] extern crate getopts; extern crate term; @@ -69,6 +70,7 @@ use std::iter::repeat; use std::path::PathBuf; use std::sync::mpsc::{channel, Sender}; use std::sync::{Arc, Mutex}; +use std::termination::Termination; use std::thread; use std::time::{Instant, Duration}; use std::borrow::Cow; @@ -322,6 +324,13 @@ pub fn test_main_static(tests: &[TestDescAndFn]) { test_main(&args, owned_tests, Options::new()) } +/// Invoked when unit tests terminate. Should panic if the unit +/// test is considered a failure. By default, invokes `report()` +/// and checks for a `0` result. +pub fn assert_test_result(result: T) { + assert_eq!(result.report(), 0); +} + #[derive(Copy, Clone, Debug)] pub enum ColorConfig { AutoColor, diff --git a/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-main-wrong-type.rs b/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-main-wrong-type.rs index a63162cf73d1c..2da518519521f 100644 --- a/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-main-wrong-type.rs +++ b/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-main-wrong-type.rs @@ -10,6 +10,6 @@ #![feature(termination_trait)] fn main() -> char { -//~^ ERROR: the trait bound `char: std::Termination` is not satisfied +//~^ ERROR: the trait bound `char: std::termination::Termination` is not satisfied ' ' } diff --git a/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-not-satisfied.rs b/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-not-satisfied.rs index 788c38c55be0a..fac60d6d39971 100644 --- a/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-not-satisfied.rs +++ b/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-not-satisfied.rs @@ -12,6 +12,6 @@ struct ReturnType {} -fn main() -> ReturnType { //~ ERROR `ReturnType: std::Termination` is not satisfied +fn main() -> ReturnType { //~ ERROR `ReturnType: std::termination::Termination` is not satisfied ReturnType {} } From 5f1e78f19ad40c6265a200b41c772c321b8b08cd Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 22 Feb 2018 17:36:55 -0500 Subject: [PATCH 24/34] move Termination trait to std::process --- src/libstd/lib.rs | 4 - src/libstd/process.rs | 67 +++++++++++++++ src/libstd/rt.rs | 2 +- src/libstd/termination.rs | 81 ------------------- src/libtest/lib.rs | 2 +- .../termination-trait-main-wrong-type.rs | 2 +- .../termination-trait-not-satisfied.rs | 2 +- 7 files changed, 71 insertions(+), 89 deletions(-) delete mode 100644 src/libstd/termination.rs diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index b247d121648f6..bdda741633692 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -502,10 +502,6 @@ mod memchr; // compiler pub mod rt; -// The trait to support returning arbitrary types in the main function -#[unstable(feature = "termination_trait", issue = "43301")] -pub mod termination; - // Include a number of private modules that exist solely to provide // the rustdoc documentation for primitive types. Using `include!` // because rustdoc only looks for these modules at the crate level. diff --git a/src/libstd/process.rs b/src/libstd/process.rs index 9b2f815b71383..e25599b8bd871 100644 --- a/src/libstd/process.rs +++ b/src/libstd/process.rs @@ -1392,6 +1392,73 @@ pub fn id() -> u32 { ::sys::os::getpid() } +#[cfg(target_arch = "wasm32")] +mod exit { + pub const SUCCESS: i32 = 0; + pub const FAILURE: i32 = 1; +} +#[cfg(not(target_arch = "wasm32"))] +mod exit { + use libc; + pub const SUCCESS: i32 = libc::EXIT_SUCCESS; + pub const FAILURE: i32 = libc::EXIT_FAILURE; +} + +/// A trait for implementing arbitrary return types in the `main` function. +/// +/// The c-main function only supports to return integers as return type. +/// So, every type implementing the `Termination` trait has to be converted +/// to an integer. +/// +/// The default implementations are returning `libc::EXIT_SUCCESS` to indicate +/// a successful execution. In case of a failure, `libc::EXIT_FAILURE` is returned. +#[cfg_attr(not(test), lang = "termination")] +#[unstable(feature = "termination_trait_lib", issue = "43301")] +#[rustc_on_unimplemented = + "`main` can only return types that implement {Termination}, not `{Self}`"] +pub trait Termination { + /// Is called to get the representation of the value as status code. + /// This status code is returned to the operating system. + fn report(self) -> i32; +} + +#[unstable(feature = "termination_trait_lib", issue = "43301")] +impl Termination for () { + fn report(self) -> i32 { exit::SUCCESS } +} + +#[unstable(feature = "termination_trait_lib", issue = "43301")] +impl Termination for Result { + fn report(self) -> i32 { + match self { + Ok(val) => val.report(), + Err(err) => { + eprintln!("Error: {:?}", err); + exit::FAILURE + } + } + } +} + +#[unstable(feature = "termination_trait_lib", issue = "43301")] +impl Termination for ! { + fn report(self) -> i32 { unreachable!(); } +} + +#[unstable(feature = "termination_trait_lib", issue = "43301")] +impl Termination for bool { + fn report(self) -> i32 { + if self { exit::SUCCESS } else { exit::FAILURE } + } +} + +#[unstable(feature = "termination_trait_lib", issue = "43301")] +impl Termination for i32 { + fn report(self) -> i32 { + self + } +} + #[cfg(all(test, not(any(target_os = "cloudabi", target_os = "emscripten"))))] mod tests { use io::prelude::*; diff --git a/src/libstd/rt.rs b/src/libstd/rt.rs index 9dbaf784f89e0..e1392762a59dc 100644 --- a/src/libstd/rt.rs +++ b/src/libstd/rt.rs @@ -68,7 +68,7 @@ fn lang_start_internal(main: &(Fn() -> i32 + Sync + ::panic::RefUnwindSafe), #[cfg(not(test))] #[lang = "start"] -fn lang_start +fn lang_start (main: fn() -> T, argc: isize, argv: *const *const u8) -> isize { lang_start_internal(&move || main().report(), argc, argv) diff --git a/src/libstd/termination.rs b/src/libstd/termination.rs deleted file mode 100644 index 203870766a9ab..0000000000000 --- a/src/libstd/termination.rs +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright 2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Defines the meaning of the return value from `main`, and hence -//! controls what happens in a Rust program after `main` returns. - -use fmt::Debug; - -#[cfg(target_arch = "wasm32")] -mod exit { - pub const SUCCESS: i32 = 0; - pub const FAILURE: i32 = 1; -} -#[cfg(not(target_arch = "wasm32"))] -mod exit { - use libc; - pub const SUCCESS: i32 = libc::EXIT_SUCCESS; - pub const FAILURE: i32 = libc::EXIT_FAILURE; -} - -/// A trait for implementing arbitrary return types in the `main` function. -/// -/// The c-main function only supports to return integers as return type. -/// So, every type implementing the `Termination` trait has to be converted -/// to an integer. -/// -/// The default implementations are returning `libc::EXIT_SUCCESS` to indicate -/// a successful execution. In case of a failure, `libc::EXIT_FAILURE` is returned. -#[cfg_attr(not(test), lang = "termination")] -#[unstable(feature = "termination_trait_lib", issue = "43301")] -#[rustc_on_unimplemented = - "`main` can only return types that implement {Termination}, not `{Self}`"] -pub trait Termination { - /// Is called to get the representation of the value as status code. - /// This status code is returned to the operating system. - fn report(self) -> i32; -} - -#[unstable(feature = "termination_trait_lib", issue = "43301")] -impl Termination for () { - fn report(self) -> i32 { exit::SUCCESS } -} - -#[unstable(feature = "termination_trait_lib", issue = "43301")] -impl Termination for Result { - fn report(self) -> i32 { - match self { - Ok(val) => val.report(), - Err(err) => { - eprintln!("Error: {:?}", err); - exit::FAILURE - } - } - } -} - -#[unstable(feature = "termination_trait_lib", issue = "43301")] -impl Termination for ! { - fn report(self) -> i32 { unreachable!(); } -} - -#[unstable(feature = "termination_trait_lib", issue = "43301")] -impl Termination for bool { - fn report(self) -> i32 { - if self { exit::SUCCESS } else { exit::FAILURE } - } -} - -#[unstable(feature = "termination_trait_lib", issue = "43301")] -impl Termination for i32 { - fn report(self) -> i32 { - self - } -} diff --git a/src/libtest/lib.rs b/src/libtest/lib.rs index 932952d649bdf..06a23cd8818ee 100644 --- a/src/libtest/lib.rs +++ b/src/libtest/lib.rs @@ -68,9 +68,9 @@ use std::io::prelude::*; use std::io; use std::iter::repeat; use std::path::PathBuf; +use std::process::Termination; use std::sync::mpsc::{channel, Sender}; use std::sync::{Arc, Mutex}; -use std::termination::Termination; use std::thread; use std::time::{Instant, Duration}; use std::borrow::Cow; diff --git a/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-main-wrong-type.rs b/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-main-wrong-type.rs index 2da518519521f..93e2561adf753 100644 --- a/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-main-wrong-type.rs +++ b/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-main-wrong-type.rs @@ -10,6 +10,6 @@ #![feature(termination_trait)] fn main() -> char { -//~^ ERROR: the trait bound `char: std::termination::Termination` is not satisfied +//~^ ERROR: the trait bound `char: std::process::Termination` is not satisfied ' ' } diff --git a/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-not-satisfied.rs b/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-not-satisfied.rs index fac60d6d39971..e87e0ceebf1b1 100644 --- a/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-not-satisfied.rs +++ b/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-not-satisfied.rs @@ -12,6 +12,6 @@ struct ReturnType {} -fn main() -> ReturnType { //~ ERROR `ReturnType: std::termination::Termination` is not satisfied +fn main() -> ReturnType { //~ ERROR `ReturnType: std::process::Termination` is not satisfied ReturnType {} } From 8f35141fbad39b94b071186e2d8259694bd4960d Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 22 Feb 2018 18:26:01 -0500 Subject: [PATCH 25/34] remove tokenstream --- src/libsyntax/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index 53ff3ccd48ad9..9181cca215c84 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -105,7 +105,6 @@ pub mod syntax { pub use ext; pub use parse; pub use ast; - pub use tokenstream; } pub mod abi; From 067c2e3d0393311ac3dc9d8abb8750fd2fd5dd11 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 22 Feb 2018 20:09:10 -0500 Subject: [PATCH 26/34] handle `#[bench]` functions better --- src/libsyntax/test.rs | 62 ++++++++++++++++++++++++++++++------------- 1 file changed, 43 insertions(+), 19 deletions(-) diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs index b48713fcf7aa1..1b48901d4ebec 100644 --- a/src/libsyntax/test.rs +++ b/src/libsyntax/test.rs @@ -747,9 +747,10 @@ fn mk_test_desc_and_fn_rec(cx: &TestCtxt, test: &Test) -> P { visible_path.extend(path); // Rather than directly give the test function to the test - // harness, we create a wrapper like this: + // harness, we create a wrapper like one of the following: // - // || test::assert_test_result(real_function()) + // || test::assert_test_result(real_function()) // for test + // |b| test::assert_test_result(real_function(b)) // for bench // // this will coerce into a fn pointer that is specialized to the // actual return type of `real_function` (Typically `()`, but not always). @@ -758,24 +759,47 @@ fn mk_test_desc_and_fn_rec(cx: &TestCtxt, test: &Test) -> P { let real_function_expr = ecx.expr_path(ecx.path_global(span, visible_path)); // construct path `test::assert_test_result` let assert_test_result = test_path("assert_test_result"); - // construct `|| {..}` - ecx.lambda( - span, - vec![], - // construct `assert_test_result(..)` - ecx.expr_call( + if test.bench { + // construct `|b| {..}` + let b_ident = Ident::with_empty_ctxt(Symbol::gensym("b")); + let b_expr = ecx.expr_ident(span, b_ident); + ecx.lambda( span, - ecx.expr_path(assert_test_result), - vec![ - // construct `real_function()` - ecx.expr_call( - span, - real_function_expr, - vec![], - ) - ], - ), - ) + vec![b_ident], + // construct `assert_test_result(..)` + ecx.expr_call( + span, + ecx.expr_path(assert_test_result), + vec![ + // construct `real_function(b)` + ecx.expr_call( + span, + real_function_expr, + vec![b_expr], + ) + ], + ), + ) + } else { + // construct `|| {..}` + ecx.lambda( + span, + vec![], + // construct `assert_test_result(..)` + ecx.expr_call( + span, + ecx.expr_path(assert_test_result), + vec![ + // construct `real_function()` + ecx.expr_call( + span, + real_function_expr, + vec![], + ) + ], + ), + ) + } }; let variant_name = if test.bench { "StaticBenchFn" } else { "StaticTestFn" }; From e0ed88df3d33637ef8a41d3655cd20587f566048 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 22 Feb 2018 20:10:36 -0500 Subject: [PATCH 27/34] add test for `fn main() -> !` --- .../termination-trait-for-never.rs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 src/test/run-fail/rfc-1937-termination-trait/termination-trait-for-never.rs diff --git a/src/test/run-fail/rfc-1937-termination-trait/termination-trait-for-never.rs b/src/test/run-fail/rfc-1937-termination-trait/termination-trait-for-never.rs new file mode 100644 index 0000000000000..c1dd44a91765e --- /dev/null +++ b/src/test/run-fail/rfc-1937-termination-trait/termination-trait-for-never.rs @@ -0,0 +1,17 @@ +// 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(termination_trait)] + +// error-pattern:oh, dear + +fn main() -> ! { + panic!("oh, dear"); +} From a0562ec369629abc0b365c95b77e67aec232bd85 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 22 Feb 2018 20:16:06 -0500 Subject: [PATCH 28/34] delete this test file: it also appears as src/rfc-1937-termination-trait/termination-trait-for-result-box-error_ok.rs --- ...termination-trait-for-result-box-error_ok.rs | 17 ----------------- 1 file changed, 17 deletions(-) delete mode 100644 src/test/run-pass/termination-trait-for-result-box-error_ok.rs diff --git a/src/test/run-pass/termination-trait-for-result-box-error_ok.rs b/src/test/run-pass/termination-trait-for-result-box-error_ok.rs deleted file mode 100644 index 269ac451cf4d8..0000000000000 --- a/src/test/run-pass/termination-trait-for-result-box-error_ok.rs +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright 2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![feature(termination_trait)] - -use std::io::Error; - -fn main() -> Result<(), Box> { - Ok(()) -} From 0a5f4aebb170a7ac758176d5eaf5e88ed71accbc Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 22 Feb 2018 20:16:30 -0500 Subject: [PATCH 29/34] move test to the proper directory and test #[bench] --- .../termination-trait-in-test.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) rename src/test/run-pass/{ => rfc-1937-termination-trait}/termination-trait-in-test.rs (72%) diff --git a/src/test/run-pass/termination-trait-in-test.rs b/src/test/run-pass/rfc-1937-termination-trait/termination-trait-in-test.rs similarity index 72% rename from src/test/run-pass/termination-trait-in-test.rs rename to src/test/run-pass/rfc-1937-termination-trait/termination-trait-in-test.rs index e67e0de5c318b..494500d522abe 100644 --- a/src/test/run-pass/termination-trait-in-test.rs +++ b/src/test/run-pass/rfc-1937-termination-trait/termination-trait-in-test.rs @@ -11,8 +11,11 @@ // compile-flags: --test #![feature(termination_trait)] +#![feature(test)] +extern crate test; use std::num::ParseIntError; +use test::Bencher; #[test] fn is_a_num() -> Result<(), ParseIntError> { @@ -26,3 +29,15 @@ fn not_a_num() -> Result<(), ParseIntError> { let _: u32 = "abc".parse()?; Ok(()) } + +#[bench] +fn test_a_positive_bench(_: &mut Bencher) -> Result<(), ParseIntError> { + Ok(()) +} + +#[bench] +#[should_panic] +fn test_a_neg_bench(_: &mut Bencher) -> Result<(), ParseIntError> { + let _: u32 = "abc".parse()?; + Ok(()) +} From 068e3832cd9c3c9ac43128e1056a8d8b05fe1406 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 23 Feb 2018 07:34:00 -0500 Subject: [PATCH 30/34] update test -- we now give a slightly different error --- src/test/compile-fail/issue-12997-2.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/test/compile-fail/issue-12997-2.rs b/src/test/compile-fail/issue-12997-2.rs index 85d91bb2db202..8d3df68577bab 100644 --- a/src/test/compile-fail/issue-12997-2.rs +++ b/src/test/compile-fail/issue-12997-2.rs @@ -15,6 +15,3 @@ #[bench] fn bar(x: isize) { } //~^ ERROR mismatched types -//~| expected type `for<'r> fn(&'r mut __test::test::Bencher)` -//~| found type `fn(isize) {bar}` -//~| expected mutable reference, found isize From 10f7c110928ee7d3db7fef15fd7dce776b17e161 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 23 Feb 2018 10:11:06 -0500 Subject: [PATCH 31/34] re-export `assert_test_result` for use when testing libtest itself --- src/libtest/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libtest/lib.rs b/src/libtest/lib.rs index 06a23cd8818ee..82077bc4cd482 100644 --- a/src/libtest/lib.rs +++ b/src/libtest/lib.rs @@ -83,8 +83,8 @@ const QUIET_MODE_MAX_COLUMN: usize = 100; // insert a '\n' after 100 tests in qu pub mod test { pub use {Bencher, TestName, TestResult, TestDesc, TestDescAndFn, TestOpts, TrFailed, TrFailedMsg, TrIgnored, TrOk, Metric, MetricMap, StaticTestFn, StaticTestName, - DynTestName, DynTestFn, run_test, test_main, test_main_static, filter_tests, - parse_opts, StaticBenchFn, ShouldPanic, Options}; + DynTestName, DynTestFn, assert_test_result, run_test, test_main, test_main_static, + filter_tests, parse_opts, StaticBenchFn, ShouldPanic, Options}; } pub mod stats; From 380e388a868ff694c4200d58f75e298416da743b Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 7 Feb 2018 17:26:40 -0500 Subject: [PATCH 32/34] do not run MIR type checker twice --- src/librustc_mir/borrow_check/nll/type_check/mod.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs index 7ca8d0bdd500b..eafb12fab9645 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -1585,6 +1585,10 @@ impl MirPass for TypeckMir { let id = tcx.hir.as_local_node_id(def_id).unwrap(); debug!("run_pass: {:?}", def_id); + if tcx.sess.nll() { + return; + } + if tcx.sess.err_count() > 0 { // compiling a broken program can obviously result in a // broken MIR, so try not to report duplicate errors. From 2370b6052972377b67444e9146cdaf37fc36d85f Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 22 Feb 2018 18:46:02 -0500 Subject: [PATCH 33/34] update tests and reference files The type checker invokes the borrow checker for closures it finds, so removing the NLL type checker affects ordering of errors somewhat. --- .../borrowck/two-phase-nonrecv-autoref.rs | 12 +- .../projection-no-regions-closure.stderr | 94 ++++---- .../projection-one-region-closure.stderr | 102 ++++---- ...tion-one-region-trait-bound-closure.stderr | 126 +++++----- ...e-region-trait-bound-static-closure.stderr | 108 ++++----- ...tion-two-region-trait-bound-closure.stderr | 228 +++++++++--------- ...ram-closure-approximate-lower-bound.stderr | 28 +-- ...-closure-outlives-from-where-clause.stderr | 126 +++++----- 8 files changed, 410 insertions(+), 414 deletions(-) diff --git a/src/test/compile-fail/borrowck/two-phase-nonrecv-autoref.rs b/src/test/compile-fail/borrowck/two-phase-nonrecv-autoref.rs index 795d45a776db5..c425ed554a6f8 100644 --- a/src/test/compile-fail/borrowck/two-phase-nonrecv-autoref.rs +++ b/src/test/compile-fail/borrowck/two-phase-nonrecv-autoref.rs @@ -105,14 +105,10 @@ fn overloaded_call_traits() { //[lxl]~^^^ ERROR use of moved value: `*f` //[nll]~^^^^ ERROR cannot move a value of type //[nll]~^^^^^ ERROR cannot move a value of type - //[nll]~^^^^^^ ERROR cannot move a value of type - //[nll]~^^^^^^^ ERROR cannot move a value of type - //[nll]~^^^^^^^^ ERROR use of moved value: `*f` - //[g2p]~^^^^^^^^^ ERROR cannot move a value of type - //[g2p]~^^^^^^^^^^ ERROR cannot move a value of type - //[g2p]~^^^^^^^^^^^ ERROR cannot move a value of type - //[g2p]~^^^^^^^^^^^^ ERROR cannot move a value of type - //[g2p]~^^^^^^^^^^^^^ ERROR use of moved value: `*f` + //[nll]~^^^^^^ ERROR use of moved value: `*f` + //[g2p]~^^^^^^^ ERROR cannot move a value of type + //[g2p]~^^^^^^^^ ERROR cannot move a value of type + //[g2p]~^^^^^^^^^ ERROR use of moved value: `*f` } twice_ten_sm(&mut |x| x + 1); diff --git a/src/test/ui/nll/ty-outlives/projection-no-regions-closure.stderr b/src/test/ui/nll/ty-outlives/projection-no-regions-closure.stderr index b2e98b7c2f6a4..30669dc4c2f8c 100644 --- a/src/test/ui/nll/ty-outlives/projection-no-regions-closure.stderr +++ b/src/test/ui/nll/ty-outlives/projection-no-regions-closure.stderr @@ -25,53 +25,6 @@ note: External requirements = note: number of external vids: 3 = note: where ::Item: '_#2r -note: External requirements - --> $DIR/projection-no-regions-closure.rs:46:23 - | -46 | with_signature(x, |mut y| Box::new(y.next())) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: defining type: DefId(0/1:18 ~ projection_no_regions_closure[317d]::correct_region[0]::{{closure}}[0]) with closure substs [ - '_#1r, - T, - i32, - extern "rust-call" fn((std::boxed::Box,)) -> std::boxed::Box - ] - = note: number of external vids: 3 - = note: where ::Item: '_#2r - -note: External requirements - --> $DIR/projection-no-regions-closure.rs:54:23 - | -54 | with_signature(x, |mut y| Box::new(y.next())) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: defining type: DefId(0/1:22 ~ projection_no_regions_closure[317d]::wrong_region[0]::{{closure}}[0]) with closure substs [ - '_#1r, - '_#2r, - T, - i32, - extern "rust-call" fn((std::boxed::Box,)) -> std::boxed::Box - ] - = note: number of external vids: 4 - = note: where ::Item: '_#3r - -note: External requirements - --> $DIR/projection-no-regions-closure.rs:65:23 - | -65 | with_signature(x, |mut y| Box::new(y.next())) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: defining type: DefId(0/1:26 ~ projection_no_regions_closure[317d]::outlives_region[0]::{{closure}}[0]) with closure substs [ - '_#1r, - '_#2r, - T, - i32, - extern "rust-call" fn((std::boxed::Box,)) -> std::boxed::Box - ] - = note: number of external vids: 4 - = note: where ::Item: '_#3r - error[E0309]: the associated type `::Item` may not live long enough --> $DIR/projection-no-regions-closure.rs:36:23 | @@ -97,6 +50,21 @@ note: No external requirements T ] +note: External requirements + --> $DIR/projection-no-regions-closure.rs:46:23 + | +46 | with_signature(x, |mut y| Box::new(y.next())) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: defining type: DefId(0/1:18 ~ projection_no_regions_closure[317d]::correct_region[0]::{{closure}}[0]) with closure substs [ + '_#1r, + T, + i32, + extern "rust-call" fn((std::boxed::Box,)) -> std::boxed::Box + ] + = note: number of external vids: 3 + = note: where ::Item: '_#2r + note: No external requirements --> $DIR/projection-no-regions-closure.rs:42:1 | @@ -113,6 +81,22 @@ note: No external requirements T ] +note: External requirements + --> $DIR/projection-no-regions-closure.rs:54:23 + | +54 | with_signature(x, |mut y| Box::new(y.next())) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: defining type: DefId(0/1:22 ~ projection_no_regions_closure[317d]::wrong_region[0]::{{closure}}[0]) with closure substs [ + '_#1r, + '_#2r, + T, + i32, + extern "rust-call" fn((std::boxed::Box,)) -> std::boxed::Box + ] + = note: number of external vids: 4 + = note: where ::Item: '_#3r + error[E0309]: the associated type `::Item` may not live long enough --> $DIR/projection-no-regions-closure.rs:54:23 | @@ -139,6 +123,22 @@ note: No external requirements T ] +note: External requirements + --> $DIR/projection-no-regions-closure.rs:65:23 + | +65 | with_signature(x, |mut y| Box::new(y.next())) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: defining type: DefId(0/1:26 ~ projection_no_regions_closure[317d]::outlives_region[0]::{{closure}}[0]) with closure substs [ + '_#1r, + '_#2r, + T, + i32, + extern "rust-call" fn((std::boxed::Box,)) -> std::boxed::Box + ] + = note: number of external vids: 4 + = note: where ::Item: '_#3r + note: No external requirements --> $DIR/projection-no-regions-closure.rs:60:1 | diff --git a/src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr b/src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr index bfe408342a868..946c1a8f37235 100644 --- a/src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr +++ b/src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr @@ -32,57 +32,6 @@ note: External requirements = note: where T: '_#2r = note: where '_#1r: '_#2r -note: External requirements - --> $DIR/projection-one-region-closure.rs:68:29 - | -68 | with_signature(cell, t, |cell, t| require(cell, t)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: defining type: DefId(0/1:23 ~ projection_one_region_closure[317d]::no_relationships_early[0]::{{closure}}[0]) with closure substs [ - '_#1r, - '_#2r, - T, - i32, - extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)) - ] - = note: number of external vids: 4 - = note: where T: '_#3r - = note: where '_#2r: '_#3r - -note: External requirements - --> $DIR/projection-one-region-closure.rs:90:29 - | -90 | with_signature(cell, t, |cell, t| require(cell, t)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: defining type: DefId(0/1:27 ~ projection_one_region_closure[317d]::projection_outlives[0]::{{closure}}[0]) with closure substs [ - '_#1r, - '_#2r, - T, - i32, - extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)) - ] - = note: number of external vids: 4 - = note: where T: '_#3r - = note: where '_#2r: '_#3r - -note: External requirements - --> $DIR/projection-one-region-closure.rs:103:29 - | -103 | with_signature(cell, t, |cell, t| require(cell, t)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: defining type: DefId(0/1:31 ~ projection_one_region_closure[317d]::elements_outlive[0]::{{closure}}[0]) with closure substs [ - '_#1r, - '_#2r, - T, - i32, - extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)) - ] - = note: number of external vids: 4 - = note: where T: '_#3r - = note: where '_#2r: '_#3r - error[E0309]: the parameter type `T` may not live long enough --> $DIR/projection-one-region-closure.rs:56:29 | @@ -114,6 +63,23 @@ note: No external requirements T ] +note: External requirements + --> $DIR/projection-one-region-closure.rs:68:29 + | +68 | with_signature(cell, t, |cell, t| require(cell, t)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: defining type: DefId(0/1:23 ~ projection_one_region_closure[317d]::no_relationships_early[0]::{{closure}}[0]) with closure substs [ + '_#1r, + '_#2r, + T, + i32, + extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)) + ] + = note: number of external vids: 4 + = note: where T: '_#3r + = note: where '_#2r: '_#3r + error[E0309]: the parameter type `T` may not live long enough --> $DIR/projection-one-region-closure.rs:68:29 | @@ -146,6 +112,23 @@ note: No external requirements T ] +note: External requirements + --> $DIR/projection-one-region-closure.rs:90:29 + | +90 | with_signature(cell, t, |cell, t| require(cell, t)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: defining type: DefId(0/1:27 ~ projection_one_region_closure[317d]::projection_outlives[0]::{{closure}}[0]) with closure substs [ + '_#1r, + '_#2r, + T, + i32, + extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)) + ] + = note: number of external vids: 4 + = note: where T: '_#3r + = note: where '_#2r: '_#3r + error[E0309]: the parameter type `T` may not live long enough --> $DIR/projection-one-region-closure.rs:90:29 | @@ -178,6 +161,23 @@ note: No external requirements T ] +note: External requirements + --> $DIR/projection-one-region-closure.rs:103:29 + | +103 | with_signature(cell, t, |cell, t| require(cell, t)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: defining type: DefId(0/1:31 ~ projection_one_region_closure[317d]::elements_outlive[0]::{{closure}}[0]) with closure substs [ + '_#1r, + '_#2r, + T, + i32, + extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)) + ] + = note: number of external vids: 4 + = note: where T: '_#3r + = note: where '_#2r: '_#3r + note: No external requirements --> $DIR/projection-one-region-closure.rs:97:1 | diff --git a/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr b/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr index 6cb54170d7a90..b26fa96fe6389 100644 --- a/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr +++ b/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr @@ -31,69 +31,6 @@ note: External requirements = note: number of external vids: 3 = note: where '_#1r: '_#2r -note: External requirements - --> $DIR/projection-one-region-trait-bound-closure.rs:59:29 - | -59 | with_signature(cell, t, |cell, t| require(cell, t)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: defining type: DefId(0/1:23 ~ projection_one_region_trait_bound_closure[317d]::no_relationships_early[0]::{{closure}}[0]) with closure substs [ - '_#1r, - '_#2r, - T, - i32, - extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)) - ] - = note: number of external vids: 4 - = note: where '_#2r: '_#3r - -note: External requirements - --> $DIR/projection-one-region-trait-bound-closure.rs:80:29 - | -80 | with_signature(cell, t, |cell, t| require(cell, t)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: defining type: DefId(0/1:27 ~ projection_one_region_trait_bound_closure[317d]::projection_outlives[0]::{{closure}}[0]) with closure substs [ - '_#1r, - '_#2r, - T, - i32, - extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)) - ] - = note: number of external vids: 4 - = note: where '_#2r: '_#3r - -note: External requirements - --> $DIR/projection-one-region-trait-bound-closure.rs:91:29 - | -91 | with_signature(cell, t, |cell, t| require(cell, t)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: defining type: DefId(0/1:31 ~ projection_one_region_trait_bound_closure[317d]::elements_outlive[0]::{{closure}}[0]) with closure substs [ - '_#1r, - '_#2r, - T, - i32, - extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)) - ] - = note: number of external vids: 4 - = note: where '_#2r: '_#3r - -note: External requirements - --> $DIR/projection-one-region-trait-bound-closure.rs:103:29 - | -103 | with_signature(cell, t, |cell, t| require(cell, t)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: defining type: DefId(0/1:34 ~ projection_one_region_trait_bound_closure[317d]::one_region[0]::{{closure}}[0]) with closure substs [ - '_#1r, - T, - i32, - extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)) - ] - = note: number of external vids: 3 - = note: where '_#1r: '_#2r - error: free region `ReEarlyBound(0, 'b)` does not outlive free region `ReFree(DefId(0/0:8 ~ projection_one_region_trait_bound_closure[317d]::no_relationships_late[0]), BrNamed(crate0:DefIndex(1:16), 'a))` --> $DIR/projection-one-region-trait-bound-closure.rs:48:20 | @@ -117,6 +54,22 @@ note: No external requirements T ] +note: External requirements + --> $DIR/projection-one-region-trait-bound-closure.rs:59:29 + | +59 | with_signature(cell, t, |cell, t| require(cell, t)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: defining type: DefId(0/1:23 ~ projection_one_region_trait_bound_closure[317d]::no_relationships_early[0]::{{closure}}[0]) with closure substs [ + '_#1r, + '_#2r, + T, + i32, + extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)) + ] + = note: number of external vids: 4 + = note: where '_#2r: '_#3r + error: free region `ReEarlyBound(1, 'b)` does not outlive free region `ReEarlyBound(0, 'a)` --> $DIR/projection-one-region-trait-bound-closure.rs:59:20 | @@ -141,6 +94,22 @@ note: No external requirements T ] +note: External requirements + --> $DIR/projection-one-region-trait-bound-closure.rs:80:29 + | +80 | with_signature(cell, t, |cell, t| require(cell, t)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: defining type: DefId(0/1:27 ~ projection_one_region_trait_bound_closure[317d]::projection_outlives[0]::{{closure}}[0]) with closure substs [ + '_#1r, + '_#2r, + T, + i32, + extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)) + ] + = note: number of external vids: 4 + = note: where '_#2r: '_#3r + error: free region `ReEarlyBound(1, 'b)` does not outlive free region `ReEarlyBound(0, 'a)` --> $DIR/projection-one-region-trait-bound-closure.rs:80:20 | @@ -165,6 +134,22 @@ note: No external requirements T ] +note: External requirements + --> $DIR/projection-one-region-trait-bound-closure.rs:91:29 + | +91 | with_signature(cell, t, |cell, t| require(cell, t)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: defining type: DefId(0/1:31 ~ projection_one_region_trait_bound_closure[317d]::elements_outlive[0]::{{closure}}[0]) with closure substs [ + '_#1r, + '_#2r, + T, + i32, + extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)) + ] + = note: number of external vids: 4 + = note: where '_#2r: '_#3r + note: No external requirements --> $DIR/projection-one-region-trait-bound-closure.rs:86:1 | @@ -183,6 +168,21 @@ note: No external requirements T ] +note: External requirements + --> $DIR/projection-one-region-trait-bound-closure.rs:103:29 + | +103 | with_signature(cell, t, |cell, t| require(cell, t)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: defining type: DefId(0/1:34 ~ projection_one_region_trait_bound_closure[317d]::one_region[0]::{{closure}}[0]) with closure substs [ + '_#1r, + T, + i32, + extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)) + ] + = note: number of external vids: 3 + = note: where '_#1r: '_#2r + note: No external requirements --> $DIR/projection-one-region-trait-bound-closure.rs:95:1 | diff --git a/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-static-closure.stderr b/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-static-closure.stderr index 986676d28d920..98b033b6a0672 100644 --- a/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-static-closure.stderr +++ b/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-static-closure.stderr @@ -12,40 +12,28 @@ note: No external requirements ] note: No external requirements - --> $DIR/projection-one-region-trait-bound-static-closure.rs:56:29 - | -56 | with_signature(cell, t, |cell, t| require(cell, t)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: defining type: DefId(0/1:23 ~ projection_one_region_trait_bound_static_closure[317d]::no_relationships_early[0]::{{closure}}[0]) with closure substs [ - '_#1r, - '_#2r, - T, - i32, - extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)) - ] - -note: No external requirements - --> $DIR/projection-one-region-trait-bound-static-closure.rs:75:29 + --> $DIR/projection-one-region-trait-bound-static-closure.rs:43:1 | -75 | with_signature(cell, t, |cell, t| require(cell, t)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +43 | / fn no_relationships_late<'a, 'b, T>(cell: Cell<&'a ()>, t: T) +44 | | where +45 | | T: Anything<'b>, +46 | | { +47 | | with_signature(cell, t, |cell, t| require(cell, t)); +48 | | } + | |_^ | - = note: defining type: DefId(0/1:27 ~ projection_one_region_trait_bound_static_closure[317d]::projection_outlives[0]::{{closure}}[0]) with closure substs [ + = note: defining type: DefId(0/0:8 ~ projection_one_region_trait_bound_static_closure[317d]::no_relationships_late[0]) with substs [ '_#1r, - '_#2r, - T, - i32, - extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)) + T ] note: No external requirements - --> $DIR/projection-one-region-trait-bound-static-closure.rs:84:29 + --> $DIR/projection-one-region-trait-bound-static-closure.rs:56:29 | -84 | with_signature(cell, t, |cell, t| require(cell, t)); +56 | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: DefId(0/1:31 ~ projection_one_region_trait_bound_static_closure[317d]::elements_outlive[0]::{{closure}}[0]) with closure substs [ + = note: defining type: DefId(0/1:23 ~ projection_one_region_trait_bound_static_closure[317d]::no_relationships_early[0]::{{closure}}[0]) with closure substs [ '_#1r, '_#2r, T, @@ -53,35 +41,6 @@ note: No external requirements extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)) ] -note: No external requirements - --> $DIR/projection-one-region-trait-bound-static-closure.rs:96:29 - | -96 | with_signature(cell, t, |cell, t| require(cell, t)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: defining type: DefId(0/1:34 ~ projection_one_region_trait_bound_static_closure[317d]::one_region[0]::{{closure}}[0]) with closure substs [ - '_#1r, - T, - i32, - extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)) - ] - -note: No external requirements - --> $DIR/projection-one-region-trait-bound-static-closure.rs:43:1 - | -43 | / fn no_relationships_late<'a, 'b, T>(cell: Cell<&'a ()>, t: T) -44 | | where -45 | | T: Anything<'b>, -46 | | { -47 | | with_signature(cell, t, |cell, t| require(cell, t)); -48 | | } - | |_^ - | - = note: defining type: DefId(0/0:8 ~ projection_one_region_trait_bound_static_closure[317d]::no_relationships_late[0]) with substs [ - '_#1r, - T - ] - note: No external requirements --> $DIR/projection-one-region-trait-bound-static-closure.rs:51:1 | @@ -100,6 +59,20 @@ note: No external requirements T ] +note: No external requirements + --> $DIR/projection-one-region-trait-bound-static-closure.rs:75:29 + | +75 | with_signature(cell, t, |cell, t| require(cell, t)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: defining type: DefId(0/1:27 ~ projection_one_region_trait_bound_static_closure[317d]::projection_outlives[0]::{{closure}}[0]) with closure substs [ + '_#1r, + '_#2r, + T, + i32, + extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)) + ] + note: No external requirements --> $DIR/projection-one-region-trait-bound-static-closure.rs:60:1 | @@ -118,6 +91,20 @@ note: No external requirements T ] +note: No external requirements + --> $DIR/projection-one-region-trait-bound-static-closure.rs:84:29 + | +84 | with_signature(cell, t, |cell, t| require(cell, t)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: defining type: DefId(0/1:31 ~ projection_one_region_trait_bound_static_closure[317d]::elements_outlive[0]::{{closure}}[0]) with closure substs [ + '_#1r, + '_#2r, + T, + i32, + extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)) + ] + note: No external requirements --> $DIR/projection-one-region-trait-bound-static-closure.rs:79:1 | @@ -136,6 +123,19 @@ note: No external requirements T ] +note: No external requirements + --> $DIR/projection-one-region-trait-bound-static-closure.rs:96:29 + | +96 | with_signature(cell, t, |cell, t| require(cell, t)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: defining type: DefId(0/1:34 ~ projection_one_region_trait_bound_static_closure[317d]::one_region[0]::{{closure}}[0]) with closure substs [ + '_#1r, + T, + i32, + extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)) + ] + note: No external requirements --> $DIR/projection-one-region-trait-bound-static-closure.rs:88:1 | diff --git a/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr b/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr index 21487899d3ba6..78775ce94addd 100644 --- a/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr +++ b/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr @@ -38,120 +38,6 @@ note: External requirements = note: number of external vids: 4 = note: where >::AssocType: '_#3r -note: External requirements - --> $DIR/projection-two-region-trait-bound-closure.rs:60:29 - | -60 | with_signature(cell, t, |cell, t| require(cell, t)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: defining type: DefId(0/1:27 ~ projection_two_region_trait_bound_closure[317d]::no_relationships_early[0]::{{closure}}[0]) with closure substs [ - '_#1r, - '_#2r, - '_#3r, - T, - i32, - extern "rust-call" fn((std::cell::Cell<&'_#4r ()>, T)) - ] - = note: number of external vids: 5 - = note: where >::AssocType: '_#4r - -note: External requirements - --> $DIR/projection-two-region-trait-bound-closure.rs:81:29 - | -81 | with_signature(cell, t, |cell, t| require(cell, t)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: defining type: DefId(0/1:32 ~ projection_two_region_trait_bound_closure[317d]::projection_outlives[0]::{{closure}}[0]) with closure substs [ - '_#1r, - '_#2r, - '_#3r, - T, - i32, - extern "rust-call" fn((std::cell::Cell<&'_#4r ()>, T)) - ] - = note: number of external vids: 5 - = note: where >::AssocType: '_#4r - -note: External requirements - --> $DIR/projection-two-region-trait-bound-closure.rs:92:29 - | -92 | with_signature(cell, t, |cell, t| require(cell, t)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: defining type: DefId(0/1:37 ~ projection_two_region_trait_bound_closure[317d]::elements_outlive1[0]::{{closure}}[0]) with closure substs [ - '_#1r, - '_#2r, - '_#3r, - T, - i32, - extern "rust-call" fn((std::cell::Cell<&'_#4r ()>, T)) - ] - = note: number of external vids: 5 - = note: where >::AssocType: '_#4r - -note: External requirements - --> $DIR/projection-two-region-trait-bound-closure.rs:101:29 - | -101 | with_signature(cell, t, |cell, t| require(cell, t)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: defining type: DefId(0/1:42 ~ projection_two_region_trait_bound_closure[317d]::elements_outlive2[0]::{{closure}}[0]) with closure substs [ - '_#1r, - '_#2r, - '_#3r, - T, - i32, - extern "rust-call" fn((std::cell::Cell<&'_#4r ()>, T)) - ] - = note: number of external vids: 5 - = note: where >::AssocType: '_#4r - -note: External requirements - --> $DIR/projection-two-region-trait-bound-closure.rs:109:29 - | -109 | with_signature(cell, t, |cell, t| require(cell, t)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: defining type: DefId(0/1:46 ~ projection_two_region_trait_bound_closure[317d]::two_regions[0]::{{closure}}[0]) with closure substs [ - '_#1r, - T, - i32, - extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)) - ] - = note: number of external vids: 3 - = note: where >::AssocType: '_#2r - -note: External requirements - --> $DIR/projection-two-region-trait-bound-closure.rs:120:29 - | -120 | with_signature(cell, t, |cell, t| require(cell, t)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: defining type: DefId(0/1:50 ~ projection_two_region_trait_bound_closure[317d]::two_regions_outlive[0]::{{closure}}[0]) with closure substs [ - '_#1r, - '_#2r, - T, - i32, - extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)) - ] - = note: number of external vids: 4 - = note: where >::AssocType: '_#3r - -note: External requirements - --> $DIR/projection-two-region-trait-bound-closure.rs:132:29 - | -132 | with_signature(cell, t, |cell, t| require(cell, t)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: defining type: DefId(0/1:53 ~ projection_two_region_trait_bound_closure[317d]::one_region[0]::{{closure}}[0]) with closure substs [ - '_#1r, - T, - i32, - extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)) - ] - = note: number of external vids: 3 - = note: where >::AssocType: '_#2r - error[E0309]: the associated type `>::AssocType` may not live long enough --> $DIR/projection-two-region-trait-bound-closure.rs:49:29 | @@ -178,6 +64,23 @@ note: No external requirements T ] +note: External requirements + --> $DIR/projection-two-region-trait-bound-closure.rs:60:29 + | +60 | with_signature(cell, t, |cell, t| require(cell, t)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: defining type: DefId(0/1:27 ~ projection_two_region_trait_bound_closure[317d]::no_relationships_early[0]::{{closure}}[0]) with closure substs [ + '_#1r, + '_#2r, + '_#3r, + T, + i32, + extern "rust-call" fn((std::cell::Cell<&'_#4r ()>, T)) + ] + = note: number of external vids: 5 + = note: where >::AssocType: '_#4r + error[E0309]: the associated type `>::AssocType` may not live long enough --> $DIR/projection-two-region-trait-bound-closure.rs:60:29 | @@ -205,6 +108,23 @@ note: No external requirements T ] +note: External requirements + --> $DIR/projection-two-region-trait-bound-closure.rs:81:29 + | +81 | with_signature(cell, t, |cell, t| require(cell, t)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: defining type: DefId(0/1:32 ~ projection_two_region_trait_bound_closure[317d]::projection_outlives[0]::{{closure}}[0]) with closure substs [ + '_#1r, + '_#2r, + '_#3r, + T, + i32, + extern "rust-call" fn((std::cell::Cell<&'_#4r ()>, T)) + ] + = note: number of external vids: 5 + = note: where >::AssocType: '_#4r + error[E0309]: the associated type `>::AssocType` may not live long enough --> $DIR/projection-two-region-trait-bound-closure.rs:81:29 | @@ -232,6 +152,23 @@ note: No external requirements T ] +note: External requirements + --> $DIR/projection-two-region-trait-bound-closure.rs:92:29 + | +92 | with_signature(cell, t, |cell, t| require(cell, t)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: defining type: DefId(0/1:37 ~ projection_two_region_trait_bound_closure[317d]::elements_outlive1[0]::{{closure}}[0]) with closure substs [ + '_#1r, + '_#2r, + '_#3r, + T, + i32, + extern "rust-call" fn((std::cell::Cell<&'_#4r ()>, T)) + ] + = note: number of external vids: 5 + = note: where >::AssocType: '_#4r + note: No external requirements --> $DIR/projection-two-region-trait-bound-closure.rs:87:1 | @@ -251,6 +188,23 @@ note: No external requirements T ] +note: External requirements + --> $DIR/projection-two-region-trait-bound-closure.rs:101:29 + | +101 | with_signature(cell, t, |cell, t| require(cell, t)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: defining type: DefId(0/1:42 ~ projection_two_region_trait_bound_closure[317d]::elements_outlive2[0]::{{closure}}[0]) with closure substs [ + '_#1r, + '_#2r, + '_#3r, + T, + i32, + extern "rust-call" fn((std::cell::Cell<&'_#4r ()>, T)) + ] + = note: number of external vids: 5 + = note: where >::AssocType: '_#4r + note: No external requirements --> $DIR/projection-two-region-trait-bound-closure.rs:96:1 | @@ -270,6 +224,21 @@ note: No external requirements T ] +note: External requirements + --> $DIR/projection-two-region-trait-bound-closure.rs:109:29 + | +109 | with_signature(cell, t, |cell, t| require(cell, t)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: defining type: DefId(0/1:46 ~ projection_two_region_trait_bound_closure[317d]::two_regions[0]::{{closure}}[0]) with closure substs [ + '_#1r, + T, + i32, + extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)) + ] + = note: number of external vids: 3 + = note: where >::AssocType: '_#2r + error: free region `ReEarlyBound(0, 'b)` does not outlive free region `ReFree(DefId(0/0:13 ~ projection_two_region_trait_bound_closure[317d]::two_regions[0]), BrNamed(crate0:DefIndex(1:43), 'a))` --> $DIR/projection-two-region-trait-bound-closure.rs:109:20 | @@ -293,6 +262,22 @@ note: No external requirements T ] +note: External requirements + --> $DIR/projection-two-region-trait-bound-closure.rs:120:29 + | +120 | with_signature(cell, t, |cell, t| require(cell, t)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: defining type: DefId(0/1:50 ~ projection_two_region_trait_bound_closure[317d]::two_regions_outlive[0]::{{closure}}[0]) with closure substs [ + '_#1r, + '_#2r, + T, + i32, + extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)) + ] + = note: number of external vids: 4 + = note: where >::AssocType: '_#3r + note: No external requirements --> $DIR/projection-two-region-trait-bound-closure.rs:115:1 | @@ -311,6 +296,21 @@ note: No external requirements T ] +note: External requirements + --> $DIR/projection-two-region-trait-bound-closure.rs:132:29 + | +132 | with_signature(cell, t, |cell, t| require(cell, t)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: defining type: DefId(0/1:53 ~ projection_two_region_trait_bound_closure[317d]::one_region[0]::{{closure}}[0]) with closure substs [ + '_#1r, + T, + i32, + extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)) + ] + = note: number of external vids: 3 + = note: where >::AssocType: '_#2r + note: No external requirements --> $DIR/projection-two-region-trait-bound-closure.rs:124:1 | diff --git a/src/test/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr b/src/test/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr index 023b58c927d86..f68a76c3d0de5 100644 --- a/src/test/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr +++ b/src/test/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr @@ -30,20 +30,6 @@ note: External requirements = note: number of external vids: 2 = note: where T: '_#1r -note: External requirements - --> $DIR/ty-param-closure-approximate-lower-bound.rs:43:24 - | -43 | twice(cell, value, |a, b| invoke(a, b)); - | ^^^^^^^^^^^^^^^^^^^ - | - = note: defining type: DefId(0/1:17 ~ ty_param_closure_approximate_lower_bound[317d]::generic_fail[0]::{{closure}}[0]) with closure substs [ - T, - i16, - for<'r, 's> extern "rust-call" fn((std::option::Option>, &ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 's)) T)) - ] - = note: number of external vids: 2 - = note: where T: '_#1r - note: No external requirements --> $DIR/ty-param-closure-approximate-lower-bound.rs:33:1 | @@ -60,6 +46,20 @@ note: No external requirements T ] +note: External requirements + --> $DIR/ty-param-closure-approximate-lower-bound.rs:43:24 + | +43 | twice(cell, value, |a, b| invoke(a, b)); + | ^^^^^^^^^^^^^^^^^^^ + | + = note: defining type: DefId(0/1:17 ~ ty_param_closure_approximate_lower_bound[317d]::generic_fail[0]::{{closure}}[0]) with closure substs [ + T, + i16, + for<'r, 's> extern "rust-call" fn((std::option::Option>, &ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 's)) T)) + ] + = note: number of external vids: 2 + = note: where T: '_#1r + error[E0309]: the parameter type `T` may not live long enough --> $DIR/ty-param-closure-approximate-lower-bound.rs:43:24 | diff --git a/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-where-clause.stderr b/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-where-clause.stderr index 2dd13810ae48a..ed4d4b1e68f7f 100644 --- a/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-where-clause.stderr +++ b/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-where-clause.stderr @@ -31,69 +31,6 @@ note: External requirements = note: number of external vids: 2 = note: where T: '_#1r -note: External requirements - --> $DIR/ty-param-closure-outlives-from-where-clause.rs:55:26 - | -55 | with_signature(a, b, |x, y| { - | __________________________^ -56 | | // Key point of this test: -57 | | // -58 | | // The *closure* is being type-checked with all of its free -... | -67 | | require(&x, &y) -68 | | }) - | |_____^ - | - = note: defining type: DefId(0/1:19 ~ ty_param_closure_outlives_from_where_clause[317d]::correct_region[0]::{{closure}}[0]) with closure substs [ - '_#1r, - T, - i32, - extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)) - ] - = note: number of external vids: 3 - = note: where T: '_#2r - -note: External requirements - --> $DIR/ty-param-closure-outlives-from-where-clause.rs:76:26 - | -76 | with_signature(a, b, |x, y| { - | __________________________^ -77 | | //~^ ERROR the parameter type `T` may not live long enough -78 | | // See `correct_region` -79 | | require(&x, &y) -80 | | //~^ WARNING not reporting region error due to -Znll -81 | | }) - | |_____^ - | - = note: defining type: DefId(0/1:23 ~ ty_param_closure_outlives_from_where_clause[317d]::wrong_region[0]::{{closure}}[0]) with closure substs [ - '_#1r, - T, - i32, - extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)) - ] - = note: number of external vids: 3 - = note: where T: '_#2r - -note: External requirements - --> $DIR/ty-param-closure-outlives-from-where-clause.rs:90:26 - | -90 | with_signature(a, b, |x, y| { - | __________________________^ -91 | | // See `correct_region` -92 | | require(&x, &y) -93 | | }) - | |_____^ - | - = note: defining type: DefId(0/1:27 ~ ty_param_closure_outlives_from_where_clause[317d]::outlives_region[0]::{{closure}}[0]) with closure substs [ - '_#1r, - '_#2r, - T, - i32, - extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)) - ] - = note: number of external vids: 4 - = note: where T: '_#3r - error[E0309]: the parameter type `T` may not live long enough --> $DIR/ty-param-closure-outlives-from-where-clause.rs:38:26 | @@ -125,6 +62,28 @@ note: No external requirements T ] +note: External requirements + --> $DIR/ty-param-closure-outlives-from-where-clause.rs:55:26 + | +55 | with_signature(a, b, |x, y| { + | __________________________^ +56 | | // Key point of this test: +57 | | // +58 | | // The *closure* is being type-checked with all of its free +... | +67 | | require(&x, &y) +68 | | }) + | |_____^ + | + = note: defining type: DefId(0/1:19 ~ ty_param_closure_outlives_from_where_clause[317d]::correct_region[0]::{{closure}}[0]) with closure substs [ + '_#1r, + T, + i32, + extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)) + ] + = note: number of external vids: 3 + = note: where T: '_#2r + note: No external requirements --> $DIR/ty-param-closure-outlives-from-where-clause.rs:51:1 | @@ -142,6 +101,27 @@ note: No external requirements T ] +note: External requirements + --> $DIR/ty-param-closure-outlives-from-where-clause.rs:76:26 + | +76 | with_signature(a, b, |x, y| { + | __________________________^ +77 | | //~^ ERROR the parameter type `T` may not live long enough +78 | | // See `correct_region` +79 | | require(&x, &y) +80 | | //~^ WARNING not reporting region error due to -Znll +81 | | }) + | |_____^ + | + = note: defining type: DefId(0/1:23 ~ ty_param_closure_outlives_from_where_clause[317d]::wrong_region[0]::{{closure}}[0]) with closure substs [ + '_#1r, + T, + i32, + extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)) + ] + = note: number of external vids: 3 + = note: where T: '_#2r + error[E0309]: the parameter type `T` may not live long enough --> $DIR/ty-param-closure-outlives-from-where-clause.rs:76:26 | @@ -173,6 +153,26 @@ note: No external requirements T ] +note: External requirements + --> $DIR/ty-param-closure-outlives-from-where-clause.rs:90:26 + | +90 | with_signature(a, b, |x, y| { + | __________________________^ +91 | | // See `correct_region` +92 | | require(&x, &y) +93 | | }) + | |_____^ + | + = note: defining type: DefId(0/1:27 ~ ty_param_closure_outlives_from_where_clause[317d]::outlives_region[0]::{{closure}}[0]) with closure substs [ + '_#1r, + '_#2r, + T, + i32, + extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)) + ] + = note: number of external vids: 4 + = note: where T: '_#3r + note: No external requirements --> $DIR/ty-param-closure-outlives-from-where-clause.rs:85:1 | From bcd996857e42a383c79ea9ae84994d3ad932ac4a Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 23 Feb 2018 10:42:12 -0500 Subject: [PATCH 34/34] explain why we don't need to run type-checker when NLL is enabled --- src/librustc_mir/borrow_check/nll/type_check/mod.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs index eafb12fab9645..d57b8e78f18a9 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -1585,6 +1585,8 @@ impl MirPass for TypeckMir { let id = tcx.hir.as_local_node_id(def_id).unwrap(); debug!("run_pass: {:?}", def_id); + // When NLL is enabled, the borrow checker runs the typeck + // itself, so we don't need this MIR pass anymore. if tcx.sess.nll() { return; }