From 48fff6f9ada2de37ad05db1084641323e7085d7d Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 9 Oct 2019 08:50:39 -0400 Subject: [PATCH 01/27] don't assume we can *always* find a return type hint in async fn In particular, we sometimes cannot if there is an earlier error. --- src/librustc_typeck/check/closure.rs | 15 ++++++++++++--- src/test/ui/async-await/issues/issue-65159.rs | 10 ++++++++++ src/test/ui/async-await/issues/issue-65159.stderr | 9 +++++++++ 3 files changed, 31 insertions(+), 3 deletions(-) create mode 100644 src/test/ui/async-await/issues/issue-65159.rs create mode 100644 src/test/ui/async-await/issues/issue-65159.stderr diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index 8b97bf643e9bb..4f4133954cf1d 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -611,6 +611,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Some(hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Fn)) => { debug!("supplied_sig_of_closure: closure is async fn body"); self.deduce_future_output_from_obligations(expr_def_id) + .unwrap_or_else(|| { + // AFAIK, deducing the future output + // always succeeds *except* in error cases + // like #65159. I'd like to return Error + // here, but I can't because I can't + // easily (and locally) prove that we + // *have* reported an + // error. --nikomatsakis + astconv.ty_infer(None, decl.output.span()) + }) } _ => astconv.ty_infer(None, decl.output.span()), @@ -645,7 +655,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn deduce_future_output_from_obligations( &self, expr_def_id: DefId, - ) -> Ty<'tcx> { + ) -> Option> { debug!("deduce_future_output_from_obligations(expr_def_id={:?})", expr_def_id); let ret_coercion = @@ -688,8 +698,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } else { None } - }) - .unwrap(); + }); debug!("deduce_future_output_from_obligations: output_ty={:?}", output_ty); output_ty diff --git a/src/test/ui/async-await/issues/issue-65159.rs b/src/test/ui/async-await/issues/issue-65159.rs new file mode 100644 index 0000000000000..b5fee061f277e --- /dev/null +++ b/src/test/ui/async-await/issues/issue-65159.rs @@ -0,0 +1,10 @@ +// Regression test for #65159. We used to ICE. +// +// edition:2018 + +async fn copy() -> Result<()> //~ ERROR wrong number of type arguments +{ + Ok(()) +} + +fn main() { } diff --git a/src/test/ui/async-await/issues/issue-65159.stderr b/src/test/ui/async-await/issues/issue-65159.stderr new file mode 100644 index 0000000000000..56d2c38b302e9 --- /dev/null +++ b/src/test/ui/async-await/issues/issue-65159.stderr @@ -0,0 +1,9 @@ +error[E0107]: wrong number of type arguments: expected 2, found 1 + --> $DIR/issue-65159.rs:5:20 + | +LL | async fn copy() -> Result<()> + | ^^^^^^^^^^ expected 2 type arguments + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0107`. From 429fc9d7b714feebeb78893f9b92b7bdab3b8b93 Mon Sep 17 00:00:00 2001 From: Igor Matuszewski Date: Sun, 13 Oct 2019 00:18:19 +0200 Subject: [PATCH 02/27] Test an assoc. type in struct member def inside fn --- src/test/ui/save-analysis/issue-64659.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 src/test/ui/save-analysis/issue-64659.rs diff --git a/src/test/ui/save-analysis/issue-64659.rs b/src/test/ui/save-analysis/issue-64659.rs new file mode 100644 index 0000000000000..a3d88a203778f --- /dev/null +++ b/src/test/ui/save-analysis/issue-64659.rs @@ -0,0 +1,10 @@ +// check-pass +// compile-flags: -Zsave-analysis + +trait Trait { type Assoc; } + +fn main() { + struct Data { + x: T::Assoc, + } +} From 7b3cd1b674eb7aa7da8fe00192404e4c9f254ad8 Mon Sep 17 00:00:00 2001 From: Igor Matuszewski Date: Sat, 5 Oct 2019 01:25:20 +0200 Subject: [PATCH 03/27] Use empty typeck tables when nesting on items without those --- src/librustc_save_analysis/dump_visitor.rs | 18 ++++++++++-------- src/librustc_save_analysis/lib.rs | 4 ++++ 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index edd2db3c8f738..2f2b8fee27d2d 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -115,15 +115,17 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> { F: FnOnce(&mut Self), { let item_def_id = self.tcx.hir().local_def_id_from_node_id(item_id); - if self.tcx.has_typeck_tables(item_def_id) { - let tables = self.tcx.typeck_tables_of(item_def_id); - let old_tables = self.save_ctxt.tables; - self.save_ctxt.tables = tables; - f(self); - self.save_ctxt.tables = old_tables; + + let tables = if self.tcx.has_typeck_tables(item_def_id) { + self.tcx.typeck_tables_of(item_def_id) } else { - f(self); - } + self.save_ctxt.empty_tables + }; + + let old_tables = self.save_ctxt.tables; + self.save_ctxt.tables = tables; + f(self); + self.save_ctxt.tables = old_tables; } fn span_from_span(&self, span: Span) -> SpanData { diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index 70b508d478697..1cfb84bb511e4 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -48,6 +48,9 @@ use log::{debug, error, info}; pub struct SaveContext<'l, 'tcx> { tcx: TyCtxt<'tcx>, tables: &'l ty::TypeckTables<'tcx>, + /// Used as a fallback when nesting the typeck tables during item processing + /// (if these are not available for that item, e.g. don't own a body) + empty_tables: &'l ty::TypeckTables<'tcx>, access_levels: &'l AccessLevels, span_utils: SpanUtils<'tcx>, config: Config, @@ -1114,6 +1117,7 @@ pub fn process_crate<'l, 'tcx, H: SaveHandler>( let save_ctxt = SaveContext { tcx, tables: &ty::TypeckTables::empty(None), + empty_tables: &ty::TypeckTables::empty(None), access_levels: &access_levels, span_utils: SpanUtils::new(&tcx.sess), config: find_config(config), From eefc1697c5d3ba52c2af46994ed158e4457171b8 Mon Sep 17 00:00:00 2001 From: Igor Matuszewski Date: Sun, 13 Oct 2019 01:45:48 +0200 Subject: [PATCH 04/27] Nest typeck tables when processing struct member types --- src/librustc_save_analysis/dump_visitor.rs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index 2f2b8fee27d2d..502ae337b5276 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -532,12 +532,14 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> { ); } - for field in def.fields() { - self.process_struct_field_def(field, item.id); - self.visit_ty(&field.ty); - } + self.nest_tables(item.id, |v| { + for field in def.fields() { + v.process_struct_field_def(field, item.id); + v.visit_ty(&field.ty); + } - self.process_generic_params(ty_params, &qualname, item.id); + v.process_generic_params(ty_params, &qualname, item.id); + }); } fn process_enum( From 6a64e9ca49d2160df75437996bb7ac6574299d14 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 11 Oct 2019 14:38:24 +0200 Subject: [PATCH 05/27] Add long error explanation for E0574 --- src/librustc_resolve/error_codes.rs | 51 ++++++++++++++++++++++++++++- 1 file changed, 50 insertions(+), 1 deletion(-) diff --git a/src/librustc_resolve/error_codes.rs b/src/librustc_resolve/error_codes.rs index 47346774180fe..1e65cbada069d 100644 --- a/src/librustc_resolve/error_codes.rs +++ b/src/librustc_resolve/error_codes.rs @@ -1611,6 +1611,56 @@ fn print_on_failure(state: &State) { ``` "##, +E0574: r##" +Something other than a struct, variant or union has been used when one was +expected. + +Erroneous code example: + +```compile_fail,E0574 +mod Mordor {} + +let sauron = Mordor { x: () }; // error! + +enum Jak { + Daxter { i: isize }, +} + +let eco = Jak::Daxter { i: 1 }; +match eco { + Jak { i } => {} // error! +} +``` + +In all these errors, a type was expected. For example, in the first error, +we tried to instantiate the `Mordor` module, which is impossible. If you want +to instantiate a type inside a module, you can do it as follow: + +``` +mod Mordor { + pub struct TheRing { + pub x: usize, + } +} + +let sauron = Mordor::TheRing { x: 1 }; // ok! +``` + +In the second error, we tried to bind the `Jak` enum directly, which is not +possible: you can only bind one of its variants. To do so: + +``` +enum Jak { + Daxter { i: isize }, +} + +let eco = Jak::Daxter { i: 1 }; +match eco { + Jak::Daxter { i } => {} // ok! +} +``` +"##, + E0603: r##" A private item was used outside its scope. @@ -1739,7 +1789,6 @@ struct Foo> { // E0467, removed // E0470, removed E0573, - E0574, E0575, E0576, E0577, From 9f392c43dc62ab3f229fcb274393eee4e93fa630 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 11 Oct 2019 15:23:18 +0200 Subject: [PATCH 06/27] Update ui tests --- src/test/ui/issues/issue-17001.stderr | 1 + src/test/ui/issues/issue-17405.stderr | 1 + src/test/ui/issues/issue-21449.stderr | 1 + src/test/ui/issues/issue-23189.stderr | 1 + src/test/ui/issues/issue-26459.stderr | 1 + src/test/ui/issues/issue-27815.stderr | 1 + src/test/ui/lexical-scopes.stderr | 3 ++- src/test/ui/resolve/issue-16058.stderr | 1 + src/test/ui/traits/trait-as-struct-constructor.stderr | 1 + src/test/ui/try-block/try-block-in-edition2015.stderr | 1 + src/test/ui/use/issue-18986.stderr | 1 + 11 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/test/ui/issues/issue-17001.stderr b/src/test/ui/issues/issue-17001.stderr index 2374e829556ec..d7e6069977b4e 100644 --- a/src/test/ui/issues/issue-17001.stderr +++ b/src/test/ui/issues/issue-17001.stderr @@ -6,3 +6,4 @@ LL | let p = foo { x: () }; error: aborting due to previous error +For more information about this error, try `rustc --explain E0574`. diff --git a/src/test/ui/issues/issue-17405.stderr b/src/test/ui/issues/issue-17405.stderr index 4b5678a88773b..37274e239ba0b 100644 --- a/src/test/ui/issues/issue-17405.stderr +++ b/src/test/ui/issues/issue-17405.stderr @@ -6,3 +6,4 @@ LL | Foo { i } => () error: aborting due to previous error +For more information about this error, try `rustc --explain E0574`. diff --git a/src/test/ui/issues/issue-21449.stderr b/src/test/ui/issues/issue-21449.stderr index 21de1ea091568..ecaf6faba429e 100644 --- a/src/test/ui/issues/issue-21449.stderr +++ b/src/test/ui/issues/issue-21449.stderr @@ -6,3 +6,4 @@ LL | let myVar = MyMod { T: 0 }; error: aborting due to previous error +For more information about this error, try `rustc --explain E0574`. diff --git a/src/test/ui/issues/issue-23189.stderr b/src/test/ui/issues/issue-23189.stderr index 50c09f17486de..ed065212c560b 100644 --- a/src/test/ui/issues/issue-23189.stderr +++ b/src/test/ui/issues/issue-23189.stderr @@ -6,3 +6,4 @@ LL | let _ = module { x: 0 }; error: aborting due to previous error +For more information about this error, try `rustc --explain E0574`. diff --git a/src/test/ui/issues/issue-26459.stderr b/src/test/ui/issues/issue-26459.stderr index c7909a142bec4..187369263a446 100644 --- a/src/test/ui/issues/issue-26459.stderr +++ b/src/test/ui/issues/issue-26459.stderr @@ -6,3 +6,4 @@ LL | char{ch} => true error: aborting due to previous error +For more information about this error, try `rustc --explain E0574`. diff --git a/src/test/ui/issues/issue-27815.stderr b/src/test/ui/issues/issue-27815.stderr index 1d68e3bf558f3..43f78ccf6395a 100644 --- a/src/test/ui/issues/issue-27815.stderr +++ b/src/test/ui/issues/issue-27815.stderr @@ -24,3 +24,4 @@ LL | u32 { x: 1 } => {} error: aborting due to 4 previous errors +For more information about this error, try `rustc --explain E0574`. diff --git a/src/test/ui/lexical-scopes.stderr b/src/test/ui/lexical-scopes.stderr index e990f705af3f9..38c7393e136a6 100644 --- a/src/test/ui/lexical-scopes.stderr +++ b/src/test/ui/lexical-scopes.stderr @@ -16,4 +16,5 @@ LL | Foo::f(); error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0599`. +Some errors have detailed explanations: E0574, E0599. +For more information about an error, try `rustc --explain E0574`. diff --git a/src/test/ui/resolve/issue-16058.stderr b/src/test/ui/resolve/issue-16058.stderr index 64177ac2a8310..9766f8f1412b6 100644 --- a/src/test/ui/resolve/issue-16058.stderr +++ b/src/test/ui/resolve/issue-16058.stderr @@ -14,3 +14,4 @@ LL | use std::thread::Result; error: aborting due to previous error +For more information about this error, try `rustc --explain E0574`. diff --git a/src/test/ui/traits/trait-as-struct-constructor.stderr b/src/test/ui/traits/trait-as-struct-constructor.stderr index 434dcbc8736aa..e1d54fbf8aa7b 100644 --- a/src/test/ui/traits/trait-as-struct-constructor.stderr +++ b/src/test/ui/traits/trait-as-struct-constructor.stderr @@ -6,3 +6,4 @@ LL | TraitNotAStruct{ value: 0 }; error: aborting due to previous error +For more information about this error, try `rustc --explain E0574`. diff --git a/src/test/ui/try-block/try-block-in-edition2015.stderr b/src/test/ui/try-block/try-block-in-edition2015.stderr index 7034cdce7553d..c94e43131faf0 100644 --- a/src/test/ui/try-block/try-block-in-edition2015.stderr +++ b/src/test/ui/try-block/try-block-in-edition2015.stderr @@ -21,3 +21,4 @@ LL | let try_result: Option<_> = try { error: aborting due to 2 previous errors +For more information about this error, try `rustc --explain E0574`. diff --git a/src/test/ui/use/issue-18986.stderr b/src/test/ui/use/issue-18986.stderr index 14e1bb624033b..6c23178c70011 100644 --- a/src/test/ui/use/issue-18986.stderr +++ b/src/test/ui/use/issue-18986.stderr @@ -6,3 +6,4 @@ LL | Trait { x: 42 } => () error: aborting due to previous error +For more information about this error, try `rustc --explain E0574`. From a9752596d3d377e34f99512eb6bc256512509610 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Sat, 7 Sep 2019 21:22:36 +0100 Subject: [PATCH 07/27] Add more tests for underscore imports --- src/test/ui/underscore-imports/hygiene-2.rs | 33 ++++++++++++++ src/test/ui/underscore-imports/hygiene.rs | 40 +++++++++++++++++ src/test/ui/underscore-imports/hygiene.stderr | 27 +++++++++++ .../ui/underscore-imports/macro-expanded.rs | 45 +++++++++++++++++++ 4 files changed, 145 insertions(+) create mode 100644 src/test/ui/underscore-imports/hygiene-2.rs create mode 100644 src/test/ui/underscore-imports/hygiene.rs create mode 100644 src/test/ui/underscore-imports/hygiene.stderr create mode 100644 src/test/ui/underscore-imports/macro-expanded.rs diff --git a/src/test/ui/underscore-imports/hygiene-2.rs b/src/test/ui/underscore-imports/hygiene-2.rs new file mode 100644 index 0000000000000..bea61eae6b51a --- /dev/null +++ b/src/test/ui/underscore-imports/hygiene-2.rs @@ -0,0 +1,33 @@ +// Make sure that underscore imports with different contexts can exist in the +// same scope. + +// check-pass + +#![feature(decl_macro)] + +mod x { + pub use std::ops::Deref as _; +} + +macro n() { + pub use crate::x::*; +} + +#[macro_export] +macro_rules! p { + () => { pub use crate::x::*; } +} + +macro m($y:ident) { + mod $y { + crate::n!(); // Reexport of `Deref` should not be imported in `main` + crate::p!(); // Reexport of `Deref` should be imported into `main` + } +} + +m!(y); + +fn main() { + use crate::y::*; + (&()).deref(); +} diff --git a/src/test/ui/underscore-imports/hygiene.rs b/src/test/ui/underscore-imports/hygiene.rs new file mode 100644 index 0000000000000..a254f6eaa5980 --- /dev/null +++ b/src/test/ui/underscore-imports/hygiene.rs @@ -0,0 +1,40 @@ +// Make sure that underscore imports have the same hygiene considerations as +// other imports. + +#![feature(decl_macro)] + +mod x { + pub use std::ops::Deref as _; +} + + +macro glob_import() { + pub use crate::x::*; +} + +macro underscore_import() { + use std::ops::DerefMut as _; +} + +mod y { + crate::glob_import!(); + crate::underscore_import!(); +} + +macro create_module($y:ident) { + mod $y { + crate::glob_import!(); + crate::underscore_import!(); + } +} + +create_module!(z); + +fn main() { + use crate::y::*; + use crate::z::*; + glob_import!(); + underscore_import!(); + (&()).deref(); //~ ERROR no method named `deref` + (&mut ()).deref_mut(); //~ ERROR no method named `deref_mut` +} diff --git a/src/test/ui/underscore-imports/hygiene.stderr b/src/test/ui/underscore-imports/hygiene.stderr new file mode 100644 index 0000000000000..44cfc5cc5d22e --- /dev/null +++ b/src/test/ui/underscore-imports/hygiene.stderr @@ -0,0 +1,27 @@ +error[E0599]: no method named `deref` found for type `&()` in the current scope + --> $DIR/hygiene.rs:38:11 + | +LL | (&()).deref(); + | ^^^^^ method not found in `&()` + | + = help: items from traits can only be used if the trait is in scope +help: the following trait is implemented but not in scope; perhaps add a `use` for it: + | +LL | use std::ops::Deref; + | + +error[E0599]: no method named `deref_mut` found for type `&mut ()` in the current scope + --> $DIR/hygiene.rs:39:15 + | +LL | (&mut ()).deref_mut(); + | ^^^^^^^^^ method not found in `&mut ()` + | + = help: items from traits can only be used if the trait is in scope +help: the following trait is implemented but not in scope; perhaps add a `use` for it: + | +LL | use std::ops::DerefMut; + | + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0599`. diff --git a/src/test/ui/underscore-imports/macro-expanded.rs b/src/test/ui/underscore-imports/macro-expanded.rs new file mode 100644 index 0000000000000..43f527bc9a408 --- /dev/null +++ b/src/test/ui/underscore-imports/macro-expanded.rs @@ -0,0 +1,45 @@ +// Check that macro expanded underscore imports behave as expected + +// check-pass + +#![feature(decl_macro, rustc_attrs)] + +mod x { + pub use std::ops::Not as _; +} + +macro m() { + mod w { + mod y { + pub use std::ops::Deref as _; + } + use crate::x::*; + use self::y::*; + use std::ops::DerefMut as _; + fn f() { + false.not(); + (&()).deref(); + (&mut ()).deref_mut(); + } + } +} + +#[rustc_macro_transparency = "transparent"] +macro n() { + mod z { + pub use std::ops::Deref as _; + } + use crate::x::*; + use crate::z::*; + use std::ops::DerefMut as _; + fn f() { + false.not(); + (&()).deref(); + (&mut ()).deref_mut(); + } +} + +m!(); +n!(); + +fn main() {} From 061b906683eccd01b59f848a7941f3fd7aff8b00 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Sun, 13 Oct 2019 12:27:11 -0700 Subject: [PATCH 08/27] Return `false` from `needs_drop` for all zero-sized arrays --- src/librustc/ty/util.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index 5ddf15317a31c..b6e8b8b92e6c6 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -1096,6 +1096,9 @@ fn needs_drop_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx> ty::UnnormalizedProjection(..) => bug!("only used with chalk-engine"), + // Zero-length arrays never contain anything to drop. + ty::Array(_, len) if len.try_eval_usize(tcx, param_env) == Some(0) => false, + // Structural recursion. ty::Array(ty, _) | ty::Slice(ty) => needs_drop(ty), From 8fd16baa57aafd4959bda052dad261da997e6862 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Sun, 13 Oct 2019 12:27:45 -0700 Subject: [PATCH 09/27] Remove special case for zero-sized arrays from indirectly mut locals --- .../dataflow/impls/indirect_mutation.rs | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/src/librustc_mir/dataflow/impls/indirect_mutation.rs b/src/librustc_mir/dataflow/impls/indirect_mutation.rs index 990425c3252e0..bc09e32717926 100644 --- a/src/librustc_mir/dataflow/impls/indirect_mutation.rs +++ b/src/librustc_mir/dataflow/impls/indirect_mutation.rs @@ -104,25 +104,16 @@ impl<'tcx> TransferFunction<'_, '_, 'tcx> { kind: mir::BorrowKind, borrowed_place: &mir::Place<'tcx>, ) -> bool { - let borrowed_ty = borrowed_place.ty(self.body, self.tcx).ty; - - // Zero-sized types cannot be mutated, since there is nothing inside to mutate. - // - // FIXME: For now, we only exempt arrays of length zero. We need to carefully - // consider the effects before extending this to all ZSTs. - if let ty::Array(_, len) = borrowed_ty.kind { - if len.try_eval_usize(self.tcx, self.param_env) == Some(0) { - return false; - } - } - match kind { mir::BorrowKind::Mut { .. } => true, | mir::BorrowKind::Shared | mir::BorrowKind::Shallow | mir::BorrowKind::Unique - => !borrowed_ty.is_freeze(self.tcx, self.param_env, DUMMY_SP), + => !borrowed_place + .ty(self.body, self.tcx) + .ty + .is_freeze(self.tcx, self.param_env, DUMMY_SP), } } } From c08a8713381ed67caea826a793145240cd873081 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Sun, 13 Oct 2019 16:00:49 -0700 Subject: [PATCH 10/27] Add regression test for #65348 --- src/test/ui/consts/issue-65348.rs | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 src/test/ui/consts/issue-65348.rs diff --git a/src/test/ui/consts/issue-65348.rs b/src/test/ui/consts/issue-65348.rs new file mode 100644 index 0000000000000..5eafa831d6317 --- /dev/null +++ b/src/test/ui/consts/issue-65348.rs @@ -0,0 +1,23 @@ +// check-pass + +struct Generic(T); + +impl Generic { + const ARRAY: [T; 0] = []; + const NEWTYPE_ARRAY: Generic<[T; 0]> = Generic([]); + const ARRAY_FIELD: Generic<(i32, [T; 0])> = Generic((0, [])); +} + +pub const fn array() -> &'static T { + &Generic::::ARRAY[0] +} + +pub const fn newtype_array() -> &'static T { + &Generic::::NEWTYPE_ARRAY.0[0] +} + +pub const fn array_field() -> &'static T { + &(Generic::::ARRAY_FIELD.0).1[0] +} + +fn main() {} From f81b1548ddf886449d8ea95f82b56274b60fbac7 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Mon, 14 Oct 2019 10:34:21 +0200 Subject: [PATCH 11/27] Add troubleshooting section to PGO chapter in rustc book. --- src/doc/rustc/src/profile-guided-optimization.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/doc/rustc/src/profile-guided-optimization.md b/src/doc/rustc/src/profile-guided-optimization.md index 38be07a6440da..d066f4a9cf59c 100644 --- a/src/doc/rustc/src/profile-guided-optimization.md +++ b/src/doc/rustc/src/profile-guided-optimization.md @@ -125,6 +125,17 @@ RUSTFLAGS="-Cprofile-use=/tmp/pgo-data/merged.profdata" \ cargo build --release --target=x86_64-unknown-linux-gnu ``` +### Troubleshooting + +- It is recommended to pass `-Cllvm-args=-pgo-warn-missing-function` during the + `-Cprofile-use` phase. LLVM by default does not warn if it cannot find + profiling data for a given function. Enabling this warning will make it + easier to spot errors in your setup. + +- There is a [known issue](https://github.com/rust-lang/cargo/issues/7416) in + Cargo prior to version 1.39 that will prevent PGO from working correctly. Be + sure to use Cargo 1.39 or newer when doing PGO. + ## Further Reading `rustc`'s PGO support relies entirely on LLVM's implementation of the feature From 307a3569c5025e72e3020a393689d10a6f5e2109 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 10 Oct 2019 10:29:03 +0200 Subject: [PATCH 12/27] Sort long error code explanation by error code --- src/librustc_mir/error_codes.rs | 406 ++++++++++++++++---------------- 1 file changed, 203 insertions(+), 203 deletions(-) diff --git a/src/librustc_mir/error_codes.rs b/src/librustc_mir/error_codes.rs index 77853ff1fe80a..b2d7bc6a30661 100644 --- a/src/librustc_mir/error_codes.rs +++ b/src/librustc_mir/error_codes.rs @@ -208,6 +208,124 @@ match x { ``` "##, +E0010: r##" +The value of statics and constants must be known at compile time, and they live +for the entire lifetime of a program. Creating a boxed value allocates memory on +the heap at runtime, and therefore cannot be done at compile time. Erroneous +code example: + +```compile_fail,E0010 +#![feature(box_syntax)] + +const CON : Box = box 0; +``` +"##, + +E0013: r##" +Static and const variables can refer to other const variables. But a const +variable cannot refer to a static variable. For example, `Y` cannot refer to +`X` here: + +```compile_fail,E0013 +static X: i32 = 42; +const Y: i32 = X; +``` + +To fix this, the value can be extracted as a const and then used: + +``` +const A: i32 = 42; +static X: i32 = A; +const Y: i32 = A; +``` +"##, + +// FIXME(#57563) Change the language here when const fn stabilizes +E0015: r##" +The only functions that can be called in static or constant expressions are +`const` functions, and struct/enum constructors. `const` functions are only +available on a nightly compiler. Rust currently does not support more general +compile-time function execution. + +``` +const FOO: Option = Some(1); // enum constructor +struct Bar {x: u8} +const BAR: Bar = Bar {x: 1}; // struct constructor +``` + +See [RFC 911] for more details on the design of `const fn`s. + +[RFC 911]: https://github.com/rust-lang/rfcs/blob/master/text/0911-const-fn.md +"##, + +E0017: r##" +References in statics and constants may only refer to immutable values. +Erroneous code example: + +```compile_fail,E0017 +static X: i32 = 1; +const C: i32 = 2; + +// these three are not allowed: +const CR: &mut i32 = &mut C; +static STATIC_REF: &'static mut i32 = &mut X; +static CONST_REF: &'static mut i32 = &mut C; +``` + +Statics are shared everywhere, and if they refer to mutable data one might +violate memory safety since holding multiple mutable references to shared data +is not allowed. + +If you really want global mutable state, try using `static mut` or a global +`UnsafeCell`. +"##, + +E0019: r##" +A function call isn't allowed in the const's initialization expression +because the expression's value must be known at compile-time. Erroneous code +example: + +```compile_fail +enum Test { + V1 +} + +impl Test { + fn test(&self) -> i32 { + 12 + } +} + +fn main() { + const FOO: Test = Test::V1; + + const A: i32 = FOO.test(); // You can't call Test::func() here! +} +``` + +Remember: you can't use a function call inside a const's initialization +expression! However, you can totally use it anywhere else: + +``` +enum Test { + V1 +} + +impl Test { + fn func(&self) -> i32 { + 12 + } +} + +fn main() { + const FOO: Test = Test::V1; + + FOO.func(); // here is good + let x = FOO.func(); // or even here! +} +``` +"##, + E0030: r##" When matching against a range, the compiler verifies that the range is non-empty. Range patterns include both end-points, so this is equivalent to @@ -226,6 +344,40 @@ match 5u32 { ``` "##, +E0133: r##" +Unsafe code was used outside of an unsafe function or block. + +Erroneous code example: + +```compile_fail,E0133 +unsafe fn f() { return; } // This is the unsafe code + +fn main() { + f(); // error: call to unsafe function requires unsafe function or block +} +``` + +Using unsafe functionality is potentially dangerous and disallowed by safety +checks. Examples: + +* Dereferencing raw pointers +* Calling functions via FFI +* Calling functions marked unsafe + +These safety checks can be relaxed for a section of the code by wrapping the +unsafe instructions with an `unsafe` block. For instance: + +``` +unsafe fn f() { return; } + +fn main() { + unsafe { f(); } // ok! +} +``` + +See also https://doc.rust-lang.org/book/ch19-01-unsafe-rust.html +"##, + E0158: r##" `const` and `static` mean different things. A `const` is a compile-time constant, an alias for a literal value. This property means you can match it @@ -247,6 +399,39 @@ match Some(42) { ``` "##, +E0161: r##" +A value was moved. However, its size was not known at compile time, and only +values of a known size can be moved. + +Erroneous code example: + +```compile_fail +#![feature(box_syntax)] + +fn main() { + let array: &[isize] = &[1, 2, 3]; + let _x: Box<[isize]> = box *array; + // error: cannot move a value of type [isize]: the size of [isize] cannot + // be statically determined +} +``` + +In Rust, you can only move a value when its size is known at compile time. + +To work around this restriction, consider "hiding" the value behind a reference: +either `&x` or `&mut x`. Since a reference has a fixed size, this lets you move +it around as usual. Example: + +``` +#![feature(box_syntax)] + +fn main() { + let array: &[isize] = &[1, 2, 3]; + let _x: Box<&[isize]> = box array; // ok! +} +``` +"##, + E0162: r##" #### Note: this error code is no longer emitted by the compiler. @@ -468,158 +653,6 @@ The `op_string_ref` binding has type `&Option<&String>` in both cases. See also https://github.com/rust-lang/rust/issues/14587 "##, -E0010: r##" -The value of statics and constants must be known at compile time, and they live -for the entire lifetime of a program. Creating a boxed value allocates memory on -the heap at runtime, and therefore cannot be done at compile time. Erroneous -code example: - -```compile_fail,E0010 -#![feature(box_syntax)] - -const CON : Box = box 0; -``` -"##, - -E0013: r##" -Static and const variables can refer to other const variables. But a const -variable cannot refer to a static variable. For example, `Y` cannot refer to -`X` here: - -```compile_fail,E0013 -static X: i32 = 42; -const Y: i32 = X; -``` - -To fix this, the value can be extracted as a const and then used: - -``` -const A: i32 = 42; -static X: i32 = A; -const Y: i32 = A; -``` -"##, - -// FIXME(#57563) Change the language here when const fn stabilizes -E0015: r##" -The only functions that can be called in static or constant expressions are -`const` functions, and struct/enum constructors. `const` functions are only -available on a nightly compiler. Rust currently does not support more general -compile-time function execution. - -``` -const FOO: Option = Some(1); // enum constructor -struct Bar {x: u8} -const BAR: Bar = Bar {x: 1}; // struct constructor -``` - -See [RFC 911] for more details on the design of `const fn`s. - -[RFC 911]: https://github.com/rust-lang/rfcs/blob/master/text/0911-const-fn.md -"##, - -E0017: r##" -References in statics and constants may only refer to immutable values. -Erroneous code example: - -```compile_fail,E0017 -static X: i32 = 1; -const C: i32 = 2; - -// these three are not allowed: -const CR: &mut i32 = &mut C; -static STATIC_REF: &'static mut i32 = &mut X; -static CONST_REF: &'static mut i32 = &mut C; -``` - -Statics are shared everywhere, and if they refer to mutable data one might -violate memory safety since holding multiple mutable references to shared data -is not allowed. - -If you really want global mutable state, try using `static mut` or a global -`UnsafeCell`. -"##, - -E0019: r##" -A function call isn't allowed in the const's initialization expression -because the expression's value must be known at compile-time. Erroneous code -example: - -```compile_fail -enum Test { - V1 -} - -impl Test { - fn test(&self) -> i32 { - 12 - } -} - -fn main() { - const FOO: Test = Test::V1; - - const A: i32 = FOO.test(); // You can't call Test::func() here! -} -``` - -Remember: you can't use a function call inside a const's initialization -expression! However, you can totally use it anywhere else: - -``` -enum Test { - V1 -} - -impl Test { - fn func(&self) -> i32 { - 12 - } -} - -fn main() { - const FOO: Test = Test::V1; - - FOO.func(); // here is good - let x = FOO.func(); // or even here! -} -``` -"##, - -E0133: r##" -Unsafe code was used outside of an unsafe function or block. - -Erroneous code example: - -```compile_fail,E0133 -unsafe fn f() { return; } // This is the unsafe code - -fn main() { - f(); // error: call to unsafe function requires unsafe function or block -} -``` - -Using unsafe functionality is potentially dangerous and disallowed by safety -checks. Examples: - -* Dereferencing raw pointers -* Calling functions via FFI -* Calling functions marked unsafe - -These safety checks can be relaxed for a section of the code by wrapping the -unsafe instructions with an `unsafe` block. For instance: - -``` -unsafe fn f() { return; } - -fn main() { - unsafe { f(); } // ok! -} -``` - -See also https://doc.rust-lang.org/book/ch19-01-unsafe-rust.html -"##, - E0373: r##" This error occurs when an attempt is made to use data captured by a closure, when that data may no longer exist. It's most commonly seen when attempting to @@ -1022,39 +1055,6 @@ fn main() { ``` "##, -E0161: r##" -A value was moved. However, its size was not known at compile time, and only -values of a known size can be moved. - -Erroneous code example: - -```compile_fail -#![feature(box_syntax)] - -fn main() { - let array: &[isize] = &[1, 2, 3]; - let _x: Box<[isize]> = box *array; - // error: cannot move a value of type [isize]: the size of [isize] cannot - // be statically determined -} -``` - -In Rust, you can only move a value when its size is known at compile time. - -To work around this restriction, consider "hiding" the value behind a reference: -either `&x` or `&mut x`. Since a reference has a fixed size, this lets you move -it around as usual. Example: - -``` -#![feature(box_syntax)] - -fn main() { - let array: &[isize] = &[1, 2, 3]; - let _x: Box<&[isize]> = box array; // ok! -} -``` -"##, - E0492: r##" A borrow of a constant containing interior mutability was attempted. Erroneous code example: @@ -1982,24 +1982,6 @@ Here executing `x = None` would modify the value being matched and require us to go "back in time" to the `None` arm. "##, -E0579: r##" -When matching against an exclusive range, the compiler verifies that the range -is non-empty. Exclusive range patterns include the start point but not the end -point, so this is equivalent to requiring the start of the range to be less -than the end of the range. - -For example: - -```compile_fail -match 5u32 { - // This range is ok, albeit pointless. - 1 .. 2 => {} - // This range is empty, and the compiler can tell. - 5 .. 5 => {} -} -``` -"##, - E0515: r##" Cannot return value that references local variable @@ -2101,6 +2083,24 @@ fn dragoooon(x: &mut isize) { ``` "##, +E0579: r##" +When matching against an exclusive range, the compiler verifies that the range +is non-empty. Exclusive range patterns include the start point but not the end +point, so this is equivalent to requiring the start of the range to be less +than the end of the range. + +For example: + +```compile_fail +match 5u32 { + // This range is ok, albeit pointless. + 1 .. 2 => {} + // This range is empty, and the compiler can tell. + 5 .. 5 => {} +} +``` +"##, + E0595: r##" #### Note: this error code is no longer emitted by the compiler. From c6de3ebd69acc627d3a8560587e5475f2240ce8a Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 10 Oct 2019 10:33:46 +0200 Subject: [PATCH 13/27] Uncomment E0386 to let users have access to its old definition --- src/librustc_mir/error_codes.rs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/librustc_mir/error_codes.rs b/src/librustc_mir/error_codes.rs index b2d7bc6a30661..93fd00c265bef 100644 --- a/src/librustc_mir/error_codes.rs +++ b/src/librustc_mir/error_codes.rs @@ -875,7 +875,8 @@ x = Foo { a: 2 }; E0384: r##" This error occurs when an attempt is made to reassign an immutable variable. -For example: + +Erroneous code example: ```compile_fail,E0384 fn main() { @@ -895,13 +896,15 @@ fn main() { ``` "##, -/*E0386: r##" +E0386: r##" +#### Note: this error code is no longer emitted by the compiler. + This error occurs when an attempt is made to mutate the target of a mutable reference stored inside an immutable container. For example, this can happen when storing a `&mut` inside an immutable `Box`: -```compile_fail,E0386 +``` let mut x: i64 = 1; let y: Box<_> = Box::new(&mut x); **y = 2; // error, cannot assign to data in an immutable container @@ -925,7 +928,7 @@ let x: i64 = 1; let y: Box> = Box::new(Cell::new(x)); y.set(2); ``` -"##,*/ +"##, E0387: r##" #### Note: this error code is no longer emitted by the compiler. From 65458190c55b06cc8301e6c16b06679677af3945 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 10 Oct 2019 10:53:08 +0200 Subject: [PATCH 14/27] Unification and cleanup of librustc_mir error codes --- src/librustc_mir/error_codes.rs | 142 +++++++++++++++++++++----------- 1 file changed, 92 insertions(+), 50 deletions(-) diff --git a/src/librustc_mir/error_codes.rs b/src/librustc_mir/error_codes.rs index 93fd00c265bef..419c905cb5127 100644 --- a/src/librustc_mir/error_codes.rs +++ b/src/librustc_mir/error_codes.rs @@ -64,7 +64,9 @@ E0004: r##" This error indicates that the compiler cannot guarantee a matching pattern for one or more possible inputs to a match expression. Guaranteed matches are required in order to assign values to match expressions, or alternatively, -determine the flow of execution. Erroneous code example: +determine the flow of execution. + +Erroneous code example: ```compile_fail,E0004 enum Terminator { @@ -109,7 +111,9 @@ match x { E0005: r##" Patterns used to bind names must be irrefutable, that is, they must guarantee -that a name will be extracted in all cases. Erroneous code example: +that a name will be extracted in all cases. + +Erroneous code example: ```compile_fail,E0005 let x = Some(1); @@ -145,6 +149,8 @@ like the following is invalid as it requires the entire `Option` to be moved into a variable called `op_string` while simultaneously requiring the inner `String` to be moved into a variable called `s`. +Erroneous code example: + ```compile_fail,E0007 let x = Some("s".to_string()); @@ -211,8 +217,9 @@ match x { E0010: r##" The value of statics and constants must be known at compile time, and they live for the entire lifetime of a program. Creating a boxed value allocates memory on -the heap at runtime, and therefore cannot be done at compile time. Erroneous -code example: +the heap at runtime, and therefore cannot be done at compile time. + +Erroneous code example: ```compile_fail,E0010 #![feature(box_syntax)] @@ -223,15 +230,17 @@ const CON : Box = box 0; E0013: r##" Static and const variables can refer to other const variables. But a const -variable cannot refer to a static variable. For example, `Y` cannot refer to -`X` here: +variable cannot refer to a static variable. + +Erroneous code example: ```compile_fail,E0013 static X: i32 = 42; const Y: i32 = X; ``` -To fix this, the value can be extracted as a const and then used: +In this example, `Y` cannot refer to `X` here. To fix this, the value can be +extracted as a const and then used: ``` const A: i32 = 42; @@ -260,6 +269,7 @@ See [RFC 911] for more details on the design of `const fn`s. E0017: r##" References in statics and constants may only refer to immutable values. + Erroneous code example: ```compile_fail,E0017 @@ -282,24 +292,17 @@ If you really want global mutable state, try using `static mut` or a global E0019: r##" A function call isn't allowed in the const's initialization expression -because the expression's value must be known at compile-time. Erroneous code -example: +because the expression's value must be known at compile-time. -```compile_fail -enum Test { - V1 -} +Erroneous code example: -impl Test { - fn test(&self) -> i32 { - 12 - } -} +```compile_fail,E0019 +#![feature(box_syntax)] fn main() { - const FOO: Test = Test::V1; + struct MyOwned; - const A: i32 = FOO.test(); // You can't call Test::func() here! + static STATIC11: Box = box MyOwned; // error! } ``` @@ -328,13 +331,13 @@ fn main() { E0030: r##" When matching against a range, the compiler verifies that the range is -non-empty. Range patterns include both end-points, so this is equivalent to +non-empty. Range patterns include both end-points, so this is equivalent to requiring the start of the range to be less than or equal to the end of the range. -For example: +Erroneous code example: -```compile_fail +```compile_fail,E0030 match 5u32 { // This range is ok, albeit pointless. 1 ..= 1 => {} @@ -379,6 +382,26 @@ See also https://doc.rust-lang.org/book/ch19-01-unsafe-rust.html "##, E0158: r##" +An associated const has been referenced in a pattern. + +Erroneous code example: + +```compile_fail,E0158 +enum EFoo { A, B, C, D } + +trait Foo { + const X: EFoo; +} + +fn test(arg: EFoo) { + match arg { + A::X => { // error! + println!("A::X"); + } + } +} +``` + `const` and `static` mean different things. A `const` is a compile-time constant, an alias for a literal value. This property means you can match it directly within a pattern. @@ -405,7 +428,7 @@ values of a known size can be moved. Erroneous code example: -```compile_fail +```compile_fail,E0161 #![feature(box_syntax)] fn main() { @@ -705,7 +728,9 @@ about safety. "##, E0381: r##" -It is not allowed to use or capture an uninitialized variable. For example: +It is not allowed to use or capture an uninitialized variable. + +Erroneous code example: ```compile_fail,E0381 fn main() { @@ -727,7 +752,9 @@ fn main() { E0382: r##" This error occurs when an attempt is made to use a variable after its contents -have been moved elsewhere. For example: +have been moved elsewhere. + +Erroneous code example: ```compile_fail,E0382 struct MyStruct { s: u32 } @@ -934,7 +961,9 @@ E0387: r##" #### Note: this error code is no longer emitted by the compiler. This error occurs when an attempt is made to mutate or mutably reference data -that a closure has captured immutably. Examples of this error are shown below: +that a closure has captured immutably. + +Erroneous code example: ```compile_fail // Accepts a function or a closure that captures its environment immutably. @@ -999,7 +1028,7 @@ An attempt was made to mutate data using a non-mutable reference. This commonly occurs when attempting to assign to a non-mutable reference of a mutable reference (`&(&mut T)`). -Example of erroneous code: +Erroneous code example: ```compile_fail struct FancyNum { @@ -1059,8 +1088,9 @@ fn main() { "##, E0492: r##" -A borrow of a constant containing interior mutability was attempted. Erroneous -code example: +A borrow of a constant containing interior mutability was attempted. + +Erroneous code example: ```compile_fail,E0492 use std::sync::atomic::AtomicUsize; @@ -1177,7 +1207,9 @@ static FOO: Foo = Foo { field1: DropType::A }; // We initialize all fields "##, E0499: r##" -A variable was borrowed as mutable more than once. Erroneous code example: +A variable was borrowed as mutable more than once. + +Erroneous code example: ```compile_fail,E0499 let mut i = 0; @@ -1208,7 +1240,9 @@ a; "##, E0500: r##" -A borrowed variable was used by a closure. Example of erroneous code: +A borrowed variable was used by a closure. + +Erroneous code example: ```compile_fail,E0500 fn you_know_nothing(jon_snow: &mut i32) { @@ -1259,7 +1293,7 @@ situation, the closure is borrowing the variable. Take a look at http://rustbyexample.com/fn/closures/capture.html for more information about capturing. -Example of erroneous code: +Erroneous code example: ```compile_fail,E0501 fn inside_closure(x: &mut i32) { @@ -1332,7 +1366,7 @@ E0502: r##" This error indicates that you are trying to borrow a variable as mutable when it has already been borrowed as immutable. -Example of erroneous code: +Erroneous code example: ```compile_fail,E0502 fn bar(x: &mut i32) {} @@ -1363,7 +1397,7 @@ https://doc.rust-lang.org/book/ch04-02-references-and-borrowing.html. E0503: r##" A value was used after it was mutably borrowed. -Example of erroneous code: +Erroneous code example: ```compile_fail,E0503 fn main() { @@ -1421,7 +1455,7 @@ E0504: r##" This error occurs when an attempt is made to move a borrowed variable into a closure. -Example of erroneous code: +Erroneous code example: ```compile_fail struct FancyNum { @@ -1612,7 +1646,7 @@ http://doc.rust-lang.org/book/ch04-02-references-and-borrowing.html E0506: r##" This error occurs when an attempt is made to assign to a borrowed value. -Example of erroneous code: +Erroneous code example: ```compile_fail,E0506 struct FancyNum { @@ -1830,7 +1864,7 @@ http://doc.rust-lang.org/book/ch04-02-references-and-borrowing.html E0508: r##" A value was moved out of a non-copy fixed-size array. -Example of erroneous code: +Erroneous code example: ```compile_fail,E0508 struct NonCopy; @@ -1875,7 +1909,7 @@ E0509: r##" This error occurs when an attempt is made to move out of a value whose type implements the `Drop` trait. -Example of erroneous code: +Erroneous code example: ```compile_fail,E0509 struct FancyNum { @@ -1991,6 +2025,8 @@ Cannot return value that references local variable Local variables, function parameters and temporaries are all dropped before the end of the function body. So a reference to them cannot be returned. +Erroneous code example: + ```compile_fail,E0515 fn get_dangling_reference() -> &'static i32 { let x = 0; @@ -2092,14 +2128,18 @@ is non-empty. Exclusive range patterns include the start point but not the end point, so this is equivalent to requiring the start of the range to be less than the end of the range. -For example: +Erroneous code example: -```compile_fail -match 5u32 { - // This range is ok, albeit pointless. - 1 .. 2 => {} - // This range is empty, and the compiler can tell. - 5 .. 5 => {} +```compile_fail,E0579 +#![feature(exclusive_range_pattern)] + +fn main() { + match 5u32 { + // This range is ok, albeit pointless. + 1 .. 2 => {} + // This range is empty, and the compiler can tell. + 5 .. 5 => {} // error! + } } ``` "##, @@ -2127,7 +2167,7 @@ let mut c = || { x += 1 }; E0596: r##" This error occurs because you tried to mutably borrow a non-mutable variable. -Example of erroneous code: +Erroneous code example: ```compile_fail,E0596 let x = 1; @@ -2146,7 +2186,7 @@ let y = &mut x; // ok! E0597: r##" This error occurs because a value was dropped while it was still borrowed -Example of erroneous code: +Erroneous code example: ```compile_fail,E0597 struct Foo<'a> { @@ -2183,6 +2223,8 @@ E0626: r##" This error occurs because a borrow in a generator persists across a yield point. +Erroneous code example: + ```compile_fail,E0626 # #![feature(generators, generator_trait, pin)] # use std::ops::Generator; @@ -2274,7 +2316,7 @@ E0712: r##" This error occurs because a borrow of a thread-local variable was made inside a function which outlived the lifetime of the function. -Example of erroneous code: +Erroneous code example: ```compile_fail,E0712 #![feature(thread_local)] @@ -2296,7 +2338,7 @@ E0713: r##" This error occurs when an attempt is made to borrow state past the end of the lifetime of a type that implements the `Drop` trait. -Example of erroneous code: +Erroneous code example: ```compile_fail,E0713 #![feature(nll)] From d4e3e6bc15ece1c017ec7bd1fd892c6a981b2020 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 14 Oct 2019 13:01:12 +0200 Subject: [PATCH 15/27] Delete extra file --- .../feature-gate-exhaustive-patterns.nll.stderr | 16 ---------------- 1 file changed, 16 deletions(-) delete mode 100644 src/test/ui/feature-gates/feature-gate-exhaustive-patterns.nll.stderr diff --git a/src/test/ui/feature-gates/feature-gate-exhaustive-patterns.nll.stderr b/src/test/ui/feature-gates/feature-gate-exhaustive-patterns.nll.stderr deleted file mode 100644 index d77fbc1e8239d..0000000000000 --- a/src/test/ui/feature-gates/feature-gate-exhaustive-patterns.nll.stderr +++ /dev/null @@ -1,16 +0,0 @@ -error[E0005]: refutable pattern in local binding: `Err(_)` not covered - --> $DIR/feature-gate-exhaustive-patterns.rs:7:9 - | -LL | let Ok(_x) = foo(); - | ^^^^^^ pattern `Err(_)` not covered - | - = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant - = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html -help: you might want to use `if let` to ignore the variant that isn't matched - | -LL | if let Ok(_x) = foo() { /* */ } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0005`. From fe09bb518d9dfb270a6f3562b50b96272524b42c Mon Sep 17 00:00:00 2001 From: Tyler Mandry Date: Thu, 10 Oct 2019 16:38:05 -0700 Subject: [PATCH 16/27] Add expanded type cache to OpaqueTypeExpander --- src/librustc/ty/util.rs | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index d0e95a18c59fc..35bd42fd74432 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -697,6 +697,9 @@ impl<'tcx> TyCtxt<'tcx> { // that type, and when we finish expanding that type we remove the // its DefId. seen_opaque_tys: FxHashSet, + // Cache of all expansions we've seen so far. This is a critical + // optimization for some large types produced by async fn trees. + expanded_cache: FxHashMap<(DefId, SubstsRef<'tcx>), Ty<'tcx>>, primary_def_id: DefId, found_recursion: bool, tcx: TyCtxt<'tcx>, @@ -713,9 +716,16 @@ impl<'tcx> TyCtxt<'tcx> { } let substs = substs.fold_with(self); if self.seen_opaque_tys.insert(def_id) { - let generic_ty = self.tcx.type_of(def_id); - let concrete_ty = generic_ty.subst(self.tcx, substs); - let expanded_ty = self.fold_ty(concrete_ty); + let expanded_ty = match self.expanded_cache.get(&(def_id, substs)) { + Some(expanded_ty) => expanded_ty, + None => { + let generic_ty = self.tcx.type_of(def_id); + let concrete_ty = generic_ty.subst(self.tcx, substs); + let expanded_ty = self.fold_ty(concrete_ty); + self.expanded_cache.insert((def_id, substs), expanded_ty); + expanded_ty + } + }; self.seen_opaque_tys.remove(&def_id); Some(expanded_ty) } else { @@ -743,6 +753,7 @@ impl<'tcx> TyCtxt<'tcx> { let mut visitor = OpaqueTypeExpander { seen_opaque_tys: FxHashSet::default(), + expanded_cache: FxHashMap::default(), primary_def_id: def_id, found_recursion: false, tcx: self, From 802554f4274f6514cd2f8f618cae567adf18128f Mon Sep 17 00:00:00 2001 From: Tyler Mandry Date: Thu, 10 Oct 2019 16:38:53 -0700 Subject: [PATCH 17/27] Only expand types that contain projections --- src/librustc/ty/util.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index 35bd42fd74432..6a94ca6b8c75c 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -745,8 +745,10 @@ impl<'tcx> TyCtxt<'tcx> { fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { if let ty::Opaque(def_id, substs) = t.kind { self.expand_opaque_ty(def_id, substs).unwrap_or(t) - } else { + } else if t.has_projections() { t.super_fold_with(self) + } else { + t } } } From 53187c5753e09006f0e03799ab01d7cb7ec676c7 Mon Sep 17 00:00:00 2001 From: phosphorus Date: Fri, 11 Oct 2019 20:16:09 +0800 Subject: [PATCH 18/27] Slides path lifetime to the lifetime resolver add test to for the fix add descriptive text for the fix simplified code logics update descriptive comments update to cope with the tidyness requirement merged commit suggestions Co-Authored-By: varkor truncated redundant comments update to cope with tidy-check --- src/librustc/hir/lowering.rs | 12 +++++++---- ...incorrect-explicit-lifetime-name-needed.rs | 14 +++++++++++++ ...rrect-explicit-lifetime-name-needed.stderr | 21 +++++++++++++++++++ 3 files changed, 43 insertions(+), 4 deletions(-) create mode 100644 src/test/ui/generics/issue-65285-incorrect-explicit-lifetime-name-needed.rs create mode 100644 src/test/ui/generics/issue-65285-incorrect-explicit-lifetime-name-needed.stderr diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 72fd054ee8a20..ecf16d9443055 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -3281,10 +3281,14 @@ impl<'a> LoweringContext<'a> { let id = self.sess.next_node_id(); self.new_named_lifetime(id, span, hir::LifetimeName::Error) } - // This is the normal case. - AnonymousLifetimeMode::PassThrough => self.new_implicit_lifetime(span), - - AnonymousLifetimeMode::ReportError => self.new_error_lifetime(None, span), + // `PassThrough` is the normal case. + // `new_error_lifetime`, which would usually be used in the case of `ReportError`, + // is unsuitable here, as these can occur from missing lifetime parameters in a + // `PathSegment`, for which there is no associated `'_` or `&T` with no explicit + // lifetime. Instead, we simply create an implicit lifetime, which will be checked + // later, at which point a suitable error will be emitted. + | AnonymousLifetimeMode::PassThrough + | AnonymousLifetimeMode::ReportError => self.new_implicit_lifetime(span), } } diff --git a/src/test/ui/generics/issue-65285-incorrect-explicit-lifetime-name-needed.rs b/src/test/ui/generics/issue-65285-incorrect-explicit-lifetime-name-needed.rs new file mode 100644 index 0000000000000..54b483f53d4cb --- /dev/null +++ b/src/test/ui/generics/issue-65285-incorrect-explicit-lifetime-name-needed.rs @@ -0,0 +1,14 @@ +#![crate_type="lib"] + +struct Nested(K); + +fn should_error() where T : Into<&u32> {} +//~^ ERROR `&` without an explicit lifetime name cannot be used here [E0637] + +trait X<'a, K: 'a> { + fn foo<'b, L: X<&'b Nested>>(); + //~^ ERROR missing lifetime specifier [E0106] +} + +fn bar<'b, L: X<&'b Nested>>(){} +//~^ ERROR missing lifetime specifier [E0106] diff --git a/src/test/ui/generics/issue-65285-incorrect-explicit-lifetime-name-needed.stderr b/src/test/ui/generics/issue-65285-incorrect-explicit-lifetime-name-needed.stderr new file mode 100644 index 0000000000000..8720288b53e58 --- /dev/null +++ b/src/test/ui/generics/issue-65285-incorrect-explicit-lifetime-name-needed.stderr @@ -0,0 +1,21 @@ +error[E0637]: `&` without an explicit lifetime name cannot be used here + --> $DIR/issue-65285-incorrect-explicit-lifetime-name-needed.rs:5:37 + | +LL | fn should_error() where T : Into<&u32> {} + | ^ explicit lifetime name needed here + +error[E0106]: missing lifetime specifier + --> $DIR/issue-65285-incorrect-explicit-lifetime-name-needed.rs:9:19 + | +LL | fn foo<'b, L: X<&'b Nested>>(); + | ^^^^^^^^^^^^^^^^ expected lifetime parameter + +error[E0106]: missing lifetime specifier + --> $DIR/issue-65285-incorrect-explicit-lifetime-name-needed.rs:13:15 + | +LL | fn bar<'b, L: X<&'b Nested>>(){} + | ^^^^^^^^^^^^^^^^^^ expected lifetime parameter + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0106`. From 1fb8cfb4815f99148cd94182accc99866de9a6d8 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Tue, 15 Oct 2019 15:28:42 +0200 Subject: [PATCH 19/27] Organize `never_type` tests Also move {run-fail -> ui}/never_type --- src/test/ui/coercion/coerce-issue-49593-box-never.rs | 2 +- .../ui/feature-gates/feature-gate-exhaustive-patterns.rs | 1 + .../feature-gates/feature-gate-exhaustive-patterns.stderr | 2 +- src/test/ui/for-loop-while/loop-break-value.rs | 1 + src/test/ui/lint/must_use-unit.rs | 1 - src/test/ui/lint/must_use-unit.stderr | 6 +++--- src/test/{run-fail => ui/never_type}/adjust_never.rs | 1 + .../ui/{ => never_type}/call-fn-never-arg-wrong-type.rs | 0 .../ui/{ => never_type}/call-fn-never-arg-wrong-type.stderr | 0 src/test/{run-fail => ui/never_type}/call-fn-never-arg.rs | 1 + src/test/{run-fail => ui/never_type}/cast-never.rs | 1 + src/test/ui/{ => never_type}/defaulted-never-note.rs | 0 src/test/ui/{ => never_type}/defaulted-never-note.stderr | 0 src/test/ui/{ => never_type}/dispatch_from_dyn_zst.rs | 0 .../ui/{ => never_type}/diverging-fallback-control-flow.rs | 1 + src/test/ui/{ => never_type}/impl-for-never.rs | 3 ++- src/test/ui/{issues => never_type}/issue-13352.rs | 0 src/test/ui/{issues => never_type}/issue-13352.stderr | 0 src/test/ui/{issues => never_type}/issue-2149.rs | 0 src/test/ui/{issues => never_type}/issue-2149.stderr | 0 src/test/ui/{issues => never_type}/issue-44402.rs | 3 ++- src/test/ui/{ => never_type}/never-assign-dead-code.rs | 4 ++-- src/test/ui/{ => never_type}/never-assign-dead-code.stderr | 4 ++-- src/test/ui/{ => never_type}/never-assign-wrong-type.rs | 0 src/test/ui/{ => never_type}/never-assign-wrong-type.stderr | 0 .../{run-fail => ui/never_type}/never-associated-type.rs | 1 + src/test/ui/{ => never_type}/never-from-impl-is-reserved.rs | 0 .../ui/{ => never_type}/never-from-impl-is-reserved.stderr | 0 src/test/ui/{ => never_type}/never-result.rs | 1 + src/test/{run-fail => ui/never_type}/never-type-arg.rs | 1 + src/test/ui/{ => never_type}/never-type-rvalues.rs | 0 src/test/ui/{ => never_type}/never_coercions.rs | 0 src/test/ui/{ => never_type}/never_transmute_never.rs | 2 +- src/test/ui/{ => never_type}/panic-uninitialized-zeroed.rs | 0 src/test/ui/{ => never_type}/try_from.rs | 0 .../auxiliary/unreachable_variant.rs | 0 src/test/ui/{unreachable => reachable}/unreachable-arm.rs | 0 .../ui/{unreachable => reachable}/unreachable-arm.stderr | 0 src/test/ui/{unreachable => reachable}/unreachable-code.rs | 0 .../ui/{unreachable => reachable}/unreachable-code.stderr | 0 .../ui/{unreachable => reachable}/unreachable-in-call.rs | 0 .../{unreachable => reachable}/unreachable-in-call.stderr | 0 .../{unreachable => reachable}/unreachable-loop-patterns.rs | 2 -- .../unreachable-loop-patterns.stderr | 6 +++--- .../{unreachable => reachable}/unreachable-try-pattern.rs | 2 +- .../unreachable-try-pattern.stderr | 0 .../ui/{unreachable => reachable}/unreachable-variant.rs | 0 .../{unreachable => reachable}/unreachable-variant.stderr | 0 .../{unreachable => reachable}/unwarned-match-on-never.rs | 0 .../unwarned-match-on-never.stderr | 0 src/test/ui/{ => uninhabited}/always-inhabited-union-ref.rs | 0 .../ui/{ => uninhabited}/always-inhabited-union-ref.stderr | 0 52 files changed, 27 insertions(+), 19 deletions(-) rename src/test/{run-fail => ui/never_type}/adjust_never.rs (93%) rename src/test/ui/{ => never_type}/call-fn-never-arg-wrong-type.rs (100%) rename src/test/ui/{ => never_type}/call-fn-never-arg-wrong-type.stderr (100%) rename src/test/{run-fail => ui/never_type}/call-fn-never-arg.rs (94%) rename src/test/{run-fail => ui/never_type}/cast-never.rs (93%) rename src/test/ui/{ => never_type}/defaulted-never-note.rs (100%) rename src/test/ui/{ => never_type}/defaulted-never-note.stderr (100%) rename src/test/ui/{ => never_type}/dispatch_from_dyn_zst.rs (100%) rename src/test/ui/{ => never_type}/diverging-fallback-control-flow.rs (99%) rename src/test/ui/{ => never_type}/impl-for-never.rs (99%) rename src/test/ui/{issues => never_type}/issue-13352.rs (100%) rename src/test/ui/{issues => never_type}/issue-13352.stderr (100%) rename src/test/ui/{issues => never_type}/issue-2149.rs (100%) rename src/test/ui/{issues => never_type}/issue-2149.stderr (100%) rename src/test/ui/{issues => never_type}/issue-44402.rs (90%) rename src/test/ui/{ => never_type}/never-assign-dead-code.rs (82%) rename src/test/ui/{ => never_type}/never-assign-dead-code.stderr (92%) rename src/test/ui/{ => never_type}/never-assign-wrong-type.rs (100%) rename src/test/ui/{ => never_type}/never-assign-wrong-type.stderr (100%) rename src/test/{run-fail => ui/never_type}/never-associated-type.rs (96%) rename src/test/ui/{ => never_type}/never-from-impl-is-reserved.rs (100%) rename src/test/ui/{ => never_type}/never-from-impl-is-reserved.stderr (100%) rename src/test/ui/{ => never_type}/never-result.rs (99%) rename src/test/{run-fail => ui/never_type}/never-type-arg.rs (95%) rename src/test/ui/{ => never_type}/never-type-rvalues.rs (100%) rename src/test/ui/{ => never_type}/never_coercions.rs (100%) rename src/test/ui/{ => never_type}/never_transmute_never.rs (87%) rename src/test/ui/{ => never_type}/panic-uninitialized-zeroed.rs (100%) rename src/test/ui/{ => never_type}/try_from.rs (100%) rename src/test/ui/{unreachable => reachable}/auxiliary/unreachable_variant.rs (100%) rename src/test/ui/{unreachable => reachable}/unreachable-arm.rs (100%) rename src/test/ui/{unreachable => reachable}/unreachable-arm.stderr (100%) rename src/test/ui/{unreachable => reachable}/unreachable-code.rs (100%) rename src/test/ui/{unreachable => reachable}/unreachable-code.stderr (100%) rename src/test/ui/{unreachable => reachable}/unreachable-in-call.rs (100%) rename src/test/ui/{unreachable => reachable}/unreachable-in-call.stderr (100%) rename src/test/ui/{unreachable => reachable}/unreachable-loop-patterns.rs (95%) rename src/test/ui/{unreachable => reachable}/unreachable-loop-patterns.stderr (73%) rename src/test/ui/{unreachable => reachable}/unreachable-try-pattern.rs (94%) rename src/test/ui/{unreachable => reachable}/unreachable-try-pattern.stderr (100%) rename src/test/ui/{unreachable => reachable}/unreachable-variant.rs (100%) rename src/test/ui/{unreachable => reachable}/unreachable-variant.stderr (100%) rename src/test/ui/{unreachable => reachable}/unwarned-match-on-never.rs (100%) rename src/test/ui/{unreachable => reachable}/unwarned-match-on-never.stderr (100%) rename src/test/ui/{ => uninhabited}/always-inhabited-union-ref.rs (100%) rename src/test/ui/{ => uninhabited}/always-inhabited-union-ref.stderr (100%) diff --git a/src/test/ui/coercion/coerce-issue-49593-box-never.rs b/src/test/ui/coercion/coerce-issue-49593-box-never.rs index f005245e6dcb9..5038eb3ebf458 100644 --- a/src/test/ui/coercion/coerce-issue-49593-box-never.rs +++ b/src/test/ui/coercion/coerce-issue-49593-box-never.rs @@ -1,4 +1,4 @@ -// build-pass (FIXME(62277): could be check-pass?) +// check-pass #![feature(never_type)] #![allow(unreachable_code)] diff --git a/src/test/ui/feature-gates/feature-gate-exhaustive-patterns.rs b/src/test/ui/feature-gates/feature-gate-exhaustive-patterns.rs index 27ff5ace25ddc..f0cc9ea70550e 100644 --- a/src/test/ui/feature-gates/feature-gate-exhaustive-patterns.rs +++ b/src/test/ui/feature-gates/feature-gate-exhaustive-patterns.rs @@ -1,4 +1,5 @@ #![feature(never_type)] + fn foo() -> Result { Ok(123) } diff --git a/src/test/ui/feature-gates/feature-gate-exhaustive-patterns.stderr b/src/test/ui/feature-gates/feature-gate-exhaustive-patterns.stderr index d77fbc1e8239d..08c36cece4cf9 100644 --- a/src/test/ui/feature-gates/feature-gate-exhaustive-patterns.stderr +++ b/src/test/ui/feature-gates/feature-gate-exhaustive-patterns.stderr @@ -1,5 +1,5 @@ error[E0005]: refutable pattern in local binding: `Err(_)` not covered - --> $DIR/feature-gate-exhaustive-patterns.rs:7:9 + --> $DIR/feature-gate-exhaustive-patterns.rs:8:9 | LL | let Ok(_x) = foo(); | ^^^^^^ pattern `Err(_)` not covered diff --git a/src/test/ui/for-loop-while/loop-break-value.rs b/src/test/ui/for-loop-while/loop-break-value.rs index e1edbbb929e6a..d7209fc4de867 100644 --- a/src/test/ui/for-loop-while/loop-break-value.rs +++ b/src/test/ui/for-loop-while/loop-break-value.rs @@ -1,4 +1,5 @@ // run-pass + #![allow(unreachable_code)] #![feature(never_type)] diff --git a/src/test/ui/lint/must_use-unit.rs b/src/test/ui/lint/must_use-unit.rs index 92568252164f6..4dd4798abb7ce 100644 --- a/src/test/ui/lint/must_use-unit.rs +++ b/src/test/ui/lint/must_use-unit.rs @@ -1,5 +1,4 @@ #![feature(never_type)] - #![deny(unused_must_use)] #[must_use] diff --git a/src/test/ui/lint/must_use-unit.stderr b/src/test/ui/lint/must_use-unit.stderr index f6229c0442f99..0a9939b2015b7 100644 --- a/src/test/ui/lint/must_use-unit.stderr +++ b/src/test/ui/lint/must_use-unit.stderr @@ -1,17 +1,17 @@ error: unused return value of `foo` that must be used - --> $DIR/must_use-unit.rs:14:5 + --> $DIR/must_use-unit.rs:13:5 | LL | foo(); | ^^^^^^ | note: lint level defined here - --> $DIR/must_use-unit.rs:3:9 + --> $DIR/must_use-unit.rs:2:9 | LL | #![deny(unused_must_use)] | ^^^^^^^^^^^^^^^ error: unused return value of `bar` that must be used - --> $DIR/must_use-unit.rs:16:5 + --> $DIR/must_use-unit.rs:15:5 | LL | bar(); | ^^^^^^ diff --git a/src/test/run-fail/adjust_never.rs b/src/test/ui/never_type/adjust_never.rs similarity index 93% rename from src/test/run-fail/adjust_never.rs rename to src/test/ui/never_type/adjust_never.rs index 8661a2f80a7ba..3aa5866ebfbeb 100644 --- a/src/test/run-fail/adjust_never.rs +++ b/src/test/ui/never_type/adjust_never.rs @@ -1,5 +1,6 @@ // Test that a variable of type ! can coerce to another type. +// run-fail // error-pattern:explicit #![feature(never_type)] diff --git a/src/test/ui/call-fn-never-arg-wrong-type.rs b/src/test/ui/never_type/call-fn-never-arg-wrong-type.rs similarity index 100% rename from src/test/ui/call-fn-never-arg-wrong-type.rs rename to src/test/ui/never_type/call-fn-never-arg-wrong-type.rs diff --git a/src/test/ui/call-fn-never-arg-wrong-type.stderr b/src/test/ui/never_type/call-fn-never-arg-wrong-type.stderr similarity index 100% rename from src/test/ui/call-fn-never-arg-wrong-type.stderr rename to src/test/ui/never_type/call-fn-never-arg-wrong-type.stderr diff --git a/src/test/run-fail/call-fn-never-arg.rs b/src/test/ui/never_type/call-fn-never-arg.rs similarity index 94% rename from src/test/run-fail/call-fn-never-arg.rs rename to src/test/ui/never_type/call-fn-never-arg.rs index f5b2cfaefe022..6218572f8a756 100644 --- a/src/test/run-fail/call-fn-never-arg.rs +++ b/src/test/ui/never_type/call-fn-never-arg.rs @@ -1,5 +1,6 @@ // Test that we can use a ! for an argument of type ! +// run-fail // error-pattern:wowzers! #![feature(never_type)] diff --git a/src/test/run-fail/cast-never.rs b/src/test/ui/never_type/cast-never.rs similarity index 93% rename from src/test/run-fail/cast-never.rs rename to src/test/ui/never_type/cast-never.rs index 0b05a4b911284..46072e186e0f2 100644 --- a/src/test/run-fail/cast-never.rs +++ b/src/test/ui/never_type/cast-never.rs @@ -1,5 +1,6 @@ // Test that we can explicitly cast ! to another type +// run-fail // error-pattern:explicit #![feature(never_type)] diff --git a/src/test/ui/defaulted-never-note.rs b/src/test/ui/never_type/defaulted-never-note.rs similarity index 100% rename from src/test/ui/defaulted-never-note.rs rename to src/test/ui/never_type/defaulted-never-note.rs diff --git a/src/test/ui/defaulted-never-note.stderr b/src/test/ui/never_type/defaulted-never-note.stderr similarity index 100% rename from src/test/ui/defaulted-never-note.stderr rename to src/test/ui/never_type/defaulted-never-note.stderr diff --git a/src/test/ui/dispatch_from_dyn_zst.rs b/src/test/ui/never_type/dispatch_from_dyn_zst.rs similarity index 100% rename from src/test/ui/dispatch_from_dyn_zst.rs rename to src/test/ui/never_type/dispatch_from_dyn_zst.rs diff --git a/src/test/ui/diverging-fallback-control-flow.rs b/src/test/ui/never_type/diverging-fallback-control-flow.rs similarity index 99% rename from src/test/ui/diverging-fallback-control-flow.rs rename to src/test/ui/never_type/diverging-fallback-control-flow.rs index 0f0f787b407d2..c68e6364ed406 100644 --- a/src/test/ui/diverging-fallback-control-flow.rs +++ b/src/test/ui/never_type/diverging-fallback-control-flow.rs @@ -4,6 +4,7 @@ #![allow(unused_assignments)] #![allow(unused_variables)] #![allow(unreachable_code)] + // Test various cases where we permit an unconstrained variable // to fallback based on control-flow. // diff --git a/src/test/ui/impl-for-never.rs b/src/test/ui/never_type/impl-for-never.rs similarity index 99% rename from src/test/ui/impl-for-never.rs rename to src/test/ui/never_type/impl-for-never.rs index c5f12981ecc26..9423f08858b9b 100644 --- a/src/test/ui/impl-for-never.rs +++ b/src/test/ui/never_type/impl-for-never.rs @@ -1,8 +1,9 @@ // run-pass -// Test that we can call static methods on ! both directly and when it appears in a generic #![feature(never_type)] +// Test that we can call static methods on ! both directly and when it appears in a generic + trait StringifyType { fn stringify_type() -> &'static str; } diff --git a/src/test/ui/issues/issue-13352.rs b/src/test/ui/never_type/issue-13352.rs similarity index 100% rename from src/test/ui/issues/issue-13352.rs rename to src/test/ui/never_type/issue-13352.rs diff --git a/src/test/ui/issues/issue-13352.stderr b/src/test/ui/never_type/issue-13352.stderr similarity index 100% rename from src/test/ui/issues/issue-13352.stderr rename to src/test/ui/never_type/issue-13352.stderr diff --git a/src/test/ui/issues/issue-2149.rs b/src/test/ui/never_type/issue-2149.rs similarity index 100% rename from src/test/ui/issues/issue-2149.rs rename to src/test/ui/never_type/issue-2149.rs diff --git a/src/test/ui/issues/issue-2149.stderr b/src/test/ui/never_type/issue-2149.stderr similarity index 100% rename from src/test/ui/issues/issue-2149.stderr rename to src/test/ui/never_type/issue-2149.stderr diff --git a/src/test/ui/issues/issue-44402.rs b/src/test/ui/never_type/issue-44402.rs similarity index 90% rename from src/test/ui/issues/issue-44402.rs rename to src/test/ui/never_type/issue-44402.rs index 29b7eb5ee49c7..699e480dfe7e5 100644 --- a/src/test/ui/issues/issue-44402.rs +++ b/src/test/ui/never_type/issue-44402.rs @@ -1,4 +1,5 @@ -// build-pass (FIXME(62277): could be check-pass?) +// check-pass + #![allow(dead_code)] #![feature(never_type)] #![feature(exhaustive_patterns)] diff --git a/src/test/ui/never-assign-dead-code.rs b/src/test/ui/never_type/never-assign-dead-code.rs similarity index 82% rename from src/test/ui/never-assign-dead-code.rs rename to src/test/ui/never_type/never-assign-dead-code.rs index fd5fbc30611a9..7bb7c87097c50 100644 --- a/src/test/ui/never-assign-dead-code.rs +++ b/src/test/ui/never_type/never-assign-dead-code.rs @@ -1,10 +1,10 @@ // Test that an assignment of type ! makes the rest of the block dead code. +// check-pass + #![feature(never_type)] -// build-pass (FIXME(62277): could be check-pass?) #![warn(unused)] - fn main() { let x: ! = panic!("aah"); //~ WARN unused drop(x); //~ WARN unreachable diff --git a/src/test/ui/never-assign-dead-code.stderr b/src/test/ui/never_type/never-assign-dead-code.stderr similarity index 92% rename from src/test/ui/never-assign-dead-code.stderr rename to src/test/ui/never_type/never-assign-dead-code.stderr index b887d580e68a9..1860150fa8bc6 100644 --- a/src/test/ui/never-assign-dead-code.stderr +++ b/src/test/ui/never_type/never-assign-dead-code.stderr @@ -7,7 +7,7 @@ LL | drop(x); | ^^^^^^^^ unreachable statement | note: lint level defined here - --> $DIR/never-assign-dead-code.rs:5:9 + --> $DIR/never-assign-dead-code.rs:6:9 | LL | #![warn(unused)] | ^^^^^^ @@ -29,7 +29,7 @@ LL | let x: ! = panic!("aah"); | ^ help: consider prefixing with an underscore: `_x` | note: lint level defined here - --> $DIR/never-assign-dead-code.rs:5:9 + --> $DIR/never-assign-dead-code.rs:6:9 | LL | #![warn(unused)] | ^^^^^^ diff --git a/src/test/ui/never-assign-wrong-type.rs b/src/test/ui/never_type/never-assign-wrong-type.rs similarity index 100% rename from src/test/ui/never-assign-wrong-type.rs rename to src/test/ui/never_type/never-assign-wrong-type.rs diff --git a/src/test/ui/never-assign-wrong-type.stderr b/src/test/ui/never_type/never-assign-wrong-type.stderr similarity index 100% rename from src/test/ui/never-assign-wrong-type.stderr rename to src/test/ui/never_type/never-assign-wrong-type.stderr diff --git a/src/test/run-fail/never-associated-type.rs b/src/test/ui/never_type/never-associated-type.rs similarity index 96% rename from src/test/run-fail/never-associated-type.rs rename to src/test/ui/never_type/never-associated-type.rs index 587f0f72d5a62..7f0a3fef6a99a 100644 --- a/src/test/run-fail/never-associated-type.rs +++ b/src/test/ui/never_type/never-associated-type.rs @@ -1,5 +1,6 @@ // Test that we can use ! as an associated type. +// run-fail // error-pattern:kapow! #![feature(never_type)] diff --git a/src/test/ui/never-from-impl-is-reserved.rs b/src/test/ui/never_type/never-from-impl-is-reserved.rs similarity index 100% rename from src/test/ui/never-from-impl-is-reserved.rs rename to src/test/ui/never_type/never-from-impl-is-reserved.rs diff --git a/src/test/ui/never-from-impl-is-reserved.stderr b/src/test/ui/never_type/never-from-impl-is-reserved.stderr similarity index 100% rename from src/test/ui/never-from-impl-is-reserved.stderr rename to src/test/ui/never_type/never-from-impl-is-reserved.stderr diff --git a/src/test/ui/never-result.rs b/src/test/ui/never_type/never-result.rs similarity index 99% rename from src/test/ui/never-result.rs rename to src/test/ui/never_type/never-result.rs index 98ce326aa6631..35af37910ef3e 100644 --- a/src/test/ui/never-result.rs +++ b/src/test/ui/never_type/never-result.rs @@ -2,6 +2,7 @@ #![allow(unused_variables)] #![allow(unreachable_code)] + // Test that we can extract a ! through pattern matching then use it as several different types. #![feature(never_type)] diff --git a/src/test/run-fail/never-type-arg.rs b/src/test/ui/never_type/never-type-arg.rs similarity index 95% rename from src/test/run-fail/never-type-arg.rs rename to src/test/ui/never_type/never-type-arg.rs index 1747e96eef4e3..a82d351f6cf2b 100644 --- a/src/test/run-fail/never-type-arg.rs +++ b/src/test/ui/never_type/never-type-arg.rs @@ -1,5 +1,6 @@ // Test that we can use ! as an argument to a trait impl. +// run-fail // error-pattern:oh no! #![feature(never_type)] diff --git a/src/test/ui/never-type-rvalues.rs b/src/test/ui/never_type/never-type-rvalues.rs similarity index 100% rename from src/test/ui/never-type-rvalues.rs rename to src/test/ui/never_type/never-type-rvalues.rs diff --git a/src/test/ui/never_coercions.rs b/src/test/ui/never_type/never_coercions.rs similarity index 100% rename from src/test/ui/never_coercions.rs rename to src/test/ui/never_type/never_coercions.rs diff --git a/src/test/ui/never_transmute_never.rs b/src/test/ui/never_type/never_transmute_never.rs similarity index 87% rename from src/test/ui/never_transmute_never.rs rename to src/test/ui/never_type/never_transmute_never.rs index 5bad756b8762f..fce3ced9aac7f 100644 --- a/src/test/ui/never_transmute_never.rs +++ b/src/test/ui/never_type/never_transmute_never.rs @@ -1,4 +1,4 @@ -// build-pass (FIXME(62277): could be check-pass?) +// check-pass #![crate_type="lib"] diff --git a/src/test/ui/panic-uninitialized-zeroed.rs b/src/test/ui/never_type/panic-uninitialized-zeroed.rs similarity index 100% rename from src/test/ui/panic-uninitialized-zeroed.rs rename to src/test/ui/never_type/panic-uninitialized-zeroed.rs diff --git a/src/test/ui/try_from.rs b/src/test/ui/never_type/try_from.rs similarity index 100% rename from src/test/ui/try_from.rs rename to src/test/ui/never_type/try_from.rs diff --git a/src/test/ui/unreachable/auxiliary/unreachable_variant.rs b/src/test/ui/reachable/auxiliary/unreachable_variant.rs similarity index 100% rename from src/test/ui/unreachable/auxiliary/unreachable_variant.rs rename to src/test/ui/reachable/auxiliary/unreachable_variant.rs diff --git a/src/test/ui/unreachable/unreachable-arm.rs b/src/test/ui/reachable/unreachable-arm.rs similarity index 100% rename from src/test/ui/unreachable/unreachable-arm.rs rename to src/test/ui/reachable/unreachable-arm.rs diff --git a/src/test/ui/unreachable/unreachable-arm.stderr b/src/test/ui/reachable/unreachable-arm.stderr similarity index 100% rename from src/test/ui/unreachable/unreachable-arm.stderr rename to src/test/ui/reachable/unreachable-arm.stderr diff --git a/src/test/ui/unreachable/unreachable-code.rs b/src/test/ui/reachable/unreachable-code.rs similarity index 100% rename from src/test/ui/unreachable/unreachable-code.rs rename to src/test/ui/reachable/unreachable-code.rs diff --git a/src/test/ui/unreachable/unreachable-code.stderr b/src/test/ui/reachable/unreachable-code.stderr similarity index 100% rename from src/test/ui/unreachable/unreachable-code.stderr rename to src/test/ui/reachable/unreachable-code.stderr diff --git a/src/test/ui/unreachable/unreachable-in-call.rs b/src/test/ui/reachable/unreachable-in-call.rs similarity index 100% rename from src/test/ui/unreachable/unreachable-in-call.rs rename to src/test/ui/reachable/unreachable-in-call.rs diff --git a/src/test/ui/unreachable/unreachable-in-call.stderr b/src/test/ui/reachable/unreachable-in-call.stderr similarity index 100% rename from src/test/ui/unreachable/unreachable-in-call.stderr rename to src/test/ui/reachable/unreachable-in-call.stderr diff --git a/src/test/ui/unreachable/unreachable-loop-patterns.rs b/src/test/ui/reachable/unreachable-loop-patterns.rs similarity index 95% rename from src/test/ui/unreachable/unreachable-loop-patterns.rs rename to src/test/ui/reachable/unreachable-loop-patterns.rs index 56ab1a270a75d..6f1d2efa1b200 100644 --- a/src/test/ui/unreachable/unreachable-loop-patterns.rs +++ b/src/test/ui/reachable/unreachable-loop-patterns.rs @@ -1,5 +1,3 @@ -// compile-fail - #![feature(never_type)] #![feature(exhaustive_patterns)] diff --git a/src/test/ui/unreachable/unreachable-loop-patterns.stderr b/src/test/ui/reachable/unreachable-loop-patterns.stderr similarity index 73% rename from src/test/ui/unreachable/unreachable-loop-patterns.stderr rename to src/test/ui/reachable/unreachable-loop-patterns.stderr index 254d1178d142e..bb5103320d2cf 100644 --- a/src/test/ui/unreachable/unreachable-loop-patterns.stderr +++ b/src/test/ui/reachable/unreachable-loop-patterns.stderr @@ -1,17 +1,17 @@ error: unreachable pattern - --> $DIR/unreachable-loop-patterns.rs:20:9 + --> $DIR/unreachable-loop-patterns.rs:18:9 | LL | for _ in unimplemented!() as Void {} | ^ | note: lint level defined here - --> $DIR/unreachable-loop-patterns.rs:7:9 + --> $DIR/unreachable-loop-patterns.rs:5:9 | LL | #![deny(unreachable_patterns)] | ^^^^^^^^^^^^^^^^^^^^ error: unreachable pattern - --> $DIR/unreachable-loop-patterns.rs:20:14 + --> $DIR/unreachable-loop-patterns.rs:18:14 | LL | for _ in unimplemented!() as Void {} | ^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/unreachable/unreachable-try-pattern.rs b/src/test/ui/reachable/unreachable-try-pattern.rs similarity index 94% rename from src/test/ui/unreachable/unreachable-try-pattern.rs rename to src/test/ui/reachable/unreachable-try-pattern.rs index cbc5fcee2f035..23360e73f4a3a 100644 --- a/src/test/ui/unreachable/unreachable-try-pattern.rs +++ b/src/test/ui/reachable/unreachable-try-pattern.rs @@ -1,4 +1,4 @@ -// build-pass (FIXME(62277): could be check-pass?) +// check-pass #![feature(never_type, exhaustive_patterns)] #![warn(unreachable_code)] #![warn(unreachable_patterns)] diff --git a/src/test/ui/unreachable/unreachable-try-pattern.stderr b/src/test/ui/reachable/unreachable-try-pattern.stderr similarity index 100% rename from src/test/ui/unreachable/unreachable-try-pattern.stderr rename to src/test/ui/reachable/unreachable-try-pattern.stderr diff --git a/src/test/ui/unreachable/unreachable-variant.rs b/src/test/ui/reachable/unreachable-variant.rs similarity index 100% rename from src/test/ui/unreachable/unreachable-variant.rs rename to src/test/ui/reachable/unreachable-variant.rs diff --git a/src/test/ui/unreachable/unreachable-variant.stderr b/src/test/ui/reachable/unreachable-variant.stderr similarity index 100% rename from src/test/ui/unreachable/unreachable-variant.stderr rename to src/test/ui/reachable/unreachable-variant.stderr diff --git a/src/test/ui/unreachable/unwarned-match-on-never.rs b/src/test/ui/reachable/unwarned-match-on-never.rs similarity index 100% rename from src/test/ui/unreachable/unwarned-match-on-never.rs rename to src/test/ui/reachable/unwarned-match-on-never.rs diff --git a/src/test/ui/unreachable/unwarned-match-on-never.stderr b/src/test/ui/reachable/unwarned-match-on-never.stderr similarity index 100% rename from src/test/ui/unreachable/unwarned-match-on-never.stderr rename to src/test/ui/reachable/unwarned-match-on-never.stderr diff --git a/src/test/ui/always-inhabited-union-ref.rs b/src/test/ui/uninhabited/always-inhabited-union-ref.rs similarity index 100% rename from src/test/ui/always-inhabited-union-ref.rs rename to src/test/ui/uninhabited/always-inhabited-union-ref.rs diff --git a/src/test/ui/always-inhabited-union-ref.stderr b/src/test/ui/uninhabited/always-inhabited-union-ref.stderr similarity index 100% rename from src/test/ui/always-inhabited-union-ref.stderr rename to src/test/ui/uninhabited/always-inhabited-union-ref.stderr From dee53d7c90812d0cbabe7f19b35c125432c1c8c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 9 Oct 2019 10:10:54 -0700 Subject: [PATCH 20/27] Fix suggestion to constrain trait for method to be found --- src/librustc_typeck/check/method/suggest.rs | 113 +++++++++++------- src/test/ui/suggestions/constrain-trait.fixed | 47 ++++++++ src/test/ui/suggestions/constrain-trait.rs | 47 ++++++++ .../ui/suggestions/constrain-trait.stderr | 27 +++++ 4 files changed, 191 insertions(+), 43 deletions(-) create mode 100644 src/test/ui/suggestions/constrain-trait.fixed create mode 100644 src/test/ui/suggestions/constrain-trait.rs create mode 100644 src/test/ui/suggestions/constrain-trait.stderr diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index 96cc5aa1dc24b..f2d001eadedde 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -777,7 +777,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } else { "items from traits can only be used if the trait is implemented and in scope" }); - let mut msg = format!( + let message = |action| format!( "the following {traits_define} an item `{name}`, perhaps you need to {action} \ {one_of_them}:", traits_define = if candidates.len() == 1 { @@ -785,11 +785,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } else { "traits define" }, - action = if let Some(param) = param_type { - format!("restrict type parameter `{}` with", param) - } else { - "implement".to_string() - }, + action = action, one_of_them = if candidates.len() == 1 { "it" } else { @@ -809,50 +805,81 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Get the `hir::Param` to verify whether it already has any bounds. // We do this to avoid suggesting code that ends up as `T: FooBar`, // instead we suggest `T: Foo + Bar` in that case. - let mut has_bounds = None; - let mut impl_trait = false; - if let Node::GenericParam(ref param) = hir.get(id) { - let kind = ¶m.kind; - if let hir::GenericParamKind::Type { synthetic: Some(_), .. } = kind { - // We've found `fn foo(x: impl Trait)` instead of - // `fn foo(x: T)`. We want to suggest the correct - // `fn foo(x: impl Trait + TraitBound)` instead of - // `fn foo(x: T)`. (See #63706.) - impl_trait = true; - has_bounds = param.bounds.get(1); - } else { - has_bounds = param.bounds.get(0); + match hir.get(id) { + Node::GenericParam(ref param) => { + let mut impl_trait = false; + let has_bounds = if let hir::GenericParamKind::Type { + synthetic: Some(_), .. + } = ¶m.kind { + // We've found `fn foo(x: impl Trait)` instead of + // `fn foo(x: T)`. We want to suggest the correct + // `fn foo(x: impl Trait + TraitBound)` instead of + // `fn foo(x: T)`. (#63706) + impl_trait = true; + param.bounds.get(1) + } else { + param.bounds.get(0) + }; + let sp = hir.span(id); + let sp = if let Some(first_bound) = has_bounds { + // `sp` only covers `T`, change it so that it covers + // `T:` when appropriate + sp.until(first_bound.span()) + } else { + sp + }; + // FIXME: contrast `t.def_id` against `param.bounds` to not suggest + // traits already there. That can happen when the cause is that + // we're in a const scope or associated function used as a method. + err.span_suggestions( + sp, + &message(format!( + "restrict type parameter `{}` with", + param.name.ident().as_str(), + )), + candidates.iter().map(|t| format!( + "{}{} {}{}", + param.name.ident().as_str(), + if impl_trait { " +" } else { ":" }, + self.tcx.def_path_str(t.def_id), + if has_bounds.is_some() { " + "} else { "" }, + )), + Applicability::MaybeIncorrect, + ); + suggested = true; + } + Node::Item(hir::Item { + kind: hir::ItemKind::Trait(.., bounds, _), ident, .. + }) => { + let (sp, sep, article) = if bounds.is_empty() { + (ident.span.shrink_to_hi(), ":", "a") + } else { + (bounds.last().unwrap().span().shrink_to_hi(), " +", "another") + }; + err.span_suggestions( + sp, + &message(format!("add {} supertrait for", article)), + candidates.iter().map(|t| format!( + "{} {}", + sep, + self.tcx.def_path_str(t.def_id), + )), + Applicability::MaybeIncorrect, + ); + suggested = true; } + _ => {} } - let sp = hir.span(id); - // `sp` only covers `T`, change it so that it covers `T:` when appropriate. - let sp = if let Some(first_bound) = has_bounds { - sp.until(first_bound.span()) - } else { - sp - }; - - // FIXME: contrast `t.def_id` against `param.bounds` to not suggest traits - // already there. That can happen when the cause is that we're in a const - // scope or associated function used as a method. - err.span_suggestions( - sp, - &msg[..], - candidates.iter().map(|t| format!( - "{}{} {}{}", - param, - if impl_trait { " +" } else { ":" }, - self.tcx.def_path_str(t.def_id), - if has_bounds.is_some() { " + " } else { "" }, - )), - Applicability::MaybeIncorrect, - ); - suggested = true; } }; } if !suggested { + let mut msg = message(if let Some(param) = param_type { + format!("restrict type parameter `{}` with", param) + } else { + "implement".to_string() + }); for (i, trait_info) in candidates.iter().enumerate() { msg.push_str(&format!( "\ncandidate #{}: `{}`", diff --git a/src/test/ui/suggestions/constrain-trait.fixed b/src/test/ui/suggestions/constrain-trait.fixed new file mode 100644 index 0000000000000..dda9e931353b2 --- /dev/null +++ b/src/test/ui/suggestions/constrain-trait.fixed @@ -0,0 +1,47 @@ +// run-rustfix +// check-only + +#[derive(Debug)] +struct Demo { + a: String +} + +trait GetString { + fn get_a(&self) -> &String; +} + +trait UseString: std::fmt::Debug + GetString { + fn use_string(&self) { + println!("{:?}", self.get_a()); //~ ERROR no method named `get_a` found for type `&Self` + } +} + +trait UseString2: GetString { + fn use_string(&self) { + println!("{:?}", self.get_a()); //~ ERROR no method named `get_a` found for type `&Self` + } +} + +impl GetString for Demo { + fn get_a(&self) -> &String { + &self.a + } +} + +impl UseString for Demo {} +impl UseString2 for Demo {} + + +#[cfg(test)] +mod tests { + use crate::{Demo, UseString}; + + #[test] + fn it_works() { + let d = Demo { a: "test".to_string() }; + d.use_string(); + } +} + + +fn main() {} diff --git a/src/test/ui/suggestions/constrain-trait.rs b/src/test/ui/suggestions/constrain-trait.rs new file mode 100644 index 0000000000000..4ef0eff5bd769 --- /dev/null +++ b/src/test/ui/suggestions/constrain-trait.rs @@ -0,0 +1,47 @@ +// run-rustfix +// check-only + +#[derive(Debug)] +struct Demo { + a: String +} + +trait GetString { + fn get_a(&self) -> &String; +} + +trait UseString: std::fmt::Debug { + fn use_string(&self) { + println!("{:?}", self.get_a()); //~ ERROR no method named `get_a` found for type `&Self` + } +} + +trait UseString2 { + fn use_string(&self) { + println!("{:?}", self.get_a()); //~ ERROR no method named `get_a` found for type `&Self` + } +} + +impl GetString for Demo { + fn get_a(&self) -> &String { + &self.a + } +} + +impl UseString for Demo {} +impl UseString2 for Demo {} + + +#[cfg(test)] +mod tests { + use crate::{Demo, UseString}; + + #[test] + fn it_works() { + let d = Demo { a: "test".to_string() }; + d.use_string(); + } +} + + +fn main() {} diff --git a/src/test/ui/suggestions/constrain-trait.stderr b/src/test/ui/suggestions/constrain-trait.stderr new file mode 100644 index 0000000000000..3cc351ac80aed --- /dev/null +++ b/src/test/ui/suggestions/constrain-trait.stderr @@ -0,0 +1,27 @@ +error[E0599]: no method named `get_a` found for type `&Self` in the current scope + --> $DIR/constrain-trait.rs:15:31 + | +LL | println!("{:?}", self.get_a()); + | ^^^^^ method not found in `&Self` + | + = help: items from traits can only be used if the type parameter is bounded by the trait +help: the following trait defines an item `get_a`, perhaps you need to add another supertrait for it: + | +LL | trait UseString: std::fmt::Debug + GetString { + | ^^^^^^^^^^^ + +error[E0599]: no method named `get_a` found for type `&Self` in the current scope + --> $DIR/constrain-trait.rs:21:31 + | +LL | println!("{:?}", self.get_a()); + | ^^^^^ method not found in `&Self` + | + = help: items from traits can only be used if the type parameter is bounded by the trait +help: the following trait defines an item `get_a`, perhaps you need to add a supertrait for it: + | +LL | trait UseString2: GetString { + | ^^^^^^^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0599`. From d82c1c546df10f07b854a2e5b088404d80ec22c9 Mon Sep 17 00:00:00 2001 From: Giles Cope Date: Tue, 15 Oct 2019 18:05:13 +0100 Subject: [PATCH 21/27] Avoid unused lifetime warning for lifetimes introduced when desugering async. --- src/librustc/middle/resolve_lifetime.rs | 8 +++- src/test/ui/async-await/unused-lifetime.rs | 42 +++++++++++++++++++ .../ui/async-await/unused-lifetime.stderr | 32 ++++++++++++++ 3 files changed, 81 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/async-await/unused-lifetime.rs create mode 100644 src/test/ui/async-await/unused-lifetime.stderr diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index 8836a632a7ca8..86afde16dc804 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -709,15 +709,22 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { match param.kind { GenericParamKind::Lifetime { .. } => { let (name, reg) = Region::early(&self.tcx.hir(), &mut index, ¶m); + let def_id = if let Region::EarlyBound(_ ,def_id , _) = reg { + def_id + } else { + bug!(); + }; if let hir::ParamName::Plain(param_name) = name { if param_name.name == kw::UnderscoreLifetime { // Pick the elided lifetime "definition" if one exists // and use it to make an elision scope. + self.lifetime_uses.insert(def_id.clone(), LifetimeUseSet::Many); elision = Some(reg); } else { lifetimes.insert(name, reg); } } else { + self.lifetime_uses.insert(def_id.clone(), LifetimeUseSet::Many); lifetimes.insert(name, reg); } } @@ -1623,7 +1630,6 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { _ => None, } { debug!("id = {:?} span = {:?} name = {:?}", id, span, name); - if name.name == kw::UnderscoreLifetime { continue; } diff --git a/src/test/ui/async-await/unused-lifetime.rs b/src/test/ui/async-await/unused-lifetime.rs new file mode 100644 index 0000000000000..1cf546bcb4266 --- /dev/null +++ b/src/test/ui/async-await/unused-lifetime.rs @@ -0,0 +1,42 @@ +// edition:2018 + +// Avoid spurious warnings of unused lifetime. The below async functions +// are desugered to have an unused lifetime +// but we don't want to warn about that as there's nothing they can do about it. + +#![deny(unused_lifetimes)] +#![allow(dead_code)] + +pub async fn october(s: &str) { + println!("{}", s); +} + +pub async fn async_fn(&mut ref s: &mut[i32]) { + println!("{:?}", s); +} + +macro_rules! foo_macro { + () => { + pub async fn async_fn_in_macro(&mut ref _s: &mut[i32]) {} + }; +} + +foo_macro!(); + +pub async fn func_with_unused_lifetime<'a>(s: &'a str) { + //~^ ERROR lifetime parameter `'a` never used + println!("{}", s); +} + +pub async fn func_with_two_unused_lifetime<'a, 'b>(s: &'a str, t: &'b str) { + //~^ ERROR lifetime parameter `'a` never used + //~^^ ERROR lifetime parameter `'b` never used + println!("{}", s); +} + +pub async fn func_with_unused_lifetime_in_two_params<'c>(s: &'c str, t: &'c str) { + //~^ ERROR lifetime parameter `'c` never used + println!("{}", s); +} + +fn main() {} diff --git a/src/test/ui/async-await/unused-lifetime.stderr b/src/test/ui/async-await/unused-lifetime.stderr new file mode 100644 index 0000000000000..885cdc04cfa4c --- /dev/null +++ b/src/test/ui/async-await/unused-lifetime.stderr @@ -0,0 +1,32 @@ +error: lifetime parameter `'a` never used + --> $DIR/unused-lifetime.rs:26:40 + | +LL | pub async fn func_with_unused_lifetime<'a>(s: &'a str) { + | ^^ + | +note: lint level defined here + --> $DIR/unused-lifetime.rs:7:9 + | +LL | #![deny(unused_lifetimes)] + | ^^^^^^^^^^^^^^^^ + +error: lifetime parameter `'a` never used + --> $DIR/unused-lifetime.rs:31:44 + | +LL | pub async fn func_with_two_unused_lifetime<'a, 'b>(s: &'a str, t: &'b str) { + | ^^ + +error: lifetime parameter `'b` never used + --> $DIR/unused-lifetime.rs:31:48 + | +LL | pub async fn func_with_two_unused_lifetime<'a, 'b>(s: &'a str, t: &'b str) { + | ^^ + +error: lifetime parameter `'c` never used + --> $DIR/unused-lifetime.rs:37:54 + | +LL | pub async fn func_with_unused_lifetime_in_two_params<'c>(s: &'c str, t: &'c str) { + | ^^ + +error: aborting due to 4 previous errors + From fa3a4aeae5f3a4c403bf07038c56e74df3d9df70 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Tue, 15 Oct 2019 12:55:39 -0300 Subject: [PATCH 22/27] Implement AsRef<[T]> for List --- src/librustc/ty/mod.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 3692caada577c..e74f8fb074f74 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -700,6 +700,13 @@ impl Deref for List { type Target = [T]; #[inline(always)] fn deref(&self) -> &[T] { + self.as_ref() + } +} + +impl AsRef<[T]> for List { + #[inline(always)] + fn as_ref(&self) -> &[T] { unsafe { slice::from_raw_parts(self.data.as_ptr(), self.len) } From 2918a7d5a9e65721a31598b50e975ae0882feac3 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 15 Oct 2019 10:02:55 +1100 Subject: [PATCH 23/27] Add `BitIter::new()`. This factors out some duplicated code. --- src/librustc_index/bit_set.rs | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/src/librustc_index/bit_set.rs b/src/librustc_index/bit_set.rs index 8c49e0dde0dcd..bfaeb847d80b8 100644 --- a/src/librustc_index/bit_set.rs +++ b/src/librustc_index/bit_set.rs @@ -168,11 +168,7 @@ impl BitSet { /// Iterates over the indices of set bits in a sorted order. #[inline] pub fn iter(&self) -> BitIter<'_, T> { - BitIter { - cur: None, - iter: self.words.iter().enumerate(), - marker: PhantomData, - } + BitIter::new(&self.words) } /// Duplicates the set as a hybrid set. @@ -296,6 +292,17 @@ pub struct BitIter<'a, T: Idx> { marker: PhantomData } +impl<'a, T: Idx> BitIter<'a, T> { + #[inline] + fn new(words: &'a [Word]) -> BitIter<'a, T> { + BitIter { + cur: None, + iter: words.iter().enumerate(), + marker: PhantomData, + } + } +} + impl<'a, T: Idx> Iterator for BitIter<'a, T> { type Item = T; fn next(&mut self) -> Option { @@ -851,11 +858,7 @@ impl BitMatrix { pub fn iter(&self, row: R) -> BitIter<'_, C> { assert!(row.index() < self.num_rows); let (start, end) = self.range(row); - BitIter { - cur: None, - iter: self.words[start..end].iter().enumerate(), - marker: PhantomData, - } + BitIter::new(&self.words[start..end]) } /// Returns the number of elements in `row`. From 60851b08e523e1a3ab4defc8b6049751b6bf1ad5 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 15 Oct 2019 10:11:30 +1100 Subject: [PATCH 24/27] Optimize `BitSet` iteration. This commit removes an `Option` check in `BitIter::next()`, avoids calling `trailing_zeros()` when it's not necessary, and avoids the need for `enumerate()`. This gives a tiny (0.2%) instruction count win on a couple of benchmarks. The commit also adds some comments, which is good because this iteration code is moderately complex. --- src/librustc_index/bit_set.rs | 44 ++++++++++++++++++++++++----------- 1 file changed, 31 insertions(+), 13 deletions(-) diff --git a/src/librustc_index/bit_set.rs b/src/librustc_index/bit_set.rs index bfaeb847d80b8..d8c6e4c33e2fa 100644 --- a/src/librustc_index/bit_set.rs +++ b/src/librustc_index/bit_set.rs @@ -287,17 +287,32 @@ impl ToString for BitSet { } pub struct BitIter<'a, T: Idx> { - cur: Option<(Word, usize)>, - iter: iter::Enumerate>, + /// A copy of the current word, but with any already-visited bits cleared. + /// (This lets us use `trailing_zeros()` to find the next set bit.) When it + /// is reduced to 0, we move onto the next word. + word: Word, + + /// The offset (measured in bits) of the current word. + offset: usize, + + /// Underlying iterator over the words. + iter: slice::Iter<'a, Word>, + marker: PhantomData } impl<'a, T: Idx> BitIter<'a, T> { #[inline] fn new(words: &'a [Word]) -> BitIter<'a, T> { + // We initialize `word` and `offset` to degenerate values. On the first + // call to `next()` we will fall through to getting the first word from + // `iter`, which sets `word` to the first word (if there is one) and + // `offset` to 0. Doing it this way saves us from having to maintain + // additional state about whether we have started. BitIter { - cur: None, - iter: words.iter().enumerate(), + word: 0, + offset: std::usize::MAX - (WORD_BITS - 1), + iter: words.iter(), marker: PhantomData, } } @@ -307,17 +322,20 @@ impl<'a, T: Idx> Iterator for BitIter<'a, T> { type Item = T; fn next(&mut self) -> Option { loop { - if let Some((ref mut word, offset)) = self.cur { - let bit_pos = word.trailing_zeros() as usize; - if bit_pos != WORD_BITS { - let bit = 1 << bit_pos; - *word ^= bit; - return Some(T::new(bit_pos + offset)) - } + if self.word != 0 { + // Get the position of the next set bit in the current word, + // then clear the bit. + let bit_pos = self.word.trailing_zeros() as usize; + let bit = 1 << bit_pos; + self.word ^= bit; + return Some(T::new(bit_pos + self.offset)) } - let (i, word) = self.iter.next()?; - self.cur = Some((*word, WORD_BITS * i)); + // Move onto the next word. `wrapping_add()` is needed to handle + // the degenerate initial value given to `offset` in `new()`. + let word = self.iter.next()?; + self.word = *word; + self.offset = self.offset.wrapping_add(WORD_BITS); } } } From 1a2597b64a9d76eb336878e9b0b9dd4021b0240c Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Mon, 9 Sep 2019 21:04:26 +0100 Subject: [PATCH 25/27] Don't use `gensym_if_underscore` to resolve `_` bindings Instead add a disambiguator to the keys used for distinguishing resolutions. --- src/librustc_resolve/build_reduced_graph.rs | 16 ++-- src/librustc_resolve/diagnostics.rs | 6 +- src/librustc_resolve/lib.rs | 38 +++++++-- src/librustc_resolve/resolve_imports.rs | 94 ++++++++++----------- 4 files changed, 91 insertions(+), 63 deletions(-) diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 030f9b97eb8b9..d1c2fa77c0166 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -93,7 +93,8 @@ impl<'a> Resolver<'a> { where T: ToNameBinding<'a>, { let binding = def.to_name_binding(self.arenas); - if let Err(old_binding) = self.try_define(parent, ident, ns, binding) { + let key = self.new_key(ident, ns); + if let Err(old_binding) = self.try_define(parent, key, binding) { self.report_conflict(parent, ident, ns, old_binding, &binding); } } @@ -349,9 +350,12 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { self.r.indeterminate_imports.push(directive); match directive.subclass { + // Don't add unresolved underscore imports to modules + SingleImport { target: Ident { name: kw::Underscore, .. }, .. } => {} SingleImport { target, type_ns_only, .. } => { self.r.per_ns(|this, ns| if !type_ns_only || ns == TypeNS { - let mut resolution = this.resolution(current_module, target, ns).borrow_mut(); + let key = this.new_key(target, ns); + let mut resolution = this.resolution(current_module, key).borrow_mut(); resolution.add_single_import(directive); }); } @@ -407,7 +411,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { }; match use_tree.kind { ast::UseTreeKind::Simple(rename, ..) => { - let mut ident = use_tree.ident().gensym_if_underscore(); + let mut ident = use_tree.ident(); let mut module_path = prefix; let mut source = module_path.pop().unwrap(); let mut type_ns_only = false; @@ -585,7 +589,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { let parent_scope = &self.parent_scope; let parent = parent_scope.module; let expansion = parent_scope.expansion; - let ident = item.ident.gensym_if_underscore(); + let ident = item.ident; let sp = item.span; let vis = self.resolve_visibility(&item.vis); @@ -850,10 +854,6 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { fn build_reduced_graph_for_external_crate_res(&mut self, child: Export) { let parent = self.parent_scope.module; let Export { ident, res, vis, span } = child; - // FIXME: We shouldn't create the gensym here, it should come from metadata, - // but metadata cannot encode gensyms currently, so we create it here. - // This is only a guess, two equivalent idents may incorrectly get different gensyms here. - let ident = ident.gensym_if_underscore(); let expansion = ExpnId::root(); // FIXME(jseyfried) intercrate hygiene // Record primary definitions. match res { diff --git a/src/librustc_resolve/diagnostics.rs b/src/librustc_resolve/diagnostics.rs index d713315decbe9..de8758086709f 100644 --- a/src/librustc_resolve/diagnostics.rs +++ b/src/librustc_resolve/diagnostics.rs @@ -80,11 +80,11 @@ impl<'a> Resolver<'a> { names: &mut Vec, filter_fn: &impl Fn(Res) -> bool, ) { - for (&(ident, _), resolution) in self.resolutions(module).borrow().iter() { + for (key, resolution) in self.resolutions(module).borrow().iter() { if let Some(binding) = resolution.borrow().binding { let res = binding.res(); if filter_fn(res) { - names.push(TypoSuggestion::from_res(ident.name, res)); + names.push(TypoSuggestion::from_res(key.ident.name, res)); } } } @@ -849,7 +849,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { } let resolutions = self.r.resolutions(crate_module).borrow(); - let resolution = resolutions.get(&(ident, MacroNS))?; + let resolution = resolutions.get(&self.r.new_key(ident, MacroNS))?; let binding = resolution.borrow().binding()?; if let Res::Def(DefKind::Macro(MacroKind::Bang), _) = binding.res() { let module_name = crate_module.kind.name().unwrap(); diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index e0ff153900917..e86d2231fa19e 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -431,7 +431,22 @@ impl ModuleKind { } } -type Resolutions<'a> = RefCell>>>; +/// A key that identifies a binding in a given `Module`. +/// +/// Multiple bindings in the same module can have the same key (in a valid +/// program) if all but one of them come from glob imports. +#[derive(Copy, Clone, PartialEq, Eq, Hash)] +struct BindingKey { + /// The identifier for the binding, aways the `modern` version of the + /// identifier. + ident: Ident, + ns: Namespace, + /// 0 if ident is not `_`, otherwise a value that's unique to the specific + /// `_` in the expanded AST that introduced this binding. + disambiguator: u32, +} + +type Resolutions<'a> = RefCell>>>; /// One node in the tree of modules. pub struct ModuleData<'a> { @@ -491,8 +506,8 @@ impl<'a> ModuleData<'a> { fn for_each_child(&'a self, resolver: &mut R, mut f: F) where R: AsMut>, F: FnMut(&mut R, Ident, Namespace, &'a NameBinding<'a>) { - for (&(ident, ns), name_resolution) in resolver.as_mut().resolutions(self).borrow().iter() { - name_resolution.borrow().binding.map(|binding| f(resolver, ident, ns, binding)); + for (key, name_resolution) in resolver.as_mut().resolutions(self).borrow().iter() { + name_resolution.borrow().binding.map(|binding| f(resolver, key.ident, key.ns, binding)); } } @@ -879,6 +894,7 @@ pub struct Resolver<'a> { module_map: FxHashMap>, extern_module_map: FxHashMap<(DefId, bool /* MacrosOnly? */), Module<'a>>, binding_parent_modules: FxHashMap>, Module<'a>>, + underscore_disambiguator: u32, /// Maps glob imports to the names of items actually imported. pub glob_map: GlobMap, @@ -1156,6 +1172,7 @@ impl<'a> Resolver<'a> { label_res_map: Default::default(), export_map: FxHashMap::default(), trait_map: Default::default(), + underscore_disambiguator: 0, empty_module, module_map, block_map: Default::default(), @@ -1280,6 +1297,17 @@ impl<'a> Resolver<'a> { self.arenas.alloc_module(module) } + fn new_key(&mut self, ident: Ident, ns: Namespace) -> BindingKey { + let ident = ident.modern(); + let disambiguator = if ident.name == kw::Underscore { + self.underscore_disambiguator += 1; + self.underscore_disambiguator + } else { + 0 + }; + BindingKey { ident, ns, disambiguator } + } + fn resolutions(&mut self, module: Module<'a>) -> &'a Resolutions<'a> { if module.populate_on_access.get() { module.populate_on_access.set(false); @@ -1288,9 +1316,9 @@ impl<'a> Resolver<'a> { &module.lazy_resolutions } - fn resolution(&mut self, module: Module<'a>, ident: Ident, ns: Namespace) + fn resolution(&mut self, module: Module<'a>, key: BindingKey) -> &'a RefCell> { - *self.resolutions(module).borrow_mut().entry((ident.modern(), ns)) + *self.resolutions(module).borrow_mut().entry(key) .or_insert_with(|| self.arenas.alloc_name_resolution()) } diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index 360343169bc3d..56fd2da2576fb 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -7,7 +7,7 @@ use crate::{CrateLint, Module, ModuleOrUniformRoot, PerNS, ScopeSet, ParentScope use crate::Determinacy::{self, *}; use crate::Namespace::{self, TypeNS, MacroNS}; use crate::{NameBinding, NameBindingKind, ToNameBinding, PathResult, PrivacyError}; -use crate::{Resolver, ResolutionError, Segment, ModuleKind}; +use crate::{Resolver, ResolutionError, BindingKey, Segment, ModuleKind}; use crate::{names_to_string, module_to_string}; use crate::diagnostics::Suggestion; @@ -235,7 +235,8 @@ impl<'a> Resolver<'a> { } }; - let resolution = self.resolution(module, ident, ns) + let key = self.new_key(ident, ns); + let resolution = self.resolution(module, key) .try_borrow_mut() .map_err(|_| (Determined, Weak::No))?; // This happens when there is a cycle of imports. @@ -447,17 +448,16 @@ impl<'a> Resolver<'a> { } // Define the name or return the existing binding if there is a collision. - pub fn try_define( + crate fn try_define( &mut self, module: Module<'a>, - ident: Ident, - ns: Namespace, + key: BindingKey, binding: &'a NameBinding<'a>, ) -> Result<(), &'a NameBinding<'a>> { let res = binding.res(); - self.check_reserved_macro_name(ident, res); + self.check_reserved_macro_name(key.ident, res); self.set_binding_parent_module(binding, module); - self.update_resolution(module, ident, ns, |this, resolution| { + self.update_resolution(module, key, |this, resolution| { if let Some(old_binding) = resolution.binding { if res == Res::Err { // Do not override real bindings with `Res::Err`s from error recovery. @@ -479,8 +479,9 @@ impl<'a> Resolver<'a> { } else { (binding, old_binding) }; - if glob_binding.res() != nonglob_binding.res() && - ns == MacroNS && nonglob_binding.expansion != ExpnId::root() { + if glob_binding.res() != nonglob_binding.res() + && key.ns == MacroNS && nonglob_binding.expansion != ExpnId::root() + { resolution.binding = Some(this.ambiguity( AmbiguityKind::GlobVsExpanded, nonglob_binding, @@ -499,9 +500,9 @@ impl<'a> Resolver<'a> { DUPLICATE_MACRO_EXPORTS, CRATE_NODE_ID, binding.span, - &format!("a macro named `{}` has already been exported", ident), + &format!("a macro named `{}` has already been exported", key.ident), BuiltinLintDiagnostics::DuplicatedMacroExports( - ident, old_binding.span, binding.span)); + key.ident, old_binding.span, binding.span)); resolution.binding = Some(binding); } else { @@ -531,9 +532,9 @@ impl<'a> Resolver<'a> { // Use `f` to mutate the resolution of the name in the module. // If the resolution becomes a success, define it in the module's glob importers. fn update_resolution( - &mut self, module: Module<'a>, - ident: Ident, - ns: Namespace, + &mut self, + module: Module<'a>, + key: BindingKey, f: F, ) -> T where F: FnOnce(&mut Resolver<'a>, &mut NameResolution<'a>) -> T @@ -541,7 +542,7 @@ impl<'a> Resolver<'a> { // Ensure that `resolution` isn't borrowed when defining in the module's glob importers, // during which the resolution might end up getting re-defined via a glob cycle. let (binding, t) = { - let resolution = &mut *self.resolution(module, ident, ns).borrow_mut(); + let resolution = &mut *self.resolution(module, key).borrow_mut(); let old_binding = resolution.binding(); let t = f(self, resolution); @@ -558,7 +559,7 @@ impl<'a> Resolver<'a> { // Define `binding` in `module`s glob importers. for directive in module.glob_importers.borrow_mut().iter() { - let mut ident = ident.modern(); + let mut ident = key.ident; let scope = match ident.span.reverse_glob_adjust(module.expansion, directive.span) { Some(Some(def)) => self.macro_def_scope(def), Some(None) => directive.parent_scope.module, @@ -566,7 +567,8 @@ impl<'a> Resolver<'a> { }; if self.is_accessible_from(binding.vis, scope) { let imported_binding = self.import(binding, directive); - let _ = self.try_define(directive.parent_scope.module, ident, ns, imported_binding); + let key = BindingKey { ident, ..key }; + let _ = self.try_define(directive.parent_scope.module, key, imported_binding); } } @@ -580,7 +582,8 @@ impl<'a> Resolver<'a> { let dummy_binding = self.dummy_binding; let dummy_binding = self.import(dummy_binding, directive); self.per_ns(|this, ns| { - let _ = this.try_define(directive.parent_scope.module, target, ns, dummy_binding); + let key = this.new_key(target, ns); + let _ = this.try_define(directive.parent_scope.module, key, dummy_binding); // Consider erroneous imports used to avoid duplicate diagnostics. this.record_use(target, ns, dummy_binding, false); }); @@ -820,8 +823,11 @@ impl<'a, 'b> ImportResolver<'a, 'b> { let parent = directive.parent_scope.module; match source_bindings[ns].get() { Err(Undetermined) => indeterminate = true, + // Don't update the resolution, because it was never added. + Err(Determined) if target.name == kw::Underscore => {} Err(Determined) => { - this.update_resolution(parent, target, ns, |_, resolution| { + let key = this.new_key(target, ns); + this.update_resolution(parent, key, |_, resolution| { resolution.single_imports.remove(&PtrKey(directive)); }); } @@ -1052,7 +1058,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { _ => None, }; let resolutions = resolutions.as_ref().into_iter().flat_map(|r| r.iter()); - let names = resolutions.filter_map(|(&(ref i, _), resolution)| { + let names = resolutions.filter_map(|(BindingKey { ident: i, .. }, resolution)| { if *i == ident { return None; } // Never suggest the same name match *resolution.borrow() { NameResolution { binding: Some(name_binding), .. } => { @@ -1301,19 +1307,18 @@ impl<'a, 'b> ImportResolver<'a, 'b> { // Ensure that `resolutions` isn't borrowed during `try_define`, // since it might get updated via a glob cycle. - let bindings = self.r.resolutions(module).borrow().iter().filter_map(|(ident, resolution)| { - resolution.borrow().binding().map(|binding| (*ident, binding)) + let bindings = self.r.resolutions(module).borrow().iter().filter_map(|(key, resolution)| { + resolution.borrow().binding().map(|binding| (*key, binding)) }).collect::>(); - for ((mut ident, ns), binding) in bindings { - let scope = match ident.span.reverse_glob_adjust(module.expansion, directive.span) { + for (mut key, binding) in bindings { + let scope = match key.ident.span.reverse_glob_adjust(module.expansion, directive.span) { Some(Some(def)) => self.r.macro_def_scope(def), Some(None) => directive.parent_scope.module, None => continue, }; if self.r.is_accessible_from(binding.pseudo_vis(), scope) { let imported_binding = self.r.import(binding, directive); - let _ = - self.r.try_define(directive.parent_scope.module, ident, ns, imported_binding); + let _ = self.r.try_define(directive.parent_scope.module, key, imported_binding); } } @@ -1329,29 +1334,23 @@ impl<'a, 'b> ImportResolver<'a, 'b> { let mut reexports = Vec::new(); - for (&(ident, ns), resolution) in self.r.resolutions(module).borrow().iter() { - let resolution = &mut *resolution.borrow_mut(); - let binding = match resolution.binding { - Some(binding) => binding, - None => continue, - }; - + module.for_each_child(self.r, |this, ident, ns, binding| { // Filter away ambiguous imports and anything that has def-site // hygiene. // FIXME: Implement actual cross-crate hygiene. let is_good_import = binding.is_import() && !binding.is_ambiguity() - && !ident.span.modern().from_expansion(); + && !ident.span.from_expansion(); if is_good_import || binding.is_macro_def() { let res = binding.res(); if res != Res::Err { if let Some(def_id) = res.opt_def_id() { if !def_id.is_local() { - self.r.cstore.export_macros_untracked(def_id.krate); + this.cstore.export_macros_untracked(def_id.krate); } } reexports.push(Export { - ident: ident.modern(), - res: res, + ident, + res, span: binding.span, vis: binding.vis, }); @@ -1360,7 +1359,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { if let NameBindingKind::Import { binding: orig_binding, directive, .. } = binding.kind { if ns == TypeNS && orig_binding.is_variant() && - !orig_binding.vis.is_at_least(binding.vis, &*self) { + !orig_binding.vis.is_at_least(binding.vis, &*this) { let msg = match directive.subclass { ImportDirectiveSubclass::SingleImport { .. } => { format!("variant `{}` is private and cannot be re-exported", @@ -1372,33 +1371,34 @@ impl<'a, 'b> ImportResolver<'a, 'b> { let error_id = (DiagnosticMessageId::ErrorId(0), // no code?! Some(binding.span), msg.clone()); - let fresh = self.r.session.one_time_diagnostics + let fresh = this.session.one_time_diagnostics .borrow_mut().insert(error_id); if !fresh { - continue; + return; } msg }, ref s @ _ => bug!("unexpected import subclass {:?}", s) }; - let mut err = self.r.session.struct_span_err(binding.span, &msg); + let mut err = this.session.struct_span_err(binding.span, &msg); let imported_module = match directive.imported_module.get() { Some(ModuleOrUniformRoot::Module(module)) => module, _ => bug!("module should exist"), }; let parent_module = imported_module.parent.expect("parent should exist"); - let resolutions = self.r.resolutions(parent_module).borrow(); + let resolutions = this.resolutions(parent_module).borrow(); let enum_path_segment_index = directive.module_path.len() - 1; let enum_ident = directive.module_path[enum_path_segment_index].ident; - let enum_resolution = resolutions.get(&(enum_ident, TypeNS)) + let key = this.new_key(enum_ident, TypeNS); + let enum_resolution = resolutions.get(&key) .expect("resolution should exist"); let enum_span = enum_resolution.borrow() .binding.expect("binding should exist") .span; - let enum_def_span = self.r.session.source_map().def_span(enum_span); - let enum_def_snippet = self.r.session.source_map() + let enum_def_span = this.session.source_map().def_span(enum_span); + let enum_def_snippet = this.session.source_map() .span_to_snippet(enum_def_span).expect("snippet should exist"); // potentially need to strip extant `crate`/`pub(path)` for suggestion let after_vis_index = enum_def_snippet.find("enum") @@ -1406,7 +1406,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { let suggestion = format!("pub {}", &enum_def_snippet[after_vis_index..]); - self.r.session + this.session .diag_span_suggestion_once(&mut err, DiagnosticMessageId::ErrorId(0), enum_def_span, @@ -1415,7 +1415,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { err.emit(); } } - } + }); if reexports.len() > 0 { if let Some(def_id) = module.def_id() { From 94967f23f793ca7849fd59239d4526acb93b913a Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Sat, 31 Aug 2019 16:40:20 +0100 Subject: [PATCH 26/27] Remove gensyms --- src/libsyntax_pos/symbol.rs | 90 ++++--------------------------- src/libsyntax_pos/symbol/tests.rs | 7 --- 2 files changed, 9 insertions(+), 88 deletions(-) diff --git a/src/libsyntax_pos/symbol.rs b/src/libsyntax_pos/symbol.rs index 2b005c3fc421a..d17e909c4d53e 100644 --- a/src/libsyntax_pos/symbol.rs +++ b/src/libsyntax_pos/symbol.rs @@ -807,25 +807,13 @@ impl Ident { Ident::new(self.name, self.span.modern_and_legacy()) } - /// Transforms an underscore identifier into one with the same name, but - /// gensymed. Leaves non-underscore identifiers unchanged. - pub fn gensym_if_underscore(self) -> Ident { - if self.name == kw::Underscore { - let name = with_interner(|interner| interner.gensymed(self.name)); - Ident::new(name, self.span) - } else { - self - } - } - /// Convert the name to a `LocalInternedString`. This is a slowish /// operation because it requires locking the symbol interner. pub fn as_str(self) -> LocalInternedString { self.name.as_str() } - /// Convert the name to an `InternedString`. This is a slowish operation - /// because it requires locking the symbol interner. + /// Convert the name to an `InternedString`. pub fn as_interned_str(self) -> InternedString { self.name.as_interned_str() } @@ -880,26 +868,9 @@ impl UseSpecializedDecodable for Ident { } } -/// A symbol is an interned or gensymed string. A gensym is a symbol that is -/// never equal to any other symbol. +/// An interned string. /// -/// Conceptually, a gensym can be thought of as a normal symbol with an -/// invisible unique suffix. Gensyms are useful when creating new identifiers -/// that must not match any existing identifiers, e.g. during macro expansion -/// and syntax desugaring. Because gensyms should always be identifiers, all -/// gensym operations are on `Ident` rather than `Symbol`. (Indeed, in the -/// future the gensym-ness may be moved from `Symbol` to hygiene data.) -/// -/// Examples: -/// ``` -/// assert_eq!(Ident::from_str("_"), Ident::from_str("_")) -/// assert_ne!(Ident::from_str("_").gensym_if_underscore(), Ident::from_str("_")) -/// assert_ne!( -/// Ident::from_str("_").gensym_if_underscore(), -/// Ident::from_str("_").gensym_if_underscore(), -/// ) -/// ``` -/// Internally, a symbol is implemented as an index, and all operations +/// Internally, a `Symbol` is implemented as an index, and all operations /// (including hashing, equality, and ordering) operate on that index. The use /// of `rustc_index::newtype_index!` means that `Option` only takes up 4 bytes, /// because `rustc_index::newtype_index!` reserves the last 256 values for tagging purposes. @@ -950,12 +921,9 @@ impl Symbol { }) } - /// Convert to an `InternedString`. This is a slowish operation because it - /// requires locking the symbol interner. + /// Convert to an `InternedString`. pub fn as_interned_str(self) -> InternedString { - with_interner(|interner| InternedString { - symbol: interner.interned(self) - }) + InternedString { symbol: self } } pub fn as_u32(self) -> u32 { @@ -965,12 +933,7 @@ impl Symbol { impl fmt::Debug for Symbol { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let is_gensymed = with_interner(|interner| interner.is_gensymed(*self)); - if is_gensymed { - write!(f, "{}({:?})", self, self.0) - } else { - write!(f, "{}", self) - } + fmt::Display::fmt(self, f) } } @@ -993,15 +956,11 @@ impl Decodable for Symbol { } // The `&'static str`s in this type actually point into the arena. -// -// Note that normal symbols are indexed upward from 0, and gensyms are indexed -// downward from SymbolIndex::MAX_AS_U32. #[derive(Default)] pub struct Interner { arena: DroplessArena, names: FxHashMap<&'static str, Symbol>, strings: Vec<&'static str>, - gensyms: Vec, } impl Interner { @@ -1034,34 +993,10 @@ impl Interner { self.names.insert(string, name); name } - - fn interned(&self, symbol: Symbol) -> Symbol { - if (symbol.0.as_usize()) < self.strings.len() { - symbol - } else { - self.gensyms[(SymbolIndex::MAX_AS_U32 - symbol.0.as_u32()) as usize] - } - } - - fn gensymed(&mut self, symbol: Symbol) -> Symbol { - self.gensyms.push(symbol); - Symbol::new(SymbolIndex::MAX_AS_U32 - self.gensyms.len() as u32 + 1) - } - - fn is_gensymed(&mut self, symbol: Symbol) -> bool { - symbol.0.as_usize() >= self.strings.len() - } - // Get the symbol as a string. `Symbol::as_str()` should be used in // preference to this function. pub fn get(&self, symbol: Symbol) -> &str { - match self.strings.get(symbol.0.as_usize()) { - Some(string) => string, - None => { - let symbol = self.gensyms[(SymbolIndex::MAX_AS_U32 - symbol.0.as_u32()) as usize]; - self.strings[symbol.0.as_usize()] - } - } + self.strings[symbol.0.as_usize()] } } @@ -1246,19 +1181,12 @@ impl fmt::Display for LocalInternedString { } } -/// An alternative to `Symbol` that is focused on string contents. It has two -/// main differences to `Symbol`. +/// An alternative to `Symbol` that is focused on string contents. /// -/// First, its implementations of `Hash`, `PartialOrd` and `Ord` work with the +/// Its implementations of `Hash`, `PartialOrd` and `Ord` work with the /// string chars rather than the symbol integer. This is useful when hash /// stability is required across compile sessions, or a guaranteed sort /// ordering is required. -/// -/// Second, gensym-ness is irrelevant. E.g.: -/// ``` -/// assert_ne!(Symbol::gensym("x"), Symbol::gensym("x")) -/// assert_eq!(Symbol::gensym("x").as_interned_str(), Symbol::gensym("x").as_interned_str()) -/// ``` #[derive(Clone, Copy, PartialEq, Eq)] pub struct InternedString { symbol: Symbol, diff --git a/src/libsyntax_pos/symbol/tests.rs b/src/libsyntax_pos/symbol/tests.rs index 1b91c9bb845a4..f74b9a0cd1d1d 100644 --- a/src/libsyntax_pos/symbol/tests.rs +++ b/src/libsyntax_pos/symbol/tests.rs @@ -14,13 +14,6 @@ fn interner_tests() { assert_eq!(i.intern("cat"), Symbol::new(1)); // dog is still at zero assert_eq!(i.intern("dog"), Symbol::new(0)); - let z = i.intern("zebra"); - assert_eq!(i.gensymed(z), Symbol::new(SymbolIndex::MAX_AS_U32)); - // gensym of same string gets new number: - assert_eq!(i.gensymed(z), Symbol::new(SymbolIndex::MAX_AS_U32 - 1)); - // gensym of *existing* string gets new number: - let d = i.intern("dog"); - assert_eq!(i.gensymed(d), Symbol::new(SymbolIndex::MAX_AS_U32 - 2)); } #[test] From 4198df1f4be969747bc92254185ae4983e8f3c5c Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Sat, 31 Aug 2019 16:41:13 +0100 Subject: [PATCH 27/27] Remove some mentions of gensyms --- src/librustc/ty/print/pretty.rs | 2 +- src/libsyntax/ext/proc_macro_server.rs | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/librustc/ty/print/pretty.rs b/src/librustc/ty/print/pretty.rs index c4967f8d66da2..363109a0582df 100644 --- a/src/librustc/ty/print/pretty.rs +++ b/src/librustc/ty/print/pretty.rs @@ -1483,7 +1483,7 @@ impl FmtPrinter<'_, 'tcx, F> { } // Replace any anonymous late-bound regions with named - // variants, using gensym'd identifiers, so that we can + // variants, using new unique identifiers, so that we can // clearly differentiate between named and unnamed regions in // the output. We'll probably want to tweak this over time to // decide just how much information to give. diff --git a/src/libsyntax/ext/proc_macro_server.rs b/src/libsyntax/ext/proc_macro_server.rs index 021ec46d987cf..63e974e323ab3 100644 --- a/src/libsyntax/ext/proc_macro_server.rs +++ b/src/libsyntax/ext/proc_macro_server.rs @@ -332,8 +332,7 @@ impl Ident { if !Self::is_valid(&string) { panic!("`{:?}` is not a valid identifier", string) } - // Get rid of gensyms to conservatively check rawness on the string contents only. - if is_raw && !sym.as_interned_str().as_symbol().can_be_raw() { + if is_raw && !sym.can_be_raw() { panic!("`{}` cannot be a raw identifier", string); } Ident { sym, is_raw, span }