From fb4d42ee6c7a66711baf40ab47b209689d9d26ae Mon Sep 17 00:00:00 2001 From: kennytm Date: Thu, 17 May 2018 04:24:10 +0800 Subject: [PATCH 01/11] Make sure the float comparison output is consistent with the expected behavior when NaN is involved. --- src/librustc_mir/interpret/operator.rs | 13 +++--- src/test/run-pass/issue-50811.rs | 65 ++++++++++++++++++++++++++ 2 files changed, 71 insertions(+), 7 deletions(-) create mode 100644 src/test/run-pass/issue-50811.rs diff --git a/src/librustc_mir/interpret/operator.rs b/src/librustc_mir/interpret/operator.rs index ef6deab047750..a4a36b0b35581 100644 --- a/src/librustc_mir/interpret/operator.rs +++ b/src/librustc_mir/interpret/operator.rs @@ -1,7 +1,6 @@ use rustc::mir; use rustc::ty::{self, Ty}; use syntax::ast::FloatTy; -use std::cmp::Ordering; use rustc::ty::layout::LayoutOf; use rustc_apfloat::ieee::{Double, Single}; use rustc_apfloat::Float; @@ -181,12 +180,12 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { let l = <$ty>::from_bits(l); let r = <$ty>::from_bits(r); let val = match bin_op { - Eq => PrimVal::from_bool(l.partial_cmp(&r).unwrap_or(Ordering::Greater) == Ordering::Equal), - Ne => PrimVal::from_bool(l.partial_cmp(&r).unwrap_or(Ordering::Greater) != Ordering::Equal), - Lt => PrimVal::from_bool(l.partial_cmp(&r).unwrap_or(Ordering::Greater) == Ordering::Less), - Le => PrimVal::from_bool(l.partial_cmp(&r).unwrap_or(Ordering::Greater) != Ordering::Greater), - Gt => PrimVal::from_bool(l.partial_cmp(&r).unwrap_or(Ordering::Greater) == Ordering::Greater), - Ge => PrimVal::from_bool(l.partial_cmp(&r).unwrap_or(Ordering::Greater) != Ordering::Less), + Eq => PrimVal::from_bool(l == r), + Ne => PrimVal::from_bool(l != r), + Lt => PrimVal::from_bool(l < r), + Le => PrimVal::from_bool(l <= r), + Gt => PrimVal::from_bool(l > r), + Ge => PrimVal::from_bool(l >= r), Add => PrimVal::Bytes((l + r).value.to_bits()), Sub => PrimVal::Bytes((l - r).value.to_bits()), Mul => PrimVal::Bytes((l * r).value.to_bits()), diff --git a/src/test/run-pass/issue-50811.rs b/src/test/run-pass/issue-50811.rs new file mode 100644 index 0000000000000..05b168d98f1f2 --- /dev/null +++ b/src/test/run-pass/issue-50811.rs @@ -0,0 +1,65 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(test)] + +extern crate test; + +use std::f64::{NAN, NEG_INFINITY, INFINITY, MAX}; +use std::mem::size_of; +use test::black_box; + +// Ensure the const-eval result and runtime result of float comparison are equivalent. + +macro_rules! compare { + ($op:tt) => { + compare!( + [NEG_INFINITY, -MAX, -1.0, -0.0, 0.0, 1.0, MAX, INFINITY, NAN], + $op + ); + }; + ([$($lhs:expr),+], $op:tt) => { + $(compare!( + $lhs, + $op, + [NEG_INFINITY, -MAX, -1.0, -0.0, 0.0, 1.0, MAX, INFINITY, NAN] + );)+ + }; + ($lhs:expr, $op:tt, [$($rhs:expr),+]) => { + $({ + // Wrap the check in its own function to reduce time needed to borrowck. + fn check() { + static CONST_EVAL: bool = $lhs $op $rhs; + let runtime_eval = black_box($lhs) $op black_box($rhs); + assert_eq!(CONST_EVAL, runtime_eval, stringify!($lhs $op $rhs)); + assert_eq!( + size_of::<[u8; ($lhs $op $rhs) as usize]>(), + runtime_eval as usize, + stringify!($lhs $op $rhs (forced const eval)) + ); + } + check(); + })+ + }; +} + +fn main() { + assert_eq!(0.0/0.0 < 0.0/0.0, false); + assert_eq!(0.0/0.0 > 0.0/0.0, false); + assert_eq!(NAN < NAN, false); + assert_eq!(NAN > NAN, false); + + compare!(==); + compare!(!=); + compare!(<); + compare!(<=); + compare!(>); + compare!(>=); +} From a6e0f040e7e7418be609c23cb7f7059f9d7a4b25 Mon Sep 17 00:00:00 2001 From: QuietMisdreavus Date: Wed, 23 May 2018 16:22:18 -0500 Subject: [PATCH 02/11] rustdoc: hide macro export statements from docs --- src/librustdoc/clean/inline.rs | 3 +++ src/librustdoc/visit_ast.rs | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index a8f4848bf89f2..782c8bf6dd177 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -97,6 +97,9 @@ pub fn try_inline(cx: &DocContext, def: Def, name: ast::Name, visited: &mut FxHa record_extern_fqn(cx, did, clean::TypeKind::Const); clean::ConstantItem(build_const(cx, did)) } + // Macros are eagerly inlined back in visit_ast, don't show their export statements + // FIXME(50647): the eager inline does not take doc(hidden)/doc(no_inline) into account + Def::Macro(..) => return Some(Vec::new()), _ => return None, }; cx.renderinfo.borrow_mut().inlined.insert(did); diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 6db02cc6cc105..8c2555c4b3de2 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -219,6 +219,8 @@ impl<'a, 'tcx, 'rcx> RustdocVisitor<'a, 'tcx, 'rcx> { if let Some(exports) = self.cx.tcx.module_exports(def_id) { for export in exports.iter().filter(|e| e.vis == Visibility::Public) { if let Def::Macro(def_id, ..) = export.def { + // FIXME(50647): this eager macro inlining does not take + // doc(hidden)/doc(no_inline) into account if def_id.krate == LOCAL_CRATE { continue // These are `krate.exported_macros`, handled in `self.visit()`. } @@ -237,6 +239,7 @@ impl<'a, 'tcx, 'rcx> RustdocVisitor<'a, 'tcx, 'rcx> { unreachable!() }; + debug!("inlining macro {}", def.ident.name); om.macros.push(Macro { def_id, attrs: def.attrs.clone().into(), @@ -561,6 +564,7 @@ impl<'a, 'tcx, 'rcx> RustdocVisitor<'a, 'tcx, 'rcx> { // convert each exported_macro into a doc item fn visit_local_macro(&self, def: &hir::MacroDef) -> Macro { + debug!("visit_local_macro: {}", def.name); let tts = def.body.trees().collect::>(); // Extract the spans of all matchers. They represent the "interface" of the macro. let matchers = tts.chunks(4).map(|arm| arm[0].span()).collect(); From 451a9ced73fd7107dc9eb6dd65dd250aaa57fad6 Mon Sep 17 00:00:00 2001 From: QuietMisdreavus Date: Wed, 23 May 2018 16:39:47 -0500 Subject: [PATCH 03/11] update "pub-use-extern-macros" test to hide the regular import statement --- src/test/rustdoc/pub-use-extern-macros.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/test/rustdoc/pub-use-extern-macros.rs b/src/test/rustdoc/pub-use-extern-macros.rs index 57d54585d84bc..2c1f2bf0be4f4 100644 --- a/src/test/rustdoc/pub-use-extern-macros.rs +++ b/src/test/rustdoc/pub-use-extern-macros.rs @@ -15,6 +15,7 @@ extern crate macros; // @has pub_use_extern_macros/macro.bar.html +// @!has pub_use_extern_macros/index.html 'pub use macros::bar;' pub use macros::bar; // @has pub_use_extern_macros/macro.baz.html From 24815d3a68393620efd40c83ecf64efe5349af13 Mon Sep 17 00:00:00 2001 From: QuietMisdreavus Date: Wed, 23 May 2018 20:53:45 -0500 Subject: [PATCH 04/11] fix @!has conditions in pub-use-extern-macros test --- src/test/rustdoc/pub-use-extern-macros.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/test/rustdoc/pub-use-extern-macros.rs b/src/test/rustdoc/pub-use-extern-macros.rs index 2c1f2bf0be4f4..a6e707cc2adea 100644 --- a/src/test/rustdoc/pub-use-extern-macros.rs +++ b/src/test/rustdoc/pub-use-extern-macros.rs @@ -15,15 +15,15 @@ extern crate macros; // @has pub_use_extern_macros/macro.bar.html -// @!has pub_use_extern_macros/index.html 'pub use macros::bar;' +// @!has pub_use_extern_macros/index.html '//code' 'pub use macros::bar;' pub use macros::bar; // @has pub_use_extern_macros/macro.baz.html -// @!has pub_use_extern_macros/index.html 'pub use macros::baz;' +// @!has pub_use_extern_macros/index.html '//code' 'pub use macros::baz;' #[doc(inline)] pub use macros::baz; // @has pub_use_extern_macros/macro.quux.html -// @!has pub_use_extern_macros/index.html 'pub use macros::quux;' +// @!has pub_use_extern_macros/index.html '//code' 'pub use macros::quux;' #[doc(hidden)] pub use macros::quux; From 068f4e00d4617430ece73cc6db19fac137bca297 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 19 May 2018 01:13:53 +0300 Subject: [PATCH 05/11] [beta] Fix naming conventions for new lints --- .../src/lints/listing/allowed-by-default.md | 2 +- src/librustc/hir/lowering.rs | 2 +- src/librustc/lint/builtin.rs | 20 +++++++++---------- src/librustc/lint/mod.rs | 2 +- src/librustc/middle/resolve_lifetime.rs | 4 ++-- src/librustc_lint/builtin.rs | 6 +++--- src/librustc_lint/lib.rs | 15 +++++++++----- src/librustc_resolve/lib.rs | 2 +- src/librustc_typeck/check/method/probe.rs | 2 +- .../trait-bounds-not-on-struct.rs | 2 +- src/test/compile-fail/useless_comment.rs | 2 +- src/test/ui/edition-lint-paths.rs | 2 +- src/test/ui/edition-lint-paths.stderr | 4 ++-- .../ui/in-band-lifetimes/ellided-lifetimes.rs | 2 +- .../ellided-lifetimes.stderr | 4 ++-- .../single_use_lifetimes-2.rs | 2 +- .../single_use_lifetimes-2.stderr | 4 ++-- .../single_use_lifetimes-3.rs | 2 +- .../single_use_lifetimes-3.stderr | 4 ++-- .../single_use_lifetimes-4.rs | 2 +- .../single_use_lifetimes-4.stderr | 4 ++-- .../single_use_lifetimes-5.rs | 2 +- .../single_use_lifetimes-5.stderr | 4 ++-- .../in-band-lifetimes/single_use_lifetimes.rs | 2 +- .../single_use_lifetimes.stderr | 4 ++-- src/test/ui/inference_unstable.stderr | 2 +- 26 files changed, 54 insertions(+), 49 deletions(-) diff --git a/src/doc/rustc/src/lints/listing/allowed-by-default.md b/src/doc/rustc/src/lints/listing/allowed-by-default.md index e1a3f96a6fe6e..7768b41f85ee4 100644 --- a/src/doc/rustc/src/lints/listing/allowed-by-default.md +++ b/src/doc/rustc/src/lints/listing/allowed-by-default.md @@ -64,7 +64,7 @@ To fix it, do as the help message suggests: ```rust #![feature(dyn_trait)] -#![deny(bare_trait_object)] +#![deny(bare_trait_objects)] trait Trait { } diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 51f0c1d7047c9..25eaff89d5511 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -4122,7 +4122,7 @@ impl<'a> LoweringContext<'a> { fn maybe_lint_bare_trait(&self, span: Span, id: NodeId, is_global: bool) { self.sess.buffer_lint_with_diagnostic( - builtin::BARE_TRAIT_OBJECT, + builtin::BARE_TRAIT_OBJECTS, id, span, "trait objects without an explicit `dyn` are deprecated", diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index 175b44991fdfe..2ec31cca81caa 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -231,7 +231,7 @@ declare_lint! { } declare_lint! { - pub SINGLE_USE_LIFETIME, + pub SINGLE_USE_LIFETIMES, Allow, "detects single use lifetimes" } @@ -243,19 +243,19 @@ declare_lint! { } declare_lint! { - pub ELIDED_LIFETIME_IN_PATH, + pub ELIDED_LIFETIMES_IN_PATHS, Allow, "hidden lifetime parameters are deprecated, try `Foo<'_>`" } declare_lint! { - pub BARE_TRAIT_OBJECT, + pub BARE_TRAIT_OBJECTS, Allow, "suggest using `dyn Trait` for trait objects" } declare_lint! { - pub ABSOLUTE_PATH_STARTING_WITH_MODULE, + pub ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE, Allow, "fully qualified paths that start with a module name \ instead of `crate`, `self`, or an extern crate name" @@ -268,7 +268,7 @@ declare_lint! { } declare_lint! { - pub UNSTABLE_NAME_COLLISION, + pub UNSTABLE_NAME_COLLISIONS, Warn, "detects name collision with an existing but unstable method" } @@ -317,12 +317,12 @@ impl LintPass for HardwiredLints { DEPRECATED, UNUSED_UNSAFE, UNUSED_MUT, - SINGLE_USE_LIFETIME, + SINGLE_USE_LIFETIMES, TYVAR_BEHIND_RAW_POINTER, - ELIDED_LIFETIME_IN_PATH, - BARE_TRAIT_OBJECT, - ABSOLUTE_PATH_STARTING_WITH_MODULE, - UNSTABLE_NAME_COLLISION, + ELIDED_LIFETIMES_IN_PATHS, + BARE_TRAIT_OBJECTS, + ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE, + UNSTABLE_NAME_COLLISIONS, ) } } diff --git a/src/librustc/lint/mod.rs b/src/librustc/lint/mod.rs index d6c6f9dc0f61a..ea5c990d5f92c 100644 --- a/src/librustc/lint/mod.rs +++ b/src/librustc/lint/mod.rs @@ -505,7 +505,7 @@ pub fn struct_lint_level<'a>(sess: &'a Session, "this was previously accepted by the compiler but is being phased out; \ it will become a hard error"; - let explanation = if lint_id == LintId::of(::lint::builtin::UNSTABLE_NAME_COLLISION) { + let explanation = if lint_id == LintId::of(::lint::builtin::UNSTABLE_NAME_COLLISIONS) { "once this method is added to the standard library, \ the ambiguity may cause an error or change in behavior!" .to_owned() diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index ceda72dcd7ae0..a4b1dd77bbb89 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -1290,7 +1290,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { this.tcx .struct_span_lint_node( - lint::builtin::SINGLE_USE_LIFETIME, + lint::builtin::SINGLE_USE_LIFETIMES, id, span, &format!( @@ -1901,7 +1901,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { if deprecated { self.tcx .struct_span_lint_node( - lint::builtin::ELIDED_LIFETIME_IN_PATH, + lint::builtin::ELIDED_LIFETIMES_IN_PATHS, id, span, &format!("hidden lifetime parameters are deprecated, try `Foo<'_>`"), diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 817abe2ceeb76..cf6406800e122 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -694,7 +694,7 @@ impl EarlyLintPass for DeprecatedAttr { } declare_lint! { - pub UNUSED_DOC_COMMENT, + pub UNUSED_DOC_COMMENTS, Warn, "detects doc comments that aren't used by rustdoc" } @@ -704,7 +704,7 @@ pub struct UnusedDocComment; impl LintPass for UnusedDocComment { fn get_lints(&self) -> LintArray { - lint_array![UNUSED_DOC_COMMENT] + lint_array![UNUSED_DOC_COMMENTS] } } @@ -713,7 +713,7 @@ impl UnusedDocComment { I: Iterator, C: LintContext<'tcx>>(&self, mut attrs: I, cx: &C) { if let Some(attr) = attrs.find(|a| a.is_value_str() && a.check_name("doc")) { - cx.struct_span_lint(UNUSED_DOC_COMMENT, attr.span, "doc comment not used by rustdoc") + cx.struct_span_lint(UNUSED_DOC_COMMENTS, attr.span, "doc comment not used by rustdoc") .emit(); } } diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index 074fa914f3772..559c245987602 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -40,7 +40,7 @@ extern crate rustc_target; extern crate syntax_pos; use rustc::lint; -use rustc::lint::builtin::{BARE_TRAIT_OBJECT, ABSOLUTE_PATH_STARTING_WITH_MODULE}; +use rustc::lint::builtin::{BARE_TRAIT_OBJECTS, ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE}; use rustc::session; use rustc::util; @@ -172,14 +172,14 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) { UNUSED_ATTRIBUTES, UNUSED_MACROS, UNUSED_ALLOCATION, - UNUSED_DOC_COMMENT, + UNUSED_DOC_COMMENTS, UNUSED_EXTERN_CRATES, UNUSED_FEATURES, UNUSED_PARENS); add_lint_group!(sess, "rust_2018_migration", - BARE_TRAIT_OBJECT, + BARE_TRAIT_OBJECTS, UNREACHABLE_PUB); // Guidelines for creating a future incompatibility lint: @@ -273,20 +273,25 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) { edition: Some(Edition::Edition2018), }, FutureIncompatibleInfo { - id: LintId::of(UNSTABLE_NAME_COLLISION), + id: LintId::of(UNSTABLE_NAME_COLLISIONS), reference: "issue #48919 ", edition: None, // Note: this item represents future incompatibility of all unstable functions in the // standard library, and thus should never be removed or changed to an error. }, FutureIncompatibleInfo { - id: LintId::of(ABSOLUTE_PATH_STARTING_WITH_MODULE), + id: LintId::of(ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE), reference: "issue TBD", edition: Some(Edition::Edition2018), }, ]); // Register renamed and removed lints + store.register_renamed("single_use_lifetime", "single_use_lifetimes"); + store.register_renamed("elided_lifetime_in_path", "elided_lifetimes_in_paths"); + store.register_renamed("bare_trait_object", "bare_trait_objects"); + store.register_renamed("unstable_name_collision", "unstable_name_collisions"); + store.register_renamed("unused_doc_comment", "unused_doc_comments"); store.register_renamed("unknown_features", "unused_features"); store.register_removed("unsigned_negation", "replaced by negate_unsigned feature gate"); store.register_removed("negate_unsigned", "cast a signed value instead"); diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 0f931d4374e59..cf0df30b93d7c 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -3367,7 +3367,7 @@ impl<'a> Resolver<'a> { let diag = lint::builtin::BuiltinLintDiagnostics ::AbsPathWithModule(path_span); self.session.buffer_lint_with_diagnostic( - lint::builtin::ABSOLUTE_PATH_STARTING_WITH_MODULE, + lint::builtin::ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE, id, path_span, "Absolute paths must start with `self`, `super`, \ `crate`, or an external crate name in the 2018 edition", diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 907c80f0daf5e..ecaa1dad033a3 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -1056,7 +1056,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { unstable_candidates: &[(&Candidate<'tcx>, Symbol)], ) { let mut diag = self.tcx.struct_span_lint_node( - lint::builtin::UNSTABLE_NAME_COLLISION, + lint::builtin::UNSTABLE_NAME_COLLISIONS, self.fcx.body_id, self.span, "a method with this name may be added to the standard library in the future", diff --git a/src/test/compile-fail/trait-bounds-not-on-struct.rs b/src/test/compile-fail/trait-bounds-not-on-struct.rs index 1b1a238a941e5..76bbca606580d 100644 --- a/src/test/compile-fail/trait-bounds-not-on-struct.rs +++ b/src/test/compile-fail/trait-bounds-not-on-struct.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![allow(bare_trait_object)] +#![allow(bare_trait_objects)] struct Foo; diff --git a/src/test/compile-fail/useless_comment.rs b/src/test/compile-fail/useless_comment.rs index 90eb66728fce5..645514971dacd 100644 --- a/src/test/compile-fail/useless_comment.rs +++ b/src/test/compile-fail/useless_comment.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![deny(unused_doc_comment)] +#![deny(unused_doc_comments)] fn foo() { /// a //~ ERROR doc comment not used by rustdoc diff --git a/src/test/ui/edition-lint-paths.rs b/src/test/ui/edition-lint-paths.rs index 0b49e72ccd94c..8164a862a18eb 100644 --- a/src/test/ui/edition-lint-paths.rs +++ b/src/test/ui/edition-lint-paths.rs @@ -9,7 +9,7 @@ // except according to those terms. #![feature(crate_in_paths)] -#![deny(absolute_path_starting_with_module)] +#![deny(absolute_paths_not_starting_with_crate)] #![allow(unused)] pub mod foo { diff --git a/src/test/ui/edition-lint-paths.stderr b/src/test/ui/edition-lint-paths.stderr index 509527e03743c..fca6edfc0558d 100644 --- a/src/test/ui/edition-lint-paths.stderr +++ b/src/test/ui/edition-lint-paths.stderr @@ -7,8 +7,8 @@ LL | use ::bar::Bar; note: lint level defined here --> $DIR/edition-lint-paths.rs:12:9 | -LL | #![deny(absolute_path_starting_with_module)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #![deny(absolute_paths_not_starting_with_crate)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition! = note: for more information, see issue TBD diff --git a/src/test/ui/in-band-lifetimes/ellided-lifetimes.rs b/src/test/ui/in-band-lifetimes/ellided-lifetimes.rs index 5151abd68232c..3739ffe6a2648 100644 --- a/src/test/ui/in-band-lifetimes/ellided-lifetimes.rs +++ b/src/test/ui/in-band-lifetimes/ellided-lifetimes.rs @@ -9,7 +9,7 @@ // except according to those terms. #![allow(warnings)] #![allow(unused_variables, dead_code, unused, bad_style)] -#![deny(elided_lifetime_in_path)] +#![deny(elided_lifetimes_in_paths)] struct Foo<'a> { x: &'a u32 } fn foo(x: &Foo) { diff --git a/src/test/ui/in-band-lifetimes/ellided-lifetimes.stderr b/src/test/ui/in-band-lifetimes/ellided-lifetimes.stderr index ba58ca1ed9597..c2bd2c261ac46 100644 --- a/src/test/ui/in-band-lifetimes/ellided-lifetimes.stderr +++ b/src/test/ui/in-band-lifetimes/ellided-lifetimes.stderr @@ -7,8 +7,8 @@ LL | fn foo(x: &Foo) { note: lint level defined here --> $DIR/ellided-lifetimes.rs:12:9 | -LL | #![deny(elided_lifetime_in_path)] - | ^^^^^^^^^^^^^^^^^^^^^^^ +LL | #![deny(elided_lifetimes_in_paths)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/in-band-lifetimes/single_use_lifetimes-2.rs b/src/test/ui/in-band-lifetimes/single_use_lifetimes-2.rs index 005f1f033b6eb..6aa95bc3ee522 100644 --- a/src/test/ui/in-band-lifetimes/single_use_lifetimes-2.rs +++ b/src/test/ui/in-band-lifetimes/single_use_lifetimes-2.rs @@ -7,7 +7,7 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. -#![deny(single_use_lifetime)] +#![deny(single_use_lifetimes)] // FIXME(#44752) -- this scenario should not be warned fn deref<'x>() -> &'x u32 { //~ ERROR lifetime name `'x` only used once 22 diff --git a/src/test/ui/in-band-lifetimes/single_use_lifetimes-2.stderr b/src/test/ui/in-band-lifetimes/single_use_lifetimes-2.stderr index 38d05369fb845..33d35de93564e 100644 --- a/src/test/ui/in-band-lifetimes/single_use_lifetimes-2.stderr +++ b/src/test/ui/in-band-lifetimes/single_use_lifetimes-2.stderr @@ -7,8 +7,8 @@ LL | fn deref<'x>() -> &'x u32 { //~ ERROR lifetime name `'x` only used once note: lint level defined here --> $DIR/single_use_lifetimes-2.rs:10:9 | -LL | #![deny(single_use_lifetime)] - | ^^^^^^^^^^^^^^^^^^^ +LL | #![deny(single_use_lifetimes)] + | ^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/in-band-lifetimes/single_use_lifetimes-3.rs b/src/test/ui/in-band-lifetimes/single_use_lifetimes-3.rs index 263548ca7f4dd..1855ec7b5ac5a 100644 --- a/src/test/ui/in-band-lifetimes/single_use_lifetimes-3.rs +++ b/src/test/ui/in-band-lifetimes/single_use_lifetimes-3.rs @@ -7,7 +7,7 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. -#![deny(single_use_lifetime)] +#![deny(single_use_lifetimes)] struct Foo<'x> { //~ ERROR lifetime name `'x` only used once x: &'x u32 // no warning! } diff --git a/src/test/ui/in-band-lifetimes/single_use_lifetimes-3.stderr b/src/test/ui/in-band-lifetimes/single_use_lifetimes-3.stderr index 49c06aafbe550..8226f2fdffd5f 100644 --- a/src/test/ui/in-band-lifetimes/single_use_lifetimes-3.stderr +++ b/src/test/ui/in-band-lifetimes/single_use_lifetimes-3.stderr @@ -7,8 +7,8 @@ LL | struct Foo<'x> { //~ ERROR lifetime name `'x` only used once note: lint level defined here --> $DIR/single_use_lifetimes-3.rs:10:9 | -LL | #![deny(single_use_lifetime)] - | ^^^^^^^^^^^^^^^^^^^ +LL | #![deny(single_use_lifetimes)] + | ^^^^^^^^^^^^^^^^^^^^ error: lifetime name `'y` only used once --> $DIR/single_use_lifetimes-3.rs:16:6 diff --git a/src/test/ui/in-band-lifetimes/single_use_lifetimes-4.rs b/src/test/ui/in-band-lifetimes/single_use_lifetimes-4.rs index 4ac8f8c0d4e22..97982ff53b524 100644 --- a/src/test/ui/in-band-lifetimes/single_use_lifetimes-4.rs +++ b/src/test/ui/in-band-lifetimes/single_use_lifetimes-4.rs @@ -7,7 +7,7 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. -#![deny(single_use_lifetime)] +#![deny(single_use_lifetimes)] // Neither should issue a warning, as explicit lifetimes are mandatory in this case struct Foo<'x> { //~ ERROR lifetime name `'x` only used once x: &'x u32 diff --git a/src/test/ui/in-band-lifetimes/single_use_lifetimes-4.stderr b/src/test/ui/in-band-lifetimes/single_use_lifetimes-4.stderr index 2df370f5d0221..fbe6f2d18674b 100644 --- a/src/test/ui/in-band-lifetimes/single_use_lifetimes-4.stderr +++ b/src/test/ui/in-band-lifetimes/single_use_lifetimes-4.stderr @@ -7,8 +7,8 @@ LL | struct Foo<'x> { //~ ERROR lifetime name `'x` only used once note: lint level defined here --> $DIR/single_use_lifetimes-4.rs:10:9 | -LL | #![deny(single_use_lifetime)] - | ^^^^^^^^^^^^^^^^^^^ +LL | #![deny(single_use_lifetimes)] + | ^^^^^^^^^^^^^^^^^^^^ error: lifetime name `'x` only used once --> $DIR/single_use_lifetimes-4.rs:16:10 diff --git a/src/test/ui/in-band-lifetimes/single_use_lifetimes-5.rs b/src/test/ui/in-band-lifetimes/single_use_lifetimes-5.rs index cef904c48962c..e9f3cb9a13749 100644 --- a/src/test/ui/in-band-lifetimes/single_use_lifetimes-5.rs +++ b/src/test/ui/in-band-lifetimes/single_use_lifetimes-5.rs @@ -7,7 +7,7 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. -#![deny(single_use_lifetime)] +#![deny(single_use_lifetimes)] // Should not issue a warning, as explicit lifetimes are mandatory in this case: trait Foo<'x> { //~ ERROR lifetime name `'x` only used once fn foo(&self, arg: &'x u32); diff --git a/src/test/ui/in-band-lifetimes/single_use_lifetimes-5.stderr b/src/test/ui/in-band-lifetimes/single_use_lifetimes-5.stderr index eec426e4e63ab..bb96fd2600609 100644 --- a/src/test/ui/in-band-lifetimes/single_use_lifetimes-5.stderr +++ b/src/test/ui/in-band-lifetimes/single_use_lifetimes-5.stderr @@ -7,8 +7,8 @@ LL | trait Foo<'x> { //~ ERROR lifetime name `'x` only used once note: lint level defined here --> $DIR/single_use_lifetimes-5.rs:10:9 | -LL | #![deny(single_use_lifetime)] - | ^^^^^^^^^^^^^^^^^^^ +LL | #![deny(single_use_lifetimes)] + | ^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/in-band-lifetimes/single_use_lifetimes.rs b/src/test/ui/in-band-lifetimes/single_use_lifetimes.rs index a97056b6240ec..af3457523ca62 100644 --- a/src/test/ui/in-band-lifetimes/single_use_lifetimes.rs +++ b/src/test/ui/in-band-lifetimes/single_use_lifetimes.rs @@ -7,7 +7,7 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. -#![deny(single_use_lifetime)] +#![deny(single_use_lifetimes)] fn deref<'x>(v: &'x u32) -> u32 { //~ ERROR lifetime name `'x` only used once *v diff --git a/src/test/ui/in-band-lifetimes/single_use_lifetimes.stderr b/src/test/ui/in-band-lifetimes/single_use_lifetimes.stderr index 15917d3c08562..a96f5c5c4e709 100644 --- a/src/test/ui/in-band-lifetimes/single_use_lifetimes.stderr +++ b/src/test/ui/in-band-lifetimes/single_use_lifetimes.stderr @@ -7,8 +7,8 @@ LL | fn deref<'x>(v: &'x u32) -> u32 { //~ ERROR lifetime name `'x` only used on note: lint level defined here --> $DIR/single_use_lifetimes.rs:10:9 | -LL | #![deny(single_use_lifetime)] - | ^^^^^^^^^^^^^^^^^^^ +LL | #![deny(single_use_lifetimes)] + | ^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/inference_unstable.stderr b/src/test/ui/inference_unstable.stderr index a217bc57b3670..3a5cb6f2b2e0f 100644 --- a/src/test/ui/inference_unstable.stderr +++ b/src/test/ui/inference_unstable.stderr @@ -4,7 +4,7 @@ warning: a method with this name may be added to the standard library in the fut LL | assert_eq!('x'.ipu_flatten(), 1); | ^^^^^^^^^^^ | - = note: #[warn(unstable_name_collision)] on by default + = note: #[warn(unstable_name_collisions)] on by default = warning: once this method is added to the standard library, the ambiguity may cause an error or change in behavior! = note: for more information, see issue #48919 = help: call with fully qualified syntax `inference_unstable_itertools::IpuItertools::ipu_flatten(...)` to keep using the current method From 10f8495e732d8d39b580f603b36110173557e9bc Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 24 May 2018 17:34:23 -0400 Subject: [PATCH 06/11] prohibit turbofish in `impl Trait` methods --- src/librustc_typeck/check/method/confirm.rs | 52 +++++++++++-------- src/librustc_typeck/check/method/mod.rs | 14 ++--- src/librustc_typeck/check/mod.rs | 4 +- ...iversal-turbofish-in-method-issue-50950.rs | 27 ++++++++++ ...sal-turbofish-in-method-issue-50950.stderr | 9 ++++ 5 files changed, 75 insertions(+), 31 deletions(-) create mode 100644 src/test/ui/impl-trait/universal-turbofish-in-method-issue-50950.rs create mode 100644 src/test/ui/impl-trait/universal-turbofish-in-method-issue-50950.stderr diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index 09feaaffc5b9d..7c67a9ec0e0f5 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -46,18 +46,21 @@ pub struct ConfirmResult<'tcx> { } impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { - pub fn confirm_method(&self, - span: Span, - self_expr: &'gcx hir::Expr, - call_expr: &'gcx hir::Expr, - unadjusted_self_ty: Ty<'tcx>, - pick: probe::Pick<'tcx>, - segment: &hir::PathSegment) - -> ConfirmResult<'tcx> { - debug!("confirm(unadjusted_self_ty={:?}, pick={:?}, generic_args={:?})", - unadjusted_self_ty, - pick, - segment.parameters); + pub fn confirm_method( + &self, + span: Span, + self_expr: &'gcx hir::Expr, + call_expr: &'gcx hir::Expr, + unadjusted_self_ty: Ty<'tcx>, + pick: probe::Pick<'tcx>, + segment: &hir::PathSegment, + ) -> ConfirmResult<'tcx> { + debug!( + "confirm(unadjusted_self_ty={:?}, pick={:?}, generic_args={:?})", + unadjusted_self_ty, + pick, + segment.parameters, + ); let mut confirm_cx = ConfirmContext::new(self, span, self_expr, call_expr); confirm_cx.confirm(unadjusted_self_ty, pick, segment) @@ -78,11 +81,12 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { } } - fn confirm(&mut self, - unadjusted_self_ty: Ty<'tcx>, - pick: probe::Pick<'tcx>, - segment: &hir::PathSegment) - -> ConfirmResult<'tcx> { + fn confirm( + &mut self, + unadjusted_self_ty: Ty<'tcx>, + pick: probe::Pick<'tcx>, + segment: &hir::PathSegment, + ) -> ConfirmResult<'tcx> { // Adjust the self expression the user provided and obtain the adjusted type. let self_ty = self.adjust_self_ty(unadjusted_self_ty, &pick); @@ -300,17 +304,19 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { }) } - fn instantiate_method_substs(&mut self, - pick: &probe::Pick<'tcx>, - segment: &hir::PathSegment, - parent_substs: &Substs<'tcx>) - -> &'tcx Substs<'tcx> { + fn instantiate_method_substs( + &mut self, + pick: &probe::Pick<'tcx>, + segment: &hir::PathSegment, + parent_substs: &Substs<'tcx>, + ) -> &'tcx Substs<'tcx> { // Determine the values for the generic parameters of the method. // If they were not explicitly supplied, just construct fresh // variables. let method_generics = self.tcx.generics_of(pick.item.def_id); let mut fn_segment = Some((segment, method_generics)); - self.fcx.check_path_parameter_count(self.span, &mut fn_segment, true, false); + let supress_mismatch = self.fcx.check_impl_trait(self.span, fn_segment); + self.fcx.check_path_parameter_count(self.span, &mut fn_segment, true, supress_mismatch); // Create subst for early-bound lifetime parameters, combining // parameters from the type and those from the method. diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index 5f904a9419b1d..03b1203b8792b 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -178,12 +178,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.tcx.check_stability(pick.item.def_id, Some(call_expr.id), span); - let result = self.confirm_method(span, - self_expr, - call_expr, - self_ty, - pick.clone(), - segment); + let result = self.confirm_method( + span, + self_expr, + call_expr, + self_ty, + pick.clone(), + segment, + ); if result.illegal_sized_bound { // We probe again, taking all traits into account (not only those in scope). diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 61c1bdb7110e5..5fc1452e347b0 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -4754,7 +4754,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // variables. If the user provided some types, we may still need // to add defaults. If the user provided *too many* types, that's // a problem. - let supress_mismatch = self.check_impl_trait(span, &mut fn_segment); + let supress_mismatch = self.check_impl_trait(span, fn_segment); self.check_path_parameter_count(span, &mut type_segment, false, supress_mismatch); self.check_path_parameter_count(span, &mut fn_segment, false, supress_mismatch); @@ -5017,7 +5017,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { /// Report error if there is an explicit type parameter when using `impl Trait`. fn check_impl_trait(&self, span: Span, - segment: &mut Option<(&hir::PathSegment, &ty::Generics)>) + segment: Option<(&hir::PathSegment, &ty::Generics)>) -> bool { use hir::SyntheticTyParamKind::*; diff --git a/src/test/ui/impl-trait/universal-turbofish-in-method-issue-50950.rs b/src/test/ui/impl-trait/universal-turbofish-in-method-issue-50950.rs new file mode 100644 index 0000000000000..ac53612d2daac --- /dev/null +++ b/src/test/ui/impl-trait/universal-turbofish-in-method-issue-50950.rs @@ -0,0 +1,27 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::any::Any; +pub struct EventHandler { +} + +impl EventHandler +{ + pub fn handle_event(&mut self, _efunc: impl FnMut(T)) {} +} + +struct TestEvent(i32); + +fn main() { + let mut evt = EventHandler {}; + evt.handle_event::(|_evt| { + //~^ ERROR cannot provide explicit type parameters + }); +} diff --git a/src/test/ui/impl-trait/universal-turbofish-in-method-issue-50950.stderr b/src/test/ui/impl-trait/universal-turbofish-in-method-issue-50950.stderr new file mode 100644 index 0000000000000..fec3f78535ddd --- /dev/null +++ b/src/test/ui/impl-trait/universal-turbofish-in-method-issue-50950.stderr @@ -0,0 +1,9 @@ +error[E0632]: cannot provide explicit type parameters when `impl Trait` is used in argument position. + --> $DIR/universal-turbofish-in-method-issue-50950.rs:24:9 + | +LL | evt.handle_event::(|_evt| { + | ^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0632`. From cfb8cbeb47d8664bdea9e52bf00af7d378ab1d2b Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 24 May 2018 17:34:09 -0400 Subject: [PATCH 07/11] restore emplacement syntax (obsolete) --- src/librustc/hir/lowering.rs | 5 +++- src/librustc_passes/ast_validation.rs | 6 +++++ src/libsyntax/ast.rs | 3 +++ src/libsyntax/feature_gate.rs | 3 +++ src/libsyntax/fold.rs | 3 +++ src/libsyntax/parse/parser.rs | 13 ++++++++++ src/libsyntax/print/pprust.rs | 7 ++++++ src/libsyntax/util/parser.rs | 16 +++++++++---- src/libsyntax/visit.rs | 4 ++++ src/test/ui/obsolete-in-place/bad.bad.stderr | 18 ++++++++++++++ src/test/ui/obsolete-in-place/bad.rs | 25 ++++++++++++++++++++ 11 files changed, 97 insertions(+), 6 deletions(-) create mode 100644 src/test/ui/obsolete-in-place/bad.bad.stderr create mode 100644 src/test/ui/obsolete-in-place/bad.rs diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 25eaff89d5511..f0c1766774e36 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -2932,7 +2932,10 @@ impl<'a> LoweringContext<'a> { fn lower_expr(&mut self, e: &Expr) -> hir::Expr { let kind = match e.node { ExprKind::Box(ref inner) => hir::ExprBox(P(self.lower_expr(inner))), - + ExprKind::ObsoleteInPlace(..) => { + self.sess.abort_if_errors(); + span_bug!(e.span, "encountered ObsoleteInPlace expr during lowering"); + } ExprKind::Array(ref exprs) => { hir::ExprArray(exprs.iter().map(|x| self.lower_expr(x)).collect()) } diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs index 6708640379a54..c85cb1adb9230 100644 --- a/src/librustc_passes/ast_validation.rs +++ b/src/librustc_passes/ast_validation.rs @@ -174,6 +174,12 @@ impl<'a> Visitor<'a> for AstValidator<'a> { ExprKind::InlineAsm(..) if !self.session.target.target.options.allow_asm => { span_err!(self.session, expr.span, E0472, "asm! is unsupported on this target"); } + ExprKind::ObsoleteInPlace(..) => { + self.err_handler() + .struct_span_err(expr.span, "emplacement syntax is obsolete (for now, anyway)") + .note("for more information, see ") + .emit(); + } _ => {} } diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index f8cd6103bdfa1..a965d9115e886 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -997,6 +997,7 @@ impl Expr { pub fn precedence(&self) -> ExprPrecedence { match self.node { ExprKind::Box(_) => ExprPrecedence::Box, + ExprKind::ObsoleteInPlace(..) => ExprPrecedence::ObsoleteInPlace, ExprKind::Array(_) => ExprPrecedence::Array, ExprKind::Call(..) => ExprPrecedence::Call, ExprKind::MethodCall(..) => ExprPrecedence::MethodCall, @@ -1055,6 +1056,8 @@ pub enum RangeLimits { pub enum ExprKind { /// A `box x` expression. Box(P), + /// First expr is the place; second expr is the value. + ObsoleteInPlace(P, P), /// An array (`[a, b, c, d]`) Array(Vec>), /// A function call diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 5155408ba63f3..9838a11372bd4 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -1677,6 +1677,9 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { gate_feature_post!(&self, type_ascription, e.span, "type ascription is experimental"); } + ast::ExprKind::ObsoleteInPlace(..) => { + // these get a hard error in ast-validation + } ast::ExprKind::Yield(..) => { gate_feature_post!(&self, generators, e.span, diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index a0cd831a9ba08..d5f2660c24497 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -1175,6 +1175,9 @@ pub fn noop_fold_expr(Expr {id, node, span, attrs}: Expr, folder: &mu ExprKind::Box(e) => { ExprKind::Box(folder.fold_expr(e)) } + ExprKind::ObsoleteInPlace(a, b) => { + ExprKind::ObsoleteInPlace(folder.fold_expr(a), folder.fold_expr(b)) + } ExprKind::Array(exprs) => { ExprKind::Array(folder.fold_exprs(exprs)) } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index bf4a68679df55..9b828d71246bb 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -2797,6 +2797,17 @@ impl<'a> Parser<'a> { let (span, e) = self.interpolated_or_expr_span(e)?; (lo.to(span), ExprKind::AddrOf(m, e)) } + token::Ident(..) if self.token.is_keyword(keywords::In) => { + self.bump(); + let place = self.parse_expr_res( + Restrictions::NO_STRUCT_LITERAL, + None, + )?; + let blk = self.parse_block()?; + let span = blk.span; + let blk_expr = self.mk_expr(span, ExprKind::Block(blk, None), ThinVec::new()); + (lo.to(span), ExprKind::ObsoleteInPlace(place, blk_expr)) + } token::Ident(..) if self.token.is_keyword(keywords::Box) => { self.bump(); let e = self.parse_prefix_expr(None); @@ -3000,6 +3011,8 @@ impl<'a> Parser<'a> { } AssocOp::Assign => self.mk_expr(span, ExprKind::Assign(lhs, rhs), ThinVec::new()), + AssocOp::ObsoleteInPlace => + self.mk_expr(span, ExprKind::ObsoleteInPlace(lhs, rhs), ThinVec::new()), AssocOp::AssignOp(k) => { let aop = match k { token::Plus => BinOpKind::Add, diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index b8ddb063d9875..cc0943894d1c0 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -2059,6 +2059,13 @@ impl<'a> State<'a> { self.word_space("box")?; self.print_expr_maybe_paren(expr, parser::PREC_PREFIX)?; } + ast::ExprKind::ObsoleteInPlace(ref place, ref expr) => { + let prec = AssocOp::ObsoleteInPlace.precedence() as i8; + self.print_expr_maybe_paren(place, prec + 1)?; + self.s.space()?; + self.word_space("<-")?; + self.print_expr_maybe_paren(expr, prec)?; + } ast::ExprKind::Array(ref exprs) => { self.print_expr_vec(&exprs[..], attrs)?; } diff --git a/src/libsyntax/util/parser.rs b/src/libsyntax/util/parser.rs index 524f9f127f57b..51b535275d649 100644 --- a/src/libsyntax/util/parser.rs +++ b/src/libsyntax/util/parser.rs @@ -56,6 +56,8 @@ pub enum AssocOp { GreaterEqual, /// `=` Assign, + /// `<-` + ObsoleteInPlace, /// `?=` where ? is one of the BinOpToken AssignOp(BinOpToken), /// `as` @@ -84,6 +86,7 @@ impl AssocOp { use self::AssocOp::*; match *t { Token::BinOpEq(k) => Some(AssignOp(k)), + Token::LArrow => Some(ObsoleteInPlace), Token::Eq => Some(Assign), Token::BinOp(BinOpToken::Star) => Some(Multiply), Token::BinOp(BinOpToken::Slash) => Some(Divide), @@ -153,6 +156,7 @@ impl AssocOp { LAnd => 6, LOr => 5, DotDot | DotDotEq => 4, + ObsoleteInPlace => 3, Assign | AssignOp(_) => 2, } } @@ -162,7 +166,7 @@ impl AssocOp { use self::AssocOp::*; // NOTE: it is a bug to have an operators that has same precedence but different fixities! match *self { - Assign | AssignOp(_) => Fixity::Right, + ObsoleteInPlace | Assign | AssignOp(_) => Fixity::Right, As | Multiply | Divide | Modulus | Add | Subtract | ShiftLeft | ShiftRight | BitAnd | BitXor | BitOr | Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual | LAnd | LOr | Colon => Fixity::Left, @@ -174,8 +178,8 @@ impl AssocOp { use self::AssocOp::*; match *self { Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual => true, - Assign | AssignOp(_) | As | Multiply | Divide | Modulus | Add | Subtract | - ShiftLeft | ShiftRight | BitAnd | BitXor | BitOr | LAnd | LOr | + ObsoleteInPlace | Assign | AssignOp(_) | As | Multiply | Divide | Modulus | Add | + Subtract | ShiftLeft | ShiftRight | BitAnd | BitXor | BitOr | LAnd | LOr | DotDot | DotDotEq | Colon => false } } @@ -183,7 +187,7 @@ impl AssocOp { pub fn is_assign_like(&self) -> bool { use self::AssocOp::*; match *self { - Assign | AssignOp(_) => true, + Assign | AssignOp(_) | ObsoleteInPlace => true, Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual | As | Multiply | Divide | Modulus | Add | Subtract | ShiftLeft | ShiftRight | BitAnd | BitXor | BitOr | LAnd | LOr | DotDot | DotDotEq | Colon => false @@ -211,7 +215,7 @@ impl AssocOp { BitOr => Some(BinOpKind::BitOr), LAnd => Some(BinOpKind::And), LOr => Some(BinOpKind::Or), - Assign | AssignOp(_) | As | DotDot | DotDotEq | Colon => None + ObsoleteInPlace | Assign | AssignOp(_) | As | DotDot | DotDotEq | Colon => None } } } @@ -238,6 +242,7 @@ pub enum ExprPrecedence { Binary(BinOpKind), + ObsoleteInPlace, Cast, Type, @@ -304,6 +309,7 @@ impl ExprPrecedence { // Binop-like expr kinds, handled by `AssocOp`. ExprPrecedence::Binary(op) => AssocOp::from_ast_binop(op).precedence() as i8, + ExprPrecedence::ObsoleteInPlace => AssocOp::ObsoleteInPlace.precedence() as i8, ExprPrecedence::Cast => AssocOp::As.precedence() as i8, ExprPrecedence::Type => AssocOp::Colon.precedence() as i8, diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 40d59d3ff8b8d..ed1112700b33f 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -655,6 +655,10 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) { ExprKind::Box(ref subexpression) => { visitor.visit_expr(subexpression) } + ExprKind::ObsoleteInPlace(ref place, ref subexpression) => { + visitor.visit_expr(place); + visitor.visit_expr(subexpression) + } ExprKind::Array(ref subexpressions) => { walk_list!(visitor, visit_expr, subexpressions); } diff --git a/src/test/ui/obsolete-in-place/bad.bad.stderr b/src/test/ui/obsolete-in-place/bad.bad.stderr new file mode 100644 index 0000000000000..f870c09d6e52c --- /dev/null +++ b/src/test/ui/obsolete-in-place/bad.bad.stderr @@ -0,0 +1,18 @@ +error: emplacement syntax is obsolete (for now, anyway) + --> $DIR/bad.rs:19:5 + | +LL | x <- y; //[bad]~ ERROR emplacement syntax is obsolete + | ^^^^^^ + | + = note: for more information, see + +error: emplacement syntax is obsolete (for now, anyway) + --> $DIR/bad.rs:20:5 + | +LL | in(foo) { bar }; //[bad]~ ERROR emplacement syntax is obsolete + | ^^^^^^^^^^^^^^^ + | + = note: for more information, see + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/obsolete-in-place/bad.rs b/src/test/ui/obsolete-in-place/bad.rs new file mode 100644 index 0000000000000..21993e43331a6 --- /dev/null +++ b/src/test/ui/obsolete-in-place/bad.rs @@ -0,0 +1,25 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Check that `<-` and `in` syntax gets a hard error. + +// revisions: good bad +//[good] run-pass + +#[cfg(bad)] +fn main() { + let (x, y, foo, bar); + x <- y; //[bad]~ ERROR emplacement syntax is obsolete + in(foo) { bar }; //[bad]~ ERROR emplacement syntax is obsolete +} + +#[cfg(good)] +fn main() { +} From 201fc4871455f146a08c954a19f68331d8cf55c3 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 25 May 2018 04:46:42 -0400 Subject: [PATCH 08/11] pacify the mercilous tidy --- src/librustc_passes/ast_validation.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs index c85cb1adb9230..912036b0014c5 100644 --- a/src/librustc_passes/ast_validation.rs +++ b/src/librustc_passes/ast_validation.rs @@ -177,7 +177,8 @@ impl<'a> Visitor<'a> for AstValidator<'a> { ExprKind::ObsoleteInPlace(..) => { self.err_handler() .struct_span_err(expr.span, "emplacement syntax is obsolete (for now, anyway)") - .note("for more information, see ") + .note("for more information, see \ + ") .emit(); } _ => {} From 561310c4bb88eeef618d3040b3e4a9f1abfc663c Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Mon, 28 May 2018 10:37:49 +0200 Subject: [PATCH 09/11] Fix build backporting #51052 --- src/libsyntax/parse/parser.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 9b828d71246bb..eef6195e81331 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -2805,7 +2805,7 @@ impl<'a> Parser<'a> { )?; let blk = self.parse_block()?; let span = blk.span; - let blk_expr = self.mk_expr(span, ExprKind::Block(blk, None), ThinVec::new()); + let blk_expr = self.mk_expr(span, ExprKind::Block(blk), ThinVec::new()); (lo.to(span), ExprKind::ObsoleteInPlace(place, blk_expr)) } token::Ident(..) if self.token.is_keyword(keywords::Box) => { From d2902174b593000ede7100c928c6a280befc5213 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 31 May 2018 10:17:51 -0400 Subject: [PATCH 10/11] change `PointerKind::Implicit` to a note `PointerKind` is included in `LoanPath` and hence forms part of the equality check; this led to having two unequal paths that both represent `*x`, depending on whether the `*` was inserted automatically or explicitly. Bad mojo. The `note` field, in contrast, is intended more-or-less primarily for this purpose of adding extra data. --- src/librustc/middle/expr_use_visitor.rs | 11 ++- src/librustc/middle/mem_categorization.rs | 90 +++++++++---------- src/librustc/traits/project.rs | 31 +++++-- .../borrowck/gather_loans/gather_moves.rs | 1 - .../borrowck/gather_loans/lifetime.rs | 4 +- .../borrowck/gather_loans/move_error.rs | 1 - .../borrowck/gather_loans/restrictions.rs | 2 +- src/librustc_typeck/check/_match.rs | 1 + src/librustc_typeck/check/regionck.rs | 1 - src/librustc_typeck/check/upvar.rs | 13 ++- src/test/ui/borrowck/issue-51117.nll.stderr | 13 +++ src/test/ui/borrowck/issue-51117.rs | 25 ++++++ src/test/ui/borrowck/issue-51117.stderr | 14 +++ 13 files changed, 139 insertions(+), 68 deletions(-) create mode 100644 src/test/ui/borrowck/issue-51117.nll.stderr create mode 100644 src/test/ui/borrowck/issue-51117.rs create mode 100644 src/test/ui/borrowck/issue-51117.stderr diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index 725fcf1e6463b..49aa0cc4f7b49 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -837,17 +837,24 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { /// established up front, e.g. via `determine_pat_move_mode` (see /// also `walk_irrefutable_pat` for patterns that stand alone). fn walk_pat(&mut self, cmt_discr: mc::cmt<'tcx>, pat: &hir::Pat, match_mode: MatchMode) { - debug!("walk_pat cmt_discr={:?} pat={:?}", cmt_discr, pat); + debug!("walk_pat(cmt_discr={:?}, pat={:?})", cmt_discr, pat); let ExprUseVisitor { ref mc, ref mut delegate, param_env } = *self; return_if_err!(mc.cat_pattern(cmt_discr.clone(), pat, |cmt_pat, pat| { if let PatKind::Binding(_, canonical_id, ..) = pat.node { - debug!("binding cmt_pat={:?} pat={:?} match_mode={:?}", cmt_pat, pat, match_mode); + debug!( + "walk_pat: binding cmt_pat={:?} pat={:?} match_mode={:?}", + cmt_pat, + pat, + match_mode, + ); let bm = *mc.tables.pat_binding_modes().get(pat.hir_id) .expect("missing binding mode"); + debug!("walk_pat: pat.hir_id={:?} bm={:?}", pat.hir_id, bm); // pat_ty: the type of the binding being produced. let pat_ty = return_if_err!(mc.node_ty(pat.hir_id)); + debug!("walk_pat: pat_ty={:?}", pat_ty); // Each match binding is effectively an assignment to the // binding being produced. diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index f40a41cd29924..4688f6708d34f 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -95,7 +95,7 @@ pub enum Categorization<'tcx> { StaticItem, Upvar(Upvar), // upvar referenced by closure env Local(ast::NodeId), // local variable - Deref(cmt<'tcx>, PointerKind<'tcx>), // deref of a ptr + Deref(cmt<'tcx>, PointerKind<'tcx>), // deref of a ptr Interior(cmt<'tcx>, InteriorKind), // something interior: field, tuple, etc Downcast(cmt<'tcx>, DefId), // selects a particular enum variant (*1) @@ -120,9 +120,6 @@ pub enum PointerKind<'tcx> { /// `*T` UnsafePtr(hir::Mutability), - - /// Implicit deref of the `&T` that results from an overloaded index `[]`. - Implicit(ty::BorrowKind, ty::Region<'tcx>), } // We use the term "interior" to mean "something reachable from the @@ -172,6 +169,7 @@ pub enum MutabilityCategory { pub enum Note { NoteClosureEnv(ty::UpvarId), // Deref through closure env NoteUpvarRef(ty::UpvarId), // Deref through by-ref upvar + NoteIndex, // Deref as part of desugaring `x[]` into its two components NoteNone // Nothing special } @@ -231,8 +229,7 @@ impl<'tcx> cmt_<'tcx> { pub fn immutability_blame(&self) -> Option> { match self.cat { - Categorization::Deref(ref base_cmt, BorrowedPtr(ty::ImmBorrow, _)) | - Categorization::Deref(ref base_cmt, Implicit(ty::ImmBorrow, _)) => { + Categorization::Deref(ref base_cmt, BorrowedPtr(ty::ImmBorrow, _)) => { // try to figure out where the immutable reference came from match base_cmt.cat { Categorization::Local(node_id) => @@ -328,7 +325,7 @@ impl MutabilityCategory { Unique => { base_mutbl.inherit() } - BorrowedPtr(borrow_kind, _) | Implicit(borrow_kind, _) => { + BorrowedPtr(borrow_kind, _) => { MutabilityCategory::from_borrow_kind(borrow_kind) } UnsafePtr(m) => { @@ -617,7 +614,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { } else { previous()? }); - self.cat_deref(expr, base, false) + self.cat_deref(expr, base, NoteNone) } adjustment::Adjust::NeverToAny | @@ -640,10 +637,10 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { match expr.node { hir::ExprUnary(hir::UnDeref, ref e_base) => { if self.tables.is_method_call(expr) { - self.cat_overloaded_place(expr, e_base, false) + self.cat_overloaded_place(expr, e_base, NoteNone) } else { let base_cmt = Rc::new(self.cat_expr(&e_base)?); - self.cat_deref(expr, base_cmt, false) + self.cat_deref(expr, base_cmt, NoteNone) } } @@ -664,7 +661,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { // The call to index() returns a `&T` value, which // is an rvalue. That is what we will be // dereferencing. - self.cat_overloaded_place(expr, base, true) + self.cat_overloaded_place(expr, base, NoteIndex) } else { let base_cmt = Rc::new(self.cat_expr(&base)?); self.cat_index(expr, base_cmt, expr_ty, InteriorOffsetKind::Index) @@ -998,12 +995,18 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { ret } - fn cat_overloaded_place(&self, - expr: &hir::Expr, - base: &hir::Expr, - implicit: bool) - -> McResult> { - debug!("cat_overloaded_place: implicit={}", implicit); + fn cat_overloaded_place( + &self, + expr: &hir::Expr, + base: &hir::Expr, + note: Note, + ) -> McResult> { + debug!( + "cat_overloaded_place(expr={:?}, base={:?}, note={:?})", + expr, + base, + note, + ); // Reconstruct the output assuming it's a reference with the // same region and mutability as the receiver. This holds for @@ -1023,14 +1026,15 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { }); let base_cmt = Rc::new(self.cat_rvalue_node(expr.id, expr.span, ref_ty)); - self.cat_deref(expr, base_cmt, implicit) + self.cat_deref(expr, base_cmt, note) } - pub fn cat_deref(&self, - node: &N, - base_cmt: cmt<'tcx>, - implicit: bool) - -> McResult> { + pub fn cat_deref( + &self, + node: &impl ast_node, + base_cmt: cmt<'tcx>, + note: Note, + ) -> McResult> { debug!("cat_deref: base_cmt={:?}", base_cmt); let base_cmt_ty = base_cmt.ty; @@ -1048,7 +1052,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { ty::TyRawPtr(ref mt) => UnsafePtr(mt.mutbl), ty::TyRef(r, mt) => { let bk = ty::BorrowKind::from_mutbl(mt.mutbl); - if implicit { Implicit(bk, r) } else { BorrowedPtr(bk, r) } + BorrowedPtr(bk, r) } ref ty => bug!("unexpected type in cat_deref: {:?}", ty) }; @@ -1059,7 +1063,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { mutbl: MutabilityCategory::from_pointer_kind(base_cmt.mutbl, ptr), cat: Categorization::Deref(base_cmt, ptr), ty: deref_ty, - note: NoteNone + note: note, }; debug!("cat_deref ret {:?}", ret); Ok(ret) @@ -1192,7 +1196,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { // step out of sync again. So you'll see below that we always // get the type of the *subpattern* and use that. - debug!("cat_pattern: {:?} cmt={:?}", pat, cmt); + debug!("cat_pattern(pat={:?}, cmt={:?})", pat, cmt); // If (pattern) adjustments are active for this pattern, adjust the `cmt` correspondingly. // `cmt`s are constructed differently from patterns. For example, in @@ -1230,10 +1234,13 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { .pat_adjustments() .get(pat.hir_id) .map(|v| v.len()) - .unwrap_or(0) { - cmt = Rc::new(self.cat_deref(pat, cmt, true /* implicit */)?); + .unwrap_or(0) + { + debug!("cat_pattern: applying adjustment to cmt={:?}", cmt); + cmt = Rc::new(self.cat_deref(pat, cmt, NoteNone)?); } let cmt = cmt; // lose mutability + debug!("cat_pattern: applied adjustment derefs to get cmt={:?}", cmt); // Invoke the callback, but only now, after the `cmt` has adjusted. // @@ -1329,7 +1336,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { // box p1, &p1, &mut p1. we can ignore the mutability of // PatKind::Ref since that information is already contained // in the type. - let subcmt = Rc::new(self.cat_deref(pat, cmt, false)?); + let subcmt = Rc::new(self.cat_deref(pat, cmt, NoteNone)?); self.cat_pattern_(subcmt, &subpat, op)?; } @@ -1390,7 +1397,6 @@ impl<'tcx> cmt_<'tcx> { Categorization::Local(..) | Categorization::Deref(_, UnsafePtr(..)) | Categorization::Deref(_, BorrowedPtr(..)) | - Categorization::Deref(_, Implicit(..)) | Categorization::Upvar(..) => { (*self).clone() } @@ -1410,9 +1416,7 @@ impl<'tcx> cmt_<'tcx> { match self.cat { Categorization::Deref(ref b, BorrowedPtr(ty::MutBorrow, _)) | - Categorization::Deref(ref b, Implicit(ty::MutBorrow, _)) | Categorization::Deref(ref b, BorrowedPtr(ty::UniqueImmBorrow, _)) | - Categorization::Deref(ref b, Implicit(ty::UniqueImmBorrow, _)) | Categorization::Deref(ref b, Unique) | Categorization::Downcast(ref b, _) | Categorization::Interior(ref b, _) => { @@ -1435,8 +1439,7 @@ impl<'tcx> cmt_<'tcx> { } } - Categorization::Deref(_, BorrowedPtr(ty::ImmBorrow, _)) | - Categorization::Deref(_, Implicit(ty::ImmBorrow, _)) => { + Categorization::Deref(_, BorrowedPtr(ty::ImmBorrow, _)) => { FreelyAliasable(AliasableBorrowed) } } @@ -1459,7 +1462,7 @@ impl<'tcx> cmt_<'tcx> { _ => bug!() }) } - NoteNone => None + NoteIndex | NoteNone => None } } @@ -1486,9 +1489,6 @@ impl<'tcx> cmt_<'tcx> { Some(_) => bug!(), None => { match pk { - Implicit(..) => { - format!("indexed content") - } Unique => { format!("`Box` content") } @@ -1496,7 +1496,10 @@ impl<'tcx> cmt_<'tcx> { format!("dereference of raw pointer") } BorrowedPtr(..) => { - format!("borrowed content") + match self.note { + NoteIndex => format!("indexed content"), + _ => format!("borrowed content"), + } } } } @@ -1524,12 +1527,9 @@ impl<'tcx> cmt_<'tcx> { pub fn ptr_sigil(ptr: PointerKind) -> &'static str { match ptr { Unique => "Box", - BorrowedPtr(ty::ImmBorrow, _) | - Implicit(ty::ImmBorrow, _) => "&", - BorrowedPtr(ty::MutBorrow, _) | - Implicit(ty::MutBorrow, _) => "&mut", - BorrowedPtr(ty::UniqueImmBorrow, _) | - Implicit(ty::UniqueImmBorrow, _) => "&unique", + BorrowedPtr(ty::ImmBorrow, _) => "&", + BorrowedPtr(ty::MutBorrow, _) => "&mut", + BorrowedPtr(ty::UniqueImmBorrow, _) => "&unique", UnsafePtr(_) => "*", } } diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs index 45fa588bbf533..58a352fb7bcf4 100644 --- a/src/librustc/traits/project.rs +++ b/src/librustc/traits/project.rs @@ -137,17 +137,30 @@ impl<'tcx> ProjectionTyCandidateSet<'tcx> { fn push_candidate(&mut self, candidate: ProjectionTyCandidate<'tcx>) -> bool { use self::ProjectionTyCandidateSet::*; use self::ProjectionTyCandidate::*; + + // This wacky variable is just used to try and + // make code readable and avoid confusing paths. + // It is assigned a "value" of `()` only on those + // paths in which we wish to convert `*self` to + // ambiguous (and return false, because the candidate + // was not used). On other paths, it is not assigned, + // and hence if those paths *could* reach the code that + // comes after the match, this fn would not compile. + let convert_to_ambigious; + match self { None => { *self = Single(candidate); - true + return true; } + Single(current) => { // Duplicates can happen inside ParamEnv. In the case, we // perform a lazy deduplication. if current == &candidate { return false; } + // Prefer where-clauses. As in select, if there are multiple // candidates, we prefer where-clause candidates over impls. This // may seem a bit surprising, since impls are the source of @@ -156,17 +169,23 @@ impl<'tcx> ProjectionTyCandidateSet<'tcx> { // clauses are the safer choice. See the comment on // `select::SelectionCandidate` and #21974 for more details. match (current, candidate) { - (ParamEnv(..), ParamEnv(..)) => { *self = Ambiguous; } - (ParamEnv(..), _) => {} + (ParamEnv(..), ParamEnv(..)) => convert_to_ambigious = (), + (ParamEnv(..), _) => return false, (_, ParamEnv(..)) => { unreachable!(); } - (_, _) => { *self = Ambiguous; } + (_, _) => convert_to_ambigious = (), } - false } + Ambiguous | Error(..) => { - false + return false; } } + + // We only ever get here when we moved from a single candidate + // to ambiguous. + let () = convert_to_ambigious; + *self = Ambiguous; + false } } diff --git a/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs b/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs index ac905d6de5d3c..fa9bb57275abd 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs @@ -180,7 +180,6 @@ fn check_and_get_illegal_move_origin<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, -> Option> { match cmt.cat { Categorization::Deref(_, mc::BorrowedPtr(..)) | - Categorization::Deref(_, mc::Implicit(..)) | Categorization::Deref(_, mc::UnsafePtr(..)) | Categorization::StaticItem => { Some(cmt.clone()) diff --git a/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs b/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs index 6d73500d31802..323e0997e3e47 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs @@ -74,7 +74,6 @@ impl<'a, 'tcx> GuaranteeLifetimeContext<'a, 'tcx> { Categorization::Local(..) | // L-Local Categorization::Upvar(..) | Categorization::Deref(_, mc::BorrowedPtr(..)) | // L-Deref-Borrowed - Categorization::Deref(_, mc::Implicit(..)) | Categorization::Deref(_, mc::UnsafePtr(..)) => { self.check_scope(self.scope(cmt)) } @@ -122,8 +121,7 @@ impl<'a, 'tcx> GuaranteeLifetimeContext<'a, 'tcx> { Categorization::Deref(_, mc::UnsafePtr(..)) => { self.bccx.tcx.types.re_static } - Categorization::Deref(_, mc::BorrowedPtr(_, r)) | - Categorization::Deref(_, mc::Implicit(_, r)) => { + Categorization::Deref(_, mc::BorrowedPtr(_, r)) => { r } Categorization::Downcast(ref cmt, _) | diff --git a/src/librustc_borrowck/borrowck/gather_loans/move_error.rs b/src/librustc_borrowck/borrowck/gather_loans/move_error.rs index 1f2b917bdb994..18026a14259de 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/move_error.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/move_error.rs @@ -140,7 +140,6 @@ fn report_cannot_move_out_of<'a, 'tcx>(bccx: &'a BorrowckCtxt<'a, 'tcx>, -> DiagnosticBuilder<'a> { match move_from.cat { Categorization::Deref(_, mc::BorrowedPtr(..)) | - Categorization::Deref(_, mc::Implicit(..)) | Categorization::Deref(_, mc::UnsafePtr(..)) | Categorization::StaticItem => { bccx.cannot_move_out_of( diff --git a/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs b/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs index 0b90127cc7e1e..f7ac01368b00c 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs @@ -148,7 +148,7 @@ impl<'a, 'tcx> RestrictionsContext<'a, 'tcx> { let result = self.restrict(&cmt_base); self.extend(result, &cmt, LpDeref(pk)) } - mc::Implicit(bk, lt) | mc::BorrowedPtr(bk, lt) => { + mc::BorrowedPtr(bk, lt) => { // R-Deref-[Mut-]Borrowed if !self.bccx.is_subregion_of(self.loan_region, lt) { self.bccx.report( diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index 7b4dc60409b12..7a31c679d3aa9 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -236,6 +236,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { .borrow_mut() .pat_binding_modes_mut() .insert(pat.hir_id, bm); + debug!("check_pat_walk: pat.hir_id={:?} bm={:?}", pat.hir_id, bm); let typ = self.local_ty(pat.span, pat.id); match bm { ty::BindByReference(mutbl) => { diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index e7e70a19e496b..5889803d4d581 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -1113,7 +1113,6 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { borrow_kind, borrow_cmt); match borrow_cmt_cat { - Categorization::Deref(ref_cmt, mc::Implicit(ref_kind, ref_region)) | Categorization::Deref(ref_cmt, mc::BorrowedPtr(ref_kind, ref_region)) => { match self.link_reborrowed_region(span, borrow_region, borrow_kind, diff --git a/src/librustc_typeck/check/upvar.rs b/src/librustc_typeck/check/upvar.rs index 58dc5839578f7..a3706b5526661 100644 --- a/src/librustc_typeck/check/upvar.rs +++ b/src/librustc_typeck/check/upvar.rs @@ -329,8 +329,7 @@ impl<'a, 'gcx, 'tcx> InferBorrowKind<'a, 'gcx, 'tcx> { guarantor.cat ); match guarantor.cat { - Categorization::Deref(_, mc::BorrowedPtr(..)) | - Categorization::Deref(_, mc::Implicit(..)) => { + Categorization::Deref(_, mc::BorrowedPtr(..)) => { debug!( "adjust_upvar_borrow_kind_for_consume: found deref with note {:?}", cmt.note @@ -368,7 +367,7 @@ impl<'a, 'gcx, 'tcx> InferBorrowKind<'a, 'gcx, 'tcx> { var_name(tcx, upvar_id.var_id), ); } - mc::NoteNone => {} + mc::NoteIndex | mc::NoteNone => {} } } _ => {} @@ -390,8 +389,7 @@ impl<'a, 'gcx, 'tcx> InferBorrowKind<'a, 'gcx, 'tcx> { self.adjust_upvar_borrow_kind_for_mut(&base); } - Categorization::Deref(base, mc::BorrowedPtr(..)) | - Categorization::Deref(base, mc::Implicit(..)) => { + Categorization::Deref(base, mc::BorrowedPtr(..)) => { if !self.try_adjust_upvar_deref(cmt, ty::MutBorrow) { // assignment to deref of an `&mut` // borrowed pointer implies that the @@ -423,8 +421,7 @@ impl<'a, 'gcx, 'tcx> InferBorrowKind<'a, 'gcx, 'tcx> { self.adjust_upvar_borrow_kind_for_unique(&base); } - Categorization::Deref(base, mc::BorrowedPtr(..)) | - Categorization::Deref(base, mc::Implicit(..)) => { + Categorization::Deref(base, mc::BorrowedPtr(..)) => { if !self.try_adjust_upvar_deref(cmt, ty::UniqueImmBorrow) { // for a borrowed pointer to be unique, its // base must be unique @@ -484,7 +481,7 @@ impl<'a, 'gcx, 'tcx> InferBorrowKind<'a, 'gcx, 'tcx> { true } - mc::NoteNone => false, + mc::NoteIndex | mc::NoteNone => false, } } diff --git a/src/test/ui/borrowck/issue-51117.nll.stderr b/src/test/ui/borrowck/issue-51117.nll.stderr new file mode 100644 index 0000000000000..1ddca21320211 --- /dev/null +++ b/src/test/ui/borrowck/issue-51117.nll.stderr @@ -0,0 +1,13 @@ +error[E0499]: cannot borrow `*bar` as mutable more than once at a time + --> $DIR/issue-51117.rs:20:13 + | +LL | Some(baz) => { + | --- first mutable borrow occurs here +LL | bar.take(); //~ ERROR cannot borrow + | ^^^ second mutable borrow occurs here +LL | drop(baz); + | --- borrow later used here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0499`. diff --git a/src/test/ui/borrowck/issue-51117.rs b/src/test/ui/borrowck/issue-51117.rs new file mode 100644 index 0000000000000..0a1e672b57761 --- /dev/null +++ b/src/test/ui/borrowck/issue-51117.rs @@ -0,0 +1,25 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Regression test for #51117 in borrowck interaction with match +// default bindings. The borrow of `*bar` created by `baz` was failing +// to register as a conflict with `bar.take()`. + +fn main() { + let mut foo = Some("foo".to_string()); + let bar = &mut foo; + match bar { + Some(baz) => { + bar.take(); //~ ERROR cannot borrow + drop(baz); + }, + None => unreachable!(), + } +} diff --git a/src/test/ui/borrowck/issue-51117.stderr b/src/test/ui/borrowck/issue-51117.stderr new file mode 100644 index 0000000000000..cb434f9b322fe --- /dev/null +++ b/src/test/ui/borrowck/issue-51117.stderr @@ -0,0 +1,14 @@ +error[E0499]: cannot borrow `*bar` as mutable more than once at a time + --> $DIR/issue-51117.rs:20:13 + | +LL | Some(baz) => { + | --- first mutable borrow occurs here +LL | bar.take(); //~ ERROR cannot borrow + | ^^^ second mutable borrow occurs here +... +LL | } + | - first borrow ends here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0499`. From 724cfd84a379503b3a3c68b1107747cc06b57a41 Mon Sep 17 00:00:00 2001 From: Dan Robertson Date: Tue, 29 May 2018 01:51:36 +0000 Subject: [PATCH 11/11] typeck: Do not pass the field check on field error If a struct pattern has a field error return an error. --- src/librustc_typeck/check/_match.rs | 13 ++++++-- src/test/ui/issue-51102.rs | 48 +++++++++++++++++++++++++++++ src/test/ui/issue-51102.stderr | 24 +++++++++++++++ 3 files changed, 82 insertions(+), 3 deletions(-) create mode 100644 src/test/ui/issue-51102.rs create mode 100644 src/test/ui/issue-51102.stderr diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index 7a31c679d3aa9..a531e17a0cab2 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -723,8 +723,11 @@ https://doc.rust-lang.org/reference/types.html#trait-objects"); self.demand_eqtype(pat.span, expected, pat_ty); // Type check subpatterns. - self.check_struct_pat_fields(pat_ty, pat.id, pat.span, variant, fields, etc, def_bm); - pat_ty + if self.check_struct_pat_fields(pat_ty, pat.id, pat.span, variant, fields, etc, def_bm) { + pat_ty + } else { + self.tcx.types.err + } } fn check_pat_path(&self, @@ -849,7 +852,7 @@ https://doc.rust-lang.org/reference/types.html#trait-objects"); variant: &'tcx ty::VariantDef, fields: &'gcx [Spanned], etc: bool, - def_bm: ty::BindingMode) { + def_bm: ty::BindingMode) -> bool { let tcx = self.tcx; let (substs, adt) = match adt_ty.sty { @@ -867,6 +870,7 @@ https://doc.rust-lang.org/reference/types.html#trait-objects"); // Keep track of which fields have already appeared in the pattern. let mut used_fields = FxHashMap(); + let mut no_field_errors = true; let mut inexistent_fields = vec![]; // Typecheck each field. @@ -882,6 +886,7 @@ https://doc.rust-lang.org/reference/types.html#trait-objects"); format!("multiple uses of `{}` in pattern", field.name)) .span_label(*occupied.get(), format!("first use of `{}`", field.name)) .emit(); + no_field_errors = false; tcx.types.err } Vacant(vacant) => { @@ -894,6 +899,7 @@ https://doc.rust-lang.org/reference/types.html#trait-objects"); }) .unwrap_or_else(|| { inexistent_fields.push((span, field.name)); + no_field_errors = false; tcx.types.err }) } @@ -992,5 +998,6 @@ https://doc.rust-lang.org/reference/types.html#trait-objects"); diag.emit(); } } + no_field_errors } } diff --git a/src/test/ui/issue-51102.rs b/src/test/ui/issue-51102.rs new file mode 100644 index 0000000000000..c8f106687ae1c --- /dev/null +++ b/src/test/ui/issue-51102.rs @@ -0,0 +1,48 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +enum SimpleEnum { + NoState, +} + +struct SimpleStruct { + no_state_here: u64, +} + +fn main() { + let _ = |simple| { + match simple { + SimpleStruct { + state: 0, + //~^ struct `SimpleStruct` does not have a field named `state` [E0026] + .. + } => (), + } + }; + + let _ = |simple| { + match simple { + SimpleStruct { + no_state_here: 0, + no_state_here: 1 + //~^ ERROR field `no_state_here` bound multiple times in the pattern [E0025] + } => (), + } + }; + + let _ = |simple| { + match simple { + SimpleEnum::NoState { + state: 0 + //~^ ERROR variant `SimpleEnum::NoState` does not have a field named `state` [E0026] + } => (), + } + }; +} diff --git a/src/test/ui/issue-51102.stderr b/src/test/ui/issue-51102.stderr new file mode 100644 index 0000000000000..a4bd0fb914fee --- /dev/null +++ b/src/test/ui/issue-51102.stderr @@ -0,0 +1,24 @@ +error[E0026]: struct `SimpleStruct` does not have a field named `state` + --> $DIR/issue-51102.rs:23:17 + | +LL | state: 0, + | ^^^^^^^^ struct `SimpleStruct` does not have this field + +error[E0025]: field `no_state_here` bound multiple times in the pattern + --> $DIR/issue-51102.rs:34:17 + | +LL | no_state_here: 0, + | ---------------- first use of `no_state_here` +LL | no_state_here: 1 + | ^^^^^^^^^^^^^^^^ multiple uses of `no_state_here` in pattern + +error[E0026]: variant `SimpleEnum::NoState` does not have a field named `state` + --> $DIR/issue-51102.rs:43:17 + | +LL | state: 0 + | ^^^^^^^^ variant `SimpleEnum::NoState` does not have this field + +error: aborting due to 3 previous errors + +Some errors occurred: E0025, E0026. +For more information about an error, try `rustc --explain E0025`.