From de7dda7bf413dc214e3f1552d6cb3f8052283513 Mon Sep 17 00:00:00 2001 From: est31 Date: Sat, 29 Apr 2017 09:15:07 +0200 Subject: [PATCH 01/16] Add illegal_floating_point_literal_pattern compat lint Adds a compatibility lint to disallow floating point literals in patterns like in match. See the tracking issue #41620. --- src/librustc_lint/builtin.rs | 76 ++++++++++++++++++++++++++++ src/librustc_lint/lib.rs | 5 ++ src/test/compile-fail/issue-41255.rs | 51 +++++++++++++++++++ 3 files changed, 132 insertions(+) create mode 100644 src/test/compile-fail/issue-41255.rs diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index c9ec152841b..715a769158b 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -692,6 +692,82 @@ impl EarlyLintPass for DeprecatedAttr { } } +declare_lint! { + pub ILLEGAL_FLOATING_POINT_LITERAL_PATTERN, + Warn, + "floating-point literals cannot be used in patterns" +} + +/// Checks for floating point literals in patterns. +#[derive(Clone)] +pub struct IllegalFloatLiteralPattern; + +impl LintPass for IllegalFloatLiteralPattern { + fn get_lints(&self) -> LintArray { + lint_array!(ILLEGAL_FLOATING_POINT_LITERAL_PATTERN) + } +} + +fn fl_lit_check_expr(cx: &EarlyContext, expr: &ast::Expr) { + use self::ast::{ExprKind, LitKind}; + match expr.node { + ExprKind::Lit(ref l) => { + match l.node { + LitKind::FloatUnsuffixed(..) | + LitKind::Float(..) => { + cx.span_lint(ILLEGAL_FLOATING_POINT_LITERAL_PATTERN, + l.span, + "floating-point literals cannot be used in patterns"); + error!("span mc spanspam"); + }, + _ => (), + } + } + // These may occur in patterns + // and can maybe contain float literals + ExprKind::Unary(_, ref f) => fl_lit_check_expr(cx, f), + // These may occur in patterns + // and can't contain float literals + ExprKind::Path(..) => (), + // If something unhandled is encountered, we need to expand the + // search or ignore more ExprKinds. + _ => span_bug!(expr.span, "Unhandled expression {:?} in float lit pattern lint", + expr.node), + } +} + +impl EarlyLintPass for IllegalFloatLiteralPattern { + fn check_pat(&mut self, cx: &EarlyContext, pat: &ast::Pat) { + use self::ast::PatKind; + pat.walk(&mut |p| { + match p.node { + // Wildcard patterns and paths are uninteresting for the lint + PatKind::Wild | + PatKind::Path(..) => (), + + // The walk logic recurses inside these + PatKind::Ident(..) | + PatKind::Struct(..) | + PatKind::Tuple(..) | + PatKind::TupleStruct(..) | + PatKind::Ref(..) | + PatKind::Box(..) | + PatKind::Slice(..) => (), + + // Extract the expressions and check them + PatKind::Lit(ref e) => fl_lit_check_expr(cx, e), + PatKind::Range(ref st, ref en, _) => { + fl_lit_check_expr(cx, st); + fl_lit_check_expr(cx, en); + }, + + PatKind::Mac(_) => bug!("lint must run post-expansion"), + } + true + }); + } +} + declare_lint! { pub UNCONDITIONAL_RECURSION, Warn, diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index c1c14cb1fd2..53ea3a8333f 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -113,6 +113,7 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) { UnusedParens, UnusedImportBraces, AnonymousParameters, + IllegalFloatLiteralPattern, ); add_early_builtin_with_new!(sess, @@ -201,6 +202,10 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) { id: LintId::of(ILLEGAL_FLOATING_POINT_CONSTANT_PATTERN), reference: "issue #36890 ", }, + FutureIncompatibleInfo { + id: LintId::of(ILLEGAL_FLOATING_POINT_LITERAL_PATTERN), + reference: "issue #41620 ", + }, FutureIncompatibleInfo { id: LintId::of(ILLEGAL_STRUCT_OR_ENUM_CONSTANT_PATTERN), reference: "issue #36891 ", diff --git a/src/test/compile-fail/issue-41255.rs b/src/test/compile-fail/issue-41255.rs new file mode 100644 index 00000000000..191b867e7a8 --- /dev/null +++ b/src/test/compile-fail/issue-41255.rs @@ -0,0 +1,51 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Matching against float literals should result in a linter error + +#![feature(slice_patterns)] +#![feature(exclusive_range_pattern)] +#![allow(unused)] +#![forbid(illegal_floating_point_literal_pattern)] + +fn main() { + let x = 42.0; + match x { + 5.0 => {}, //~ ERROR floating-point literals cannot be used + //~| WARNING hard error + 5.0f32 => {}, //~ ERROR floating-point literals cannot be used + //~| WARNING hard error + -5.0 => {}, //~ ERROR floating-point literals cannot be used + //~| WARNING hard error + 1.0 .. 33.0 => {}, //~ ERROR floating-point literals cannot be used + //~| WARNING hard error + //~| ERROR floating-point literals cannot be used + //~| WARNING hard error + 39.0 ... 70.0 => {}, //~ ERROR floating-point literals cannot be used + //~| WARNING hard error + //~| ERROR floating-point literals cannot be used + //~| WARNING hard error + _ => {}, + }; + let y = 5.0; + // Same for tuples + match (x, 5) { + (3.14, 1) => {}, //~ ERROR floating-point literals cannot be used + //~| WARNING hard error + _ => {}, + } + // Or structs + struct Foo { x: f32 }; + match (Foo { x }) { + Foo { x: 2.0 } => {}, //~ ERROR floating-point literals cannot be used + //~| WARNING hard error + _ => {}, + } +} From 51c3173465ef4e158117da2421707f3b0a9d3e25 Mon Sep 17 00:00:00 2001 From: est31 Date: Sat, 29 Apr 2017 10:02:42 +0200 Subject: [PATCH 02/16] Fix non exhaustive match test --- src/test/compile-fail/non-exhaustive-match.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/test/compile-fail/non-exhaustive-match.rs b/src/test/compile-fail/non-exhaustive-match.rs index 74e728d713b..13b62429f46 100644 --- a/src/test/compile-fail/non-exhaustive-match.rs +++ b/src/test/compile-fail/non-exhaustive-match.rs @@ -9,6 +9,7 @@ // except according to those terms. #![feature(slice_patterns)] +#![allow(illegal_floating_point_literal_pattern)] enum t { a, b, } From 37fb676fcf99631b0acd69585e5b3899485fd96b Mon Sep 17 00:00:00 2001 From: est31 Date: Sat, 29 Apr 2017 10:09:02 +0200 Subject: [PATCH 03/16] Fix test --- src/test/compile-fail/issue-41255.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/test/compile-fail/issue-41255.rs b/src/test/compile-fail/issue-41255.rs index 191b867e7a8..a4585f7bac7 100644 --- a/src/test/compile-fail/issue-41255.rs +++ b/src/test/compile-fail/issue-41255.rs @@ -39,6 +39,8 @@ fn main() { match (x, 5) { (3.14, 1) => {}, //~ ERROR floating-point literals cannot be used //~| WARNING hard error + //~| ERROR floating-point literals cannot be used + //~| WARNING hard error _ => {}, } // Or structs @@ -46,6 +48,8 @@ fn main() { match (Foo { x }) { Foo { x: 2.0 } => {}, //~ ERROR floating-point literals cannot be used //~| WARNING hard error + //~| ERROR floating-point literals cannot be used + //~| WARNING hard error _ => {}, } } From 56411443f2421e6726413c212a697a45d45ddfa1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Mon, 24 Apr 2017 16:27:07 -0700 Subject: [PATCH 04/16] Use diagnostics for trace_macro instead of println --- src/librustc_errors/lib.rs | 6 ++++++ src/libsyntax/ext/base.rs | 3 +++ src/libsyntax/ext/tt/macro_rules.rs | 4 +++- src/test/run-make/trace-macros-flag/Makefile | 9 --------- src/test/run-make/trace-macros-flag/hello.trace | 2 -- .../hello.rs => ui/macros/trace-macro.rs} | 0 src/test/ui/macros/trace-macro.stderr | 14 ++++++++++++++ 7 files changed, 26 insertions(+), 12 deletions(-) delete mode 100644 src/test/run-make/trace-macros-flag/Makefile delete mode 100644 src/test/run-make/trace-macros-flag/hello.trace rename src/test/{run-make/trace-macros-flag/hello.rs => ui/macros/trace-macro.rs} (100%) create mode 100644 src/test/ui/macros/trace-macro.stderr diff --git a/src/librustc_errors/lib.rs b/src/librustc_errors/lib.rs index 02d8297dd46..06aafa05052 100644 --- a/src/librustc_errors/lib.rs +++ b/src/librustc_errors/lib.rs @@ -388,6 +388,12 @@ impl Handler { pub fn span_note_without_error>(&self, sp: S, msg: &str) { self.emit(&sp.into(), msg, Note); } + pub fn span_label_without_error(&self, sp: Span, msg: &str, lbl: &str) { + let mut db = DiagnosticBuilder::new(self, Note, msg); + db.set_span(sp); + db.span_label(sp, &lbl); + db.emit(); + } pub fn span_unimpl>(&self, sp: S, msg: &str) -> ! { self.span_bug(sp, &format!("unimplemented {}", msg)); } diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index fda026fec64..3bfa63a022d 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -765,6 +765,9 @@ impl<'a> ExtCtxt<'a> { pub fn span_bug(&self, sp: Span, msg: &str) -> ! { self.parse_sess.span_diagnostic.span_bug(sp, msg); } + pub fn span_label_without_error(&self, sp: Span, msg: &str, label: &str) { + self.parse_sess.span_diagnostic.span_label_without_error(sp, msg, label); + } pub fn bug(&self, msg: &str) -> ! { self.parse_sess.span_diagnostic.bug(msg); } diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs index be979960725..46c49ffb24c 100644 --- a/src/libsyntax/ext/tt/macro_rules.rs +++ b/src/libsyntax/ext/tt/macro_rules.rs @@ -93,7 +93,9 @@ fn generic_extension<'cx>(cx: &'cx ExtCtxt, rhses: &[quoted::TokenTree]) -> Box { if cx.trace_macros() { - println!("{}! {{ {} }}", name, arg); + cx.span_label_without_error(sp, + &"trace_macro", + &format!("expands to `{}! {{ {} }}`", name, arg)); } // Which arm's failure should we report? (the one furthest along) diff --git a/src/test/run-make/trace-macros-flag/Makefile b/src/test/run-make/trace-macros-flag/Makefile deleted file mode 100644 index 3338e394e0e..00000000000 --- a/src/test/run-make/trace-macros-flag/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -# This test verifies that "-Z trace-macros" works as it should. The traditional -# "hello world" program provides a small example of this as not only println! is -# listed, but also print! (since println! expands to this) - --include ../tools.mk - -all: - $(RUSTC) -Z trace-macros hello.rs > $(TMPDIR)/hello.out - diff -u $(TMPDIR)/hello.out hello.trace diff --git a/src/test/run-make/trace-macros-flag/hello.trace b/src/test/run-make/trace-macros-flag/hello.trace deleted file mode 100644 index cf733339ead..00000000000 --- a/src/test/run-make/trace-macros-flag/hello.trace +++ /dev/null @@ -1,2 +0,0 @@ -println! { "Hello, World!" } -print! { concat ! ( "Hello, World!" , "\n" ) } diff --git a/src/test/run-make/trace-macros-flag/hello.rs b/src/test/ui/macros/trace-macro.rs similarity index 100% rename from src/test/run-make/trace-macros-flag/hello.rs rename to src/test/ui/macros/trace-macro.rs diff --git a/src/test/ui/macros/trace-macro.stderr b/src/test/ui/macros/trace-macro.stderr new file mode 100644 index 00000000000..8f091ef9455 --- /dev/null +++ b/src/test/ui/macros/trace-macro.stderr @@ -0,0 +1,14 @@ +note: trace_macro + --> $DIR/trace-macro.rs:12:5 + | +12 | println!("Hello, World!"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ expands to `println! { "Hello, World!" }` + +note: trace_macro + --> $DIR/trace-macro.rs:12:5 + | +12 | println!("Hello, World!"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ expands to `print! { concat ! ( "Hello, World!" , "\n" ) }` + | + = note: this error originates in a macro outside of the current crate + From 8c9ad8d72c5a3ad73af33e3ad9a409327645ac28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 5 May 2017 21:49:59 -0700 Subject: [PATCH 05/16] Group "macro expansion" notes per call span --- src/librustc_errors/lib.rs | 8 +++++--- src/libsyntax/ext/base.rs | 13 +++++++++++-- src/libsyntax/ext/expand.rs | 2 +- src/libsyntax/ext/tt/macro_rules.rs | 12 ++++++------ src/test/ui/macros/trace-macro.rs | 2 ++ src/test/ui/macros/trace-macro.stderr | 17 ++++++----------- 6 files changed, 31 insertions(+), 23 deletions(-) diff --git a/src/librustc_errors/lib.rs b/src/librustc_errors/lib.rs index 06aafa05052..db8c9ac306b 100644 --- a/src/librustc_errors/lib.rs +++ b/src/librustc_errors/lib.rs @@ -388,11 +388,13 @@ impl Handler { pub fn span_note_without_error>(&self, sp: S, msg: &str) { self.emit(&sp.into(), msg, Note); } - pub fn span_label_without_error(&self, sp: Span, msg: &str, lbl: &str) { + pub fn span_note_diag<'a>(&'a self, + sp: Span, + msg: &str) + -> DiagnosticBuilder<'a> { let mut db = DiagnosticBuilder::new(self, Note, msg); db.set_span(sp); - db.span_label(sp, &lbl); - db.emit(); + db } pub fn span_unimpl>(&self, sp: S, msg: &str) -> ! { self.span_bug(sp, &format!("unimplemented {}", msg)); diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 3bfa63a022d..f731c5abdd6 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -24,6 +24,7 @@ use ptr::P; use symbol::Symbol; use util::small_vector::SmallVector; +use std::collections::HashMap; use std::path::PathBuf; use std::rc::Rc; use std::default::Default; @@ -643,6 +644,7 @@ pub struct ExtCtxt<'a> { pub resolver: &'a mut Resolver, pub resolve_err_count: usize, pub current_expansion: ExpansionData, + pub expansions: HashMap>, } impl<'a> ExtCtxt<'a> { @@ -662,6 +664,7 @@ impl<'a> ExtCtxt<'a> { module: Rc::new(ModuleData { mod_path: Vec::new(), directory: PathBuf::new() }), directory_ownership: DirectoryOwnership::Owned, }, + expansions: HashMap::new(), } } @@ -765,8 +768,14 @@ impl<'a> ExtCtxt<'a> { pub fn span_bug(&self, sp: Span, msg: &str) -> ! { self.parse_sess.span_diagnostic.span_bug(sp, msg); } - pub fn span_label_without_error(&self, sp: Span, msg: &str, label: &str) { - self.parse_sess.span_diagnostic.span_label_without_error(sp, msg, label); + pub fn trace_macros_diag(&self) { + for (sp, notes) in self.expansions.iter() { + let mut db = self.parse_sess.span_diagnostic.span_note_diag(*sp, &"trace_macro"); + for note in notes { + db.note(¬e); + } + db.emit(); + } } pub fn bug(&self, msg: &str) -> ! { self.parse_sess.span_diagnostic.bug(msg); diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 2db295d0136..31d4cc779c2 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -231,7 +231,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { }, _ => unreachable!(), }; - + self.cx.trace_macros_diag(); krate } diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs index 46c49ffb24c..f959ccc989e 100644 --- a/src/libsyntax/ext/tt/macro_rules.rs +++ b/src/libsyntax/ext/tt/macro_rules.rs @@ -27,8 +27,8 @@ use symbol::Symbol; use tokenstream::{TokenStream, TokenTree}; use std::cell::RefCell; -use std::collections::{HashMap}; -use std::collections::hash_map::{Entry}; +use std::collections::HashMap; +use std::collections::hash_map::Entry; use std::rc::Rc; pub struct ParserAnyMacro<'a> { @@ -85,7 +85,7 @@ impl TTMacroExpander for MacroRulesMacroExpander { } /// Given `lhses` and `rhses`, this is the new macro we create -fn generic_extension<'cx>(cx: &'cx ExtCtxt, +fn generic_extension<'cx>(cx: &'cx mut ExtCtxt, sp: Span, name: ast::Ident, arg: TokenStream, @@ -93,9 +93,9 @@ fn generic_extension<'cx>(cx: &'cx ExtCtxt, rhses: &[quoted::TokenTree]) -> Box { if cx.trace_macros() { - cx.span_label_without_error(sp, - &"trace_macro", - &format!("expands to `{}! {{ {} }}`", name, arg)); + let sp = sp.macro_backtrace().last().map(|trace| trace.call_site).unwrap_or(sp); + let mut values: &mut Vec = cx.expansions.entry(sp).or_insert(vec![]); + values.push(format!("expands to `{}! {{ {} }}`", name, arg)); } // Which arm's failure should we report? (the one furthest along) diff --git a/src/test/ui/macros/trace-macro.rs b/src/test/ui/macros/trace-macro.rs index 42d3d4c799d..34f674ae016 100644 --- a/src/test/ui/macros/trace-macro.rs +++ b/src/test/ui/macros/trace-macro.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// compile-flags: -Z trace-macros + fn main() { println!("Hello, World!"); } diff --git a/src/test/ui/macros/trace-macro.stderr b/src/test/ui/macros/trace-macro.stderr index 8f091ef9455..09117a4ca74 100644 --- a/src/test/ui/macros/trace-macro.stderr +++ b/src/test/ui/macros/trace-macro.stderr @@ -1,14 +1,9 @@ note: trace_macro - --> $DIR/trace-macro.rs:12:5 + --> $DIR/trace-macro.rs:14:5 | -12 | println!("Hello, World!"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ expands to `println! { "Hello, World!" }` - -note: trace_macro - --> $DIR/trace-macro.rs:12:5 - | -12 | println!("Hello, World!"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ expands to `print! { concat ! ( "Hello, World!" , "\n" ) }` - | - = note: this error originates in a macro outside of the current crate +14 | println!("Hello, World!"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: expands to `println! { "Hello, World!" }` + = note: expands to `print! { concat ! ( "Hello, World!" , "/n" ) }` From 0e8e45c74068b72301f9045f0efc38ba8b51e0a4 Mon Sep 17 00:00:00 2001 From: Masaki Hara Date: Mon, 8 May 2017 22:29:24 +0900 Subject: [PATCH 06/16] Allow bare CR in ////-style comment. --- src/libsyntax/parse/lexer/mod.rs | 2 +- .../lex-bare-cr-string-literal-doc-comment.rs | 6 ++++++ .../run-pass/lex-bare-cr-nondoc-comment.rs | 18 ++++++++++++++++++ 3 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 src/test/run-pass/lex-bare-cr-nondoc-comment.rs diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs index 7d2a1b3c4a4..ded1f0b599a 100644 --- a/src/libsyntax/parse/lexer/mod.rs +++ b/src/libsyntax/parse/lexer/mod.rs @@ -504,7 +504,7 @@ impl<'a> StringReader<'a> { self.bump(); // line comments starting with "///" or "//!" are doc-comments - let doc_comment = self.ch_is('/') || self.ch_is('!'); + let doc_comment = (self.ch_is('/') && !self.nextch_is('/')) || self.ch_is('!'); let start_bpos = self.pos - BytePos(2); while !self.is_eof() { diff --git a/src/test/parse-fail/lex-bare-cr-string-literal-doc-comment.rs b/src/test/parse-fail/lex-bare-cr-string-literal-doc-comment.rs index f8943057543..ac085d47511 100644 --- a/src/test/parse-fail/lex-bare-cr-string-literal-doc-comment.rs +++ b/src/test/parse-fail/lex-bare-cr-string-literal-doc-comment.rs @@ -21,6 +21,12 @@ pub fn bar() {} //~^^ ERROR: bare CR not allowed in block doc-comment fn main() { + //! doc comment with bare CR: ' ' + //~^ ERROR: bare CR not allowed in doc-comment + + /*! block doc comment with bare CR: ' ' */ + //~^ ERROR: bare CR not allowed in block doc-comment + // the following string literal has a bare CR in it let _s = "foo bar"; //~ ERROR: bare CR not allowed in string diff --git a/src/test/run-pass/lex-bare-cr-nondoc-comment.rs b/src/test/run-pass/lex-bare-cr-nondoc-comment.rs new file mode 100644 index 00000000000..ba949ca8881 --- /dev/null +++ b/src/test/run-pass/lex-bare-cr-nondoc-comment.rs @@ -0,0 +1,18 @@ +// 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. + +// ignore-tidy-cr + +// nondoc comment with bare CR: ' ' +//// nondoc comment with bare CR: ' ' +/* block nondoc comment with bare CR: ' ' */ + +fn main() { +} From 052d071bb28048c0e1d481891a6017ca97e326e7 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Mon, 8 May 2017 17:05:03 +0300 Subject: [PATCH 07/16] try to fix lvalue ops for real Hopefully this is the last PR needed. Fixes #41726. Fixes #41742. Fixes #41774. --- src/librustc_typeck/check/method/confirm.rs | 48 ++++++++++++------- src/test/compile-fail/issue-41726.rs | 17 +++++++ src/test/compile-fail/issue-41742.rs | 35 ++++++++++++++ .../regions-adjusted-lvalue-op.rs | 26 ++++++++++ 4 files changed, 109 insertions(+), 17 deletions(-) create mode 100644 src/test/compile-fail/issue-41726.rs create mode 100644 src/test/compile-fail/issue-41742.rs create mode 100644 src/test/compile-fail/regions-adjusted-lvalue-op.rs diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index aad14bc975d..5cec71a7eb7 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -433,22 +433,11 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { for (i, &expr) in exprs.iter().rev().enumerate() { debug!("convert_lvalue_derefs_to_mutable: i={} expr={:?}", i, expr); - // Fix up the adjustment. - let autoderefs = match self.tables.borrow_mut().adjustments.get_mut(&expr.id) { - Some(&mut Adjustment { - kind: Adjust::DerefRef { autoderefs, ref mut autoref, .. }, ref mut target - }) => { - if let &mut Some(AutoBorrow::Ref(_, ref mut mutbl)) = autoref { - *mutbl = hir::Mutability::MutMutable; - *target = match target.sty { - ty::TyRef(r, ty::TypeAndMut { ty, .. }) => - self.tcx.mk_ref(r, ty::TypeAndMut { ty, mutbl: *mutbl }), - _ => span_bug!(expr.span, "AutoBorrow::Ref resulted in non-ref {:?}", - target) - }; - } - autoderefs - } + // Fix up the autoderefs. Autorefs can only occur immediately preceding + // overloaded lvalue ops, and will be fixed by them in order to get + // the correct region. + let autoderefs = match self.tables.borrow().adjustments.get(&expr.id) { + Some(&Adjustment { kind: Adjust::DerefRef { autoderefs, .. }, .. }) => autoderefs, Some(_) | None => 0 }; @@ -502,10 +491,35 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { let method = self.try_overloaded_lvalue_op( expr.span, None, base_ty, arg_tys, PreferMutLvalue, op); - let ok = method.expect("re-trying op failed"); + let ok = match method { + Some(method) => method, + None => return self.tcx.sess.delay_span_bug(expr.span, "re-trying op failed") + }; let method = self.register_infer_ok_obligations(ok); debug!("convert_lvalue_op_to_mutable: method={:?}", method); self.tables.borrow_mut().method_map.insert(method_call, method); + + // Convert the autoref in the base expr to mutable with the correct + // region and mutability. + if let Some(&mut Adjustment { + ref mut target, kind: Adjust::DerefRef { + autoref: Some(AutoBorrow::Ref(ref mut r, ref mut mutbl)), .. + } + }) = self.tables.borrow_mut().adjustments.get_mut(&base_expr.id) { + debug!("convert_lvalue_op_to_mutable: converting autoref of {:?}", target); + + // extract method return type, which will be &mut T; + // all LB regions should have been instantiated during method lookup + let method_sig = self.tcx.no_late_bound_regions(&method.ty.fn_sig()).unwrap(); + + *target = method_sig.inputs()[0]; + if let ty::TyRef(r_, mt) = target.sty { + *r = r_; + *mutbl = mt.mutbl; + } else { + span_bug!(expr.span, "input to lvalue op is not a ref?"); + } + } } /////////////////////////////////////////////////////////////////////////// diff --git a/src/test/compile-fail/issue-41726.rs b/src/test/compile-fail/issue-41726.rs new file mode 100644 index 00000000000..c8cd9209bce --- /dev/null +++ b/src/test/compile-fail/issue-41726.rs @@ -0,0 +1,17 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::collections::HashMap; +fn main() { + let things: HashMap> = HashMap::new(); + for src in things.keys() { + things[src.as_str()].sort(); //~ ERROR cannot borrow immutable + } +} diff --git a/src/test/compile-fail/issue-41742.rs b/src/test/compile-fail/issue-41742.rs new file mode 100644 index 00000000000..067531e036a --- /dev/null +++ b/src/test/compile-fail/issue-41742.rs @@ -0,0 +1,35 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::ops::{Index, IndexMut}; + +struct S; +struct H; + +impl S { + fn f(&mut self) {} +} + +impl Index for H { + type Output = S; + fn index(&self, index: u32) -> &S { + unimplemented!() + } +} + +impl IndexMut for H { + fn index_mut(&mut self, index: u32) -> &mut S { + unimplemented!() + } +} + +fn main() { + H["?"].f(); //~ ERROR mismatched types +} diff --git a/src/test/compile-fail/regions-adjusted-lvalue-op.rs b/src/test/compile-fail/regions-adjusted-lvalue-op.rs new file mode 100644 index 00000000000..167c8630707 --- /dev/null +++ b/src/test/compile-fail/regions-adjusted-lvalue-op.rs @@ -0,0 +1,26 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// check that we link regions in mutable lvalue ops correctly - issue #41774 + +struct Data(i32); + +trait OhNo { + fn oh_no(&mut self, other: &Vec) { loop {} } +} + +impl OhNo for Data {} +impl OhNo for [Data] {} + +fn main() { + let mut v = vec![Data(0)]; + v[0].oh_no(&v); //~ ERROR cannot borrow `v` as immutable because + (*v).oh_no(&v); //~ ERROR cannot borrow `v` as immutable because +} From 7bed5437fad0d8310654de2616434bfafba85d24 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Tue, 9 May 2017 07:15:48 +1200 Subject: [PATCH 08/16] Update save-analysis deps and RLS submodule --- src/Cargo.lock | 14 +++++++------- src/librustc_save_analysis/Cargo.toml | 4 ++-- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/Cargo.lock b/src/Cargo.lock index 0b21ec98650..3dd8231a49f 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -411,16 +411,16 @@ version = "0.1.0" [[package]] name = "rls-data" -version = "0.1.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "rls-span 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rls-span" -version = "0.1.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "rustc-serialize 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)", @@ -719,8 +719,8 @@ name = "rustc_save_analysis" version = "0.0.0" dependencies = [ "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", - "rls-data 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rls-span 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rls-data 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc-serialize 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_typeck 0.0.0", @@ -1021,8 +1021,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum quick-error 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0aad603e8d7fb67da22dbdf1f4b826ce8829e406124109e73cf1b2454b93a71c" "checksum regex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4278c17d0f6d62dfef0ab00028feb45bd7d2102843f80763474eeb1be8a10c01" "checksum regex-syntax 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9191b1f57603095f105d317e375d19b1c9c5c3185ea9633a99a6dcbed04457" -"checksum rls-data 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "af1dfff00189fd7b78edb9af131b0de703676c04fa8126aed77fd2c586775a4d" -"checksum rls-span 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8656f7b850ac85fb204ef94318c641bbb15a32766e12f9a589a23e4c0fbc38db" +"checksum rls-data 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fc4277ce3c57f456b11fe3145b181a844a25201bab5cbaa1978457e6e2f27d47" +"checksum rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5d7c7046dc6a92f2ae02ed302746db4382e75131b9ce20ce967259f6b5867a6a" "checksum rustc-serialize 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)" = "684ce48436d6465300c9ea783b6b14c4361d6b8dcbb1375b486a69cc19e2dfb0" "checksum serde 0.9.11 (registry+https://github.com/rust-lang/crates.io-index)" = "a702319c807c016e51f672e5c77d6f0b46afddd744b5e437d6b8436b888b458f" "checksum serde_json 0.9.9 (registry+https://github.com/rust-lang/crates.io-index)" = "dbc45439552eb8fb86907a2c41c1fd0ef97458efb87ff7f878db466eb581824e" diff --git a/src/librustc_save_analysis/Cargo.toml b/src/librustc_save_analysis/Cargo.toml index 702c4b691c9..6d04bff8282 100644 --- a/src/librustc_save_analysis/Cargo.toml +++ b/src/librustc_save_analysis/Cargo.toml @@ -14,7 +14,7 @@ rustc = { path = "../librustc" } rustc_typeck = { path = "../librustc_typeck" } syntax = { path = "../libsyntax" } syntax_pos = { path = "../libsyntax_pos" } -rls-data = "0.1" -rls-span = "0.1" +rls-data = "0.3" +rls-span = "0.4" # FIXME(#40527) should move rustc serialize out of tree rustc-serialize = "0.3" From f096c8d17412b6303dc80cfff3dee5c2dffd16e5 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Mon, 8 May 2017 14:56:33 -0500 Subject: [PATCH 09/16] inferring expected types of closure arguments when coercing to a fn --- src/librustc_typeck/check/closure.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index 45b0a571bd0..fb3be849319 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -126,6 +126,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { (sig, kind) } ty::TyInfer(ty::TyVar(vid)) => self.deduce_expectations_from_obligations(vid), + ty::TyFnPtr(sig) => (Some(sig.skip_binder().clone()), Some(ty::ClosureKind::Fn)), _ => (None, None), } } From 576266927a53aba4c0d81ed9641a9435df84baa4 Mon Sep 17 00:00:00 2001 From: Jing Zhao Date: Mon, 8 May 2017 13:33:54 -0700 Subject: [PATCH 10/16] Grammar fixes to rustc-ux-guidelines.md 1) changed "long way into" to "long way toward" 2) changed "developer lives" to "developers' lives" 3) removed the "either... or..." format from second paragraph because there are more than 2 options 4) Minor revisions to paragraphs 3-6 to make them more consistent in format and to fix minor grammar issues. --- src/doc/rustc-ux-guidelines.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/doc/rustc-ux-guidelines.md b/src/doc/rustc-ux-guidelines.md index 0b2069e25aa..ecfb2fb2572 100644 --- a/src/doc/rustc-ux-guidelines.md +++ b/src/doc/rustc-ux-guidelines.md @@ -1,14 +1,14 @@ % Rustc UX guidelines Don't forget the user. Whether human or another program, such as an IDE, a -good user experience with the compiler goes a long way into making developer -lives better. We don't want users to be baffled by compiler output or +good user experience with the compiler goes a long way toward making developers' +lives better. We do not want users to be baffled by compiler output or learn arcane patterns to compile their program. ## Error, Warning, Help, Note Messages -When the compiler detects a problem, it can emit either an error, warning, -note, or help message. +When the compiler detects a problem, it can emit one of the following: an error, a warning, +a note, or a help message. An `error` is emitted when the compiler detects a problem that makes it unable to compile the program, either because the program is invalid or the @@ -17,11 +17,11 @@ An `error` is emitted when the compiler detects a problem that makes it unable A `warning` is emitted when the compiler detects something odd about a program. For instance, dead code and unused `Result` values. -A `help` is emitted following either an `error` or `warning` giving extra +A `help` message is emitted following an `error` or `warning` to give additional information to the user about how to solve their problem. -A `note` is for identifying additional circumstances and parts of the code -that lead to a warning or error. For example, the borrow checker will note any +A `note` to emitted to identify additional circumstances and parts of the code +that caused the warning or error. For example, the borrow checker will note any previous conflicting borrows. * Write in plain simple English. If your message, when shown on a – possibly From 170c4340f66bd9843a2bfc2ccfa305cddbeb4807 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Mon, 8 May 2017 16:04:49 -0500 Subject: [PATCH 11/16] dividied closure-no-fn.rs into three different tests --- .../{closure-no-fn.rs => closure-no-fn-1.rs} | 6 ------ src/test/compile-fail/closure-no-fn-2.rs | 18 ++++++++++++++++++ src/test/compile-fail/closure-no-fn-3.rs | 18 ++++++++++++++++++ 3 files changed, 36 insertions(+), 6 deletions(-) rename src/test/compile-fail/{closure-no-fn.rs => closure-no-fn-1.rs} (77%) create mode 100644 src/test/compile-fail/closure-no-fn-2.rs create mode 100644 src/test/compile-fail/closure-no-fn-3.rs diff --git a/src/test/compile-fail/closure-no-fn.rs b/src/test/compile-fail/closure-no-fn-1.rs similarity index 77% rename from src/test/compile-fail/closure-no-fn.rs rename to src/test/compile-fail/closure-no-fn-1.rs index fe179e8a48f..10c99703a97 100644 --- a/src/test/compile-fail/closure-no-fn.rs +++ b/src/test/compile-fail/closure-no-fn-1.rs @@ -15,10 +15,4 @@ fn main() { let mut a = 0u8; let foo: fn(u8) -> u8 = |v: u8| { a += v; a }; //~^ ERROR mismatched types - let b = 0u8; - let bar: fn() -> u8 = || { b }; - //~^ ERROR mismatched types - let baz: fn() -> u8 = || { b } as fn() -> u8; - //~^ ERROR mismatched types - //~^^ ERROR non-scalar cast } diff --git a/src/test/compile-fail/closure-no-fn-2.rs b/src/test/compile-fail/closure-no-fn-2.rs new file mode 100644 index 00000000000..a6438bb5f24 --- /dev/null +++ b/src/test/compile-fail/closure-no-fn-2.rs @@ -0,0 +1,18 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Ensure that capturing closures are never coerced to fns +// Especially interesting as non-capturing closures can be. + +fn main() { + let b = 0u8; + let bar: fn() -> u8 = || { b }; + //~^ ERROR mismatched types +} diff --git a/src/test/compile-fail/closure-no-fn-3.rs b/src/test/compile-fail/closure-no-fn-3.rs new file mode 100644 index 00000000000..85dbc899208 --- /dev/null +++ b/src/test/compile-fail/closure-no-fn-3.rs @@ -0,0 +1,18 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Ensure that capturing closures are never coerced to fns +// Especially interesting as non-capturing closures can be. + +fn main() { + let b = 0u8; + let baz: fn() -> u8 = (|| { b }) as fn() -> u8; + //~^ ERROR non-scalar cast +} From 8aaae945eaf929cc277cfb5705e8d6d280e2a102 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Mon, 8 May 2017 16:17:26 -0500 Subject: [PATCH 12/16] first part of issue-40000.rs is now passing --- src/test/compile-fail/issue-40000.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/test/compile-fail/issue-40000.rs b/src/test/compile-fail/issue-40000.rs index 9be114ebcb6..3ccee0f12be 100644 --- a/src/test/compile-fail/issue-40000.rs +++ b/src/test/compile-fail/issue-40000.rs @@ -11,8 +11,7 @@ #![feature(closure_to_fn_coercion)] fn main() { - let bar: fn(&mut u32) = |_| {}; //~ ERROR mismatched types - //~| expected concrete lifetime, found bound lifetime parameter + let bar: fn(&mut u32) = |_| {}; fn foo(x: Box) {} let bar = Box::new(|x: &i32| {}) as Box; From 78b27373dced7ec5bb1243982271cda9f1079693 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Mon, 8 May 2017 16:34:29 -0500 Subject: [PATCH 13/16] added test --- .../closure_to_fn_coercion-expected-types.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 src/test/run-pass/closure_to_fn_coercion-expected-types.rs diff --git a/src/test/run-pass/closure_to_fn_coercion-expected-types.rs b/src/test/run-pass/closure_to_fn_coercion-expected-types.rs new file mode 100644 index 00000000000..7d951c655ca --- /dev/null +++ b/src/test/run-pass/closure_to_fn_coercion-expected-types.rs @@ -0,0 +1,18 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. +// +// Ensure that we deduce expected argument types when a `fn()` type is expected (#41755) + +#![feature(closure_to_fn_coercion)] +fn foo(f: fn(Vec) -> usize) { } + +fn main() { + foo(|x| x.len()) +} From 82e07363916146f0d6e01199ef30544e7fdd6248 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Mon, 8 May 2017 16:39:47 -0500 Subject: [PATCH 14/16] massive refactor --- src/test/run-pass/closure_to_fn_coercion-expected-types.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/test/run-pass/closure_to_fn_coercion-expected-types.rs b/src/test/run-pass/closure_to_fn_coercion-expected-types.rs index 7d951c655ca..7214ebfaf07 100644 --- a/src/test/run-pass/closure_to_fn_coercion-expected-types.rs +++ b/src/test/run-pass/closure_to_fn_coercion-expected-types.rs @@ -7,7 +7,6 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. -// // Ensure that we deduce expected argument types when a `fn()` type is expected (#41755) #![feature(closure_to_fn_coercion)] From dfd584997bb789f27204d61e34a84e7ea1a1aa1f Mon Sep 17 00:00:00 2001 From: Migi Date: Tue, 9 May 2017 01:32:46 +0200 Subject: [PATCH 15/16] Fix typo in subst.rs --- src/librustc/ty/subst.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc/ty/subst.rs b/src/librustc/ty/subst.rs index c9ffcee51c2..e23003bf772 100644 --- a/src/librustc/ty/subst.rs +++ b/src/librustc/ty/subst.rs @@ -102,7 +102,7 @@ impl<'tcx> fmt::Debug for Kind<'tcx> { } else if let Some(r) = self.as_region() { write!(f, "{:?}", r) } else { - write!(f, "", self.ptr.get() as *const ()) + write!(f, "", self.ptr.get() as *const ()) } } } From 9b8f9b7cf8c9f6d73e67369b6cf57efbc154512a Mon Sep 17 00:00:00 2001 From: Jing Zhao Date: Mon, 8 May 2017 18:15:23 -0700 Subject: [PATCH 16/16] Update rustc-ux-guidelines.md "A `note` to emitted to" changed to "A `note` is emitted to" --- src/doc/rustc-ux-guidelines.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc-ux-guidelines.md b/src/doc/rustc-ux-guidelines.md index ecfb2fb2572..323d49e4691 100644 --- a/src/doc/rustc-ux-guidelines.md +++ b/src/doc/rustc-ux-guidelines.md @@ -20,7 +20,7 @@ program. For instance, dead code and unused `Result` values. A `help` message is emitted following an `error` or `warning` to give additional information to the user about how to solve their problem. -A `note` to emitted to identify additional circumstances and parts of the code +A `note` is emitted to identify additional circumstances and parts of the code that caused the warning or error. For example, the borrow checker will note any previous conflicting borrows.